+++ /dev/null
-/*
- * 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.md.sal.dom.store.impl;
-
-import com.google.common.base.Preconditions;
-
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
-import org.opendaylight.yangtools.util.concurrent.NotificationManager;
-import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
-import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-class ChangeListenerNotifyTask implements Runnable {
- private static final Logger LOG = LoggerFactory.getLogger(ChangeListenerNotifyTask.class);
-
- @SuppressWarnings("rawtypes")
- private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr;
- private final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event;
- private final DataChangeListenerRegistration<?> listener;
-
- @SuppressWarnings("rawtypes")
- public ChangeListenerNotifyTask(final DataChangeListenerRegistration<?> listener,
- final AsyncDataChangeEvent<YangInstanceIdentifier, NormalizedNode<?, ?>> event,
- final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
- this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
- this.listener = Preconditions.checkNotNull(listener);
- this.event = Preconditions.checkNotNull(event);
- }
-
- @Override
- public void run() {
- final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> l = listener.getInstance();
- if (l == null) {
- LOG.trace("Skipping event delivery to unregistered listener {}", l);
- return;
- }
- LOG.trace("Listener {} event {}", l, event);
-
- // FIXME: Yo dawg I heard you like queues, so this was queued to be queued
- notificationMgr.submitNotification(l, event);
- }
-
- @Override
- public String toString() {
- return "ChangeListenerNotifyTask [listener=" + listener + ", event=" + event + "]";
- }
-}
*/
package org.opendaylight.controller.md.sal.dom.store.impl;
+import static com.google.common.base.Preconditions.checkState;
+
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.ListeningExecutorService;
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import javax.annotation.concurrent.GuardedBy;
+
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
import org.opendaylight.controller.md.sal.common.api.data.OptimisticLockFailedException;
import org.opendaylight.controller.md.sal.common.api.data.TransactionCommitFailedException;
import org.opendaylight.controller.md.sal.dom.store.impl.SnapshotBackedWriteTransaction.TransactionReadyPrototype;
-import org.opendaylight.yangtools.util.ExecutorServiceUtil;
-import org.opendaylight.yangtools.util.concurrent.NotificationManager;
-import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
-import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
-import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
import org.opendaylight.controller.sal.core.spi.data.DOMStore;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadTransaction;
import org.opendaylight.controller.sal.core.spi.data.DOMStoreReadWriteTransaction;
import org.opendaylight.yangtools.concepts.AbstractListenerRegistration;
import org.opendaylight.yangtools.concepts.Identifiable;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.util.ExecutorServiceUtil;
+import org.opendaylight.yangtools.util.concurrent.NotificationManager;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager;
+import org.opendaylight.yangtools.util.concurrent.QueuedNotificationManager.Invoker;
import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.ConflictingModificationAppliedException;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTree;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeCandidate;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeModification;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataTreeSnapshot;
+import org.opendaylight.yangtools.yang.data.api.schema.tree.DataValidationFailedException;
+import org.opendaylight.yangtools.yang.data.impl.schema.tree.InMemoryDataTreeFactory;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaContextListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import javax.annotation.concurrent.GuardedBy;
-
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicLong;
-
-import static com.google.common.base.Preconditions.checkState;
-
/**
* In-memory DOM Data Store
*
public class InMemoryDOMDataStore implements DOMStore, Identifiable<String>, SchemaContextListener,
TransactionReadyPrototype,AutoCloseable {
private static final Logger LOG = LoggerFactory.getLogger(InMemoryDOMDataStore.class);
+ private static final ListenableFuture<Void> SUCCESSFUL_FUTURE = Futures.immediateFuture(null);
- @SuppressWarnings("rawtypes")
- private static final QueuedNotificationManager.Invoker<AsyncDataChangeListener,
- AsyncDataChangeEvent> DCL_NOTIFICATION_MGR_INVOKER =
- new QueuedNotificationManager.Invoker<AsyncDataChangeListener,
- AsyncDataChangeEvent>() {
-
- @SuppressWarnings("unchecked")
+ private static final Invoker<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> DCL_NOTIFICATION_MGR_INVOKER =
+ new Invoker<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent>() {
@Override
- public void invokeListener( AsyncDataChangeListener listener,
- AsyncDataChangeEvent notification ) {
- listener.onDataChanged(notification);
+ public void invokeListener(final DataChangeListenerRegistration<?> listener,
+ final DOMImmutableDataChangeEvent notification ) {
+ final AsyncDataChangeListener<YangInstanceIdentifier, NormalizedNode<?, ?>> inst = listener.getInstance();
+ if (inst != null) {
+ inst.onDataChanged(notification);
+ }
}
};
private final AtomicLong txCounter = new AtomicLong(0);
private final ListeningExecutorService listeningExecutor;
- @SuppressWarnings("rawtypes")
- private final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent>
- dataChangeListenerNotificationManager;
+ private final NotificationManager<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> dataChangeListenerNotificationManager;
private final ExecutorService dataChangeListenerExecutor;
private final String name;
}
public InMemoryDOMDataStore(final String name, final ListeningExecutorService listeningExecutor,
- final ExecutorService dataChangeListenerExecutor, int maxDataChangeListenerQueueSize) {
+ final ExecutorService dataChangeListenerExecutor, final int maxDataChangeListenerQueueSize) {
this.name = Preconditions.checkNotNull(name);
this.listeningExecutor = Preconditions.checkNotNull(listeningExecutor);
-
this.dataChangeListenerExecutor = Preconditions.checkNotNull(dataChangeListenerExecutor);
dataChangeListenerNotificationManager =
.addCreated(path, data) //
.build();
- new ChangeListenerNotifyTask(reg, event,
- dataChangeListenerNotificationManager).run();
+ dataChangeListenerNotificationManager.submitNotification(reg, event);
}
}
}
public synchronized void onTransactionCommited(final SnapshotBackedWriteTransaction transaction) {
- // If commited transaction is latestOutstandingTx we clear
+ // If committed transaction is latestOutstandingTx we clear
// latestOutstandingTx
// field in order to base new transactions on Datastore Data Tree
// directly.
@Override
public Void call() {
candidate = dataTree.prepare(modification);
- listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree,
- dataChangeListenerNotificationManager);
+ listenerResolver = ResolveDataChangeEventsTask.create(candidate, listenerTree);
return null;
}
});
@Override
public ListenableFuture<Void> abort() {
candidate = null;
- return Futures.immediateFuture(null);
+ return SUCCESSFUL_FUTURE;
}
@Override
*/
synchronized (this) {
dataTree.commit(candidate);
-
- for (ChangeListenerNotifyTask task : listenerResolver.call()) {
- LOG.trace("Scheduling invocation of listeners: {}", task);
- task.run();
- }
+ listenerResolver.resolve(dataChangeListenerNotificationManager);
}
- return Futures.immediateFuture(null);
+ return SUCCESSFUL_FUTURE;
}
}
}
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Map.Entry;
-import java.util.concurrent.Callable;
import org.opendaylight.controller.md.sal.common.api.data.AsyncDataBroker.DataChangeScope;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeEvent;
-import org.opendaylight.controller.md.sal.common.api.data.AsyncDataChangeListener;
import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.Builder;
import org.opendaylight.controller.md.sal.dom.store.impl.DOMImmutableDataChangeEvent.SimpleEventFactory;
import org.opendaylight.controller.md.sal.dom.store.impl.tree.ListenerTree;
* Computes data change events for all affected registered listeners in data
* tree.
*/
-final class ResolveDataChangeEventsTask implements Callable<Iterable<ChangeListenerNotifyTask>> {
+final class ResolveDataChangeEventsTask {
private static final Logger LOG = LoggerFactory.getLogger(ResolveDataChangeEventsTask.class);
- @SuppressWarnings("rawtypes")
- private final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr;
private final DataTreeCandidate candidate;
private final ListenerTree listenerRoot;
private Multimap<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> collectedEvents;
- @SuppressWarnings("rawtypes")
- public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree,
- final NotificationManager<AsyncDataChangeListener, AsyncDataChangeEvent> notificationMgr) {
+ public ResolveDataChangeEventsTask(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
this.candidate = Preconditions.checkNotNull(candidate);
this.listenerRoot = Preconditions.checkNotNull(listenerTree);
- this.notificationMgr = Preconditions.checkNotNull(notificationMgr);
}
/**
- * Resolves and creates Notification Tasks
- *
- * Implementation of done as Map-Reduce with two steps: 1. resolving events
- * and their mapping to listeners 2. merging events affecting same listener
- *
- * @return An {@link Iterable} of Notification Tasks which needs to be executed in
- * order to delivery data change events.
+ * Resolves and submits notification tasks to the specified manager.
*/
- @Override
- public synchronized Iterable<ChangeListenerNotifyTask> call() {
+ public synchronized void resolve(final NotificationManager<DataChangeListenerRegistration<?>, DOMImmutableDataChangeEvent> manager) {
try (final Walker w = listenerRoot.getWalker()) {
// Defensive: reset internal state
collectedEvents = ArrayListMultimap.create();
* Convert to tasks, but be mindful of multiple values -- those indicate multiple
* wildcard matches, which need to be merged.
*/
- final Collection<ChangeListenerNotifyTask> ret = new ArrayList<>();
for (Entry<DataChangeListenerRegistration<?>, Collection<DOMImmutableDataChangeEvent>> e : collectedEvents.asMap().entrySet()) {
final Collection<DOMImmutableDataChangeEvent> col = e.getValue();
final DOMImmutableDataChangeEvent event;
event = col.iterator().next();
}
- ret.add(new ChangeListenerNotifyTask(e.getKey(), event, notificationMgr));
+ manager.submitNotification(e.getKey(), event);
}
-
- // FIXME: so now we have tasks to submit tasks... Inception-style!
- LOG.debug("Created tasks {}", ret);
- return ret;
}
}
return scope != null;
}
- @SuppressWarnings("rawtypes")
- public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate,
- final ListenerTree listenerTree,
- final NotificationManager<AsyncDataChangeListener,AsyncDataChangeEvent> notificationMgr) {
- return new ResolveDataChangeEventsTask(candidate, listenerTree, notificationMgr);
+ public static ResolveDataChangeEventsTask create(final DataTreeCandidate candidate, final ListenerTree listenerTree) {
+ return new ResolveDataChangeEventsTask(candidate, listenerTree);
}
}
QName childNode = NetconfMessageTransformUtil.IETF_NETCONF_MONITORING_SCHEMA_FORMAT.withoutRevision();
- final String formatAsString = getSingleChildNodeValue(schemaNode, childNode).get();
+ String formatAsString = getSingleChildNodeValue(schemaNode, childNode).get();
+ //This is HotFix for situations where format statement in netconf-monitoring might be passed with prefix.
+ if (formatAsString.contains(":")) {
+ String[] prefixedString = formatAsString.split(":");
+ //FIXME: might be good idea to check prefix against model namespace
+ formatAsString = prefixedString[1];
+ }
if(formatAsString.equals(Yang.QNAME.getLocalName()) == false) {
logger.debug("{}: Ignoring schema due to unsupported format: {}", id, formatAsString);
return Optional.absent();
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.net.URI;
+import java.util.Iterator;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
}
-
+ boolean isDataRoot = false;
URI initialNs = null;
outputWriter.write('{');
- if (!SchemaPath.ROOT.equals(path)) {
+ if (SchemaPath.ROOT.equals(path)) {
+ isDataRoot = true;
+ } else {
path = path.getParent();
// FIXME: Add proper handling of reading root.
}
- if(data instanceof MapEntryNode) {
- data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).withChild(((MapEntryNode) data)).build();
- }
if(!schema.isAugmenting() && !(schema instanceof SchemaContext)) {
initialNs = schema.getQName().getNamespace();
}
NormalizedNodeStreamWriter jsonWriter = JSONNormalizedNodeStreamWriter.create(context.getSchemaContext(),path,initialNs,outputWriter);
NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(jsonWriter);
- nnWriter.write(data);
+ if(isDataRoot) {
+ writeDataRoot(outputWriter,nnWriter,(ContainerNode) data);
+ } else {
+ if(data instanceof MapEntryNode) {
+ data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).withChild(((MapEntryNode) data)).build();
+ }
+ nnWriter.write(data);
+ }
nnWriter.flush();
-
outputWriter.write('}');
outputWriter.flush();
}
+ private void writeDataRoot(OutputStreamWriter outputWriter, NormalizedNodeWriter nnWriter, ContainerNode data) throws IOException {
+ Iterator<DataContainerChild<? extends PathArgument, ?>> iterator = data.getValue().iterator();
+ while(iterator.hasNext()) {
+ DataContainerChild<? extends PathArgument, ?> child = iterator.next();
+ nnWriter.write(child);
+ nnWriter.flush();
+ if(iterator.hasNext()) {
+ outputWriter.write(",");
+ }
+ }
+ }
+
}
*/
package org.opendaylight.controller.sal.rest.impl;
+import com.google.common.base.Throwables;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import org.opendaylight.controller.sal.restconf.impl.InstanceIdentifierContext;
import org.opendaylight.controller.sal.restconf.impl.NormalizedNodeContext;
import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.data.api.schema.ContainerNode;
+import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
import org.opendaylight.yangtools.yang.data.api.schema.MapEntryNode;
import org.opendaylight.yangtools.yang.data.api.schema.NormalizedNode;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeWriter;
import org.opendaylight.yangtools.yang.data.impl.codec.xml.XMLStreamNormalizedNodeStreamWriter;
import org.opendaylight.yangtools.yang.data.impl.schema.ImmutableNodes;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
import org.opendaylight.yangtools.yang.model.api.SchemaPath;
@Provider
@Produces({ Draft02.MediaTypes.API + RestconfService.XML, Draft02.MediaTypes.DATA + RestconfService.XML,
- Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
-
+ Draft02.MediaTypes.OPERATION + RestconfService.XML, MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public class NormalizedNodeXmlBodyWriter implements MessageBodyWriter<NormalizedNodeContext> {
-
private static final XMLOutputFactory XML_FACTORY;
static {
- XML_FACTORY = XMLOutputFactory.newFactory();
+ XML_FACTORY = XMLOutputFactory.newFactory();
XML_FACTORY.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
}
-
@Override
- public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
+ public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations,
+ final MediaType mediaType) {
return type.equals(NormalizedNodeContext.class);
}
@Override
- public long getSize(final NormalizedNodeContext t, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
+ public long getSize(final NormalizedNodeContext t, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType) {
return -1;
}
@Override
- public void writeTo(final NormalizedNodeContext t, final Class<?> type, final Type genericType, final Annotation[] annotations,
- final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
- throws IOException, WebApplicationException {
+ public void writeTo(final NormalizedNodeContext t, final Class<?> type, final Type genericType,
+ final Annotation[] annotations, final MediaType mediaType,
+ final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream) throws IOException,
+ WebApplicationException {
InstanceIdentifierContext pathContext = t.getInstanceIdentifierContext();
if (t.getData() == null) {
throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
throw new IllegalStateException(e);
}
NormalizedNode<?, ?> data = t.getData();
- SchemaPath schemaPath = pathContext.getSchemaNode().getPath().getParent();
- if(data instanceof MapEntryNode) {
- data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).addChild((MapEntryNode) data).build();
- //schemaPath = pathContext.getSchemaNode().getPath();
+ SchemaPath schemaPath = pathContext.getSchemaNode().getPath();
+
+ boolean isDataRoot = false;
+ if (SchemaPath.ROOT.equals(schemaPath)) {
+ isDataRoot = true;
+ } else {
+ schemaPath = schemaPath.getParent();
}
- NormalizedNodeStreamWriter jsonWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,pathContext.getSchemaContext(),schemaPath);
+ NormalizedNodeStreamWriter jsonWriter = XMLStreamNormalizedNodeStreamWriter.create(xmlWriter,
+ pathContext.getSchemaContext(), schemaPath);
NormalizedNodeWriter nnWriter = NormalizedNodeWriter.forStreamWriter(jsonWriter);
+ if (isDataRoot) {
+ writeRootElement(xmlWriter, nnWriter, (ContainerNode) data);
+ } else {
+ if (data instanceof MapEntryNode) {
+ // Restconf allows returning one list item. We need to wrap it
+ // in map node in order to serialize it properly
+ data = ImmutableNodes.mapNodeBuilder(data.getNodeType()).addChild((MapEntryNode) data).build();
+ }
+ nnWriter.write(data);
+ nnWriter.flush();
+ }
+ }
- nnWriter.write(data);
- nnWriter.flush();
+ private void writeRootElement(XMLStreamWriter xmlWriter, NormalizedNodeWriter nnWriter, ContainerNode data)
+ throws IOException {
+ try {
+ QName name = SchemaContext.NAME;
+ xmlWriter.writeStartElement(name.getNamespace().toString(), name.getLocalName());
+ for (DataContainerChild<? extends PathArgument, ?> child : data.getValue()) {
+ nnWriter.write(child);
+ }
+ nnWriter.flush();
+ xmlWriter.writeEndElement();
+ xmlWriter.flush();
+ } catch (XMLStreamException e) {
+ Throwables.propagate(e);
+ }
}
}