blob: 1dd4b1da2dc58adb20b79b971e12d1b86fdba143 [file] [log] [blame]
/*
* 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;
}
}