accumulo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From bhava...@apache.org
Subject [1/4] git commit: ACCUMULO-2615 Refactor server configurations
Date Mon, 14 Jul 2014 18:30:44 GMT
Repository: accumulo
Updated Branches:
  refs/heads/1.6.1-SNAPSHOT ea78c28f4 -> d53d45ccd
  refs/heads/master 10a100680 -> 46f5e8c88


ACCUMULO-2615 Refactor server configurations

* ServerConfiguration is deprecated in favor of the new ServerConfigurationFactory.
* ServerConfigurationFactory caches configurations not just but namespace or table ID, but
  also by instance ID.
* ZooConfigurationFactory takes over the creation logic from ZooConfiguration. A
  ZooConfiguration instance is no longer a singleton, but an ordinary instance.
  ZooConfigurationFactory caches created ones by instance ID.
* NamespaceConfiguration and TableConfiguration each keep a static map of ZooCache instances,
  rather than a single static instance. The map is keyed by instance ID and namespace/table
  (resp.) ID.
* getParentConfiguration() was added to all appropriate configurations.
* The logic for retrieving properties from ZooCache instances is refactored to a new
  ZooCachePropertyAccessor object.


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/d53d45cc
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/d53d45cc
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/d53d45cc

Branch: refs/heads/1.6.1-SNAPSHOT
Commit: d53d45ccd3002765cf05aef0540666eccbd63dc1
Parents: ea78c28
Author: Bill Havanki <bhavanki@cloudera.com>
Authored: Thu Jun 5 16:40:04 2014 -0400
Committer: Bill Havanki <bhavanki@cloudera.com>
Committed: Mon Jul 14 14:03:19 2014 -0400

----------------------------------------------------------------------
 .../server/conf/NamespaceConfWatcher.java       |  40 ++--
 .../server/conf/NamespaceConfiguration.java     | 104 +++++-----
 .../server/conf/ServerConfiguration.java        |  79 ++------
 .../server/conf/ServerConfigurationFactory.java | 194 +++++++++++++++++++
 .../accumulo/server/conf/TableConfWatcher.java  |  42 ++--
 .../server/conf/TableConfiguration.java         |  90 ++++-----
 .../server/conf/TableParentConfiguration.java   |  10 +
 .../server/conf/ZooCachePropertyAccessor.java   | 150 ++++++++++++++
 .../accumulo/server/conf/ZooConfiguration.java  |  47 ++---
 .../server/conf/ZooConfigurationFactory.java    | 107 ++++++++++
 .../server/conf/NamespaceConfigurationTest.java | 159 +++++++++++++++
 .../conf/ServerConfigurationFactoryTest.java    | 159 +++++++++++++++
 .../server/conf/TableConfigurationTest.java     | 129 ++++++++++--
 .../conf/ZooCachePropertyAccessorTest.java      | 188 ++++++++++++++++++
 .../conf/ZooConfigurationFactoryTest.java       |  66 +++++++
 15 files changed, 1323 insertions(+), 241 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfWatcher.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfWatcher.java b/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfWatcher.java
index 50ab27e..65d9388 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfWatcher.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfWatcher.java
@@ -31,26 +31,40 @@ class NamespaceConfWatcher implements Watcher {
   }
 
   private static final Logger log = Logger.getLogger(NamespaceConfWatcher.class);
-  private Instance instance = null;
+  private final Instance instance;
+  private final String namespacesPrefix;
+  private final int namespacesPrefixLength;
+  private ServerConfigurationFactory scf;
 
   NamespaceConfWatcher(Instance instance) {
     this.instance = instance;
+    namespacesPrefix = ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/";
+    namespacesPrefixLength = namespacesPrefix.length();
+    scf = new ServerConfigurationFactory(instance);
+  }
+
+  void setServerConfigurationFactory(ServerConfigurationFactory scf) {
+    this.scf = scf;
+  }
+
+  static String toString(WatchedEvent event) {
+    return new StringBuilder("{path=").append(event.getPath()).append(",state=")
+      .append(event.getState()).append(",type=").append(event.getType())
+      .append("}").toString();
   }
 
   @Override
   public void process(WatchedEvent event) {
     String path = event.getPath();
     if (log.isTraceEnabled())
-      log.trace("WatchEvent : " + path + " " + event.getState() + " " + event.getType());
-
-    String namespacesPrefix = ZooUtil.getRoot(instance) + Constants.ZNAMESPACES + "/";
+      log.trace("WatchedEvent : " + toString(event));
 
     String namespaceId = null;
     String key = null;
 
     if (path != null) {
       if (path.startsWith(namespacesPrefix)) {
-        namespaceId = path.substring(namespacesPrefix.length());
+        namespaceId = path.substring(namespacesPrefixLength);
         if (namespaceId.contains("/")) {
           namespaceId = namespaceId.substring(0, namespaceId.indexOf('/'));
           if (path.startsWith(namespacesPrefix + namespaceId + Constants.ZNAMESPACE_CONF + "/"))
@@ -59,7 +73,7 @@ class NamespaceConfWatcher implements Watcher {
       }
 
       if (namespaceId == null) {
-        log.warn("Zookeeper told me about a path I was not watching " + path + " state=" + event.getState() + " type=" + event.getType());
+        log.warn("Zookeeper told me about a path I was not watching: " + path + ", event " + toString(event));
         return;
       }
     }
@@ -69,27 +83,27 @@ class NamespaceConfWatcher implements Watcher {
         if (log.isTraceEnabled())
           log.trace("EventNodeDataChanged " + event.getPath());
         if (key != null)
-          ServerConfiguration.getNamespaceConfiguration(instance, namespaceId).propertyChanged(key);
+          scf.getNamespaceConfiguration(namespaceId).propertyChanged(key);
         break;
       case NodeChildrenChanged:
-        ServerConfiguration.getNamespaceConfiguration(instance, namespaceId).propertiesChanged();
+        scf.getNamespaceConfiguration(namespaceId).propertiesChanged();
         break;
       case NodeDeleted:
         if (key == null) {
-          ServerConfiguration.removeNamespaceIdInstance(namespaceId);
+          ServerConfigurationFactory.removeCachedNamespaceConfiguration(instance.getInstanceID(), namespaceId);
         }
         break;
       case None:
         switch (event.getState()) {
           case Expired:
-            ServerConfiguration.expireAllTableObservers();
+            ServerConfigurationFactory.expireAllTableObservers();
             break;
           case SyncConnected:
             break;
           case Disconnected:
             break;
           default:
-            log.warn("EventNone event not handled path = " + event.getPath() + " state=" + event.getState());
+            log.warn("EventNone event not handled " + toString(event));
         }
         break;
       case NodeCreated:
@@ -97,11 +111,11 @@ class NamespaceConfWatcher implements Watcher {
           case SyncConnected:
             break;
           default:
-            log.warn("Event NodeCreated event not handled path = " + event.getPath() + " state=" + event.getState());
+            log.warn("Event NodeCreated event not handled " + toString(event));
         }
         break;
       default:
-        log.warn("Event not handled path = " + event.getPath() + " state=" + event.getState() + " type = " + event.getType());
+        log.warn("Event not handled " + toString(event));
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java
index ebb098b..cadbd8e 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/NamespaceConfiguration.java
@@ -30,16 +30,19 @@ import org.apache.accumulo.core.zookeeper.ZooUtil;
 import org.apache.accumulo.fate.zookeeper.ZooCache;
 import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
 import org.apache.accumulo.server.client.HdfsZooInstance;
+import org.apache.accumulo.server.conf.ZooCachePropertyAccessor.PropCacheKey;
 import org.apache.log4j.Logger;
 
 public class NamespaceConfiguration extends ObservableConfiguration {
   private static final Logger log = Logger.getLogger(NamespaceConfiguration.class);
 
+  private static final Map<PropCacheKey,ZooCache> propCaches = new java.util.HashMap<PropCacheKey,ZooCache>();
+
   private final AccumuloConfiguration parent;
-  private static volatile ZooCache propCache = null;
-  private static final Object lock = new Object();
+  private ZooCachePropertyAccessor propCacheAccessor = null;
   protected String namespaceId = null;
   protected Instance inst = null;
+  private ZooCacheFactory zcf = new ZooCacheFactory();
 
   public NamespaceConfiguration(String namespaceId, AccumuloConfiguration parent) {
     this(namespaceId, HdfsZooInstance.getInstance(), parent);
@@ -51,43 +54,49 @@ public class NamespaceConfiguration extends ObservableConfiguration {
     this.namespaceId = namespaceId;
   }
 
-  @Override
-  public String get(Property property) {
-    String key = property.getKey();
-    String value = get(getPropCache(), key);
-
-    if (value == null || !property.getType().isValidFormat(value)) {
-      if (value != null)
-        log.error("Using default value for " + key + " due to improperly formatted " + property.getType() + ": " + value);
-      if (!(namespaceId.equals(Namespaces.ACCUMULO_NAMESPACE_ID) && isIteratorOrConstraint(property.getKey()))) {
-        // ignore iterators from parent if system namespace
-        value = parent.get(property);
-      }
-    }
-    return value;
+  /**
+   * Gets the parent configuration of this configuration.
+   *
+   * @return parent configuration
+   */
+  public AccumuloConfiguration getParentConfiguration() {
+    return parent;
   }
 
-  private String get(ZooCache zc, String key) {
-    String zPath = ZooUtil.getRoot(inst.getInstanceID()) + Constants.ZNAMESPACES + "/" + getNamespaceId() + Constants.ZNAMESPACE_CONF + "/" + key;
-    byte[] v = zc.get(zPath);
-    String value = null;
-    if (v != null)
-      value = new String(v, Constants.UTF8);
-    return value;
+  void setZooCacheFactory(ZooCacheFactory zcf) {
+    this.zcf = zcf;
   }
 
-  private void initializePropCache() {
-    synchronized (lock) {
-      if (propCache == null)
-        propCache = new ZooCacheFactory().getZooCache(inst.getZooKeepers(), inst.getZooKeepersSessionTimeOut(), new NamespaceConfWatcher(inst));
+  private synchronized ZooCachePropertyAccessor getPropCacheAccessor() {
+    if (propCacheAccessor == null) {
+      synchronized (propCaches) {
+        PropCacheKey key = new PropCacheKey(inst.getInstanceID(), namespaceId);
+        ZooCache propCache = propCaches.get(key);
+        if (propCache == null) {
+          propCache = zcf.getZooCache(inst.getZooKeepers(), inst.getZooKeepersSessionTimeOut(), new NamespaceConfWatcher(inst));
+          propCaches.put(key, propCache);
+        }
+        propCacheAccessor = new ZooCachePropertyAccessor(propCache);
+      }
     }
+    return propCacheAccessor;
+  }
+
+  private String getPath() {
+    return ZooUtil.getRoot(inst.getInstanceID()) + Constants.ZNAMESPACES + "/" + getNamespaceId() + Constants.ZNAMESPACE_CONF;
   }
 
-  private ZooCache getPropCache() {
-    if (null == propCache) {
-      initializePropCache();
+  @Override
+  public String get(Property property) {
+    String key = property.getKey();
+    AccumuloConfiguration getParent;
+    if (!(namespaceId.equals(Namespaces.ACCUMULO_NAMESPACE_ID) && isIteratorOrConstraint(property.getKey()))) {
+      getParent = parent;
+    } else {
+      // ignore iterators from parent if system namespace
+      getParent = null;
     }
-    return propCache;
+    return getPropCacheAccessor().get(property, getPath(), getParent);
   }
 
   private class SystemNamespaceFilter implements PropertyFilter {
@@ -109,28 +118,13 @@ public class NamespaceConfiguration extends ObservableConfiguration {
 
   @Override
   public void getProperties(Map<String,String> props, PropertyFilter filter) {
-
     PropertyFilter parentFilter = filter;
-
     // exclude system iterators/constraints from the system namespace
     // so they don't affect the metadata or root tables.
     if (getNamespaceId().equals(Namespaces.ACCUMULO_NAMESPACE_ID))
       parentFilter = new SystemNamespaceFilter(filter);
 
-    parent.getProperties(props, parentFilter);
-
-    ZooCache zc = getPropCache();
-
-    List<String> children = zc.getChildren(ZooUtil.getRoot(inst.getInstanceID()) + Constants.ZNAMESPACES + "/" + getNamespaceId() + Constants.ZNAMESPACE_CONF);
-    if (children != null) {
-      for (String child : children) {
-        if (child != null && filter.accept(child)) {
-          String value = get(zc, child);
-          if (value != null)
-            props.put(child, value);
-        }
-      }
-    }
+    getPropCacheAccessor().getProperties(props, getPath(), filter, parent, parentFilter);
   }
 
   protected String getNamespaceId() {
@@ -158,17 +152,21 @@ public class NamespaceConfiguration extends ObservableConfiguration {
     super.removeObserver(co);
   }
 
-  protected boolean isIteratorOrConstraint(String key) {
+  static boolean isIteratorOrConstraint(String key) {
     return key.startsWith(Property.TABLE_ITERATOR_PREFIX.getKey()) || key.startsWith(Property.TABLE_CONSTRAINT_PREFIX.getKey());
   }
 
+  /**
+   * Invalidates the <code>ZooCache</code> used for storage and quick retrieval
+   * of properties for this namespace configuration.
+   */
   @Override
-  public void invalidateCache() {
-    if (null != propCache) {
-      propCache.clear();
+  public synchronized void invalidateCache() {
+    if (null != propCacheAccessor) {
+      propCacheAccessor.invalidateCache();
     }
-    // Else, if the cache is null, we could lock and double-check
-    // to see if it happened to be created so we could invalidate it
+    // Else, if the accessor is null, we could lock and double-check
+    // to see if it happened to be created so we could invalidate its cache
     // but I don't see much benefit coming from that extra check.
   }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfiguration.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfiguration.java
index 2115f3f..0793177 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfiguration.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfiguration.java
@@ -17,23 +17,19 @@
 package org.apache.accumulo.server.conf;
 
 import java.security.SecurityPermission;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Map.Entry;
 
 import org.apache.accumulo.core.client.Instance;
-import org.apache.accumulo.core.client.impl.Tables;
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
-import org.apache.accumulo.core.conf.ConfigSanityCheck;
 import org.apache.accumulo.core.conf.DefaultConfiguration;
 import org.apache.accumulo.core.conf.SiteConfiguration;
 import org.apache.accumulo.core.data.KeyExtent;
 
+/**
+ * @deprecated Use {@link ServerConfigurationFactory} instead.
+ */
+@Deprecated
 public class ServerConfiguration {
 
-  private static final Map<String,TableConfiguration> tableInstances = new HashMap<String,TableConfiguration>(1);
-  private static final Map<String,NamespaceConfiguration> namespaceInstances = new HashMap<String,NamespaceConfiguration>(1);
-  private static final Map<String,NamespaceConfiguration> tableParentInstances = new HashMap<String,NamespaceConfiguration>(1);
   private static SecurityPermission CONFIGURATION_PERMISSION = new SecurityPermission("configurationPermission");
 
   public static synchronized SiteConfiguration getSiteConfiguration() {
@@ -49,8 +45,7 @@ public class ServerConfiguration {
   }
 
   private static synchronized ZooConfiguration getZooConfiguration(Instance instance) {
-    checkPermissions();
-    return ZooConfiguration.getInstance(instance, getSiteConfiguration());
+    return (ZooConfiguration) new ServerConfigurationFactory(instance).getConfiguration();
   }
 
   public static synchronized DefaultConfiguration getDefaultConfiguration() {
@@ -63,72 +58,28 @@ public class ServerConfiguration {
   }
 
   public static NamespaceConfiguration getNamespaceConfigurationForTable(Instance instance, String tableId) {
-    checkPermissions();
-    synchronized (tableParentInstances) {
-      NamespaceConfiguration conf = tableParentInstances.get(tableId);
-      if (conf == null) {
-        conf = new TableParentConfiguration(tableId, getSystemConfiguration(instance));
-        ConfigSanityCheck.validate(conf);
-        tableParentInstances.put(tableId, conf);
-      }
-      return conf;
-    }
+    return new ServerConfigurationFactory(instance).getNamespaceConfigurationForTable(tableId);
   }
 
   public static NamespaceConfiguration getNamespaceConfiguration(Instance instance, String namespaceId) {
-    checkPermissions();
-    synchronized (namespaceInstances) {
-      NamespaceConfiguration conf = namespaceInstances.get(namespaceId);
-      if (conf == null) {
-        conf = new NamespaceConfiguration(namespaceId, getSystemConfiguration(instance));
-        ConfigSanityCheck.validate(conf);
-        namespaceInstances.put(namespaceId, conf);
-      }
-      return conf;
-    }
+    return new ServerConfigurationFactory(instance).getNamespaceConfiguration(namespaceId);
   }
 
   public static TableConfiguration getTableConfiguration(Instance instance, String tableId) {
-    checkPermissions();
-    synchronized (tableInstances) {
-      TableConfiguration conf = tableInstances.get(tableId);
-      if (conf == null && Tables.exists(instance, tableId)) {
-        conf = new TableConfiguration(instance.getInstanceID(), tableId, getNamespaceConfigurationForTable(instance, tableId));
-        ConfigSanityCheck.validate(conf);
-        tableInstances.put(tableId, conf);
-      }
-      return conf;
-    }
-  }
-
-  static void removeTableIdInstance(String tableId) {
-    synchronized (tableInstances) {
-      tableInstances.remove(tableId);
-    }
-  }
-
-  static void removeNamespaceIdInstance(String namespaceId) {
-    synchronized (namespaceInstances) {
-      namespaceInstances.remove(namespaceId);
-    }
+    return new ServerConfigurationFactory(instance).getTableConfiguration(tableId);
   }
 
   static void expireAllTableObservers() {
-    synchronized (tableInstances) {
-      for (Entry<String,TableConfiguration> entry : tableInstances.entrySet()) {
-        entry.getValue().expireAllObservers();
-      }
-    }
+    ServerConfigurationFactory.expireAllTableObservers();
   }
-
-  private final Instance instance;
+  private final ServerConfigurationFactory scf;
 
   public ServerConfiguration(Instance instance) {
-    this.instance = instance;
+    scf = new ServerConfigurationFactory(instance);
   }
 
   public TableConfiguration getTableConfiguration(String tableId) {
-    return getTableConfiguration(instance, tableId);
+    return scf.getTableConfiguration(tableId);
   }
 
   public TableConfiguration getTableConfiguration(KeyExtent extent) {
@@ -136,15 +87,15 @@ public class ServerConfiguration {
   }
 
   public NamespaceConfiguration getNamespaceConfiguration(String namespaceId) {
-    return getNamespaceConfiguration(instance, namespaceId);
+    return scf.getNamespaceConfiguration(namespaceId);
   }
 
   public synchronized AccumuloConfiguration getConfiguration() {
-    return getZooConfiguration(instance);
+    return scf.getConfiguration();
   }
 
   public Instance getInstance() {
-    return instance;
+    return scf.getInstance();
   }
 
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfigurationFactory.java b/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfigurationFactory.java
new file mode 100644
index 0000000..3bc349f
--- /dev/null
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/ServerConfigurationFactory.java
@@ -0,0 +1,194 @@
+/*
+ * 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.server.conf;
+
+import java.security.SecurityPermission;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.impl.Tables;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.ConfigSanityCheck;
+import org.apache.accumulo.core.conf.DefaultConfiguration;
+import org.apache.accumulo.core.conf.SiteConfiguration;
+import org.apache.accumulo.core.data.KeyExtent;
+import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
+
+/**
+ * A factor for configurations used by a server process. Instance of this class are thread-safe.
+ */
+public class ServerConfigurationFactory {
+
+  private static final Map<String,Map<String,TableConfiguration>> tableConfigs;
+  private static final Map<String,Map<String,NamespaceConfiguration>> namespaceConfigs;
+  private static final Map<String,Map<String,NamespaceConfiguration>> tableParentConfigs;
+  static {
+    tableConfigs = new HashMap<String,Map<String,TableConfiguration>>(1);
+    namespaceConfigs = new HashMap<String,Map<String,NamespaceConfiguration>>(1);
+    tableParentConfigs = new HashMap<String,Map<String,NamespaceConfiguration>>(1);
+  }
+  private static void addInstanceToCaches(String iid) {
+    synchronized(tableConfigs) {
+      if (!tableConfigs.containsKey(iid)) {
+        tableConfigs.put(iid, new HashMap<String,TableConfiguration>());
+      }
+    }
+    synchronized(namespaceConfigs) {
+      if (!namespaceConfigs.containsKey(iid)) {
+        namespaceConfigs.put(iid, new HashMap<String,NamespaceConfiguration>());
+      }
+    }
+    synchronized(tableParentConfigs) {
+      if (!tableParentConfigs.containsKey(iid)) {
+        tableParentConfigs.put(iid, new HashMap<String,NamespaceConfiguration>());
+      }
+    }
+  }
+  private static final SecurityPermission CONFIGURATION_PERMISSION = new SecurityPermission("configurationPermission");
+  private static final SecurityManager SM = System.getSecurityManager();
+
+  private static void checkPermissions() {
+    if (SM != null) {
+      SM.checkPermission(CONFIGURATION_PERMISSION);
+    }
+  }
+
+  static boolean removeCachedTableConfiguration(String instanceId, String tableId) {
+    synchronized (tableConfigs) {
+      return tableConfigs.get(instanceId).remove(tableId) != null;
+    }
+  }
+  static boolean removeCachedNamespaceConfiguration(String instanceId, String namespaceId) {
+    synchronized (namespaceConfigs) {
+      return namespaceConfigs.get(instanceId).remove(namespaceId) != null;
+    }
+  }
+  static void clearCachedConfigurations() {
+    synchronized (tableConfigs) {
+      tableConfigs.clear();
+    }
+    synchronized (namespaceConfigs) {
+      namespaceConfigs.clear();
+    }
+    synchronized (tableParentConfigs) {
+      tableParentConfigs.clear();
+    }
+  }
+  static void expireAllTableObservers() {
+    synchronized (tableConfigs) {
+      for (Map<String,TableConfiguration> instanceMap : tableConfigs.values()) {
+        for (TableConfiguration c : instanceMap.values()) {
+          c.expireAllObservers();
+        }
+      }
+    }
+  }
+
+  private final Instance instance;
+  private final String instanceID;
+  private ZooCacheFactory zcf = new ZooCacheFactory();
+
+  public ServerConfigurationFactory(Instance instance) {
+    this.instance = instance;
+    instanceID = instance.getInstanceID();
+    addInstanceToCaches(instanceID);
+  }
+  void setZooCacheFactory(ZooCacheFactory zcf) {
+    this.zcf = zcf;
+  }
+
+  private SiteConfiguration siteConfig = null;
+  private DefaultConfiguration defaultConfig = null;
+  private AccumuloConfiguration systemConfig = null;
+
+  public synchronized SiteConfiguration getSiteConfiguration() {
+    if (siteConfig == null) {
+      checkPermissions();
+      siteConfig = SiteConfiguration.getInstance(getDefaultConfiguration());
+    }
+    return siteConfig;
+  }
+
+  public synchronized DefaultConfiguration getDefaultConfiguration() {
+    if (defaultConfig == null) {
+      checkPermissions();
+      defaultConfig = DefaultConfiguration.getInstance();
+    }
+    return defaultConfig;
+  }
+
+  public synchronized AccumuloConfiguration getConfiguration() {
+    if (systemConfig == null) {
+      checkPermissions();
+      systemConfig = new ZooConfigurationFactory().getInstance(instance, zcf, getSiteConfiguration());
+    }
+    return systemConfig;
+  }
+
+
+  public TableConfiguration getTableConfiguration(String tableId) {
+    checkPermissions();
+    synchronized (tableConfigs) {
+      TableConfiguration conf = tableConfigs.get(instanceID).get(tableId);
+      if (conf == null && Tables.exists(instance, tableId)) {
+        conf = new TableConfiguration(instance.getInstanceID(), tableId, getNamespaceConfigurationForTable(tableId));
+        ConfigSanityCheck.validate(conf);
+        tableConfigs.get(instanceID).put(tableId, conf);
+      }
+      return conf;
+    }
+  }
+
+  public TableConfiguration getTableConfiguration(KeyExtent extent) {
+    return getTableConfiguration(extent.getTableId().toString());
+  }
+
+  public NamespaceConfiguration getNamespaceConfigurationForTable(String tableId) {
+    checkPermissions();
+    synchronized (tableParentConfigs) {
+      NamespaceConfiguration conf = tableParentConfigs.get(instanceID).get(tableId);
+      if (conf == null) {
+        // changed - include instance in constructor call
+        conf = new TableParentConfiguration(tableId, instance, getConfiguration());
+        ConfigSanityCheck.validate(conf);
+        tableParentConfigs.get(instanceID).put(tableId, conf);
+      }
+      return conf;
+    }
+  }
+
+  public NamespaceConfiguration getNamespaceConfiguration(String namespaceId) {
+    checkPermissions();
+    synchronized (namespaceConfigs) {
+      NamespaceConfiguration conf = namespaceConfigs.get(instanceID).get(namespaceId);
+      if (conf == null) {
+        // changed - include instance in constructor call
+        conf = new NamespaceConfiguration(namespaceId, instance, getConfiguration());
+        conf.setZooCacheFactory(zcf);
+        ConfigSanityCheck.validate(conf);
+        namespaceConfigs.get(instanceID).put(namespaceId, conf);
+      }
+      return conf;
+    }
+  }
+
+  public Instance getInstance() {
+    return instance;
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfWatcher.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfWatcher.java b/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfWatcher.java
index 3c24ec4..4709b85 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfWatcher.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfWatcher.java
@@ -31,19 +31,33 @@ class TableConfWatcher implements Watcher {
   }
   
   private static final Logger log = Logger.getLogger(TableConfWatcher.class);
-  private Instance instance = null;
-  
+  private final Instance instance;
+  private final String tablesPrefix;
+  private final int tablesPrefixLength;
+  private ServerConfigurationFactory scf;
+
   TableConfWatcher(Instance instance) {
     this.instance = instance;
+    tablesPrefix = ZooUtil.getRoot(instance) + Constants.ZTABLES + "/";
+    tablesPrefixLength = tablesPrefix.length();
+    scf = new ServerConfigurationFactory(instance);
   }
-  
+
+  void setServerConfigurationFactory(ServerConfigurationFactory scf) {
+    this.scf = scf;
+  }
+
+  static String toString(WatchedEvent event) {
+    return new StringBuilder("{path=").append(event.getPath()).append(",state=")
+      .append(event.getState()).append(",type=").append(event.getType())
+      .append("}").toString();
+  }
+
   @Override
   public void process(WatchedEvent event) {
     String path = event.getPath();
     if (log.isTraceEnabled())
-      log.trace("WatchEvent : " + path + " " + event.getState() + " " + event.getType());
-    
-    String tablesPrefix = ZooUtil.getRoot(instance) + Constants.ZTABLES + "/";
+      log.trace("WatchedEvent : " + toString(event));
     
     String tableId = null;
     String key = null;
@@ -59,7 +73,7 @@ class TableConfWatcher implements Watcher {
       }
       
       if (tableId == null) {
-        log.warn("Zookeeper told me about a path I was not watching " + path + " state=" + event.getState() + " type=" + event.getType());
+        log.warn("Zookeeper told me about a path I was not watching: " + path + ", event " + toString(event));
         return;
       }
     }
@@ -69,30 +83,30 @@ class TableConfWatcher implements Watcher {
         if (log.isTraceEnabled())
           log.trace("EventNodeDataChanged " + event.getPath());
         if (key != null)
-          ServerConfiguration.getTableConfiguration(instance, tableId).propertyChanged(key);
+          scf.getTableConfiguration(tableId).propertyChanged(key);
         break;
       case NodeChildrenChanged:
-        ServerConfiguration.getTableConfiguration(instance, tableId).propertiesChanged();
+        scf.getTableConfiguration(tableId).propertiesChanged();
         break;
       case NodeDeleted:
         if (key == null) {
           // only remove the AccumuloConfiguration object when a
           // table node is deleted, not when a tables property is
           // deleted.
-          ServerConfiguration.removeTableIdInstance(tableId);
+          ServerConfigurationFactory.removeCachedTableConfiguration(instance.getInstanceID(), tableId);
         }
         break;
       case None:
         switch (event.getState()) {
           case Expired:
-            ServerConfiguration.expireAllTableObservers();
+            ServerConfigurationFactory.expireAllTableObservers();
             break;
           case SyncConnected:
             break;
           case Disconnected:
             break;
           default:
-            log.warn("EventNone event not handled path = " + event.getPath() + " state=" + event.getState());
+            log.warn("EventNone event not handled " + toString(event));
         }
         break;
       case NodeCreated:
@@ -100,11 +114,11 @@ class TableConfWatcher implements Watcher {
           case SyncConnected:
             break;
           default:
-            log.warn("Event NodeCreated event not handled path = " + event.getPath() + " state=" + event.getState());
+            log.warn("Event NodeCreated event not handled " + toString(event));
         }
         break;
       default:
-        log.warn("Event not handled path = " + event.getPath() + " state=" + event.getState() + " type = " + event.getType());
+        log.warn("Event not handled " + toString(event));
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java
index b538d2e..1936484 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/TableConfiguration.java
@@ -28,18 +28,19 @@ import org.apache.accumulo.core.zookeeper.ZooUtil;
 import org.apache.accumulo.fate.zookeeper.ZooCache;
 import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
 import org.apache.accumulo.server.client.HdfsZooInstance;
+import org.apache.accumulo.server.conf.ZooCachePropertyAccessor.PropCacheKey;
 import org.apache.log4j.Logger;
 
 public class TableConfiguration extends ObservableConfiguration {
   private static final Logger log = Logger.getLogger(TableConfiguration.class);
 
-  // Need volatile keyword to ensure double-checked locking works as intended
-  private static volatile ZooCache tablePropCache = null;
-  private static final Object initLock = new Object();
+  private static final Map<PropCacheKey,ZooCache> propCaches = new java.util.HashMap<PropCacheKey,ZooCache>();
 
+  private ZooCachePropertyAccessor propCacheAccessor = null;
   private final String instanceId;
   private final Instance instance;
   private final NamespaceConfiguration parent;
+  private ZooCacheFactory zcf = new ZooCacheFactory();
 
   private String table = null;
 
@@ -54,19 +55,23 @@ public class TableConfiguration extends ObservableConfiguration {
     this.parent = parent;
   }
 
-  private void initializeZooCache() {
-    synchronized (initLock) {
-      if (null == tablePropCache) {
-        tablePropCache = new ZooCacheFactory().getZooCache(instance.getZooKeepers(), instance.getZooKeepersSessionTimeOut(), new TableConfWatcher(instance));
-      }
-    }
+  void setZooCacheFactory(ZooCacheFactory zcf) {
+    this.zcf = zcf;
   }
 
-  private ZooCache getTablePropCache() {
-    if (null == tablePropCache) {
-      initializeZooCache();
+  private synchronized ZooCachePropertyAccessor getPropCacheAccessor() {
+    if (propCacheAccessor == null) {
+      synchronized (propCaches) {
+        PropCacheKey key = new PropCacheKey(instance.getInstanceID(), table);
+        ZooCache propCache = propCaches.get(key);
+        if (propCache == null) {
+          propCache = zcf.getZooCache(instance.getZooKeepers(), instance.getZooKeepersSessionTimeOut(), new TableConfWatcher(instance));
+          propCaches.put(key, propCache);
+        }
+        propCacheAccessor = new ZooCachePropertyAccessor(propCache);
+      }
     }
-    return tablePropCache;
+    return propCacheAccessor;
   }
 
   @Override
@@ -90,44 +95,18 @@ public class TableConfiguration extends ObservableConfiguration {
     super.removeObserver(co);
   }
 
-  @Override
-  public String get(Property property) {
-    String key = property.getKey();
-    String value = get(getTablePropCache(), key);
-
-    if (value == null || !property.getType().isValidFormat(value)) {
-      if (value != null)
-        log.error("Using default value for " + key + " due to improperly formatted " + property.getType() + ": " + value);
-      value = parent.get(property);
-    }
-    return value;
+  private String getPath() {
+    return ZooUtil.getRoot(instanceId) + Constants.ZTABLES + "/" + table + Constants.ZTABLE_CONF;
   }
 
-  private String get(ZooCache zc, String key) {
-    String zPath = ZooUtil.getRoot(instanceId) + Constants.ZTABLES + "/" + table + Constants.ZTABLE_CONF + "/" + key;
-    byte[] v = zc.get(zPath);
-    String value = null;
-    if (v != null)
-      value = new String(v, Constants.UTF8);
-    return value;
+  @Override
+  public String get(Property property) {
+    return getPropCacheAccessor().get(property, getPath(), parent);
   }
 
   @Override
   public void getProperties(Map<String,String> props, PropertyFilter filter) {
-    parent.getProperties(props, filter);
-
-    ZooCache zc = getTablePropCache();
-
-    List<String> children = zc.getChildren(ZooUtil.getRoot(instanceId) + Constants.ZTABLES + "/" + table + Constants.ZTABLE_CONF);
-    if (children != null) {
-      for (String child : children) {
-        if (child != null && filter.accept(child)) {
-          String value = get(zc, child);
-          if (value != null)
-            props.put(child, value);
-        }
-      }
-    }
+    getPropCacheAccessor().getProperties(props, getPath(), filter, parent, null);
   }
 
   public String getTableId() {
@@ -138,23 +117,30 @@ public class TableConfiguration extends ObservableConfiguration {
    * returns the actual NamespaceConfiguration that corresponds to the current parent namespace.
    */
   public NamespaceConfiguration getNamespaceConfiguration() {
-    return ServerConfiguration.getNamespaceConfiguration(parent.inst, parent.namespaceId);
+    return new ServerConfigurationFactory(parent.inst).getNamespaceConfiguration(parent.namespaceId);
   }
 
   /**
-   * returns the parent, which is actually a TableParentConfiguration that can change which namespace it references
+   * Gets the parent configuration of this configuration. The parent is actually a {@link TableParentConfiguration} that can change which namespace it
+   * references.
+   *
+   * @return parent configuration
    */
   public NamespaceConfiguration getParentConfiguration() {
     return parent;
   }
 
+  /**
+   * Invalidates the <code>ZooCache</code> used for storage and quick retrieval
+   * of properties for this table configuration.
+   */
   @Override
-  public void invalidateCache() {
-    if (null != tablePropCache) {
-      tablePropCache.clear();
+  public synchronized void invalidateCache() {
+    if (null != propCacheAccessor) {
+      propCacheAccessor.invalidateCache();
     }
-    // Else, if the cache is null, we could lock and double-check
-    // to see if it happened to be created so we could invalidate it
+    // Else, if the accessor is null, we could lock and double-check
+    // to see if it happened to be created so we could invalidate its cache
     // but I don't see much benefit coming from that extra check.
   }
 

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java
index 34eb781..2a2bfce 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/TableParentConfiguration.java
@@ -16,6 +16,7 @@
  */
 package org.apache.accumulo.server.conf;
 
+import org.apache.accumulo.core.client.Instance;
 import org.apache.accumulo.core.client.impl.Tables;
 import org.apache.accumulo.core.conf.AccumuloConfiguration;
 
@@ -31,6 +32,15 @@ public class TableParentConfiguration extends NamespaceConfiguration {
     this.tableId = tableId;
     this.namespaceId = getNamespaceId();
   }
+  public TableParentConfiguration(String tableId, Instance inst, AccumuloConfiguration parent) {
+    super(null, inst, parent);
+    this.tableId = tableId;
+    this.namespaceId = getNamespaceId();
+  }
+
+  String getTableId() {
+    return tableId;
+  }
 
   @Override
   protected String getNamespaceId() {

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/ZooCachePropertyAccessor.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/ZooCachePropertyAccessor.java b/server/base/src/main/java/org/apache/accumulo/server/conf/ZooCachePropertyAccessor.java
new file mode 100644
index 0000000..ac30008
--- /dev/null
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/ZooCachePropertyAccessor.java
@@ -0,0 +1,150 @@
+/*
+ * 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.server.conf;
+
+import java.util.List;
+import java.util.Map;
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.AccumuloConfiguration.PropertyFilter;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.zookeeper.ZooUtil;
+import org.apache.accumulo.fate.zookeeper.ZooCache;
+import org.apache.log4j.Logger;
+
+/**
+ * A helper object for accessing properties in a {@link ZooCache}.
+ */
+public class ZooCachePropertyAccessor {
+  private static final Logger log = Logger.getLogger(ZooCachePropertyAccessor.class);
+
+  static class PropCacheKey {
+    final String instanceId;
+    final String scope;
+    PropCacheKey(String iid, String s) {
+      instanceId = iid;
+      scope = s;
+    }
+    @Override
+    public boolean equals(Object other) {
+      if (this == other) {
+        return true;
+      }
+      if (!(other instanceof PropCacheKey)) {
+        return false;
+      }
+      PropCacheKey o = (PropCacheKey) other;
+      return (instanceId.equals(o.instanceId) && scope.equals(o.scope));
+    }
+    @Override
+    public int hashCode() {
+      int c = 17;
+      c = (37 * c) + instanceId.hashCode();
+      c = (37 * c) + scope.hashCode();
+      return c;
+    }
+  }
+
+  private final ZooCache propCache;
+
+  /**
+   * Creates a new accessor.
+   *
+   * @param propCache property cache
+   */
+  ZooCachePropertyAccessor(ZooCache propCache) {
+    this.propCache = propCache;
+  }
+  /**
+   * Gets the property cache accessed by this object.
+   *
+   * @return property cache
+   */
+  ZooCache getZooCache() {
+    return propCache;
+  }
+
+  /**
+   * Gets a property. If the property is not in ZooKeeper or is present but an
+   * invalid format for the property type, the parent configuration is consulted
+   * (if provided).
+   *
+   * @param property property to get
+   * @param path ZooKeeper path where properties lie
+   * @param parent parent configuration (optional)
+   * @return property value, or null if not found
+   */
+  String get(Property property, String path, AccumuloConfiguration parent) {
+    String key = property.getKey();
+    String value = get(path + "/" + key);
+
+    if (value == null || !property.getType().isValidFormat(value)) {
+      if (value != null) {
+        log.error("Using default value for " + key + " due to improperly formatted " + property.getType() + ": " + value);
+      }
+      if (parent != null) {
+        value = parent.get(property);
+      }
+    }
+    return value;
+  }
+
+  private String get(String path) {
+    byte[] v = propCache.get(path);
+    if (v != null) {
+      return new String(v, Constants.UTF8);
+    } else {
+      return null;
+    }
+  }
+
+  /**
+   * Gets all properties into the given map. Properties are filtered using the
+   * given filter. Properties from a parent configuration are also added to the
+   * map and filtered, either using a separate filter or, if not specified, the
+   * other filter.
+   *
+   * @param props map to populate with properties
+   * @param path ZooKeeper path where properties lie
+   * @param filter property filter (required)
+   * @param parent parent configuration (required)
+   * @param parentFilter separate filter for parent properties (optional)
+   */
+  void getProperties(Map<String,String> props, String path, PropertyFilter filter, AccumuloConfiguration parent, PropertyFilter parentFilter) {
+    parent.getProperties(props, parentFilter != null ? parentFilter : filter);
+
+    List<String> children = propCache.getChildren(path);
+    if (children != null) {
+      for (String child : children) {
+        if (child != null && filter.accept(child)) {
+          String value = get(path + "/" + child);
+          if (value != null) {
+            props.put(child, value);
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Clears the internal {@link ZooCache}.
+   */
+  void invalidateCache() {
+    propCache.clear();
+  }
+
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfiguration.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfiguration.java b/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfiguration.java
index 696873b..e2bf5f5 100644
--- a/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfiguration.java
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfiguration.java
@@ -38,49 +38,32 @@ import org.apache.log4j.Logger;
 public class ZooConfiguration extends AccumuloConfiguration {
   private static final Logger log = Logger.getLogger(ZooConfiguration.class);
   
+  private final String instanceId;
+  private final ZooCache propCache;
   private final AccumuloConfiguration parent;
-  private static ZooConfiguration instance = null;
-  private static String instanceId = null;
-  private static ZooCache propCache = null;
   private final Map<String,String> fixedProps = Collections.synchronizedMap(new HashMap<String,String>());
   
-  private ZooConfiguration(AccumuloConfiguration parent) {
+  protected ZooConfiguration(String instanceId, ZooCache propCache, AccumuloConfiguration parent) {
+    this.instanceId = instanceId;
+    this.propCache = propCache;
     this.parent = parent;
   }
   
-  synchronized public static ZooConfiguration getInstance(Instance inst, AccumuloConfiguration parent) {
-    if (instance == null) {
-      propCache = new ZooCacheFactory().getZooCache(inst.getZooKeepers(), inst.getZooKeepersSessionTimeOut());
-      instance = new ZooConfiguration(parent);
-      instanceId = inst.getInstanceID();
-    }
-    return instance;
-  }
-  
-  synchronized public static ZooConfiguration getInstance(AccumuloConfiguration parent) {
-    if (instance == null) {
-      propCache = new ZooCacheFactory().getZooCache(parent.get(Property.INSTANCE_ZK_HOST), (int) parent.getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT));
-      instance = new ZooConfiguration(parent);
-      // InstanceID should be the same across all volumes, so just choose one
-      VolumeManager fs;
-      try {
-        fs = VolumeManagerImpl.get();
-      } catch (IOException e) {
-        throw new RuntimeException(e);
-      }
-      Path instanceIdPath = Accumulo.getAccumuloInstanceIdPath(fs);
-      String deprecatedInstanceIdFromHdfs = ZooUtil.getInstanceIDFromHdfs(instanceIdPath, parent);
-      instanceId = deprecatedInstanceIdFromHdfs;
-    }
-    return instance;
-  }
-  
   @Override
   public void invalidateCache() {
     if (propCache != null)
       propCache.clear();
   }
-  
+
+  /**
+   * Gets the parent configuration of this configuration.
+   *
+   * @return parent configuration
+   */
+  public AccumuloConfiguration getParentConfiguration() {
+    return parent;
+  }
+
   private String _get(Property property) {
     String key = property.getKey();
     String value = null;

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfigurationFactory.java
----------------------------------------------------------------------
diff --git a/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfigurationFactory.java b/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfigurationFactory.java
new file mode 100644
index 0000000..4fbb645
--- /dev/null
+++ b/server/base/src/main/java/org/apache/accumulo/server/conf/ZooConfigurationFactory.java
@@ -0,0 +1,107 @@
+/*
+ * 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.server.conf;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.zookeeper.ZooUtil;
+import org.apache.accumulo.fate.zookeeper.ZooCache;
+import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
+import org.apache.accumulo.server.Accumulo;
+import org.apache.accumulo.server.fs.VolumeManager;
+import org.apache.accumulo.server.fs.VolumeManagerImpl;
+import org.apache.hadoop.fs.Path;
+
+/**
+ * A factory for {@link ZooConfiguration} objects.
+ */
+class ZooConfigurationFactory {
+  private static final Map<String,ZooConfiguration> instances = new HashMap<String,ZooConfiguration>();
+
+  /**
+   * Gets a configuration object for the given instance with the given parent. Repeated calls will return the same object.
+   *
+   * @param inst
+   *          instance; if null, instance is determined from HDFS
+   * @param zcf
+   *          {@link ZooCacheFactory} for building {@link ZooCache} to contact ZooKeeper (required)
+   * @param parent
+   *          parent configuration (required)
+   * @return configuration
+   */
+  ZooConfiguration getInstance(Instance inst, ZooCacheFactory zcf, AccumuloConfiguration parent) {
+    String instanceId;
+    if (inst == null) {
+      // InstanceID should be the same across all volumes, so just choose one
+      VolumeManager fs;
+      try {
+        fs = VolumeManagerImpl.get();
+      } catch (IOException e) {
+        throw new RuntimeException(e);
+      }
+      Path instanceIdPath = Accumulo.getAccumuloInstanceIdPath(fs);
+      instanceId = ZooUtil.getInstanceIDFromHdfs(instanceIdPath, parent);
+    } else {
+      instanceId = inst.getInstanceID();
+    }
+
+    ZooConfiguration config;
+    synchronized (instances) {
+      config = instances.get(instanceId);
+      if (config == null) {
+        ZooCache propCache;
+        if (inst == null) {
+          propCache = zcf.getZooCache(parent.get(Property.INSTANCE_ZK_HOST), (int) parent.getTimeInMillis(Property.INSTANCE_ZK_TIMEOUT));
+        } else {
+          propCache = zcf.getZooCache(inst.getZooKeepers(), inst.getZooKeepersSessionTimeOut());
+        }
+        config = new ZooConfiguration(instanceId, propCache, parent);
+        instances.put(instanceId, config);
+      }
+    }
+    return config;
+  }
+
+  /**
+   * Gets a configuration object with the given parent. A default instance is used. Repeated calls will return the same object.
+   *
+   * @param parent
+   *          parent configuration (required)
+   * @return configuration
+   */
+  public ZooConfiguration getInstance(AccumuloConfiguration parent) {
+    return getInstance(null, parent);
+  }
+
+  /**
+   * Gets a configuration object for the given instance with the given parent. Repeated calls will return the same object.
+   *
+   * @param inst
+   *          instance; if null, instance is determined from HDFS
+   * @param parent
+   *          parent configuration (required)
+   * @return configuration
+   */
+  public ZooConfiguration getInstance(Instance inst, AccumuloConfiguration parent) {
+    return getInstance(inst, new ZooCacheFactory(), parent);
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/test/java/org/apache/accumulo/server/conf/NamespaceConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/base/src/test/java/org/apache/accumulo/server/conf/NamespaceConfigurationTest.java b/server/base/src/test/java/org/apache/accumulo/server/conf/NamespaceConfigurationTest.java
new file mode 100644
index 0000000..e7f42af
--- /dev/null
+++ b/server/base/src/test/java/org/apache/accumulo/server/conf/NamespaceConfigurationTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.server.conf;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.impl.Namespaces;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.AccumuloConfiguration.AllFilter;
+import org.apache.accumulo.core.conf.AccumuloConfiguration.PropertyFilter;
+import org.apache.accumulo.core.conf.ConfigurationObserver;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.zookeeper.ZooUtil;
+import org.apache.accumulo.fate.zookeeper.ZooCache;
+import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+public class NamespaceConfigurationTest {
+  private static final String NSID = "namespace";
+  private static final String ZOOKEEPERS = "localhost";
+  private static final int ZK_SESSION_TIMEOUT = 120000;
+
+  private String iid;
+  private Instance instance;
+  private AccumuloConfiguration parent;
+  private ZooCacheFactory zcf;
+  private ZooCache zc;
+  private NamespaceConfiguration c;
+
+  @Before
+  public void setUp() {
+    iid = UUID.randomUUID().toString();
+    instance = createMock(Instance.class);
+    parent = createMock(AccumuloConfiguration.class);
+    c = new NamespaceConfiguration(NSID, instance, parent);
+    zcf = createMock(ZooCacheFactory.class);
+    c.setZooCacheFactory(zcf);
+
+    expect(instance.getInstanceID()).andReturn(iid);
+    expectLastCall().anyTimes();
+    expect(instance.getZooKeepers()).andReturn(ZOOKEEPERS);
+    expect(instance.getZooKeepersSessionTimeOut()).andReturn(ZK_SESSION_TIMEOUT);
+    replay(instance);
+    zc = createMock(ZooCache.class);
+    expect(zcf.getZooCache(eq(ZOOKEEPERS), eq(ZK_SESSION_TIMEOUT), anyObject(NamespaceConfWatcher.class))).andReturn(zc);
+    replay(zcf);
+  }
+
+  @Test
+  public void testGetters() {
+    assertEquals(NSID, c.getNamespaceId());
+    assertEquals(parent, c.getParentConfiguration());
+  }
+
+  @Test
+  public void testGet_InZK() {
+    Property p = Property.INSTANCE_SECRET;
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZNAMESPACES + "/" + NSID + Constants.ZNAMESPACE_CONF + "/" + p.getKey())).andReturn(
+        "sekrit".getBytes(Constants.UTF8));
+    replay(zc);
+    assertEquals("sekrit", c.get(Property.INSTANCE_SECRET));
+  }
+
+  @Test
+  public void testGet_InParent() {
+    Property p = Property.INSTANCE_SECRET;
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZNAMESPACES + "/" + NSID + Constants.ZNAMESPACE_CONF + "/" + p.getKey())).andReturn(null);
+    replay(zc);
+    expect(parent.get(p)).andReturn("sekrit");
+    replay(parent);
+    assertEquals("sekrit", c.get(Property.INSTANCE_SECRET));
+  }
+
+  @Test
+  public void testGet_SkipParentIfAccumuloNS() {
+    c = new NamespaceConfiguration(Namespaces.ACCUMULO_NAMESPACE_ID, instance, parent);
+    c.setZooCacheFactory(zcf);
+    Property p = Property.INSTANCE_SECRET;
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZNAMESPACES + "/" + Namespaces.ACCUMULO_NAMESPACE_ID + Constants.ZNAMESPACE_CONF + "/" + p.getKey()))
+        .andReturn(null);
+    replay(zc);
+    assertNull(c.get(Property.INSTANCE_SECRET));
+  }
+
+  @Test
+  public void testGetProperties() {
+    PropertyFilter filter = new AllFilter();
+    Map<String,String> props = new java.util.HashMap<String,String>();
+    parent.getProperties(props, filter);
+    replay(parent);
+    List<String> children = new java.util.ArrayList<String>();
+    children.add("foo");
+    children.add("ding");
+    expect(zc.getChildren(ZooUtil.getRoot(iid) + Constants.ZNAMESPACES + "/" + NSID + Constants.ZNAMESPACE_CONF)).andReturn(children);
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZNAMESPACES + "/" + NSID + Constants.ZNAMESPACE_CONF + "/" + "foo")).andReturn(
+        "bar".getBytes(Constants.UTF8));
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZNAMESPACES + "/" + NSID + Constants.ZNAMESPACE_CONF + "/" + "ding")).andReturn(
+        "dong".getBytes(Constants.UTF8));
+    replay(zc);
+    c.getProperties(props, filter);
+    assertEquals(2, props.size());
+    assertEquals("bar", props.get("foo"));
+    assertEquals("dong", props.get("ding"));
+  }
+
+  @Test
+  public void testObserver() {
+    ConfigurationObserver o = createMock(ConfigurationObserver.class);
+    c.addObserver(o);
+    Collection<ConfigurationObserver> os = c.getObservers();
+    assertEquals(1, os.size());
+    assertTrue(os.contains(o));
+    c.removeObserver(o);
+    os = c.getObservers();
+    assertEquals(0, os.size());
+  }
+
+  @Test
+  public void testInvalidateCache() {
+    // need to do a get so the accessor is created
+    Property p = Property.INSTANCE_SECRET;
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZNAMESPACES + "/" + NSID + Constants.ZNAMESPACE_CONF + "/" + p.getKey())).andReturn(
+        "sekrit".getBytes(Constants.UTF8));
+    zc.clear();
+    replay(zc);
+    c.get(Property.INSTANCE_SECRET);
+    c.invalidateCache();
+    verify(zc);
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/test/java/org/apache/accumulo/server/conf/ServerConfigurationFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/base/src/test/java/org/apache/accumulo/server/conf/ServerConfigurationFactoryTest.java b/server/base/src/test/java/org/apache/accumulo/server/conf/ServerConfigurationFactoryTest.java
new file mode 100644
index 0000000..bb89b04
--- /dev/null
+++ b/server/base/src/test/java/org/apache/accumulo/server/conf/ServerConfigurationFactoryTest.java
@@ -0,0 +1,159 @@
+/*
+ * 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.server.conf;
+
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.DefaultConfiguration;
+import org.apache.accumulo.core.conf.SiteConfiguration;
+import org.apache.accumulo.fate.zookeeper.ZooCache;
+import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.*;
+import org.easymock.Capture;
+import static org.easymock.EasyMock.*;
+
+public class ServerConfigurationFactoryTest {
+  private static final String ZK_HOST = "localhost";
+  private static final int ZK_TIMEOUT = 120000;
+  private static final String IID = "iid";
+
+  // use the same mock ZooCacheFactory and ZooCache for all tests
+  private static ZooCacheFactory zcf;
+  private static ZooCache zc;
+
+  @BeforeClass
+  public static void setUpClass() throws Exception {
+    zcf = createMock(ZooCacheFactory.class);
+    zc = createMock(ZooCache.class);
+    expect(zcf.getZooCache(eq(ZK_HOST), eq(ZK_TIMEOUT), anyObject(NamespaceConfWatcher.class))).andReturn(zc);
+    expectLastCall().anyTimes();
+    expect(zcf.getZooCache(ZK_HOST, ZK_TIMEOUT)).andReturn(zc);
+    expectLastCall().anyTimes();
+    replay(zcf);
+
+    expect(zc.getChildren(anyObject(String.class))).andReturn(null);
+    expectLastCall().anyTimes();
+    // ConfigSanityCheck looks at timeout
+    expect(zc.get(endsWith("timeout"))).andReturn(("" + ZK_TIMEOUT + "ms").getBytes(Constants.UTF8));
+    replay(zc);
+  }
+
+  private Instance instance;
+  private ServerConfigurationFactory scf;
+
+  @Before
+  public void setUp() throws Exception {
+    instance = createMock(Instance.class);
+    expect(instance.getInstanceID()).andReturn(IID);
+    expectLastCall().anyTimes();
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    scf.clearCachedConfigurations();
+  }
+
+  private void mockInstanceForConfig() {
+    expect(instance.getZooKeepers()).andReturn(ZK_HOST);
+    expect(instance.getZooKeepersSessionTimeOut()).andReturn(ZK_TIMEOUT);
+  }
+
+  private void ready() {
+    replay(instance);
+    scf = new ServerConfigurationFactory(instance);
+    scf.setZooCacheFactory(zcf);
+  }
+
+  @Test
+  public void testGetInstance() {
+    ready();
+    assertSame(instance, scf.getInstance());
+  }
+
+  @Test
+  public void testGetDefaultConfiguration() {
+    ready();
+    DefaultConfiguration c = scf.getDefaultConfiguration();
+    assertNotNull(c);
+  }
+
+  @Test
+  public void testGetSiteConfiguration() {
+    ready();
+    SiteConfiguration c = scf.getSiteConfiguration();
+    assertNotNull(c);
+    // TBD: assertTrue(c.getParent() instanceof DefaultConfiguration);
+  }
+
+  @Test
+  public void testGetConfiguration() {
+    mockInstanceForConfig();
+    ready();
+    AccumuloConfiguration c = scf.getConfiguration();
+    assertNotNull(c);
+    // TBD: assertTrue(c.getParent() instanceof SiteConfiguration);
+  }
+
+  private static final String NSID = "NAMESPACE";
+  private static final String TABLE = "TABLE";
+
+  @Test
+  public void testGetNamespaceConfiguration() {
+    mockInstanceForConfig();
+    ready();
+    NamespaceConfiguration c = scf.getNamespaceConfiguration(NSID);
+    assertEquals(NSID, c.getNamespaceId());
+    // TBD: assertTrue(c.getParent() instanceof AccumuloConfiguration);
+
+    assertSame(c, scf.getNamespaceConfiguration(NSID));
+  }
+
+  /*
+   * TBD: need to work around Tables.getNamespaceId() call in constructor
+  @Test
+  public void testGetNamespaceConfigurationForTable() {
+    mockInstanceForConfig();
+    ready();
+    NamespaceConfiguration c = scf.getNamespaceConfigurationForTable(TABLE);
+    assertTrue(c instanceof TableParentConfiguration);
+    assertEquals(TABLE, ((TableParentConfiguration) c).getTableId());
+    // TBD: assertTrue(c.getParent() instanceof AccumuloConfiguration);
+
+    assertSame(c, scf.getNamespaceConfigurationForTable(TABLE));
+  }
+  */
+
+  /*
+   * TBD: ditto
+  @Test
+  public void testGetTableConfiguration() {
+    mockInstanceForConfig();
+    ready();
+    TableConfiguration c = scf.getTableConfiguration(TABLE);
+    assertEquals(TABLE, c.getTableId());
+    // TBD: assertTrue(c.getParent() instanceof TableParentConfiguration);
+
+    assertSame(c, scf.getTableConfiguration(TABLE));
+  }
+  */
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/test/java/org/apache/accumulo/server/conf/TableConfigurationTest.java
----------------------------------------------------------------------
diff --git a/server/base/src/test/java/org/apache/accumulo/server/conf/TableConfigurationTest.java b/server/base/src/test/java/org/apache/accumulo/server/conf/TableConfigurationTest.java
index ae73ba6..b7f27cc 100644
--- a/server/base/src/test/java/org/apache/accumulo/server/conf/TableConfigurationTest.java
+++ b/server/base/src/test/java/org/apache/accumulo/server/conf/TableConfigurationTest.java
@@ -16,28 +16,131 @@
  */
 package org.apache.accumulo.server.conf;
 
-import static org.easymock.EasyMock.createMock;
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertSame;
-
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.client.impl.Namespaces;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.AccumuloConfiguration.AllFilter;
+import org.apache.accumulo.core.conf.AccumuloConfiguration.PropertyFilter;
+import org.apache.accumulo.core.conf.ConfigurationObserver;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.zookeeper.ZooUtil;
+import org.apache.accumulo.fate.zookeeper.ZooCache;
+import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
 import org.junit.Before;
 import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
 
 public class TableConfigurationTest {
-  private static final String INSTANCE_ID = "instanceId";
-  private static final String TABLE = "table";
-  private NamespaceConfiguration nsconf;
-  private TableConfiguration tconf;
+  private static final String TID = "table";
+  private static final String ZOOKEEPERS = "localhost";
+  private static final int ZK_SESSION_TIMEOUT = 120000;
+
+  private String iid;
+  private Instance instance;
+  private NamespaceConfiguration parent;
+  private ZooCacheFactory zcf;
+  private ZooCache zc;
+  private TableConfiguration c;
 
   @Before
-  public void setUp() throws Exception {
-    nsconf = createMock(NamespaceConfiguration.class);
-    tconf = new TableConfiguration(INSTANCE_ID, TABLE, nsconf);
+  public void setUp() {
+    iid = UUID.randomUUID().toString();
+    instance = createMock(Instance.class);
+    parent = createMock(NamespaceConfiguration.class);
+    c = new TableConfiguration(iid, instance, TID, parent);
+    zcf = createMock(ZooCacheFactory.class);
+    c.setZooCacheFactory(zcf);
+
+    expect(instance.getInstanceID()).andReturn(iid);
+    expectLastCall().anyTimes();
+    expect(instance.getZooKeepers()).andReturn(ZOOKEEPERS);
+    expect(instance.getZooKeepersSessionTimeOut()).andReturn(ZK_SESSION_TIMEOUT);
+    replay(instance);
+    zc = createMock(ZooCache.class);
+    expect(zcf.getZooCache(eq(ZOOKEEPERS), eq(ZK_SESSION_TIMEOUT), anyObject(TableConfWatcher.class))).andReturn(zc);
+    replay(zcf);
   }
 
   @Test
   public void testGetters() {
-    assertEquals(TABLE, tconf.getTableId());
-    assertSame(nsconf, tconf.getParentConfiguration());
+    assertEquals(TID, c.getTableId());
+    assertEquals(parent, c.getParentConfiguration());
+  }
+
+  @Test
+  public void testGet_InZK() {
+    Property p = Property.INSTANCE_SECRET;
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZTABLES + "/" + TID + Constants.ZTABLE_CONF + "/" + p.getKey()))
+        .andReturn("sekrit".getBytes(Constants.UTF8));
+    replay(zc);
+    assertEquals("sekrit", c.get(Property.INSTANCE_SECRET));
+  }
+
+  @Test
+  public void testGet_InParent() {
+    Property p = Property.INSTANCE_SECRET;
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZTABLES + "/" + TID + Constants.ZTABLE_CONF + "/" + p.getKey())).andReturn(null);
+    replay(zc);
+    expect(parent.get(p)).andReturn("sekrit");
+    replay(parent);
+    assertEquals("sekrit", c.get(Property.INSTANCE_SECRET));
+  }
+
+  @Test
+  public void testGetProperties() {
+    PropertyFilter filter = new AllFilter();
+    Map<String,String> props = new java.util.HashMap<String,String>();
+    parent.getProperties(props, filter);
+    replay(parent);
+    List<String> children = new java.util.ArrayList<String>();
+    children.add("foo");
+    children.add("ding");
+    expect(zc.getChildren(ZooUtil.getRoot(iid) + Constants.ZTABLES + "/" + TID + Constants.ZTABLE_CONF)).andReturn(children);
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZTABLES + "/" + TID + Constants.ZTABLE_CONF + "/" + "foo")).andReturn("bar".getBytes(Constants.UTF8));
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZTABLES + "/" + TID + Constants.ZTABLE_CONF + "/" + "ding")).andReturn("dong".getBytes(Constants.UTF8));
+    replay(zc);
+    c.getProperties(props, filter);
+    assertEquals(2, props.size());
+    assertEquals("bar", props.get("foo"));
+    assertEquals("dong", props.get("ding"));
+  }
+
+  @Test
+  public void testObserver() {
+    ConfigurationObserver o = createMock(ConfigurationObserver.class);
+    c.addObserver(o);
+    Collection<ConfigurationObserver> os = c.getObservers();
+    assertEquals(1, os.size());
+    assertTrue(os.contains(o));
+    c.removeObserver(o);
+    os = c.getObservers();
+    assertEquals(0, os.size());
+  }
+
+  @Test
+  public void testInvalidateCache() {
+    // need to do a get so the accessor is created
+    Property p = Property.INSTANCE_SECRET;
+    expect(zc.get(ZooUtil.getRoot(iid) + Constants.ZTABLES + "/" + TID + Constants.ZTABLE_CONF + "/" + p.getKey()))
+        .andReturn("sekrit".getBytes(Constants.UTF8));
+    zc.clear();
+    replay(zc);
+    c.get(Property.INSTANCE_SECRET);
+    c.invalidateCache();
+    verify(zc);
   }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/test/java/org/apache/accumulo/server/conf/ZooCachePropertyAccessorTest.java
----------------------------------------------------------------------
diff --git a/server/base/src/test/java/org/apache/accumulo/server/conf/ZooCachePropertyAccessorTest.java b/server/base/src/test/java/org/apache/accumulo/server/conf/ZooCachePropertyAccessorTest.java
new file mode 100644
index 0000000..77e88b1
--- /dev/null
+++ b/server/base/src/test/java/org/apache/accumulo/server/conf/ZooCachePropertyAccessorTest.java
@@ -0,0 +1,188 @@
+/*
+ * 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.server.conf;
+
+import java.nio.charset.Charset;
+import java.util.List;
+import java.util.Map;
+import org.apache.accumulo.core.Constants;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.core.conf.AccumuloConfiguration.PropertyFilter;
+import org.apache.accumulo.core.conf.Property;
+import org.apache.accumulo.core.conf.PropertyType;
+import org.apache.accumulo.fate.zookeeper.ZooCache;
+
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import org.easymock.Capture;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+public class ZooCachePropertyAccessorTest {
+  private static final String PATH = "/root/path/to/props";
+  private static final Property PROP = Property.INSTANCE_SECRET;
+  private static final String KEY = PROP.getKey();
+  private static final String FULL_PATH = PATH + "/" + KEY;
+  private static final String VALUE = "value";
+  private static final byte[] VALUE_BYTES = VALUE.getBytes(Constants.UTF8);
+
+  private ZooCache zc;
+  private ZooCachePropertyAccessor a;
+
+  @Before
+  public void setUp() {
+    zc = createMock(ZooCache.class);
+    a = new ZooCachePropertyAccessor(zc);
+  }
+
+  @Test
+  public void testGetter() {
+    assertSame(zc, a.getZooCache());
+  }
+
+  @Test
+  public void testGet_Valid() {
+    expect(zc.get(PATH + "/" + KEY)).andReturn(VALUE_BYTES);
+    replay(zc);
+    assertEquals(VALUE, a.get(PROP, PATH, null));
+  }
+
+  @Test
+  public void testGet_Parent() {
+    AccumuloConfiguration parent = createMock(AccumuloConfiguration.class);
+    expect(parent.get(PROP)).andReturn(VALUE);
+    replay(parent);
+    expect(zc.get(PATH + "/" + KEY)).andReturn(null);
+    replay(zc);
+    assertEquals(VALUE, a.get(PROP, PATH, parent));
+  }
+
+  @Test
+  public void testGet_Parent_Null() {
+    AccumuloConfiguration parent = createMock(AccumuloConfiguration.class);
+    expect(parent.get(PROP)).andReturn(null);
+    replay(parent);
+    expect(zc.get(PATH + "/" + KEY)).andReturn(null);
+    replay(zc);
+    assertNull(a.get(PROP, PATH, parent));
+  }
+
+  @Test
+  public void testGet_Null_NoParent() {
+    expect(zc.get(PATH + "/" + KEY)).andReturn(null);
+    replay(zc);
+    assertNull(a.get(PROP, PATH, null));
+  }
+
+  @Test
+  public void testGet_InvalidFormat() {
+    Property badProp = Property.MASTER_CLIENTPORT;
+    expect(zc.get(PATH + "/" + badProp.getKey())).andReturn(VALUE_BYTES);
+    replay(zc);
+    AccumuloConfiguration parent = createMock(AccumuloConfiguration.class);
+    expect(parent.get(badProp)).andReturn("12345");
+    replay(parent);
+    assertEquals("12345", a.get(badProp, PATH, parent));
+  }
+
+  @Test
+  public void testGetProperties() {
+    Map<String,String> props = new java.util.HashMap<String,String>();
+    AccumuloConfiguration parent = createMock(AccumuloConfiguration.class);
+    PropertyFilter filter = createMock(PropertyFilter.class);
+    parent.getProperties(props, filter);
+    replay(parent);
+    String child1 = "child1";
+    String child2 = "child2";
+    List<String> children = new java.util.ArrayList<String>();
+    children.add(child1);
+    children.add(child2);
+    expect(zc.getChildren(PATH)).andReturn(children);
+    expect(zc.get(PATH + "/" + child1)).andReturn(VALUE_BYTES);
+    expect(zc.get(PATH + "/" + child2)).andReturn(null);
+    replay(zc);
+    expect(filter.accept(child1)).andReturn(true);
+    expect(filter.accept(child2)).andReturn(true);
+    replay(filter);
+
+    a.getProperties(props, PATH, filter, parent, null);
+    assertEquals(1, props.size());
+    assertEquals(VALUE, props.get(child1));
+    verify(parent);
+  }
+
+  @Test
+  public void testGetProperties_NoChildren() {
+    Map<String,String> props = new java.util.HashMap<String,String>();
+    AccumuloConfiguration parent = createMock(AccumuloConfiguration.class);
+    PropertyFilter filter = createMock(PropertyFilter.class);
+    parent.getProperties(props, filter);
+    replay(parent);
+    expect(zc.getChildren(PATH)).andReturn(null);
+    replay(zc);
+
+    a.getProperties(props, PATH, filter, parent, null);
+    assertEquals(0, props.size());
+  }
+
+  @Test
+  public void testGetProperties_Filter() {
+    Map<String,String> props = new java.util.HashMap<String,String>();
+    AccumuloConfiguration parent = createMock(AccumuloConfiguration.class);
+    PropertyFilter filter = createMock(PropertyFilter.class);
+    parent.getProperties(props, filter);
+    replay(parent);
+    String child1 = "child1";
+    List<String> children = new java.util.ArrayList<String>();
+    children.add(child1);
+    expect(zc.getChildren(PATH)).andReturn(children);
+    replay(zc);
+    expect(filter.accept(child1)).andReturn(false);
+    replay(filter);
+
+    a.getProperties(props, PATH, filter, parent, null);
+    assertEquals(0, props.size());
+  }
+
+  @Test
+  public void testGetProperties_ParentFilter() {
+    Map<String,String> props = new java.util.HashMap<String,String>();
+    AccumuloConfiguration parent = createMock(AccumuloConfiguration.class);
+    PropertyFilter filter = createMock(PropertyFilter.class);
+    PropertyFilter parentFilter = createMock(PropertyFilter.class);
+    parent.getProperties(props, parentFilter);
+    replay(parent);
+    expect(zc.getChildren(PATH)).andReturn(null);
+    replay(zc);
+
+    a.getProperties(props, PATH, filter, parent, parentFilter);
+    verify(parent);
+  }
+
+  @Test
+  public void testInvalidateCache() {
+    zc.clear();
+    replay(zc);
+    a.invalidateCache();
+    verify(zc);
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/d53d45cc/server/base/src/test/java/org/apache/accumulo/server/conf/ZooConfigurationFactoryTest.java
----------------------------------------------------------------------
diff --git a/server/base/src/test/java/org/apache/accumulo/server/conf/ZooConfigurationFactoryTest.java b/server/base/src/test/java/org/apache/accumulo/server/conf/ZooConfigurationFactoryTest.java
new file mode 100644
index 0000000..b54f3e7
--- /dev/null
+++ b/server/base/src/test/java/org/apache/accumulo/server/conf/ZooConfigurationFactoryTest.java
@@ -0,0 +1,66 @@
+/*
+ * 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.server.conf;
+
+import org.apache.accumulo.core.client.Instance;
+import org.apache.accumulo.core.conf.AccumuloConfiguration;
+import org.apache.accumulo.fate.zookeeper.ZooCache;
+import org.apache.accumulo.fate.zookeeper.ZooCacheFactory;
+import org.junit.Before;
+import org.junit.Test;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.verify;
+
+public class ZooConfigurationFactoryTest {
+  private Instance instance;
+  private ZooCacheFactory zcf;
+  private ZooCache zc;
+  private ZooConfigurationFactory zconff;
+  private AccumuloConfiguration parent;
+
+  @Before
+  public void setUp() {
+    instance = createMock(Instance.class);
+    zcf = createMock(ZooCacheFactory.class);
+    zc = createMock(ZooCache.class);
+    zconff = new ZooConfigurationFactory();
+    parent = createMock(AccumuloConfiguration.class);
+  }
+
+  @Test
+  public void testGetInstance() {
+    expect(instance.getInstanceID()).andReturn("iid");
+    expectLastCall().anyTimes();
+    expect(instance.getZooKeepers()).andReturn("localhost");
+    expect(instance.getZooKeepersSessionTimeOut()).andReturn(120000);
+    replay(instance);
+    expect(zcf.getZooCache("localhost", 120000)).andReturn(zc);
+    replay(zcf);
+
+    ZooConfiguration c = zconff.getInstance(instance, zcf, parent);
+    assertNotNull(c);
+    assertSame(c, zconff.getInstance(instance, zcf, parent));
+
+    verify(instance);
+    verify(zcf);
+  }
+}


Mime
View raw message