| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.accumulo.core.client.impl; |
| |
| import java.util.EnumSet; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| |
| import org.apache.accumulo.core.client.AccumuloException; |
| import org.apache.accumulo.core.client.AccumuloSecurityException; |
| import org.apache.accumulo.core.client.IteratorSetting; |
| import org.apache.accumulo.core.client.NamespaceNotFoundException; |
| import org.apache.accumulo.core.client.admin.NamespaceOperations; |
| import org.apache.accumulo.core.conf.Property; |
| import org.apache.accumulo.core.iterators.IteratorUtil.IteratorScope; |
| |
| public abstract class NamespaceOperationsHelper implements NamespaceOperations { |
| |
| @Override |
| public String systemNamespace() { |
| return Namespace.ACCUMULO; |
| } |
| |
| @Override |
| public String defaultNamespace() { |
| return Namespace.DEFAULT; |
| } |
| |
| @Override |
| public void attachIterator(String namespace, IteratorSetting setting) |
| throws AccumuloSecurityException, AccumuloException, NamespaceNotFoundException { |
| attachIterator(namespace, setting, EnumSet.allOf(IteratorScope.class)); |
| } |
| |
| @Override |
| public void attachIterator(String namespace, IteratorSetting setting, |
| EnumSet<IteratorScope> scopes) |
| throws AccumuloSecurityException, AccumuloException, NamespaceNotFoundException { |
| checkIteratorConflicts(namespace, setting, scopes); |
| for (IteratorScope scope : scopes) { |
| String root = String.format("%s%s.%s", Property.TABLE_ITERATOR_PREFIX, |
| scope.name().toLowerCase(), setting.getName()); |
| for (Entry<String,String> prop : setting.getOptions().entrySet()) { |
| this.setProperty(namespace, root + ".opt." + prop.getKey(), prop.getValue()); |
| } |
| this.setProperty(namespace, root, setting.getPriority() + "," + setting.getIteratorClass()); |
| } |
| } |
| |
| @Override |
| public void removeIterator(String namespace, String name, EnumSet<IteratorScope> scopes) |
| throws AccumuloSecurityException, AccumuloException, NamespaceNotFoundException { |
| if (!exists(namespace)) |
| throw new NamespaceNotFoundException(null, namespace, null); |
| Map<String,String> copy = new TreeMap<>(); |
| for (Entry<String,String> property : this.getProperties(namespace)) { |
| copy.put(property.getKey(), property.getValue()); |
| } |
| for (IteratorScope scope : scopes) { |
| String root = String.format("%s%s.%s", Property.TABLE_ITERATOR_PREFIX, |
| scope.name().toLowerCase(), name); |
| for (Entry<String,String> property : copy.entrySet()) { |
| if (property.getKey().equals(root) || property.getKey().startsWith(root + ".opt.")) |
| this.removeProperty(namespace, property.getKey()); |
| } |
| } |
| } |
| |
| @Override |
| public IteratorSetting getIteratorSetting(String namespace, String name, IteratorScope scope) |
| throws AccumuloSecurityException, AccumuloException, NamespaceNotFoundException { |
| if (!exists(namespace)) |
| throw new NamespaceNotFoundException(null, namespace, null); |
| int priority = -1; |
| String classname = null; |
| Map<String,String> settings = new HashMap<>(); |
| |
| String root = String.format("%s%s.%s", Property.TABLE_ITERATOR_PREFIX, |
| scope.name().toLowerCase(), name); |
| String opt = root + ".opt."; |
| for (Entry<String,String> property : this.getProperties(namespace)) { |
| if (property.getKey().equals(root)) { |
| String parts[] = property.getValue().split(","); |
| if (parts.length != 2) { |
| throw new AccumuloException("Bad value for iterator setting: " + property.getValue()); |
| } |
| priority = Integer.parseInt(parts[0]); |
| classname = parts[1]; |
| } else if (property.getKey().startsWith(opt)) { |
| settings.put(property.getKey().substring(opt.length()), property.getValue()); |
| } |
| } |
| if (priority <= 0 || classname == null) { |
| return null; |
| } |
| return new IteratorSetting(priority, name, classname, settings); |
| } |
| |
| @Override |
| public Map<String,EnumSet<IteratorScope>> listIterators(String namespace) |
| throws AccumuloSecurityException, AccumuloException, NamespaceNotFoundException { |
| if (!exists(namespace)) |
| throw new NamespaceNotFoundException(null, namespace, null); |
| Map<String,EnumSet<IteratorScope>> result = new TreeMap<>(); |
| for (Entry<String,String> property : this.getProperties(namespace)) { |
| String name = property.getKey(); |
| String[] parts = name.split("\\."); |
| if (parts.length == 4) { |
| if (parts[0].equals("table") && parts[1].equals("iterator")) { |
| IteratorScope scope = IteratorScope.valueOf(parts[2]); |
| if (!result.containsKey(parts[3])) |
| result.put(parts[3], EnumSet.noneOf(IteratorScope.class)); |
| result.get(parts[3]).add(scope); |
| } |
| } |
| } |
| return result; |
| } |
| |
| @Override |
| public void checkIteratorConflicts(String namespace, IteratorSetting setting, |
| EnumSet<IteratorScope> scopes) |
| throws AccumuloException, NamespaceNotFoundException, AccumuloSecurityException { |
| if (!exists(namespace)) |
| throw new NamespaceNotFoundException(null, namespace, null); |
| for (IteratorScope scope : scopes) { |
| String scopeStr = String.format("%s%s", Property.TABLE_ITERATOR_PREFIX, |
| scope.name().toLowerCase()); |
| String nameStr = String.format("%s.%s", scopeStr, setting.getName()); |
| String optStr = String.format("%s.opt.", nameStr); |
| Map<String,String> optionConflicts = new TreeMap<>(); |
| for (Entry<String,String> property : this.getProperties(namespace)) { |
| if (property.getKey().startsWith(scopeStr)) { |
| if (property.getKey().equals(nameStr)) |
| throw new AccumuloException(new IllegalArgumentException("iterator name conflict for " |
| + setting.getName() + ": " + property.getKey() + "=" + property.getValue())); |
| if (property.getKey().startsWith(optStr)) |
| optionConflicts.put(property.getKey(), property.getValue()); |
| if (property.getKey().contains(".opt.")) |
| continue; |
| String parts[] = property.getValue().split(","); |
| if (parts.length != 2) |
| throw new AccumuloException("Bad value for existing iterator setting: " |
| + property.getKey() + "=" + property.getValue()); |
| try { |
| if (Integer.parseInt(parts[0]) == setting.getPriority()) |
| throw new AccumuloException(new IllegalArgumentException( |
| "iterator priority conflict: " + property.getKey() + "=" + property.getValue())); |
| } catch (NumberFormatException e) { |
| throw new AccumuloException("Bad value for existing iterator setting: " |
| + property.getKey() + "=" + property.getValue()); |
| } |
| } |
| } |
| if (optionConflicts.size() > 0) |
| throw new AccumuloException(new IllegalArgumentException( |
| "iterator options conflict for " + setting.getName() + ": " + optionConflicts)); |
| } |
| } |
| |
| @Override |
| public int addConstraint(String namespace, String constraintClassName) |
| throws AccumuloException, AccumuloSecurityException, NamespaceNotFoundException { |
| TreeSet<Integer> constraintNumbers = new TreeSet<>(); |
| TreeMap<String,Integer> constraintClasses = new TreeMap<>(); |
| int i; |
| for (Entry<String,String> property : this.getProperties(namespace)) { |
| if (property.getKey().startsWith(Property.TABLE_CONSTRAINT_PREFIX.toString())) { |
| try { |
| i = Integer.parseInt( |
| property.getKey().substring(Property.TABLE_CONSTRAINT_PREFIX.toString().length())); |
| } catch (NumberFormatException e) { |
| throw new AccumuloException("Bad key for existing constraint: " + property); |
| } |
| constraintNumbers.add(i); |
| constraintClasses.put(property.getValue(), i); |
| } |
| } |
| i = 1; |
| while (constraintNumbers.contains(i)) |
| i++; |
| if (constraintClasses.containsKey(constraintClassName)) |
| throw new AccumuloException( |
| "Constraint " + constraintClassName + " already exists for namespace " + namespace |
| + " with number " + constraintClasses.get(constraintClassName)); |
| this.setProperty(namespace, Property.TABLE_CONSTRAINT_PREFIX.toString() + i, |
| constraintClassName); |
| return i; |
| } |
| |
| @Override |
| public void removeConstraint(String namespace, int number) |
| throws AccumuloException, AccumuloSecurityException, NamespaceNotFoundException { |
| this.removeProperty(namespace, Property.TABLE_CONSTRAINT_PREFIX.toString() + number); |
| } |
| |
| @Override |
| public Map<String,Integer> listConstraints(String namespace) |
| throws AccumuloException, NamespaceNotFoundException, AccumuloSecurityException { |
| Map<String,Integer> constraints = new TreeMap<>(); |
| for (Entry<String,String> property : this.getProperties(namespace)) { |
| if (property.getKey().startsWith(Property.TABLE_CONSTRAINT_PREFIX.toString())) { |
| if (constraints.containsKey(property.getValue())) |
| throw new AccumuloException("Same constraint configured twice: " + property.getKey() + "=" |
| + Property.TABLE_CONSTRAINT_PREFIX + constraints.get(property.getValue()) + "=" |
| + property.getKey()); |
| try { |
| constraints.put(property.getValue(), Integer.parseInt( |
| property.getKey().substring(Property.TABLE_CONSTRAINT_PREFIX.toString().length()))); |
| } catch (NumberFormatException e) { |
| throw new AccumuloException("Bad key for existing constraint: " + property); |
| } |
| } |
| } |
| return constraints; |
| } |
| } |