Merge "Do not create the operational/configuration cache if it already exists"
authorEd Warnicke <eaw@cisco.com>
Tue, 12 Nov 2013 14:08:59 +0000 (14:08 +0000)
committerGerrit Code Review <gerrit@opendaylight.org>
Tue, 12 Nov 2013 14:08:59 +0000 (14:08 +0000)
14 files changed:
opendaylight/arphandler/pom.xml
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/Activator.java
opendaylight/arphandler/src/main/java/org/opendaylight/controller/arphandler/internal/ArpHandler.java
opendaylight/distribution/opendaylight/pom.xml
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfClientDispatcher.java
opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java [new file with mode: 0644]
opendaylight/netconf/netconf-impl/src/main/java/org/opendaylight/controller/netconf/impl/NetconfServerDispatcher.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractChannelInitializer.java
opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractSslChannelInitializer.java [new file with mode: 0644]
opendaylight/northbound/java-client/enunciate.xml [new file with mode: 0644]
opendaylight/northbound/java-client/pom.xml [new file with mode: 0644]
opendaylight/web/root/src/main/java/org/opendaylight/controller/web/DaylightWebAdmin.java
opendaylight/web/root/src/main/resources/js/open.js
pom.xml

index 4c22b4a74b08a8bf23793dd8ba4f7a6496fbbddf..8f1f4d5d2e7a85da93715a1ebba4cb66e3137a78 100644 (file)
@@ -32,6 +32,7 @@
               org.opendaylight.controller.sal.core,
               org.opendaylight.controller.sal.utils,
               org.opendaylight.controller.sal.packet,
+              org.opendaylight.controller.sal.routing,
               org.opendaylight.controller.switchmanager,
               org.opendaylight.controller.topologymanager,
               org.opendaylight.controller.clustering.services,
index f4edf6c74e989d6ce45fe6be27ca9c0d3fb44a0b..b253179c87185d50834240f654a524409a0fa392 100644 (file)
@@ -24,6 +24,7 @@ import org.opendaylight.controller.hosttracker.hostAware.IHostFinder;
 import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
 import org.opendaylight.controller.sal.packet.IDataPacketService;
 import org.opendaylight.controller.sal.packet.IListenDataPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
 import org.opendaylight.controller.switchmanager.ISwitchManager;
 import org.opendaylight.controller.topologymanager.ITopologyManager;
 import org.slf4j.Logger;
@@ -99,6 +100,10 @@ public class Activator extends ComponentActivatorAbstractBase {
                    "setClusterContainerService", "unsetClusterContainerService")
                    .setRequired(true));
 
+            c.add(createContainerServiceDependency(containerName).setService(
+                   IRouting.class).setCallbacks("setRouting","unsetRouting")
+                   .setRequired(false));
+
             // the Host Listener is optional
             c.add(createContainerServiceDependency(containerName).setService(
                     IfHostListener.class).setCallbacks("setHostListener",
index 7925c05f59466a5c3de3e4fa517f12e4d8368db8..abe104a40638f1a58e47fdcc5f91eda6b1f87359 100644 (file)
@@ -53,6 +53,7 @@ import org.opendaylight.controller.sal.packet.IPv4;
 import org.opendaylight.controller.sal.packet.Packet;
 import org.opendaylight.controller.sal.packet.PacketResult;
 import org.opendaylight.controller.sal.packet.RawPacket;
+import org.opendaylight.controller.sal.routing.IRouting;
 import org.opendaylight.controller.sal.utils.EtherTypes;
 import org.opendaylight.controller.sal.utils.HexEncode;
 import org.opendaylight.controller.sal.utils.NetUtils;
@@ -69,6 +70,7 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
     private ISwitchManager switchManager;
     private ITopologyManager topologyManager;
     private IDataPacketService dataPacketService;
+    private IRouting routing;
     private IClusterContainerServices clusterContainerService;
     private IConnectionManager connectionManager;
     private Set<IfHostListener> hostListeners = new CopyOnWriteArraySet<IfHostListener>();
@@ -108,6 +110,16 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
         }
     }
 
+    void setRouting(IRouting r) {
+        this.routing = r;
+    }
+
+    void unsetRouting(IRouting r) {
+        if (this.routing == r) {
+            this.routing = null;
+        }
+    }
+
     void setHostListener(IfHostListener s) {
         if (this.hostListeners != null) {
             this.hostListeners.add(s);
@@ -460,21 +472,36 @@ public class ArpHandler implements IHostFinder, IListenDataPacket, ICacheUpdateA
 
         if (host == null) {
             // if we don't, know about the host, try to find it
-            log.trace("Punted IP pkt from {}, sending bcast ARP event...",
+            log.trace("Punted IP pkt to {}, sending bcast ARP event...",
                       dIP);
             /*
              * unknown destination host, initiate bcast ARP request
              */
             arpRequestReplyEvent.put(new ARPRequest(dIP, subnet), false);
-        }else{
 
-            // we know about the host, send the packet the right place
+        } else if (routing == null ||
+                   routing.getRoute(p.getNode(), host.getnodeconnectorNode()) != null) {
+            /* if IRouting is available, make sure that this packet can get it's
+             * destination normally before teleporting it there. If it's not
+             * available, then assume it's reachable.
+             *
+             * TODO: come up with a way to do this in the absence of IRouting
+             */
+
+            log.trace("forwarding punted IP pkt to {} received at {}", dIP, p);
+
+            /* if we know where the host is and there's a path from where this
+             * packet was punted to where the host is, then deliver it to the
+             * host for now */
             NodeConnector nc = host.getnodeConnector();
 
             // re-encode the Ethernet packet (the parent of the IPv4 packet)
             RawPacket rp = this.dataPacketService.encodeDataPacket(pkt.getParent());
             rp.setOutgoingNodeConnector(nc);
             this.dataPacketService.transmitDataPacket(rp);
+        } else {
+            log.trace("ignoring punted IP pkt to {} because there is no route from {}",
+                      dIP, p);
         }
     }
 
index cc42fefd975662a61da91e5e17f4d45f206c6109..db4efef0300bf0271b513fd2d5c5d1201e0ab66e 100644 (file)
           <artifactId>yang-jmx-generator-plugin</artifactId>
           <version>${config.version}</version>
         </dependency>
-        <dependency>
-          <groupId>org.opendaylight.controller</groupId>
-          <artifactId>yang-jmx-generator-it</artifactId>
-          <version>${config.version}</version>
-        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>yang-store-api</artifactId>
           <artifactId>yang-store-impl</artifactId>
           <version>${config.version}</version>
         </dependency>
-        <dependency>
-          <groupId>org.opendaylight.controller</groupId>
-          <artifactId>yang-test</artifactId>
-          <version>${config.version}</version>
-        </dependency>
         <dependency>
           <groupId>org.opendaylight.controller</groupId>
           <artifactId>logback-config</artifactId>
index 4df8235441b582f5650edfa6dbd4aca346daf2c2..d18f0208d4288d87abef3dc7b8de7c1451c1826d 100644 (file)
@@ -17,7 +17,7 @@ import io.netty.util.concurrent.Promise;
 import org.opendaylight.controller.netconf.api.NetconfMessage;
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.api.NetconfTerminationReason;
-import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.AbstractSslChannelInitializer;
 import org.opendaylight.protocol.framework.AbstractDispatcher;
 import org.opendaylight.protocol.framework.ReconnectStrategy;
 import org.opendaylight.protocol.framework.SessionListener;
@@ -48,18 +48,18 @@ public class NetconfClientDispatcher extends AbstractDispatcher<NetconfClientSes
             }
 
             private void initialize(SocketChannel ch, Promise<NetconfClientSession> promise) {
-                new ClientChannelInitializer(maybeContext, negotatorFactory, sessionListener).initialize(ch, promise);
+                new ClientSslChannelInitializer(maybeContext, negotatorFactory, sessionListener).initialize(ch, promise);
             }
         });
     }
 
-    private static class ClientChannelInitializer extends AbstractChannelInitializer {
+    private static class ClientSslChannelInitializer extends AbstractSslChannelInitializer {
 
         private final NetconfClientSessionNegotiatorFactory negotiatorFactory;
         private final NetconfClientSessionListener sessionListener;
 
-        private ClientChannelInitializer(Optional<SSLContext> maybeContext,
-                NetconfClientSessionNegotiatorFactory negotiatorFactory, NetconfClientSessionListener sessionListener) {
+        private ClientSslChannelInitializer(Optional<SSLContext> maybeContext,
+                                            NetconfClientSessionNegotiatorFactory negotiatorFactory, NetconfClientSessionListener sessionListener) {
             super(maybeContext);
             this.negotiatorFactory = negotiatorFactory;
             this.sessionListener = sessionListener;
diff --git a/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java b/opendaylight/netconf/netconf-client/src/main/java/org/opendaylight/controller/netconf/client/NetconfSshClientDispatcher.java
new file mode 100644 (file)
index 0000000..a426181
--- /dev/null
@@ -0,0 +1,15 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.client;
+
+public class NetconfSshClientDispatcher extends NetconfClientDispatcher {
+    public NetconfSshClientDispatcher() {
+        super(null);
+    }
+}
index 324da56ca58474ecc2b338e0b4e8a3cc29755d1f..c73840132f67856b296de749cbe60a961a6a2023 100644 (file)
@@ -14,7 +14,7 @@ import io.netty.channel.socket.SocketChannel;
 import io.netty.util.concurrent.Promise;
 import org.opendaylight.controller.netconf.api.NetconfSession;
 import org.opendaylight.controller.netconf.impl.util.DeserializerExceptionHandler;
-import org.opendaylight.controller.netconf.util.AbstractChannelInitializer;
+import org.opendaylight.controller.netconf.util.AbstractSslChannelInitializer;
 import org.opendaylight.protocol.framework.AbstractDispatcher;
 
 import javax.net.ssl.SSLContext;
@@ -23,12 +23,12 @@ import java.net.InetSocketAddress;
 
 public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession, NetconfServerSessionListener> {
 
-    private final ServerChannelInitializer initializer;
+    private final ServerSslChannelInitializer initializer;
 
     public NetconfServerDispatcher(final Optional<SSLContext> maybeContext,
             NetconfServerSessionNegotiatorFactory serverNegotiatorFactory,
             NetconfServerSessionListenerFactory listenerFactory) {
-        this.initializer = new ServerChannelInitializer(maybeContext, serverNegotiatorFactory, listenerFactory);
+        this.initializer = new ServerSslChannelInitializer(maybeContext, serverNegotiatorFactory, listenerFactory);
     }
 
     // FIXME change headers for all new source code files
@@ -44,14 +44,14 @@ public class NetconfServerDispatcher extends AbstractDispatcher<NetconfSession,
         });
     }
 
-    private static class ServerChannelInitializer extends AbstractChannelInitializer {
+    private static class ServerSslChannelInitializer extends AbstractSslChannelInitializer {
 
         private final NetconfServerSessionNegotiatorFactory negotiatorFactory;
         private final NetconfServerSessionListenerFactory listenerFactory;
 
-        private ServerChannelInitializer(Optional<SSLContext> maybeContext,
-                NetconfServerSessionNegotiatorFactory negotiatorFactory,
-                NetconfServerSessionListenerFactory listenerFactory) {
+        private ServerSslChannelInitializer(Optional<SSLContext> maybeContext,
+                                            NetconfServerSessionNegotiatorFactory negotiatorFactory,
+                                            NetconfServerSessionListenerFactory listenerFactory) {
             super(maybeContext);
             this.negotiatorFactory = negotiatorFactory;
             this.listenerFactory = listenerFactory;
index 5d082c92cda6c59a86fdd557206cb6817a4d4f6e..caee5421525515a2b9cef2b136cf00d2f5944fd5 100644 (file)
@@ -8,73 +8,14 @@
 
 package org.opendaylight.controller.netconf.util;
 
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLEngine;
-
-import org.opendaylight.controller.netconf.api.NetconfMessage;
-import org.opendaylight.controller.netconf.api.NetconfSession;
-import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
-import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
-import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
-import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
-import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
-import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
-import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
-
-import com.google.common.base.Optional;
-
-import io.netty.channel.ChannelHandler;
 import io.netty.channel.socket.SocketChannel;
-import io.netty.handler.ssl.SslHandler;
 import io.netty.util.concurrent.Promise;
+import org.opendaylight.controller.netconf.api.NetconfSession;
 
 public abstract class AbstractChannelInitializer {
 
-    private final Optional<SSLContext> maybeContext;
-    private final NetconfHandlerFactory handlerFactory;
-
-    public AbstractChannelInitializer(Optional<SSLContext> maybeContext) {
-        this.maybeContext = maybeContext;
-        this.handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
-    }
-
-    public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
-        if (maybeContext.isPresent()) {
-            initSsl(ch);
-        }
-
-        ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
-        ch.pipeline().addLast(handlerFactory.getDecoders());
-        initializeAfterDecoder(ch, promise);
-        ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
-        ch.pipeline().addLast(handlerFactory.getEncoders());
-    }
+    public abstract void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise);
 
     protected abstract void initializeAfterDecoder(SocketChannel ch, Promise<? extends NetconfSession> promise);
 
-    private void initSsl(SocketChannel ch) {
-        SSLEngine sslEngine = maybeContext.get().createSSLEngine();
-        initSslEngine(sslEngine);
-        final SslHandler handler = new SslHandler(sslEngine);
-        ch.pipeline().addLast("ssl", handler);
-    }
-
-    protected abstract void initSslEngine(SSLEngine sslEngine);
-
-    private static final class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
-
-        public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
-            super(msgFactory);
-        }
-
-        @Override
-        public ChannelHandler[] getEncoders() {
-            return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
-        }
-
-        @Override
-        public ChannelHandler[] getDecoders() {
-            return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
-        }
-    }
 }
diff --git a/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractSslChannelInitializer.java b/opendaylight/netconf/netconf-util/src/main/java/org/opendaylight/controller/netconf/util/AbstractSslChannelInitializer.java
new file mode 100644 (file)
index 0000000..d490eb2
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.netconf.util;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+
+import org.opendaylight.controller.netconf.api.NetconfMessage;
+import org.opendaylight.controller.netconf.api.NetconfSession;
+import org.opendaylight.controller.netconf.util.handler.FramingMechanismHandlerFactory;
+import org.opendaylight.controller.netconf.util.handler.NetconfMessageAggregator;
+import org.opendaylight.controller.netconf.util.messages.FramingMechanism;
+import org.opendaylight.controller.netconf.util.messages.NetconfMessageFactory;
+import org.opendaylight.protocol.framework.ProtocolHandlerFactory;
+import org.opendaylight.protocol.framework.ProtocolMessageDecoder;
+import org.opendaylight.protocol.framework.ProtocolMessageEncoder;
+
+import com.google.common.base.Optional;
+
+import io.netty.channel.ChannelHandler;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.handler.ssl.SslHandler;
+import io.netty.util.concurrent.Promise;
+
+public abstract class AbstractSslChannelInitializer extends AbstractChannelInitializer {
+
+    private final Optional<SSLContext> maybeContext;
+    private final NetconfHandlerFactory handlerFactory;
+
+    public AbstractSslChannelInitializer(Optional<SSLContext> maybeContext) {
+        this.maybeContext = maybeContext;
+        this.handlerFactory = new NetconfHandlerFactory(new NetconfMessageFactory());
+    }
+
+    @Override
+    public void initialize(SocketChannel ch, Promise<? extends NetconfSession> promise) {
+        if (maybeContext.isPresent()) {
+            initSsl(ch);
+        }
+
+        ch.pipeline().addLast("aggregator", new NetconfMessageAggregator(FramingMechanism.EOM));
+        ch.pipeline().addLast(handlerFactory.getDecoders());
+        initializeAfterDecoder(ch, promise);
+        ch.pipeline().addLast("frameEncoder", FramingMechanismHandlerFactory.createHandler(FramingMechanism.EOM));
+        ch.pipeline().addLast(handlerFactory.getEncoders());
+    }
+
+    private void initSsl(SocketChannel ch) {
+        SSLEngine sslEngine = maybeContext.get().createSSLEngine();
+        initSslEngine(sslEngine);
+        final SslHandler handler = new SslHandler(sslEngine);
+        ch.pipeline().addLast("ssl", handler);
+    }
+
+    protected abstract void initSslEngine(SSLEngine sslEngine);
+
+    private static final class NetconfHandlerFactory extends ProtocolHandlerFactory<NetconfMessage> {
+
+        public NetconfHandlerFactory(final NetconfMessageFactory msgFactory) {
+            super(msgFactory);
+        }
+
+        @Override
+        public ChannelHandler[] getEncoders() {
+            return new ChannelHandler[] { new ProtocolMessageEncoder(this.msgFactory) };
+        }
+
+        @Override
+        public ChannelHandler[] getDecoders() {
+            return new ChannelHandler[] { new ProtocolMessageDecoder(this.msgFactory) };
+        }
+    }
+}
diff --git a/opendaylight/northbound/java-client/enunciate.xml b/opendaylight/northbound/java-client/enunciate.xml
new file mode 100644 (file)
index 0000000..ce9186e
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<enunciate label="full" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:noNamespaceSchemaLocation="http://enunciate.codehaus.org/schemas/enunciate-1.26.xsd">
+
+  <services> </services>
+
+  <modules>
+    <!-- Disable doc generation -->
+    <docs disabled="true"/>
+
+    <!-- Disable all the client generation tools -->
+    <basic-app disabled="true" />
+    <c disabled="true" />
+    <csharp disabled="true" />
+    <jaxws-client disabled="true" />
+    <jaxws-ri disabled="true" />
+    <jaxws-support disabled="true" />
+    <obj-c disabled="true" />
+    <ruby disabled="true"/>
+    <php disabled="true"/>
+
+    <!-- enable only the java clients -->
+    <xml disabled="false" />
+    <java-client disabled="false"/>
+  </modules>
+
+  <api-classes>
+    <include pattern="org.opendaylight.controller.**"/>
+  </api-classes>
+
+  <api-import pattern="org.opendaylight.controller.**"/>
+</enunciate>
diff --git a/opendaylight/northbound/java-client/pom.xml b/opendaylight/northbound/java-client/pom.xml
new file mode 100644 (file)
index 0000000..b6fd296
--- /dev/null
@@ -0,0 +1,301 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <parent>
+    <groupId>org.opendaylight.controller</groupId>
+    <artifactId>commons.opendaylight</artifactId>
+    <version>1.4.1-SNAPSHOT</version>
+    <relativePath>../../commons/opendaylight</relativePath>
+  </parent>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+    <tag>HEAD</tag>
+  </scm>
+
+  <artifactId>northbound.client</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>pom</packaging>
+
+  <properties>
+    <docs.output.dir>${project.build.directory}/rest-api-docs</docs.output.dir>
+    <java-client>${project.build.directory}/enunciate/build/java-client/full-client.jar</java-client>
+    <java-client-sources>${project.build.directory}/enunciate/build/java-client/full-client-sources.jar</java-client-sources>
+    <json-client>${project.build.directory}/enunciate/build/java-client/full-json-client.jar</json-client>
+    <json-client-sources>${project.build.directory}/enunciate/build/java-client/full-json-client-sources.jar</json-client-sources>
+  </properties>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.codehaus.enunciate</groupId>
+        <artifactId>maven-enunciate-plugin</artifactId>
+        <version>${enunciate.version}</version>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-antrun-plugin</artifactId>
+        <version>1.5</version>
+        <executions>
+          <execution>
+            <phase>install</phase>
+            <goals>
+                <goal>run</goal>
+            </goals>
+          </execution>
+        </executions>
+        <configuration>
+          <target>
+            <taskdef resource="net/sf/antcontrib/antcontrib.properties"
+                     classpathref="maven.plugin.classpath" />
+            <patternset id="rest.paths">
+              <include name="**/target/site/wsdocs/**"/>
+              <exclude name="**/java-client/**"/>
+            </patternset>
+
+            <echo message="======== Assembling enunciate docs ========"/>
+            <!-- cleanup existing generated files -->
+            <delete dir="${docs.output.dir}"/>
+            <delete file="${docs.output.dir}.zip"/>
+            <mkdir dir="${docs.output.dir}"/>
+            <!-- copy enunciate docs to stage -->
+            <copy todir="${docs.output.dir}">
+              <fileset dir="${basedir}/../../..">
+                <patternset refid="rest.paths"/>
+              </fileset>
+              <mapper type="regexp"
+                      from="^(.*)/([^/]+)/target/site/wsdocs/(.*)$$"
+                      to="\2/\3"/>
+            </copy>
+            <!-- generate index.html -->
+            <!-- append header -->
+            <echo file="${docs.output.dir}/index.html" append="true">
+&lt;![CDATA[
+&lt;html&gt;
+  &lt;head&gt;
+    &lt;title&gt; OpenDaylight REST API Documentation &lt;/title&gt;
+  &lt;/head&gt;
+  &lt;body&gt;
+  &lt;h2&gt;OpenDaylight REST API Documentation&lt;/h2&gt;
+  &lt;p&gt; OpenDaylight supports the following &lt;a href="http://en.wikipedia.org/wiki/Representational_State_Transfer"&gt;Representational State Transfer (REST)&lt;/a&gt; APIs: &lt;/p&gt;
+  &lt;h4&gt;
+]]&gt;
+            </echo>
+            <dirset id="nbset" dir="${docs.output.dir}">
+              <include name="*"/>
+            </dirset>
+            <pathconvert pathsep="&amp;#36;{line.separator}"
+                         property="nbs"
+                         refid="nbset"/>
+            <echo file="${docs.output.dir}/index.html"
+                  append="true"
+                  message="${nbs}"/>
+            <replaceregexp file="${docs.output.dir}/index.html"
+                           match="^\${docs.output.dir}/(.*)$"
+                           replace="&amp;lt;li&amp;gt;&amp;lt;a href=\1/index.html&amp;gt; \1 &amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;"
+                           byline="true"/>
+
+            <!-- append footer -->
+            <echo file="${docs.output.dir}/index.html" append="true">
+&lt;![CDATA[
+  &lt;/h4&gt;
+  &lt;i&gt;---&lt;/i&gt;
+  &lt;/body&gt;
+&lt;/html&gt;
+]]&gt;
+            </echo>
+            <!-- archive all the docs excluding whatever is not needed -->
+            <echo message="======== Archiving enunciate docs ========"/>
+            <zip destfile="${docs.output.dir}.zip">
+              <zipfileset dir="${docs.output.dir}"/>
+            </zip>
+
+            <echo message="======== Build successful ========"/>
+            <echo message="REST docs archive: ${docs.output.dir}.zip"/>
+          </target>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>ant-contrib</groupId>
+            <artifactId>ant-contrib</artifactId>
+            <version>20020829</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-install-plugin</artifactId>
+        <version>2.5</version>
+        <configuration>
+          <packaging>jar</packaging>
+          <groupId>${project.groupId}</groupId>
+          <version>${project.version}</version>
+        </configuration>
+        <executions>
+          <execution>
+            <!-- skip default install -->
+            <id>default-install</id>
+            <phase>install</phase>
+            <goals>
+              <goal>install</goal>
+            </goals>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+          <execution>
+            <!-- install full java client -->
+            <id>install-full-client</id>
+            <phase>install</phase>
+            <goals>
+              <goal>install-file</goal>
+            </goals>
+            <configuration>
+              <artifactId>${project.artifactId}.full-client</artifactId>
+              <file>${java-client}</file>
+              <sources>${java-client-sources}</sources>
+            </configuration>
+          </execution>
+          <execution>
+            <!-- install full java json client -->
+            <id>install-full-json-client</id>
+            <phase>install</phase>
+            <goals>
+              <goal>install-file</goal>
+            </goals>
+            <configuration>
+              <artifactId>${project.artifactId}.full-json-client</artifactId>
+              <file>${json-client}</file>
+              <sources>${json-client-sources}</sources>
+            </configuration>
+          </execution>
+        </executions>
+      </plugin>
+
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-deploy-plugin</artifactId>
+        <version>2.5</version>
+        <configuration>
+          <packaging>jar</packaging>
+          <generatePom>true</generatePom>
+          <groupId>${project.groupId}</groupId>
+          <version>${project.version}</version>
+          <url>${project.distributionManagement.repository.url}</url>
+        </configuration>
+        <executions>
+          <execution>
+            <!-- skip default deploy -->
+            <id>default-deploy</id>
+            <phase>deploy</phase>
+            <goals>
+              <goal>deploy</goal>
+            </goals>
+            <configuration>
+              <skip>true</skip>
+            </configuration>
+          </execution>
+          <execution>
+            <!-- deploy full java client -->
+            <id>deploy-full-client</id>
+            <phase>deploy</phase>
+            <goals>
+              <goal>deploy-file</goal>
+            </goals>
+            <configuration>
+              <artifactId>${project.artifactId}.full-client</artifactId>
+              <file>${java-client}</file>
+              <sources>${java-client-sources}</sources>
+            </configuration>
+          </execution>
+          <execution>
+            <!-- deploy full java json client -->
+            <id>deploy-full-json-client</id>
+            <phase>deploy</phase>
+            <goals>
+              <goal>deploy-file</goal>
+            </goals>
+            <configuration>
+              <artifactId>${project.artifactId}.full-json-client</artifactId>
+              <file>${json-client}</file>
+              <sources>${json-client-sources}</sources>
+            </configuration>
+          </execution>
+       </executions>
+    </plugin>
+
+    </plugins>
+  </build>
+  <dependencies>
+    <dependency>
+      <groupId>org.codehaus.enunciate</groupId>
+      <artifactId>enunciate-core-annotations</artifactId>
+      <version>${enunciate.version}</version>
+    </dependency>
+
+    <!-- add dependency on all northbound bundles -->
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>connectionmanager.northbound</artifactId>
+      <version>0.1.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>controllermanager.northbound</artifactId>
+      <version>0.0.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>flowprogrammer.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>hosttracker.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>networkconfig.bridgedomain.northbound</artifactId>
+      <version>0.0.2-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>networkconfig.neutron.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>forwarding.staticrouting.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>statistics.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>subnets.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>switchmanager.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>topology.northbound</artifactId>
+      <version>0.4.1-SNAPSHOT</version>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>usermanager.northbound</artifactId>
+      <version>0.0.1-SNAPSHOT</version>
+    </dependency>
+  </dependencies>
+</project>
index 8c6e23f9d3c5b3243e9f842c2739ee67a78319ac..3c28152c25fa0a16e7263d3b69b2fa49f8264306 100644 (file)
@@ -161,16 +161,16 @@ public class DaylightWebAdmin {
      */
     @RequestMapping(value = "/users", method = RequestMethod.POST)
     @ResponseBody
-    public String saveLocalUserConfig(@RequestParam(required = true) String json,
+    public Status saveLocalUserConfig(@RequestParam(required = true) String json,
             @RequestParam(required = true) String action, HttpServletRequest request) {
 
         IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
         if (userManager == null) {
-            return "Internal Error";
+            return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
         }
 
         if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
-            return "Operation not permitted";
+            return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
         }
 
         Gson gson = new Gson();
@@ -180,46 +180,87 @@ public class DaylightWebAdmin {
 
         Status result = (action.equals("add")) ? userManager.addLocalUser(config) : userManager.removeLocalUser(config);
         if (result.isSuccess()) {
-            String userAction = (action.equals("add")) ? "added" : "removed";
             if (action.equals("add")) {
-                String userRoles = "";
-                for (String userRole : config.getRoles()) {
-                    userRoles = userRoles + userRole + ",";
-                }
-                DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), userAction, config.getUser()
-                        + " as " + userRoles.substring(0, userRoles.length() - 1));
+                DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "added", config.getUser()
+                        + " as " + config.getRoles().toString());
             } else {
-                DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), userAction, config.getUser());
+                DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", config.getUser());
             }
-            return "Success";
         }
-        return result.getDescription();
+        return result;
     }
 
+    @RequestMapping(value = "/user/modify", method = RequestMethod.POST)
+    @ResponseBody
+    public Status modifyUser(@RequestParam(required = true) String json,
+            @RequestParam(required = true) String action, HttpServletRequest request) {
+
+        IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
+        if (userManager == null) {
+            return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
+        }
+
+        if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
+            return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
+        }
+
+        UserConfig newConfig = gson.fromJson(json, UserConfig.class);
+        List<UserConfig> currentUserConfig = userManager.getLocalUserList();
+        String password = null;
+        String user = newConfig.getUser();
+        for (UserConfig userConfig : currentUserConfig) {
+            if(userConfig.getUser().equals(user)){
+                password = userConfig.getPassword();
+                break;
+            }
+        }
+        if (password == null) {
+            String msg = String.format("User %s not found in configuration database", user);
+            return new Status(StatusCode.NOTFOUND, msg);
+        }
+
+        //While modifying a user role, the password is not provided from GUI for any user.
+        //The password is stored in hash mode, hence it cannot be retrieved and added to UserConfig object
+        //The hashed password is injected below to the json string containing username and new roles before
+        //converting to UserConfig object.
+        json = json.replace("\"roles\"", "\"password\":\""+ password + "\",\"roles\"");
+        Gson gson = new Gson();
+        newConfig = gson.fromJson(json, UserConfig.class);
+
+        Status result = userManager.modifyLocalUser(newConfig);
+        if (result.isSuccess()) {
+            DaylightWebUtil.auditlog("Roles of", request.getUserPrincipal().getName(), "updated", newConfig.getUser()
+                    + " to " + newConfig.getRoles().toString());
+        }
+        return result;
+    }
+
+
     @RequestMapping(value = "/users/{username}", method = RequestMethod.POST)
     @ResponseBody
-    public String removeLocalUser(@PathVariable("username") String userName, HttpServletRequest request) {
+    public Status removeLocalUser(@PathVariable("username") String userName, HttpServletRequest request) {
 
-        String username = request.getUserPrincipal().getName();
-        if (username.equals(userName)) {
-            return "Invalid Request: User cannot delete itself";
+        String loggedInUser = request.getUserPrincipal().getName();
+        if (loggedInUser.equals(userName)) {
+            String msg = "Invalid Request: User cannot delete itself";
+            return new Status(StatusCode.NOTALLOWED, msg);
         }
 
         IUserManager userManager = (IUserManager) ServiceHelper.getGlobalInstance(IUserManager.class, this);
         if (userManager == null) {
-            return "Internal Error";
+            return new Status(StatusCode.NOSERVICE, "User Manager unavailable");
         }
 
         if (!authorize(userManager, UserLevel.NETWORKADMIN, request)) {
-            return "Operation not permitted";
+            return new Status(StatusCode.UNAUTHORIZED, "Operation not permitted");
         }
 
-        Status result = userManager.removeLocalUser(userName);
-        if (result.isSuccess()) {
+        Status status = userManager.removeLocalUser(userName);
+        if (status.isSuccess()) {
             DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "removed", userName);
-            return "Success";
+            return status;
         }
-        return result.getDescription();
+        return status;
     }
 
     @RequestMapping(value = "/users/password/{username}", method = RequestMethod.POST)
@@ -280,7 +321,7 @@ public class DaylightWebAdmin {
         }
 
         if (status.isSuccess()) {
-            DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), " changed password for User ",
+            DaylightWebUtil.auditlog("User", request.getUserPrincipal().getName(), "changed password for",
                     username);
         }
         return status;
index 6a2efdbf9a730e51fc37bc18a3fd297d91c93535..511e5881ac557ca90ca1fc5192babdcd2c2f74c5 100644 (file)
@@ -142,6 +142,9 @@ one.main.admin = {
         close : "one_main_admin_id_modal_remove_close",
         password : 'one_main_admin_id_modal_remove_password'
       },
+      modify : {
+          user : "one_main_admin_id_modal_modify_user",
+      },
       password : {
         modal : 'one_main_admin_id_modal_password_modal',
         submit : 'one_main_admin_id_modal_password_submit',
@@ -156,10 +159,14 @@ one.main.admin = {
     add : {
       user : "one_main_admin_id_add_user"
     }
+  },
+  registry :{
+
   },
   address : {
     root : "/admin",
     users : "/users",
+    modifyUser : "/user/modify",
     password : '/admin/users/password/'
   },
   modal : {
@@ -195,6 +202,7 @@ one.main.admin = {
       $.getJSON(one.main.admin.address.root
           + one.main.admin.address.users, function(data) {
             var body = one.main.admin.data.users(data);
+            one.main.admin.registry["users"] = data;
             var $body = one.main.admin.body.users(body);
             callback($body);
           });
@@ -258,7 +266,7 @@ one.main.admin = {
   remove : {
     modal : {
       initialize : function(id) {
-        var h3 = "Edit User";
+        var h3 = "Manage user - " + id;
         var footer = one.main.admin.remove.footer();
         var $body = one.main.admin.remove.body();
         var $modal = one.lib.modal.spawn(one.main.admin.id.modal.user,
@@ -267,10 +275,14 @@ one.main.admin = {
         $('#'+one.main.admin.id.modal.remove.close, $modal).click(function() {
           $modal.modal('hide');
         });
+        // close binding
+        $('#'+one.main.admin.id.modal.modify.user, $modal).click(function() {
+          one.main.admin.add.modal.initialize(id, true);
+        });
         // remove binding
         $('#' + one.main.admin.id.modal.remove.user, $modal).click(function() {
           one.main.admin.remove.modal.ajax(id, function(result) {
-            if (result == 'Success') {
+            if (result.description == 'Success') {
               $modal.modal('hide');
               // body inject
               var $admin = $('#'+one.main.admin.id.modal.main);
@@ -278,7 +290,7 @@ one.main.admin = {
                 one.lib.modal.inject.body($admin, $body);
               });
             } else {
-              alert("Failed to remove user: " + result);
+              alert("Failed to remove user: " + result.description);
             }
           });
         });
@@ -302,6 +314,10 @@ one.main.admin = {
           one.main.admin.id.modal.remove.user, "btn-danger", "");
       var $removeButton = one.lib.dashlet.button.button(removeButton);
       footer.push($removeButton);
+      var modifyButton = one.lib.dashlet.button.single("Change Role",
+              one.main.admin.id.modal.modify.user, "btn-success", "");
+      var $modifyButton = one.lib.dashlet.button.button(modifyButton);
+      footer.push($modifyButton);
       var change = one.lib.dashlet.button.single('Change Password',
           one.main.admin.id.modal.remove.password, 'btn-success', '');
       var $change = one.lib.dashlet.button.button(change);
@@ -320,10 +336,10 @@ one.main.admin = {
   },
   add : {
     modal : {
-      initialize : function() {
-        var h3 = "Add User";
-        var footer = one.main.admin.add.footer();
-        var $body = one.main.admin.add.body();
+      initialize : function(id, edit) {
+        var h3 = edit? "Change Role of user " + id:"Add User";
+        var footer = one.main.admin.add.footer(edit);
+        var $body = one.main.admin.add.body(id, edit);
         var $modal = one.lib.modal.spawn(one.main.admin.id.modal.user,
             h3, $body, footer);
         // close binding
@@ -332,73 +348,100 @@ one.main.admin = {
         });
         // add binding
         $('#' + one.main.admin.id.modal.add.user, $modal).click(function() {
-          one.main.admin.add.modal.add($modal, function(result) {
-            if (result == 'Success') {
+          one.main.admin.add.modal.add($modal, edit, function(result) {
+            if (result.description == 'Success') {
               $modal.modal('hide');
               // body inject
               var $admin = $('#'+one.main.admin.id.modal.main);
               one.main.admin.ajax.users(function($body) {
-                one.lib.modal.inject.body($admin, $body);
+               one.lib.modal.inject.body($admin, $body);
               });
             } else {
-              alert("Failed to add user: "+result);
+              var action = edit? "edit" :"add";
+              alert("Failed to "+ action +" user: "+result.description);
             }
           });
         });
         $modal.modal();
       },
-      add : function($modal, callback) {
+      add : function($modal, edit, callback) {
         var user = {};
         user['user'] = $modal.find(
             '#' + one.main.admin.id.modal.add.form.name).val();
-        user['password'] = $modal.find(
-            '#' + one.main.admin.id.modal.add.form.password).val();
+        if (!edit) {
+            user['password'] = $modal.find(
+                '#' + one.main.admin.id.modal.add.form.password).val();
+        }
         roles = new Array();
         roles[0] = $modal.find(
             '#' + one.main.admin.id.modal.add.form.role).find(
               'option:selected').attr('value');
         user['roles'] = roles;
 
-        // password check
-        var verify = $('#'+one.main.admin.id.modal.add.form.verify).val();
-        if (user.password != verify) {
-          alert('Passwords do not match');
-          return false;
+        if (!edit) {
+            // password check
+            var verify = $('#'+one.main.admin.id.modal.add.form.verify).val();
+            if (user.password != verify) {
+              alert('Passwords do not match');
+              return false;
+            }
         }
-
         var resource = {};
         resource['json'] = JSON.stringify(user);
         resource['action'] = 'add'
 
-          one.main.admin.add.modal.ajax(resource, callback);
+        one.main.admin.add.modal.ajax(resource, edit, callback);
       },
-      ajax : function(data, callback) {
-        $.post(one.main.admin.address.root
-            + one.main.admin.address.users, data, function(data) {
-              callback(data);
-            });
+      ajax : function(data, edit, callback) {
+          if(edit) {
+            $.post(one.main.admin.address.root
+              + one.main.admin.address.modifyUser, data, function(data) {
+                callback(data);
+              });
+          } else {  
+            $.post(one.main.admin.address.root
+              + one.main.admin.address.users, data, function(data) {
+                callback(data);
+              });
+          }
       }
     },
-    body : function() {
+    body : function(id, edit) {
       var $form = $(document.createElement('form'));
       var $fieldset = $(document.createElement('fieldset'));
+      var users = one.main.admin.registry["users"];
+      var currentUser;
+      if(edit) {
+        $(users).each(function(index, val) {
+             if(val.user == id){
+            currentUser = val;
+          }
+        });
+      }
+
       // user
       var $label = one.lib.form.label('Username');
       var $input = one.lib.form.input('Username');
       $input.attr('id', one.main.admin.id.modal.add.form.name);
+      if(edit) {
+         $input.attr("disabled",true);
+         $input.val(id);
+      }
       $fieldset.append($label).append($input);
-      // password
-      var $label = one.lib.form.label('Password');
-      var $input = one.lib.form.input('Password');
-      $input.attr('id', one.main.admin.id.modal.add.form.password);
-      $input.attr('type', 'password');
-      $fieldset.append($label).append($input);
-      // password verify
-      var $label = one.lib.form.label('Verify Password');
-      var $input = one.lib.form.input('Verify Password');
-      $input.attr('id', one.main.admin.id.modal.add.form.verify);
-      $input.attr('type', 'password');
-      $fieldset.append($label).append($input);
+      if(!edit) {
+          // password
+          var $label = one.lib.form.label('Password');
+          var $input = one.lib.form.input('Password');
+          $input.attr('id', one.main.admin.id.modal.add.form.password);
+          $input.attr('type', 'password');
+          $fieldset.append($label).append($input);
+          // password verify
+          var $label = one.lib.form.label('Verify Password');
+          var $input = one.lib.form.input('Verify Password');
+          $input.attr('id', one.main.admin.id.modal.add.form.verify);
+          $input.attr('type', 'password');
+          $fieldset.append($label).append($input);
+      }
       // roles
       var $label = one.lib.form.label('Roles');
       var options = {
@@ -407,14 +450,22 @@ one.main.admin = {
       };
       var $select = one.lib.form.select.create(options);
       $select.attr('id', one.main.admin.id.modal.add.form.role);
+      if(edit) {
+          $select.children().each(function() {
+                 this.selected = (this.text == options[currentUser.roles[0]]);
+          });
+      }
+
       $fieldset.append($label).append($select);
       $form.append($fieldset);
       return $form;
     },
-    footer : function() {
+    footer : function(edit) {
       var footer = [];
 
-      var addButton = one.lib.dashlet.button.single("Add User",
+      var buttonText = edit ? "Update User" : "Add User";
+
+      var addButton = one.lib.dashlet.button.single(buttonText,
           one.main.admin.id.modal.add.user, "btn-primary", "");
       var $addButton = one.lib.dashlet.button.button(addButton);
       footer.push($addButton);
@@ -743,4 +794,4 @@ $.ajaxSetup({
 });
 
 /** MAIN PAGE LOAD */
-one.main.menu.load();
+one.main.menu.load();
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index c603a9446e2e871ef4bd3667277db5df99b9f505..f7f9bc2256b35c72697d4deeaef84e70930521ec 100644 (file)
--- a/pom.xml
+++ b/pom.xml
                 <module>opendaylight/distribution/sanitytest/</module>
             </modules>
         </profile>
+        <profile>
+           <id>docs</id>
+           <activation>
+               <activeByDefault>false</activeByDefault>
+           </activation>
+            <modules>
+              <module>opendaylight/northbound/java-client</module>
+            </modules>
+        </profile>
     </profiles>
 </project>