Merge "Bug 1290 - Swagger Documentation is failing to load - java script exception"
authorTony Tkacik <ttkacik@cisco.com>
Thu, 3 Jul 2014 14:36:35 +0000 (14:36 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Thu, 3 Jul 2014 14:36:35 +0000 (14:36 +0000)
27 files changed:
opendaylight/md-sal/sal-dom-broker/src/main/java/org/opendaylight/controller/sal/dom/broker/GlobalBundleScanningSchemaServiceImpl.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonMapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonReader.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/JsonToCompositeNodeProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestUtil.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/RestconfDocumentedExceptionMapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToJsonProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/rest/impl/StructuredDataToXmlProvider.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/CompositeNodeWrapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/ControllerContext.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/restconf/impl/EmptyNodeWrapper.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/listeners/ListenerAdapter.java
opendaylight/md-sal/sal-rest-connector/src/main/java/org/opendaylight/controller/sal/streams/websockets/WebSocketServerHandler.java
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronObject.java [new file with mode: 0644]
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronNetwork.java
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronPort.java
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronRouter.java
opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/NeutronSubnet.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/INeutronRequest.java [new file with mode: 0644]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworkRequest.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortRequest.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetRequest.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedNeutronNetworkRequest.java [deleted file]
opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedRequestFactory.java [new file with mode: 0644]

index c9402c62ab77c92c747183bb5ef2a7810a7dff7e..60a7e81c4c046183e6ee59e0f27d48e5a15e90bc 100644 (file)
@@ -9,6 +9,7 @@ package org.opendaylight.controller.sal.dom.broker;
 
 import static com.google.common.base.Preconditions.checkState;
 
+import com.google.common.annotations.VisibleForTesting;
 import java.net.URL;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -68,6 +69,11 @@ public class GlobalBundleScanningSchemaServiceImpl implements SchemaContextProvi
         return instance;
     }
 
+    @VisibleForTesting
+    public static synchronized void destroyInstance() {
+        instance = null;
+    }
+
     public BundleContext getContext() {
         return context;
     }
index 696bf715355e402a0932532a36cde8e795a08236..85b4b2dee071aff3be08fb82b11690a8793d7014 100644 (file)
@@ -11,13 +11,16 @@ import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.google.common.base.Preconditions;
 import com.google.gson.stream.JsonWriter;
+
 import java.io.IOException;
 import java.net.URI;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+
 import javax.activation.UnsupportedDataTypeException;
+
 import org.opendaylight.controller.sal.core.api.mount.MountInstance;
 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
 import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
@@ -50,16 +53,18 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 class JsonMapper {
+    private static final Logger LOG = LoggerFactory.getLogger(JsonMapper.class);
+    private final MountInstance mountPoint;
 
-    private MountInstance mountPoint;
-    private final Logger logger = LoggerFactory.getLogger(JsonMapper.class);
+    public JsonMapper(final MountInstance mountPoint) {
+        this.mountPoint = mountPoint;
+    }
 
-    public void write(final JsonWriter writer, final CompositeNode data, final DataNodeContainer schema, final MountInstance mountPoint)
+    public void write(final JsonWriter writer, final CompositeNode data, final DataNodeContainer schema)
             throws IOException {
         Preconditions.checkNotNull(writer);
         Preconditions.checkNotNull(data);
         Preconditions.checkNotNull(schema);
-        this.mountPoint = mountPoint;
 
         writer.beginObject();
 
@@ -82,73 +87,68 @@ class JsonMapper {
         final Set<QName> foundLists = new HashSet<>();
 
         Set<DataSchemaNode> parentSchemaChildNodes = parentSchema == null ?
-                                   Collections.<DataSchemaNode>emptySet() : parentSchema.getChildNodes();
+                Collections.<DataSchemaNode>emptySet() : parentSchema.getChildNodes();
 
 
-        for (Node<?> child : parent.getValue()) {
-            DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchemaChildNodes);
+                for (Node<?> child : parent.getValue()) {
+                    DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchemaChildNodes);
 
-            if (childSchema == null) {
-                // Node may not conform to schema or allows "anyxml" - we'll process it.
+                    if (childSchema == null) {
+                        // Node may not conform to schema or allows "anyxml" - we'll process it.
 
-                logger.debug( "No schema found for data node \"" + child.getNodeType() );
+                        LOG.debug("No schema found for data node \"{}\"", child.getNodeType());
 
-                if( !foundLists.contains( child.getNodeType() ) ) {
-                    handleNoSchemaFound( writer, child, parent );
+                        if( !foundLists.contains( child.getNodeType() ) ) {
+                            handleNoSchemaFound( writer, child, parent );
 
-                    // Since we don't have a schema, we don't know which nodes are supposed to be
-                    // lists so treat every one as a potential list to avoid outputting duplicates.
+                            // Since we don't have a schema, we don't know which nodes are supposed to be
+                            // lists so treat every one as a potential list to avoid outputting duplicates.
 
-                    foundLists.add( child.getNodeType() );
-                }
-            }
-            else if (childSchema instanceof ContainerSchemaNode) {
-                Preconditions.checkState(child instanceof CompositeNode,
-                        "Data representation of Container should be CompositeNode - " + child.getNodeType());
-                writeContainer(writer, (CompositeNode) child, (ContainerSchemaNode) childSchema);
-            } else if (childSchema instanceof ListSchemaNode) {
-                if (!foundLists.contains( child.getNodeType() ) ) {
-                    Preconditions.checkState(child instanceof CompositeNode,
-                            "Data representation of List should be CompositeNode - " + child.getNodeType());
-                    foundLists.add( child.getNodeType() );
-                    writeList(writer, parent, (CompositeNode) child, (ListSchemaNode) childSchema);
-                }
-            } else if (childSchema instanceof LeafListSchemaNode) {
-                if (!foundLists.contains( child.getNodeType() ) ) {
-                    Preconditions.checkState(child instanceof SimpleNode<?>,
-                            "Data representation of LeafList should be SimpleNode - " + child.getNodeType());
-                    foundLists.add( child.getNodeType() );
-                    writeLeafList(writer, parent, (SimpleNode<?>) child, (LeafListSchemaNode) childSchema);
-                }
-            } else if (childSchema instanceof LeafSchemaNode) {
-                Preconditions.checkState(child instanceof SimpleNode<?>,
-                        "Data representation of LeafList should be SimpleNode - " + child.getNodeType());
-                writeLeaf(writer, (SimpleNode<?>) child, (LeafSchemaNode) childSchema);
-            } else if (childSchema instanceof AnyXmlSchemaNode) {
-                if( child instanceof CompositeNode ) {
-                    writeContainer(writer, (CompositeNode) child, null);
-                }
-                else {
-                    handleNoSchemaFound( writer, child, parent );
+                            foundLists.add( child.getNodeType() );
+                        }
+                    }
+                    else if (childSchema instanceof ContainerSchemaNode) {
+                        Preconditions.checkState(child instanceof CompositeNode,
+                                "Data representation of Container should be CompositeNode - %s", child.getNodeType());
+                        writeContainer(writer, (CompositeNode) child, (ContainerSchemaNode) childSchema);
+                    } else if (childSchema instanceof ListSchemaNode) {
+                        if (!foundLists.contains( child.getNodeType() ) ) {
+                            Preconditions.checkState(child instanceof CompositeNode,
+                                    "Data representation of List should be CompositeNode - %s", child.getNodeType());
+                            foundLists.add( child.getNodeType() );
+                            writeList(writer, parent, (CompositeNode) child, (ListSchemaNode) childSchema);
+                        }
+                    } else if (childSchema instanceof LeafListSchemaNode) {
+                        if (!foundLists.contains( child.getNodeType() ) ) {
+                            Preconditions.checkState(child instanceof SimpleNode<?>,
+                                    "Data representation of LeafList should be SimpleNode - %s", child.getNodeType());
+                            foundLists.add( child.getNodeType() );
+                            writeLeafList(writer, parent, (SimpleNode<?>) child, (LeafListSchemaNode) childSchema);
+                        }
+                    } else if (childSchema instanceof LeafSchemaNode) {
+                        Preconditions.checkState(child instanceof SimpleNode<?>,
+                                "Data representation of LeafList should be SimpleNode - %s", child.getNodeType());
+                        writeLeaf(writer, (SimpleNode<?>) child, (LeafSchemaNode) childSchema);
+                    } else if (childSchema instanceof AnyXmlSchemaNode) {
+                        if( child instanceof CompositeNode ) {
+                            writeContainer(writer, (CompositeNode) child, null);
+                        }
+                        else {
+                            handleNoSchemaFound( writer, child, parent );
+                        }
+                    } else {
+                        throw new UnsupportedDataTypeException("Schema can be ContainerSchemaNode, ListSchemaNode, "
+                                + "LeafListSchemaNode, or LeafSchemaNode. Other types are not supported yet.");
+                    }
                 }
-            } else {
-                throw new UnsupportedDataTypeException("Schema can be ContainerSchemaNode, ListSchemaNode, "
-                        + "LeafListSchemaNode, or LeafSchemaNode. Other types are not supported yet.");
-            }
-        }
     }
 
-    private void writeValue( final JsonWriter writer, Object value ) throws IOException {
-        if( value != null ) {
-            writer.value( String.valueOf( value ) );
-        }
-        else {
-            writer.value( "" );
-        }
+    private static void writeValue(final JsonWriter writer, final Object value) throws IOException {
+        writer.value(value == null ? "" : String.valueOf(value));
     }
 
     private void handleNoSchemaFound( final JsonWriter writer, final Node<?> node,
-                                      final CompositeNode parent ) throws IOException {
+            final CompositeNode parent ) throws IOException {
         if( node instanceof SimpleNode<?> ) {
             List<SimpleNode<?>> nodeLeafList = parent.getSimpleNodesByName( node.getNodeType() );
             if( nodeLeafList.size() == 1 ) {
@@ -166,7 +166,7 @@ class JsonMapper {
             }
         } else { // CompositeNode
             Preconditions.checkState( node instanceof CompositeNode,
-                    "Data representation of Container should be CompositeNode - " + node.getNodeType() );
+                    "Data representation of Container should be CompositeNode - %s", node.getNodeType());
 
             List<CompositeNode> nodeList = parent.getCompositesByName( node.getNodeType() );
             if( nodeList.size() == 1 ) {
@@ -178,11 +178,12 @@ class JsonMapper {
         }
     }
 
-    private DataSchemaNode findFirstSchemaForNode(final Node<?> node, final Set<DataSchemaNode> dataSchemaNode) {
+    private static DataSchemaNode findFirstSchemaForNode(final Node<?> node, final Set<DataSchemaNode> dataSchemaNode) {
         for (DataSchemaNode dsn : dataSchemaNode) {
             if (node.getNodeType().equals(dsn.getQName())) {
                 return dsn;
-            } else if (dsn instanceof ChoiceNode) {
+            }
+            if (dsn instanceof ChoiceNode) {
                 for (ChoiceCaseNode choiceCase : ((ChoiceNode) dsn).getCases()) {
                     DataSchemaNode foundDsn = findFirstSchemaForNode(node, choiceCase.getChildNodes());
                     if (foundDsn != null) {
@@ -245,8 +246,8 @@ class JsonMapper {
         TypeDefinition<?> baseType = RestUtil.resolveBaseTypeFrom(type);
 
         if (node.getValue() == null && !(baseType instanceof EmptyTypeDefinition)) {
-            logger.debug("While generationg JSON output null value was found for type "
-                    + baseType.getClass().getSimpleName() + ".");
+            LOG.debug("While generationg JSON output null value was found for type {}.",
+                    baseType.getClass().getSimpleName());
         }
 
         if (baseType instanceof IdentityrefTypeDefinition) {
@@ -291,25 +292,24 @@ class JsonMapper {
         }
     }
 
-    private void writeIdentityValuesDTOToJson(final JsonWriter writer, final IdentityValuesDTO valueDTO) throws IOException {
+    private static void writeIdentityValuesDTOToJson(final JsonWriter writer, final IdentityValuesDTO valueDTO) throws IOException {
         StringBuilder result = new StringBuilder();
         for (IdentityValue identityValue : valueDTO.getValuesWithNamespaces()) {
-            result.append("/");
+            result.append('/');
 
             writeModuleNameAndIdentifier(result, identityValue);
             if (identityValue.getPredicates() != null && !identityValue.getPredicates().isEmpty()) {
                 for (Predicate predicate : identityValue.getPredicates()) {
                     IdentityValue identityValuePredicate = predicate.getName();
-                    result.append("[");
+                    result.append('[');
                     if (identityValuePredicate == null) {
-                        result.append(".");
+                        result.append('.');
                     } else {
                         writeModuleNameAndIdentifier(result, identityValuePredicate);
                     }
                     result.append("='");
                     result.append(predicate.getValue());
-                    result.append("'");
-                    result.append("]");
+                    result.append("']");
                 }
             }
         }
@@ -317,21 +317,22 @@ class JsonMapper {
         writer.value(result.toString());
     }
 
-    private void writeModuleNameAndIdentifier(final StringBuilder result, final IdentityValue identityValue) {
+    private static void writeModuleNameAndIdentifier(final StringBuilder result, final IdentityValue identityValue) {
         String moduleName = ControllerContext.getInstance().findModuleNameByNamespace(
                 URI.create(identityValue.getNamespace()));
         if (moduleName != null && !moduleName.isEmpty()) {
             result.append(moduleName);
-            result.append(":");
+            result.append(':');
         }
         result.append(identityValue.getValue());
     }
 
-    private void writeStringRepresentation(final JsonWriter writer, final SimpleNode<?> node, final TypeDefinition<?> baseType,
+    private static void writeStringRepresentation(final JsonWriter writer, final SimpleNode<?> node, final TypeDefinition<?> baseType,
             final Class<?> requiredType) throws IOException {
         Object value = node.getValue();
-        logger.debug("Value of " + baseType.getQName().getNamespace() + ":" + baseType.getQName().getLocalName()
-                + " is not instance of " + requiredType.getClass() + " but is " + node.getValue().getClass());
+        LOG.debug("Value of {}:{} is not instance of {} but is {}",
+                baseType.getQName().getNamespace(), baseType.getQName().getLocalName(),
+                requiredType.getClass(), node.getValue().getClass());
         if (value == null) {
             writer.value("");
         } else {
@@ -358,7 +359,7 @@ class JsonMapper {
             if (moduleName != null) {
                 nameForOutput = moduleName.toString();
             } else {
-                logger.info("Module '{}' was not found in schema from mount point", schema.getQName());
+                LOG.info("Module '{}' was not found in schema from mount point", schema.getQName());
             }
         }
         writer.name(nameForOutput);
index 1f7b061e921cd057d13ece0002e998973fb66db2..e94554061800cb8ae918dc59a598fea980cac972 100644 (file)
@@ -7,9 +7,17 @@
  */
 package org.opendaylight.controller.sal.rest.impl;
 
+import com.google.common.base.Splitter;
+import com.google.common.collect.Iterators;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonParser;
+import com.google.gson.JsonPrimitive;
+
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.URI;
+import java.util.Iterator;
 import java.util.Map.Entry;
 import java.util.Set;
 
@@ -18,21 +26,22 @@ import org.opendaylight.controller.sal.restconf.impl.CompositeNodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.EmptyNodeWrapper;
 import org.opendaylight.controller.sal.restconf.impl.IdentityValuesDTO;
 import org.opendaylight.controller.sal.restconf.impl.SimpleNodeWrapper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
-import com.google.common.collect.Lists;
-import com.google.gson.JsonElement;
-import com.google.gson.JsonObject;
-import com.google.gson.JsonParser;
-import com.google.gson.JsonPrimitive;
+final class JsonReader {
+    private static final Logger LOG = LoggerFactory.getLogger(JsonReader.class);
+    private static final Splitter COLON_SPLITTER = Splitter.on(':');
+
+    private JsonReader() {
 
-class JsonReader {
+    }
 
-    public CompositeNodeWrapper read(InputStream entityStream) throws UnsupportedFormatException {
+    public static CompositeNodeWrapper read(final InputStream entityStream) throws UnsupportedFormatException {
         JsonParser parser = new JsonParser();
 
         JsonElement rootElement = parser.parse(new InputStreamReader(entityStream));
-        if( rootElement.isJsonNull() )
-        {
+        if (rootElement.isJsonNull()) {
             //no content, so return null to indicate no input
             return null;
         }
@@ -44,29 +53,31 @@ class JsonReader {
         Set<Entry<String, JsonElement>> entrySetsOfRootJsonObject = rootElement.getAsJsonObject().entrySet();
         if (entrySetsOfRootJsonObject.size() != 1) {
             throw new UnsupportedFormatException("Json Object should contain one element");
-        } else {
-            Entry<String, JsonElement> childEntry = Lists.newArrayList(entrySetsOfRootJsonObject).get(0);
-            String firstElementName = childEntry.getKey();
-            JsonElement firstElementType = childEntry.getValue();
-            if (firstElementType.isJsonObject()) { // container in yang
-                return createStructureWithRoot(firstElementName, firstElementType.getAsJsonObject());
-            }
-            if (firstElementType.isJsonArray()) { // list in yang
-                if (firstElementType.getAsJsonArray().size() == 1) {
-                    JsonElement firstElementInArray = firstElementType.getAsJsonArray().get(0);
-                    if (firstElementInArray.isJsonObject()) {
-                        return createStructureWithRoot(firstElementName, firstElementInArray.getAsJsonObject());
-                    }
-                    throw new UnsupportedFormatException(
-                            "Array as the first element in Json Object can have only Object element");
+        }
+
+        Entry<String, JsonElement> childEntry = entrySetsOfRootJsonObject.iterator().next();
+        String firstElementName = childEntry.getKey();
+        JsonElement firstElementType = childEntry.getValue();
+        if (firstElementType.isJsonObject()) {
+            // container in yang
+            return createStructureWithRoot(firstElementName, firstElementType.getAsJsonObject());
+        }
+        if (firstElementType.isJsonArray()) {
+            // list in yang
+            if (firstElementType.getAsJsonArray().size() == 1) {
+                JsonElement firstElementInArray = firstElementType.getAsJsonArray().get(0);
+                if (firstElementInArray.isJsonObject()) {
+                    return createStructureWithRoot(firstElementName, firstElementInArray.getAsJsonObject());
                 }
+                throw new UnsupportedFormatException(
+                        "Array as the first element in Json Object can have only Object element");
             }
-            throw new UnsupportedFormatException(
-                    "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet.");
         }
+        throw new UnsupportedFormatException(
+                "First element in Json Object has to be \"Object\" or \"Array with one Object element\". Other scenarios are not supported yet.");
     }
 
-    private CompositeNodeWrapper createStructureWithRoot(String rootObjectName, JsonObject rootObject) {
+    private static CompositeNodeWrapper createStructureWithRoot(final String rootObjectName, final JsonObject rootObject) {
         CompositeNodeWrapper firstNode = new CompositeNodeWrapper(getNamespaceFor(rootObjectName),
                 getLocalNameFor(rootObjectName));
         for (Entry<String, JsonElement> childOfFirstNode : rootObject.entrySet()) {
@@ -75,7 +86,7 @@ class JsonReader {
         return firstNode;
     }
 
-    private void addChildToParent(String childName, JsonElement childType, CompositeNodeWrapper parent) {
+    private static void addChildToParent(final String childName, final JsonElement childType, final CompositeNodeWrapper parent) {
         if (childType.isJsonObject()) {
             CompositeNodeWrapper child = new CompositeNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName));
             parent.addValue(child);
@@ -85,7 +96,6 @@ class JsonReader {
         } else if (childType.isJsonArray()) {
             if (childType.getAsJsonArray().size() == 1 && childType.getAsJsonArray().get(0).isJsonNull()) {
                 parent.addValue(new EmptyNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName)));
-
             } else {
                 for (JsonElement childOfChildType : childType.getAsJsonArray()) {
                     addChildToParent(childName, childOfChildType, parent);
@@ -96,35 +106,42 @@ class JsonReader {
             String value = childPrimitive.getAsString().trim();
             parent.addValue(new SimpleNodeWrapper(getNamespaceFor(childName), getLocalNameFor(childName),
                     resolveValueOfElement(value)));
+        } else {
+            LOG.debug("Ignoring unhandled child type {}", childType);
         }
     }
 
-    private URI getNamespaceFor(String jsonElementName) {
-        String[] moduleNameAndLocalName = jsonElementName.split(":");
-        // it is not "moduleName:localName"
-        if (moduleNameAndLocalName.length != 2) {
-            return null;
+    private static URI getNamespaceFor(final String jsonElementName) {
+        final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
+
+        // The string needs to me in form "moduleName:localName"
+        if (it.hasNext()) {
+            final String maybeURI = it.next();
+            if (Iterators.size(it) == 1) {
+                return URI.create(maybeURI);
+            }
         }
-        return URI.create(moduleNameAndLocalName[0]);
+
+        return null;
     }
 
-    private String getLocalNameFor(String jsonElementName) {
-        String[] moduleNameAndLocalName = jsonElementName.split(":");
-        // it is not "moduleName:localName"
-        if (moduleNameAndLocalName.length != 2) {
-            return jsonElementName;
-        }
-        return moduleNameAndLocalName[1];
+    private static String getLocalNameFor(final String jsonElementName) {
+        final Iterator<String> it = COLON_SPLITTER.split(jsonElementName).iterator();
+
+        // The string needs to me in form "moduleName:localName"
+        final String ret = Iterators.get(it, 1, null);
+        return ret != null && !it.hasNext() ? ret : jsonElementName;
     }
 
-    private Object resolveValueOfElement(String value) {
+    private static Object resolveValueOfElement(final String value) {
         // it could be instance-identifier Built-In Type
-        if (value.startsWith("/")) {
+        if (!value.isEmpty() && value.charAt(0) == '/') {
             IdentityValuesDTO resolvedValue = RestUtil.asInstanceIdentifier(value, new PrefixMapingFromJson());
             if (resolvedValue != null) {
                 return resolvedValue;
             }
         }
+
         // it could be identityref Built-In Type
         URI namespace = getNamespaceFor(value);
         if (namespace != null) {
index 856e09fabd21a1083cbe716890ba22ae3b2d5bc6..9e6966540534c9c79d2a120f89c35ebf603d956d 100644 (file)
@@ -30,29 +30,28 @@ import org.slf4j.LoggerFactory;
 
 @Provider
 @Consumes({ Draft02.MediaTypes.DATA + RestconfService.JSON, Draft02.MediaTypes.OPERATION + RestconfService.JSON,
-        MediaType.APPLICATION_JSON })
+    MediaType.APPLICATION_JSON })
 public enum JsonToCompositeNodeProvider implements MessageBodyReader<CompositeNode> {
     INSTANCE;
 
     private final static Logger LOG = LoggerFactory.getLogger( JsonToCompositeNodeProvider.class );
 
     @Override
-    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    public boolean isReadable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
         return true;
     }
 
     @Override
-    public CompositeNode readFrom(Class<CompositeNode> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream)
-            throws IOException, WebApplicationException {
-        JsonReader jsonReader = new JsonReader();
+    public CompositeNode readFrom(final Class<CompositeNode> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType, final MultivaluedMap<String, String> httpHeaders, final InputStream entityStream)
+                    throws IOException, WebApplicationException {
         try {
-            return jsonReader.read(entityStream);
+            return JsonReader.read(entityStream);
         } catch (Exception e) {
-            LOG.debug( "Error parsing json input", e );
+            LOG.debug( "Error parsing json input", e);
             throw new RestconfDocumentedException(
-                            "Error parsing input: " + e.getMessage(),
-                            ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE );
+                    "Error parsing input: " + e.getMessage(),
+                    ErrorType.PROTOCOL, ErrorTag.MALFORMED_MESSAGE);
         }
     }
 
index 290d976b2857c493e7c638592e2715e963a03277..cd263d3c55b0a56ce40feca32690749bd489ed6e 100644 (file)
@@ -21,11 +21,13 @@ import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 
 public final class RestUtil {
 
+    // FIXME: BUG-1275: this is code duplicates data.impl.codec
+
     public static final String SQUOTE = "'";
     public static final String DQUOTE = "\"";
     private static final Pattern PREDICATE_PATTERN = Pattern.compile("\\[(.*?)\\]");
 
-    public final static TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) {
+    public final static TypeDefinition<?> resolveBaseTypeFrom(final TypeDefinition<?> type) {
         TypeDefinition<?> superType = type;
         while (superType.getBaseType() != null) {
             superType = superType.getBaseType();
@@ -33,7 +35,7 @@ public final class RestUtil {
         return superType;
     }
 
-    public static IdentityValuesDTO asInstanceIdentifier(String value, PrefixesMaping prefixMap) {
+    public static IdentityValuesDTO asInstanceIdentifier(final String value, final PrefixesMaping prefixMap) {
         String valueTrimmed = value.trim();
         if (!valueTrimmed.startsWith("/")) {
             return null;
@@ -63,12 +65,12 @@ public final class RestUtil {
         return identityValuesDTO.getValuesWithNamespaces().isEmpty() ? null : identityValuesDTO;
     }
 
-    private static String getIdAndPrefixAsStr(String pathPart) {
+    private static String getIdAndPrefixAsStr(final String pathPart) {
         int predicateStartIndex = pathPart.indexOf("[");
         return predicateStartIndex == -1 ? pathPart : pathPart.substring(0, predicateStartIndex);
     }
 
-    private static IdentityValue toIdentity(String xPathPart, PrefixesMaping prefixMap) {
+    private static IdentityValue toIdentity(final String xPathPart, final PrefixesMaping prefixMap) {
         String xPathPartTrimmed = xPathPart.trim();
         if (xPathPartTrimmed.isEmpty()) {
             return null;
@@ -87,7 +89,7 @@ public final class RestUtil {
         return new IdentityValue(namespace, identifier, namespace.equals(prefix) ? null : prefix);
     }
 
-    private static List<Predicate> toPredicates(String predicatesStr, PrefixesMaping prefixMap) {
+    private static List<Predicate> toPredicates(final String predicatesStr, final PrefixesMaping prefixMap) {
         List<Predicate> result = new ArrayList<>();
         List<String> predicates = new ArrayList<>();
         Matcher matcher = PREDICATE_PATTERN.matcher(predicatesStr);
@@ -116,7 +118,7 @@ public final class RestUtil {
         return result;
     }
 
-    private static String toPredicateValue(String predicatedValue) {
+    private static String toPredicateValue(final String predicatedValue) {
         String predicatedValueTrimmed = predicatedValue.trim();
         if ((predicatedValueTrimmed.startsWith(DQUOTE) || predicatedValueTrimmed.startsWith(SQUOTE))
                 && (predicatedValueTrimmed.endsWith(DQUOTE) || predicatedValueTrimmed.endsWith(SQUOTE))) {
@@ -132,12 +134,12 @@ public final class RestUtil {
     public static class PrefixMapingFromXml implements PrefixesMaping {
         StartElement startElement = null;
 
-        public PrefixMapingFromXml(StartElement startElement) {
+        public PrefixMapingFromXml(final StartElement startElement) {
             this.startElement = startElement;
         }
 
         @Override
-        public String getNamespace(String prefix) {
+        public String getNamespace(final String prefix) {
             return startElement.getNamespaceContext().getNamespaceURI(prefix);
         }
     }
@@ -145,7 +147,7 @@ public final class RestUtil {
     public static class PrefixMapingFromJson implements PrefixesMaping {
 
         @Override
-        public String getNamespace(String prefix) {
+        public String getNamespace(final String prefix) {
             return prefix;
         }
     }
index 5f6909cea8e3e15d2b7887fe975d2d3e613163b5..0854ca71673465e76e7659bfa9479afc3fb1962f 100644 (file)
@@ -17,6 +17,11 @@ import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ER
 import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.ERROR_TYPE_QNAME;
 import static org.opendaylight.controller.sal.rest.api.Draft02.RestConfModule.NAMESPACE;
 
+import com.google.common.base.Charsets;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.gson.stream.JsonWriter;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.OutputStreamWriter;
@@ -57,10 +62,6 @@ import org.slf4j.LoggerFactory;
 import org.w3c.dom.Document;
 import org.xml.sax.InputSource;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.gson.stream.JsonWriter;
-
 /**
  * This class defines an ExceptionMapper that handles RestconfDocumentedExceptions thrown by
  * resource implementations and translates appropriately to restconf error response as defined in
@@ -139,20 +140,19 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
     private Object toJsonResponseBody( final ImmutableCompositeNode errorsNode,
             final DataNodeContainer errorsSchemaNode ) {
 
-        JsonMapper jsonMapper = new JsonMapper();
+        JsonMapper jsonMapper = new JsonMapper(null);
 
         Object responseBody = null;
         try {
             ByteArrayOutputStream outStream = new ByteArrayOutputStream();
-            JsonWriter writer = new JsonWriter( new OutputStreamWriter( outStream, "UTF-8" ) );
+            JsonWriter writer = new JsonWriter(new OutputStreamWriter( outStream, Charsets.UTF_8));
             writer.setIndent( "    " );
 
-            jsonMapper.write( writer, errorsNode, errorsSchemaNode, null );
+            jsonMapper.write( writer, errorsNode, errorsSchemaNode);
             writer.flush();
 
             responseBody = outStream.toString( "UTF-8" );
-        }
-        catch( IOException e ) {
+        } catch( IOException e ) {
             LOG.error( "Error writing error response body", e );
         }
 
@@ -239,13 +239,11 @@ public class RestconfDocumentedExceptionMapper implements ExceptionMapper<Restco
         try {
             doc = factory.newDocumentBuilder().parse(
                     new InputSource( new StringReader( errorInfoWithRoot ) ) );
-        }
-        catch( Exception e ) {
+        } catch( Exception e ) {
             // TODO: what if the content is text that happens to contain invalid markup? Could
             // wrap in CDATA and try again.
 
-            LOG.warn( "Error parsing restconf error-info, \"" + errorInfo + "\", as XML: " +
-                    e.toString() );
+            LOG.warn( "Error parsing restconf error-info, \"{}\", as XML", errorInfo, e);
             return null;
         }
 
index 422cf04cca82f7d0bf5d2f535df40a6f7688215e..1c2e9c5009897f741efaa6a1320665d7ba2a4b0a 100644 (file)
@@ -7,6 +7,9 @@
  */
 package org.opendaylight.controller.sal.rest.impl;
 
+import com.google.common.base.Charsets;
+import com.google.gson.stream.JsonWriter;
+
 import java.io.IOException;
 import java.io.OutputStream;
 import java.io.OutputStreamWriter;
@@ -28,37 +31,35 @@ import org.opendaylight.controller.sal.restconf.impl.StructuredData;
 import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
 
-import com.google.gson.stream.JsonWriter;
-
 @Provider
 @Produces({ Draft02.MediaTypes.API + RestconfService.JSON, Draft02.MediaTypes.DATA + RestconfService.JSON,
-        Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON })
+    Draft02.MediaTypes.OPERATION + RestconfService.JSON, MediaType.APPLICATION_JSON })
 public enum StructuredDataToJsonProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
     @Override
-    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
         return type.equals( StructuredData.class );
     }
 
     @Override
-    public long getSize(StructuredData t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    public long getSize(final StructuredData t, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
         return -1;
     }
 
     @Override
-    public void writeTo(StructuredData t, Class<?> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
-            throws IOException, WebApplicationException {
+    public void writeTo(final StructuredData t, final Class<?> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
+                    throws IOException, WebApplicationException {
         CompositeNode data = t.getData();
         if (data == null) {
             throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
         }
 
-        JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, "UTF-8"));
+        JsonWriter writer = new JsonWriter(new OutputStreamWriter(entityStream, Charsets.UTF_8));
         writer.setIndent("    ");
-        JsonMapper jsonMapper = new JsonMapper();
-        jsonMapper.write(writer, data, (DataNodeContainer) t.getSchema(), t.getMountPoint());
+        JsonMapper jsonMapper = new JsonMapper(t.getMountPoint());
+        jsonMapper.write(writer, data, (DataNodeContainer) t.getSchema());
         writer.flush();
     }
 
index bcb3c422ff8dc0c33c8a44d27d20b63ec1e3852d..e5a56cf47566c6ca4d3d8e1113b817706b404d71 100644 (file)
@@ -21,6 +21,7 @@ import javax.ws.rs.ext.MessageBodyWriter;
 import javax.ws.rs.ext.Provider;
 import javax.xml.transform.OutputKeys;
 import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
 import javax.xml.transform.TransformerException;
 import javax.xml.transform.TransformerFactory;
 import javax.xml.transform.dom.DOMSource;
@@ -40,46 +41,68 @@ import org.w3c.dom.Document;
 
 @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 enum StructuredDataToXmlProvider implements MessageBodyWriter<StructuredData> {
     INSTANCE;
 
-    private final static Logger logger = LoggerFactory.getLogger(StructuredDataToXmlProvider.class);
+    private static final Logger LOG = LoggerFactory.getLogger(StructuredDataToXmlProvider.class);
+    private static final TransformerFactory FACTORY = TransformerFactory.newInstance();
+    private static final ThreadLocal<Transformer> TRANSFORMER = new ThreadLocal<Transformer>() {
+        @Override
+        protected Transformer initialValue() {
+            final Transformer ret;
+            try {
+                ret = FACTORY.newTransformer();
+            } catch (TransformerConfigurationException e) {
+                LOG.error("Failed to instantiate XML transformer", e);
+                throw new IllegalStateException("XML encoding currently unavailable", e);
+            }
+
+            ret.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+            ret.setOutputProperty(OutputKeys.METHOD, "xml");
+            ret.setOutputProperty(OutputKeys.INDENT, "yes");
+            ret.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
+            ret.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
+
+            return ret;
+        }
+    };
 
     @Override
-    public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    public boolean isWriteable(final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
         return type.equals( StructuredData.class );
     }
 
     @Override
-    public long getSize(StructuredData t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
+    public long getSize(final StructuredData t, final Class<?> type, final Type genericType, final Annotation[] annotations, final MediaType mediaType) {
         return -1;
     }
 
     @Override
-    public void writeTo(StructuredData t, Class<?> type, Type genericType, Annotation[] annotations,
-            MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream)
-            throws IOException, WebApplicationException {
+    public void writeTo(final StructuredData t, final Class<?> type, final Type genericType, final Annotation[] annotations,
+            final MediaType mediaType, final MultivaluedMap<String, Object> httpHeaders, final OutputStream entityStream)
+                    throws IOException, WebApplicationException {
         CompositeNode data = t.getData();
         if (data == null) {
             throw new RestconfDocumentedException(Response.Status.NOT_FOUND);
         }
 
-        XmlMapper xmlMapper = new XmlMapper();
-        Document domTree = xmlMapper.write(data, (DataNodeContainer) t.getSchema());
+        final Transformer trans;
+        try {
+            trans = TRANSFORMER.get();
+        } catch (RuntimeException e) {
+            throw new RestconfDocumentedException(e.getMessage(), ErrorType.TRANSPORT,
+                    ErrorTag.OPERATION_FAILED);
+        }
+
+        // FIXME: BUG-1281: eliminate the intermediate Document
+        final Document domTree = new XmlMapper().write(data, (DataNodeContainer) t.getSchema());
         try {
-            TransformerFactory tf = TransformerFactory.newInstance();
-            Transformer transformer = tf.newTransformer();
-            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
-            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
-            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
-            transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
-            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
-            transformer.transform(new DOMSource(domTree), new StreamResult(entityStream));
+            trans.transform(new DOMSource(domTree), new StreamResult(entityStream));
         } catch (TransformerException e) {
-            logger.error("Error during translation of Document to OutputStream", e);
-            throw new RestconfDocumentedException( e.getMessage(), ErrorType.TRANSPORT,
-                                                   ErrorTag.OPERATION_FAILED );
+            LOG.error("Error during translation of Document to OutputStream", e);
+            throw new RestconfDocumentedException(e.getMessage(), ErrorType.TRANSPORT,
+                    ErrorTag.OPERATION_FAILED);
         }
     }
 
index 96ad528a0dd3f9e0591b78b2be702e9b1d004c4c..69b975dab7e5ef15bb7e5ad4cf389ed55f0ef9c8 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.sal.restconf.impl;
 
+import com.google.common.base.Preconditions;
+
 import java.net.URI;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -23,8 +25,6 @@ import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.api.SimpleNode;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 
-import com.google.common.base.Preconditions;
-
 public final class CompositeNodeWrapper implements NodeWrapper<CompositeNode>, CompositeNode {
 
     private MutableCompositeNode compositeNode;
@@ -104,7 +104,7 @@ public final class CompositeNodeWrapper implements NodeWrapper<CompositeNode>, C
                 name = new QName(namespace, localName);
             }
 
-            List<Node<?>> nodeValues = new ArrayList<>();
+            List<Node<?>> nodeValues = new ArrayList<>(values.size());
             for (NodeWrapper<?> nodeWrapper : values) {
                 nodeValues.add(nodeWrapper.unwrap());
             }
index 7a16105056eea240ecf7aa2815f785152478ed82..85c8e595396e9463b8fb7bf93437510041306b09 100644 (file)
@@ -18,7 +18,6 @@ import com.google.common.collect.BiMap;
 import com.google.common.collect.FluentIterable;
 import com.google.common.collect.HashBiMap;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
 
 import java.io.UnsupportedEncodingException;
 import java.net.URI;
@@ -83,6 +82,10 @@ public class ControllerContext implements SchemaContextListener {
 
     private final static String URI_ENCODING_CHAR_SET = "ISO-8859-1";
 
+    private static final Splitter SLASH_SPLITTER = Splitter.on('/');
+
+    private static final Splitter COLON_SPLITTER = Splitter.on(':');
+
     private final BiMap<URI, String> uriToModuleName = HashBiMap.<URI, String> create();
 
     private final Map<String, URI> moduleNameToUri = uriToModuleName.inverse();
@@ -129,10 +132,8 @@ public class ControllerContext implements SchemaContextListener {
             final boolean toMountPointIdentifier ) {
         this.checkPreconditions();
 
-        Iterable<String> split = Splitter.on( "/" ).split( restconfInstance );
-        final ArrayList<String> encodedPathArgs = Lists.<String> newArrayList( split );
-        final List<String> pathArgs = this.urlPathArgsDecode( encodedPathArgs );
-        this.omitFirstAndLastEmptyString( pathArgs );
+        final List<String> pathArgs = urlPathArgsDecode( SLASH_SPLITTER.split( restconfInstance ) );
+        omitFirstAndLastEmptyString( pathArgs );
         if( pathArgs.isEmpty() ) {
             return null;
         }
@@ -158,7 +159,7 @@ public class ControllerContext implements SchemaContextListener {
         return iiWithSchemaNode;
     }
 
-    private List<String> omitFirstAndLastEmptyString( final List<String> list ) {
+    private static List<String> omitFirstAndLastEmptyString( final List<String> list ) {
         if( list.isEmpty() ) {
             return list;
         }
@@ -562,7 +563,7 @@ public class ControllerContext implements SchemaContextListener {
         }
 
         String head = strings.iterator().next();
-        final String nodeName = this.toNodeName( head );
+        final String nodeName = toNodeName( head );
         final String moduleName = ControllerContext.toModuleName( head );
 
         DataSchemaNode targetNode = null;
@@ -839,20 +840,20 @@ public class ControllerContext implements SchemaContextListener {
 
     private static String toModuleName( final String str ) {
         Preconditions.<String> checkNotNull( str );
-        if( str.contains( ":" ) ) {
-            final String[] args = str.split( ":" );
-            if( args.length == 2 ) {
-                return args[0];
+        if( str.indexOf( ':' ) != -1 ) {
+            final Iterable<String> args = COLON_SPLITTER.split( str );
+            if( Iterables.size( args ) == 2 ) {
+                return args.iterator().next();
             }
         }
         return null;
     }
 
-    private String toNodeName( final String str ) {
-        if( str.contains( ":" ) ) {
-            final String[] args = str.split( ":" );
-            if( args.length == 2 ) {
-                return args[1];
+    private static String toNodeName( final String str ) {
+        if( str.indexOf( ':' ) != -1 ) {
+            final Iterable<String> args = COLON_SPLITTER.split( str );
+            if( Iterables.size( args ) == 2 ) {
+                return Iterables.get( args, 1 );
             }
         }
         return str;
@@ -860,7 +861,7 @@ public class ControllerContext implements SchemaContextListener {
 
     private QName toQName( final String name ) {
         final String module = toModuleName( name );
-        final String node = this.toNodeName( name );
+        final String node = toNodeName( name );
         Set<Module> modules = globalSchema.getModules();
 
         final Comparator<Module> comparator = new Comparator<Module>() {
@@ -916,7 +917,7 @@ public class ControllerContext implements SchemaContextListener {
         }
     }
 
-    public List<String> urlPathArgsDecode( final List<String> strings ) {
+    public static List<String> urlPathArgsDecode( final Iterable<String> strings ) {
         try {
             List<String> decodedPathArgs = new ArrayList<String>();
             for( final String pathArg : strings ) {
@@ -998,7 +999,7 @@ public class ControllerContext implements SchemaContextListener {
             try {
                 builder.append( this.toUriString( keyValues.get( key ) ) );
             } catch( UnsupportedEncodingException e ) {
-                LOG.error( "Error parsing URI: " + keyValues.get( key ), e );
+                LOG.error( "Error parsing URI: {}", keyValues.get( key ), e );
                 return null;
             }
         }
index 934d4434c38a3e724279405da05198099eba2f70..f93a0aea70fa311a7dd0b6f8ba520d8153f03b89 100644 (file)
@@ -7,6 +7,8 @@
  */
 package org.opendaylight.controller.sal.restconf.impl;
 
+import com.google.common.base.Preconditions;
+
 import java.net.URI;
 import java.util.Collections;
 
@@ -15,8 +17,6 @@ import org.opendaylight.yangtools.yang.data.api.CompositeNode;
 import org.opendaylight.yangtools.yang.data.api.Node;
 import org.opendaylight.yangtools.yang.data.impl.NodeFactory;
 
-import com.google.common.base.Preconditions;
-
 public final class EmptyNodeWrapper implements NodeWrapper<Node<?>>, Node<Void> {
 
     private Node<?> unwrapped;
@@ -31,17 +31,17 @@ public final class EmptyNodeWrapper implements NodeWrapper<Node<?>>, Node<Void>
         return composite;
     }
 
-    public void setComposite(boolean composite) {
+    public void setComposite(final boolean composite) {
         this.composite = composite;
     }
 
-    public EmptyNodeWrapper(URI namespace, String localName) {
+    public EmptyNodeWrapper(final URI namespace, final String localName) {
         this.localName = Preconditions.checkNotNull(localName);
         this.namespace = namespace;
     }
 
     @Override
-    public void setQname(QName name) {
+    public void setQname(final QName name) {
         Preconditions.checkState(unwrapped == null, "Cannot change the object, due to data inconsistencies.");
         this.name = name;
     }
@@ -68,7 +68,7 @@ public final class EmptyNodeWrapper implements NodeWrapper<Node<?>>, Node<Void>
     }
 
     @Override
-    public void setNamespace(URI namespace) {
+    public void setNamespace(final URI namespace) {
         Preconditions.checkState(unwrapped == null, "Cannot change the object, due to data inconsistencies.");
         this.namespace = namespace;
     }
@@ -103,6 +103,7 @@ public final class EmptyNodeWrapper implements NodeWrapper<Node<?>>, Node<Void>
     }
 
     @Override
+    @Deprecated
     public CompositeNode getParent() {
         return unwrap().getParent();
     }
@@ -118,7 +119,7 @@ public final class EmptyNodeWrapper implements NodeWrapper<Node<?>>, Node<Void>
     }
 
     @Override
-    public Void setValue(Void value) {
+    public Void setValue(final Void value) {
         return null;
     }
 
index e1c163bc48ad14bf3a7cb59757320d5bc5ab4d65..925a09337ca3ee1e8fba707020e3c7a19b8e03f6 100644 (file)
@@ -7,6 +7,7 @@
  */
 package org.opendaylight.controller.sal.streams.listeners;
 
+import com.google.common.base.Charsets;
 import com.google.common.base.Preconditions;
 import com.google.common.eventbus.AsyncEventBus;
 import com.google.common.eventbus.EventBus;
@@ -28,6 +29,7 @@ import java.util.Map.Entry;
 import java.util.Random;
 import java.util.Set;
 import java.util.concurrent.Executors;
+import java.util.regex.Pattern;
 
 import javax.activation.UnsupportedDataTypeException;
 import javax.xml.parsers.DocumentBuilder;
@@ -64,8 +66,11 @@ import org.w3c.dom.Node;
  */
 public class ListenerAdapter implements DataChangeListener {
 
-    private static final Logger logger = LoggerFactory
-            .getLogger(ListenerAdapter.class);
+    private static final Logger LOG = LoggerFactory.getLogger(ListenerAdapter.class);
+    private static final DocumentBuilderFactory DBF = DocumentBuilderFactory.newInstance();
+    private static final TransformerFactory FACTORY = TransformerFactory.newInstance();
+    private static final Pattern RFC3339_PATTERN = Pattern.compile("(\\d\\d)(\\d\\d)$");
+
     private final XmlMapper xmlMapper = new XmlMapper();
     private final SimpleDateFormat rfc3339 = new SimpleDateFormat(
             "yyyy-MM-dd'T'hh:mm:ssZ");
@@ -77,6 +82,7 @@ public class ListenerAdapter implements DataChangeListener {
     private final EventBus eventBus;
     private final EventBusChangeRecorder eventBusChangeRecorder;
 
+
     /**
      * Creates new {@link ListenerAdapter} listener specified by path and stream
      * name.
@@ -131,12 +137,12 @@ public class ListenerAdapter implements DataChangeListener {
             } else if (event.getType() == EventType.NOTIFY) {
                 for (Channel subscriber : subscribers) {
                     if (subscriber.isActive()) {
-                        logger.debug("Data are sent to subscriber {}:",
+                        LOG.debug("Data are sent to subscriber {}:",
                                 subscriber.remoteAddress());
                         subscriber.writeAndFlush(new TextWebSocketFrame(event
                                 .getData()));
                     } else {
-                        logger.debug(
+                        LOG.debug(
                                 "Subscriber {} is removed - channel is not active yet.",
                                 subscriber.remoteAddress());
                         subscribers.remove(subscriber);
@@ -248,22 +254,19 @@ public class ListenerAdapter implements DataChangeListener {
 
         try {
             ByteArrayOutputStream out = new ByteArrayOutputStream();
-            TransformerFactory tf = TransformerFactory.newInstance();
-            Transformer transformer = tf.newTransformer();
-            transformer
-            .setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
+            Transformer transformer = FACTORY.newTransformer();
+            transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no");
             transformer.setOutputProperty(OutputKeys.METHOD, "xml");
             transformer.setOutputProperty(OutputKeys.INDENT, "yes");
             transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
-            transformer.setOutputProperty(
-                    "{http://xml.apache.org/xslt}indent-amount", "4");
+            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
             transformer.transform(new DOMSource(doc), new StreamResult(
-                    new OutputStreamWriter(out, "UTF-8")));
+                    new OutputStreamWriter(out, Charsets.UTF_8)));
             byte[] charData = out.toByteArray();
             return new String(charData, "UTF-8");
         } catch (TransformerException | UnsupportedEncodingException e) {
             String msg = "Error during transformation of Document into String";
-            logger.error(msg, e);
+            LOG.error(msg, e);
             return msg;
         }
     }
@@ -276,7 +279,7 @@ public class ListenerAdapter implements DataChangeListener {
      * @return Data specified by RFC3339.
      */
     private String toRFC3339(final Date d) {
-        return rfc3339.format(d).replaceAll("(\\d\\d)(\\d\\d)$", "$1:$2");
+        return RFC3339_PATTERN.matcher(rfc3339.format(d)).replaceAll("$1:$2");
     }
 
     /**
@@ -285,15 +288,13 @@ public class ListenerAdapter implements DataChangeListener {
      * @return {@link Document} document.
      */
     private Document createDocument() {
-        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
-        Document doc = null;
+        final DocumentBuilder bob;
         try {
-            DocumentBuilder bob = dbf.newDocumentBuilder();
-            doc = bob.newDocument();
+            bob = DBF.newDocumentBuilder();
         } catch (ParserConfigurationException e) {
             return null;
         }
-        return doc;
+        return bob.newDocument();
     }
 
     /**
@@ -444,7 +445,7 @@ public class ListenerAdapter implements DataChangeListener {
         DataNodeContainer schemaNode = ControllerContext.getInstance()
                 .getDataNodeContainerFor(path);
         if (schemaNode == null) {
-            logger.info(
+            LOG.info(
                     "Path '{}' contains node with unsupported type (supported type is Container or List) or some node was not found.",
                     path);
             return null;
@@ -453,7 +454,7 @@ public class ListenerAdapter implements DataChangeListener {
             Document xml = xmlMapper.write(data, schemaNode);
             return xml.getFirstChild();
         } catch (UnsupportedDataTypeException e) {
-            logger.error(
+            LOG.error(
                     "Error occured during translation of notification to XML.",
                     e);
             return null;
@@ -474,6 +475,8 @@ public class ListenerAdapter implements DataChangeListener {
         Map<String, String> prefixes = new HashMap<>();
         InstanceIdentifier instanceIdentifier = path;
         StringBuilder textContent = new StringBuilder();
+
+        // FIXME: BUG-1281: this is duplicated code from yangtools (BUG-1275)
         for (PathArgument pathArgument : instanceIdentifier.getPathArguments()) {
             textContent.append("/");
             writeIdentifierWithNamespacePrefix(element, textContent,
@@ -613,7 +616,7 @@ public class ListenerAdapter implements DataChangeListener {
      */
     public void addSubscriber(final Channel subscriber) {
         if (!subscriber.isActive()) {
-            logger.debug("Channel is not active between websocket server and subscriber {}"
+            LOG.debug("Channel is not active between websocket server and subscriber {}"
                     + subscriber.remoteAddress());
         }
         Event event = new Event(EventType.REGISTER);
@@ -628,7 +631,7 @@ public class ListenerAdapter implements DataChangeListener {
      * @param subscriber
      */
     public void removeSubscriber(final Channel subscriber) {
-        logger.debug("Subscriber {} is removed.", subscriber.remoteAddress());
+        LOG.debug("Subscriber {} is removed.", subscriber.remoteAddress());
         Event event = new Event(EventType.DEREGISTER);
         event.setSubscriber(subscriber);
         eventBus.post(event);
index b5d6a6ea9be647d22c1dc8a75609506433e850f6..26e4936d3f27d0d20e3875fe051335d79beae3be 100644 (file)
@@ -46,7 +46,7 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
     private WebSocketServerHandshaker handshaker;
 
     @Override
-    protected void channelRead0(ChannelHandlerContext ctx, Object msg)
+    protected void channelRead0(final ChannelHandlerContext ctx, final Object msg)
             throws Exception {
         if (msg instanceof FullHttpRequest) {
             handleHttpRequest(ctx, (FullHttpRequest) msg);
@@ -64,8 +64,8 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
      * @param req
      *            FullHttpRequest
      */
-    private void handleHttpRequest(ChannelHandlerContext ctx,
-            FullHttpRequest req) throws Exception {
+    private void handleHttpRequest(final ChannelHandlerContext ctx,
+            final FullHttpRequest req) throws Exception {
         // Handle a bad request.
         if (!req.getDecoderResult().isSuccess()) {
             sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1,
@@ -97,8 +97,7 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
                 getWebSocketLocation(req), null, false);
         handshaker = wsFactory.newHandshaker(req);
         if (handshaker == null) {
-            WebSocketServerHandshakerFactory
-                    .sendUnsupportedWebSocketVersionResponse(ctx.channel());
+            WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
         } else {
             handshaker.handshake(ctx.channel(), req);
         }
@@ -115,8 +114,8 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
      * @param res
      *            FullHttpResponse
      */
-    private static void sendHttpResponse(ChannelHandlerContext ctx,
-            HttpRequest req, FullHttpResponse res) {
+    private static void sendHttpResponse(final ChannelHandlerContext ctx,
+            final HttpRequest req, final FullHttpResponse res) {
         // Generate an error page if response getStatus code is not OK (200).
         if (res.getStatus().code() != 200) {
             ByteBuf buf = Unpooled.copiedBuffer(res.getStatus().toString(),
@@ -141,8 +140,8 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
      * @param frame
      *            {@link WebSocketFrame}
      */
-    private void handleWebSocketFrame(ChannelHandlerContext ctx,
-            WebSocketFrame frame) throws IOException {
+    private void handleWebSocketFrame(final ChannelHandlerContext ctx,
+            final WebSocketFrame frame) throws IOException {
         if (frame instanceof CloseWebSocketFrame) {
             handshaker.close(ctx.channel(),
                     (CloseWebSocketFrame) frame.retain());
@@ -164,7 +163,7 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
     }
 
     @Override
-    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
+    public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable cause)
             throws Exception {
         if (cause instanceof java.nio.channels.ClosedChannelException == false) {
             // cause.printStackTrace();
@@ -179,7 +178,7 @@ public class WebSocketServerHandler extends SimpleChannelInboundHandler<Object>
      *            HTTP request from which the location will be returned
      * @return String representation of web socket location.
      */
-    private static String getWebSocketLocation(HttpRequest req) {
+    private static String getWebSocketLocation(final HttpRequest req) {
         return "http://" + req.headers().get(HOST) + req.getUri();
     }
 
diff --git a/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronObject.java b/opendaylight/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/INeutronObject.java
new file mode 100644 (file)
index 0000000..bebac37
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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
+ *
+ *  Authors : Dave Tucker
+ */
+
+package org.opendaylight.controller.networkconfig.neutron;
+
+/**
+ * This class contains behaviour common to Neutron configuration objects
+ */
+public interface INeutronObject {
+    public String getID();
+    public void setID(String id);
+}
index 5b35dc2b34ff73519e4350fa7070ec06cf60801d..a3c38a9265dc50c814a83c776a0c0c7e599f1dba 100644 (file)
@@ -23,7 +23,7 @@ import org.opendaylight.controller.configuration.ConfigurationObject;
 @XmlRootElement(name = "network")
 @XmlAccessorType(XmlAccessType.NONE)
 
-public class NeutronNetwork extends ConfigurationObject implements Serializable {
+public class NeutronNetwork extends ConfigurationObject implements Serializable, INeutronObject {
     // See OpenStack Network API v2.0 Reference for description of
     // annotated attributes
 
@@ -93,6 +93,8 @@ public class NeutronNetwork extends ConfigurationObject implements Serializable
 
     public String getID() { return networkUUID; }
 
+    public void setID(String id) { this.networkUUID = id; }
+
     public String getNetworkUUID() {
         return networkUUID;
     }
index 680a07453b94b3f56072804b2981006574837f5a..b32b01cb3f3015930510d22fd1a39836a25a0cbb 100644 (file)
@@ -25,7 +25,7 @@ import org.opendaylight.controller.configuration.ConfigurationObject;
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
 
-public class NeutronPort extends ConfigurationObject implements Serializable {
+public class NeutronPort extends ConfigurationObject implements Serializable, INeutronObject {
     private static final long serialVersionUID = 1L;
 
     // See OpenStack Network API v2.0 Reference for description of
@@ -76,6 +76,8 @@ public class NeutronPort extends ConfigurationObject implements Serializable {
 
     public String getID() { return portUUID; }
 
+    public void setID(String id) { this.portUUID = id; }
+
     public String getPortUUID() {
         return portUUID;
     }
index fa35f71fd6ae425aac90f7d31524198413ade2f2..2c10cca0c0e4d0819f91d2f7d5543897d216cd65 100644 (file)
@@ -23,7 +23,7 @@ import org.opendaylight.controller.configuration.ConfigurationObject;
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
 
-public class NeutronRouter extends ConfigurationObject implements Serializable {
+public class NeutronRouter extends ConfigurationObject implements Serializable, INeutronObject {
     private static final long serialVersionUID = 1L;
 
     // See OpenStack Network API v2.0 Reference for description of
@@ -57,6 +57,8 @@ public class NeutronRouter extends ConfigurationObject implements Serializable {
 
     public String getID() { return routerUUID; }
 
+    public void setID(String id) { this.routerUUID = id; }
+
     public String getRouterUUID() {
         return routerUUID;
     }
index ae84a72bbac84ddda56c102972c894e21873a603..840029006be5b16a4d394bae0d6daa0b5efd65a5 100644 (file)
@@ -25,7 +25,7 @@ import org.opendaylight.controller.configuration.ConfigurationObject;
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
 
-public class NeutronSubnet extends ConfigurationObject implements Serializable {
+public class NeutronSubnet extends ConfigurationObject implements Serializable, INeutronObject {
     private static final long serialVersionUID = 1L;
 
     // See OpenStack Network API v2.0 Reference for description of
@@ -83,6 +83,8 @@ public class NeutronSubnet extends ConfigurationObject implements Serializable {
 
     public String getID() { return subnetUUID; }
 
+    public void setID(String id) { this.subnetUUID = id; }
+
     public String getSubnetUUID() {
         return subnetUUID;
     }
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/INeutronRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/INeutronRequest.java
new file mode 100644 (file)
index 0000000..8e0ff5c
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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
+ *
+ *  Authors : Dave Tucker
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.INeutronObject;
+
+import java.util.List;
+
+public interface INeutronRequest<T extends INeutronObject> {
+    public T getSingleton();
+    public boolean isSingleton();
+    public List<T> getBulk();
+}
index cebd3c267dd1a1ad2d3b345f2f97d498046631b0..a4c113c2c1803081409e61c4132770482d51f3c0 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
 
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
-public class NeutronNetworkRequest {
+public class NeutronNetworkRequest implements INeutronRequest {
     // See OpenStack Network API v2.0 Reference for description of
     // annotated attributes
 
@@ -29,9 +29,18 @@ public class NeutronNetworkRequest {
     @XmlElement(name="networks")
     List<NeutronNetwork> bulkRequest;
 
+    @XmlElement(name="networks_links")
+    List<NeutronPageLink> links;
+
     NeutronNetworkRequest() {
     }
 
+    NeutronNetworkRequest(List<NeutronNetwork> bulkRequest, List<NeutronPageLink> links) {
+        this.bulkRequest = bulkRequest;
+        this.links = links;
+        this.singletonNetwork = null;
+    }
+
     NeutronNetworkRequest(List<NeutronNetwork> bulk) {
         bulkRequest = bulk;
         singletonNetwork = null;
index 52c3337e40047fb844352fd9dcc0b6c596fcb8d0..9de5aef5f421eb2436ac73a6dff63e24efcf4c64 100644 (file)
@@ -9,8 +9,6 @@
 package org.opendaylight.controller.networkconfig.neutron.northbound;
 
 import java.util.ArrayList;
-import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
@@ -33,6 +31,7 @@ import javax.ws.rs.core.Response;
 import org.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
 import org.codehaus.enunciate.jaxrs.TypeHint;
+
 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkAware;
 import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
 import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
@@ -95,13 +94,13 @@ public class NeutronNetworksNorthbound {
             @QueryParam("provider_network_type") String queryProviderNetworkType,
             @QueryParam("provider_physical_network") String queryProviderPhysicalNetwork,
             @QueryParam("provider_segmentation_id") String queryProviderSegmentationID,
-            // pagination
+            // linkTitle
             @QueryParam("limit") Integer limit,
             @QueryParam("marker") String marker,
             @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
             // sorting not supported
             ) {
-        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD(this);
         if (networkInterface == null) {
             throw new ServiceUnavailableException("Network CRUD Interface "
                     + RestMessages.SERVICEUNAVAILABLE.toString());
@@ -139,89 +138,11 @@ public class NeutronNetworksNorthbound {
             }
         }
 
-        Comparator<NeutronNetwork> neutronNetworkComparator = new Comparator<NeutronNetwork>() {
-            @Override
-            public int compare(NeutronNetwork o1, NeutronNetwork o2) {
-                return o1.getID().compareTo(o2.getID());
-            }
-        };
-
-        Collections.sort(ans, neutronNetworkComparator);
-
         if (limit != null && ans.size() > 1) {
-            List<NeutronPageLink> links = new ArrayList<>();
-            Integer startPos = null;
-            String startMarker;
-            String endMarker;
-            Boolean firstPage = false;
-            Boolean lastPage = false;
-
-            if (marker == null) {
-                startPos = 0;
-            }
-
-            else {
-
-                NeutronNetwork markerNetwork = new NeutronNetwork();
-                markerNetwork.setNetworkUUID(marker);
-
-                startPos = Collections.binarySearch(ans, markerNetwork, neutronNetworkComparator);
-
-                if (!pageReverse){
-                    startPos = startPos + 1;
-                }
-                else {
-                    startPos = startPos - limit;
-                }
-
-            }
-
-            if (startPos == null) {
-                throw new ResourceNotFoundException("UUID for marker:" + marker + " could not be found");
-            }
-
-            if (startPos == 0){
-                firstPage = true;
-            }
-
-            if (startPos + limit >= ans.size()) {
-                ans = ans.subList(startPos, ans.size());
-                startMarker = ans.get(0).getID();
-                endMarker = ans.get(ans.size() - 1).getID();
-                lastPage = true;
-            }
-            else if (startPos < 0) {
-                if (startPos + limit > 0) {
-                    ans = ans.subList(0, startPos + limit);
-                    startMarker = ans.get(0).getID();
-                    endMarker = ans.get(ans.size() - 1).getID();
-                    firstPage = true;
-                }
-                else {
-                    throw new BadRequestException("Requested page is out of bounds. Please check the supplied limit and marker");
-                }
-            }
-            else {
-                ans = ans.subList(startPos, startPos + limit);
-                startMarker = ans.get(0).getID();
-                endMarker = ans.get(limit-1).getID();
-            }
-
-            if (!lastPage) {
-                NeutronPageLink next = new NeutronPageLink();
-                next.setRef("next");
-                next.setHref(uriInfo.getAbsolutePath().toString() + "?limit=" + limit.toString() + "&marker=" + endMarker);
-                links.add(next);
-            }
-
-            if (!firstPage) {
-                NeutronPageLink previous = new NeutronPageLink();
-                previous.setRef("previous");
-                previous.setHref(uriInfo.getAbsolutePath().toString() + "?limit=" + limit.toString() + "&marker=" + startMarker + "&page_reverse=True");
-                links.add(previous);
-            }
-
-            return Response.status(200).entity(new PaginatedNeutronNetworkRequest(ans, links)).build();
+            // Return a paginated request
+            NeutronNetworkRequest request = (NeutronNetworkRequest) PaginatedRequestFactory.createRequest(limit,
+                    marker, pageReverse, uriInfo, ans, NeutronNetwork.class);
+            return Response.status(200).entity(request).build();
         }
 
     return Response.status(200).entity(new NeutronNetworkRequest(ans)).build();
index 9b3399d9a8bfe72266843b0d4d8c34d6b163ef52..12b58aa2abc54e30799fd0458a4e126b9185124a 100644 (file)
@@ -19,7 +19,7 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
 
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
-public class NeutronPortRequest {
+public class NeutronPortRequest implements INeutronRequest {
     // See OpenStack Network API v2.0 Reference for description of
     // annotated attributes
 
@@ -29,9 +29,18 @@ public class NeutronPortRequest {
     @XmlElement(name="ports")
     List<NeutronPort> bulkRequest;
 
+    @XmlElement(name="ports_links")
+    List<NeutronPageLink> links;
+
     NeutronPortRequest() {
     }
 
+    public NeutronPortRequest(List<NeutronPort> bulkRequest, List<NeutronPageLink> links) {
+        this.bulkRequest = bulkRequest;
+        this.links = links;
+        this.singletonPort = null;
+    }
+
     NeutronPortRequest(List<NeutronPort> bulk) {
         bulkRequest = bulk;
         singletonPort = null;
index 1a2512fde3c3fd6c689a872f9ee148bba4a67521..5451fbf3e129e4be88addabcc7816e308c2cb2b7 100644 (file)
@@ -15,6 +15,7 @@ import java.util.List;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -22,8 +23,10 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+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.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
@@ -69,6 +72,9 @@ public class NeutronPortsNorthbound {
         return o.extractFields(fields);
     }
 
+    @Context
+    UriInfo uriInfo;
+
     /**
      * Returns a list of all Ports */
 
@@ -92,10 +98,10 @@ public class NeutronPortsNorthbound {
             @QueryParam("device_id") String queryDeviceID,
             @QueryParam("device_owner") String queryDeviceOwner,
             @QueryParam("tenant_id") String queryTenantID,
-            // pagination
-            @QueryParam("limit") String limit,
+            // linkTitle
+            @QueryParam("limit") Integer limit,
             @QueryParam("marker") String marker,
-            @QueryParam("page_reverse") String pageReverse
+            @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
             // sorting not supported
             ) {
         INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
@@ -124,7 +130,14 @@ public class NeutronPortsNorthbound {
                 }
             }
         }
-        //TODO: apply pagination to results
+
+        if (limit != null && ans.size() > 1) {
+            // Return a paginated request
+            NeutronPortRequest request = (NeutronPortRequest) PaginatedRequestFactory.createRequest(limit,
+                    marker, pageReverse, uriInfo, ans, NeutronPort.class);
+            return Response.status(200).entity(request).build();
+        }
+
         return Response.status(200).entity(
                 new NeutronPortRequest(ans)).build();
     }
index aed9db58bd34c3255c54830c8b76957da6d4de5c..57a724c1cc60936b3a15ed80ba0c1b9bc6d53288 100644 (file)
@@ -20,7 +20,7 @@ import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
 @XmlRootElement
 @XmlAccessorType(XmlAccessType.NONE)
 
-public class NeutronSubnetRequest {
+public class NeutronSubnetRequest implements INeutronRequest {
     // See OpenStack Network API v2.0 Reference for description of
     // annotated attributes
 
@@ -30,16 +30,28 @@ public class NeutronSubnetRequest {
     @XmlElement(name="subnets")
     List<NeutronSubnet> bulkRequest;
 
+    @XmlElement(name="subnets_links")
+    List<NeutronPageLink> links;
+
     NeutronSubnetRequest() {
     }
 
+    public NeutronSubnetRequest(List<NeutronSubnet> bulkRequest, List<NeutronPageLink> links) {
+        this.bulkRequest = bulkRequest;
+        this.links = links;
+        this.singletonSubnet = null;
+    }
+
     NeutronSubnetRequest(List<NeutronSubnet> bulk) {
         bulkRequest = bulk;
         singletonSubnet = null;
+        links = null;
     }
 
     NeutronSubnetRequest(NeutronSubnet subnet) {
         singletonSubnet = subnet;
+        bulkRequest = null;
+        links = null;
     }
 
     public NeutronSubnet getSingleton() {
index f397eb3a97b0630002b3fc1b70901a1a25cf0609..8f20269603b1ed1802fc04812974125016c1811b 100644 (file)
@@ -13,8 +13,10 @@ import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
+
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
+import javax.ws.rs.DefaultValue;
 import javax.ws.rs.GET;
 import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
@@ -22,8 +24,10 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.QueryParam;
+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.codehaus.enunciate.jaxrs.ResponseCode;
 import org.codehaus.enunciate.jaxrs.StatusCodes;
@@ -65,6 +69,8 @@ public class NeutronSubnetsNorthbound {
         return o.extractFields(fields);
     }
 
+    @Context
+    UriInfo uriInfo;
 
     /**
      * Returns a list of all Subnets */
@@ -89,13 +95,13 @@ public class NeutronSubnetsNorthbound {
             @QueryParam("tenant_id") String queryTenantID,
             @QueryParam("ipv6_address_mode") String queryIpV6AddressMode,
             @QueryParam("ipv6_ra_mode") String queryIpV6RaMode,
-            // pagination
-            @QueryParam("limit") String limit,
+            // linkTitle
+            @QueryParam("limit") Integer limit,
             @QueryParam("marker") String marker,
-            @QueryParam("page_reverse") String pageReverse
+            @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
             // sorting not supported
             ) {
-        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
         if (subnetInterface == null) {
             throw new ServiceUnavailableException("Subnet CRUD Interface "
                     + RestMessages.SERVICEUNAVAILABLE.toString());
@@ -122,7 +128,14 @@ public class NeutronSubnetsNorthbound {
                 }
             }
         }
-        //TODO: apply pagination to results
+
+        if (limit != null && ans.size() > 1) {
+            // Return a paginated request
+            NeutronSubnetRequest request = (NeutronSubnetRequest) PaginatedRequestFactory.createRequest(limit,
+                    marker, pageReverse, uriInfo, ans, NeutronSubnet.class);
+            return Response.status(200).entity(request).build();
+        }
+
         return Response.status(200).entity(
                 new NeutronSubnetRequest(ans)).build();
     }
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedNeutronNetworkRequest.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedNeutronNetworkRequest.java
deleted file mode 100644 (file)
index c050661..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2014 Hewlett-Packard Development Company L.P
- *
- * 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
- *
- * Authors : Dave Tucker
- */
-
-package org.opendaylight.controller.networkconfig.neutron.northbound;
-
-import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
-
-import javax.xml.bind.annotation.XmlAccessType;
-import javax.xml.bind.annotation.XmlAccessorType;
-import javax.xml.bind.annotation.XmlElement;
-import javax.xml.bind.annotation.XmlRootElement;
-import java.util.List;
-
-@XmlRootElement
-@XmlAccessorType(XmlAccessType.NONE)
-
-public class PaginatedNeutronNetworkRequest {
-
-    @XmlElement (name="networks")
-    List<NeutronNetwork> networks;
-
-    @XmlElement (name="network_links")
-    List<NeutronPageLink> networkLinks;
-
-    public PaginatedNeutronNetworkRequest() {
-    }
-
-    public PaginatedNeutronNetworkRequest(List<NeutronNetwork> networks, List<NeutronPageLink> networkLinks) {
-        this.networks = networks;
-        this.networkLinks = networkLinks;
-    }
-
-    public List<NeutronNetwork> getNetworks() {
-        return networks;
-    }
-
-    public void setNetworks(List<NeutronNetwork> networks) {
-        this.networks = networks;
-    }
-
-    public List<NeutronPageLink> getNetworkLinks() {
-        return networkLinks;
-    }
-
-    public void setNetworkLinks(List<NeutronPageLink> networkLinks) {
-        this.networkLinks = networkLinks;
-    }
-}
diff --git a/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedRequestFactory.java b/opendaylight/northbound/networkconfiguration/neutron/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedRequestFactory.java
new file mode 100644 (file)
index 0000000..8f05e76
--- /dev/null
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2014 Red Hat, Inc.
+ *
+ * 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
+ *
+ *  Authors : Dave Tucker
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.INeutronObject;
+import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+
+import javax.ws.rs.core.UriInfo;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+public class PaginatedRequestFactory {
+
+    public static class PaginationResults<T extends INeutronObject> {
+        List<T> collection;
+        List<NeutronPageLink> links;
+
+        public PaginationResults(List<T> collection, List<NeutronPageLink> links) {
+            this.collection = collection;
+            this.links = links;
+        }
+    }
+
+    public static <T extends INeutronObject> INeutronRequest createRequest(Integer limit, String marker,
+                                                                           Boolean pageReverse,
+                                                                           UriInfo uriInfo,
+                                                                           List<T> collection,
+                                                                           Class<T> clazz) {
+        PaginationResults results = _paginate(limit, marker, pageReverse, uriInfo, collection);
+
+        if (clazz.equals(NeutronNetwork.class)){
+            return new NeutronNetworkRequest(results.collection, results.links);
+        }
+        if (clazz.equals(NeutronSubnet.class)){
+            return new NeutronSubnetRequest(results.collection, results.links);
+        }
+        if (clazz.equals(NeutronPort.class)){
+            return new NeutronPortRequest(results.collection, results.links);
+        }
+        return null;
+    }
+
+    private static <T extends INeutronObject> PaginationResults _paginate(Integer limit, String marker, Boolean pageReverse, UriInfo uriInfo, List<T> collection) {
+        List<NeutronPageLink> links = new ArrayList<>();
+        Integer startPos = null;
+        String startMarker;
+        String endMarker;
+        Boolean firstPage = false;
+        Boolean lastPage = false;
+
+        Comparator<INeutronObject> neutronObjectComparator = new Comparator<INeutronObject>() {
+            @Override
+            public int compare(INeutronObject o1, INeutronObject o2) {
+                return o1.getID().compareTo(o2.getID());
+            }
+        };
+
+        Collections.sort(collection, neutronObjectComparator);
+
+        if (marker == null) {
+            startPos = 0;
+        }
+
+        else {
+
+            class MarkerObject implements INeutronObject {
+                private String id;
+
+                public String getID() {
+                    return id;
+                }
+
+                public void setID(String id) {
+                    this.id = id;
+                }
+            }
+
+            INeutronObject markerObject = new MarkerObject();
+
+            markerObject.setID(marker);
+
+            startPos = Collections.binarySearch(collection, markerObject, neutronObjectComparator);
+
+            if (!pageReverse){
+                startPos = startPos + 1;
+            }
+            else {
+                startPos = startPos - limit;
+            }
+
+        }
+
+        if (startPos == null) {
+            throw new ResourceNotFoundException("UUID for marker:" + marker + " could not be found");
+        }
+
+        if (startPos == 0){
+            firstPage = true;
+        }
+
+        if (startPos + limit >= collection.size()) {
+            collection = collection.subList(startPos, collection.size());
+            startMarker = collection.get(0).getID();
+            endMarker = collection.get(collection.size() - 1).getID();
+            lastPage = true;
+        }
+        else if (startPos < 0) {
+            if (startPos + limit > 0) {
+                collection = collection.subList(0, startPos + limit);
+                startMarker = collection.get(0).getID();
+                endMarker = collection.get(collection.size() - 1).getID();
+                firstPage = true;
+            }
+            else {
+                throw new BadRequestException("Requested page is out of bounds. Please check the supplied limit and marker");
+            }
+        }
+        else {
+            collection = collection.subList(startPos, startPos + limit);
+            startMarker = collection.get(0).getID();
+            endMarker = collection.get(limit-1).getID();
+        }
+
+        if (!lastPage) {
+            NeutronPageLink next = new NeutronPageLink();
+            next.setRef("next");
+            next.setHref(uriInfo.getAbsolutePath().toString() + "?limit=" + limit.toString() + "&marker=" + endMarker);
+            links.add(next);
+        }
+
+        if (!firstPage) {
+            NeutronPageLink previous = new NeutronPageLink();
+            previous.setRef("previous");
+            previous.setHref(uriInfo.getAbsolutePath().toString() + "?limit=" + limit.toString() + "&marker=" + startMarker + "&page_reverse=True");
+            links.add(previous);
+        }
+
+        return new PaginationResults(collection, links);
+    }
+}