From: Tony Tkacik Date: Fri, 25 Jul 2014 11:17:52 +0000 (+0000) Subject: Merge "BUG-1381: make users of JavassistUtils.getLock synchronized properly" X-Git-Tag: release/helium~446 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=bc6fe782ce2868db0121defeebe7f006429c1203;hp=1d5ba4a98412a83dc83a6151ef7fea2289f33fdb Merge "BUG-1381: make users of JavassistUtils.getLock synchronized properly" --- diff --git a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTracker.java b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTracker.java index c1ebba7881..eff267ad13 100644 --- a/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTracker.java +++ b/opendaylight/config/config-manager/src/main/java/org/opendaylight/controller/config/manager/impl/osgi/ExtensibleBundleTracker.java @@ -7,6 +7,13 @@ */ package org.opendaylight.controller.config.manager.impl.osgi; +import com.google.common.util.concurrent.ThreadFactoryBuilder; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.ThreadFactory; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleEvent; @@ -15,74 +22,114 @@ import org.osgi.util.tracker.BundleTrackerCustomizer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + /** * - * Extensible bundle tracker. Takes several BundleTrackerCustomizers and propagates bundle events to all of them. - * Primary customizer + * Extensible bundle tracker. Takes several BundleTrackerCustomizers and + * propagates bundle events to all of them. + * + * Primary customizer may return tracking object, + * which will be passed to it during invocation of + * {@link BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Future)} + * + * + * This extender modifies behaviour to not leak platform thread + * in {@link BundleTrackerCustomizer#addingBundle(Bundle, BundleEvent)} + * but deliver this event from its own single threaded executor. + * + * If bundle is removed before event for adding bundle was executed, + * that event is cancelled. If addingBundle event is currently in progress + * or was already executed, platform thread is block untill addingBundle + * finishes so bundle could be removed correctly in platform thread. + * + * + * Method {@link BundleTrackerCustomizer#removedBundle(Bundle, BundleEvent, Object)} + * is never invoked on registered trackers. * * @param */ -public final class ExtensibleBundleTracker extends BundleTracker { +public final class ExtensibleBundleTracker extends BundleTracker> { + private static final ThreadFactory THREAD_FACTORY = new ThreadFactoryBuilder() + .setNameFormat("config-bundle-tracker-%d") + .build(); + private final ExecutorService eventExecutor; private final BundleTrackerCustomizer primaryTracker; private final BundleTrackerCustomizer[] additionalTrackers; - private static final Logger logger = LoggerFactory.getLogger(ExtensibleBundleTracker.class); + private static final Logger LOG = LoggerFactory.getLogger(ExtensibleBundleTracker.class); - public ExtensibleBundleTracker(BundleContext context, BundleTrackerCustomizer primaryBundleTrackerCustomizer, - BundleTrackerCustomizer... additionalBundleTrackerCustomizers) { + public ExtensibleBundleTracker(final BundleContext context, final BundleTrackerCustomizer primaryBundleTrackerCustomizer, + final BundleTrackerCustomizer... additionalBundleTrackerCustomizers) { this(context, Bundle.ACTIVE, primaryBundleTrackerCustomizer, additionalBundleTrackerCustomizers); } - public ExtensibleBundleTracker(BundleContext context, int bundleState, - BundleTrackerCustomizer primaryBundleTrackerCustomizer, - BundleTrackerCustomizer... additionalBundleTrackerCustomizers) { + public ExtensibleBundleTracker(final BundleContext context, final int bundleState, + final BundleTrackerCustomizer primaryBundleTrackerCustomizer, + final BundleTrackerCustomizer... additionalBundleTrackerCustomizers) { super(context, bundleState, null); this.primaryTracker = primaryBundleTrackerCustomizer; this.additionalTrackers = additionalBundleTrackerCustomizers; - logger.trace("Registered as extender with context {} and bundle state {}", context, bundleState); + eventExecutor = Executors.newSingleThreadExecutor(THREAD_FACTORY); + LOG.trace("Registered as extender with context {} and bundle state {}", context, bundleState); } @Override - public T addingBundle(final Bundle bundle, final BundleEvent event) { - T primaryTrackerRetVal = primaryTracker.addingBundle(bundle, event); - - forEachAdditionalBundle(new BundleStrategy() { + public Future addingBundle(final Bundle bundle, final BundleEvent event) { + LOG.trace("Submiting AddingBundle for bundle {} and event {} to be processed asynchronously",bundle,event); + Future future = eventExecutor.submit(new Callable() { @Override - public void execute(BundleTrackerCustomizer tracker) { - tracker.addingBundle(bundle, event); + public T call() throws Exception { + try { + T primaryTrackerRetVal = primaryTracker.addingBundle(bundle, event); + + forEachAdditionalBundle(new BundleStrategy() { + @Override + public void execute(final BundleTrackerCustomizer tracker) { + tracker.addingBundle(bundle, event); + } + }); + LOG.trace("AddingBundle for {} and event {} finished successfully",bundle,event); + return primaryTrackerRetVal; + } catch (Exception e) { + LOG.error("Failed to add bundle {}",e); + throw e; + } } }); - - return primaryTrackerRetVal; + return future; } @Override - public void modifiedBundle(final Bundle bundle, final BundleEvent event, final T object) { - primaryTracker.modifiedBundle(bundle, event, object); - - forEachAdditionalBundle(new BundleStrategy() { - @Override - public void execute(BundleTrackerCustomizer tracker) { - tracker.modifiedBundle(bundle, event, null); - } - }); + public void modifiedBundle(final Bundle bundle, final BundleEvent event, final Future object) { + // Intentionally NOOP } @Override - public void removedBundle(final Bundle bundle, final BundleEvent event, final T object) { - primaryTracker.removedBundle(bundle, event, object); - - forEachAdditionalBundle(new BundleStrategy() { - @Override - public void execute(BundleTrackerCustomizer tracker) { - tracker.removedBundle(bundle, event, null); - } - }); + public void removedBundle(final Bundle bundle, final BundleEvent event, final Future object) { + if(!object.isDone() && object.cancel(false)) { + // We canceled adding event before it was processed + // so it is safe to return + LOG.trace("Adding Bundle event for {} was cancelled. No additional work required.",bundle); + return; + } + try { + LOG.trace("Invoking removedBundle event for {}",bundle); + primaryTracker.removedBundle(bundle, event, object.get()); + forEachAdditionalBundle(new BundleStrategy() { + @Override + public void execute(final BundleTrackerCustomizer tracker) { + tracker.removedBundle(bundle, event, null); + } + }); + LOG.trace("Removed bundle event for {} finished successfully.",bundle); + } catch (InterruptedException | ExecutionException e) { + LOG.error("Addition of bundle failed, ", e); + } } - private void forEachAdditionalBundle(BundleStrategy lambda) { + private void forEachAdditionalBundle(final BundleStrategy lambda) { for (BundleTrackerCustomizer trac : additionalTrackers) { lambda.execute(trac); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java index ed43487df9..619a08eac5 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/DataBroker.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.md.sal.binding.api; import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionChainFactory; +import org.opendaylight.controller.md.sal.common.api.data.TransactionChainListener; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; @@ -34,4 +35,7 @@ public interface DataBroker extends TransactionFactory, AsyncDataBroker registerDataChangeListener(LogicalDatastoreType store, InstanceIdentifier path, DataChangeListener listener, DataChangeScope triggeringScope); + + @Override + BindingTransactionChain createTransactionChain(TransactionChainListener listener); } diff --git a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/WriteTransaction.java b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/WriteTransaction.java index 044a700d84..a6ba2e2799 100644 --- a/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/WriteTransaction.java +++ b/opendaylight/md-sal/sal-binding-api/src/main/java/org/opendaylight/controller/md/sal/binding/api/WriteTransaction.java @@ -22,6 +22,10 @@ public interface WriteTransaction extends AsyncWriteTransaction + * This method does not automatically create missing parent nodes. It is equivalent to invoking + * {@link #put(LogicalDatastoreType, InstanceIdentifier, DataObject, boolean)} + * with createMissingParents set to false. *

* For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}. *

@@ -39,15 +43,50 @@ public interface WriteTransaction extends AsyncWriteTransaction void put(LogicalDatastoreType store, InstanceIdentifier path, T data); + + /** + * Stores a piece of data at the specified path. This acts as an add / + * replace operation, which is to say that whole subtree will be replaced by + * the specified data. + *

+ * For more information on usage and examples, please see the documentation + * in {@link AsyncWriteTransaction}. + *

+ * If you need to make sure that a parent object exists but you do not want + * modify its pre-existing state by using put, consider using {@link #merge} + * instead. + * + * Note: Using createMissingParents with value true, may + * introduce garbage in data store, or recreate nodes, which were deleted by + * previous transaction. + * + * @param store + * the logical data store which should be modified + * @param path + * the data object path + * @param data + * the data object to be written to the specified path + * @param createMissingParents + * if true, any missing parent nodes will be automatically + * created using a merge operation. + * @throws IllegalStateException + * if the transaction has already been submitted + */ + void put(LogicalDatastoreType store, InstanceIdentifier path, T data, + boolean createMissingParents); + /** * Merges a piece of data with the existing data at a specified path. Any pre-existing data * which is not explicitly overwritten will be preserved. This means that if you store a container, * its child lists will be merged. *

+ * This method does not automatically create missing parent nodes. It is equivalent to invoking + * {@link #merge(LogicalDatastoreType, InstanceIdentifier, DataObject, boolean)} + * with createMissingParents set to false. + *

* For more information on usage and examples, please see the documentation in {@link AsyncWriteTransaction}. *

* If you require an explicit replace operation, use {@link #put} instead. - * * @param store * the logical data store which should be modified * @param path @@ -59,6 +98,31 @@ public interface WriteTransaction extends AsyncWriteTransaction void merge(LogicalDatastoreType store, InstanceIdentifier path, T data); + /** + * Merges a piece of data with the existing data at a specified path. Any + * pre-existing data which is not explicitly overwritten will be preserved. + * This means that if you store a container, its child lists will be merged. + *

+ * For more information on usage and examples, please see the documentation + * in {@link AsyncWriteTransaction}. + *

+ * If you require an explicit replace operation, use {@link #put} instead. + * + * @param store + * the logical data store which should be modified + * @param path + * the data object path + * @param data + * the data object to be merged to the specified path + * @param createMissingParents + * if true, any missing parent nodes will be automatically created + * using a merge operation. + * @throws IllegalStateException + * if the transaction has already been submitted + */ + void merge(LogicalDatastoreType store, InstanceIdentifier path, T data, + boolean createMissingParents); + @Override void delete(LogicalDatastoreType store, InstanceIdentifier path); } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractReadWriteTransaction.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractReadWriteTransaction.java index 3988bc6960..44be74b424 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractReadWriteTransaction.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractReadWriteTransaction.java @@ -10,14 +10,12 @@ package org.opendaylight.controller.md.sal.binding.impl; import java.util.ArrayList; import java.util.Iterator; import java.util.List; -import java.util.Map.Entry; import java.util.concurrent.ExecutionException; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; import org.opendaylight.controller.md.sal.dom.api.DOMDataReadWriteTransaction; -import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode; @@ -34,27 +32,8 @@ public class AbstractReadWriteTransaction extends AbstractWriteTransaction path, final DataObject data) { - final Entry> normalized = getCodec() - .toNormalizedNode(path, data); - - final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey(); - ensureParentsByMerge(store, normalizedPath, path); - LOG.debug("Tx: {} : Putting data {}", getDelegate().getIdentifier(), normalizedPath); - doPut(store, path, data); - } - - protected final void doMergeWithEnsureParents(final LogicalDatastoreType store, final InstanceIdentifier path, final DataObject data) { - final Entry> normalized = getCodec() - .toNormalizedNode(path, data); - - final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath = normalized.getKey(); - ensureParentsByMerge(store, normalizedPath, path); - LOG.debug("Tx: {} : Merge data {}", getDelegate().getIdentifier(), normalizedPath); - doMerge(store, path, data); - } - - private final void ensureParentsByMerge(final LogicalDatastoreType store, + @Override + protected final void ensureParentsByMerge(final LogicalDatastoreType store, final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath, final InstanceIdentifier path) { List currentArguments = new ArrayList<>(); diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java index a8eef5a3ca..f8c56f95b3 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/AbstractWriteTransaction.java @@ -30,7 +30,7 @@ import com.google.common.util.concurrent.CheckedFuture; * Abstract Base Transaction for transactions which are backed by * {@link DOMDataWriteTransaction} */ -public class AbstractWriteTransaction extends +public abstract class AbstractWriteTransaction extends AbstractForwardedTransaction { private static final Logger LOG = LoggerFactory.getLogger(AbstractWriteTransaction.class); @@ -40,15 +40,36 @@ public class AbstractWriteTransaction extends super(delegate, codec); } - protected final void doPut(final LogicalDatastoreType store, - final InstanceIdentifier path, final DataObject data) { + + public final void put(final LogicalDatastoreType store, + final InstanceIdentifier path, final U data, final boolean createParents) { final Entry> normalized = getCodec() .toNormalizedNode(path, data); - ensureListParentIfNeeded(store,path,normalized); + if(createParents) { + ensureParentsByMerge(store, normalized.getKey(), path); + } else { + ensureListParentIfNeeded(store,path,normalized); + } getDelegate().put(store, normalized.getKey(), normalized.getValue()); } + public final void merge(final LogicalDatastoreType store, + final InstanceIdentifier path, final U data,final boolean createParents) { + + final Entry> normalized = getCodec() + .toNormalizedNode(path, data); + + if(createParents) { + ensureParentsByMerge(store, normalized.getKey(), path); + } else { + ensureListParentIfNeeded(store,path,normalized); + } + + getDelegate().merge(store, normalized.getKey(), normalized.getValue()); + } + + /** * * Ensures list parent if item is list, otherwise noop. @@ -106,14 +127,16 @@ public class AbstractWriteTransaction extends } } - protected final void doMerge(final LogicalDatastoreType store, - final InstanceIdentifier path, final DataObject data) { - - final Entry> normalized = getCodec() - .toNormalizedNode(path, data); - ensureListParentIfNeeded(store,path,normalized); - getDelegate().merge(store, normalized.getKey(), normalized.getValue()); - } + /** + * Subclasses of this class are required to implement creation of parent + * nodes based on behaviour of their underlying transaction. + * + * @param store + * @param key + * @param path + */ + protected abstract void ensureParentsByMerge(LogicalDatastoreType store, + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier key, InstanceIdentifier path); protected final void doDelete(final LogicalDatastoreType store, final InstanceIdentifier path) { diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java index 29790fb60a..e62b4f736a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/BindingDataWriteTransactionImpl.java @@ -7,15 +7,23 @@ */ package org.opendaylight.controller.md.sal.binding.impl; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.common.api.TransactionStatus; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.controller.md.sal.common.impl.service.AbstractDataTransaction; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationException; +import org.opendaylight.controller.md.sal.common.impl.util.compat.DataNormalizationOperation; import org.opendaylight.controller.md.sal.dom.api.DOMDataWriteTransaction; import org.opendaylight.yangtools.yang.binding.DataObject; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; import org.opendaylight.yangtools.yang.common.RpcResult; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument; + import com.google.common.util.concurrent.CheckedFuture; import com.google.common.util.concurrent.ListenableFuture; @@ -27,15 +35,37 @@ class BindingDataWriteTransactionImpl extends } @Override - public void put(final LogicalDatastoreType store, final InstanceIdentifier path, - final T data) { - doPut(store, path, data); + public void put(final LogicalDatastoreType store, final InstanceIdentifier path, + final U data) { + put(store, path, data,false); } @Override public void merge(final LogicalDatastoreType store, final InstanceIdentifier path, final T data) { - doMerge(store, path, data); + merge(store, path, data,false); + } + + + @Override + protected void ensureParentsByMerge(final LogicalDatastoreType store, + final org.opendaylight.yangtools.yang.data.api.InstanceIdentifier normalizedPath, final InstanceIdentifier path) { + List currentArguments = new ArrayList<>(); + DataNormalizationOperation currentOp = getCodec().getDataNormalizer().getRootOperation(); + Iterator iterator = normalizedPath.getPathArguments().iterator(); + while (iterator.hasNext()) { + PathArgument currentArg = iterator.next(); + try { + currentOp = currentOp.getChild(currentArg); + } catch (DataNormalizationException e) { + throw new IllegalArgumentException(String.format("Invalid child encountered in path %s", path), e); + } + currentArguments.add(currentArg); + org.opendaylight.yangtools.yang.data.api.InstanceIdentifier currentPath = org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.create( + currentArguments); + + getDelegate().merge(store, currentPath, currentOp.createDefault(currentArg)); + } } @Override diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java index 12f26b09bb..a243e6223a 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/md/sal/binding/impl/ForwardedBackwardsCompatibleDataBroker.java @@ -55,6 +55,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; +@SuppressWarnings("deprecation") public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDataBroker implements DataProviderService, AutoCloseable { private static final Logger LOG = LoggerFactory.getLogger(ForwardedBackwardsCompatibleDataBroker.class); @@ -213,10 +214,13 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat @Override public void putOperationalData(final InstanceIdentifier path, final DataObject data) { boolean previouslyRemoved = posponedRemovedOperational.remove(path); + + @SuppressWarnings({ "rawtypes", "unchecked" }) + final InstanceIdentifier castedPath = (InstanceIdentifier) path; if(previouslyRemoved) { - doPutWithEnsureParents(LogicalDatastoreType.OPERATIONAL, path, data); + put(LogicalDatastoreType.OPERATIONAL, castedPath, data,true); } else { - doMergeWithEnsureParents(LogicalDatastoreType.OPERATIONAL, path, data); + merge(LogicalDatastoreType.OPERATIONAL, castedPath, data,true); } } @@ -231,10 +235,12 @@ public class ForwardedBackwardsCompatibleDataBroker extends AbstractForwardedDat created.put(path, data); } updated.put(path, data); + @SuppressWarnings({"rawtypes","unchecked"}) + final InstanceIdentifier castedPath = (InstanceIdentifier) path; if(previouslyRemoved) { - doPutWithEnsureParents(LogicalDatastoreType.CONFIGURATION, path, data); + put(LogicalDatastoreType.CONFIGURATION, castedPath, data,true); } else { - doMergeWithEnsureParents(LogicalDatastoreType.CONFIGURATION, path, data); + merge(LogicalDatastoreType.CONFIGURATION, castedPath, data,true); } } diff --git a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedBindingBrokerImpl.java b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedBindingBrokerImpl.java index 8c74008990..e1f8c6c652 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedBindingBrokerImpl.java +++ b/opendaylight/md-sal/sal-binding-broker/src/main/java/org/opendaylight/controller/sal/binding/impl/forward/DomForwardedBindingBrokerImpl.java @@ -18,7 +18,7 @@ import org.opendaylight.yangtools.yang.data.impl.codec.DeserializationException; import org.opendaylight.controller.sal.core.api.Broker.ProviderSession; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; -import org.opendaylight.controller.sal.core.api.mount.MountProvisionService.MountProvisionListener; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; diff --git a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java index b577e2af1f..b504837d67 100644 --- a/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java +++ b/opendaylight/md-sal/sal-binding-broker/src/test/java/org/opendaylight/controller/md/sal/binding/impl/test/WriteTransactionTest.java @@ -7,12 +7,16 @@ */ package org.opendaylight.controller.md.sal.binding.impl.test; +import static org.junit.Assert.assertTrue; + import java.util.concurrent.ExecutionException; import org.junit.Test; +import org.opendaylight.controller.md.sal.binding.api.ReadOnlyTransaction; import org.opendaylight.controller.md.sal.binding.api.WriteTransaction; import org.opendaylight.controller.md.sal.binding.test.AbstractDataBrokerTest; import org.opendaylight.controller.md.sal.common.api.data.LogicalDatastoreType; +import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.Top; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.TopBuilder; import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelList; @@ -20,19 +24,49 @@ import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controll import org.opendaylight.yang.gen.v1.urn.opendaylight.params.xml.ns.yang.controller.md.sal.test.list.rev140701.two.level.list.TopLevelListKey; import org.opendaylight.yangtools.yang.binding.InstanceIdentifier; +import com.google.common.base.Optional; + public class WriteTransactionTest extends AbstractDataBrokerTest { private static final InstanceIdentifier TOP_PATH = InstanceIdentifier.create(Top.class); private static final TopLevelListKey TOP_LIST_KEY = new TopLevelListKey("foo"); private static final InstanceIdentifier NODE_PATH = TOP_PATH.child(TopLevelList.class, TOP_LIST_KEY); - + private static final TopLevelList NODE = new TopLevelListBuilder().setKey(TOP_LIST_KEY).build(); @Test public void test() throws InterruptedException, ExecutionException { WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); writeTx.put(LogicalDatastoreType.OPERATIONAL, TOP_PATH, new TopBuilder().build()); - writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, new TopLevelListBuilder().setKey(TOP_LIST_KEY).build()); + writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, NODE); writeTx.submit().get(); } + @Test + public void testPutCreateParentsSuccess() throws TransactionCommitFailedException, InterruptedException, ExecutionException { + + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.put(LogicalDatastoreType.OPERATIONAL, NODE_PATH, NODE,true); + writeTx.submit().checkedGet(); + + ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + Optional topNode = readTx.read(LogicalDatastoreType.OPERATIONAL, TOP_PATH).get(); + assertTrue("Top node must exists after commit",topNode.isPresent()); + Optional listNode = readTx.read(LogicalDatastoreType.OPERATIONAL, NODE_PATH).get(); + assertTrue("List node must exists after commit",listNode.isPresent()); + } + + @Test + public void testMergeCreateParentsSuccess() throws TransactionCommitFailedException, InterruptedException, ExecutionException { + + WriteTransaction writeTx = getDataBroker().newWriteOnlyTransaction(); + writeTx.merge(LogicalDatastoreType.OPERATIONAL, NODE_PATH, NODE,true); + writeTx.submit().checkedGet(); + + ReadOnlyTransaction readTx = getDataBroker().newReadOnlyTransaction(); + Optional topNode = readTx.read(LogicalDatastoreType.OPERATIONAL, TOP_PATH).get(); + assertTrue("Top node must exists after commit",topNode.isPresent()); + Optional listNode = readTx.read(LogicalDatastoreType.OPERATIONAL, NODE_PATH).get(); + assertTrue("List node must exists after commit",listNode.isPresent()); + } + } diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMMountPointService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMMountPointService.java index 96020c6d97..3155bd50ab 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMMountPointService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/md/sal/dom/api/DOMMountPointService.java @@ -9,6 +9,8 @@ package org.opendaylight.controller.md.sal.dom.api; import org.opendaylight.controller.sal.core.api.BrokerService; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.ObjectRegistration; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -22,6 +24,7 @@ public interface DOMMountPointService extends BrokerService { DOMMountPointBuilder createMountPoint(InstanceIdentifier path); + ListenerRegistration registerProvisionListener(MountProvisionListener listener); public interface DOMMountPointBuilder { diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionListener.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionListener.java new file mode 100644 index 0000000000..64851472e6 --- /dev/null +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionListener.java @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v1.0 which accompanies this distribution, + * and is available at http://www.eclipse.org/legal/epl-v10.html. + */ + +package org.opendaylight.controller.sal.core.api.mount; + +import java.util.EventListener; +import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; + +public interface MountProvisionListener extends EventListener { + + void onMountPointCreated(InstanceIdentifier path); + + void onMountPointRemoved(InstanceIdentifier path); + +} diff --git a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionService.java b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionService.java index cb32603048..807b020b72 100644 --- a/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionService.java +++ b/opendaylight/md-sal/sal-dom-api/src/main/java/org/opendaylight/controller/sal/core/api/mount/MountProvisionService.java @@ -7,8 +7,6 @@ */ package org.opendaylight.controller.sal.core.api.mount; -import java.util.EventListener; - import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; @@ -27,11 +25,4 @@ public interface MountProvisionService extends MountService { ListenerRegistration registerProvisionListener(MountProvisionListener listener); - public interface MountProvisionListener extends EventListener { - - void onMountPointCreated(InstanceIdentifier path); - - void onMountPointRemoved(InstanceIdentifier path); - - } } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java index 49a499709e..cdb78fc592 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/md/sal/dom/broker/impl/mount/DOMMountPointServiceImpl.java @@ -15,7 +15,10 @@ import org.opendaylight.controller.md.sal.dom.api.DOMMountPoint; import org.opendaylight.controller.md.sal.dom.api.DOMMountPointService; import org.opendaylight.controller.md.sal.dom.api.DOMService; import org.opendaylight.controller.md.sal.dom.broker.spi.mount.SimpleDOMMountPoint; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; +import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.ObjectRegistration; +import org.opendaylight.yangtools.concepts.util.ListenerRegistry; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; import org.opendaylight.yangtools.yang.model.api.SchemaContext; @@ -28,6 +31,8 @@ public class DOMMountPointServiceImpl implements DOMMountPointService { private final Map mountPoints = new HashMap<>(); + private final ListenerRegistry listeners = ListenerRegistry.create(); + @Override public Optional getMountPoint(final InstanceIdentifier path) { return Optional.fromNullable(mountPoints.get(path)); @@ -39,11 +44,27 @@ public class DOMMountPointServiceImpl implements DOMMountPointService { return new DOMMountPointBuilderImpl(path); } + public void notifyMountCreated(final InstanceIdentifier identifier) { + for (final ListenerRegistration listener : listeners + .getListeners()) { + listener.getInstance().onMountPointCreated(identifier); + } + } + + @Override + public ListenerRegistration registerProvisionListener( + final MountProvisionListener listener) { + return listeners.register(listener); + } + public ObjectRegistration registerMountPoint(final SimpleDOMMountPoint mountPoint) { synchronized (mountPoints) { Preconditions.checkState(!mountPoints.containsKey(mountPoint.getIdentifier()), "Mount point already exists"); mountPoints.put(mountPoint.getIdentifier(), mountPoint); } + notifyMountCreated(mountPoint.getIdentifier()); + + // FIXME this shouldnt be null return null; } diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointManagerImpl.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointManagerImpl.java index 20f79eea71..ac2ab04bbe 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointManagerImpl.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/MountPointManagerImpl.java @@ -14,6 +14,7 @@ import java.util.concurrent.ConcurrentMap; import org.opendaylight.controller.sal.core.api.data.DataProviderService; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.concepts.util.ListenerRegistry; diff --git a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/MountProviderServiceProxy.java b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/MountProviderServiceProxy.java index 24d5430d6d..2669f1279e 100644 --- a/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/MountProviderServiceProxy.java +++ b/opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/osgi/MountProviderServiceProxy.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.sal.dom.broker.osgi; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; import org.opendaylight.yangtools.concepts.ListenerRegistration; import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier; diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/DocProvider.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/DocProvider.java index 31f4253318..9a1816b90e 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/DocProvider.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/DocProvider.java @@ -16,7 +16,7 @@ import org.opendaylight.controller.sal.core.api.Broker; import org.opendaylight.controller.sal.core.api.Provider; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; -import org.opendaylight.controller.sal.core.api.mount.MountProvisionService.MountProvisionListener; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; import org.opendaylight.controller.sal.rest.doc.impl.ApiDocGenerator; import org.opendaylight.controller.sal.rest.doc.mountpoints.MountPointSwagger; import org.opendaylight.yangtools.concepts.ListenerRegistration; diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/mountpoints/MountPointSwagger.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/mountpoints/MountPointSwagger.java index fcabb088f4..20e0fa56a7 100644 --- a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/mountpoints/MountPointSwagger.java +++ b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/mountpoints/MountPointSwagger.java @@ -23,7 +23,7 @@ import javax.ws.rs.core.UriInfo; import org.opendaylight.controller.sal.core.api.model.SchemaService; import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance; import org.opendaylight.controller.sal.core.api.mount.MountProvisionService; -import org.opendaylight.controller.sal.core.api.mount.MountProvisionService.MountProvisionListener; +import org.opendaylight.controller.sal.core.api.mount.MountProvisionListener; import org.opendaylight.controller.sal.rest.doc.impl.BaseYangSwaggerGenerator; import org.opendaylight.controller.sal.rest.doc.swagger.Api; import org.opendaylight.controller.sal.rest.doc.swagger.ApiDeclaration;