View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
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      // remove empty values
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       // clean up the overall options that caused things to fail
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           // Places all Parameters and Values into the LocalOptions, even if the value is "".
174           // This allows us to check for "" values when setting the iterators and allows us to remove
175           // the parameter and value from the table property.
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 }