Moved Schema Aware logic from DataStore to SchemaAwareDataStore adapter 33/3133/2
authorTony Tkacik <ttkacik@cisco.com>
Wed, 27 Nov 2013 14:45:51 +0000 (15:45 +0100)
committerTony Tkacik <ttkacik@cisco.com>
Wed, 27 Nov 2013 17:18:38 +0000 (18:18 +0100)
    All YANG schema logic necessary for proper function of DataStore
    for all components was moved to separate component which
    provides this functionality unified from one place for multiple
    datastores.

Change-Id: I840f752b03e22047e8a7f3d2b7dbe3026fb087c9
Signed-off-by: Tony Tkacik <ttkacik@cisco.com>
15 files changed:
opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/sal/binding/test/AbstractDataServiceTest.java
opendaylight/md-sal/sal-common-api/src/main/java/org/opendaylight/controller/md/sal/common/api/data/DataChangeEvent.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/AbstractDataBroker.xtend
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/DataChangeEventImpl.java
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java [new file with mode: 0644]
opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/data/DataStore.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/config/yang/md/sal/dom/impl/DomBrokerImplModule.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/BrokerConfigActivator.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/DataBrokerImpl.java
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend [deleted file]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/HashMapDataStore.xtend
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend [new file with mode: 0644]
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java [new file with mode: 0644]

index 5b35861e9dd189bbabc2d385a82d0fd6ea5b24fa..9f3a6e8652f8c3d47dc65c2aafce56061d26aace 100644 (file)
@@ -8,6 +8,7 @@ import java.util.Set;
 
 import javassist.ClassPool;
 
+import org.junit.After;
 import org.junit.Before;
 import org.opendaylight.controller.sal.binding.api.data.DataProviderService;
 import org.opendaylight.controller.sal.binding.impl.DataBrokerImpl;
@@ -15,78 +16,96 @@ import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndepende
 import org.opendaylight.controller.sal.binding.impl.connect.dom.BindingIndependentMappingService;
 import org.opendaylight.controller.sal.binding.dom.serializer.impl.RuntimeGeneratedMappingServiceImpl;
 import org.opendaylight.controller.sal.core.api.data.DataBrokerService;
+import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.DataStoreStatsWrapper;
 import org.opendaylight.controller.sal.dom.broker.impl.HashMapDataStore;
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter;
 import org.opendaylight.yangtools.yang.model.api.Module;
 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
 import org.reflections.Reflections;
 import org.reflections.scanners.ResourcesScanner;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import com.google.common.base.Predicate;
 import com.google.common.util.concurrent.ListeningExecutorService;
 import com.google.common.util.concurrent.MoreExecutors;
 
-public  abstract class AbstractDataServiceTest {
+public abstract class AbstractDataServiceTest {
+    private static Logger log = LoggerFactory.getLogger(AbstractDataServiceTest.class);
+
     protected org.opendaylight.controller.sal.core.api.data.DataProviderService biDataService;
     protected DataProviderService baDataService;
-    
+
     /**
      * Workaround for JUNIT sharing classloaders
      * 
      */
     protected static final ClassPool POOL = new ClassPool();
-    
+
     protected RuntimeGeneratedMappingServiceImpl mappingServiceImpl;
     protected BindingIndependentMappingService mappingService;
     protected DataBrokerImpl baDataImpl;
     protected org.opendaylight.controller.sal.dom.broker.DataBrokerImpl biDataImpl;
     protected ListeningExecutorService executor;
     protected BindingIndependentDataServiceConnector connectorServiceImpl;
-    protected HashMapDataStore dataStore;
-    
-    
+    protected HashMapDataStore rawDataStore;
+    private SchemaAwareDataStoreAdapter schemaAwareDataStore;
+    private DataStoreStatsWrapper dataStoreStats;
+
+    protected DataStore dataStore;
+
     @Before
     public void setUp() {
         executor = MoreExecutors.sameThreadExecutor();
         baDataImpl = new DataBrokerImpl();
         baDataService = baDataImpl;
         baDataImpl.setExecutor(executor);
-        
+
         biDataImpl = new org.opendaylight.controller.sal.dom.broker.DataBrokerImpl();
-        biDataService =  biDataImpl;
+        biDataService = biDataImpl;
         biDataImpl.setExecutor(executor);
-        
-        dataStore = new HashMapDataStore();
-        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.builder().toInstance();
+
+        rawDataStore = new HashMapDataStore();
+        schemaAwareDataStore = new SchemaAwareDataStoreAdapter();
+        schemaAwareDataStore.changeDelegate(rawDataStore);
+        dataStoreStats = new DataStoreStatsWrapper(schemaAwareDataStore);
+        dataStore = dataStoreStats;
+
+        org.opendaylight.yangtools.yang.data.api.InstanceIdentifier treeRoot = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
+                .builder().toInstance();
         biDataImpl.registerConfigurationReader(treeRoot, dataStore);
         biDataImpl.registerOperationalReader(treeRoot, dataStore);
         biDataImpl.registerCommitHandler(treeRoot, dataStore);
-        
+
         mappingServiceImpl = new RuntimeGeneratedMappingServiceImpl();
         mappingServiceImpl.setPool(POOL);
         mappingService = mappingServiceImpl;
         File pathname = new File("target/gen-classes-debug");
-        //System.out.println("Generated classes are captured in " + pathname.getAbsolutePath());
+        // System.out.println("Generated classes are captured in " +
+        // pathname.getAbsolutePath());
         mappingServiceImpl.start(null);
-        //mappingServiceImpl.getBinding().setClassFileCapturePath(pathname);
-        
+        // mappingServiceImpl.getBinding().setClassFileCapturePath(pathname);
+
         connectorServiceImpl = new BindingIndependentDataServiceConnector();
         connectorServiceImpl.setBaDataService(baDataService);
         connectorServiceImpl.setBiDataService(biDataService);
         connectorServiceImpl.setMappingService(mappingServiceImpl);
         connectorServiceImpl.start();
-        
-        String[] yangFiles= getModelFilenames();
-        if(yangFiles != null && yangFiles.length > 0) {
-            mappingServiceImpl.onGlobalContextUpdated(getContext(yangFiles));
+
+        String[] yangFiles = getModelFilenames();
+        if (yangFiles != null && yangFiles.length > 0) {
+            SchemaContext context = getContext(yangFiles);
+            mappingServiceImpl.onGlobalContextUpdated(context);
+            schemaAwareDataStore.onGlobalContextUpdated(context);
         }
     }
 
-
-    protected  String[] getModelFilenames() {
+    protected String[] getModelFilenames() {
         return getAllModelFilenames();
     }
-    
+
     public static String[] getAllModelFilenames() {
         Predicate<String> predicate = new Predicate<String>() {
             @Override
@@ -94,11 +113,11 @@ public  abstract class AbstractDataServiceTest {
                 return input.endsWith(".yang");
             }
         };
-        Reflections reflection= new Reflections("META-INF.yang", new ResourcesScanner());
+        Reflections reflection = new Reflections("META-INF.yang", new ResourcesScanner());
         Set<String> result = reflection.getResources(predicate);
         return (String[]) result.toArray(new String[result.size()]);
     }
-    
+
     public static SchemaContext getContext(String[] yangFiles) {
 
         ClassLoader loader = AbstractDataServiceTest.class.getClassLoader();
@@ -114,4 +133,21 @@ public  abstract class AbstractDataServiceTest {
         Set<Module> modules = parser.parseYangModelsFromStreams(streams);
         return parser.resolveSchemaContext(modules);
     }
+
+    @After
+    public void afterTest() {
+
+        log.info("BIDataStore Statistics: Configuration Read Count: {} TotalTime: {} ns AverageTime (ns): {} ns",
+                dataStoreStats.getConfigurationReadCount(), dataStoreStats.getConfigurationReadTotalTime(),
+                dataStoreStats.getConfigurationReadAverageTime());
+
+        log.info("BIDataStore Statistics: Operational Read Count: {} TotalTime: {} ns AverageTime (ns): {} ns",
+                dataStoreStats.getOperationalReadCount(), dataStoreStats.getOperationalReadTotalTime(),
+                dataStoreStats.getOperationalReadAverageTime());
+
+        log.info("BIDataStore Statistics: Request Commit Count: {} TotalTime: {} ns AverageTime (ns): {} ns",
+                dataStoreStats.getRequestCommitCount(), dataStoreStats.getRequestCommitTotalTime(),
+                dataStoreStats.getRequestCommitAverageTime());
+
+    }
 }
index 144a81b2566f549c56e7cbb00bb0e9567db644f2..d62e176e62d1beeb22c934f7c82aa3a713909b91 100644 (file)
@@ -11,15 +11,31 @@ import org.opendaylight.yangtools.concepts.Immutable;
 
 public interface DataChangeEvent<P,D> extends DataChange<P, D>, Immutable {
 
+    /**
+     * Returns a orignal subtree of data, which starts at the path
+     * where listener was registered.
+     * 
+     */
+    D getOriginalConfigurationSubtree();
+
     /**
      * Returns a new subtree of data, which starts at the path
      * where listener was registered.
      * 
      */
+    D getOriginalOperationalSubtree();
+    
+    
+    
+    /**
+     * Returns a updated subtree of data, which starts at the path
+     * where listener was registered.
+     * 
+     */
     D getUpdatedConfigurationSubtree();
 
     /**
-     * Returns a new subtree of data, which starts at the path
+     * Returns a udpated subtree of data, which starts at the path
      * where listener was registered.
      * 
      */
index e3d2b567a71f42b202bf028db6f0d8dcd5f70ae2..a18e5a9c824a675af339d93e02d770e4ccbaf285 100644 (file)
@@ -38,6 +38,7 @@ import org.opendaylight.controller.md.sal.common.api.data.DataCommitHandlerRegis
 import org.opendaylight.controller.md.sal.common.api.RegistrationListener
 import org.opendaylight.yangtools.concepts.util.ListenerRegistry
 import java.util.concurrent.atomic.AtomicLong
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent
 
 abstract class AbstractDataBroker<P extends Path<P>, D, DCL extends DataChangeListener<P, D>> implements DataModificationTransactionFactory<P, D>, //
 DataReader<P, D>, //
@@ -91,6 +92,10 @@ DataProvisionService<P, D> {
     override final def registerDataChangeListener(P path, DCL listener) {
         val reg = new DataChangeListenerRegistration(path, listener, this);
         listeners.put(path, reg);
+        val initialConfig = dataReadRouter.readConfigurationData(path);
+        val initialOperational = dataReadRouter.readOperationalData(path);
+        val event = createInitialListenerEvent(path,initialConfig,initialOperational);
+        listener.onDataChanged(event);
         return reg;
     }
 
@@ -108,6 +113,10 @@ DataProvisionService<P, D> {
         return ret;
     }
     
+    protected  def DataChangeEvent<P,D> createInitialListenerEvent(P path,D initialConfig,D initialOperational) {
+        return new InitialDataChangeEventImpl<P, D>(initialConfig,initialOperational);
+        
+    }
 
     protected final def removeListener(DataChangeListenerRegistration<P, D, DCL> registration) {
         listeners.remove(registration.path, registration);
index 4eb9586fdf94a8b1a1ffa8388f7a699d3fbd60b1..68f9506c56425e29ad91e6b2c42a1fd9059542f1 100644 (file)
@@ -11,6 +11,8 @@ public class DataChangeEventImpl<P, D> implements DataChangeEvent<P, D> {
     private final DataChange<P, D> dataChange;
 
     private final D originalConfigurationSubtree;
+
+
     private final D originalOperationalSubtree;
     private final D updatedOperationalSubtree;
     private final D updatedConfigurationSubtree;
@@ -28,6 +30,16 @@ public class DataChangeEventImpl<P, D> implements DataChangeEvent<P, D> {
         this.updatedConfigurationSubtree = updatedConfigurationSubtree;
     }
 
+    @Override
+    public D getOriginalConfigurationSubtree() {
+        return originalConfigurationSubtree;
+    }
+
+    @Override
+    public D getOriginalOperationalSubtree() {
+        return originalOperationalSubtree;
+    }
+
     @Override
     public D getUpdatedOperationalSubtree() {
         return updatedOperationalSubtree;
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/service/InitialDataChangeEventImpl.java
new file mode 100644 (file)
index 0000000..2764635
--- /dev/null
@@ -0,0 +1,75 @@
+package org.opendaylight.controller.md.sal.common.impl.service;
+
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
+
+public class InitialDataChangeEventImpl<P,D> implements DataChangeEvent<P, D> {
+
+    private final D originalOperationalTree;
+    private final D originalConfigurationTree;
+
+    public InitialDataChangeEventImpl(D configTree, D operTree) {
+        originalConfigurationTree = configTree;
+        originalOperationalTree = operTree;
+    }
+    
+    @Override
+    public Map<P, D> getCreatedConfigurationData() {
+        return Collections.emptyMap();
+    }
+    
+    @Override
+    public Map<P, D> getCreatedOperationalData() {
+        return Collections.emptyMap();
+    }
+    
+    @Override
+    public Map<P, D> getOriginalConfigurationData() {
+        return Collections.emptyMap();
+    }
+    @Override
+    public Map<P, D> getOriginalOperationalData() {
+        return Collections.emptyMap();
+    }
+    @Override
+    public Set<P> getRemovedConfigurationData() {
+        return Collections.emptySet();
+    }
+    @Override
+    public Set<P> getRemovedOperationalData() {
+        return Collections.emptySet();
+    }
+    @Override
+    public Map<P, D> getUpdatedConfigurationData() {
+        return Collections.emptyMap();
+    }
+    
+    @Override
+    public D getUpdatedConfigurationSubtree() {
+        return originalConfigurationTree;
+    }
+    @Override
+    public D getUpdatedOperationalSubtree() {
+        return originalOperationalTree;
+    }
+    
+    @Override
+    public D getOriginalConfigurationSubtree() {
+        return originalConfigurationTree;
+    }
+    
+    @Override
+    public D getOriginalOperationalSubtree() {
+        return originalOperationalTree;
+    }
+    
+    @Override
+    public Map<P, D> getUpdatedOperationalData() {
+        return Collections.emptyMap();
+    }
+    
+
+}
diff --git a/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java b/opendaylight/md-sal/sal-common-impl/src/main/java/org/opendaylight/controller/md/sal/common/impl/util/AbstractLockableDelegator.java
new file mode 100644 (file)
index 0000000..61abe66
--- /dev/null
@@ -0,0 +1,76 @@
+package org.opendaylight.controller.md.sal.common.impl.util;
+
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
+
+import org.opendaylight.yangtools.concepts.Delegator;
+
+import com.google.common.base.Preconditions;
+
+public class AbstractLockableDelegator<T> implements Delegator<T> {
+
+    private final ReentrantReadWriteLock delegateLock = new ReentrantReadWriteLock();
+    private final ReadLock delegateReadLock = delegateLock.readLock();
+    private final WriteLock delegateWriteLock = delegateLock.writeLock();
+    
+    
+    protected Lock getDelegateReadLock() {
+        return delegateReadLock;
+    }
+
+    private T delegate;
+
+    public AbstractLockableDelegator() {
+        // NOOP
+    }
+
+    public AbstractLockableDelegator(T initialDelegate) {
+        delegate = initialDelegate;
+    }
+
+    @Override
+    public T getDelegate() {
+        try {
+            delegateReadLock.lock();
+            return delegate;
+        } finally {
+            delegateReadLock.unlock();
+        }
+    }
+
+    public T retrieveDelegate() {
+        try {
+            delegateReadLock.lock();
+            Preconditions.checkState(delegate != null,"Delegate is null");
+            return delegate;
+        } finally {
+            delegateReadLock.unlock();
+        }
+    }
+
+    /**
+     * 
+     * @param newDelegate
+     * @return oldDelegate
+     */
+    public final T changeDelegate(T newDelegate) {
+        try {
+            delegateWriteLock.lock();
+            T oldDelegate = delegate;
+            delegate = newDelegate;
+            onDelegateChanged(oldDelegate, newDelegate);
+            return oldDelegate;
+        } finally {
+            delegateWriteLock.unlock();
+        }
+    }
+    
+    
+    protected void onDelegateChanged(T oldDelegate, T newDelegate) {
+        // NOOP in abstract calss;
+    }
+}
index 1062f5e5352d82f8fa003431c92561a6633dc62f..87129d68631ba382f0096b604d9c6e6302e14fd7 100644 (file)
@@ -8,5 +8,12 @@ import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
 public interface DataStore extends //
     DataReader<InstanceIdentifier, CompositeNode>,
     DataCommitHandler<InstanceIdentifier, CompositeNode> {
+    
+    
+    Iterable<InstanceIdentifier> getStoredConfigurationPaths();
+    Iterable<InstanceIdentifier> getStoredOperationalPaths();
+    
+    boolean containsConfigurationPath(InstanceIdentifier path);
+    boolean containsOperationalPath(InstanceIdentifier path);
 
 }
index 9a4fc6ddc1f303ba8521667a0604036d592bb74e..050966faa0496a81715388352c0ccefb38fe3567 100644 (file)
@@ -13,6 +13,7 @@ import org.opendaylight.controller.sal.core.api.data.DataStore;
 import org.opendaylight.controller.sal.dom.broker.BrokerConfigActivator;
 import org.opendaylight.controller.sal.dom.broker.BrokerImpl;
 import org.osgi.framework.BundleContext;
+import static com.google.common.base.Preconditions.*;
 
 /**
 *
@@ -33,8 +34,10 @@ public final class DomBrokerImplModule extends org.opendaylight.controller.confi
     @Override
     public void validate(){
         super.validate();
-        // Add custom validation for module attributes here.
+        checkArgument(getDataStore() != null, "Data Store needs to be provided for DomBroker");
     }
+    
+    
 
     @Override
     public java.lang.AutoCloseable createInstance() {
index a6aa0ce32eea75a5aa0498bfe22a9bcf4b0c2169..54c94dca9f83601dfbbd666a49e48476091feb02 100644 (file)
@@ -12,6 +12,7 @@ import java.util.Hashtable
 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 import org.opendaylight.controller.sal.core.api.data.DataStore
+import org.opendaylight.controller.sal.dom.broker.impl.SchemaAwareDataStoreAdapter
 
 class BrokerConfigActivator implements AutoCloseable {
     
@@ -27,6 +28,8 @@ class BrokerConfigActivator implements AutoCloseable {
     private var SchemaServiceImpl schemaService;
     private var DataBrokerImpl dataService;
     private var MountPointManagerImpl mountService;
+    
+    SchemaAwareDataStoreAdapter wrappedStore
 
     public def void start(BrokerImpl broker,DataStore store,BundleContext context) {
         val emptyProperties = new Hashtable<String, String>();
@@ -45,9 +48,13 @@ class BrokerConfigActivator implements AutoCloseable {
         dataReg = context.registerService(DataBrokerService, dataService, emptyProperties);
         dataProviderReg = context.registerService(DataProviderService, dataService, emptyProperties);
 
-        dataService.registerConfigurationReader(ROOT, store);
-        dataService.registerCommitHandler(ROOT, store);
-        dataService.registerOperationalReader(ROOT, store);
+        wrappedStore = new SchemaAwareDataStoreAdapter();
+        wrappedStore.changeDelegate(store);
+        wrappedStore.setValidationEnabled(false);
+        
+        dataService.registerConfigurationReader(ROOT, wrappedStore);
+        dataService.registerCommitHandler(ROOT, wrappedStore);
+        dataService.registerOperationalReader(ROOT, wrappedStore);
         
         mountService = new MountPointManagerImpl();
         mountService.setDataBroker(dataService);
index 1197ef34bd926d2de186931184c70043c5404033..ac5313a9caa99fdaf4fdb5c29fd7690b08e3589c 100644 (file)
@@ -2,6 +2,7 @@ package org.opendaylight.controller.sal.dom.broker;
 
 import java.util.concurrent.atomic.AtomicLong;
 
+import org.opendaylight.controller.md.sal.common.api.data.DataChangeEvent;
 import org.opendaylight.controller.md.sal.common.api.data.DataReader;
 import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataBroker;
 import org.opendaylight.controller.sal.common.DataStoreIdentifier;
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataStoreStatsWrapper.java
new file mode 100644 (file)
index 0000000..9116d50
--- /dev/null
@@ -0,0 +1,137 @@
+package org.opendaylight.controller.sal.dom.broker.impl;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.yangtools.concepts.Delegator;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+
+public class DataStoreStatsWrapper implements Delegator<DataStore>, DataStore {
+
+    private final DataStore delegate;
+
+    private AtomicLong cfgReadCount = new AtomicLong();
+    private AtomicLong cfgReadTimeTotal = new AtomicLong();
+
+    private AtomicLong operReadCount = new AtomicLong();
+    private AtomicLong operReadTimeTotal = new AtomicLong();
+
+    private AtomicLong requestCommitCount = new AtomicLong();
+    private AtomicLong requestCommitTimeTotal = new AtomicLong();
+
+    public DataStoreStatsWrapper(DataStore store) {
+        delegate = store;
+    }
+
+    @Override
+    public DataStore getDelegate() {
+        return delegate;
+    }
+
+    @Override
+    public CompositeNode readConfigurationData(InstanceIdentifier path) {
+        cfgReadCount.incrementAndGet();
+        final long startTime = System.nanoTime();
+        try {
+            return delegate.readConfigurationData(path);
+        } finally {
+            final long endTime = System.nanoTime();
+            final long runTime = endTime - startTime;
+            cfgReadTimeTotal.addAndGet(runTime);
+        }
+    }
+
+    @Override
+    public CompositeNode readOperationalData(InstanceIdentifier path) {
+        operReadCount.incrementAndGet();
+        final long startTime = System.nanoTime();
+        try {
+            return delegate.readOperationalData(path);
+        } finally {
+            final long endTime = System.nanoTime();
+            final long runTime = endTime - startTime;
+            cfgReadTimeTotal.addAndGet(runTime);
+        }
+    }
+
+    public DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
+            DataModification<InstanceIdentifier, CompositeNode> modification) {
+        requestCommitCount.incrementAndGet();
+        final long startTime = System.nanoTime();
+        try {
+            return delegate.requestCommit(modification);
+        } finally {
+            final long endTime = System.nanoTime();
+            final long runTime = endTime - startTime;
+            requestCommitTimeTotal.addAndGet(runTime);
+        }
+    };
+
+    @Override
+    public boolean containsConfigurationPath(InstanceIdentifier path) {
+        return delegate.containsConfigurationPath(path);
+    }
+
+    public Iterable<InstanceIdentifier> getStoredConfigurationPaths() {
+        return delegate.getStoredConfigurationPaths();
+    }
+
+    public Iterable<InstanceIdentifier> getStoredOperationalPaths() {
+        return delegate.getStoredOperationalPaths();
+    }
+
+    public boolean containsOperationalPath(InstanceIdentifier path) {
+        return delegate.containsOperationalPath(path);
+    }
+
+    public final long getConfigurationReadCount() {
+        return cfgReadCount.get();
+    }
+
+    public final long getOperationalReadCount() {
+        return operReadCount.get();
+    }
+
+    public final long getRequestCommitCount() {
+        return requestCommitCount.get();
+    }
+
+    public final long getConfigurationReadTotalTime() {
+        return cfgReadTimeTotal.get();
+    }
+
+    public final long getOperationalReadTotalTime() {
+        return operReadTimeTotal.get();
+    }
+
+    public final long getRequestCommitTotalTime() {
+        return requestCommitTimeTotal.get();
+    }
+
+    public final long getConfigurationReadAverageTime() {
+        long readCount = cfgReadCount.get();
+        if(readCount == 0) {
+            return 0;
+        }
+        return cfgReadTimeTotal.get() / readCount;
+    }
+
+    public final long getOperationalReadAverageTime() {
+        long readCount = operReadCount.get();
+        if(readCount == 0) {
+            return 0;
+        }
+        return operReadTimeTotal.get() / readCount;
+    }
+
+    public final long getRequestCommitAverageTime() {
+        long count = requestCommitCount.get();
+        if(count == 0) {
+            return 0;
+        }
+        return requestCommitTimeTotal.get() / count;
+    }
+
+}
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/DataUtils.xtend
deleted file mode 100644 (file)
index 1a2f947..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-package org.opendaylight.controller.sal.dom.broker.impl
-
-import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import java.util.Map
-import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
-import java.util.Map.Entry
-import java.util.HashSet
-import java.util.ArrayList
-import org.opendaylight.yangtools.yang.data.api.Node
-import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl
-
-class DataUtils {
-
-    static def CompositeNode read(Map<InstanceIdentifier, CompositeNode> map, InstanceIdentifier path) {
-        val root = map.get(path);
-        val childs = map.getChilds(path);
-        if(root === null && childs.empty) {
-            return null;
-        }
-        
-        return merge(path, root, childs);
-    }
-
-    static def CompositeNode merge(InstanceIdentifier path, CompositeNode node,
-        HashSet<Entry<InstanceIdentifier, CompositeNode>> entries) {
-        val it = new ArrayList<Node<?>>();
-        val qname = path.path.last.nodeType;
-        if (node != null) {
-            addAll(node.children);
-        }
-        for (entry : entries) {
-            val nesting = entry.key.path.size - path.path.size;
-            if (nesting === 1) {
-                add(entry.value);
-            }
-        }
-        return new CompositeNodeTOImpl(qname, null, it);
-    }
-
-    static def getChilds(Map<InstanceIdentifier, CompositeNode> map, InstanceIdentifier path) {
-        val it = new HashSet<Entry<InstanceIdentifier, CompositeNode>>();
-        for (entry : map.entrySet) {
-            if (path.contains(entry.key)) {
-                add(entry);
-            }
-        }
-        return it;
-    }
-
-}
index e7445e6965582c90a9401279d37aab18f704f17e..e9ed71a05287982faad6438962b3324c66c5cb6c 100644 (file)
@@ -9,23 +9,41 @@ import org.opendaylight.controller.sal.common.util.Rpcs
 import java.util.Collections
 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier
 import org.opendaylight.yangtools.yang.data.api.CompositeNode
-import static extension org.opendaylight.controller.sal.dom.broker.impl.DataUtils.*;
 import org.opendaylight.controller.sal.core.api.data.DataStore
 import java.util.HashSet
 
 class HashMapDataStore implements DataStore, AutoCloseable {
 
+
     val Map<InstanceIdentifier, CompositeNode> configuration = new ConcurrentHashMap();
     val Map<InstanceIdentifier, CompositeNode> operational = new ConcurrentHashMap();
+    
+    
+    
+    override containsConfigurationPath(InstanceIdentifier path) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+        
+    }
+    
+    override containsOperationalPath(InstanceIdentifier path) {
+        throw new UnsupportedOperationException("TODO: auto-generated method stub")
+    }
+    
+    override getStoredConfigurationPaths() {
+        configuration.keySet
+    }
+    
+    override getStoredOperationalPaths() {
+        operational.keySet
+    }
 
     override readConfigurationData(InstanceIdentifier path) {
-        configuration.read(path);
+        configuration.get(path);
     }
 
     override readOperationalData(InstanceIdentifier path) {
-        operational.read(path);
+        operational.get(path);
     }
-    
 
 
 
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataMerger.xtend
new file mode 100644 (file)
index 0000000..8cdbf92
--- /dev/null
@@ -0,0 +1,13 @@
+package org.opendaylight.controller.sal.dom.broker.impl
+
+import org.opendaylight.yangtools.yang.model.api.SchemaContext
+import org.opendaylight.yangtools.yang.data.api.CompositeNode
+
+class SchemaAwareDataMerger {
+
+    private SchemaContext schema;
+    
+    
+    
+    
+}
\ No newline at end of file
diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/impl/SchemaAwareDataStoreAdapter.java
new file mode 100644 (file)
index 0000000..1f90814
--- /dev/null
@@ -0,0 +1,245 @@
+package org.opendaylight.controller.sal.dom.broker.impl;
+
+import java.awt.PageAttributes.OriginType;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.opendaylight.controller.md.sal.common.api.data.DataModification;
+import org.opendaylight.controller.md.sal.common.api.data.DataReader;
+import org.opendaylight.controller.md.sal.common.impl.util.AbstractLockableDelegator;
+import org.opendaylight.controller.sal.core.api.data.DataStore;
+import org.opendaylight.controller.sal.core.api.model.SchemaServiceListener;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.CompositeNode;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.Node;
+import org.opendaylight.yangtools.yang.data.impl.CompositeNodeTOImpl;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.base.Predicate;
+import com.google.common.collect.FluentIterable;
+
+import static com.google.common.base.Preconditions.*;
+
+public class SchemaAwareDataStoreAdapter extends AbstractLockableDelegator<DataStore> implements //
+        DataStore, //
+        SchemaServiceListener, //
+        AutoCloseable {
+
+    private final static Logger LOG = LoggerFactory.getLogger(SchemaAwareDataStoreAdapter.class);
+
+    private SchemaContext schema = null;
+    private boolean validationEnabled = false;
+    private SchemaAwareDataMerger dataMerger = null;
+    private DataReader<InstanceIdentifier, CompositeNode> reader = new MergeFirstLevelReader();
+
+    @Override
+    public boolean containsConfigurationPath(InstanceIdentifier path) {
+        try {
+            getDelegateReadLock().lock();
+            return getDelegate().containsConfigurationPath(path);
+
+        } finally {
+            getDelegateReadLock().unlock();
+        }
+    }
+
+    @Override
+    public boolean containsOperationalPath(InstanceIdentifier path) {
+        try {
+            getDelegateReadLock().lock();
+            return getDelegate().containsOperationalPath(path);
+
+        } finally {
+            getDelegateReadLock().unlock();
+        }
+    }
+
+    @Override
+    public Iterable<InstanceIdentifier> getStoredConfigurationPaths() {
+        try {
+            getDelegateReadLock().lock();
+            return getDelegate().getStoredConfigurationPaths();
+
+        } finally {
+            getDelegateReadLock().unlock();
+        }
+    }
+
+    @Override
+    public Iterable<InstanceIdentifier> getStoredOperationalPaths() {
+        try {
+            getDelegateReadLock().lock();
+            return getDelegate().getStoredOperationalPaths();
+
+        } finally {
+            getDelegateReadLock().unlock();
+        }
+    }
+
+    @Override
+    public CompositeNode readConfigurationData(InstanceIdentifier path) {
+        return reader.readConfigurationData(path);
+    }
+
+    @Override
+    public CompositeNode readOperationalData(InstanceIdentifier path) {
+        return reader.readOperationalData(path);
+    }
+
+    @Override
+    public org.opendaylight.controller.md.sal.common.api.data.DataCommitHandler.DataCommitTransaction<InstanceIdentifier, CompositeNode> requestCommit(
+            DataModification<InstanceIdentifier, CompositeNode> modification) {
+        validateAgainstSchema(modification);
+        DataModification<InstanceIdentifier, CompositeNode> cleanedUp = prepareMergedTransaction(modification);
+        return retrieveDelegate().requestCommit(cleanedUp);
+    }
+
+    public boolean isValidationEnabled() {
+        return validationEnabled;
+    }
+
+    public void setValidationEnabled(boolean validationEnabled) {
+        this.validationEnabled = validationEnabled;
+    }
+
+    private void validateAgainstSchema(DataModification<InstanceIdentifier, CompositeNode> modification) {
+        if (!validationEnabled) {
+            return;
+        }
+
+        if (schema == null) {
+            LOG.info("Validation not performed for {}. Reason: YANG Schema not present.", modification.getIdentifier());
+            return;
+        }
+    }
+
+    @Override
+    protected void onDelegateChanged(DataStore oldDelegate, DataStore newDelegate) {
+        // NOOP
+    }
+
+    @Override
+    public void onGlobalContextUpdated(SchemaContext context) {
+        this.schema = context;
+    }
+
+    @Override
+    public void close() throws Exception {
+        this.schema = null;
+    }
+
+    private DataModification<InstanceIdentifier, CompositeNode> prepareMergedTransaction(
+            DataModification<InstanceIdentifier, CompositeNode> original) {
+        // NOOP for now
+        return original;
+    }
+
+    private final Comparator<Entry<InstanceIdentifier, CompositeNode>> preparationComparator = new Comparator<Entry<InstanceIdentifier, CompositeNode>>() {
+        @Override
+        public int compare(Entry<InstanceIdentifier, CompositeNode> o1, Entry<InstanceIdentifier, CompositeNode> o2) {
+            InstanceIdentifier o1Key = o1.getKey();
+            InstanceIdentifier o2Key = o2.getKey();
+            return Integer.compare(o1Key.getPath().size(), o2Key.getPath().size());
+        }
+    };
+
+    private class MergeFirstLevelReader implements DataReader<InstanceIdentifier, CompositeNode> {
+
+        @Override
+        public CompositeNode readConfigurationData(final InstanceIdentifier path) {
+            getDelegateReadLock().lock();
+            try {
+                if (path.getPath().isEmpty()) {
+                    return null;
+                }
+                QName qname = null;
+                CompositeNode original = getDelegate().readConfigurationData(path);
+                ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
+                if (original != null) {
+                    childNodes.addAll(original.getChildren());
+                    qname = original.getNodeType();
+                } else {
+                    qname = path.getPath().get(path.getPath().size() - 1).getNodeType();
+                }
+
+                FluentIterable<InstanceIdentifier> directChildren = FluentIterable.from(getStoredConfigurationPaths())
+                        .filter(new Predicate<InstanceIdentifier>() {
+                            @Override
+                            public boolean apply(InstanceIdentifier input) {
+                                if (path.contains(input)) {
+                                    int nesting = input.getPath().size() - path.getPath().size();
+                                    if (nesting == 1) {
+                                        return true;
+                                    }
+                                }
+                                return false;
+                            }
+                        });
+                for (InstanceIdentifier instanceIdentifier : directChildren) {
+                    childNodes.add(getDelegate().readConfigurationData(instanceIdentifier));
+                }
+                if (original == null && childNodes.isEmpty()) {
+                    return null;
+                }
+
+                return new CompositeNodeTOImpl(qname, null, childNodes);
+            } finally {
+                getDelegateReadLock().unlock();
+            }
+        }
+
+        @Override
+        public CompositeNode readOperationalData(final InstanceIdentifier path) {
+            getDelegateReadLock().lock();
+            try {
+                if (path.getPath().isEmpty()) {
+                    return null;
+                }
+                QName qname = null;
+                CompositeNode original = getDelegate().readOperationalData(path);
+                ArrayList<Node<?>> childNodes = new ArrayList<Node<?>>();
+                if (original != null) {
+                    childNodes.addAll(original.getChildren());
+                    qname = original.getNodeType();
+                } else {
+                    qname = path.getPath().get(path.getPath().size() - 1).getNodeType();
+                }
+
+                FluentIterable<InstanceIdentifier> directChildren = FluentIterable.from(getStoredOperationalPaths())
+                        .filter(new Predicate<InstanceIdentifier>() {
+                            @Override
+                            public boolean apply(InstanceIdentifier input) {
+                                if (path.contains(input)) {
+                                    int nesting = input.getPath().size() - path.getPath().size();
+                                    if (nesting == 1) {
+                                        return true;
+                                    }
+                                }
+                                return false;
+                            }
+                        });
+
+                for (InstanceIdentifier instanceIdentifier : directChildren) {
+                    childNodes.add(getDelegate().readOperationalData(instanceIdentifier));
+                }
+                if (original == null && childNodes.isEmpty()) {
+                    return null;
+                }
+
+                return new CompositeNodeTOImpl(qname, null, childNodes);
+            } finally {
+                getDelegateReadLock().unlock();
+            }
+        }
+    }
+}