1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.accumulo.core.util.shell.commands;
18
19 import java.io.IOException;
20 import java.util.EnumSet;
21 import java.util.HashMap;
22 import java.util.Iterator;
23 import java.util.Map;
24 import java.util.Map.Entry;
25
26 import jline.ConsoleReader;
27
28 import org.apache.accumulo.core.client.AccumuloException;
29 import org.apache.accumulo.core.client.AccumuloSecurityException;
30 import org.apache.accumulo.core.client.IteratorSetting;
31 import org.apache.accumulo.core.client.TableNotFoundException;
32 import org.apache.accumulo.core.iterators.AggregatingIterator;
33 import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope;
34 import org.apache.accumulo.core.iterators.OptionDescriber;
35 import org.apache.accumulo.core.iterators.OptionDescriber.IteratorOptions;
36 import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
37 import org.apache.accumulo.core.iterators.aggregation.Aggregator;
38 import org.apache.accumulo.core.iterators.user.AgeOffFilter;
39 import org.apache.accumulo.core.iterators.user.RegExFilter;
40 import org.apache.accumulo.core.iterators.user.ReqVisFilter;
41 import org.apache.accumulo.core.iterators.user.VersioningIterator;
42 import org.apache.accumulo.core.util.shell.Shell;
43 import org.apache.accumulo.core.util.shell.Shell.Command;
44 import org.apache.accumulo.core.util.shell.ShellCommandException;
45 import org.apache.accumulo.core.util.shell.ShellCommandException.ErrorCode;
46 import org.apache.accumulo.start.classloader.vfs.AccumuloVFSClassLoader;
47 import org.apache.commons.cli.CommandLine;
48 import org.apache.commons.cli.Option;
49 import org.apache.commons.cli.OptionGroup;
50 import org.apache.commons.cli.Options;
51
52 @SuppressWarnings("deprecation")
53 public class SetIterCommand extends Command {
54
55 private Option mincScopeOpt, majcScopeOpt, scanScopeOpt, nameOpt, priorityOpt;
56 private Option aggTypeOpt, ageoffTypeOpt, regexTypeOpt, versionTypeOpt, reqvisTypeOpt, classnameTypeOpt;
57
58 public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException, TableNotFoundException,
59 IOException, ShellCommandException {
60
61 final int priority = Integer.parseInt(cl.getOptionValue(priorityOpt.getOpt()));
62
63 final Map<String,String> options = new HashMap<String,String>();
64 String classname = cl.getOptionValue(classnameTypeOpt.getOpt());
65 if (cl.hasOption(aggTypeOpt.getOpt())) {
66 Shell.log.warn("aggregators are deprecated");
67 classname = AggregatingIterator.class.getName();
68 } else if (cl.hasOption(regexTypeOpt.getOpt())) {
69 classname = RegExFilter.class.getName();
70 } else if (cl.hasOption(ageoffTypeOpt.getOpt())) {
71 classname = AgeOffFilter.class.getName();
72 } else if (cl.hasOption(versionTypeOpt.getOpt())) {
73 classname = VersioningIterator.class.getName();
74 } else if (cl.hasOption(reqvisTypeOpt.getOpt())) {
75 classname = ReqVisFilter.class.getName();
76 }
77
78 if (!shellState.getConnector().instanceOperations().testClassLoad(classname, SortedKeyValueIterator.class.getName())) {
79 throw new ShellCommandException(ErrorCode.INITIALIZATION_FAILURE, "Servers are unable to load " + classname + " as type "
80 + SortedKeyValueIterator.class.getName());
81 }
82 final String name = cl.getOptionValue(nameOpt.getOpt(), setUpOptions(shellState.getReader(), classname, options));
83
84 final String aggregatorClass = options.get("aggregatorClass");
85 if (aggregatorClass != null && !shellState.getConnector().instanceOperations().testClassLoad(aggregatorClass, Aggregator.class.getName())) {
86 throw new ShellCommandException(ErrorCode.INITIALIZATION_FAILURE, "Servers are unable to load " + aggregatorClass + " as type "
87 + Aggregator.class.getName());
88 }
89 setTableProperties(cl, shellState, priority, options, classname, name);
90
91 return 0;
92 }
93
94 protected void setTableProperties(final CommandLine cl, final Shell shellState, final int priority, final Map<String,String> options, final String classname,
95 final String name)
96 throws AccumuloException, AccumuloSecurityException, ShellCommandException, TableNotFoundException {
97
98
99 final String tableName = OptUtil.getTableOpt(cl, shellState);
100
101 for (Iterator<Entry<String,String>> i = options.entrySet().iterator(); i.hasNext();) {
102 final Entry<String,String> entry = i.next();
103 if (entry.getValue() == null || entry.getValue().isEmpty()) {
104 i.remove();
105 }
106 }
107 final EnumSet<IteratorScope> scopes = EnumSet.noneOf(IteratorScope.class);
108 if (cl.hasOption(mincScopeOpt.getOpt())) {
109 scopes.add(IteratorScope.minc);
110 }
111 if (cl.hasOption(majcScopeOpt.getOpt())) {
112 scopes.add(IteratorScope.majc);
113 }
114 if (cl.hasOption(scanScopeOpt.getOpt())) {
115 scopes.add(IteratorScope.scan);
116 }
117 if (scopes.isEmpty()) {
118 throw new IllegalArgumentException("You must select at least one scope to configure");
119 }
120 final IteratorSetting setting = new IteratorSetting(priority, name, classname, options);
121 shellState.getConnector().tableOperations().attachIterator(tableName, setting, scopes);
122 }
123
124 private static String setUpOptions(final ConsoleReader reader, final String className, final Map<String,String> options) throws IOException, ShellCommandException {
125 String input;
126 OptionDescriber skvi;
127 Class<? extends OptionDescriber> clazz;
128 try {
129 clazz = AccumuloVFSClassLoader.loadClass(className, OptionDescriber.class);
130 skvi = clazz.newInstance();
131 } catch (ClassNotFoundException e) {
132 throw new IllegalArgumentException(e.getMessage());
133 } catch (InstantiationException e) {
134 throw new IllegalArgumentException(e.getMessage());
135 } catch (IllegalAccessException e) {
136 throw new IllegalArgumentException(e.getMessage());
137 } catch (ClassCastException e) {
138 throw new ShellCommandException(ErrorCode.INITIALIZATION_FAILURE, "Unable to load " + className + " as type " + OptionDescriber.class.getName()
139 + "; configure with 'config' instead");
140 }
141
142 final IteratorOptions itopts = skvi.describeOptions();
143 if (itopts.getName() == null) {
144 throw new IllegalArgumentException(className + " described its default distinguishing name as null");
145 }
146 String shortClassName = className;
147 if (className.contains(".")) {
148 shortClassName = className.substring(className.lastIndexOf('.') + 1);
149 }
150 final Map<String,String> localOptions = new HashMap<String,String>();
151 do {
152
153 for (String key : localOptions.keySet()) {
154 options.remove(key);
155 }
156 localOptions.clear();
157
158 reader.printString(itopts.getDescription());
159 reader.printNewline();
160
161 String prompt;
162 if (itopts.getNamedOptions() != null) {
163 for (Entry<String,String> e : itopts.getNamedOptions().entrySet()) {
164 prompt = Shell.repeat("-", 10) + "> set " + shortClassName + " parameter " + e.getKey() + ", " + e.getValue() + ": ";
165 reader.flushConsole();
166 input = reader.readLine(prompt);
167 if (input == null) {
168 reader.printNewline();
169 throw new IOException("Input stream closed");
170 } else {
171 input = new String(input);
172 }
173
174
175
176 localOptions.put(e.getKey(), input);
177 }
178 }
179
180 if (itopts.getUnnamedOptionDescriptions() != null) {
181 for (String desc : itopts.getUnnamedOptionDescriptions()) {
182 reader.printString(Shell.repeat("-", 10) + "> entering options: " + desc + "\n");
183 input = "start";
184 while (true) {
185 prompt = Shell.repeat("-", 10) + "> set " + shortClassName + " option (<name> <value>, hit enter to skip): ";
186
187 reader.flushConsole();
188 input = reader.readLine(prompt);
189 if (input == null) {
190 reader.printNewline();
191 throw new IOException("Input stream closed");
192 } else {
193 input = new String(input);
194 }
195
196 if (input.length() == 0)
197 break;
198
199 String[] sa = input.split(" ", 2);
200 localOptions.put(sa[0], sa[1]);
201 }
202 }
203 }
204
205 options.putAll(localOptions);
206 if (!skvi.validateOptions(options))
207 reader.printString("invalid options for " + clazz.getName() + "\n");
208
209 } while (!skvi.validateOptions(options));
210 return itopts.getName();
211 }
212
213 @Override
214 public String description() {
215 return "sets a table-specific iterator";
216 }
217
218 public Options getOptions() {
219 final Options o = new Options();
220
221 priorityOpt = new Option("p", "priority", true, "the order in which the iterator is applied");
222 priorityOpt.setArgName("pri");
223 priorityOpt.setRequired(true);
224
225 nameOpt = new Option("n", "name", true, "iterator to set");
226 nameOpt.setArgName("itername");
227
228 mincScopeOpt = new Option(IteratorScope.minc.name(), "minor-compaction", false, "applied at minor compaction");
229 majcScopeOpt = new Option(IteratorScope.majc.name(), "major-compaction", false, "applied at major compaction");
230 scanScopeOpt = new Option(IteratorScope.scan.name(), "scan-time", false, "applied at scan time");
231
232 final OptionGroup typeGroup = new OptionGroup();
233 classnameTypeOpt = new Option("class", "class-name", true, "a java class that implements SortedKeyValueIterator");
234 classnameTypeOpt.setArgName("name");
235 aggTypeOpt = new Option("agg", "aggregator", false, "an aggregating type");
236 regexTypeOpt = new Option("regex", "regular-expression", false, "a regex matching iterator");
237 versionTypeOpt = new Option("vers", "version", false, "a versioning iterator");
238 reqvisTypeOpt = new Option("reqvis", "require-visibility", false, "an iterator that omits entries with empty visibilities");
239 ageoffTypeOpt = new Option("ageoff", "ageoff", false, "an aging off iterator");
240
241 typeGroup.addOption(classnameTypeOpt);
242 typeGroup.addOption(aggTypeOpt);
243 typeGroup.addOption(regexTypeOpt);
244 typeGroup.addOption(versionTypeOpt);
245 typeGroup.addOption(reqvisTypeOpt);
246 typeGroup.addOption(ageoffTypeOpt);
247 typeGroup.setRequired(true);
248
249 o.addOption(OptUtil.tableOpt("table to configure iterators on"));
250 o.addOption(priorityOpt);
251 o.addOption(nameOpt);
252 o.addOption(mincScopeOpt);
253 o.addOption(majcScopeOpt);
254 o.addOption(scanScopeOpt);
255 o.addOptionGroup(typeGroup);
256 return o;
257 }
258
259 @Override
260 public int numArgs() {
261 return 0;
262 }
263 }