ovsdb.listenPort=6640
# ovsdb creates Openflow nodes/bridges. This configuration configures the bridge's Openflow version.
-# default Openflow version = 1.0, we also support 1.3.
-# ovsdb.of.version=1.3
+# default Openflow version = 1.3, we also support 1.0.
+ovsdb.of.version=1.3
# TLS configuration
# To enable TLS, set secureChannelEnabled=true and specify the location of controller Java KeyStore and TrustStore files.
import org.opendaylight.yangtools.yang.binding.Notification;
/**
- * Interface implemented by objects interested in some sort of Notification. This
- * class acts as a base interface for specific listeners which usually are a type
+ * Interface for a generic listener that is interested in receiving YANG modeled notifications.
+ * This interface acts as a base interface for specific listeners which usually are a type
* capture of this interface.
*
- * @param <T> Notification type
+ * @param <T> the interested notification type
*/
public interface NotificationListener<T extends Notification> extends EventListener {
/**
- * Invoked to deliver the notification. Note that this method may be invoked
- * from a shared thread pool, so implementations SHOULD NOT perform CPU-intensive
- * operations and they definitely MUST NOT invoke any potentially blocking
- * operations.
+ * Invoked to deliver a notification.
+ * <p>
+ * Note that this method may be invoked from a shared thread pool, so implementations SHOULD NOT
+ * perform CPU-intensive operations and MUST NOT invoke any potentially blocking operations.
*
- * @param notification Notification being delivered.
+ * @param notification the notification.
*/
void onNotification(T notification);
}
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.Notification;
+/**
+ * Interface for a notification service that provides publish/subscribe capabilities for YANG
+ * modeled notifications. This interface is a combination of the {@link NotificationService} and
+ * {@link NotificationPublishService} interfaces.
+ */
public interface NotificationProviderService extends NotificationService, NotificationPublishService<Notification> {
+
/**
- * Publishes a notification.
- *
- * @param Notification
- * notification to publish.
- *
+ * {@inheritDoc}
*/
@Override
- void publish(Notification notification);
+ public void publish(Notification notification);
/**
- * Publishes a notification, listener calls are done in provided executor.
- *
+ * {@inheritDoc}
*/
@Override
- void publish(Notification notification, ExecutorService service);
+ void publish(Notification notification, ExecutorService executor);
+ /**
+ * Registers a listener to be notified about notification subscriptions. This
+ * enables a component to know when there is a notification listener subscribed
+ * for a particular notification type.
+ * <p>
+ * On registration of this listener, the
+ * {@link NotificationInterestListener#onNotificationSubscribtion(Class)} method
+ * will be invoked for every notification type that currently has a notification listener
+ * subscribed.
+ *
+ * @param interestListener the listener that will be notified when subscriptions
+ * for new notification types occur.
+ * @return a {@link ListenerRegistration} instance that should be used to unregister the listener
+ * by invoking the {@link ListenerRegistration#close()} method when no longer needed.
+ */
ListenerRegistration<NotificationInterestListener> registerInterestListener(
NotificationInterestListener interestListener);
+ /**
+ * Interface for a listener interested in being notified about notification subscriptions.
+ */
public interface NotificationInterestListener extends EventListener {
+ /**
+ * Callback that is invoked when a notification listener subscribes for a
+ * particular notification type.
+ * <p>
+ * This method is only called for the first subscription that occurs for a
+ * particular notification type. Subsequent subscriptions for the same
+ * notification type do not trigger invocation of this method.
+ * <p>
+ * <b>Note:</b>This callback is delivered from thread not owned by this listener,
+ * all processing should be as fast as possible and implementations should
+ * not do any blocking calls or block this thread.
+ *
+ * @param notificationType the notification type for the subscription that occurred.
+ */
void onNotificationSubscribtion(Class<? extends Notification> notificationType);
}
}
import org.opendaylight.yangtools.concepts.ListenerRegistration;
import org.opendaylight.yangtools.yang.binding.Notification;
+/**
+ * Notification broker which allows clients to subscribe for and publish YANG-modeled notifications.
+ *
+ *<p>
+ * Two styles of listeners are supported:
+ * <ul>
+ * <li>Generic listener</li>
+ * <li>Dispatch listener - listener, which implements <code>{ModelName}Listener</code> interface,
+ * which has dispatch methods for each defined notification. Methods are invoked based on notification type (class).
+ * </li>
+ *
+ * <h3>Generic Listener</h3>
+ * <p>
+ * A generic listener implements the {@link NotificationListener} interface which has one callback method
+ * <code>onNotification</code> that is invoked for any notification type the listener is subscribed to.
+ * <p>
+ * A generic listener is subscribed using the {@link #registerNotificationListener(Class, NotificationListener)}
+ * method by which you specify the type of notification to receive. A generic listener may be registered for
+ * multiple notification types via multiple subscriptions.
+ * <p>
+ * Generic listeners allow for a more flexible approach, allowing you to subscribe for just
+ * one type of notification from a YANG model. You could also have a general subscription
+ * for all notification in the system via
+ * <pre>
+ * service.registerNotificationListener(Notification.class, listener);
+ * </pre>
+ *
+ * <h3>Dispatch Listener</h3>
+ * <p>
+ * A dispatch listener implements a YANG-generated module interface <code>{ModuleName}Listener</code>
+ * which handles all the notifications defined in the YANG model. Each notification type translates to
+ * a specific method of the form <code>on{NotificationType}</code> on the generated interface.
+ * The generated interface also extends the
+ * {@link org.opendaylight.yangtools.yang.binding.NotificationListener} interface and implementations
+ * are registered using {@link #registerNotificationListener(org.opendaylight.yangtools.yang.binding.NotificationListener)}
+ * method.
+ *
+ * <h5>Dispatch Listener Example</h5>
+ * <p>
+ * Lets assume we have following YANG model:
+ *
+ * <pre>
+ * module example {
+ * ...
+ *
+ * notification start {
+ * ...
+ * }
+ *
+ * notification stop {
+ * ...
+ * }
+ * }
+ * </pre>
+ *
+ * The generated interface will be:
+ * <pre>
+ * public interface ExampleListener extends NotificationListener {
+ * void onStart(Start notification);
+ * void onStop(Stop notification);
+ * }
+ * </pre>
+ * The following defines an implementation of the generated interface:
+ * <pre>
+ * public class MyExampleListener implements ExampleListener {
+ * public void onStart(Start notification) {
+ * // do something
+ * }
+ *
+ * public void onStop(Stop notification) {
+ * // do something
+ * }
+ * }
+ * </pre>
+ * The implementation is registered as follows:
+ * <pre>
+ * MyExampleListener listener = new MyExampleListener();
+ * ListenerRegistration<NotificationListener> reg = service.registerNotificationListener( listener );
+ * </pre>
+ * The <code>onStart</code> method will be invoked when someone publishes a <code>Start</code> notification and
+ * the <code>onStop</code> method will be invoked when someone publishes a <code>Stop</code> notification.
+ */
public interface NotificationService extends BindingAwareService {
/**
- * Register a generic listener for specified notification type only.
+ * Registers a generic listener implementation for a specified notification type.
*
- * @param notificationType
- * @param listener
- * @return Registration for listener. To unregister listener invoke {@link ListenerRegistration#close()} method.
+ * @param notificationType the YANG-generated interface of the notification type.
+ * @param listener the listener implementation that will receive notifications.
+ * @return a {@link ListenerRegistration} instance that should be used to unregister the listener
+ * by invoking the {@link ListenerRegistration#close()} method when no longer needed.
*/
<T extends Notification> ListenerRegistration<NotificationListener<T>> registerNotificationListener(
Class<T> notificationType, NotificationListener<T> listener);
/**
- * Register a listener which implements generated notification interfaces derived from
+ * Registers a listener which implements a YANG-generated notification interface derived from
* {@link org.opendaylight.yangtools.yang.binding.NotificationListener}.
- * Listener is registered for all notifications present in implemented interfaces.
+ * The listener is registered for all notifications present in the implemented interface.
*
- * @param listener
- * @return Registration for listener. To unregister listener invoke {@link ListenerRegistration#close()} method.
+ * @param listener the listener implementation that will receive notifications.
+ * @return a {@link ListenerRegistration} instance that should be used to unregister the listener
+ * by invoking the {@link ListenerRegistration#close()} method when no longer needed.
*/
ListenerRegistration<org.opendaylight.yangtools.yang.binding.NotificationListener> registerNotificationListener(
org.opendaylight.yangtools.yang.binding.NotificationListener listener);
+++ /dev/null
-/*
- * Copyright (c) 2013 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.binding.codegen.impl;
-
-public class BrokerImplClassLoader extends ClassLoader {
- private final ClassLoader spiClassLoader;
-
- public BrokerImplClassLoader(final ClassLoader model, final ClassLoader spi) {
- super(model);
- this.spiClassLoader = spi;
- }
-
- @Override
- public Class<? extends Object> loadClass(final String name) throws ClassNotFoundException {
- try {
- return super.loadClass(name);
- } catch (ClassNotFoundException e) {
- return this.spiClassLoader.loadClass(name);
- }
- }
-}
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
-import com.google.common.base.Optional;
import org.opendaylight.controller.md.sal.binding.impl.AbstractForwardedDataBroker;
import org.opendaylight.controller.md.sal.common.api.RegistrationListener;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.core.api.data.DataModificationTransaction;
import org.opendaylight.controller.sal.core.api.notify.NotificationListener;
import org.opendaylight.controller.sal.core.api.notify.NotificationPublishService;
+import org.opendaylight.yangtools.concepts.CompositeObjectRegistration;
+import org.opendaylight.yangtools.concepts.CompositeObjectRegistration.CompositeObjectRegistrationBuilder;
import org.opendaylight.yangtools.concepts.ListenerRegistration;
+import org.opendaylight.yangtools.concepts.ObjectRegistration;
import org.opendaylight.yangtools.concepts.Registration;
import org.opendaylight.yangtools.yang.binding.Augmentable;
import org.opendaylight.yangtools.yang.binding.Augmentation;
import org.slf4j.LoggerFactory;
import com.google.common.base.Function;
+import com.google.common.base.Optional;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSet.Builder;
public void onRegister(
final DataCommitHandlerRegistration<InstanceIdentifier<? extends DataObject>, DataObject> registration) {
- org.opendaylight.yangtools.yang.data.api.InstanceIdentifier domPath = mappingService.toDataDom(registration
+ mappingService.toDataDom(registration
.getPath());
}
}
@Override
- public void onRpcImplementationAdded(QName name) {
+ public void onRpcImplementationAdded(final QName name) {
final Optional<Class<? extends RpcService>> rpcInterface = mappingService.getRpcServiceClassFor(
name.getNamespace().toString(), name.getFormattedRevision());
}
@Override
- public void onRpcImplementationRemoved(QName name) {
+ public void onRpcImplementationRemoved(final QName name) {
}
}
private final Map<QName, RpcInvocationStrategy> strategiesByQName = new HashMap<>();
private final WeakHashMap<Method, RpcInvocationStrategy> strategiesByMethod = new WeakHashMap<>();
private final RpcService proxy;
+ private ObjectRegistration<?> forwarderRegistration;
public DomToBindingRpcForwarder(final Class<? extends RpcService> service) {
this.rpcServiceType = new WeakReference<Class<? extends RpcService>>(service);
}
+ /**
+ * Registers RPC Forwarder to DOM Broker,
+ * this means Binding Aware Broker has implementation of RPC
+ * which is registered to it.
+ *
+ * If RPC Forwarder was previously registered to DOM Broker
+ * or to Bidning Broker this method is noop to prevent
+ * creating forwarding loop.
+ *
+ */
public void registerToDOMBroker() {
- try {
- for (QName rpc : supportedRpcs) {
- biRpcRegistry.addRpcImplementation(rpc, this);
+ if(forwarderRegistration == null) {
+ CompositeObjectRegistrationBuilder<DomToBindingRpcForwarder> builder = CompositeObjectRegistration.builderFor(this);
+ try {
+ for (QName rpc : supportedRpcs) {
+ builder.add(biRpcRegistry.addRpcImplementation(rpc, this));
+ }
+ } catch (Exception e) {
+ LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
}
- } catch (Exception e) {
- LOG.error("Could not forward Rpcs of type {}", rpcServiceType.get(), e);
+ this.forwarderRegistration = builder.toInstance();
}
}
});
}
+ /**
+ * Registers RPC Forwarder to Binding Broker,
+ * this means DOM Broekr has implementation of RPC
+ * which is registered to it.
+ *
+ * If RPC Forwarder was previously registered to DOM Broker
+ * or to Bidning Broker this method is noop to prevent
+ * creating forwarding loop.
+ *
+ */
public void registerToBidningBroker() {
- baRpcRegistry.addRpcImplementation((Class)rpcServiceType.get(), proxy);
+ if(forwarderRegistration == null) {
+ try {
+ this.forwarderRegistration = baRpcRegistry.addRpcImplementation((Class)rpcServiceType.get(), proxy);
+ } catch (Exception e) {
+ LOG.error("Unable to forward RPCs for {}",rpcServiceType.get(),e);
+ }
+ }
}
}
+++ /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.sal.binding.impl.connect.dom;
-
-public class CompositeNodeUtils {
-
-}
+++ /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.sal.binding.impl.connect.dom;
-
-public class Constants {
- public static final Class<byte[]> BYTES_CLASS = byte[].class;
-}
+++ /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.sal.binding.impl.connect.dom;
-
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-
-import org.opendaylight.controller.md.sal.common.api.data.DataModification;
-import org.opendaylight.yangtools.concepts.Path;
-
-public final class DataModificationTracker<P extends Path<P>,D> {
- ConcurrentMap<Object, DataModification<P,D>> trackedTransactions = new ConcurrentHashMap<>();
-
- public void startTrackingModification(DataModification<P,D> modification) {
- trackedTransactions.putIfAbsent(modification.getIdentifier(), modification);
- }
-
- public boolean containsIdentifier(Object identifier) {
- return trackedTransactions.containsKey(identifier);
- }
-}
+++ /dev/null
-/*
- * Copyright (c) 2013 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.binding.impl;
\ No newline at end of file
+++ /dev/null
-/*
- * Copyright (c) 2013 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.binding.spi;
-
-public interface DelegateProxy<T> {
-
- void setDelegate(T delegate);
- T getDelegate();
-}
+++ /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.sal.binding.spi.remote;
-
-import org.opendaylight.yangtools.concepts.ListenerRegistration;
-
-public interface RemoteRpcRouter {
-
-
-
-
-
-
- ListenerRegistration<RouteChangeListener> registerRouteChangeListener(RouteChangeListener listener);
-
-
-
-
-}
+++ /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.sal.binding.spi.remote;
-
-import java.util.EventListener;
-
-import org.opendaylight.controller.md.sal.common.api.routing.RouteChange;
-import org.opendaylight.yangtools.yang.binding.BaseIdentity;
-import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
-
-public interface RouteChangeListener extends EventListener {
-
- void onRouteChange(RouteChange<Class<? extends BaseIdentity>, InstanceIdentifier<?>> change);
-
-}
import java.util.concurrent.ExecutorService;
+/**
+ * Interface for publishing YANG-modeled notifications.
+ * <p>
+ * Users of this interface can publish any YANG-modeled notification which will
+ * be delivered to all subscribed listeners.
+ * <p>
+ * Prefered way of publishing of notifications is done by invoking {@link #publish(Object)}.
+ *
+ * <p>You may consider using {@link #publish(Object, ExecutorService)} if and only if
+ * your use-case requires customized execution policy or run-to-completion
+ * inside process.
+ *
+ * <p>
+ * The metadata required to deliver a notification to the correct listeners is
+ * extracted from the published notification.
+ *
+ *
+ * FIXME: Consider clarification of execution/delivery policy, how it will be
+ * affected by Actor model and cluster-wide notifications.
+ *
+ * @param <N>
+ * the type of notifications
+ */
public interface NotificationPublishService<N> {
+ /**
+ * Publishes a notification and notifies subscribed listeners. All listener
+ * notifications are done via a default executor.
+ * <p>
+ * <b>Note:</b> This call will block when the default executor is saturated
+ * and the notification queue for this executor is full.
+ *
+ * @param notification
+ * the notification to publish.
+ */
void publish(N notification);
- void publish(N notification,ExecutorService executor);
+ /**
+ * Publishes a notification and notifies subscribed listeners. All listener
+ * notifications are done via the provided executor.
+ * <p>
+ * <b>Note:</b> Use only if ineccessary. Consider using
+ * {@link #publish(Object)} for most use-cases.
+ *
+ * <p>
+ * By using this method you could customize execution policy of listeners present
+ * inside process (e.g. using single-threaded executor or even same-thread executor
+ * delivery.
+ *
+ * <p>
+ * This executor is used only for inside-process notification deliveries.
+ *
+ * @param notification
+ * the notification to publish.
+ * @param executor
+ * the executor that will be used to deliver notifications to
+ * subscribed listeners.
+ */
+ void publish(N notification, ExecutorService executor);
}
+++ /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.sal.compability;
-
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.inventory.rev130819.FlowCapableNodeConnector;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.flow.types.port.rev130925.PortFeatures;
-import org.opendaylight.yang.gen.v1.urn.opendaylight.inventory.rev130819.node.NodeConnector;
-
-public class ToSalPropertyClassUtils {
- public static Bandwidth salAdvertisedBandwidthFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
- PortFeatures portFeatures = flowCapNodeConn.getAdvertisedFeatures();
- return new AdvertisedBandwidth(resolveBandwidth(portFeatures));
- }
-
- public static Bandwidth salPeerBandwidthFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
- PortFeatures portFeatures = flowCapNodeConn.getPeerFeatures();
- return new PeerBandwidth(resolveBandwidth(portFeatures));
- }
-
- public static Bandwidth salSupportedBandwidthFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
- PortFeatures portFeatures = flowCapNodeConn.getSupported();
- return new SupportedBandwidth(resolveBandwidth(portFeatures));
- }
-
- public static MacAddress salMacAddressFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
- String hwAddress = flowCapNodeConn.getHardwareAddress().getValue();
- return new MacAddress(bytesFrom(hwAddress));
- }
-
-
- public static Name salNameFrom(NodeConnector nodeConnector) {
- FlowCapableNodeConnector flowCapNodeConn = nodeConnector.getAugmentation(FlowCapableNodeConnector.class);
- return new Name(flowCapNodeConn.getName());
- }
-
-
-
- private static byte[] bytesFrom(String hwAddress) {
- String[] mac = hwAddress.split(":");
- byte[] macAddress = new byte[6]; // mac.length == 6 bytes
- for (int i = 0; i < mac.length; i++) {
- macAddress[i] = Integer.decode("0x" + mac[i]).byteValue();
- }
- return macAddress;
- }
-
- private static long resolveBandwidth(PortFeatures portFeatures) {
- if (portFeatures.is_1tbFd()) {
- return Bandwidth.BW1Tbps;
- } else if (portFeatures.is_100gbFd()) {
- return Bandwidth.BW100Gbps;
- } else if (portFeatures.is_40gbFd()) {
- return Bandwidth.BW40Gbps;
- } else if (portFeatures.is_10gbFd()) {
- return Bandwidth.BW10Gbps;
- } else if (portFeatures.is_1gbHd() || portFeatures.is_1gbFd()) {
- return Bandwidth.BW1Gbps;
- } else if (portFeatures.is_100mbHd() || portFeatures.is_100mbFd()) {
- return Bandwidth.BW100Mbps;
- } else if (portFeatures.is_10mbHd() || portFeatures.is_10mbFd()) {
- return Bandwidth.BW10Mbps;
- } else {
- return Bandwidth.BWUNK;
- }
- }
-
-}
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.DefaultValue;
+import javax.ws.rs.Encoded;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
-import javax.ws.rs.Encoded;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
-
import org.opendaylight.controller.sal.restconf.impl.StructuredData;
import org.opendaylight.yangtools.yang.data.api.CompositeNode;
/**
- * The URI hierarchy for the RESTCONF resources consists of an entry
- * point container, 4 top-level resources, and 1 field.
- * <ul>
- * <li><b>/restconf</b> - {@link #getRoot()}
- * <ul>
- * <li><b>/config</b> - {@link #readConfigurationData(String)}
- * {@link #updateConfigurationData(String, CompositeNode)}
- * {@link #createConfigurationData(CompositeNode)}
- * {@link #createConfigurationData(String, CompositeNode)}
- * {@link #deleteConfigurationData(String)}
- * <li><b>/operational</b> - {@link #readOperationalData(String)}
- * <li>/modules - {@link #getModules()}
- * <ul>
- * <li>/module
- * </ul>
- * <li><b>/operations</b> - {@link #invokeRpc(String, CompositeNode)}
- * {@link #invokeRpc(String, CompositeNode)}
- * <li>/version (field)
- * </ul>
- * </ul>
+ * The URI hierarchy for the RESTCONF resources consists of an entry point
+ * container, 4 top-level resources, and 1 field.
+ * <ul>
+ * <li><b>/restconf</b> - {@link #getRoot()}
+ * <ul>
+ * <li><b>/config</b> - {@link #readConfigurationData(String)}
+ * {@link #updateConfigurationData(String, CompositeNode)}
+ * {@link #createConfigurationData(CompositeNode)}
+ * {@link #createConfigurationData(String, CompositeNode)}
+ * {@link #deleteConfigurationData(String)}
+ * <li><b>/operational</b> - {@link #readOperationalData(String)}
+ * <li>/modules - {@link #getModules()}
+ * <ul>
+ * <li>/module
+ * </ul>
+ * <li><b>/operations</b> - {@link #invokeRpc(String, CompositeNode)}
+ * {@link #invokeRpc(String, CompositeNode)}
+ * <li>/version (field)
+ * </ul>
+ * </ul>
*/
@Path("/")
public interface RestconfService {
@GET
@Path("/modules")
- @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData getModules();
+ @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData getModules(@Context UriInfo uriInfo);
@GET
@Path("/modules/{identifier:.+}")
- @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData getModules(@PathParam("identifier") String identifier);
+ @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData getModules(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
@GET
@Path("/modules/module/{identifier:.+}")
- @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData getModule(@PathParam("identifier") String identifier);
+ @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData getModule(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
@GET
@Path("/operations")
- @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData getOperations();
+ @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData getOperations(@Context UriInfo uriInfo);
@GET
@Path("/operations/{identifier:.+}")
- @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData getOperations(@PathParam("identifier") String identifier);
+ @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData getOperations(@PathParam("identifier") String identifier, @Context UriInfo uriInfo);
@POST
@Path("/operations/{identifier:.+}")
- @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
- Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- @Consumes({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
- Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
+ @Produces({ Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + XML,
+ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ @Consumes({ Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + XML,
+ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, CompositeNode payload, @Context UriInfo uriInfo);
@POST
@Path("/operations/{identifier:.+}")
- @Produces({Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+XML,
- Draft02.MediaTypes.DATA+JSON, Draft02.MediaTypes.DATA+XML,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier, @DefaultValue("") String noPayload);
+ @Produces({ Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + XML,
+ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData invokeRpc(@Encoded @PathParam("identifier") String identifier,
+ @DefaultValue("") String noPayload, @Context UriInfo uriInfo);
@GET
@Path("/config/{identifier:.+}")
- @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ @Produces({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public StructuredData readConfigurationData(@Encoded @PathParam("identifier") String identifier,
- @Context UriInfo depth);
+ @Context UriInfo uriInfo);
@GET
@Path("/operational/{identifier:.+}")
- @Produces({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData readOperationalData(@Encoded @PathParam("identifier") String identifier,
- @Context UriInfo depth);
+ @Produces({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData readOperationalData(@Encoded @PathParam("identifier") String identifier, @Context UriInfo uriInfo);
@PUT
@Path("/config/{identifier:.+}")
- @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public Response updateConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
@POST
@Path("/config/{identifier:.+}")
- @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public Response createConfigurationData(@Encoded @PathParam("identifier") String identifier, CompositeNode payload);
@POST
@Path("/config")
- @Consumes({Draft02.MediaTypes.DATA+JSON,Draft02.MediaTypes.DATA+XML,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
+ @Consumes({ Draft02.MediaTypes.DATA + JSON, Draft02.MediaTypes.DATA + XML, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
public Response createConfigurationData(CompositeNode payload);
@DELETE
@GET
@Path("/streams")
- @Produces({Draft02.MediaTypes.API+XML, Draft02.MediaTypes.API+JSON,
- MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, MediaType.TEXT_XML})
- public StructuredData getAvailableStreams();
-
+ @Produces({ Draft02.MediaTypes.API + XML, Draft02.MediaTypes.API + JSON, MediaType.APPLICATION_JSON,
+ MediaType.APPLICATION_XML, MediaType.TEXT_XML })
+ public StructuredData getAvailableStreams(@Context UriInfo uriInfo);
}
import com.google.common.base.Charsets;
import com.google.gson.stream.JsonWriter;
-
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
-
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.ws.rs.ext.Provider;
-
import org.opendaylight.controller.sal.rest.api.Draft02;
import org.opendaylight.controller.sal.rest.api.RestconfService;
import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
@Override
public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
- return type.equals( StructuredData.class );
+ return type.equals(StructuredData.class);
}
@Override
}
JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8));
- writer.setIndent(" ");
+
+ if (t.isPrettyPrintMode()) {
+ writer.setIndent(" ");
+ } else {
+ writer.setIndent("");
+ }
JsonMapper jsonMapper = new JsonMapper(t.getMountPoint());
jsonMapper.write(writer, data, (DataNodeContainer) t.getSchema());
writer.flush();
}
-
}
import java.io.OutputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
-
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-
import org.opendaylight.controller.sal.rest.api.Draft02;
import org.opendaylight.controller.sal.rest.api.RestconfService;
import org.opendaylight.controller.sal.restconf.impl.RestconfDocumentedException;
@Override
public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
- return type.equals( StructuredData.class );
+ return type.equals(StructuredData.class);
}
@Override
final Transformer trans;
try {
trans = TRANSFORMER.get();
+ if (t.isPrettyPrintMode()) {
+ trans.setOutputProperty(OutputKeys.INDENT, "yes");
+ } else {
+ trans.setOutputProperty(OutputKeys.INDENT, "no");
+ }
} catch (RuntimeException e) {
throw new RestconfDocumentedException(e.getMessage(), ErrorType.TRANSPORT,
ErrorTag.OPERATION_FAILED);
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
-
import java.net.URI;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
-
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.core.UriBuilder;
import javax.ws.rs.core.UriInfo;
-
import org.apache.commons.lang3.StringUtils;
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.core.api.mount.MountInstance;
import org.opendaylight.yangtools.yang.parser.builder.impl.LeafSchemaNodeBuilder;
public class RestconfImpl implements RestconfService {
+ private enum UriParameters {
+ PRETTY_PRINT( "prettyPrint"),
+ DEPTH( "depth");
+
+ private String uriParameterName;
+ UriParameters(String uriParameterName) {
+ this.uriParameterName = uriParameterName;
+ }
+
+ @Override
+ public String toString() {
+ return uriParameterName;
+ }
+ }
+
private final static RestconfImpl INSTANCE = new RestconfImpl();
private static final int CHAR_NOT_FOUND = -1;
}
@Override
- public StructuredData getModules() {
+ public StructuredData getModules(final UriInfo uriInfo) {
final Module restconfModule = this.getRestconfModule();
final List<Node<?>> modulesAsData = new ArrayList<Node<?>>();
restconfModule, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
QName qName = modulesSchemaNode.getQName();
final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData);
- return new StructuredData(modulesNode, modulesSchemaNode, null);
+ return new StructuredData(modulesNode, modulesSchemaNode, null,parsePrettyPrintParameter( uriInfo ));
}
@Override
- public StructuredData getAvailableStreams() {
+ public StructuredData getAvailableStreams(final UriInfo uriInfo) {
Set<String> availableStreams = Notificator.getStreamNames();
final List<Node<?>> streamsAsData = new ArrayList<Node<?>>();
restconfModule, Draft02.RestConfModule.STREAMS_CONTAINER_SCHEMA_NODE);
QName qName = streamsSchemaNode.getQName();
final CompositeNode streamsNode = NodeFactory.createImmutableCompositeNode(qName, null, streamsAsData);
- return new StructuredData(streamsNode, streamsSchemaNode, null);
+ return new StructuredData(streamsNode, streamsSchemaNode, null,parsePrettyPrintParameter( uriInfo ));
}
@Override
- public StructuredData getModules(final String identifier) {
+ public StructuredData getModules(final String identifier,final UriInfo uriInfo) {
Set<Module> modules = null;
MountInstance mountPoint = null;
if (identifier.contains(ControllerContext.MOUNT)) {
restconfModule, Draft02.RestConfModule.MODULES_CONTAINER_SCHEMA_NODE);
QName qName = modulesSchemaNode.getQName();
final CompositeNode modulesNode = NodeFactory.createImmutableCompositeNode(qName, null, modulesAsData);
- return new StructuredData(modulesNode, modulesSchemaNode, mountPoint);
+ return new StructuredData(modulesNode, modulesSchemaNode, mountPoint,parsePrettyPrintParameter( uriInfo ));
}
@Override
- public StructuredData getModule(final String identifier) {
+ public StructuredData getModule(final String identifier,final UriInfo uriInfo) {
final QName moduleNameAndRevision = this.getModuleNameAndRevision(identifier);
Module module = null;
MountInstance mountPoint = null;
final DataSchemaNode moduleSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
restconfModule, Draft02.RestConfModule.MODULE_LIST_SCHEMA_NODE);
final CompositeNode moduleNode = this.toModuleCompositeNode(module, moduleSchemaNode);
- return new StructuredData(moduleNode, moduleSchemaNode, mountPoint);
+ return new StructuredData(moduleNode, moduleSchemaNode, mountPoint,parsePrettyPrintParameter( uriInfo ));
}
@Override
- public StructuredData getOperations() {
+ public StructuredData getOperations(final UriInfo uriInfo) {
Set<Module> allModules = this.controllerContext.getAllModules();
- return this.operationsFromModulesToStructuredData(allModules, null);
+ return this.operationsFromModulesToStructuredData(allModules, null,parsePrettyPrintParameter(uriInfo));
}
@Override
- public StructuredData getOperations(final String identifier) {
+ public StructuredData getOperations(final String identifier,final UriInfo uriInfo) {
Set<Module> modules = null;
MountInstance mountPoint = null;
if (identifier.contains(ControllerContext.MOUNT)) {
ControllerContext.MOUNT, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
- return this.operationsFromModulesToStructuredData(modules, mountPoint);
+ return this.operationsFromModulesToStructuredData(modules, mountPoint,parsePrettyPrintParameter(uriInfo));
}
private StructuredData operationsFromModulesToStructuredData(final Set<Module> modules,
- final MountInstance mountPoint) {
+ final MountInstance mountPoint,boolean prettyPrint) {
final List<Node<?>> operationsAsData = new ArrayList<Node<?>>();
Module restconfModule = this.getRestconfModule();
final DataSchemaNode operationsSchemaNode = controllerContext.getRestconfModuleRestConfSchemaNode(
final CompositeNode operationsNode =
NodeFactory.createImmutableCompositeNode(qName, null, operationsAsData);
ContainerSchemaNode schemaNode = fakeOperationsSchemaNode.build();
- return new StructuredData(operationsNode, schemaNode, mountPoint);
+ return new StructuredData(operationsNode, schemaNode, mountPoint,prettyPrint);
}
private Module getRestconfModule() {
}
@Override
- public StructuredData invokeRpc(final String identifier, final CompositeNode payload) {
+ public StructuredData invokeRpc(final String identifier, final CompositeNode payload,final UriInfo uriInfo) {
final RpcExecutor rpc = this.resolveIdentifierInInvokeRpc(identifier);
QName rpcName = rpc.getRpcDefinition().getQName();
URI rpcNamespace = rpcName.getNamespace();
if (Objects.equal(rpcNamespace.toString(), SAL_REMOTE_NAMESPACE) &&
Objects.equal(rpcName.getLocalName(), SAL_REMOTE_RPC_SUBSRCIBE)) {
- return invokeSalRemoteRpcSubscribeRPC(payload, rpc.getRpcDefinition());
+ return invokeSalRemoteRpcSubscribeRPC(payload, rpc.getRpcDefinition(),parsePrettyPrintParameter(uriInfo));
}
validateInput( rpc.getRpcDefinition().getInput(), payload );
- return callRpc(rpc, payload);
+ return callRpc(rpc, payload,parsePrettyPrintParameter(uriInfo));
}
private void validateInput(final DataSchemaNode inputSchema, final CompositeNode payload) {
}
private StructuredData invokeSalRemoteRpcSubscribeRPC(final CompositeNode payload,
- final RpcDefinition rpc) {
+ final RpcDefinition rpc,final boolean prettyPrint) {
final CompositeNode value = this.normalizeNode(payload, rpc.getInput(), null);
final SimpleNode<? extends Object> pathNode = value == null ? null :
value.getFirstSimpleByName( QName.create(rpc.getQName(), "path") );
Notificator.createListener(pathIdentifier, streamName);
}
- return new StructuredData(responseData, rpc.getOutput(), null);
+ return new StructuredData(responseData, rpc.getOutput(), null,prettyPrint);
}
@Override
- public StructuredData invokeRpc(final String identifier, final String noPayload) {
+ public StructuredData invokeRpc(final String identifier, final String noPayload, final UriInfo uriInfo) {
if (StringUtils.isNotBlank(noPayload)) {
throw new RestconfDocumentedException(
"Content must be empty.", ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE );
}
- return invokeRpc( identifier, (CompositeNode)null );
+ return invokeRpc( identifier, (CompositeNode)null,uriInfo);
}
private RpcExecutor resolveIdentifierInInvokeRpc(final String identifier) {
}
- private StructuredData callRpc(final RpcExecutor rpcExecutor, final CompositeNode payload) {
+ private StructuredData callRpc(final RpcExecutor rpcExecutor, final CompositeNode payload,boolean prettyPrint) {
if (rpcExecutor == null) {
throw new RestconfDocumentedException(
"RPC does not exist.", ErrorType.RPC, ErrorTag.UNKNOWN_ELEMENT );
return null; //no output, nothing to send back.
}
- return new StructuredData(rpcResult.getResult(), rpc.getOutput(), null);
+ return new StructuredData(rpcResult.getResult(), rpc.getOutput(), null,prettyPrint);
}
private void checkRpcSuccessAndThrowException(final RpcResult<CompositeNode> rpcResult) {
}
@Override
- public StructuredData readConfigurationData(final String identifier, final UriInfo info) {
+ public StructuredData readConfigurationData(final String identifier, final UriInfo uriInfo) {
final InstanceIdWithSchemaNode iiWithData = this.controllerContext.toInstanceIdentifier(identifier);
CompositeNode data = null;
MountInstance mountPoint = iiWithData.getMountPoint();
data = broker.readConfigurationData(iiWithData.getInstanceIdentifier());
}
- data = pruneDataAtDepth( data, parseDepthParameter( info ) );
- return new StructuredData(data, iiWithData.getSchemaNode(), iiWithData.getMountPoint());
+ data = pruneDataAtDepth( data, parseDepthParameter( uriInfo ) );
+ boolean prettyPrintMode = parsePrettyPrintParameter( uriInfo );
+ return new StructuredData(data, iiWithData.getSchemaNode(), iiWithData.getMountPoint(),prettyPrintMode);
}
@SuppressWarnings("unchecked")
}
private Integer parseDepthParameter( final UriInfo info ) {
- String param = info.getQueryParameters( false ).getFirst( "depth" );
+ String param = info.getQueryParameters( false ).getFirst( UriParameters.DEPTH.toString() );
if( Strings.isNullOrEmpty( param ) || "unbounded".equals( param ) ) {
return null;
}
}
data = pruneDataAtDepth( data, parseDepthParameter( info ) );
- return new StructuredData(data, iiWithData.getSchemaNode(), mountPoint);
+ boolean prettyPrintMode = parsePrettyPrintParameter( info );
+ return new StructuredData(data, iiWithData.getSchemaNode(), mountPoint,prettyPrintMode);
+ }
+
+ private boolean parsePrettyPrintParameter(UriInfo info) {
+ String param = info.getQueryParameters(false).getFirst(UriParameters.PRETTY_PRINT.toString());
+ return Boolean.parseBoolean(param);
}
@Override
private final CompositeNode data;
private final DataSchemaNode schema;
private final MountInstance mountPoint;
+ private final boolean prettyPrintMode;
public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint) {
+ this(data, schema, mountPoint, false);
+ }
+
+ public StructuredData(final CompositeNode data, final DataSchemaNode schema, final MountInstance mountPoint,
+ final boolean preattyPrintMode) {
this.data = data;
this.schema = schema;
this.mountPoint = mountPoint;
+ this.prettyPrintMode = preattyPrintMode;
}
public CompositeNode getData() {
public MountInstance getMountPoint() {
return mountPoint;
}
+
+ public boolean isPrettyPrintMode() {
+ return prettyPrintMode;
+ }
}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.opendaylight.controller.sal.restconf.impl.test.TestUtils.containsStringData;
import java.io.IOException;
import java.util.Collections;
Collections.<Module>emptySet(), prepareDataSchemaNode(),
StructuredDataToJsonProvider.INSTANCE);
assertNotNull(jsonOutput);
- assertTrue(jsonOutput.contains("\"lf1\": \"\""));
+
+// pattern for e.g. > "lf1" : "" < or >"lf1":""<
+ assertTrue(containsStringData(jsonOutput, "\"lf1\"",":","\"\""));
}
private CompositeNode prepareCompositeNode() {
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.opendaylight.controller.sal.restconf.impl.test.TestUtils.containsStringData;
import java.io.IOException;
-
import javax.ws.rs.WebApplicationException;
-
import org.junit.BeforeClass;
import org.junit.Test;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
}
assertNotNull(jsonOutput);
- assertTrue(jsonOutput.contains("\"augment-leaf:lf2\": \"lf2\""));
- assertTrue(jsonOutput.contains("\"augment-container:cont1\": {"));
- assertTrue(jsonOutput.contains("\"augment-container:lf11\": \"lf11\""));
- assertTrue(jsonOutput.contains("\"augment-list:lst1\": ["));
- assertTrue(jsonOutput.contains("\"augment-list:lf11\": \"lf1_1\""));
- assertTrue(jsonOutput.contains("\"augment-list:lf11\": \"lf1_2\""));
- assertTrue(jsonOutput.contains("\"augment-leaflist:lflst1\": ["));
+ assertTrue(containsStringData(jsonOutput,"\"augment-leaf:lf2\"",":", "\"lf2\""));
+ assertTrue(containsStringData(jsonOutput,"\"augment-container:cont1\"",":", "\\{"));
+ assertTrue(containsStringData(jsonOutput,"\"augment-container:lf11\"",":", "\"lf11\""));
+ assertTrue(containsStringData(jsonOutput,"\"augment-list:lst1\"",":", "\\["));
+ assertTrue(containsStringData(jsonOutput,"\"augment-list:lf11\"",":", "\"lf1_1\""));
+ assertTrue(containsStringData(jsonOutput,"\"augment-list:lf11\"",":", "\"lf1_2\""));
+ assertTrue(containsStringData(jsonOutput,"\"augment-leaflist:lflst1\"",":", "\\["));
}
}
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.opendaylight.controller.sal.restconf.impl.test.TestUtils.containsStringData;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-
import javax.ws.rs.WebApplicationException;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
-
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToJsonProvider;
import org.opendaylight.controller.sal.rest.impl.StructuredDataToXmlProvider;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeWithValue;
import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
-import org.opendaylight.yangtools.yang.data.api.MutableCompositeNode;
-import org.opendaylight.yangtools.yang.data.api.MutableSimpleNode;
+import org.opendaylight.yangtools.yang.data.api.SimpleNode;
+import org.opendaylight.yangtools.yang.data.impl.ImmutableCompositeNode;
import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
+import org.opendaylight.yangtools.yang.data.impl.util.CompositeNodeBuilder;
public class CnSnToXmlAndJsonInstanceIdentifierTest extends YangAndXmlAndDataSchemaLoader {
CompositeNode cnSn = prepareCnSn(createInstanceIdentifier());
String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
StructuredDataToXmlProvider.INSTANCE);
- //uncomment for debug
- // System.out.println(output);
validateXmlOutput(output);
}
- @Ignore
@Test
public void saveCnSnWithLeafListInstIdentifierToXmlTest() throws WebApplicationException, IOException,
- URISyntaxException, XMLStreamException {
+ URISyntaxException, XMLStreamException {
CompositeNode cnSn = prepareCnSn(createInstanceIdentifierWithLeafList());
String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
StructuredDataToXmlProvider.INSTANCE);
- //uncomment for debug
- // System.out.println(output);
validateXmlOutputWithLeafList(output);
}
String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
StructuredDataToJsonProvider.INSTANCE);
boolean strInOutput = false;
- strInOutput = output
- .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111=\\\"value1\\\"][augment-module:keyvalue112=\\\"value2\\\"]/augment-augment-module:lf112\"");
+ strInOutput = containsStringData(
+ output,
+ "\"augment-augment-module:lf111\"",
+ ":",
+ "\"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11\\[augment-module:keyvalue111=\\\\\"value1\\\\\"\\]\\[augment-module:keyvalue112=\\\\\"value2\\\\\"\\]/augment-augment-module:lf112\"");
if (!strInOutput) {
- strInOutput = output
- .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11[augment-module:keyvalue111='value1'][augment-module:keyvalue112='value2']/augment-augment-module:lf112\"");
+ strInOutput = containsStringData(
+ output,
+ "\"augment-augment-module:lf111\"",
+ ":",
+ "\"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module:lst11\\[augment-module:keyvalue111='value1'\\]\\[augment-module:keyvalue112='value2'\\]/augment-augment-module:lf112\"");
}
- //uncomment for debug
- // System.out.println(output);
assertTrue(strInOutput);
}
-
@Test
public void saveCnSnWithLeafListInstIdentifierToJsonTest() throws WebApplicationException, IOException,
- URISyntaxException {
+ URISyntaxException {
CompositeNode cnSn = prepareCnSn(createInstanceIdentifierWithLeafList());
String output = TestUtils.writeCompNodeWithSchemaContextToOutput(cnSn, modules, dataSchemaNode,
StructuredDataToJsonProvider.INSTANCE);
- //uncomment for debug
- // System.out.println(output);
boolean strInOutput = false;
- strInOutput = output
- .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.='lflst11_1']\"");
+ strInOutput = containsStringData(
+ output,
+ "\"augment-augment-module:lf111\"",
+ ":",
+ "\"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11\\[.='lflst11_1'\\]\"");
if (!strInOutput) {
- strInOutput = output
- .contains("\"augment-augment-module:lf111\": \"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11[.=\\\"lflst11_1\\\"]\"");
+ strInOutput = containsStringData(
+ output,
+ "\"augment-augment-module:lf111\"",
+ ":",
+ "\"/instance-identifier-module:cont/instance-identifier-module:cont1/augment-module-leaf-list:lflst11\\[.=\\\\\"lflst11_1\\\\\"\\]\"");
}
assertTrue(strInOutput);
}
private CompositeNode prepareCnSn(final InstanceIdentifier instanceIdentifier) throws URISyntaxException {
- MutableCompositeNode cont = NodeFactory.createMutableCompositeNode(
- TestUtils.buildQName("cont", "instance:identifier:module", "2014-01-17"), null, null,null,null);
- MutableCompositeNode cont1 = NodeFactory.createMutableCompositeNode(
- TestUtils.buildQName("cont1", "instance:identifier:module", "2014-01-17"), cont, null,null,null);
- MutableCompositeNode lst11 = NodeFactory.createMutableCompositeNode(
- TestUtils.buildQName("lst11", "augment:module", "2014-01-17"), cont1, null,null,null);
-
- MutableSimpleNode<?> lf111 = NodeFactory.createMutableSimpleNode(TestUtils.buildQName("lf111", "augment:augment:module", "2014-01-17"),
- lst11, instanceIdentifier,null,null);
-
-
- lst11.getValue().add(lf111);
- lst11.init();
+ CompositeNodeBuilder<ImmutableCompositeNode> cont = ImmutableCompositeNode.builder();
+ cont.setQName(QName.create("instance:identifier:module", "2014-01-17", "cont"));
- cont1.getValue().add(lst11);
- cont1.init();
+ CompositeNodeBuilder<ImmutableCompositeNode> cont1 = ImmutableCompositeNode.builder();
+ cont1.setQName(QName.create("instance:identifier:module", "2014-01-17", "cont1"));
- cont.getValue().add(cont1);
- cont.init();
+ CompositeNodeBuilder<ImmutableCompositeNode> lst11 = ImmutableCompositeNode.builder();
+ lst11.setQName(QName.create("augment:module", "2014-01-17", "lst11"));
- return cont;
+ SimpleNode<?> lf111 = NodeFactory.createImmutableSimpleNode(
+ QName.create("augment:augment:module", "2014-01-17", "lf111"), null, instanceIdentifier);
+ lst11.add(lf111);
+ cont1.add(lst11.toInstance());
+ cont.add(cont1.toInstance());
+ return cont.toInstance();
}
private InstanceIdentifier createInstanceIdentifier() throws URISyntaxException {
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
+import com.google.common.base.Optional;
+import com.google.common.util.concurrent.Futures;
+import com.google.common.util.concurrent.ListenableFuture;
import java.io.FileNotFoundException;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-
+import javax.ws.rs.core.MultivaluedHashMap;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriInfo;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
import org.opendaylight.yangtools.yang.model.api.SchemaContext;
-import com.google.common.base.Optional;
-import com.google.common.util.concurrent.Futures;
-import com.google.common.util.concurrent.ListenableFuture;
-
public class InvokeRpcMethodTest {
private RestconfImpl restconfImpl = null;
private static ControllerContext controllerContext = null;
+ private static UriInfo uriInfo;
@BeforeClass
SchemaContext schemaContext = TestUtils.loadSchemaContext(allModules);
controllerContext = spy( ControllerContext.getInstance() );
controllerContext.setSchemas(schemaContext);
-
+ uriInfo = mock(UriInfo.class);
+ MultivaluedMap<String, String> map = new MultivaluedHashMap<>();
+ map.put("prettyPrint", Collections.singletonList("true"));
+ when(uriInfo.getQueryParameters(any(Boolean.class))).thenReturn(map);
}
@Before
.thenReturn( Futures.<RpcResult<CompositeNode>>immediateFuture(
Rpcs.<CompositeNode>getRpcResult( true ) ) );
- StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", payload);
+ StructuredData structData = restconf.invokeRpc("invoke-rpc-module:rpc-test", payload,uriInfo);
assertTrue(structData == null);
}
restconfImpl.setBroker(brokerFacade);
try {
- restconfImpl.invokeRpc("toaster:cancel-toast", "");
+ restconfImpl.invokeRpc("toaster:cancel-toast", "",uriInfo);
fail("Expected an exception to be thrown.");
}
catch (RestconfDocumentedException e) {
restconfImpl.setBroker(brokerFacade);
try {
- restconfImpl.invokeRpc("toaster:cancel-toast", "");
+ restconfImpl.invokeRpc("toaster:cancel-toast", "",uriInfo);
fail("Expected an exception to be thrown.");
}
catch (RestconfDocumentedException e) {
restconfImpl.setBroker(brokerFacade);
StructuredData output = restconfImpl.invokeRpc("toaster:cancel-toast",
- "");
+ "",uriInfo);
assertEquals(null, output);
//additional validation in the fact that the restconfImpl does not throw an exception.
}
@Test
public void testInvokeRpcMethodExpectingNoPayloadButProvidePayload() {
try {
- restconfImpl.invokeRpc("toaster:cancel-toast", " a payload ");
+ restconfImpl.invokeRpc("toaster:cancel-toast", " a payload ",uriInfo);
fail("Expected an exception");
} catch (RestconfDocumentedException e) {
verifyRestconfDocumentedException( e, 0, ErrorType.PROTOCOL, ErrorTag.INVALID_VALUE,
@Test
public void testInvokeRpcMethodWithBadMethodName() {
try {
- restconfImpl.invokeRpc("toaster:bad-method", "");
+ restconfImpl.invokeRpc("toaster:bad-method", "",uriInfo);
fail("Expected an exception");
}
catch (RestconfDocumentedException e) {
restconfImpl.setBroker(brokerFacade);
StructuredData output = restconfImpl.invokeRpc("toaster:make-toast",
- payload);
+ payload,uriInfo);
assertEquals(null, output);
//additional validation in the fact that the restconfImpl does not throw an exception.
}
@Test
public void testThrowExceptionWhenSlashInModuleName() {
try {
- restconfImpl.invokeRpc("toaster/slash", "");
+ restconfImpl.invokeRpc("toaster/slash", "",uriInfo);
fail("Expected an exception.");
}
catch (RestconfDocumentedException e) {
restconfImpl.setBroker(brokerFacade);
- StructuredData output = restconfImpl.invokeRpc("toaster:testOutput", "");
+ StructuredData output = restconfImpl.invokeRpc("toaster:testOutput", "",uriInfo);
assertNotNull( output );
assertSame( compositeNode, output.getData() );
assertNotNull( output.getSchema() );
restconfImpl.setControllerContext( mockedContext );
StructuredData output = restconfImpl.invokeRpc(
"opendaylight-inventory:nodes/node/REMOTE_HOST/yang-ext:mount/toaster:cancel-toast",
- "");
+ "",uriInfo);
assertEquals(null, output);
//additional validation in the fact that the restconfImpl does not throw an exception.
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
-
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
-
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.BeforeClass;
@Override
protected Application configure() {
/* enable/disable Jersey logs to console */
-// enable(TestProperties.LOG_TRAFFIC);
-// enable(TestProperties.DUMP_ENTITY);
-// enable(TestProperties.RECORD_LOG_LEVEL);
-// set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
+ // enable(TestProperties.LOG_TRAFFIC);
+ // enable(TestProperties.DUMP_ENTITY);
+ // enable(TestProperties.RECORD_LOG_LEVEL);
+ // set(TestProperties.RECORD_LOG_LEVEL, Level.ALL.intValue());
ResourceConfig resourceConfig = new ResourceConfig();
resourceConfig = resourceConfig.registerInstances(restconfService, StructuredDataToXmlProvider.INSTANCE,
StructuredDataToJsonProvider.INSTANCE, XmlToCompositeNodeProvider.INSTANCE,
return resourceConfig;
}
- @Test
- public void testPostOperationsWithInputDataMediaTypes() throws UnsupportedEncodingException {
- String uriPrefix = "/operations/";
- String uriPath = "ietf-interfaces:interfaces";
- String uri = uriPrefix + uriPath;
- when(restconfService.invokeRpc(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
- post(uri, Draft02.MediaTypes.OPERATION+JSON, Draft02.MediaTypes.OPERATION+JSON, jsonData);
- verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(CompositeNode.class));
- post(uri, Draft02.MediaTypes.OPERATION+XML, Draft02.MediaTypes.OPERATION+XML, xmlData);
- verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(CompositeNode.class));
- post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData);
- verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(CompositeNode.class));
- post(uri, MediaType.APPLICATION_XML, MediaType.APPLICATION_XML, xmlData);
- verify(restconfService, times(4)).invokeRpc(eq(uriPath), any(CompositeNode.class));
- post(uri, MediaType.TEXT_XML, MediaType.TEXT_XML, xmlData);
- verify(restconfService, times(5)).invokeRpc(eq(uriPath), any(CompositeNode.class));
- post(uri, null, MediaType.TEXT_XML, xmlData);
- verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class));
-
- // negative tests
- post(uri, MediaType.TEXT_PLAIN, MediaType.TEXT_XML, xmlData);
- verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class));
- post(uri, MediaType.TEXT_XML, MediaType.TEXT_PLAIN, xmlData);
- verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class));
- }
+ @Test
+ public void testPostOperationsWithInputDataMediaTypes() throws UnsupportedEncodingException {
+ String uriPrefix = "/operations/";
+ String uriPath = "ietf-interfaces:interfaces";
+ String uri = uriPrefix + uriPath;
+ when(restconfService.invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class))).thenReturn(null);
+ post(uri, Draft02.MediaTypes.OPERATION + JSON, Draft02.MediaTypes.OPERATION + JSON, jsonData);
+ verify(restconfService, times(1)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class));
+ post(uri, Draft02.MediaTypes.OPERATION + XML, Draft02.MediaTypes.OPERATION + XML, xmlData);
+ verify(restconfService, times(2)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class));
+ post(uri, MediaType.APPLICATION_JSON, MediaType.APPLICATION_JSON, jsonData);
+ verify(restconfService, times(3)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class));
+ post(uri, MediaType.APPLICATION_XML, MediaType.APPLICATION_XML, xmlData);
+ verify(restconfService, times(4)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class));
+ post(uri, MediaType.TEXT_XML, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(5)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class));
+ post(uri, null, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class));
+
+ // negative tests
+ post(uri, MediaType.TEXT_PLAIN, MediaType.TEXT_XML, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class));
+ post(uri, MediaType.TEXT_XML, MediaType.TEXT_PLAIN, xmlData);
+ verify(restconfService, times(6)).invokeRpc(eq(uriPath), any(CompositeNode.class), any(UriInfo.class));
+ }
@Test
public void testGetConfigMediaTypes() throws UnsupportedEncodingException {
String uriPath = "ietf-interfaces:interfaces";
String uri = uriPrefix + uriPath;
when(restconfService.readConfigurationData(eq(uriPath), any(UriInfo.class))).thenReturn(null);
- get(uri, Draft02.MediaTypes.DATA+JSON);
+ get(uri, Draft02.MediaTypes.DATA + JSON);
verify(restconfService, times(1)).readConfigurationData(eq(uriPath), any(UriInfo.class));
- get(uri, Draft02.MediaTypes.DATA+XML);
+ get(uri, Draft02.MediaTypes.DATA + XML);
verify(restconfService, times(2)).readConfigurationData(eq(uriPath), any(UriInfo.class));
get(uri, MediaType.APPLICATION_JSON);
verify(restconfService, times(3)).readConfigurationData(eq(uriPath), any(UriInfo.class));
String uriPath = "ietf-interfaces:interfaces";
String uri = uriPrefix + uriPath;
when(restconfService.readOperationalData(eq(uriPath), any(UriInfo.class))).thenReturn(null);
- get(uri, Draft02.MediaTypes.DATA+JSON);
+ get(uri, Draft02.MediaTypes.DATA + JSON);
verify(restconfService, times(1)).readOperationalData(eq(uriPath), any(UriInfo.class));
- get(uri, Draft02.MediaTypes.DATA+XML);
+ get(uri, Draft02.MediaTypes.DATA + XML);
verify(restconfService, times(2)).readOperationalData(eq(uriPath), any(UriInfo.class));
get(uri, MediaType.APPLICATION_JSON);
verify(restconfService, times(3)).readOperationalData(eq(uriPath), any(UriInfo.class));
String uriPath = "ietf-interfaces:interfaces";
String uri = uriPrefix + uriPath;
when(restconfService.updateConfigurationData(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
- put(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData);
+ put(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
verify(restconfService, times(1)).updateConfigurationData(eq(uriPath), any(CompositeNode.class));
- put(uri, null, Draft02.MediaTypes.DATA+XML, xmlData);
+ put(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
verify(restconfService, times(2)).updateConfigurationData(eq(uriPath), any(CompositeNode.class));
put(uri, null, MediaType.APPLICATION_JSON, jsonData);
verify(restconfService, times(3)).updateConfigurationData(eq(uriPath), any(CompositeNode.class));
String uriPath = "ietf-interfaces:interfaces";
String uri = uriPrefix + uriPath;
when(restconfService.createConfigurationData(eq(uriPath), any(CompositeNode.class))).thenReturn(null);
- post(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData);
+ post(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
verify(restconfService, times(1)).createConfigurationData(eq(uriPath), any(CompositeNode.class));
- post(uri, null, Draft02.MediaTypes.DATA+XML, xmlData);
+ post(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
verify(restconfService, times(2)).createConfigurationData(eq(uriPath), any(CompositeNode.class));
post(uri, null, MediaType.APPLICATION_JSON, jsonData);
verify(restconfService, times(3)).createConfigurationData(eq(uriPath), any(CompositeNode.class));
String uriPrefix = "/config/";
String uri = uriPrefix;
when(restconfService.createConfigurationData(any(CompositeNode.class))).thenReturn(null);
- post(uri, null, Draft02.MediaTypes.DATA+JSON, jsonData);
+ post(uri, null, Draft02.MediaTypes.DATA + JSON, jsonData);
verify(restconfService, times(1)).createConfigurationData(any(CompositeNode.class));
- post(uri, null, Draft02.MediaTypes.DATA+XML, xmlData);
+ post(uri, null, Draft02.MediaTypes.DATA + XML, xmlData);
verify(restconfService, times(2)).createConfigurationData(any(CompositeNode.class));
post(uri, null, MediaType.APPLICATION_JSON, jsonData);
verify(restconfService, times(3)).createConfigurationData(any(CompositeNode.class));
package org.opendaylight.controller.sal.restconf.impl.test;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
-
import javax.ws.rs.core.Application;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriInfo;
-
import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.BeforeClass;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
public class RestGetOperationTest extends JerseyTest {
static class NodeData {
return null;
}
+ /**
+ * If includeWhiteChars URI parameter is set to false then no white
+ * characters can be included in returned output
+ * @throws UnsupportedEncodingException
+ */
+ @Test
+ public void getDataWithUriIncludeWhiteCharsParameterTest() throws UnsupportedEncodingException {
+ getDataWithUriIncludeWhiteCharsParameter("config");
+ getDataWithUriIncludeWhiteCharsParameter("operational");
+ }
+
+
+ private void getDataWithUriIncludeWhiteCharsParameter(String target) throws UnsupportedEncodingException {
+ mockReadConfigurationDataMethod();
+ String uri = "/"+target+"/ietf-interfaces:interfaces/interface/eth0";
+ Response response = target(uri).queryParam("prettyPrint", "false").request("application/xml").get();
+ String xmlData = response.readEntity(String.class);
+
+ Pattern pattern = Pattern.compile(".*(>\\s+|\\s+<).*", Pattern.DOTALL);
+ Matcher matcher = pattern.matcher(xmlData);
+ // XML element can't surrounded with white character (e.g "> " or
+ // " <")
+ assertFalse(matcher.matches());
+
+ response = target(uri).queryParam("prettyPrint", "false").request("application/json").get();
+ String jsonData = response.readEntity(String.class);
+ pattern = Pattern.compile(".*(\\}\\s+|\\s+\\{|\\]\\s+|\\s+\\[|\\s+:|:\\s+).*", Pattern.DOTALL);
+ matcher = pattern.matcher(jsonData);
+ // JSON element can't surrounded with white character (e.g "} ", " {",
+ // "] ", " [", " :" or ": ")
+ assertFalse(matcher.matches());
+ }
+
@Test
public void getDataWithUriDepthParameterTest() throws UnsupportedEncodingException {
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
+import com.google.common.base.Preconditions;
import java.io.BufferedReader;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
-
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
-
import org.opendaylight.controller.md.sal.common.api.TransactionStatus;
import org.opendaylight.controller.sal.restconf.impl.BrokerFacade;
import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
-import com.google.common.base.Preconditions;
-
public final class TestUtils {
private static final Logger LOG = LoggerFactory.getLogger(TestUtils.class);
}
bufReader.close();
return result.toString();
+ }
+
+ private static Pattern patternForStringsSeparatedByWhiteChars(String ... substrings ) {
+ StringBuilder pattern = new StringBuilder();
+ pattern.append(".*");
+ for (String substring : substrings) {
+ pattern.append(substring);
+ pattern.append("\\s*");
+ }
+ pattern.append(".*");
+ return Pattern.compile(pattern.toString(), Pattern.DOTALL);
+ }
+ public static boolean containsStringData(String jsonOutput,String ...substrings ) {
+ Pattern pattern = patternForStringsSeparatedByWhiteChars(substrings);
+ Matcher matcher = pattern.matcher(jsonOutput);
+ return matcher.matches();
}
}