Move adsal into its own subdirectory.
authorEd Warnicke <eaw@cisco.com>
Tue, 4 Nov 2014 22:17:43 +0000 (16:17 -0600)
committerAndrew Grimberg <agrimberg@linuxfoundation.org>
Fri, 13 Feb 2015 16:05:05 +0000 (08:05 -0800)
Moved various adsal components into an opendaylight/adsal subdir,
gave it a parent pom, and changed the root parent pom to have the
opendaylight/adsal as a module.

Change-Id: I1d0e5a7b2a50c65559c2f80dd47cab491b68d561
Signed-off-by: Ed Warnicke <eaw@cisco.com>
38 files changed:
northbound/enunciate.xml [new file with mode: 0644]
northbound/pom.xml [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/INeutronRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRuleRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRulesNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMemberRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMembersNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworkRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNorthboundRSApplication.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPageLink.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRouterRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityGroupRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityGroupsNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityRuleRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityRulesNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetRequest.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java [new file with mode: 0644]
northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedRequestFactory.java [new file with mode: 0644]
northbound/src/main/resources/WEB-INF/web.xml [new file with mode: 0644]
northbound/src/main/resources/org/opendaylight/controller/networkconfig/neutron/northbound/jaxb.properties [new file with mode: 0644]

diff --git a/northbound/enunciate.xml b/northbound/enunciate.xml
new file mode 100644 (file)
index 0000000..6616025
--- /dev/null
@@ -0,0 +1,12 @@
+<?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.28.xsd">
+
+  <services>
+    <rest defaultRestSubcontext="/controller/nb/v2/neutron"/>
+  </services>
+
+  <modules>
+    <docs docsDir="rest" title="OpenStack Neutron REST API" includeExampleXml="false" includeExampleJson="true"/>
+   </modules>
+</enunciate>
diff --git a/northbound/pom.xml b/northbound/pom.xml
new file mode 100644 (file)
index 0000000..8111e69
--- /dev/null
@@ -0,0 +1,110 @@
+<?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.5.0-SNAPSHOT</version>
+    <relativePath>../../../commons/opendaylight</relativePath>
+  </parent>
+  <artifactId>networkconfig.neutron.northbound</artifactId>
+  <version>0.5.0-SNAPSHOT</version>
+  <packaging>bundle</packaging>
+  <dependencies>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.codehaus.enunciate</groupId>
+      <artifactId>enunciate-core-annotations</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.persistence</groupId>
+      <artifactId>org.eclipse.persistence.antlr</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.persistence</groupId>
+      <artifactId>org.eclipse.persistence.core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.eclipse.persistence</groupId>
+      <artifactId>org.eclipse.persistence.moxy</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>commons.northbound</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>containermanager</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>networkconfig.neutron</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>org.opendaylight.controller</groupId>
+      <artifactId>sal</artifactId>
+    </dependency>
+  </dependencies>
+
+  <build>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.felix</groupId>
+        <artifactId>maven-bundle-plugin</artifactId>
+        <extensions>true</extensions>
+        <configuration>
+          <instructions>
+            <Import-Package>org.opendaylight.controller.sal.utils,
+                            org.opendaylight.controller.containermanager,
+                            org.opendaylight.controller.northbound.commons,
+                            org.opendaylight.controller.northbound.commons.exception,
+                            org.opendaylight.controller.northbound.commons.utils,
+                            org.opendaylight.controller.networkconfig.neutron,
+                            org.eclipse.persistence.jaxb.rs,
+                            com.sun.jersey.spi.container.servlet,
+                            javax.ws.rs,
+                            javax.ws.rs.ext,
+                            javax.ws.rs.core,
+                            javax.xml.bind.annotation,
+                            javax.xml.bind,
+                            org.slf4j,
+                            !org.codehaus.enunciate.jaxrs</Import-Package>
+            <Web-ContextPath>/controller/nb/v2/neutron</Web-ContextPath>
+          </instructions>
+          <manifestLocation>${project.basedir}/src/main/resources/META-INF</manifestLocation>
+        </configuration>
+      </plugin>
+      <plugin>
+        <groupId>org.codehaus.enunciate</groupId>
+        <artifactId>maven-enunciate-plugin</artifactId>
+      </plugin>
+    </plugins>
+  </build>
+  <scm>
+    <connection>scm:git:ssh://git.opendaylight.org:29418/controller.git</connection>
+    <developerConnection>scm:git:ssh://git.opendaylight.org:29418/controller.git</developerConnection>
+    <tag>HEAD</tag>
+    <url>https://wiki.opendaylight.org/view/OpenDaylight_Controller:Main</url>
+  </scm>
+
+  <distributionManagement>
+    <!-- OpenDayLight Released artifact -->
+    <repository>
+      <id>opendaylight-release</id>
+      <url>${nexusproxy}/repositories/${nexus.repository.release}/</url>
+    </repository>
+    <!-- OpenDayLight Snapshot artifact -->
+    <snapshotRepository>
+      <id>opendaylight-snapshot</id>
+      <url>${nexusproxy}/repositories/${nexus.repository.snapshot}/</url>
+    </snapshotRepository>
+    <!-- Site deployment -->
+    <site>
+      <id>website</id>
+      <url>${sitedeploy}</url>
+    </site>
+  </distributionManagement>
+</project>
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/INeutronRequest.java b/northbound/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();
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallNorthbound.java
new file mode 100644 (file)
index 0000000..204c9f5
--- /dev/null
@@ -0,0 +1,381 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronFirewall;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for Firewall.<br>
+ * This class provides REST APIs for managing neutron Firewall
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/fw/firewalls")
+public class NeutronFirewallNorthbound {
+
+    private NeutronFirewall extractFields(NeutronFirewall o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all Firewalls */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack firewall attributes
+            @QueryParam("id") String queryFirewallUUID,
+            @QueryParam("tenant_id") String queryFirewallTenantID,
+            @QueryParam("name") String queryFirewallName,
+            @QueryParam("description") String queryFirewallDescription,
+            @QueryParam("shared") Boolean queryFirewallAdminStateIsUp,
+            @QueryParam("status") String queryFirewallStatus,
+            @QueryParam("shared") Boolean queryFirewallIsShared,
+            @QueryParam("firewall_policy_id") String queryFirewallPolicyID,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this);
+        INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this);
+
+        if (firewallInterface == null) {
+            throw new ServiceUnavailableException("Firewall CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronFirewall> allFirewalls = firewallInterface.getAllNeutronFirewalls();
+        List<NeutronFirewall> ans = new ArrayList<NeutronFirewall>();
+        Iterator<NeutronFirewall> i = allFirewalls.iterator();
+        while (i.hasNext()) {
+            NeutronFirewall nsg = i.next();
+            if ((queryFirewallUUID == null ||
+                queryFirewallUUID.equals(nsg.getFirewallUUID())) &&
+                (queryFirewallTenantID == null ||
+                    queryFirewallTenantID.equals(nsg.getFirewallTenantID())) &&
+                (queryFirewallName == null ||
+                    queryFirewallName.equals(nsg.getFirewallName())) &&
+                (queryFirewallDescription == null ||
+                    queryFirewallDescription.equals(nsg.getFirewallDescription())) &&
+                (queryFirewallAdminStateIsUp == null ||
+                    queryFirewallAdminStateIsUp.equals(nsg.getFirewallAdminStateIsUp())) &&
+                (queryFirewallStatus == null ||
+                    queryFirewallStatus.equals(nsg.getFirewallStatus())) &&
+                (queryFirewallIsShared == null ||
+                    queryFirewallIsShared.equals(nsg.getFirewallIsShared())) &&
+                (queryFirewallPolicyID == null ||
+                    queryFirewallPolicyID.equals(nsg.getFirewallPolicyID()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        //TODO: apply pagination to results
+        return Response.status(200).entity(
+                new NeutronFirewallRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific Firewall */
+
+    @Path("{firewallUUID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showFirewall(@PathParam("firewallUUID") String firewallUUID,
+                                      // return fields
+                                      @QueryParam("fields") List<String> fields) {
+        INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this);
+        if (firewallInterface == null) {
+            throw new ServiceUnavailableException("Firewall CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!firewallInterface.neutronFirewallExists(firewallUUID)) {
+            throw new ResourceNotFoundException("Firewall UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronFirewall ans = firewallInterface.getNeutronFirewall(firewallUUID);
+            return Response.status(200).entity(
+                    new NeutronFirewallRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronFirewallRequest(firewallInterface.getNeutronFirewall(firewallUUID))).build();
+        }
+    }
+
+    /**
+     * Creates new Firewall */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createFirewalls(final NeutronFirewallRequest input) {
+        INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this);
+        if (firewallInterface == null) {
+            throw new ServiceUnavailableException("Firewall CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronFirewall singleton = input.getSingleton();
+
+            /*
+             *  Verify that the Firewall doesn't already exist.
+             */
+            if (firewallInterface.neutronFirewallExists(singleton.getFirewallUUID())) {
+                throw new BadRequestException("Firewall UUID already exists");
+            }
+            firewallInterface.addNeutronFirewall(singleton);
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                    int status = service.canCreateNeutronFirewall(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            firewallInterface.addNeutronFirewall(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                    service.neutronFirewallCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronFirewall> bulk = input.getBulk();
+            Iterator<NeutronFirewall> i = bulk.iterator();
+            HashMap<String, NeutronFirewall> testMap = new HashMap<String, NeutronFirewall>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronFirewall test = i.next();
+
+                /*
+                 *  Verify that the secruity group doesn't already exist
+                 */
+                if (firewallInterface.neutronFirewallExists(test.getFirewallUUID())) {
+                    throw new BadRequestException("Firewall UUID already is already created");
+                }
+                if (testMap.containsKey(test.getFirewallUUID())) {
+                    throw new BadRequestException("Firewall UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                        int status = service.canCreateNeutronFirewall(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronFirewall test = i.next();
+                firewallInterface.addNeutronFirewall(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                        service.neutronFirewallCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Firewall */
+
+    @Path("{firewallUUID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateFirewall(
+            @PathParam("firewallUUID") String firewallUUID, final NeutronFirewallRequest input) {
+        INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this);
+        if (firewallInterface == null) {
+            throw new ServiceUnavailableException("Firewall CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Firewall exists and there is only one delta provided
+         */
+        if (!firewallInterface.neutronFirewallExists(firewallUUID)) {
+            throw new ResourceNotFoundException("Firewall UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronFirewall delta = input.getSingleton();
+        NeutronFirewall original = firewallInterface.getNeutronFirewall(firewallUUID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getFirewallUUID() != null ||
+                delta.getFirewallTenantID() != null ||
+                delta.getFirewallName() != null ||
+                delta.getFirewallDescription() != null ||
+                delta.getFirewallAdminStateIsUp() != null ||
+                delta.getFirewallStatus() != null ||
+                delta.getFirewallIsShared() != null ||
+                delta.getFirewallPolicyID() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                int status = service.canUpdateNeutronFirewall(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        firewallInterface.updateNeutronFirewall(firewallUUID, delta);
+        NeutronFirewall updatedFirewall = firewallInterface.getNeutronFirewall(firewallUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                service.neutronFirewallUpdated(updatedFirewall);
+            }
+        }
+        return Response.status(200).entity(new NeutronFirewallRequest(firewallInterface.getNeutronFirewall(firewallUUID))).build();
+    }
+
+    /**
+     * Deletes a Firewall */
+
+    @Path("{firewallUUID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteFirewall(
+            @PathParam("firewallUUID") String firewallUUID) {
+        INeutronFirewallCRUD firewallInterface = NeutronCRUDInterfaces.getINeutronFirewallCRUD(this);
+        if (firewallInterface == null) {
+            throw new ServiceUnavailableException("Firewall CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Firewall exists and it isn't currently in use
+         */
+        if (!firewallInterface.neutronFirewallExists(firewallUUID)) {
+            throw new ResourceNotFoundException("Firewall UUID does not exist.");
+        }
+        if (firewallInterface.neutronFirewallInUse(firewallUUID)) {
+            return Response.status(409).build();
+        }
+        NeutronFirewall singleton = firewallInterface.getNeutronFirewall(firewallUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                int status = service.canDeleteNeutronFirewall(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * remove it and return 204 status
+         */
+        firewallInterface.removeNeutronFirewall(firewallUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallAware service = (INeutronFirewallAware) instance;
+                service.neutronFirewallDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyNorthbound.java
new file mode 100644 (file)
index 0000000..cc45d6d
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallPolicy;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for Firewall Policies.<br>
+ * This class provides REST APIs for managing neutron Firewall Policies
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/fw/firewalls_policies")
+public class NeutronFirewallPolicyNorthbound {
+
+    private NeutronFirewallPolicy extractFields(NeutronFirewallPolicy o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all Firewall Policies */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack Firewall Policy attributes
+            @QueryParam("id") String queryFirewallPolicyUUID,
+            @QueryParam("tenant_id") String queryFirewallPolicyTenantID,
+            @QueryParam("name") String queryFirewallPolicyName,
+            @QueryParam("description") String querySecurityPolicyDescription,
+            @QueryParam("shared") String querySecurityPolicyIsShared,
+            @QueryParam("firewall_rules") List<String> querySecurityPolicyFirewallRules,
+            @QueryParam("audited") Boolean querySecurityPolicyIsAudited,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this);
+
+        if (firewallPolicyInterface == null) {
+            throw new ServiceUnavailableException("Firewall Policy CRUD Interface "
+                + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronFirewallPolicy> allFirewallPolicies = firewallPolicyInterface.getAllNeutronFirewallPolicies();
+        List<NeutronFirewallPolicy> ans = new ArrayList<NeutronFirewallPolicy>();
+        Iterator<NeutronFirewallPolicy> i = allFirewallPolicies.iterator();
+        while (i.hasNext()) {
+            NeutronFirewallPolicy nsg = i.next();
+            if ((queryFirewallPolicyUUID == null ||
+                queryFirewallPolicyUUID.equals(nsg.getFirewallPolicyUUID())) &&
+                (queryFirewallPolicyTenantID == null ||
+                    queryFirewallPolicyTenantID.equals(nsg.getFirewallPolicyTenantID())) &&
+                (queryFirewallPolicyName == null ||
+                    queryFirewallPolicyName.equals(nsg.getFirewallPolicyName())) &&
+                (querySecurityPolicyDescription == null ||
+                    querySecurityPolicyDescription.equals(nsg.getFirewallPolicyDescription())) &&
+                (querySecurityPolicyIsShared == null ||
+                    querySecurityPolicyIsShared.equals(nsg.getFirewallPolicyIsShared())) &&
+                (querySecurityPolicyFirewallRules.size() == 0 ||
+                    querySecurityPolicyFirewallRules.equals(nsg.getFirewallPolicyRules())) &&
+                (querySecurityPolicyIsAudited == null ||
+                    querySecurityPolicyIsAudited.equals(nsg.getFirewallPolicyIsAudited()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        } // ans.add((NeutronFirewallPolicy) rules);
+        //TODO: apply pagination to results
+        return Response.status(200).entity(
+                new NeutronFirewallPolicyRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific Firewall Policy */
+
+    @Path("{firewallPolicyUUID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showFirewallPolicy(@PathParam("firewallPolicyUUID") String firewallPolicyUUID,
+                                      // return fields
+                                      @QueryParam("fields") List<String> fields) {
+        INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this);
+        if (firewallPolicyInterface == null) {
+            throw new ServiceUnavailableException("Firewall Policy CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!firewallPolicyInterface.neutronFirewallPolicyExists(firewallPolicyUUID)) {
+            throw new ResourceNotFoundException("Firewall Policy UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronFirewallPolicy ans = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID);
+            return Response.status(200).entity(
+                    new NeutronFirewallPolicyRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronFirewallPolicyRequest(firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID))).build();
+        }
+    }
+
+    /**
+     * Creates new Firewall Policy
+     * */
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createFirewallPolicies(final NeutronFirewallPolicyRequest input) {
+        INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this);
+        if (firewallPolicyInterface == null) {
+            throw new ServiceUnavailableException("Firewall Policy CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronFirewallPolicy singleton = input.getSingleton();
+
+            /*
+             *  Verify that the Firewall Policy doesn't already exist.
+             */
+            if (firewallPolicyInterface.neutronFirewallPolicyExists(singleton.getFirewallPolicyUUID())) {
+                throw new BadRequestException("Firewall Policy UUID already exists");
+            }
+            firewallPolicyInterface.addNeutronFirewallPolicy(singleton);
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallPolicyAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                    int status = service.canCreateNeutronFirewallPolicy(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            firewallPolicyInterface.addNeutronFirewallPolicy(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                    service.neutronFirewallPolicyCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronFirewallPolicy> bulk = input.getBulk();
+            Iterator<NeutronFirewallPolicy> i = bulk.iterator();
+            HashMap<String, NeutronFirewallPolicy> testMap = new HashMap<String, NeutronFirewallPolicy>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallPolicyAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronFirewallPolicy test = i.next();
+
+                /*
+                 *  Verify that the firewall policy doesn't already exist
+                 */
+
+                if (firewallPolicyInterface.neutronFirewallPolicyExists(test.getFirewallPolicyUUID())) {
+                    throw new BadRequestException("Firewall Policy UUID already is already created");
+                }
+                if (testMap.containsKey(test.getFirewallPolicyUUID())) {
+                    throw new BadRequestException("Firewall Policy UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                        int status = service.canCreateNeutronFirewallPolicy(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronFirewallPolicy test = i.next();
+                firewallPolicyInterface.addNeutronFirewallPolicy(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                        service.neutronFirewallPolicyCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Firewall Policy
+     */
+    @Path("{firewallPolicyUUID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackSubnets.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateFirewallPolicy(
+            @PathParam("firewallPolicyUUID") String firewallPolicyUUID, final NeutronFirewallPolicyRequest input) {
+        INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this);
+        if (firewallPolicyInterface == null) {
+            throw new ServiceUnavailableException("Firewall Policy CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Firewall Policy exists and there is only one delta provided
+         */
+        if (!firewallPolicyInterface.neutronFirewallPolicyExists(firewallPolicyUUID)) {
+            throw new ResourceNotFoundException("Firewall Policy UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronFirewallPolicy delta = input.getSingleton();
+        NeutronFirewallPolicy original = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getFirewallPolicyUUID() != null ||
+                delta.getFirewallPolicyTenantID() != null ||
+                delta.getFirewallPolicyName() != null ||
+                delta.getFirewallPolicyDescription() != null ||
+                delta.getFirewallPolicyIsShared() != null ||
+                delta.getFirewallPolicyRules().size() > 0 ||
+                delta.getFirewallPolicyIsAudited() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallPolicyAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                int status = service.canUpdateNeutronFirewallPolicy(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        firewallPolicyInterface.updateNeutronFirewallPolicy(firewallPolicyUUID, delta);
+        NeutronFirewallPolicy updatedFirewallPolicy = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                service.neutronFirewallPolicyUpdated(updatedFirewallPolicy);
+            }
+        }
+        return Response.status(200).entity(new NeutronFirewallPolicyRequest(firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID))).build();
+    }
+
+    /**
+     * Deletes a Firewall Policy */
+
+    @Path("{firewallPolicyUUID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteFirewallPolicy(
+            @PathParam("firewallPolicyUUID") String firewallPolicyUUID) {
+        INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this);
+        if (firewallPolicyInterface == null) {
+            throw new ServiceUnavailableException("Firewall Policy CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Firewall Policy exists and it isn't currently in use
+         */
+        if (!firewallPolicyInterface.neutronFirewallPolicyExists(firewallPolicyUUID)) {
+            throw new ResourceNotFoundException("Firewall Policy UUID does not exist.");
+        }
+        if (firewallPolicyInterface.neutronFirewallPolicyInUse(firewallPolicyUUID)) {
+            return Response.status(409).build();
+        }
+        NeutronFirewallPolicy singleton = firewallPolicyInterface.getNeutronFirewallPolicy(firewallPolicyUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallPolicyAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                int status = service.canDeleteNeutronFirewallPolicy(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        firewallPolicyInterface.removeNeutronFirewallPolicy(firewallPolicyUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallPolicyAware service = (INeutronFirewallPolicyAware) instance;
+                service.neutronFirewallPolicyDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallPolicyRequest.java
new file mode 100644 (file)
index 0000000..473846a
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallPolicy;
+
+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 NeutronFirewallPolicyRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="firewall_policy")
+    NeutronFirewallPolicy singletonFirewallPolicy;
+
+    @XmlElement(name="firewall_policies")
+    List<NeutronFirewallPolicy> bulkRequest;
+
+    NeutronFirewallPolicyRequest() {
+    }
+
+    NeutronFirewallPolicyRequest(List<NeutronFirewallPolicy> bulk) {
+        bulkRequest = bulk;
+        singletonFirewallPolicy = null;
+    }
+
+    NeutronFirewallPolicyRequest(NeutronFirewallPolicy group) {
+        singletonFirewallPolicy = group;
+    }
+
+    public List<NeutronFirewallPolicy> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronFirewallPolicy getSingleton() {
+        return singletonFirewallPolicy;
+    }
+
+    public boolean isSingleton() {
+        return (singletonFirewallPolicy != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRequest.java
new file mode 100644 (file)
index 0000000..11a7836
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronFirewall;
+
+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 NeutronFirewallRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="firewall")
+    NeutronFirewall singletonFirewall;
+
+    @XmlElement(name="firewalls")
+    List<NeutronFirewall> bulkRequest;
+
+    NeutronFirewallRequest() {
+    }
+
+    NeutronFirewallRequest(List<NeutronFirewall> bulk) {
+        bulkRequest = bulk;
+        singletonFirewall = null;
+    }
+
+    NeutronFirewallRequest(NeutronFirewall group) {
+        singletonFirewall = group;
+    }
+
+    public List<NeutronFirewall> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronFirewall getSingleton() {
+        return singletonFirewall;
+    }
+
+    public boolean isSingleton() {
+        return (singletonFirewall != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRuleRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRuleRequest.java
new file mode 100644 (file)
index 0000000..19e67dd
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallRule;
+
+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 NeutronFirewallRuleRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="firewall_rule")
+    NeutronFirewallRule singletonFirewallRule;
+
+    @XmlElement(name="firewall_rules")
+    List<NeutronFirewallRule> bulkRequest;
+
+    NeutronFirewallRuleRequest() {
+    }
+
+    NeutronFirewallRuleRequest(List<NeutronFirewallRule> bulk) {
+        bulkRequest = bulk;
+        singletonFirewallRule = null;
+    }
+
+    NeutronFirewallRuleRequest(NeutronFirewallRule group) {
+        singletonFirewallRule = group;
+    }
+
+    public List<NeutronFirewallRule> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronFirewallRule getSingleton() {
+        return singletonFirewallRule;
+    }
+
+    public boolean isSingleton() {
+        return (singletonFirewallRule != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRulesNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFirewallRulesNorthbound.java
new file mode 100644 (file)
index 0000000..9911b4d
--- /dev/null
@@ -0,0 +1,427 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallPolicyCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFirewallRuleCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronFirewallRule;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for Firewall Rule.<br>
+ * This class provides REST APIs for managing neutron Firewall Rule
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ */
+
+@Path("fw/firewalls_rules")
+public class NeutronFirewallRulesNorthbound {
+
+    private NeutronFirewallRule extractFields(NeutronFirewallRule o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all Firewall Rules
+     */
+    @GET
+    @Produces({MediaType.APPLICATION_JSON})
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented")})
+    public Response listRules(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack firewall rule attributes
+            @QueryParam("id") String queryFirewallRuleUUID,
+            @QueryParam("tenant_id") String queryFirewallRuleTenantID,
+            @QueryParam("name") String queryFirewallRuleName,
+            @QueryParam("description") String queryFirewallRuleDescription,
+            @QueryParam("admin_state_up") Boolean queryFirewallRuleAdminStateIsUp,
+            @QueryParam("status") String queryFirewallRuleStatus,
+            @QueryParam("shared") Boolean queryFirewallRuleIsShared,
+            @QueryParam("firewall_policy_id") String queryFirewallRulePolicyID,
+            @QueryParam("protocol") String queryFirewallRuleProtocol,
+            @QueryParam("ip_version") Integer queryFirewallRuleIpVer,
+            @QueryParam("source_ip_address") String queryFirewallRuleSrcIpAddr,
+            @QueryParam("destination_ip_address") String queryFirewallRuleDstIpAddr,
+            @QueryParam("source_port") Integer queryFirewallRuleSrcPort,
+            @QueryParam("destination_port") Integer queryFirewallRuleDstPort,
+            @QueryParam("position") Integer queryFirewallRulePosition,
+            @QueryParam("action") String queryFirewallRuleAction,
+            @QueryParam("enabled") Boolean queryFirewallRuleIsEnabled,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this);
+        if (firewallRuleInterface == null) {
+            throw new ServiceUnavailableException("Firewall Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronFirewallRule> allFirewallRules = firewallRuleInterface.getAllNeutronFirewallRules();
+        List<NeutronFirewallRule> ans = new ArrayList<NeutronFirewallRule>();
+        Iterator<NeutronFirewallRule> i = allFirewallRules.iterator();
+        while (i.hasNext()) {
+            NeutronFirewallRule nsr = i.next();
+            if ((queryFirewallRuleUUID == null ||
+                    queryFirewallRuleUUID.equals(nsr.getFirewallRuleUUID())) &&
+                    (queryFirewallRuleTenantID == null ||
+                            queryFirewallRuleTenantID.equals(nsr.getFirewallRuleTenantID())) &&
+                    (queryFirewallRuleName == null ||
+                            queryFirewallRuleName.equals(nsr.getFirewallRuleName())) &&
+                    (queryFirewallRuleDescription == null ||
+                            queryFirewallRuleDescription.equals(nsr.getFirewallRuleDescription())) &&
+                    (queryFirewallRuleAdminStateIsUp == null ||
+                            queryFirewallRuleAdminStateIsUp.equals(nsr.getFirewallRuleAdminStateIsUp())) &&
+                    (queryFirewallRuleStatus == null ||
+                            queryFirewallRuleStatus.equals(nsr.getFirewallRuleStatus())) &&
+                    (queryFirewallRuleIsShared == null ||
+                            queryFirewallRuleIsShared.equals(nsr.getFirewallRuleIsShared())) &&
+                    (queryFirewallRulePolicyID == null ||
+                            queryFirewallRulePolicyID.equals(nsr.getFirewallRulePolicyID())) &&
+                    (queryFirewallRuleProtocol == null ||
+                            queryFirewallRuleProtocol.equals(nsr.getFirewallRuleProtocol())) &&
+                    (queryFirewallRuleIpVer == null ||
+                            queryFirewallRuleIpVer.equals(nsr.getFirewallRuleIpVer())) &&
+                    (queryFirewallRuleSrcIpAddr == null ||
+                            queryFirewallRuleSrcIpAddr.equals(nsr.getFirewallRuleSrcIpAddr())) &&
+                    (queryFirewallRuleDstIpAddr == null ||
+                            queryFirewallRuleDstIpAddr.equals(nsr.getFirewallRuleDstIpAddr())) &&
+                    (queryFirewallRuleSrcPort == null ||
+                            queryFirewallRuleSrcPort.equals(nsr.getFirewallRuleSrcPort())) &&
+                    (queryFirewallRuleDstPort == null ||
+                            queryFirewallRuleDstPort.equals(nsr.getFirewallRuleDstPort())) &&
+                    (queryFirewallRulePosition == null ||
+                            queryFirewallRulePosition.equals(nsr.getFirewallRulePosition())) &&
+                    (queryFirewallRuleAction == null ||
+                            queryFirewallRuleAction.equals(nsr.getFirewallRuleAction())) &&
+                    (queryFirewallRuleIsEnabled == null ||
+                            queryFirewallRuleIsEnabled.equals(nsr.getFirewallRuleIsEnabled()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsr, fields));
+                } else {
+                    ans.add(nsr);
+                }
+            }
+        }
+        //TODO: apply pagination to results
+        return Response.status(200).entity(
+                new NeutronFirewallRuleRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific Firewall Rule
+     */
+
+    @Path("{firewallRuleUUID}")
+    @GET
+    @Produces({MediaType.APPLICATION_JSON})
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented")})
+    public Response showFirewallRule(@PathParam("firewallRuleUUID") String firewallRuleUUID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this);
+        if (firewallRuleInterface == null) {
+            throw new ServiceUnavailableException("Firewall Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!firewallRuleInterface.neutronFirewallRuleExists(firewallRuleUUID)) {
+            throw new ResourceNotFoundException("Firewall Rule UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronFirewallRule ans = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID);
+            return Response.status(200).entity(
+                    new NeutronFirewallRuleRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200)
+                    .entity(new NeutronFirewallRuleRequest(
+                            firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID)))
+                    .build();
+        }
+    }
+
+    /**
+     * Creates new Firewall Rule
+     */
+
+    @POST
+    @Produces({MediaType.APPLICATION_JSON})
+    @Consumes({MediaType.APPLICATION_JSON})
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented")})
+    public Response createFirewallRules(final NeutronFirewallRuleRequest input) {
+        INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this);
+        if (firewallRuleInterface == null) {
+            throw new ServiceUnavailableException("Firewall Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronFirewallPolicyCRUD firewallPolicyInterface = NeutronCRUDInterfaces.getINeutronFirewallPolicyCRUD(this);
+        if (firewallPolicyInterface == null) {
+            throw new ServiceUnavailableException("Firewall Policy CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if (input.isSingleton()) {
+            NeutronFirewallRule singleton = input.getSingleton();
+            if (firewallRuleInterface.neutronFirewallRuleExists(singleton.getFirewallRuleUUID())) {
+                throw new BadRequestException("Firewall Rule UUID already exists");
+            }
+            firewallRuleInterface.addNeutronFirewallRule(singleton);
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallRuleAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                    int status = service.canCreateNeutronFirewallRule(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            // add rule to cache
+            singleton.initDefaults();
+            firewallRuleInterface.addNeutronFirewallRule(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                    service.neutronFirewallRuleCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronFirewallRule> bulk = input.getBulk();
+            Iterator<NeutronFirewallRule> i = bulk.iterator();
+            HashMap<String, NeutronFirewallRule> testMap = new HashMap<String, NeutronFirewallRule>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallRuleAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronFirewallRule test = i.next();
+
+                /*
+                 *  Verify that the Firewall rule doesn't already exist
+                 */
+
+                if (firewallRuleInterface.neutronFirewallRuleExists(test.getFirewallRuleUUID())) {
+                    throw new BadRequestException("Firewall Rule UUID already exists");
+                }
+                if (testMap.containsKey(test.getFirewallRuleUUID())) {
+                    throw new BadRequestException("Firewall Rule UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                        int status = service.canCreateNeutronFirewallRule(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronFirewallRule test = i.next();
+                firewallRuleInterface.addNeutronFirewallRule(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                        service.neutronFirewallRuleCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Firewall Rule
+     */
+    @Path("{firewallRuleUUID}")
+    @PUT
+    @Produces({MediaType.APPLICATION_JSON})
+    @Consumes({MediaType.APPLICATION_JSON})
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented")})
+    public Response updateFirewallRule(
+            @PathParam("firewallRuleUUID") String firewallRuleUUID, final NeutronFirewallRuleRequest input) {
+        INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this);
+        if (firewallRuleInterface == null) {
+            throw new ServiceUnavailableException("Firewall Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        /*
+         * verify the Firewall Rule exists
+         */
+        if (!firewallRuleInterface.neutronFirewallRuleExists(firewallRuleUUID)) {
+            throw new ResourceNotFoundException("Firewall Rule UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronFirewallRule delta = input.getSingleton();
+        NeutronFirewallRule original = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID);
+
+        /*
+         * updates restricted by Neutron
+         *
+         */
+        if (delta.getFirewallRuleUUID() != null ||
+                delta.getFirewallRuleTenantID() != null ||
+                delta.getFirewallRuleName() != null ||
+                delta.getFirewallRuleDescription() != null ||
+                delta.getFirewallRuleAdminStateIsUp() != null ||
+                delta.getFirewallRuleStatus() != null ||
+                delta.getFirewallRuleIsShared() != null ||
+                delta.getFirewallRulePolicyID() != null ||
+                delta.getFirewallRuleProtocol() != null ||
+                delta.getFirewallRuleIpVer() != null ||
+                delta.getFirewallRuleSrcIpAddr() != null ||
+                delta.getFirewallRuleDstIpAddr() != null ||
+                delta.getFirewallRuleSrcPort() != null ||
+                delta.getFirewallRuleDstPort() != null ||
+                delta.getFirewallRulePosition() != null ||
+                delta.getFirewallRuleAction() != null ||
+                delta.getFirewallRuleIsEnabled() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallRuleAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                int status = service.canUpdateNeutronFirewallRule(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        firewallRuleInterface.updateNeutronFirewallRule(firewallRuleUUID, delta);
+        NeutronFirewallRule updatedFirewallRule = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                service.neutronFirewallRuleUpdated(updatedFirewallRule);
+            }
+        }
+        return Response.status(200)
+                .entity(new NeutronFirewallRuleRequest(firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID)))
+                .build();
+    }
+
+    /**
+     * Deletes a Firewall Rule
+     */
+
+    @Path("{firewallRuleUUID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented")})
+    public Response deleteFirewallRule(
+            @PathParam("firewallRuleUUID") String firewallRuleUUID) {
+        INeutronFirewallRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronFirewallRuleCRUD(this);
+        if (firewallRuleInterface == null) {
+            throw new ServiceUnavailableException("Firewall Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Firewall Rule exists and it isn't currently in use
+         */
+        if (!firewallRuleInterface.neutronFirewallRuleExists(firewallRuleUUID)) {
+            throw new ResourceNotFoundException("Firewall Rule UUID does not exist.");
+        }
+        if (firewallRuleInterface.neutronFirewallRuleInUse(firewallRuleUUID)) {
+            return Response.status(409).build();
+        }
+        NeutronFirewallRule singleton = firewallRuleInterface.getNeutronFirewallRule(firewallRuleUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronFirewallRuleAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                int status = service.canDeleteNeutronFirewallRule(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * remove it and return 204 status
+         */
+        firewallRuleInterface.removeNeutronFirewallRule(firewallRuleUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFirewallRuleAware service = (INeutronFirewallRuleAware) instance;
+                service.neutronFirewallRuleDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPRequest.java
new file mode 100644 (file)
index 0000000..efb86e0
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+import java.util.List;
+
+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 org.opendaylight.controller.networkconfig.neutron.NeutronFloatingIP;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronFloatingIPRequest {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name="floatingip")
+    NeutronFloatingIP singletonFloatingIP;
+
+    @XmlElement(name="floatingips")
+    List<NeutronFloatingIP> bulkRequest;
+
+    NeutronFloatingIPRequest() {
+    }
+
+    NeutronFloatingIPRequest(List<NeutronFloatingIP> bulk) {
+        bulkRequest = bulk;
+        singletonFloatingIP = null;
+    }
+
+    NeutronFloatingIPRequest(NeutronFloatingIP singleton) {
+        bulkRequest = null;
+        singletonFloatingIP = singleton;
+    }
+
+    public NeutronFloatingIP getSingleton() {
+        return singletonFloatingIP;
+    }
+
+    public boolean isSingleton() {
+        return (singletonFloatingIP != null);
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronFloatingIPsNorthbound.java
new file mode 100644 (file)
index 0000000..af7cfd1
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFloatingIPAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronFloatingIPCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronFloatingIP;
+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.networkconfig.neutron.Neutron_IPs;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+/**
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing Neutron Floating IPs
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+
+@Path("/floatingips")
+public class NeutronFloatingIPsNorthbound {
+
+    private NeutronFloatingIP extractFields(NeutronFloatingIP o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all FloatingIPs */
+
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response listFloatingIPs(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // note: openstack isn't clear about filtering on lists, so we aren't handling them
+            @QueryParam("id") String queryID,
+            @QueryParam("floating_network_id") String queryFloatingNetworkId,
+            @QueryParam("port_id") String queryPortId,
+            @QueryParam("fixed_ip_address") String queryFixedIPAddress,
+            @QueryParam("floating_ip_address") String queryFloatingIPAddress,
+            @QueryParam("tenant_id") String queryTenantID,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+            ) {
+        INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
+        if (floatingIPInterface == null) {
+            throw new ServiceUnavailableException("Floating IP CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronFloatingIP> allFloatingIPs = floatingIPInterface.getAllFloatingIPs();
+        List<NeutronFloatingIP> ans = new ArrayList<NeutronFloatingIP>();
+        Iterator<NeutronFloatingIP> i = allFloatingIPs.iterator();
+        while (i.hasNext()) {
+            NeutronFloatingIP oSS = i.next();
+            //match filters: TODO provider extension and router extension
+            if ((queryID == null || queryID.equals(oSS.getID())) &&
+                    (queryFloatingNetworkId == null || queryFloatingNetworkId.equals(oSS.getFloatingNetworkUUID())) &&
+                    (queryPortId == null || queryPortId.equals(oSS.getPortUUID())) &&
+                    (queryFixedIPAddress == null || queryFixedIPAddress.equals(oSS.getFixedIPAddress())) &&
+                    (queryFloatingIPAddress == null || queryFloatingIPAddress.equals(oSS.getFloatingIPAddress())) &&
+                    (queryTenantID == null || queryTenantID.equals(oSS.getTenantUUID()))) {
+                if (fields.size() > 0)
+                    ans.add(extractFields(oSS,fields));
+                else
+                    ans.add(oSS);
+            }
+        }
+        //TODO: apply pagination to results
+        return Response.status(200).entity(
+                new NeutronFloatingIPRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific FloatingIP */
+
+    @Path("{floatingipUUID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showFloatingIP(
+            @PathParam("floatingipUUID") String floatingipUUID,
+            // return fields
+            @QueryParam("fields") List<String> fields ) {
+        INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
+        if (floatingIPInterface == null) {
+            throw new ServiceUnavailableException("Floating IP CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!floatingIPInterface.floatingIPExists(floatingipUUID))
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
+        if (fields.size() > 0) {
+            NeutronFloatingIP ans = floatingIPInterface.getFloatingIP(floatingipUUID);
+            return Response.status(200).entity(
+                    new NeutronFloatingIPRequest(extractFields(ans, fields))).build();
+        } else
+            return Response.status(200).entity(
+                    new NeutronFloatingIPRequest(floatingIPInterface.getFloatingIP(floatingipUUID))).build();
+
+    }
+
+    /**
+     * Creates new FloatingIPs */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+        @ResponseCode(code = 201, condition = "Created"),
+        @ResponseCode(code = 400, condition = "Bad Request"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 409, condition = "Conflict"),
+        @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createFloatingIPs(final NeutronFloatingIPRequest input) {
+        INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
+        if (floatingIPInterface == null) {
+            throw new ServiceUnavailableException("Floating IP CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronFloatingIP singleton = input.getSingleton();
+            // check existence of id in cache and return badrequest if exists
+            if (floatingIPInterface.floatingIPExists(singleton.getID()))
+                throw new BadRequestException("Floating IP UUID already exists.");
+            // check if the external network is specified, exists, and is an external network
+            String externalNetworkUUID = singleton.getFloatingNetworkUUID();
+            if (externalNetworkUUID == null)
+                throw new BadRequestException("external network UUID doesn't exist.");
+            if (!networkInterface.networkExists(externalNetworkUUID))
+                throw new BadRequestException("external network UUID doesn't exist.");
+            NeutronNetwork externNetwork = networkInterface.getNetwork(externalNetworkUUID);
+            if (!externNetwork.isRouterExternal())
+                throw new BadRequestException("external network isn't marked router:external");
+            // if floating IP is specified, make sure it can come from the network
+            String floatingIP = singleton.getFloatingIPAddress();
+            if (floatingIP != null) {
+                if (externNetwork.getSubnets().size() != 1)
+                    throw new BadRequestException("external network doesn't have a subnet");
+                NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
+                if (!externSubnet.isValidIP(floatingIP))
+                    throw new BadRequestException("external IP isn't valid for the specified subnet.");
+                if (externSubnet.isIPInUse(floatingIP))
+                    throw new ResourceConflictException("floating IP is in use.");
+            }
+            // if port_id is specified, then check that the port exists and has at least one IP
+            String port_id = singleton.getPortUUID();
+            if (port_id != null) {
+                String fixedIP = null;        // used for the fixedIP calculation
+                if (!portInterface.portExists(port_id))
+                    throw new ResourceNotFoundException("Port UUID doesn't exist.");
+                NeutronPort port = portInterface.getPort(port_id);
+                if (port.getFixedIPs().size() < 1)
+                    throw new BadRequestException("port UUID doesn't have an IP address.");
+                // if there is more than one fixed IP then check for fixed_ip_address
+                // and that it is in the list of port addresses
+                if (port.getFixedIPs().size() > 1) {
+                    fixedIP = singleton.getFixedIPAddress();
+                    if (fixedIP == null)
+                        throw new BadRequestException("fixed IP address doesn't exist.");
+                    Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
+                    boolean validFixedIP = false;
+                    while (i.hasNext() && !validFixedIP) {
+                        Neutron_IPs ip = i.next();
+                        if (ip.getIpAddress().equals(fixedIP))
+                            validFixedIP = true;
+                    }
+                    if (!validFixedIP)
+                        throw new BadRequestException("can't find a valid fixed IP address");
+                } else {
+                    fixedIP = port.getFixedIPs().get(0).getIpAddress();
+                    if (singleton.getFixedIPAddress() != null && !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
+                        throw new BadRequestException("mismatched fixed IP address in request");
+                }
+                //lastly check that this fixed IP address isn't already used
+                if (port.isBoundToFloatingIP(fixedIP))
+                    throw new ResourceConflictException("fixed IP is in use.");
+                singleton.setFixedIPAddress(fixedIP);
+            }
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                    int status = service.canCreateFloatingIP(singleton);
+                    if (status < 200 || status > 299)
+                        return Response.status(status).build();
+                }
+            }
+            floatingIPInterface.addFloatingIP(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                    service.neutronFloatingIPCreated(singleton);
+                }
+            }
+        } else {
+            throw new BadRequestException("only singleton requests allowed.");
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a FloatingIP */
+
+    @Path("{floatingipUUID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateFloatingIP(
+            @PathParam("floatingipUUID") String floatingipUUID,
+            NeutronFloatingIPRequest input
+            ) {
+        INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
+        if (floatingIPInterface == null) {
+            throw new ServiceUnavailableException("Floating IP CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD( this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!floatingIPInterface.floatingIPExists(floatingipUUID))
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
+
+        NeutronFloatingIP sourceFloatingIP = floatingIPInterface.getFloatingIP(floatingipUUID);
+        if (!input.isSingleton())
+            throw new BadRequestException("only singleton requests allowed.");
+        NeutronFloatingIP singleton = input.getSingleton();
+        if (singleton.getID() == null)
+            throw new BadRequestException("singleton UUID doesn't exist.");
+
+        NeutronNetwork externNetwork = networkInterface.getNetwork(
+                sourceFloatingIP.getFloatingNetworkUUID());
+
+        // if floating IP is specified, make sure it can come from the network
+        String floatingIP = singleton.getFloatingIPAddress();
+        if (floatingIP != null) {
+            if (externNetwork.getSubnets().size() != 1)
+                throw new BadRequestException("external network doesn't have a subnet.");
+            NeutronSubnet externSubnet = subnetInterface.getSubnet(externNetwork.getSubnets().get(0));
+            if (!externSubnet.isValidIP(floatingIP))
+                throw new BadRequestException("floating IP not valid for external subnet");
+            if (externSubnet.isIPInUse(floatingIP))
+                throw new ResourceConflictException("floating IP is in use.");
+        }
+
+        // if port_id is specified, then check that the port exists and has at least one IP
+        String port_id = singleton.getPortUUID();
+        if (port_id != null) {
+            String fixedIP = null;        // used for the fixedIP calculation
+            if (!portInterface.portExists(port_id))
+                throw new ResourceNotFoundException("Port UUID doesn't exist.");
+            NeutronPort port = portInterface.getPort(port_id);
+            if (port.getFixedIPs().size() < 1)
+                throw new BadRequestException("port ID doesn't have a fixed IP address.");
+            // if there is more than one fixed IP then check for fixed_ip_address
+            // and that it is in the list of port addresses
+            if (port.getFixedIPs().size() > 1) {
+                fixedIP = singleton.getFixedIPAddress();
+                if (fixedIP == null)
+                    throw new BadRequestException("request doesn't have a fixed IP address");
+                Iterator<Neutron_IPs> i = port.getFixedIPs().iterator();
+                boolean validFixedIP = false;
+                while (i.hasNext() && !validFixedIP) {
+                    Neutron_IPs ip = i.next();
+                    if (ip.getIpAddress().equals(fixedIP))
+                        validFixedIP = true;
+                }
+                if (!validFixedIP)
+                    throw new BadRequestException("couldn't find a valid fixed IP address");
+            } else {
+                fixedIP = port.getFixedIPs().get(0).getIpAddress();
+                if (singleton.getFixedIPAddress() != null &&
+                        !fixedIP.equalsIgnoreCase(singleton.getFixedIPAddress()))
+                    throw new BadRequestException("mismatch in fixed IP addresses");
+            }
+            //lastly check that this fixed IP address isn't already used
+            if (port.isBoundToFloatingIP(fixedIP))
+                throw new ResourceConflictException("fixed IP is in use.");
+            singleton.setFixedIPAddress(fixedIP);
+        }
+        NeutronFloatingIP target = floatingIPInterface.getFloatingIP(floatingipUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                int status = service.canUpdateFloatingIP(singleton, target);
+                if (status < 200 || status > 299)
+                    return Response.status(status).build();
+            }
+        }
+        floatingIPInterface.updateFloatingIP(floatingipUUID, singleton);
+        target = floatingIPInterface.getFloatingIP(floatingipUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                service.neutronFloatingIPUpdated(target);
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronFloatingIPRequest(target)).build();
+
+    }
+
+    /**
+     * Deletes a FloatingIP */
+
+    @Path("{floatingipUUID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteFloatingIP(
+            @PathParam("floatingipUUID") String floatingipUUID) {
+        INeutronFloatingIPCRUD floatingIPInterface = NeutronCRUDInterfaces.getINeutronFloatingIPCRUD(this);
+        if (floatingIPInterface == null) {
+            throw new ServiceUnavailableException("Floating IP CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!floatingIPInterface.floatingIPExists(floatingipUUID))
+            throw new ResourceNotFoundException("Floating IP UUID doesn't exist.");
+        // TODO: need to undo port association if it exists
+        NeutronFloatingIP singleton = floatingIPInterface.getFloatingIP(floatingipUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronFloatingIPAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                int status = service.canDeleteFloatingIP(singleton);
+                if (status < 200 || status > 299)
+                    return Response.status(status).build();
+            }
+        }
+        floatingIPInterface.removeFloatingIP(floatingipUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronFloatingIPAware service = (INeutronFloatingIPAware) instance;
+                service.neutronFloatingIPDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorNorthbound.java
new file mode 100644 (file)
index 0000000..6cd2673
--- /dev/null
@@ -0,0 +1,410 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerHealthMonitorAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerHealthMonitorCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerHealthMonitor;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for Load Balancer HealthMonitor.<br>
+ * This class provides REST APIs for managing neutron LoadBalancerHealthMonitor
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/healthmonitors")
+public class NeutronLoadBalancerHealthMonitorNorthbound {
+    private static final Logger logger = LoggerFactory.getLogger(NeutronLoadBalancer.class);
+
+    private NeutronLoadBalancerHealthMonitor extractFields(NeutronLoadBalancerHealthMonitor o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all LoadBalancerHealthMonitor */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack LoadBalancerHealthMonitor attributes
+            @QueryParam("id") String queryLoadBalancerHealthMonitorID,
+            @QueryParam("tenant_id") String queryLoadBalancerHealthMonitorTenantID,
+            // TODO "type" is being a property by the JSON parser.
+            @QueryParam("type") String queryLoadBalancerHealthMonitorType,
+            @QueryParam("delay") Integer queryLoadBalancerHealthMonitorDelay,
+            @QueryParam("timeout") Integer queryLoadBalancerHealthMonitorTimeout,
+            @QueryParam("max_retries") Integer queryLoadBalancerHealthMonitorMaxRetries,
+            @QueryParam("http_method") String queryLoadBalancerHealthMonitorHttpMethod,
+            @QueryParam("url_path") String queryLoadBalancerHealthMonitorUrlPath,
+            @QueryParam("expected_codes") String queryLoadBalancerHealthMonitorExpectedCodes,
+            @QueryParam("admin_state_up") Boolean queryLoadBalancerHealthMonitorIsAdminStateUp,
+            @QueryParam("status") String queryLoadBalancerHealthMonitorStatus,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces
+                .getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronLoadBalancerHealthMonitor> allLoadBalancerHealthMonitors = loadBalancerHealthMonitorInterface.getAllNeutronLoadBalancerHealthMonitors();
+        List<NeutronLoadBalancerHealthMonitor> ans = new ArrayList<NeutronLoadBalancerHealthMonitor>();
+        Iterator<NeutronLoadBalancerHealthMonitor> i = allLoadBalancerHealthMonitors.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancerHealthMonitor nsg = i.next();
+            if ((queryLoadBalancerHealthMonitorID == null ||
+                    queryLoadBalancerHealthMonitorID.equals(nsg.getLoadBalancerHealthMonitorID())) &&
+                    (queryLoadBalancerHealthMonitorTenantID == null ||
+                            queryLoadBalancerHealthMonitorTenantID.equals
+                                    (nsg.getLoadBalancerHealthMonitorTenantID())) &&
+                    (queryLoadBalancerHealthMonitorType == null ||
+                            queryLoadBalancerHealthMonitorType.equals
+                                    (nsg.getLoadBalancerHealthMonitorType())) &&
+                    (queryLoadBalancerHealthMonitorDelay == null ||
+                            queryLoadBalancerHealthMonitorDelay.equals
+                                    (nsg.getLoadBalancerHealthMonitorDelay())) &&
+                    (queryLoadBalancerHealthMonitorTimeout == null ||
+                            queryLoadBalancerHealthMonitorTimeout.equals
+                                    (nsg.getLoadBalancerHealthMonitorTimeout())) &&
+                    (queryLoadBalancerHealthMonitorMaxRetries == null ||
+                            queryLoadBalancerHealthMonitorMaxRetries.equals
+                                    (nsg.getLoadBalancerHealthMonitorMaxRetries())) &&
+                    (queryLoadBalancerHealthMonitorHttpMethod == null ||
+                            queryLoadBalancerHealthMonitorHttpMethod.equals
+                                    (nsg.getLoadBalancerHealthMonitorHttpMethod())) &&
+                    (queryLoadBalancerHealthMonitorUrlPath == null ||
+                            queryLoadBalancerHealthMonitorUrlPath.equals
+                                    (nsg.getLoadBalancerHealthMonitorUrlPath())) &&
+                    (queryLoadBalancerHealthMonitorExpectedCodes == null ||
+                            queryLoadBalancerHealthMonitorExpectedCodes.equals
+                                    (nsg.getLoadBalancerHealthMonitorExpectedCodes())) &&
+                    (queryLoadBalancerHealthMonitorIsAdminStateUp == null ||
+                            queryLoadBalancerHealthMonitorIsAdminStateUp.equals
+                                    (nsg.getLoadBalancerHealthMonitorAdminStateIsUp())) &&
+                    (queryLoadBalancerHealthMonitorStatus == null ||
+                            queryLoadBalancerHealthMonitorStatus.equals
+                                    (nsg.getLoadBalancerHealthMonitorStatus()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronLoadBalancerHealthMonitorRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific LoadBalancerHealthMonitor */
+
+    @Path("{loadBalancerHealthMonitorID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showLoadBalancerHealthMonitor(@PathParam("loadBalancerHealthMonitorID") String loadBalancerHealthMonitorID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorExists(loadBalancerHealthMonitorID)) {
+            throw new ResourceNotFoundException("LoadBalancerHealthMonitor UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronLoadBalancerHealthMonitor ans = loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+            return Response.status(200).entity(
+                    new NeutronLoadBalancerHealthMonitorRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronLoadBalancerHealthMonitorRequest(loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID))).build();
+        }
+    }
+
+    /**
+     * Creates new LoadBalancerHealthMonitor */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createLoadBalancerHealthMonitors(final NeutronLoadBalancerHealthMonitorRequest input) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronLoadBalancerHealthMonitor singleton = input.getSingleton();
+
+            /*
+             *  Verify that the LoadBalancerHealthMonitor doesn't already exist.
+             */
+            if (loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorExists(singleton.getLoadBalancerHealthMonitorID())) {
+                throw new BadRequestException("LoadBalancerHealthMonitor UUID already exists");
+            }
+            loadBalancerHealthMonitorInterface.addNeutronLoadBalancerHealthMonitor(singleton);
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerHealthMonitorAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                    int status = service.canCreateNeutronLoadBalancerHealthMonitor(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            loadBalancerHealthMonitorInterface.addNeutronLoadBalancerHealthMonitor(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                    service.neutronLoadBalancerHealthMonitorCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronLoadBalancerHealthMonitor> bulk = input.getBulk();
+            Iterator<NeutronLoadBalancerHealthMonitor> i = bulk.iterator();
+            HashMap<String, NeutronLoadBalancerHealthMonitor> testMap = new HashMap<String, NeutronLoadBalancerHealthMonitor>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerHealthMonitorAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronLoadBalancerHealthMonitor test = i.next();
+
+                /*
+                 *  Verify that the firewall policy doesn't already exist
+                 */
+
+                if (loadBalancerHealthMonitorInterface
+                        .neutronLoadBalancerHealthMonitorExists(test.getLoadBalancerHealthMonitorID())) {
+                    throw new BadRequestException("LoadBalancerHealthMonitor UUID already is already created");
+                }
+                if (testMap.containsKey(test.getLoadBalancerHealthMonitorID())) {
+                    throw new BadRequestException("LoadBalancerHealthMonitor UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                        int status = service.canCreateNeutronLoadBalancerHealthMonitor(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronLoadBalancerHealthMonitor test = i.next();
+                loadBalancerHealthMonitorInterface.addNeutronLoadBalancerHealthMonitor(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                        service.neutronLoadBalancerHealthMonitorCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a LoadBalancerHealthMonitor Policy
+     */
+    @Path("{loadBalancerHealthMonitorID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateLoadBalancerHealthMonitor(
+            @PathParam("loadBalancerHealthMonitorID") String loadBalancerHealthMonitorID,
+            final NeutronLoadBalancerHealthMonitorRequest input) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces
+                .getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerHealthMonitor exists and there is only one delta provided
+         */
+        if (!loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorExists(loadBalancerHealthMonitorID)) {
+            throw new ResourceNotFoundException("LoadBalancerHealthMonitor UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronLoadBalancerHealthMonitor delta = input.getSingleton();
+        NeutronLoadBalancerHealthMonitor original = loadBalancerHealthMonitorInterface
+                .getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getLoadBalancerHealthMonitorID() != null ||
+                delta.getLoadBalancerHealthMonitorTenantID() != null ||
+                delta.getLoadBalancerHealthMonitorType() != null ||
+                delta.getLoadBalancerHealthMonitorDelay() != null ||
+                delta.getLoadBalancerHealthMonitorTimeout() != null ||
+                delta.getLoadBalancerHealthMonitorMaxRetries() != null ||
+                delta.getLoadBalancerHealthMonitorHttpMethod() != null ||
+                delta.getLoadBalancerHealthMonitorUrlPath() != null ||
+                delta.getLoadBalancerHealthMonitorExpectedCodes() != null ||
+                delta.getLoadBalancerHealthMonitorAdminStateIsUp() != null ||
+                delta.getLoadBalancerHealthMonitorStatus() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerHealthMonitorAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                int status = service.canUpdateNeutronLoadBalancerHealthMonitor(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        loadBalancerHealthMonitorInterface.updateNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID, delta);
+        NeutronLoadBalancerHealthMonitor updatedLoadBalancerHealthMonitor = loadBalancerHealthMonitorInterface
+                .getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                service.neutronLoadBalancerHealthMonitorUpdated(updatedLoadBalancerHealthMonitor);
+            }
+        }
+        return Response.status(200).entity(new NeutronLoadBalancerHealthMonitorRequest
+                (loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor
+                        (loadBalancerHealthMonitorID))).build();
+    }
+
+
+
+    /**
+     * Deletes a LoadBalancerHealthMonitor
+     * */
+    @Path("{loadBalancerHealthMonitorID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteLoadBalancerHealthMonitor(
+            @PathParam("loadBalancerHealthMonitorID") String loadBalancerHealthMonitorID) {
+        INeutronLoadBalancerHealthMonitorCRUD loadBalancerHealthMonitorInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerHealthMonitorCRUD(this);
+        if (loadBalancerHealthMonitorInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerHealthMonitor CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        /*
+         * verify the LoadBalancerHealthMonitor exists and it isn't currently in use
+         */
+        if (!loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorExists(loadBalancerHealthMonitorID)) {
+            throw new ResourceNotFoundException("LoadBalancerHealthMonitor UUID does not exist.");
+        }
+        if (loadBalancerHealthMonitorInterface.neutronLoadBalancerHealthMonitorInUse(loadBalancerHealthMonitorID)) {
+            return Response.status(409).build();
+        }
+        NeutronLoadBalancerHealthMonitor singleton = loadBalancerHealthMonitorInterface.getNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerHealthMonitorAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                int status = service.canDeleteNeutronLoadBalancerHealthMonitor(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+        loadBalancerHealthMonitorInterface.removeNeutronLoadBalancerHealthMonitor(loadBalancerHealthMonitorID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerHealthMonitorAware service = (INeutronLoadBalancerHealthMonitorAware) instance;
+                service.neutronLoadBalancerHealthMonitorDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerHealthMonitorRequest.java
new file mode 100644 (file)
index 0000000..dc4af2f
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerHealthMonitor;
+
+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 NeutronLoadBalancerHealthMonitorRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="healthmonitor")
+    NeutronLoadBalancerHealthMonitor singletonLoadBalancerHealthMonitor;
+
+    @XmlElement(name="healthmonitors")
+    List<NeutronLoadBalancerHealthMonitor> bulkRequest;
+
+    NeutronLoadBalancerHealthMonitorRequest() {
+    }
+
+    NeutronLoadBalancerHealthMonitorRequest(List<NeutronLoadBalancerHealthMonitor> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerHealthMonitor = null;
+    }
+
+    NeutronLoadBalancerHealthMonitorRequest(NeutronLoadBalancerHealthMonitor group) {
+        singletonLoadBalancerHealthMonitor = group;
+    }
+
+    public List<NeutronLoadBalancerHealthMonitor> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerHealthMonitor getSingleton() {
+        return singletonLoadBalancerHealthMonitor;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerHealthMonitor != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerNorthbound.java
new file mode 100644 (file)
index 0000000..f3ef39f
--- /dev/null
@@ -0,0 +1,391 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerListenerAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerListenerCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerListener;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for LoadBalancerListener Policies.<br>
+ * This class provides REST APIs for managing neutron LoadBalancerListener Policies
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/listeners")
+public class NeutronLoadBalancerListenerNorthbound {
+
+    private NeutronLoadBalancerListener extractFields(NeutronLoadBalancerListener o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all LoadBalancerListener */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack LoadBalancerListener attributes
+            @QueryParam("id") String queryLoadBalancerListenerID,
+            @QueryParam("default_pool_id") String queryLoadBalancerListenerDefaultPoolID,
+            @QueryParam("tenant_id") String queryLoadBalancerListenerTenantID,
+            @QueryParam("name") String queryLoadBalancerListenerName,
+            @QueryParam("description") String queryLoadBalancerListenerDescription,
+            @QueryParam("shared") String queryLoadBalancerListenerIsShared,
+            @QueryParam("protocol") String queryLoadBalancerListenerProtocol,
+            @QueryParam("protocol_port") String queryLoadBalancerListenerProtocolPort,
+            @QueryParam("load_balancer_id") String queryLoadBalancerListenerLoadBalancerID,
+            @QueryParam("admin_state_up") String queryLoadBalancerListenerAdminIsUp,
+            @QueryParam("status") String queryLoadBalancerListenerStatus,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        //        INeutronLoadBalancerListenerRuleCRUD firewallRuleInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerRuleCRUD(this);
+
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronLoadBalancerListener> allLoadBalancerListeners = loadBalancerListenerInterface.getAllNeutronLoadBalancerListeners();
+        //        List<NeutronLoadBalancerListenerRule> allLoadBalancerListenerRules = firewallRuleInterface.getAllNeutronLoadBalancerListenerRules();
+        List<NeutronLoadBalancerListener> ans = new ArrayList<NeutronLoadBalancerListener>();
+        //        List<NeutronLoadBalancerListenerRule> rules = new ArrayList<NeutronLoadBalancerListenerRule>();
+        Iterator<NeutronLoadBalancerListener> i = allLoadBalancerListeners.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancerListener nsg = i.next();
+            if ((queryLoadBalancerListenerID == null ||
+                    queryLoadBalancerListenerID.equals(nsg.getLoadBalancerListenerID())) &&
+                    (queryLoadBalancerListenerDefaultPoolID == null ||
+                            queryLoadBalancerListenerDefaultPoolID.equals(nsg.getNeutronLoadBalancerListenerDefaultPoolID())) &&
+                    (queryLoadBalancerListenerTenantID == null ||
+                            queryLoadBalancerListenerTenantID.equals(nsg.getLoadBalancerListenerTenantID())) &&
+                    (queryLoadBalancerListenerName == null ||
+                            queryLoadBalancerListenerName.equals(nsg.getLoadBalancerListenerName())) &&
+                    (queryLoadBalancerListenerDescription == null ||
+                            queryLoadBalancerListenerDescription.equals(nsg.getLoadBalancerListenerDescription())) &&
+                    (queryLoadBalancerListenerIsShared == null ||
+                            queryLoadBalancerListenerIsShared.equals(nsg.getLoadBalancerListenerIsShared())) &&
+                    (queryLoadBalancerListenerProtocol == null ||
+                            queryLoadBalancerListenerProtocol.equals(nsg.getNeutronLoadBalancerListenerProtocol())) &&
+                    (queryLoadBalancerListenerProtocolPort == null ||
+                            queryLoadBalancerListenerProtocolPort.equals(nsg.getNeutronLoadBalancerListenerProtocolPort())) &&
+                    (queryLoadBalancerListenerLoadBalancerID == null ||
+                            queryLoadBalancerListenerLoadBalancerID.equals(nsg.getNeutronLoadBalancerListenerLoadBalancerID())) &&
+                    (queryLoadBalancerListenerAdminIsUp == null ||
+                            queryLoadBalancerListenerAdminIsUp.equals(nsg.getLoadBalancerListenerAdminStateIsUp())) &&
+                    (queryLoadBalancerListenerStatus == null ||
+                            queryLoadBalancerListenerStatus.equals(nsg.getLoadBalancerListenerStatus()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronLoadBalancerListenerRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific LoadBalancerListener */
+
+    @Path("{loadBalancerListenerID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showLoadBalancerListener(@PathParam("loadBalancerListenerID") String loadBalancerListenerID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!loadBalancerListenerInterface.neutronLoadBalancerListenerExists(loadBalancerListenerID)) {
+            throw new ResourceNotFoundException("LoadBalancerListener UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronLoadBalancerListener ans = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
+            return Response.status(200).entity(
+                    new NeutronLoadBalancerListenerRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronLoadBalancerListenerRequest(loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID))).build();
+        }
+    }
+
+    /**
+     * Creates new LoadBalancerListener */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createLoadBalancerListeners(final NeutronLoadBalancerListenerRequest input) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronLoadBalancerListener singleton = input.getSingleton();
+
+            /*
+             *  Verify that the LoadBalancerListener doesn't already exist.
+             */
+            if (loadBalancerListenerInterface.neutronLoadBalancerListenerExists(singleton.getLoadBalancerListenerID())) {
+                throw new BadRequestException("LoadBalancerListener UUID already exists");
+            }
+            loadBalancerListenerInterface.addNeutronLoadBalancerListener(singleton);
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerListenerAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                    int status = service.canCreateNeutronLoadBalancerListener(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            loadBalancerListenerInterface.addNeutronLoadBalancerListener(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                    service.neutronLoadBalancerListenerCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronLoadBalancerListener> bulk = input.getBulk();
+            Iterator<NeutronLoadBalancerListener> i = bulk.iterator();
+            HashMap<String, NeutronLoadBalancerListener> testMap = new HashMap<String, NeutronLoadBalancerListener>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerListenerAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronLoadBalancerListener test = i.next();
+
+                /*
+                 *  Verify that the firewall policy doesn't already exist
+                 */
+
+                if (loadBalancerListenerInterface.neutronLoadBalancerListenerExists(test.getLoadBalancerListenerID())) {
+                    throw new BadRequestException("LoadBalancerListener UUID already is already created");
+                }
+                if (testMap.containsKey(test.getLoadBalancerListenerID())) {
+                    throw new BadRequestException("LoadBalancerListener UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                        int status = service.canCreateNeutronLoadBalancerListener(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronLoadBalancerListener test = i.next();
+                loadBalancerListenerInterface.addNeutronLoadBalancerListener(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                        service.neutronLoadBalancerListenerCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a LoadBalancerListener Policy
+     */
+    @Path("{loadBalancerListenerID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateLoadBalancerListener(
+            @PathParam("loadBalancerListenerID") String loadBalancerListenerID, final NeutronLoadBalancerListenerRequest input) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerListener exists and there is only one delta provided
+         */
+        if (!loadBalancerListenerInterface.neutronLoadBalancerListenerExists(loadBalancerListenerID)) {
+            throw new ResourceNotFoundException("LoadBalancerListener UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronLoadBalancerListener delta = input.getSingleton();
+        NeutronLoadBalancerListener original = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getLoadBalancerListenerID() != null ||
+                delta.getNeutronLoadBalancerListenerDefaultPoolID() != null ||
+                delta.getLoadBalancerListenerTenantID() != null ||
+                delta.getLoadBalancerListenerName() != null ||
+                delta.getLoadBalancerListenerDescription() != null ||
+                delta.getLoadBalancerListenerIsShared() != null ||
+                delta.getNeutronLoadBalancerListenerProtocol() != null ||
+                delta.getNeutronLoadBalancerListenerProtocolPort() != null ||
+                delta.getNeutronLoadBalancerListenerLoadBalancerID() != null ||
+                delta.getLoadBalancerListenerAdminStateIsUp() != null ||
+                delta.getLoadBalancerListenerStatus() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerListenerAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                int status = service.canUpdateNeutronLoadBalancerListener(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        loadBalancerListenerInterface.updateNeutronLoadBalancerListener(loadBalancerListenerID, delta);
+        NeutronLoadBalancerListener updatedLoadBalancerListener = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                service.neutronLoadBalancerListenerUpdated(updatedLoadBalancerListener);
+            }
+        }
+        return Response.status(200).entity(new NeutronLoadBalancerListenerRequest(loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID))).build();
+    }
+
+    /**
+     * Deletes a LoadBalancerListener */
+
+    @Path("{loadBalancerListenerID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteLoadBalancerListener(
+            @PathParam("loadBalancerListenerID") String loadBalancerListenerID) {
+        INeutronLoadBalancerListenerCRUD loadBalancerListenerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerListenerCRUD(this);
+        if (loadBalancerListenerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerListener CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerListener exists and it isn't currently in use
+         */
+        if (!loadBalancerListenerInterface.neutronLoadBalancerListenerExists(loadBalancerListenerID)) {
+            throw new ResourceNotFoundException("LoadBalancerListener UUID does not exist.");
+        }
+        if (loadBalancerListenerInterface.neutronLoadBalancerListenerInUse(loadBalancerListenerID)) {
+            return Response.status(409).build();
+        }
+        NeutronLoadBalancerListener singleton = loadBalancerListenerInterface.getNeutronLoadBalancerListener(loadBalancerListenerID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerListenerAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                int status = service.canDeleteNeutronLoadBalancerListener(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        loadBalancerListenerInterface.removeNeutronLoadBalancerListener(loadBalancerListenerID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerListenerAware service = (INeutronLoadBalancerListenerAware) instance;
+                service.neutronLoadBalancerListenerDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerListenerRequest.java
new file mode 100644 (file)
index 0000000..ba375af
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerListener;
+
+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 NeutronLoadBalancerListenerRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="listener")
+    NeutronLoadBalancerListener singletonLoadBalancerListener;
+
+    @XmlElement(name="listeners")
+    List<NeutronLoadBalancerListener> bulkRequest;
+
+    NeutronLoadBalancerListenerRequest() {
+    }
+
+    NeutronLoadBalancerListenerRequest(List<NeutronLoadBalancerListener> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerListener = null;
+    }
+
+    NeutronLoadBalancerListenerRequest(NeutronLoadBalancerListener group) {
+        singletonLoadBalancerListener = group;
+    }
+
+    public List<NeutronLoadBalancerListener> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerListener getSingleton() {
+        return singletonLoadBalancerListener;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerListener != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerNorthbound.java
new file mode 100644 (file)
index 0000000..863b3cb
--- /dev/null
@@ -0,0 +1,380 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for LoadBalancers.<br>
+ * This class provides REST APIs for managing neutron LoadBalancers
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+@Path("/loadbalancers")
+public class NeutronLoadBalancerNorthbound {
+
+    private NeutronLoadBalancer extractFields(NeutronLoadBalancer o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all LoadBalancer */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack LoadBalancer attributes
+            @QueryParam("id") String queryLoadBalancerID,
+            @QueryParam("tenant_id") String queryLoadBalancerTenantID,
+            @QueryParam("name") String queryLoadBalancerName,
+            @QueryParam("description") String queryLoadBalancerDescription,
+            @QueryParam("status") String queryLoadBalancerStatus,
+            @QueryParam("vip_address") String queryLoadBalancerVipAddress,
+            @QueryParam("vip_subnet") String queryLoadBalancerVipSubnet,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronLoadBalancerCRUD loadBalancerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(this);
+
+        if (loadBalancerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronLoadBalancer> allLoadBalancers = loadBalancerInterface.getAllNeutronLoadBalancers();
+        //        List<NeutronLoadBalancerRule> allLoadBalancerRules = firewallRuleInterface.getAllNeutronLoadBalancerRules();
+        List<NeutronLoadBalancer> ans = new ArrayList<NeutronLoadBalancer>();
+        //        List<NeutronLoadBalancerRule> rules = new ArrayList<NeutronLoadBalancerRule>();
+        Iterator<NeutronLoadBalancer> i = allLoadBalancers.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancer nsg = i.next();
+            if ((queryLoadBalancerID == null ||
+                    queryLoadBalancerID.equals(nsg.getLoadBalancerID())) &&
+                    (queryLoadBalancerTenantID == null ||
+                            queryLoadBalancerTenantID.equals(nsg.getLoadBalancerTenantID())) &&
+                    (queryLoadBalancerName == null ||
+                            queryLoadBalancerName.equals(nsg.getLoadBalancerName())) &&
+                    (queryLoadBalancerDescription == null ||
+                            queryLoadBalancerDescription.equals(nsg.getLoadBalancerDescription())) &&
+                    (queryLoadBalancerVipAddress == null ||
+                            queryLoadBalancerVipAddress.equals(nsg.getLoadBalancerVipAddress())) &&
+                    (queryLoadBalancerVipSubnet == null ||
+                            queryLoadBalancerVipSubnet.equals(nsg.getLoadBalancerVipSubnetID()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronLoadBalancerRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific LoadBalancer */
+
+    @Path("{loadBalancerID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showLoadBalancer(@PathParam("loadBalancerID") String loadBalancerID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronLoadBalancerCRUD loadBalancerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        if (loadBalancerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!loadBalancerInterface.neutronLoadBalancerExists(loadBalancerID)) {
+            throw new ResourceNotFoundException("LoadBalancer UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronLoadBalancer ans = loadBalancerInterface.getNeutronLoadBalancer(loadBalancerID);
+            return Response.status(200).entity(
+                    new NeutronLoadBalancerRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronLoadBalancerRequest(loadBalancerInterface.getNeutronLoadBalancer(
+                    loadBalancerID))).build();
+        }
+    }
+
+    /**
+     * Creates new LoadBalancer */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createLoadBalancers(final NeutronLoadBalancerRequest input) {
+        INeutronLoadBalancerCRUD loadBalancerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        if (loadBalancerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronLoadBalancer singleton = input.getSingleton();
+
+            /*
+             *  Verify that the LoadBalancer doesn't already exist.
+             */
+            if (loadBalancerInterface.neutronLoadBalancerExists(singleton.getLoadBalancerID())) {
+                throw new BadRequestException("LoadBalancer UUID already exists");
+            }
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                    int status = service.canCreateNeutronLoadBalancer(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            loadBalancerInterface.addNeutronLoadBalancer(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                    service.neutronLoadBalancerCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronLoadBalancer> bulk = input.getBulk();
+            Iterator<NeutronLoadBalancer> i = bulk.iterator();
+            HashMap<String, NeutronLoadBalancer> testMap = new HashMap<String, NeutronLoadBalancer>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronLoadBalancer test = i.next();
+
+                /*
+                 *  Verify that the loadbalancer doesn't already exist
+                 */
+
+                if (loadBalancerInterface.neutronLoadBalancerExists(test.getLoadBalancerID())) {
+                    throw new BadRequestException("Load Balancer Pool UUID already is already created");
+                }
+                if (testMap.containsKey(test.getLoadBalancerID())) {
+                    throw new BadRequestException("Load Balancer Pool UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                        int status = service.canCreateNeutronLoadBalancer(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronLoadBalancer test = i.next();
+                loadBalancerInterface.addNeutronLoadBalancer(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                        service.neutronLoadBalancerCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a LoadBalancer Policy
+     */
+    @Path("{loadBalancerID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateLoadBalancer(
+            @PathParam("loadBalancerID") String loadBalancerID, final NeutronLoadBalancerRequest input) {
+        INeutronLoadBalancerCRUD loadBalancerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        if (loadBalancerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancer exists and there is only one delta provided
+         */
+        if (!loadBalancerInterface.neutronLoadBalancerExists(loadBalancerID)) {
+            throw new ResourceNotFoundException("LoadBalancer UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronLoadBalancer delta = input.getSingleton();
+        NeutronLoadBalancer original = loadBalancerInterface.getNeutronLoadBalancer(loadBalancerID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getLoadBalancerID() != null ||
+                delta.getLoadBalancerTenantID() != null ||
+                delta.getLoadBalancerName() != null ||
+                delta.getLoadBalancerDescription() != null ||
+                delta.getLoadBalancerStatus() != null ||
+                delta.getLoadBalancerVipAddress() != null ||
+                delta.getLoadBalancerVipSubnetID() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                int status = service.canUpdateNeutronLoadBalancer(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        loadBalancerInterface.updateNeutronLoadBalancer(loadBalancerID, delta);
+        NeutronLoadBalancer updatedLoadBalancer = loadBalancerInterface.getNeutronLoadBalancer(
+                loadBalancerID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                service.neutronLoadBalancerUpdated(updatedLoadBalancer);
+            }
+        }
+        return Response.status(200).entity(new NeutronLoadBalancerRequest(loadBalancerInterface.getNeutronLoadBalancer(
+                loadBalancerID))).build();
+    }
+
+    /**
+     * Deletes a LoadBalancer */
+
+    @Path("{loadBalancerID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteLoadBalancer(
+            @PathParam("loadBalancerID") String loadBalancerID) {
+        INeutronLoadBalancerCRUD loadBalancerInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerCRUD(
+                this);
+        if (loadBalancerInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancer CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancer exists and it isn't currently in use
+         */
+        if (!loadBalancerInterface.neutronLoadBalancerExists(loadBalancerID)) {
+            throw new ResourceNotFoundException("LoadBalancer UUID does not exist.");
+        }
+        if (loadBalancerInterface.neutronLoadBalancerInUse(loadBalancerID)) {
+            return Response.status(409).build();
+        }
+        NeutronLoadBalancer singleton = loadBalancerInterface.getNeutronLoadBalancer(loadBalancerID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                int status = service.canDeleteNeutronLoadBalancer(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        loadBalancerInterface.removeNeutronLoadBalancer(loadBalancerID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerAware service = (INeutronLoadBalancerAware) instance;
+                service.neutronLoadBalancerDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMemberRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMemberRequest.java
new file mode 100644 (file)
index 0000000..9b949da
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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
+ */
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
+
+import javax.xml.bind.annotation.XmlElement;
+import java.util.List;
+
+public class NeutronLoadBalancerPoolMemberRequest {
+
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="member")
+    NeutronLoadBalancerPoolMember singletonLoadBalancerPoolMember;
+
+    @XmlElement(name="members")
+    List<NeutronLoadBalancerPoolMember> bulkRequest;
+
+    NeutronLoadBalancerPoolMemberRequest() {
+    }
+
+    NeutronLoadBalancerPoolMemberRequest(List<NeutronLoadBalancerPoolMember> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerPoolMember = null;
+    }
+
+    NeutronLoadBalancerPoolMemberRequest(NeutronLoadBalancerPoolMember group) {
+        singletonLoadBalancerPoolMember = group;
+    }
+
+    public List<NeutronLoadBalancerPoolMember> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerPoolMember getSingleton() {
+        return singletonLoadBalancerPoolMember;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerPoolMember != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMembersNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolMembersNorthbound.java
new file mode 100644 (file)
index 0000000..f8f3cd8
--- /dev/null
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2014 SDN Hub, LLC.
+ *
+ * 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 : Srini Seetharaman
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolMemberAware;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.PUT;
+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.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+@Path("/pools/{loadBalancerPoolUUID}/members")
+public class NeutronLoadBalancerPoolMembersNorthbound {
+    private NeutronLoadBalancerPoolMember extractFields(NeutronLoadBalancerPoolMember o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+/**
+ * Returns a list of all LoadBalancerPoolMembers in specified pool
+ */
+@GET
+@Produces({MediaType.APPLICATION_JSON})
+@StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 501, condition = "Not Implemented")})
+
+public Response listMembers(
+        //Path param
+        @PathParam("loadBalancerPoolUUID") String loadBalancerPoolUUID,
+
+        // return fields
+        @QueryParam("fields") List<String> fields,
+
+        // OpenStack LoadBalancerPool attributes
+        @QueryParam("id") String queryLoadBalancerPoolMemberID,
+        @QueryParam("tenant_id") String queryLoadBalancerPoolMemberTenantID,
+        @QueryParam("address") String queryLoadBalancerPoolMemberAddress,
+        @QueryParam("protocol_port") String queryLoadBalancerPoolMemberProtoPort,
+        @QueryParam("admin_state_up") String queryLoadBalancerPoolMemberAdminStateUp,
+        @QueryParam("weight") String queryLoadBalancerPoolMemberWeight,
+        @QueryParam("subnet_id") String queryLoadBalancerPoolMemberSubnetID,
+        @QueryParam("status") String queryLoadBalancerPoolMemberStatus,
+
+        // pagination
+        @QueryParam("limit") String limit,
+        @QueryParam("marker") String marker,
+        @QueryParam("page_reverse") String pageReverse
+        // sorting not supported
+) {
+    INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces
+            .getINeutronLoadBalancerPoolCRUD(this);
+    if (loadBalancerPoolInterface == null) {
+        throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                + RestMessages.SERVICEUNAVAILABLE.toString());
+    }
+    if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolUUID)) {
+        throw new ResourceNotFoundException("loadBalancerPool UUID does not exist.");
+    }
+    List<NeutronLoadBalancerPoolMember> members =
+                loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolUUID).getLoadBalancerPoolMembers();
+    List<NeutronLoadBalancerPoolMember> ans = new ArrayList<NeutronLoadBalancerPoolMember>();
+    Iterator<NeutronLoadBalancerPoolMember> i = members.iterator();
+    while (i.hasNext()) {
+        NeutronLoadBalancerPoolMember nsg = i.next();
+        if ((queryLoadBalancerPoolMemberID == null ||
+                queryLoadBalancerPoolMemberID.equals(nsg.getPoolMemberID())) &&
+                loadBalancerPoolUUID.equals(nsg.getPoolID()) &&
+                (queryLoadBalancerPoolMemberTenantID == null ||
+                        queryLoadBalancerPoolMemberTenantID.equals(nsg.getPoolMemberTenantID())) &&
+                (queryLoadBalancerPoolMemberAddress == null ||
+                        queryLoadBalancerPoolMemberAddress.equals(nsg.getPoolMemberAddress())) &&
+                (queryLoadBalancerPoolMemberAdminStateUp == null ||
+                        queryLoadBalancerPoolMemberAdminStateUp.equals(nsg.getPoolMemberAdminStateIsUp())) &&
+                (queryLoadBalancerPoolMemberWeight == null ||
+                        queryLoadBalancerPoolMemberWeight.equals(nsg.getPoolMemberWeight())) &&
+                (queryLoadBalancerPoolMemberSubnetID == null ||
+                        queryLoadBalancerPoolMemberSubnetID.equals(nsg.getPoolMemberSubnetID())) &&
+                (queryLoadBalancerPoolMemberStatus == null ||
+                        queryLoadBalancerPoolMemberStatus.equals(nsg.getPoolMemberStatus()))) {
+            if (fields.size() > 0) {
+                ans.add(extractFields(nsg, fields));
+            } else {
+                ans.add(nsg);
+            }
+        }
+    }
+    return Response.status(200).entity(
+            new NeutronLoadBalancerPoolMemberRequest(ans)).build();
+}
+
+/**
+ * Returns a specific LoadBalancerPoolMember
+ */
+
+@Path("{loadBalancerPoolMemberUUID}")
+@GET
+@Produces({ MediaType.APPLICATION_JSON })
+//@TypeHint(OpenStackLoadBalancerPoolMembers.class)
+@StatusCodes({
+    @ResponseCode(code = 200, condition = "Operation successful"),
+    @ResponseCode(code = 401, condition = "Unauthorized"),
+    @ResponseCode(code = 404, condition = "Not Found"),
+    @ResponseCode(code = 501, condition = "Not Implemented") })
+public Response showLoadBalancerPoolMember(
+        @PathParam("loadBalancerPoolUUID") String loadBalancerPoolUUID,
+        @PathParam("loadBalancerPoolMemberUUID") String loadBalancerPoolMemberUUID,
+        // return fields
+        @QueryParam("fields") List<String> fields ) {
+
+    INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces
+            .getINeutronLoadBalancerPoolCRUD(this);
+    if (loadBalancerPoolInterface == null) {
+        throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                + RestMessages.SERVICEUNAVAILABLE.toString());
+    }
+    if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolUUID)) {
+        throw new ResourceNotFoundException("loadBalancerPool UUID does not exist.");
+    }
+    List<NeutronLoadBalancerPoolMember> members =
+                loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolUUID).getLoadBalancerPoolMembers();
+    for (NeutronLoadBalancerPoolMember ans: members) {
+        if (!ans.getPoolMemberID().equals(loadBalancerPoolMemberUUID))
+            continue;
+
+        if (fields.size() > 0) {
+            return Response.status(200).entity(
+                new NeutronLoadBalancerPoolMemberRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(
+                new NeutronLoadBalancerPoolMemberRequest(ans)).build();
+        }
+    }
+    return Response.status(204).build();
+}
+
+/**
+ * Adds a Member to an LBaaS Pool member
+ */
+@PUT
+@Produces({MediaType.APPLICATION_JSON})
+@Consumes({MediaType.APPLICATION_JSON})
+@StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 404, condition = "Not Found"),
+        @ResponseCode(code = 501, condition = "Not Implemented")})
+public Response createLoadBalancerPoolMember(
+        @PathParam("loadBalancerPoolUUID") String loadBalancerPoolUUID,
+        final NeutronLoadBalancerPoolMemberRequest input) {
+
+    INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+    if (loadBalancerPoolInterface == null) {
+        throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                + RestMessages.SERVICEUNAVAILABLE.toString());
+    }
+    // Verify that the loadBalancerPool exists, for the member to be added to its cache
+    if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolUUID)) {
+        throw new ResourceNotFoundException("loadBalancerPool UUID does not exist.");
+    }
+    NeutronLoadBalancerPool singletonPool = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolUUID);
+
+    if (input.isSingleton()) {
+        NeutronLoadBalancerPoolMember singleton = input.getSingleton();
+        singleton.setPoolID(loadBalancerPoolUUID);
+        String loadBalancerPoolMemberUUID = singleton.getPoolMemberID();
+
+        /*
+         *  Verify that the LoadBalancerPoolMember doesn't already exist.
+         */
+        List<NeutronLoadBalancerPoolMember> members = singletonPool.getLoadBalancerPoolMembers();
+        for (NeutronLoadBalancerPoolMember member: members) {
+            if (member.getPoolMemberID().equals(loadBalancerPoolMemberUUID))
+                throw new BadRequestException("LoadBalancerPoolMember UUID already exists");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolMemberAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                int status = service.canCreateNeutronLoadBalancerPoolMember(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                service.neutronLoadBalancerPoolMemberCreated(singleton);
+            }
+        }
+
+        /**
+         * Add the member from the neutron load balancer pool as well
+         */
+        singletonPool.addLoadBalancerPoolMember(singleton);
+
+    } else {
+        List<NeutronLoadBalancerPoolMember> bulk = input.getBulk();
+        Iterator<NeutronLoadBalancerPoolMember> i = bulk.iterator();
+        HashMap<String, NeutronLoadBalancerPoolMember> testMap = new HashMap<String, NeutronLoadBalancerPoolMember>();
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolMemberAware.class, this, null);
+        while (i.hasNext()) {
+            NeutronLoadBalancerPoolMember test = i.next();
+            String loadBalancerPoolMemberUUID = test.getPoolMemberID();
+
+            /*
+             *  Verify that the LoadBalancerPoolMember doesn't already exist.
+             */
+            List<NeutronLoadBalancerPoolMember> members = singletonPool.getLoadBalancerPoolMembers();
+            for (NeutronLoadBalancerPoolMember member: members) {
+                if (member.getPoolMemberID().equals(loadBalancerPoolMemberUUID))
+                    throw new BadRequestException("LoadBalancerPoolMember UUID already exists");
+            }
+
+            if (testMap.containsKey(test.getPoolMemberID())) {
+                throw new BadRequestException("Load Balancer PoolMember UUID already exists");
+            }
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                    int status = service.canCreateNeutronLoadBalancerPoolMember(test);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+        }
+        /*
+         * now, each element of the bulk request can be added to the cache
+         */
+        i = bulk.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancerPoolMember test = i.next();
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+                    service.neutronLoadBalancerPoolMemberCreated(test);
+                }
+            }
+            singletonPool.addLoadBalancerPoolMember(test);
+        }
+    }
+    return Response.status(201).entity(input).build();
+}
+
+/**
+ * Updates a LB member pool
+ */
+
+@Path("{loadBalancerPoolMemberUUID}")
+@PUT
+@Produces({ MediaType.APPLICATION_JSON })
+@Consumes({ MediaType.APPLICATION_JSON })
+@StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 400, condition = "Bad Request"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 403, condition = "Forbidden"),
+        @ResponseCode(code = 404, condition = "Not Found"),
+        @ResponseCode(code = 501, condition = "Not Implemented") })
+public Response updateLoadBalancerPoolMember(
+        @PathParam("loadBalancerPoolUUID") String loadBalancerPoolUUID,
+        @PathParam("loadBalancerPoolMemberUUID") String loadBalancerPoolMemberUUID,
+        final NeutronLoadBalancerPoolMemberRequest input) {
+
+    //TODO: Implement update LB member pool
+    return Response.status(501).entity(input).build();
+}
+
+/**
+ * Deletes a LoadBalancerPoolMember
+ */
+
+@Path("{loadBalancerPoolMemberUUID}")
+@DELETE
+@StatusCodes({
+    @ResponseCode(code = 204, condition = "No Content"),
+    @ResponseCode(code = 401, condition = "Unauthorized"),
+    @ResponseCode(code = 403, condition = "Forbidden"),
+    @ResponseCode(code = 404, condition = "Not Found"),
+    @ResponseCode(code = 501, condition = "Not Implemented") })
+public Response deleteLoadBalancerPoolMember(
+        @PathParam("loadBalancerPoolUUID") String loadBalancerPoolUUID,
+        @PathParam("loadBalancerPoolMemberUUID") String loadBalancerPoolMemberUUID) {
+    INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+    if (loadBalancerPoolInterface == null) {
+        throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                + RestMessages.SERVICEUNAVAILABLE.toString());
+    }
+
+    // Verify that the loadBalancerPool exists, for the member to be removed from its cache
+    if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolUUID)) {
+        throw new ResourceNotFoundException("loadBalancerPool UUID does not exist.");
+    }
+
+    //Verify that the LB pool member exists
+    NeutronLoadBalancerPoolMember singleton = null;
+    List<NeutronLoadBalancerPoolMember> members =
+            loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolUUID).getLoadBalancerPoolMembers();
+    for (NeutronLoadBalancerPoolMember member: members) {
+        if (member.getPoolMemberID().equals(loadBalancerPoolMemberUUID)) {
+            singleton = member;
+            break;
+        }
+    }
+    if (singleton == null)
+        throw new BadRequestException("LoadBalancerPoolMember UUID does not exist.");
+
+    Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolMemberAware.class, this, null);
+    if (instances != null) {
+        for (Object instance : instances) {
+            INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+            int status = service.canDeleteNeutronLoadBalancerPoolMember(singleton);
+            if (status < 200 || status > 299) {
+                return Response.status(status).build();
+            }
+        }
+    }
+
+    if (instances != null) {
+        for (Object instance : instances) {
+            INeutronLoadBalancerPoolMemberAware service = (INeutronLoadBalancerPoolMemberAware) instance;
+            service.neutronLoadBalancerPoolMemberDeleted(singleton);
+        }
+    }
+
+    /**
+     * Remove the member from the neutron load balancer pool
+     */
+    NeutronLoadBalancerPool singletonPool = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolUUID);
+    singletonPool.removeLoadBalancerPoolMember(singleton);
+
+    return Response.status(204).build();
+}
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolNorthbound.java
new file mode 100644 (file)
index 0000000..5235030
--- /dev/null
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2014 SDN Hub, LLC.
+ *
+ * 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 : Srini Seetharaman
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronLoadBalancerPoolCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPoolMember;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * Neutron Northbound REST APIs for LoadBalancerPool Policies.<br>
+ * This class provides REST APIs for managing neutron LoadBalancerPool Policies
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+
+/**
+ * For now, the LB pool member data is maintained with the INeutronLoadBalancerPoolCRUD,
+ * and not duplicated within the INeutronLoadBalancerPoolMemberCRUD's cache.
+ */
+
+@Path("/pools")
+public class NeutronLoadBalancerPoolNorthbound {
+
+    private NeutronLoadBalancerPool extractFields(NeutronLoadBalancerPool o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all LoadBalancerPool
+     * */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+
+    public Response listGroups(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // OpenStack LoadBalancerPool attributes
+            @QueryParam("id") String queryLoadBalancerPoolID,
+            @QueryParam("tenant_id") String queryLoadBalancerPoolTenantID,
+            @QueryParam("name") String queryLoadBalancerPoolName,
+            @QueryParam("description") String queryLoadBalancerDescription,
+            @QueryParam("protocol") String queryLoadBalancerProtocol,
+            @QueryParam("lb_algorithm") String queryLoadBalancerPoolLbAlgorithm,
+            @QueryParam("healthmonitor_id") String queryLoadBalancerPoolHealthMonitorID,
+            @QueryParam("admin_state_up") String queryLoadBalancerIsAdminStateUp,
+            @QueryParam("status") String queryLoadBalancerPoolStatus,
+            @QueryParam("members") List<NeutronLoadBalancerPoolMember> queryLoadBalancerPoolMembers,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+    ) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronLoadBalancerPool> allLoadBalancerPools = loadBalancerPoolInterface.getAllNeutronLoadBalancerPools();
+        List<NeutronLoadBalancerPool> ans = new ArrayList<NeutronLoadBalancerPool>();
+        Iterator<NeutronLoadBalancerPool> i = allLoadBalancerPools.iterator();
+        while (i.hasNext()) {
+            NeutronLoadBalancerPool nsg = i.next();
+            if ((queryLoadBalancerPoolID == null ||
+                    queryLoadBalancerPoolID.equals(nsg.getLoadBalancerPoolID())) &&
+                    (queryLoadBalancerPoolTenantID == null ||
+                            queryLoadBalancerPoolTenantID.equals(nsg.getLoadBalancerPoolTenantID())) &&
+                    (queryLoadBalancerPoolName == null ||
+                            queryLoadBalancerPoolName.equals(nsg.getLoadBalancerPoolName())) &&
+                    (queryLoadBalancerDescription == null ||
+                            queryLoadBalancerDescription.equals(nsg.getLoadBalancerPoolDescription())) &&
+                    (queryLoadBalancerPoolLbAlgorithm == null ||
+                            queryLoadBalancerPoolLbAlgorithm.equals(nsg.getLoadBalancerPoolLbAlgorithm())) &&
+                    (queryLoadBalancerPoolHealthMonitorID == null ||
+                            queryLoadBalancerPoolHealthMonitorID.equals(nsg.getNeutronLoadBalancerPoolHealthMonitorID())) &&
+                    (queryLoadBalancerIsAdminStateUp == null ||
+                            queryLoadBalancerIsAdminStateUp.equals(nsg.getLoadBalancerPoolAdminIsStateIsUp())) &&
+                    (queryLoadBalancerPoolStatus == null ||
+                            queryLoadBalancerPoolStatus.equals(nsg.getLoadBalancerPoolStatus())) &&
+                    (queryLoadBalancerPoolMembers.size() == 0 ||
+                            queryLoadBalancerPoolMembers.equals(nsg.getLoadBalancerPoolMembers()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg,fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronLoadBalancerPoolRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific LoadBalancerPool */
+
+    @Path("{loadBalancerPoolID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showLoadBalancerPool(@PathParam("loadBalancerPoolID") String loadBalancerPoolID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolID)) {
+            throw new ResourceNotFoundException("LoadBalancerPool UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronLoadBalancerPool ans = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID);
+            return Response.status(200).entity(
+                    new NeutronLoadBalancerPoolRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronLoadBalancerPoolRequest(loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID))).build();
+        }
+    }
+
+    /**
+     * Creates new LoadBalancerPool */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createLoadBalancerPools(final NeutronLoadBalancerPoolRequest input) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronLoadBalancerPool singleton = input.getSingleton();
+
+            /*
+             *  Verify that the LoadBalancerPool doesn't already exist.
+             */
+            if (loadBalancerPoolInterface.neutronLoadBalancerPoolExists(singleton.getLoadBalancerPoolID())) {
+                throw new BadRequestException("LoadBalancerPool UUID already exists");
+            }
+            loadBalancerPoolInterface.addNeutronLoadBalancerPool(singleton);
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                    int status = service.canCreateNeutronLoadBalancerPool(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            loadBalancerPoolInterface.addNeutronLoadBalancerPool(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                    service.neutronLoadBalancerPoolCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronLoadBalancerPool> bulk = input.getBulk();
+            Iterator<NeutronLoadBalancerPool> i = bulk.iterator();
+            HashMap<String, NeutronLoadBalancerPool> testMap = new HashMap<String, NeutronLoadBalancerPool>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronLoadBalancerPool test = i.next();
+
+                /*
+                 *  Verify that the loadBalancerPool doesn't already exist
+                 */
+
+                if (loadBalancerPoolInterface.neutronLoadBalancerPoolExists(test.getLoadBalancerPoolID())) {
+                    throw new BadRequestException("Load Balancer Pool UUID already is already created");
+                }
+                if (testMap.containsKey(test.getLoadBalancerPoolID())) {
+                    throw new BadRequestException("Load Balancer Pool UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                        int status = service.canCreateNeutronLoadBalancerPool(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronLoadBalancerPool test = i.next();
+                loadBalancerPoolInterface.addNeutronLoadBalancerPool(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                        service.neutronLoadBalancerPoolCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a LoadBalancerPool Policy
+     */
+    @Path("{loadBalancerPoolID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateLoadBalancerPool(
+            @PathParam("loadBalancerPoolID") String loadBalancerPoolID, final NeutronLoadBalancerPoolRequest input) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerPool exists and there is only one delta provided
+         */
+        if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolID)) {
+            throw new ResourceNotFoundException("LoadBalancerPool UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronLoadBalancerPool delta = input.getSingleton();
+        NeutronLoadBalancerPool original = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getLoadBalancerPoolID() != null ||
+                delta.getLoadBalancerPoolTenantID() != null ||
+                delta.getLoadBalancerPoolName() != null ||
+                delta.getLoadBalancerPoolDescription() != null ||
+                delta.getLoadBalancerPoolProtocol() != null ||
+                delta.getLoadBalancerPoolLbAlgorithm() != null ||
+                delta.getNeutronLoadBalancerPoolHealthMonitorID() != null ||
+                delta.getLoadBalancerPoolAdminIsStateIsUp() != null ||
+                delta.getLoadBalancerPoolStatus() != null ||
+                delta.getLoadBalancerPoolMembers() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                int status = service.canUpdateNeutronLoadBalancerPool(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        loadBalancerPoolInterface.updateNeutronLoadBalancerPool(loadBalancerPoolID, delta);
+        NeutronLoadBalancerPool updatedLoadBalancerPool = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                service.neutronLoadBalancerPoolUpdated(updatedLoadBalancerPool);
+            }
+        }
+        return Response.status(200).entity(new NeutronLoadBalancerPoolRequest(loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolID))).build();
+    }
+
+    /**
+     * Deletes a LoadBalancerPool
+     */
+
+    @Path("{loadBalancerPoolUUID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteLoadBalancerPool(
+            @PathParam("loadBalancerPoolUUID") String loadBalancerPoolUUID) {
+        INeutronLoadBalancerPoolCRUD loadBalancerPoolInterface = NeutronCRUDInterfaces.getINeutronLoadBalancerPoolCRUD(this);
+        if (loadBalancerPoolInterface == null) {
+            throw new ServiceUnavailableException("LoadBalancerPool CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the LoadBalancerPool exists and it isn't currently in use
+         */
+        if (!loadBalancerPoolInterface.neutronLoadBalancerPoolExists(loadBalancerPoolUUID)) {
+            throw new ResourceNotFoundException("LoadBalancerPool UUID does not exist.");
+        }
+        if (loadBalancerPoolInterface.neutronLoadBalancerPoolInUse(loadBalancerPoolUUID)) {
+            return Response.status(409).build();
+        }
+        NeutronLoadBalancerPool singleton = loadBalancerPoolInterface.getNeutronLoadBalancerPool(loadBalancerPoolUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronLoadBalancerPoolAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                int status = service.canDeleteNeutronLoadBalancerPool(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * remove it and return 204 status
+         */
+        loadBalancerPoolInterface.removeNeutronLoadBalancerPool(loadBalancerPoolUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronLoadBalancerPoolAware service = (INeutronLoadBalancerPoolAware) instance;
+                service.neutronLoadBalancerPoolDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerPoolRequest.java
new file mode 100644 (file)
index 0000000..a1cdc41
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancerPool;
+
+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 NeutronLoadBalancerPoolRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="pool")
+    NeutronLoadBalancerPool singletonLoadBalancerPool;
+
+    @XmlElement(name="pools")
+    List<NeutronLoadBalancerPool> bulkRequest;
+
+    NeutronLoadBalancerPoolRequest() {
+    }
+
+    NeutronLoadBalancerPoolRequest(List<NeutronLoadBalancerPool> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancerPool = null;
+    }
+
+    NeutronLoadBalancerPoolRequest(NeutronLoadBalancerPool group) {
+        singletonLoadBalancerPool = group;
+    }
+
+    public List<NeutronLoadBalancerPool> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancerPool getSingleton() {
+        return singletonLoadBalancerPool;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancerPool != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronLoadBalancerRequest.java
new file mode 100644 (file)
index 0000000..1cf4e70
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * 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
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronLoadBalancer;
+
+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 NeutronLoadBalancerRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for description of
+     * http://docs.openstack.org/api/openstack-network/2.0/content/
+     */
+
+    @XmlElement(name="loadbalancer")
+    NeutronLoadBalancer singletonLoadBalancer;
+
+    @XmlElement(name="loadbalancers")
+    List<NeutronLoadBalancer> bulkRequest;
+
+    NeutronLoadBalancerRequest() {
+    }
+
+    NeutronLoadBalancerRequest(List<NeutronLoadBalancer> bulk) {
+        bulkRequest = bulk;
+        singletonLoadBalancer = null;
+    }
+
+    NeutronLoadBalancerRequest(NeutronLoadBalancer group) {
+        singletonLoadBalancer = group;
+    }
+
+    public List<NeutronLoadBalancer> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronLoadBalancer getSingleton() {
+        return singletonLoadBalancer;
+    }
+
+    public boolean isSingleton() {
+        return (singletonLoadBalancer != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworkRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworkRequest.java
new file mode 100644 (file)
index 0000000..2001fb7
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+import java.util.List;
+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 org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronNetworkRequest implements INeutronRequest<NeutronNetwork> {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name="network")
+    NeutronNetwork singletonNetwork;
+
+    @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;
+    }
+
+    NeutronNetworkRequest(NeutronNetwork net) {
+        singletonNetwork = net;
+    }
+
+    @Override
+    public NeutronNetwork getSingleton() {
+        return singletonNetwork;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return (singletonNetwork != null);
+    }
+
+    @Override
+    public List<NeutronNetwork> getBulk() {
+        return bulkRequest;
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNetworksNorthbound.java
new file mode 100644 (file)
index 0000000..9de5aef
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+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;
+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.UriInfo;
+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;
+import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+/**
+ * Neutron Northbound REST APIs for Network.<br>
+ * This class provides REST APIs for managing neutron Networks
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+
+@Path("/networks")
+public class NeutronNetworksNorthbound {
+
+    @Context
+    UriInfo uriInfo;
+
+    private NeutronNetwork extractFields(NeutronNetwork o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all Networks */
+
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackNetworks.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 401, condition = "Unauthorized")})
+    public Response listNetworks(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // note: openstack isn't clear about filtering on lists, so we aren't handling them
+            @QueryParam("id") String queryID,
+            @QueryParam("name") String queryName,
+            @QueryParam("admin_state_up") String queryAdminStateUp,
+            @QueryParam("status") String queryStatus,
+            @QueryParam("shared") String queryShared,
+            @QueryParam("tenant_id") String queryTenantID,
+            @QueryParam("router_external") String queryRouterExternal,
+            @QueryParam("provider_network_type") String queryProviderNetworkType,
+            @QueryParam("provider_physical_network") String queryProviderPhysicalNetwork,
+            @QueryParam("provider_segmentation_id") String queryProviderSegmentationID,
+            // linkTitle
+            @QueryParam("limit") Integer limit,
+            @QueryParam("marker") String marker,
+            @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
+            // sorting not supported
+            ) {
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD(this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronNetwork> allNetworks = networkInterface.getAllNetworks();
+        List<NeutronNetwork> ans = new ArrayList<NeutronNetwork>();
+        Iterator<NeutronNetwork> i = allNetworks.iterator();
+        while (i.hasNext()) {
+            NeutronNetwork oSN = i.next();
+            //match filters: TODO provider extension
+            Boolean bAdminStateUp = null;
+            Boolean bShared = null;
+            Boolean bRouterExternal = null;
+            if (queryAdminStateUp != null) {
+                bAdminStateUp = Boolean.valueOf(queryAdminStateUp);
+            }
+            if (queryShared != null) {
+                bShared = Boolean.valueOf(queryShared);
+            }
+            if (queryRouterExternal != null) {
+                bRouterExternal = Boolean.valueOf(queryRouterExternal);
+            }
+            if ((queryID == null || queryID.equals(oSN.getID())) &&
+                    (queryName == null || queryName.equals(oSN.getNetworkName())) &&
+                    (bAdminStateUp == null || bAdminStateUp.booleanValue() == oSN.isAdminStateUp()) &&
+                    (queryStatus == null || queryStatus.equals(oSN.getStatus())) &&
+                    (bShared == null || bShared.booleanValue() == oSN.isShared()) &&
+                    (bRouterExternal == null || bRouterExternal.booleanValue() == oSN.isRouterExternal()) &&
+                    (queryTenantID == null || queryTenantID.equals(oSN.getTenantID()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(oSN,fields));
+                } else {
+                    ans.add(oSN);
+                }
+            }
+        }
+
+        if (limit != null && ans.size() > 1) {
+            // 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();
+
+    }
+
+    /**
+     * Returns a specific Network */
+
+    @Path("{netUUID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackNetworks.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 404, condition = "Not Found") })
+    public Response showNetwork(
+            @PathParam("netUUID") String netUUID,
+            // return fields
+            @QueryParam("fields") List<String> fields
+            ) {
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!networkInterface.networkExists(netUUID)) {
+            throw new ResourceNotFoundException("network UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronNetwork ans = networkInterface.getNetwork(netUUID);
+            return Response.status(200).entity(
+                    new NeutronNetworkRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(
+                    new NeutronNetworkRequest(networkInterface.getNetwork(netUUID))).build();
+        }
+    }
+
+    /**
+     * Creates new Networks */
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    @TypeHint(NeutronNetwork.class)
+    @StatusCodes({
+        @ResponseCode(code = 201, condition = "Created"),
+        @ResponseCode(code = 400, condition = "Bad Request"),
+        @ResponseCode(code = 401, condition = "Unauthorized") })
+    public Response createNetworks(final NeutronNetworkRequest input) {
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronNetwork singleton = input.getSingleton();
+
+            /*
+             * network ID can't already exist
+             */
+            if (networkInterface.networkExists(singleton.getID())) {
+                throw new BadRequestException("network UUID already exists");
+            }
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                    int status = service.canCreateNetwork(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+
+            // add network to cache
+            singleton.initDefaults();
+            networkInterface.addNetwork(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                    service.neutronNetworkCreated(singleton);
+                }
+            }
+
+        } else {
+            List<NeutronNetwork> bulk = input.getBulk();
+            Iterator<NeutronNetwork> i = bulk.iterator();
+            HashMap<String, NeutronNetwork> testMap = new HashMap<String, NeutronNetwork>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronNetwork test = i.next();
+
+                /*
+                 * network ID can't already exist, nor can there be an entry for this UUID
+                 * already in this bulk request
+                 */
+                if (networkInterface.networkExists(test.getID())) {
+                    throw new BadRequestException("network UUID already exists");
+                }
+                if (testMap.containsKey(test.getID())) {
+                    throw new BadRequestException("network UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance: instances) {
+                        INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                        int status = service.canCreateNetwork(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+                testMap.put(test.getID(),test);
+            }
+
+            // now that everything passed, add items to the cache
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronNetwork test = i.next();
+                test.initDefaults();
+                networkInterface.addNetwork(test);
+                if (instances != null) {
+                    for (Object instance: instances) {
+                        INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                        service.neutronNetworkCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Network */
+    @Path("{netUUID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackNetworks.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 400, condition = "Bad Request"),
+        @ResponseCode(code = 403, condition = "Forbidden"),
+        @ResponseCode(code = 404, condition = "Not Found"), })
+    public Response updateNetwork(
+            @PathParam("netUUID") String netUUID, final NeutronNetworkRequest input
+            ) {
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * network has to exist and only a single delta is supported
+         */
+        if (!networkInterface.networkExists(netUUID)) {
+            throw new ResourceNotFoundException("network UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("only singleton edits supported");
+        }
+        NeutronNetwork delta = input.getSingleton();
+
+        /*
+         * transitions forbidden by Neutron
+         */
+        if (delta.getID() != null || delta.getTenantID() != null ||
+                delta.getStatus() != null) {
+            throw new BadRequestException("attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                NeutronNetwork original = networkInterface.getNetwork(netUUID);
+                int status = service.canUpdateNetwork(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        // update network object and return the modified object
+                networkInterface.updateNetwork(netUUID, delta);
+                NeutronNetwork updatedSingleton = networkInterface.getNetwork(netUUID);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                        service.neutronNetworkUpdated(updatedSingleton);
+                    }
+                }
+                return Response.status(200).entity(
+                        new NeutronNetworkRequest(networkInterface.getNetwork(netUUID))).build();
+    }
+
+    /**
+     * Deletes a Network */
+
+    @Path("{netUUID}")
+    @DELETE
+    @StatusCodes({
+        @ResponseCode(code = 204, condition = "No Content"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 404, condition = "Not Found"),
+        @ResponseCode(code = 409, condition = "Network In Use") })
+    public Response deleteNetwork(
+            @PathParam("netUUID") String netUUID) {
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * network has to exist and not be in use before it can be removed
+         */
+        if (!networkInterface.networkExists(netUUID)) {
+            throw new ResourceNotFoundException("network UUID does not exist.");
+        }
+        if (networkInterface.networkInUse(netUUID)) {
+            throw new ResourceConflictException("Network ID in use");
+        }
+
+        NeutronNetwork singleton = networkInterface.getNetwork(netUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronNetworkAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                int status = service.canDeleteNetwork(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+        networkInterface.removeNetwork(netUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronNetworkAware service = (INeutronNetworkAware) instance;
+                service.neutronNetworkDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNorthboundRSApplication.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronNorthboundRSApplication.java
new file mode 100644 (file)
index 0000000..96d72cb
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+import org.eclipse.persistence.jaxb.rs.MOXyJsonProvider;
+
+import javax.ws.rs.core.Application;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+
+/**
+ * This class is an instance of javax.ws.rs.core.Application and is used to return the classes
+ * that will be instantiated for JAXRS processing. This is necessary
+ * because package scanning in jersey doesn't yet work in OSGi environment.
+ *
+ */
+public class NeutronNorthboundRSApplication extends Application {
+    @Override
+    public Set<Class<?>> getClasses() {
+        Set<Class<?>> classes = new HashSet<Class<?>>();
+// northbound URIs
+        classes.add(NeutronNetworksNorthbound.class);
+        classes.add(NeutronSubnetsNorthbound.class);
+        classes.add(NeutronPortsNorthbound.class);
+        classes.add(NeutronRoutersNorthbound.class);
+        classes.add(NeutronFloatingIPsNorthbound.class);
+        classes.add(NeutronSecurityGroupsNorthbound.class);
+        classes.add(NeutronSecurityRulesNorthbound.class);
+        classes.add(NeutronFirewallNorthbound.class);
+        classes.add(NeutronFirewallPolicyNorthbound.class);
+        classes.add(NeutronFirewallRulesNorthbound.class);
+        classes.add(NeutronLoadBalancerNorthbound.class);
+        classes.add(NeutronLoadBalancerListenerNorthbound.class);
+        classes.add(NeutronLoadBalancerPoolNorthbound.class);
+        classes.add(NeutronLoadBalancerHealthMonitorNorthbound.class);
+        classes.add(NeutronLoadBalancerPoolMembersNorthbound.class);
+        return classes;
+    }
+
+    @Override
+    public Set<Object> getSingletons() {
+        MOXyJsonProvider moxyJsonProvider = new MOXyJsonProvider();
+
+        moxyJsonProvider.setAttributePrefix("@");
+        moxyJsonProvider.setFormattedOutput(true);
+        moxyJsonProvider.setIncludeRoot(false);
+        moxyJsonProvider.setMarshalEmptyCollections(true);
+        moxyJsonProvider.setValueWrapper("$");
+
+        Map<String, String> namespacePrefixMapper = new HashMap<String, String>(1);
+        namespacePrefixMapper.put("router", "router");        // FIXME: fill in with XSD
+        namespacePrefixMapper.put("provider", "provider");    // FIXME: fill in with XSD
+        moxyJsonProvider.setNamespacePrefixMapper(namespacePrefixMapper);
+        moxyJsonProvider.setNamespaceSeparator(':');
+
+        HashSet<Object> set = new HashSet<Object>(1);
+        set.add(moxyJsonProvider);
+        return set;
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPageLink.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPageLink.java
new file mode 100644 (file)
index 0000000..f65d7f6
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * 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 javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronPageLink {
+
+    @XmlElement(name="ref")
+    String ref;
+
+    @XmlElement (name="href")
+    String href;
+
+    public String getRef() {
+        return ref;
+    }
+
+    public void setRef(String ref) {
+        this.ref = ref;
+    }
+
+    public String getHref() {
+        return href;
+    }
+
+    public void setHref(String href) {
+        this.href = href;
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortRequest.java
new file mode 100644 (file)
index 0000000..3bfac8a
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+import java.util.List;
+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 org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronPortRequest implements INeutronRequest<NeutronPort> {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name="port")
+    NeutronPort singletonPort;
+
+    @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;
+    }
+
+    NeutronPortRequest(NeutronPort port) {
+        singletonPort = port;
+    }
+
+    @Override
+    public NeutronPort getSingleton() {
+        return singletonPort;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return (singletonPort != null);
+    }
+
+    @Override
+    public List<NeutronPort> getBulk() {
+        return bulkRequest;
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronPortsNorthbound.java
new file mode 100644 (file)
index 0000000..5451fbf
--- /dev/null
@@ -0,0 +1,537 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+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;
+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;
+import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
+import org.opendaylight.controller.networkconfig.neutron.Neutron_IPs;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+/**
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing neutron port objects
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+
+@Path("/ports")
+public class NeutronPortsNorthbound {
+
+    final String mac_regex="^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$";
+
+    private NeutronPort extractFields(NeutronPort o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    @Context
+    UriInfo uriInfo;
+
+    /**
+     * Returns a list of all Ports */
+
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackPorts.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response listPorts(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // note: openstack isn't clear about filtering on lists, so we aren't handling them
+            @QueryParam("id") String queryID,
+            @QueryParam("network_id") String queryNetworkID,
+            @QueryParam("name") String queryName,
+            @QueryParam("admin_state_up") String queryAdminStateUp,
+            @QueryParam("status") String queryStatus,
+            @QueryParam("mac_address") String queryMACAddress,
+            @QueryParam("device_id") String queryDeviceID,
+            @QueryParam("device_owner") String queryDeviceOwner,
+            @QueryParam("tenant_id") String queryTenantID,
+            // linkTitle
+            @QueryParam("limit") Integer limit,
+            @QueryParam("marker") String marker,
+            @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
+            // sorting not supported
+            ) {
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronPort> allPorts = portInterface.getAllPorts();
+        List<NeutronPort> ans = new ArrayList<NeutronPort>();
+        Iterator<NeutronPort> i = allPorts.iterator();
+        while (i.hasNext()) {
+            NeutronPort oSS = i.next();
+            if ((queryID == null || queryID.equals(oSS.getID())) &&
+                    (queryNetworkID == null || queryNetworkID.equals(oSS.getNetworkUUID())) &&
+                    (queryName == null || queryName.equals(oSS.getName())) &&
+                    (queryAdminStateUp == null || queryAdminStateUp.equals(oSS.getAdminStateUp())) &&
+                    (queryStatus == null || queryStatus.equals(oSS.getStatus())) &&
+                    (queryMACAddress == null || queryMACAddress.equals(oSS.getMacAddress())) &&
+                    (queryDeviceID == null || queryDeviceID.equals(oSS.getDeviceID())) &&
+                    (queryDeviceOwner == null || queryDeviceOwner.equals(oSS.getDeviceOwner())) &&
+                    (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(oSS,fields));
+                } else {
+                    ans.add(oSS);
+                }
+            }
+        }
+
+        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();
+    }
+
+    /**
+     * Returns a specific Port */
+
+    @Path("{portUUID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackPorts.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 404, condition = "Not Found"),
+        @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showPort(
+            @PathParam("portUUID") String portUUID,
+            // return fields
+            @QueryParam("fields") List<String> fields ) {
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!portInterface.portExists(portUUID)) {
+            throw new ResourceNotFoundException("port UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronPort ans = portInterface.getPort(portUUID);
+            return Response.status(200).entity(
+                    new NeutronPortRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(
+                    new NeutronPortRequest(portInterface.getPort(portUUID))).build();
+        }
+    }
+
+    /**
+     * Creates new Ports */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackPorts.class)
+    @StatusCodes({
+        @ResponseCode(code = 201, condition = "Created"),
+        @ResponseCode(code = 400, condition = "Bad Request"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 403, condition = "Forbidden"),
+        @ResponseCode(code = 404, condition = "Not Found"),
+        @ResponseCode(code = 409, condition = "Conflict"),
+        @ResponseCode(code = 501, condition = "Not Implemented"),
+        @ResponseCode(code = 503, condition = "MAC generation failure") })
+    public Response createPorts(final NeutronPortRequest input) {
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronPort singleton = input.getSingleton();
+
+            /*
+             * the port must be part of an existing network, must not already exist,
+             * have a valid MAC and the MAC not be in use
+             */
+            if (singleton.getNetworkUUID() == null) {
+                throw new BadRequestException("network UUID musy be specified");
+            }
+            if (portInterface.portExists(singleton.getID())) {
+                throw new BadRequestException("port UUID already exists");
+            }
+            if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
+                throw new ResourceNotFoundException("network UUID does not exist.");
+            }
+            if (singleton.getMacAddress() == null ||
+                    !singleton.getMacAddress().matches(mac_regex)) {
+                throw new BadRequestException("MAC address not properly formatted");
+            }
+            if (portInterface.macInUse(singleton.getMacAddress())) {
+                throw new ResourceConflictException("MAC Address is in use.");
+            }
+            /*
+             * if fixed IPs are specified, each one has to have an existing subnet ID
+             * that is in the same scoping network as the port.  In addition, if an IP
+             * address is specified it has to be a valid address for the subnet and not
+             * already in use
+             */
+            List<Neutron_IPs> fixedIPs = singleton.getFixedIPs();
+            if (fixedIPs != null && fixedIPs.size() > 0) {
+                Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();
+                while (fixedIPIterator.hasNext()) {
+                    Neutron_IPs ip = fixedIPIterator.next();
+                    if (ip.getSubnetUUID() == null) {
+                        throw new BadRequestException("subnet UUID not specified");
+                    }
+                    if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
+                        throw new BadRequestException("subnet UUID must exists");
+                    }
+                    NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
+                    if (!singleton.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
+                        throw new BadRequestException("network UUID must match that of subnet");
+                    }
+                    if (ip.getIpAddress() != null) {
+                        if (!subnet.isValidIP(ip.getIpAddress())) {
+                            throw new BadRequestException("IP address is not valid");
+                        }
+                        if (subnet.isIPInUse(ip.getIpAddress())) {
+                            throw new ResourceConflictException("IP address is in use.");
+                        }
+                    }
+                }
+            }
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronPortAware service = (INeutronPortAware) instance;
+                    int status = service.canCreatePort(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+
+
+            // add the port to the cache
+            portInterface.addPort(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronPortAware service = (INeutronPortAware) instance;
+                    service.neutronPortCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronPort> bulk = input.getBulk();
+            Iterator<NeutronPort> i = bulk.iterator();
+            HashMap<String, NeutronPort> testMap = new HashMap<String, NeutronPort>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronPort test = i.next();
+
+                /*
+                 * the port must be part of an existing network, must not already exist,
+                 * have a valid MAC and the MAC not be in use.  Further the bulk request
+                 * can't already contain a new port with the same UUID
+                 */
+                if (portInterface.portExists(test.getID())) {
+                    throw new BadRequestException("port UUID already exists");
+                }
+                if (testMap.containsKey(test.getID())) {
+                    throw new BadRequestException("port UUID already exists");
+                }
+                for (NeutronPort check : testMap.values()) {
+                    if (test.getMacAddress().equalsIgnoreCase(check.getMacAddress())) {
+                        throw new ResourceConflictException("MAC address already allocated");
+                    }
+                    for (Neutron_IPs test_fixedIP : test.getFixedIPs()) {
+                        for (Neutron_IPs check_fixedIP : check.getFixedIPs()) {
+                            if (test_fixedIP.getIpAddress().equals(check_fixedIP.getIpAddress())) {
+                                throw new ResourceConflictException("IP address already allocated");
+                            }
+                        }
+                    }
+                }
+                testMap.put(test.getID(), test);
+                if (!networkInterface.networkExists(test.getNetworkUUID())) {
+                    throw new ResourceNotFoundException("network UUID does not exist.");
+                }
+                if (!test.getMacAddress().matches(mac_regex)) {
+                    throw new BadRequestException("MAC address not properly formatted");
+                }
+                if (portInterface.macInUse(test.getMacAddress())) {
+                    throw new ResourceConflictException("MAC address in use");
+                }
+
+                /*
+                 * if fixed IPs are specified, each one has to have an existing subnet ID
+                 * that is in the same scoping network as the port.  In addition, if an IP
+                 * address is specified it has to be a valid address for the subnet and not
+                 * already in use (or be the gateway IP address of the subnet)
+                 */
+                List<Neutron_IPs> fixedIPs = test.getFixedIPs();
+                if (fixedIPs != null && fixedIPs.size() > 0) {
+                    Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();
+                    while (fixedIPIterator.hasNext()) {
+                        Neutron_IPs ip = fixedIPIterator.next();
+                        if (ip.getSubnetUUID() == null) {
+                            throw new BadRequestException("subnet UUID must be specified");
+                        }
+                        if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
+                            throw new BadRequestException("subnet UUID doesn't exists");
+                        }
+                        NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
+                        if (!test.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
+                            throw new BadRequestException("network UUID must match that of subnet");
+                        }
+                        if (ip.getIpAddress() != null) {
+                            if (!subnet.isValidIP(ip.getIpAddress())) {
+                                throw new BadRequestException("ip address not valid");
+                            }
+                            //TODO: need to add consideration for a fixed IP being assigned the same address as a allocated IP in the
+                            //same bulk create
+                            if (subnet.isIPInUse(ip.getIpAddress())) {
+                                throw new ResourceConflictException("IP address in use");
+                            }
+                        }
+                    }
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronPortAware service = (INeutronPortAware) instance;
+                        int status = service.canCreatePort(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+
+            //once everything has passed, then we can add to the cache
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronPort test = i.next();
+                portInterface.addPort(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronPortAware service = (INeutronPortAware) instance;
+                        service.neutronPortCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Port */
+
+    @Path("{portUUID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackPorts.class)
+    @StatusCodes({
+        @ResponseCode(code = 200, condition = "Operation successful"),
+        @ResponseCode(code = 400, condition = "Bad Request"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 403, condition = "Forbidden"),
+        @ResponseCode(code = 404, condition = "Not Found"),
+        @ResponseCode(code = 409, condition = "Conflict"),
+        @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updatePort(
+            @PathParam("portUUID") String portUUID,
+            NeutronPortRequest input
+            ) {
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        // port has to exist and only a single delta is supported
+        if (!portInterface.portExists(portUUID)) {
+            throw new ResourceNotFoundException("port UUID does not exist.");
+        }
+        NeutronPort target = portInterface.getPort(portUUID);
+        if (!input.isSingleton()) {
+            throw new BadRequestException("only singleton edit suported");
+        }
+        NeutronPort singleton = input.getSingleton();
+        NeutronPort original = portInterface.getPort(portUUID);
+
+        // deltas restricted by Neutron
+        if (singleton.getID() != null || singleton.getTenantID() != null ||
+                singleton.getStatus() != null) {
+            throw new BadRequestException("attribute change blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronPortAware service = (INeutronPortAware) instance;
+                int status = service.canUpdatePort(singleton, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        // Verify the new fixed ips are valid
+        List<Neutron_IPs> fixedIPs = singleton.getFixedIPs();
+        if (fixedIPs != null && fixedIPs.size() > 0) {
+            Iterator<Neutron_IPs> fixedIPIterator = fixedIPs.iterator();
+            while (fixedIPIterator.hasNext()) {
+                Neutron_IPs ip = fixedIPIterator.next();
+                if (ip.getSubnetUUID() == null) {
+                    throw new BadRequestException("subnet UUID must be specified");
+                }
+                if (!subnetInterface.subnetExists(ip.getSubnetUUID())) {
+                    throw new BadRequestException("subnet UUID doesn't exist.");
+                }
+                NeutronSubnet subnet = subnetInterface.getSubnet(ip.getSubnetUUID());
+                if (!target.getNetworkUUID().equalsIgnoreCase(subnet.getNetworkUUID())) {
+                    throw new BadRequestException("network UUID must match that of subnet");
+                }
+                if (ip.getIpAddress() != null) {
+                    if (!subnet.isValidIP(ip.getIpAddress())) {
+                        throw new BadRequestException("invalid IP address");
+                    }
+                    if (subnet.isIPInUse(ip.getIpAddress())) {
+                        throw new ResourceConflictException("IP address in use");
+                    }
+                }
+            }
+        }
+
+        //        TODO: Support change of security groups
+        // update the port and return the modified object
+        portInterface.updatePort(portUUID, singleton);
+        NeutronPort updatedPort = portInterface.getPort(portUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronPortAware service = (INeutronPortAware) instance;
+                service.neutronPortUpdated(updatedPort);
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronPortRequest(updatedPort)).build();
+
+    }
+
+    /**
+     * Deletes a Port */
+
+    @Path("{portUUID}")
+    @DELETE
+    @StatusCodes({
+        @ResponseCode(code = 204, condition = "No Content"),
+        @ResponseCode(code = 401, condition = "Unauthorized"),
+        @ResponseCode(code = 403, condition = "Forbidden"),
+        @ResponseCode(code = 404, condition = "Not Found"),
+        @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deletePort(
+            @PathParam("portUUID") String portUUID) {
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        // port has to exist and not be owned by anyone.  then it can be removed from the cache
+        if (!portInterface.portExists(portUUID)) {
+            throw new ResourceNotFoundException("port UUID does not exist.");
+        }
+        NeutronPort port = portInterface.getPort(portUUID);
+        if (port.getDeviceID() != null ||
+                port.getDeviceOwner() != null) {
+            Response.status(403).build();
+        }
+        NeutronPort singleton = portInterface.getPort(portUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronPortAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronPortAware service = (INeutronPortAware) instance;
+                int status = service.canDeletePort(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+        portInterface.removePort(portUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronPortAware service = (INeutronPortAware) instance;
+                service.neutronPortDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRouterRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRouterRequest.java
new file mode 100644 (file)
index 0000000..806fd69
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+import java.util.List;
+
+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 org.opendaylight.controller.networkconfig.neutron.NeutronRouter;
+
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+
+public class NeutronRouterRequest {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name="router")
+    NeutronRouter singletonRouter;
+
+    @XmlElement(name="routers")
+    List<NeutronRouter> bulkRequest;
+
+    NeutronRouterRequest() {
+    }
+
+    NeutronRouterRequest(List<NeutronRouter> bulk) {
+        bulkRequest = bulk;
+        singletonRouter = null;
+    }
+
+    NeutronRouterRequest(NeutronRouter router) {
+        singletonRouter = router;
+    }
+
+    public List<NeutronRouter> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronRouter getSingleton() {
+        return singletonRouter;
+    }
+
+    public boolean isSingleton() {
+        return (singletonRouter != null);
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronRoutersNorthbound.java
new file mode 100644 (file)
index 0000000..0c02ada
--- /dev/null
@@ -0,0 +1,590 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronPortCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronRouterAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronRouterCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronNetwork;
+import org.opendaylight.controller.networkconfig.neutron.NeutronPort;
+import org.opendaylight.controller.networkconfig.neutron.NeutronRouter;
+import org.opendaylight.controller.networkconfig.neutron.NeutronRouter_Interface;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+
+/**
+ * Neutron Northbound REST APIs.<br>
+ * This class provides REST APIs for managing neutron routers
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+
+@Path("/routers")
+public class NeutronRoutersNorthbound {
+
+    private NeutronRouter extractFields(NeutronRouter o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all Routers */
+
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackRouters.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response listRouters(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // note: openstack isn't clear about filtering on lists, so we aren't handling them
+            @QueryParam("id") String queryID,
+            @QueryParam("name") String queryName,
+            @QueryParam("admin_state_up") String queryAdminStateUp,
+            @QueryParam("status") String queryStatus,
+            @QueryParam("tenant_id") String queryTenantID,
+            @QueryParam("external_gateway_info") String queryExternalGatewayInfo,
+            // pagination
+            @QueryParam("limit") String limit,
+            @QueryParam("marker") String marker,
+            @QueryParam("page_reverse") String pageReverse
+            // sorting not supported
+            ) {
+        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
+        if (routerInterface == null) {
+            throw new ServiceUnavailableException("Router CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronRouter> allRouters = routerInterface.getAllRouters();
+        List<NeutronRouter> ans = new ArrayList<NeutronRouter>();
+        Iterator<NeutronRouter> i = allRouters.iterator();
+        while (i.hasNext()) {
+            NeutronRouter oSS = i.next();
+            if ((queryID == null || queryID.equals(oSS.getID())) &&
+                    (queryName == null || queryName.equals(oSS.getName())) &&
+                    (queryAdminStateUp == null || queryAdminStateUp.equals(oSS.getAdminStateUp())) &&
+                    (queryStatus == null || queryStatus.equals(oSS.getStatus())) &&
+                    (queryExternalGatewayInfo == null || queryExternalGatewayInfo.equals(oSS.getExternalGatewayInfo())) &&
+                    (queryTenantID == null || queryTenantID.equals(oSS.getTenantID()))) {
+                if (fields.size() > 0)
+                    ans.add(extractFields(oSS,fields));
+                else
+                    ans.add(oSS);
+            }
+        }
+        //TODO: apply pagination to results
+        return Response.status(200).entity(
+                new NeutronRouterRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific Router */
+
+    @Path("{routerUUID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackRouters.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showRouter(
+            @PathParam("routerUUID") String routerUUID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
+        if (routerInterface == null) {
+            throw new ServiceUnavailableException("Router CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!routerInterface.routerExists(routerUUID)) {
+            throw new ResourceNotFoundException("Router UUID not found");
+        }
+        if (fields.size() > 0) {
+            NeutronRouter ans = routerInterface.getRouter(routerUUID);
+            return Response.status(200).entity(
+                    new NeutronRouterRequest(extractFields(ans, fields))).build();
+        } else
+            return Response.status(200).entity(
+                    new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
+    }
+
+    /**
+     * Creates new Routers */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackRouters.class)
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createRouters(final NeutronRouterRequest input) {
+        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
+        if (routerInterface == null) {
+            throw new ServiceUnavailableException("Router CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronRouter singleton = input.getSingleton();
+
+            /*
+             * verify that the router doesn't already exist (issue: is deeper inspection necessary?)
+             * if there is external gateway information provided, verify that the specified network
+             * exists and has been designated as "router:external"
+             */
+            if (routerInterface.routerExists(singleton.getID()))
+                throw new BadRequestException("router UUID already exists");
+            if (singleton.getExternalGatewayInfo() != null) {
+                String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
+                if (!networkInterface.networkExists(externNetworkPtr))
+                    throw new BadRequestException("External Network Pointer doesn't exist");
+                NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
+                if (!externNetwork.isRouterExternal())
+                    throw new BadRequestException("External Network Pointer isn't marked as router:external");
+            }
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronRouterAware service = (INeutronRouterAware) instance;
+                    int status = service.canCreateRouter(singleton);
+                    if (status < 200 || status > 299)
+                        return Response.status(status).build();
+                }
+            }
+
+            /*
+             * add router to the cache
+             */
+            routerInterface.addRouter(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronRouterAware service = (INeutronRouterAware) instance;
+                    service.neutronRouterCreated(singleton);
+                }
+            }
+        } else {
+
+            /*
+             * only singleton router creates supported
+             */
+            throw new BadRequestException("Only singleton router creates supported");
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Router */
+
+    @Path("{routerUUID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackRouters.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateRouter(
+            @PathParam("routerUUID") String routerUUID,
+            NeutronRouterRequest input
+            ) {
+        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
+        if (routerInterface == null) {
+            throw new ServiceUnavailableException("Router CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * router has to exist and only a single delta can be supplied
+         */
+        if (!routerInterface.routerExists(routerUUID))
+            throw new ResourceNotFoundException("Router UUID not found");
+        if (!input.isSingleton())
+            throw new BadRequestException("Only single router deltas supported");
+        NeutronRouter singleton = input.getSingleton();
+        NeutronRouter original = routerInterface.getRouter(routerUUID);
+
+        /*
+         * attribute changes blocked by Neutron
+         */
+        if (singleton.getID() != null || singleton.getTenantID() != null ||
+                singleton.getStatus() != null)
+            throw new BadRequestException("Request attribute change not allowed");
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronRouterAware service = (INeutronRouterAware) instance;
+                int status = service.canUpdateRouter(singleton, original);
+                if (status < 200 || status > 299)
+                    return Response.status(status).build();
+            }
+        }
+        /*
+         * if the external gateway info is being changed, verify that the new network
+         * exists and has been designated as an external network
+         */
+        if (singleton.getExternalGatewayInfo() != null) {
+            String externNetworkPtr = singleton.getExternalGatewayInfo().getNetworkID();
+            if (!networkInterface.networkExists(externNetworkPtr))
+                throw new BadRequestException("External Network Pointer does not exist");
+            NeutronNetwork externNetwork = networkInterface.getNetwork(externNetworkPtr);
+            if (!externNetwork.isRouterExternal())
+                throw new BadRequestException("External Network Pointer isn't marked as router:external");
+        }
+
+        /*
+         * update the router entry and return the modified object
+         */
+        routerInterface.updateRouter(routerUUID, singleton);
+        NeutronRouter updatedRouter = routerInterface.getRouter(routerUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronRouterAware service = (INeutronRouterAware) instance;
+                service.neutronRouterUpdated(updatedRouter);
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronRouterRequest(routerInterface.getRouter(routerUUID))).build();
+
+    }
+
+    /**
+     * Deletes a Router */
+
+    @Path("{routerUUID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteRouter(
+            @PathParam("routerUUID") String routerUUID) {
+        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
+        if (routerInterface == null) {
+            throw new ServiceUnavailableException("Router CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify that the router exists and is not in use before removing it
+         */
+        if (!routerInterface.routerExists(routerUUID))
+            throw new ResourceNotFoundException("Router UUID not found");
+        if (routerInterface.routerInUse(routerUUID))
+            throw new ResourceConflictException("Router UUID in Use");
+        NeutronRouter singleton = routerInterface.getRouter(routerUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronRouterAware service = (INeutronRouterAware) instance;
+                int status = service.canDeleteRouter(singleton);
+                if (status < 200 || status > 299)
+                    return Response.status(status).build();
+            }
+        }
+        routerInterface.removeRouter(routerUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronRouterAware service = (INeutronRouterAware) instance;
+                service.neutronRouterDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+
+    /**
+     * Adds an interface to a router */
+
+    @Path("{routerUUID}/add_router_interface")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackRouterInterfaces.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response addRouterInterface(
+            @PathParam("routerUUID") String routerUUID,
+            NeutronRouter_Interface input
+            ) {
+        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
+        if (routerInterface == null) {
+            throw new ServiceUnavailableException("Router CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         *  While the Neutron specification says that the router has to exist and the input can only specify either a subnet id
+         *  or a port id, but not both, this code assumes that the plugin has filled everything in for us and so both must be present
+         */
+        if (!routerInterface.routerExists(routerUUID))
+            throw new BadRequestException("Router UUID doesn't exist");
+        NeutronRouter target = routerInterface.getRouter(routerUUID);
+        if (input.getSubnetUUID() == null ||
+                    input.getPortUUID() == null)
+            throw new BadRequestException("Must specify at subnet id, port id or both");
+
+        // check that the port is part of the subnet
+        NeutronSubnet targetSubnet = subnetInterface.getSubnet(input.getSubnetUUID());
+        if (targetSubnet == null)
+            throw new BadRequestException("Subnet id doesn't exist");
+        NeutronPort targetPort = portInterface.getPort(input.getPortUUID());
+        if (targetPort == null)
+            throw new BadRequestException("Port id doesn't exist");
+        if (!targetSubnet.getPortsInSubnet().contains(targetPort))
+            throw new BadRequestException("Port id not part of subnet id");
+
+        if (targetPort.getFixedIPs().size() != 1)
+            throw new BadRequestException("Port id must have a single fixedIP address");
+        if (targetPort.getDeviceID() != null ||
+                targetPort.getDeviceOwner() != null)
+            throw new ResourceConflictException("Target Port already allocated");
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronRouterAware service = (INeutronRouterAware) instance;
+                int status = service.canAttachInterface(target, input);
+                if (status < 200 || status > 299)
+                    return Response.status(status).build();
+            }
+        }
+
+        //mark the port device id and device owner fields
+        targetPort.setDeviceOwner("network:router_interface");
+        targetPort.setDeviceID(routerUUID);
+
+        target.addInterface(input.getPortUUID(), input);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronRouterAware service = (INeutronRouterAware) instance;
+                service.neutronRouterInterfaceAttached(target, input);
+            }
+        }
+
+        return Response.status(200).entity(input).build();
+    }
+
+    /**
+     * Removes an interface to a router */
+
+    @Path("{routerUUID}/remove_router_interface")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackRouterInterfaces.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response removeRouterInterface(
+            @PathParam("routerUUID") String routerUUID,
+            NeutronRouter_Interface input
+            ) {
+        INeutronRouterCRUD routerInterface = NeutronCRUDInterfaces.getINeutronRouterCRUD(this);
+        if (routerInterface == null) {
+            throw new ServiceUnavailableException("Router CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronPortCRUD portInterface = NeutronCRUDInterfaces.getINeutronPortCRUD(this);
+        if (portInterface == null) {
+            throw new ServiceUnavailableException("Port CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        // verify the router exists
+        if (!routerInterface.routerExists(routerUUID))
+            throw new BadRequestException("Router does not exist");
+        NeutronRouter target = routerInterface.getRouter(routerUUID);
+
+        /*
+         * remove by subnet id.  Collect information about the impacted router for the response and
+         * remove the port corresponding to the gateway IP address of the subnet
+         */
+        if (input.getPortUUID() == null &&
+                input.getSubnetUUID() != null) {
+            NeutronPort port = portInterface.getGatewayPort(input.getSubnetUUID());
+            if (port == null)
+                throw new ResourceNotFoundException("Port UUID not found");
+            input.setPortUUID(port.getID());
+            input.setID(target.getID());
+            input.setTenantID(target.getTenantID());
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronRouterAware service = (INeutronRouterAware) instance;
+                    int status = service.canDetachInterface(target, input);
+                    if (status < 200 || status > 299)
+                        return Response.status(status).build();
+                }
+            }
+
+            // reset the port ownership
+            port.setDeviceID(null);
+            port.setDeviceOwner(null);
+
+            target.removeInterface(input.getPortUUID());
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronRouterAware service = (INeutronRouterAware) instance;
+                    service.neutronRouterInterfaceDetached(target, input);
+                }
+            }
+            return Response.status(200).entity(input).build();
+        }
+
+        /*
+         * remove by port id. collect information about the impacted router for the response
+         * remove the interface and reset the port ownership
+         */
+        if (input.getPortUUID() != null &&
+                input.getSubnetUUID() == null) {
+            NeutronRouter_Interface targetInterface = target.getInterfaces().get(input.getPortUUID());
+            if (targetInterface == null) {
+                throw new ResourceNotFoundException("Router interface not found for given Port UUID");
+            }
+            input.setSubnetUUID(targetInterface.getSubnetUUID());
+            input.setID(target.getID());
+            input.setTenantID(target.getTenantID());
+            NeutronPort port = portInterface.getPort(input.getPortUUID());
+            port.setDeviceID(null);
+            port.setDeviceOwner(null);
+            target.removeInterface(input.getPortUUID());
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
+            for (Object instance : instances) {
+                INeutronRouterAware service = (INeutronRouterAware) instance;
+                service.neutronRouterInterfaceDetached(target, input);
+            }
+            return Response.status(200).entity(input).build();
+        }
+
+        /*
+         * remove by both port and subnet ID.  Verify that the first fixed IP of the port is a valid
+         * IP address for the subnet, and then remove the interface, collecting information about the
+         * impacted router for the response and reset port ownership
+         */
+        if (input.getPortUUID() != null &&
+                input.getSubnetUUID() != null) {
+            NeutronPort port = portInterface.getPort(input.getPortUUID());
+            if (port == null) {
+                throw new ResourceNotFoundException("Port UUID not found");
+            }
+            if (port.getFixedIPs() == null) {
+                throw new ResourceNotFoundException("Port UUID has no fixed IPs");
+            }
+            NeutronSubnet subnet = subnetInterface.getSubnet(input.getSubnetUUID());
+            if (subnet == null) {
+                throw new ResourceNotFoundException("Subnet UUID not found");
+            }
+            if (!subnet.isValidIP(port.getFixedIPs().get(0).getIpAddress()))
+                throw new ResourceConflictException("Target Port IP not in Target Subnet");
+            input.setID(target.getID());
+            input.setTenantID(target.getTenantID());
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronRouterAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronRouterAware service = (INeutronRouterAware) instance;
+                    service.canDetachInterface(target, input);
+                }
+            }
+            port.setDeviceID(null);
+            port.setDeviceOwner(null);
+            target.removeInterface(input.getPortUUID());
+            for (Object instance : instances) {
+                INeutronRouterAware service = (INeutronRouterAware) instance;
+                service.neutronRouterInterfaceDetached(target, input);
+            }
+            return Response.status(200).entity(input).build();
+        }
+
+        // have to specify either a port ID or a subnet ID
+        throw new BadRequestException("Must specify port id or subnet id or both");
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityGroupRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityGroupRequest.java
new file mode 100644 (file)
index 0000000..6e779d6
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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
+ *
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+
+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 NeutronSecurityGroupRequest {
+    /**
+    * See OpenStack Network API v2.0 Reference for a
+    * description of annotated attributes and operations
+    */
+
+    @XmlElement (name = "security_group")
+    NeutronSecurityGroup singletonSecurityGroup;
+
+    @XmlElement (name = "security_groups")
+    List<NeutronSecurityGroup> bulkRequest;
+
+    NeutronSecurityGroupRequest() {
+    }
+
+    NeutronSecurityGroupRequest(List<NeutronSecurityGroup> bulk) {
+        bulkRequest = bulk;
+        singletonSecurityGroup = null;
+    }
+
+    NeutronSecurityGroupRequest(NeutronSecurityGroup group) {
+        singletonSecurityGroup = group;
+    }
+
+    public List<NeutronSecurityGroup> getBulk() {
+        return bulkRequest;
+    }
+
+    public NeutronSecurityGroup getSingleton() {
+        return singletonSecurityGroup;
+    }
+
+    public boolean isSingleton() {
+        return (singletonSecurityGroup != null);
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityGroupsNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityGroupsNorthbound.java
new file mode 100644 (file)
index 0000000..5e9a331
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * 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
+ *
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+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.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityGroup;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Neutron Northbound REST APIs for Security Group.<br>
+ * This class provides REST APIs for managing neutron Security Group
+ * <p/>
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ */
+@Path ("/security-groups")
+public class NeutronSecurityGroupsNorthbound {
+    static final Logger logger = LoggerFactory.getLogger(NeutronSecurityGroupsNorthbound.class);
+
+    private NeutronSecurityGroup extractFields(NeutronSecurityGroup o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all Security Groups
+     */
+    @GET
+    @Produces ({MediaType.APPLICATION_JSON})
+    @StatusCodes ({
+            @ResponseCode (code = 200, condition = "Operation successful"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+
+    public Response listGroups(
+            // return fields
+            @QueryParam ("fields") List<String> fields,
+            // OpenStack security group attributes
+            @QueryParam ("id") String querySecurityGroupUUID,
+            @QueryParam ("name") String querySecurityGroupName,
+            @QueryParam ("description") String querySecurityDescription,
+            @QueryParam ("tenant_id") String querySecurityTenantID,
+            @QueryParam ("limit") String limit,
+            @QueryParam ("marker") String marker,
+            @QueryParam ("page_reverse") String pageReverse
+    ) {
+        INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+
+        if (securityGroupInterface == null) {
+            throw new ServiceUnavailableException("Security Group CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronSecurityGroup> allSecurityGroups = securityGroupInterface.getAllNeutronSecurityGroups();
+        List<NeutronSecurityGroup> ans = new ArrayList<NeutronSecurityGroup>();
+        Iterator<NeutronSecurityGroup> i = allSecurityGroups.iterator();
+        while (i.hasNext()) {
+            NeutronSecurityGroup nsg = i.next();
+            if ((querySecurityGroupUUID == null ||
+                    querySecurityGroupUUID.equals(nsg.getSecurityGroupUUID())) &&
+                    (querySecurityGroupName == null ||
+                            querySecurityGroupName.equals(nsg.getSecurityGroupName())) &&
+                    (querySecurityDescription == null ||
+                            querySecurityDescription.equals(nsg.getSecurityGroupDescription())) &&
+                    (querySecurityTenantID == null ||
+                            querySecurityTenantID.equals(nsg.getSecurityGroupTenantID()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsg, fields));
+                } else {
+                    ans.add(nsg);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronSecurityGroupRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific Security Group
+     */
+
+    @Path ("{securityGroupUUID}")
+    @GET
+    @Produces ({MediaType.APPLICATION_JSON})
+    @StatusCodes ({
+            @ResponseCode (code = 200, condition = "Operation successful"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 404, condition = "Not Found"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response showSecurityGroup(@PathParam ("securityGroupUUID") String securityGroupUUID,
+                                      // return fields
+                                      @QueryParam ("fields") List<String> fields) {
+        INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+        if (securityGroupInterface == null) {
+            throw new ServiceUnavailableException("Security Group CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!securityGroupInterface.neutronSecurityGroupExists(securityGroupUUID)) {
+            throw new ResourceNotFoundException("Security Group UUID does not exist.");
+        }
+        if (!fields.isEmpty()) {
+            NeutronSecurityGroup ans = securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID);
+            return Response.status(200).entity(
+                    new NeutronSecurityGroupRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronSecurityGroupRequest(securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID))).build();
+        }
+    }
+
+    /**
+     * Creates new Security Group
+     */
+
+    @POST
+    @Produces ({MediaType.APPLICATION_JSON})
+    @Consumes ({MediaType.APPLICATION_JSON})
+    @StatusCodes ({
+            @ResponseCode (code = 201, condition = "Created"),
+            @ResponseCode (code = 400, condition = "Bad Request"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 403, condition = "Forbidden"),
+            @ResponseCode (code = 404, condition = "Not Found"),
+            @ResponseCode (code = 409, condition = "Conflict"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response createSecurityGroups(final NeutronSecurityGroupRequest input) {
+        INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+        if (securityGroupInterface == null) {
+            throw new ServiceUnavailableException("Security Group CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        if (input.isSingleton()) {
+            NeutronSecurityGroup singleton = input.getSingleton();
+
+            /*
+             *  Verify that the Security Group doesn't already exist.
+             */
+            if (securityGroupInterface.neutronSecurityGroupExists(singleton.getSecurityGroupUUID())) {
+                throw new BadRequestException("Security Group UUID already exists");
+            }
+
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityGroupAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+                    int status = service.canCreateNeutronSecurityGroup(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            // Add to Neutron cache
+            securityGroupInterface.addNeutronSecurityGroup(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+                    service.neutronSecurityGroupCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronSecurityGroup> bulk = input.getBulk();
+            Iterator<NeutronSecurityGroup> i = bulk.iterator();
+            HashMap<String, NeutronSecurityGroup> testMap = new HashMap<String, NeutronSecurityGroup>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityGroupAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronSecurityGroup test = i.next();
+
+                /*
+                 *  Verify that the security group doesn't already exist
+                 */
+
+                if (securityGroupInterface.neutronSecurityGroupExists(test.getSecurityGroupUUID())) {
+                    throw new BadRequestException("Security Group UUID already is already created");
+                }
+                if (instances != null) for (Object instance : instances) {
+                    INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+                    int status = service.canCreateNeutronSecurityGroup(test);
+                    if ((status < 200) || (status > 299)) return Response.status(status).build();
+                }
+            }
+
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronSecurityGroup test = i.next();
+                securityGroupInterface.addNeutronSecurityGroup(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+                        service.neutronSecurityGroupCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Security Group
+     */
+
+    @Path ("{securityGroupUUID}")
+    @PUT
+    @Produces ({MediaType.APPLICATION_JSON})
+    @Consumes ({MediaType.APPLICATION_JSON})
+    @StatusCodes ({
+            @ResponseCode (code = 200, condition = "Operation successful"),
+            @ResponseCode (code = 400, condition = "Bad Request"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 403, condition = "Forbidden"),
+            @ResponseCode (code = 404, condition = "Not Found"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response updateSecurityGroup(
+            @PathParam ("securityGroupUUID") String securityGroupUUID, final NeutronSecurityGroupRequest input) {
+        INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+        if (securityGroupInterface == null) {
+            throw new ServiceUnavailableException("Security Group CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Security Group exists and there is only one delta provided
+         */
+        if (!securityGroupInterface.neutronSecurityGroupExists(securityGroupUUID)) {
+            throw new ResourceNotFoundException("Security Group UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronSecurityGroup delta = input.getSingleton();
+        NeutronSecurityGroup original = securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID);
+
+        if (delta.getSecurityGroupUUID() != null ||
+                delta.getSecurityGroupTenantID() != null ||
+                delta.getSecurityGroupName() != null ||
+                delta.getSecurityGroupDescription() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityGroupAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+                int status = service.canUpdateNeutronSecurityGroup(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        securityGroupInterface.updateNeutronSecurityGroup(securityGroupUUID, delta);
+        NeutronSecurityGroup updatedSecurityGroup = securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+                service.neutronSecurityGroupUpdated(updatedSecurityGroup);
+            }
+        }
+        return Response.status(200).entity(new NeutronSecurityGroupRequest(securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID))).build();
+    }
+
+    /**
+     * Deletes a Security Group
+     */
+
+    @Path ("{securityGroupUUID}")
+    @DELETE
+    @StatusCodes ({
+            @ResponseCode (code = 204, condition = "No Content"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 404, condition = "Not Found"),
+            @ResponseCode (code = 409, condition = "Conflict"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response deleteSecurityGroup(
+            @PathParam ("securityGroupUUID") String securityGroupUUID) {
+        INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+        if (securityGroupInterface == null) {
+            throw new ServiceUnavailableException("Security Group CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Security Group exists and it isn't currently in use
+         */
+        if (!securityGroupInterface.neutronSecurityGroupExists(securityGroupUUID)) {
+            throw new ResourceNotFoundException("Security Group UUID does not exist.");
+        }
+        if (securityGroupInterface.neutronSecurityGroupInUse(securityGroupUUID)) {
+            return Response.status(409).build();
+        }
+        NeutronSecurityGroup singleton = securityGroupInterface.getNeutronSecurityGroup(securityGroupUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityGroupAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+                int status = service.canDeleteNeutronSecurityGroup(singleton);
+                if ((status < 200) || (status > 299)) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * remove it and return 204 status
+         */
+        securityGroupInterface.removeNeutronSecurityGroup(securityGroupUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSecurityGroupAware service = (INeutronSecurityGroupAware) instance;
+                service.neutronSecurityGroupDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityRuleRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityRuleRequest.java
new file mode 100644 (file)
index 0000000..b805bd6
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * 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
+ *
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityRule;
+
+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 NeutronSecurityRuleRequest {
+    /**
+     * See OpenStack Network API v2.0 Reference for a
+     * description of annotated attributes and operations
+     */
+
+    @XmlElement(name="security_group_rule")
+    NeutronSecurityRule singletonSecurityRule;
+
+    @XmlElement(name="security_group_rules")
+    List<NeutronSecurityRule> bulkRequest;
+
+    NeutronSecurityRuleRequest() {
+    }
+
+    NeutronSecurityRuleRequest(List<NeutronSecurityRule> bulk) {
+        bulkRequest = bulk;
+        singletonSecurityRule = null;
+    }
+
+    NeutronSecurityRuleRequest(NeutronSecurityRule rule) {
+        singletonSecurityRule = rule;
+    }
+
+    public NeutronSecurityRule getSingleton() {
+        return singletonSecurityRule;
+    }
+
+    public boolean isSingleton() {
+        return (singletonSecurityRule != null);
+    }
+    public List<NeutronSecurityRule> getBulk() {
+        return bulkRequest;
+    }
+
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityRulesNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSecurityRulesNorthbound.java
new file mode 100644 (file)
index 0000000..b2c05e0
--- /dev/null
@@ -0,0 +1,411 @@
+/*
+ * 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
+ *
+ */
+
+package org.opendaylight.controller.networkconfig.neutron.northbound;
+
+
+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.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.codehaus.enunciate.jaxrs.ResponseCode;
+import org.codehaus.enunciate.jaxrs.StatusCodes;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityGroupCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityRuleAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSecurityRuleCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSecurityRule;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Neutron Northbound REST APIs for Security Rule.<br>
+ * This class provides REST APIs for managing neutron Security Rule
+ * <p/>
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ */
+
+@Path ("/security-group-rules")
+public class NeutronSecurityRulesNorthbound {
+    static final Logger logger = LoggerFactory.getLogger(NeutronSecurityRulesNorthbound.class);
+
+    private NeutronSecurityRule extractFields(NeutronSecurityRule o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    /**
+     * Returns a list of all Security Rules
+     */
+    @GET
+    @Produces ({MediaType.APPLICATION_JSON})
+    @StatusCodes ({
+            @ResponseCode (code = 200, condition = "Operation successful"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response listRules(
+            // return fields
+            @QueryParam ("fields") List<String> fields,
+            // OpenStack security rule attributes
+            @QueryParam ("id") String querySecurityRuleUUID,
+            @QueryParam ("direction") String querySecurityRuleDirection,
+            @QueryParam ("protocol") String querySecurityRuleProtocol,
+            @QueryParam ("port_range_min") Integer querySecurityRulePortMin,
+            @QueryParam ("port_range_max") Integer querySecurityRulePortMax,
+            @QueryParam ("ethertype") String querySecurityRuleEthertype,
+            @QueryParam ("remote_ip_prefix") String querySecurityRuleIpPrefix,
+            @QueryParam ("remote_group_id") String querySecurityRemoteGroupID,
+            @QueryParam ("security_group_id") String querySecurityRuleGroupID,
+            @QueryParam ("tenant_id") String querySecurityRuleTenantID,
+            @QueryParam ("limit") String limit,
+            @QueryParam ("marker") String marker,
+            @QueryParam ("page_reverse") String pageReverse
+    ) {
+        INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+        if (securityRuleInterface == null) {
+            throw new ServiceUnavailableException("Security Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronSecurityRule> allSecurityRules = securityRuleInterface.getAllNeutronSecurityRules();
+        List<NeutronSecurityRule> ans = new ArrayList<NeutronSecurityRule>();
+        Iterator<NeutronSecurityRule> i = allSecurityRules.iterator();
+        while (i.hasNext()) {
+            NeutronSecurityRule nsr = i.next();
+            if ((querySecurityRuleUUID == null ||
+                    querySecurityRuleUUID.equals(nsr.getSecurityRuleUUID())) &&
+                    (querySecurityRuleDirection == null ||
+                            querySecurityRuleDirection.equals(nsr.getSecurityRuleDirection())) &&
+                    (querySecurityRuleProtocol == null ||
+                            querySecurityRuleProtocol.equals(nsr.getSecurityRuleProtocol())) &&
+                    (querySecurityRulePortMin == null ||
+                            querySecurityRulePortMin.equals(nsr.getSecurityRulePortMin())) &&
+                    (querySecurityRulePortMax == null ||
+                            querySecurityRulePortMax.equals(nsr.getSecurityRulePortMax())) &&
+                    (querySecurityRuleEthertype == null ||
+                            querySecurityRuleEthertype.equals(nsr.getSecurityRuleEthertype())) &&
+                    (querySecurityRuleIpPrefix == null ||
+                            querySecurityRuleIpPrefix.equals(nsr.getSecurityRuleRemoteIpPrefix())) &&
+                    (querySecurityRuleGroupID == null ||
+                            querySecurityRuleGroupID.equals(nsr.getSecurityRuleGroupID())) &&
+                    (querySecurityRemoteGroupID == null ||
+                            querySecurityRemoteGroupID.equals(nsr.getSecurityRemoteGroupID())) &&
+                    (querySecurityRuleTenantID == null ||
+                            querySecurityRuleTenantID.equals(nsr.getSecurityRuleTenantID()))) {
+                if (fields.size() > 0) {
+                    ans.add(extractFields(nsr, fields));
+                } else {
+                    ans.add(nsr);
+                }
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronSecurityRuleRequest(ans)).build();
+    }
+
+    /**
+     * Returns a specific Security Rule
+     */
+
+    @Path ("{securityRuleUUID}")
+    @GET
+    @Produces ({MediaType.APPLICATION_JSON})
+    @StatusCodes ({
+            @ResponseCode (code = 200, condition = "Operation successful"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 404, condition = "Not Found"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response showSecurityRule(@PathParam ("securityRuleUUID") String securityRuleUUID,
+                                     // return fields
+                                     @QueryParam ("fields") List<String> fields) {
+        INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+        if (securityRuleInterface == null) {
+            throw new ServiceUnavailableException("Security Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!securityRuleInterface.neutronSecurityRuleExists(securityRuleUUID)) {
+            throw new ResourceNotFoundException("Security Rule UUID does not exist.");
+        }
+        if (!fields.isEmpty()) {
+            NeutronSecurityRule ans = securityRuleInterface.getNeutronSecurityRule(securityRuleUUID);
+            return Response.status(200).entity(
+                    new NeutronSecurityRuleRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(new NeutronSecurityRuleRequest(securityRuleInterface.getNeutronSecurityRule(securityRuleUUID))).build();
+        }
+    }
+
+    /**
+     * Creates new Security Rule
+     */
+
+    @POST
+    @Produces ({MediaType.APPLICATION_JSON})
+    @Consumes ({MediaType.APPLICATION_JSON})
+    @StatusCodes ({
+            @ResponseCode (code = 201, condition = "Created"),
+            @ResponseCode (code = 400, condition = "Bad Request"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 403, condition = "Forbidden"),
+            @ResponseCode (code = 404, condition = "Not Found"),
+            @ResponseCode (code = 409, condition = "Conflict"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response createSecurityRules(final NeutronSecurityRuleRequest input) {
+        INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+        if (securityRuleInterface == null) {
+            throw new ServiceUnavailableException("Security Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronSecurityGroupCRUD securityGroupInterface = NeutronCRUDInterfaces.getINeutronSecurityGroupCRUD(this);
+        if (securityGroupInterface == null) {
+            throw new ServiceUnavailableException("Security Group CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * Existing entry checks
+        */
+
+        if (input.isSingleton()) {
+            NeutronSecurityRule singleton = input.getSingleton();
+
+            if (securityRuleInterface.neutronSecurityRuleExists(singleton.getSecurityRuleUUID())) {
+                throw new BadRequestException("Security Rule UUID already exists");
+            }
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityRuleAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                    int status = service.canCreateNeutronSecurityRule(singleton);
+                    if ((status < 200) || (status > 299)) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+
+            // add rule to cache
+            singleton.initDefaults();
+            securityRuleInterface.addNeutronSecurityRule(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                    service.neutronSecurityRuleCreated(singleton);
+                }
+            }
+
+            securityRuleInterface.addNeutronSecurityRule(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                    service.neutronSecurityRuleCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronSecurityRule> bulk = input.getBulk();
+            Iterator<NeutronSecurityRule> i = bulk.iterator();
+            HashMap<String, NeutronSecurityRule> testMap = new HashMap<String, NeutronSecurityRule>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityRuleAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronSecurityRule test = i.next();
+
+                /*
+                 *  Verify that the security rule doesn't already exist
+                 */
+
+                if (securityRuleInterface.neutronSecurityRuleExists(test.getSecurityRuleUUID())) {
+                    throw new BadRequestException("Security Rule UUID already exists");
+                }
+                if (testMap.containsKey(test.getSecurityRuleUUID())) {
+                    throw new BadRequestException("Security Rule UUID already exists");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                        int status = service.canCreateNeutronSecurityRule(test);
+                        if ((status < 200) || (status > 299)) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronSecurityRule test = i.next();
+                securityRuleInterface.addNeutronSecurityRule(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                        service.neutronSecurityRuleCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Security Rule
+     */
+
+    @Path ("{securityRuleUUID}")
+    @PUT
+    @Produces ({MediaType.APPLICATION_JSON})
+    @Consumes ({MediaType.APPLICATION_JSON})
+    @StatusCodes ({
+            @ResponseCode (code = 200, condition = "Operation successful"),
+            @ResponseCode (code = 400, condition = "Bad Request"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 403, condition = "Forbidden"),
+            @ResponseCode (code = 404, condition = "Not Found"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response updateSecurityRule(
+            @PathParam ("securityRuleUUID") String securityRuleUUID, final NeutronSecurityRuleRequest input) {
+        INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+        if (securityRuleInterface == null) {
+            throw new ServiceUnavailableException("Security Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Security Rule exists and there is only one delta provided
+         */
+        if (!securityRuleInterface.neutronSecurityRuleExists(securityRuleUUID)) {
+            throw new ResourceNotFoundException("Security Rule UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronSecurityRule delta = input.getSingleton();
+        NeutronSecurityRule original = securityRuleInterface.getNeutronSecurityRule(securityRuleUUID);
+
+        /*
+         * updates restricted by Neutron
+         *
+         */
+        if (delta.getSecurityRuleUUID() != null ||
+                delta.getSecurityRuleDirection() != null ||
+                delta.getSecurityRuleProtocol() != null ||
+                delta.getSecurityRulePortMin() != null ||
+                delta.getSecurityRulePortMax() != null ||
+                delta.getSecurityRuleEthertype() != null ||
+                delta.getSecurityRuleRemoteIpPrefix() != null ||
+                delta.getSecurityRuleGroupID() != null ||
+                delta.getSecurityRemoteGroupID() != null ||
+                delta.getSecurityRuleTenantID() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityRuleAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                int status = service.canUpdateNeutronSecurityRule(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        securityRuleInterface.updateNeutronSecurityRule(securityRuleUUID, delta);
+        NeutronSecurityRule updatedSecurityRule = securityRuleInterface.getNeutronSecurityRule(securityRuleUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                service.neutronSecurityRuleUpdated(updatedSecurityRule);
+            }
+        }
+        return Response.status(200).entity(new NeutronSecurityRuleRequest(securityRuleInterface.getNeutronSecurityRule(securityRuleUUID))).build();
+    }
+
+    /**
+     * Deletes a Security Rule
+     */
+
+    @Path ("{securityRuleUUID}")
+    @DELETE
+    @StatusCodes ({
+            @ResponseCode (code = 204, condition = "No Content"),
+            @ResponseCode (code = 401, condition = "Unauthorized"),
+            @ResponseCode (code = 404, condition = "Not Found"),
+            @ResponseCode (code = 409, condition = "Conflict"),
+            @ResponseCode (code = 501, condition = "Not Implemented")})
+    public Response deleteSecurityRule(
+            @PathParam ("securityRuleUUID") String securityRuleUUID) {
+        INeutronSecurityRuleCRUD securityRuleInterface = NeutronCRUDInterfaces.getINeutronSecurityRuleCRUD(this);
+        if (securityRuleInterface == null) {
+            throw new ServiceUnavailableException("Security Rule CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the Security Rule exists and it isn't currently in use
+         */
+        if (!securityRuleInterface.neutronSecurityRuleExists(securityRuleUUID)) {
+            throw new ResourceNotFoundException("Security Rule UUID does not exist.");
+        }
+        if (securityRuleInterface.neutronSecurityRuleInUse(securityRuleUUID)) {
+            return Response.status(409).build();
+        }
+        NeutronSecurityRule singleton = securityRuleInterface.getNeutronSecurityRule(securityRuleUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronSecurityRuleAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                int status = service.canDeleteNeutronSecurityRule(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * remove it and return 204 status
+         */
+        securityRuleInterface.removeNeutronSecurityRule(securityRuleUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSecurityRuleAware service = (INeutronSecurityRuleAware) instance;
+                service.neutronSecurityRuleDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
\ No newline at end of file
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetRequest.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetRequest.java
new file mode 100644 (file)
index 0000000..4c230c5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright IBM Corporation, 2013.  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.networkconfig.neutron.northbound;
+
+import java.util.List;
+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 org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.NONE)
+public class NeutronSubnetRequest implements INeutronRequest<NeutronSubnet> {
+    // See OpenStack Network API v2.0 Reference for description of
+    // annotated attributes
+
+    @XmlElement(name="subnet")
+    NeutronSubnet singletonSubnet;
+
+    @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;
+    }
+
+    @Override
+    public NeutronSubnet getSingleton() {
+        return singletonSubnet;
+    }
+
+    @Override
+    public List<NeutronSubnet> getBulk() {
+        return bulkRequest;
+    }
+
+    @Override
+    public boolean isSingleton() {
+        return (singletonSubnet != null);
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/NeutronSubnetsNorthbound.java
new file mode 100644 (file)
index 0000000..8f20269
--- /dev/null
@@ -0,0 +1,430 @@
+/*
+ * Copyright IBM Corporation and others, 2013.  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.networkconfig.neutron.northbound;
+
+
+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;
+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;
+import org.opendaylight.controller.networkconfig.neutron.INeutronNetworkCRUD;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetAware;
+import org.opendaylight.controller.networkconfig.neutron.INeutronSubnetCRUD;
+import org.opendaylight.controller.networkconfig.neutron.NeutronCRUDInterfaces;
+import org.opendaylight.controller.networkconfig.neutron.NeutronSubnet;
+import org.opendaylight.controller.northbound.commons.RestMessages;
+import org.opendaylight.controller.northbound.commons.exception.BadRequestException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceConflictException;
+import org.opendaylight.controller.northbound.commons.exception.ResourceNotFoundException;
+import org.opendaylight.controller.northbound.commons.exception.InternalServerErrorException;
+import org.opendaylight.controller.northbound.commons.exception.ServiceUnavailableException;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
+
+/**
+ * Neutron Northbound REST APIs for Subnets.<br>
+ * This class provides REST APIs for managing neutron Subnets
+ *
+ * <br>
+ * <br>
+ * Authentication scheme : <b>HTTP Basic</b><br>
+ * Authentication realm : <b>opendaylight</b><br>
+ * Transport : <b>HTTP and HTTPS</b><br>
+ * <br>
+ * HTTPS Authentication is disabled by default. Administrator can enable it in
+ * tomcat-server.xml after adding a proper keystore / SSL certificate from a
+ * trusted authority.<br>
+ * More info :
+ * http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html#Configuration
+ *
+ */
+
+@Path("/subnets")
+public class NeutronSubnetsNorthbound {
+
+    private NeutronSubnet extractFields(NeutronSubnet o, List<String> fields) {
+        return o.extractFields(fields);
+    }
+
+    @Context
+    UriInfo uriInfo;
+
+    /**
+     * Returns a list of all Subnets */
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackSubnets.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response listSubnets(
+            // return fields
+            @QueryParam("fields") List<String> fields,
+            // note: openstack isn't clear about filtering on lists, so we aren't handling them
+            @QueryParam("id") String queryID,
+            @QueryParam("network_id") String queryNetworkID,
+            @QueryParam("name") String queryName,
+            @QueryParam("ip_version") String queryIPVersion,
+            @QueryParam("cidr") String queryCIDR,
+            @QueryParam("gateway_ip") String queryGatewayIP,
+            @QueryParam("enable_dhcp") String queryEnableDHCP,
+            @QueryParam("tenant_id") String queryTenantID,
+            @QueryParam("ipv6_address_mode") String queryIpV6AddressMode,
+            @QueryParam("ipv6_ra_mode") String queryIpV6RaMode,
+            // linkTitle
+            @QueryParam("limit") Integer limit,
+            @QueryParam("marker") String marker,
+            @DefaultValue("false") @QueryParam("page_reverse") Boolean pageReverse
+            // sorting not supported
+            ) {
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        List<NeutronSubnet> allNetworks = subnetInterface.getAllSubnets();
+        List<NeutronSubnet> ans = new ArrayList<NeutronSubnet>();
+        Iterator<NeutronSubnet> i = allNetworks.iterator();
+        while (i.hasNext()) {
+            NeutronSubnet oSS = i.next();
+            if ((queryID == null || queryID.equals(oSS.getID())) &&
+                    (queryNetworkID == null || queryNetworkID.equals(oSS.getNetworkUUID())) &&
+                    (queryName == null || queryName.equals(oSS.getName())) &&
+                    (queryIPVersion == null || queryIPVersion.equals(oSS.getIpVersion())) &&
+                    (queryCIDR == null || queryCIDR.equals(oSS.getCidr())) &&
+                    (queryGatewayIP == null || queryGatewayIP.equals(oSS.getGatewayIP())) &&
+                    (queryEnableDHCP == null || queryEnableDHCP.equals(oSS.getEnableDHCP())) &&
+                    (queryTenantID == null || queryTenantID.equals(oSS.getTenantID())) &&
+                    (queryIpV6AddressMode == null || queryIpV6AddressMode.equals(oSS.getIpV6AddressMode())) &&
+                    (queryIpV6RaMode == null || queryIpV6RaMode.equals(oSS.getIpV6RaMode()))){
+                if (fields.size() > 0) {
+                    ans.add(extractFields(oSS,fields));
+                } else {
+                    ans.add(oSS);
+                }
+            }
+        }
+
+        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();
+    }
+
+    /**
+     * Returns a specific Subnet */
+
+    @Path("{subnetUUID}")
+    @GET
+    @Produces({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackSubnets.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response showSubnet(
+            @PathParam("subnetUUID") String subnetUUID,
+            // return fields
+            @QueryParam("fields") List<String> fields) {
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (!subnetInterface.subnetExists(subnetUUID)) {
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
+        }
+        if (fields.size() > 0) {
+            NeutronSubnet ans = subnetInterface.getSubnet(subnetUUID);
+            return Response.status(200).entity(
+                    new NeutronSubnetRequest(extractFields(ans, fields))).build();
+        } else {
+            return Response.status(200).entity(
+                    new NeutronSubnetRequest(subnetInterface.getSubnet(subnetUUID))).build();
+        }
+    }
+
+    /**
+     * Creates new Subnets */
+
+    @POST
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackSubnets.class)
+    @StatusCodes({
+            @ResponseCode(code = 201, condition = "Created"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response createSubnets(final NeutronSubnetRequest input) {
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD(this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        INeutronNetworkCRUD networkInterface = NeutronCRUDInterfaces.getINeutronNetworkCRUD( this);
+        if (networkInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+        if (input.isSingleton()) {
+            NeutronSubnet singleton = input.getSingleton();
+
+            /*
+             *  Verify that the subnet doesn't already exist (Issue: is a deeper check necessary?)
+             *  the specified network exists, the subnet has a valid network address,
+             *  and that the gateway IP doesn't overlap with the allocation pools
+             *  *then* add the subnet to the cache
+             */
+            if (subnetInterface.subnetExists(singleton.getID())) {
+                throw new BadRequestException("subnet UUID already exists");
+            }
+            if (!networkInterface.networkExists(singleton.getNetworkUUID())) {
+                throw new ResourceNotFoundException("network UUID does not exist.");
+            }
+            if (!singleton.isValidCIDR()) {
+                throw new BadRequestException("invaild CIDR");
+            }
+            if (!singleton.initDefaults()) {
+                throw new InternalServerErrorException("subnet object could not be initialized properly");
+            }
+            if (singleton.gatewayIP_Pool_overlap()) {
+                throw new ResourceConflictException("IP pool overlaps with gateway");
+            }
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronSubnetAware service = (INeutronSubnetAware) instance;
+                    int status = service.canCreateSubnet(singleton);
+                    if (status < 200 || status > 299) {
+                        return Response.status(status).build();
+                    }
+                }
+            }
+            subnetInterface.addSubnet(singleton);
+            if (instances != null) {
+                for (Object instance : instances) {
+                    INeutronSubnetAware service = (INeutronSubnetAware) instance;
+                    service.neutronSubnetCreated(singleton);
+                }
+            }
+        } else {
+            List<NeutronSubnet> bulk = input.getBulk();
+            Iterator<NeutronSubnet> i = bulk.iterator();
+            HashMap<String, NeutronSubnet> testMap = new HashMap<String, NeutronSubnet>();
+            Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
+            while (i.hasNext()) {
+                NeutronSubnet test = i.next();
+
+                /*
+                 *  Verify that the subnet doesn't already exist (Issue: is a deeper check necessary?)
+                 *  the specified network exists, the subnet has a valid network address,
+                 *  and that the gateway IP doesn't overlap with the allocation pools,
+                 *  and that the bulk request doesn't already contain a subnet with this id
+                 */
+
+                if (!test.initDefaults()) {
+                    throw new InternalServerErrorException("subnet object could not be initialized properly");
+                }
+                if (subnetInterface.subnetExists(test.getID())) {
+                    throw new BadRequestException("subnet UUID already exists");
+                }
+                if (testMap.containsKey(test.getID())) {
+                    throw new BadRequestException("subnet UUID already exists");
+                }
+                testMap.put(test.getID(), test);
+                if (!networkInterface.networkExists(test.getNetworkUUID())) {
+                    throw new ResourceNotFoundException("network UUID does not exist.");
+                }
+                if (!test.isValidCIDR()) {
+                    throw new BadRequestException("Invalid CIDR");
+                }
+                if (test.gatewayIP_Pool_overlap()) {
+                    throw new ResourceConflictException("IP pool overlaps with gateway");
+                }
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronSubnetAware service = (INeutronSubnetAware) instance;
+                        int status = service.canCreateSubnet(test);
+                        if (status < 200 || status > 299) {
+                            return Response.status(status).build();
+                        }
+                    }
+                }
+            }
+
+            /*
+             * now, each element of the bulk request can be added to the cache
+             */
+            i = bulk.iterator();
+            while (i.hasNext()) {
+                NeutronSubnet test = i.next();
+                subnetInterface.addSubnet(test);
+                if (instances != null) {
+                    for (Object instance : instances) {
+                        INeutronSubnetAware service = (INeutronSubnetAware) instance;
+                        service.neutronSubnetCreated(test);
+                    }
+                }
+            }
+        }
+        return Response.status(201).entity(input).build();
+    }
+
+    /**
+     * Updates a Subnet */
+
+    @Path("{subnetUUID}")
+    @PUT
+    @Produces({ MediaType.APPLICATION_JSON })
+    @Consumes({ MediaType.APPLICATION_JSON })
+    //@TypeHint(OpenStackSubnets.class)
+    @StatusCodes({
+            @ResponseCode(code = 200, condition = "Operation successful"),
+            @ResponseCode(code = 400, condition = "Bad Request"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 403, condition = "Forbidden"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response updateSubnet(
+            @PathParam("subnetUUID") String subnetUUID, final NeutronSubnetRequest input
+            ) {
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Subnet CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the subnet exists and there is only one delta provided
+         */
+        if (!subnetInterface.subnetExists(subnetUUID)) {
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
+        }
+        if (!input.isSingleton()) {
+            throw new BadRequestException("Only singleton edit supported");
+        }
+        NeutronSubnet delta = input.getSingleton();
+        NeutronSubnet original = subnetInterface.getSubnet(subnetUUID);
+
+        /*
+         * updates restricted by Neutron
+         */
+        if (delta.getID() != null || delta.getTenantID() != null ||
+                delta.getIpVersion() != null || delta.getCidr() != null ||
+                delta.getAllocationPools() != null) {
+            throw new BadRequestException("Attribute edit blocked by Neutron");
+        }
+
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSubnetAware service = (INeutronSubnetAware) instance;
+                int status = service.canUpdateSubnet(delta, original);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * update the object and return it
+         */
+        subnetInterface.updateSubnet(subnetUUID, delta);
+        NeutronSubnet updatedSubnet = subnetInterface.getSubnet(subnetUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSubnetAware service = (INeutronSubnetAware) instance;
+                service.neutronSubnetUpdated(updatedSubnet);
+            }
+        }
+        return Response.status(200).entity(
+                new NeutronSubnetRequest(subnetInterface.getSubnet(subnetUUID))).build();
+    }
+
+    /**
+     * Deletes a Subnet */
+
+    @Path("{subnetUUID}")
+    @DELETE
+    @StatusCodes({
+            @ResponseCode(code = 204, condition = "No Content"),
+            @ResponseCode(code = 401, condition = "Unauthorized"),
+            @ResponseCode(code = 404, condition = "Not Found"),
+            @ResponseCode(code = 409, condition = "Conflict"),
+            @ResponseCode(code = 501, condition = "Not Implemented") })
+    public Response deleteSubnet(
+            @PathParam("subnetUUID") String subnetUUID) {
+        INeutronSubnetCRUD subnetInterface = NeutronCRUDInterfaces.getINeutronSubnetCRUD( this);
+        if (subnetInterface == null) {
+            throw new ServiceUnavailableException("Network CRUD Interface "
+                    + RestMessages.SERVICEUNAVAILABLE.toString());
+        }
+
+        /*
+         * verify the subnet exists and it isn't currently in use
+         */
+        if (!subnetInterface.subnetExists(subnetUUID)) {
+            throw new ResourceNotFoundException("subnet UUID does not exist.");
+        }
+        if (subnetInterface.subnetInUse(subnetUUID)) {
+            return Response.status(409).build();
+        }
+        NeutronSubnet singleton = subnetInterface.getSubnet(subnetUUID);
+        Object[] instances = ServiceHelper.getGlobalInstances(INeutronSubnetAware.class, this, null);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSubnetAware service = (INeutronSubnetAware) instance;
+                int status = service.canDeleteSubnet(singleton);
+                if (status < 200 || status > 299) {
+                    return Response.status(status).build();
+                }
+            }
+        }
+
+        /*
+         * remove it and return 204 status
+         */
+        subnetInterface.removeSubnet(subnetUUID);
+        if (instances != null) {
+            for (Object instance : instances) {
+                INeutronSubnetAware service = (INeutronSubnetAware) instance;
+                service.neutronSubnetDeleted(singleton);
+            }
+        }
+        return Response.status(204).build();
+    }
+}
diff --git a/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedRequestFactory.java b/northbound/src/main/java/org/opendaylight/controller/networkconfig/neutron/northbound/PaginatedRequestFactory.java
new file mode 100644 (file)
index 0000000..7f6c296
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import javax.ws.rs.core.UriInfo;
+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;
+
+public class PaginatedRequestFactory {
+    private static final Comparator<INeutronObject> NEUTRON_OBJECT_COMPARATOR = new Comparator<INeutronObject>() {
+        @Override
+        public int compare(INeutronObject o1, INeutronObject o2) {
+            return o1.getID().compareTo(o2.getID());
+        }
+    };
+
+    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;
+        }
+    }
+
+    private static final class MarkerObject implements INeutronObject {
+        private final String id;
+
+        MarkerObject(String id) {
+            this.id = id;
+        }
+
+        @Override
+        public String getID() {
+            return id;
+        }
+
+        @Override
+        public void setID(String id) {
+            throw new UnsupportedOperationException("Marker has constant ID");
+        }
+    }
+
+    /*
+     * SuppressWarnings is needed because the compiler does not understand that we
+     * are actually safe here.
+     *
+     * FIXME: the only caller performs a cast back, so this is not actually necessary.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T extends INeutronObject> INeutronRequest<T> createRequest(Integer limit, String marker,
+                                                                           Boolean pageReverse,
+                                                                           UriInfo uriInfo,
+                                                                           List<T> collection,
+                                                                           Class<T> clazz) {
+        PaginationResults<T> results = _paginate(limit, marker, pageReverse, uriInfo, collection);
+
+        if (clazz.equals(NeutronNetwork.class)){
+            return (INeutronRequest<T>) new NeutronNetworkRequest((List<NeutronNetwork>) results.collection, results.links);
+        }
+        if (clazz.equals(NeutronSubnet.class)){
+            return (INeutronRequest<T>) new NeutronSubnetRequest((List<NeutronSubnet>) results.collection, results.links);
+        }
+        if (clazz.equals(NeutronPort.class)){
+            return (INeutronRequest<T>) new NeutronPortRequest((List<NeutronPort>) results.collection, results.links);
+        }
+        return null;
+    }
+
+    private static <T extends INeutronObject> PaginationResults<T> _paginate(Integer limit, String marker, Boolean pageReverse, UriInfo uriInfo, List<T> collection) {
+        List<NeutronPageLink> links = new ArrayList<>();
+        final int startPos;
+        String startMarker;
+        String endMarker;
+        Boolean firstPage = false;
+        Boolean lastPage = false;
+
+        Collections.sort(collection, NEUTRON_OBJECT_COMPARATOR);
+
+        if (marker != null) {
+            int offset = Collections.binarySearch(collection, new MarkerObject(marker), NEUTRON_OBJECT_COMPARATOR);
+            if (offset < 0) {
+                throw new ResourceNotFoundException("UUID for marker: " + marker + " could not be found");
+            }
+
+            if (!pageReverse) {
+                startPos = offset + 1;
+            }
+            else {
+                startPos = offset - limit;
+            }
+        }
+        else {
+            startPos = 0;
+        }
+
+        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<T>(collection, links);
+    }
+}
diff --git a/northbound/src/main/resources/WEB-INF/web.xml b/northbound/src/main/resources/WEB-INF/web.xml
new file mode 100644 (file)
index 0000000..dccd133
--- /dev/null
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="ISO-8859-1"?>\r
+<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"\r
+        xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"\r
+        version="3.0">\r
+  <servlet>\r
+    <servlet-name>JAXRSNeutron</servlet-name>\r
+    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>\r
+    <init-param>\r
+      <param-name>javax.ws.rs.Application</param-name>\r
+      <param-value>org.opendaylight.controller.networkconfig.neutron.northbound.NeutronNorthboundRSApplication</param-value>\r
+    </init-param>\r
+    <load-on-startup>1</load-on-startup>\r
+  </servlet>\r
+\r
+  <servlet-mapping>\r
+    <servlet-name>JAXRSNeutron</servlet-name>\r
+    <url-pattern>/*</url-pattern>\r
+  </servlet-mapping>\r
+        <security-constraint>\r
+                <web-resource-collection>\r
+                        <web-resource-name>NB api</web-resource-name>\r
+                        <url-pattern>/*</url-pattern>\r
+                </web-resource-collection>\r
+                <auth-constraint>\r
+                        <role-name>System-Admin</role-name>\r
+                        <role-name>Network-Admin</role-name>\r
+                        <role-name>Network-Operator</role-name>\r
+                        <role-name>Container-User</role-name>\r
+                </auth-constraint>\r
+        </security-constraint>\r
+\r
+        <security-role>\r
+                <role-name>System-Admin</role-name>\r
+        </security-role>\r
+        <security-role>\r
+                <role-name>Network-Admin</role-name>\r
+        </security-role>\r
+        <security-role>\r
+                <role-name>Network-Operator</role-name>\r
+        </security-role>\r
+        <security-role>\r
+                <role-name>Container-User</role-name>\r
+        </security-role>\r
+\r
+        <login-config>\r
+                <auth-method>BASIC</auth-method>\r
+                <realm-name>opendaylight</realm-name>\r
+        </login-config>\r
+</web-app>\r
diff --git a/northbound/src/main/resources/org/opendaylight/controller/networkconfig/neutron/northbound/jaxb.properties b/northbound/src/main/resources/org/opendaylight/controller/networkconfig/neutron/northbound/jaxb.properties
new file mode 100644 (file)
index 0000000..5837a4c
--- /dev/null
@@ -0,0 +1 @@
+javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
\ No newline at end of file