[ONOS-2247]The implementation of subnet resource service.

Change-Id: I52cbd5c52ce2439122664e8c18b7603e61500d5c
diff --git a/apps/vtnrsc/pom.xml b/apps/vtnrsc/pom.xml
index dbfc410..b07cd84c 100644
--- a/apps/vtnrsc/pom.xml
+++ b/apps/vtnrsc/pom.xml
@@ -14,8 +14,7 @@
 	<artifactId>onos-app-vtnrsc</artifactId>
 	<packaging>bundle</packaging>
 
-
-	<properties>
+    <properties>
 		<onos.app.name>org.onosproject.vtnrsc</onos.app.name>
 	</properties>
 	<dependencies>
@@ -34,50 +33,19 @@
 			<version>${project.version}</version>
 		</dependency>
 		<dependency>
-            <groupId>org.apache.felix</groupId>
-            <artifactId>org.apache.felix.scr.annotations</artifactId>
-        </dependency>
+			<groupId>org.apache.felix</groupId>
+			<artifactId>org.apache.felix.scr.annotations</artifactId>
+		</dependency>
 		<dependency>
-            <groupId>org.apache.karaf.shell</groupId>
-            <artifactId>org.apache.karaf.shell.console</artifactId>
-        </dependency>
+			<groupId>org.apache.karaf.shell</groupId>
+			<artifactId>org.apache.karaf.shell.console</artifactId>
+		</dependency>
+		<dependency>
+			<groupId>org.onosproject</groupId>
+			<artifactId>onlab-junit</artifactId>
+			<version>${project.version}</version>
+		</dependency>
 	</dependencies>
-	
-	<build>
-        <plugins>
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-bundle-plugin</artifactId>
-                <extensions>true</extensions>
-                <configuration>
-                    <instructions>
-                        <Bundle-SymbolicName>
-                            ${project.groupId}.${project.artifactId}
-                        </Bundle-SymbolicName>
-                        <Import-Package>
-                            org.slf4j,
-                            org.osgi.framework,
-                            javax.ws.rs,
-                            javax.ws.rs.core,
-                            com.sun.jersey.api.core,
-                            com.sun.jersey.spi.container.servlet,
-                            com.sun.jersey.server.impl.container.servlet,
-                            com.fasterxml.jackson.databind,
-                            com.fasterxml.jackson.databind.node,
-                            com.fasterxml.jackson.core,
-                            org.apache.karaf.shell.commands,
-                            org.apache.commons.lang.math.*,
-                            com.google.common.*,
-                            org.onlab.packet.*,
-                            org.onlab.rest.*,
-                            org.onosproject.*,
-                            org.onlab.util.*,
-                            org.jboss.netty.util.*
-                        </Import-Package>
-                    </instructions>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
+
 
 </project>
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/AllocationPool.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/AllocationPool.java
index df9b2d9..feab8e3 100644
--- a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/AllocationPool.java
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/AllocationPool.java
@@ -27,12 +27,12 @@
      *
      * @return startIp
      */
-    IpAddress startIP();
+    IpAddress startIp();
 
     /**
      * The end address for the allocation pool.
      *
      * @return endIp
      */
-    IpAddress endIP();
+    IpAddress endIp();
 }
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultAllocationPool.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultAllocationPool.java
new file mode 100644
index 0000000..2844de5
--- /dev/null
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultAllocationPool.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.app.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkNotNull;
+import java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+
+/**
+ * The continuous IP address range between the start address and the end address
+ * for the allocation pools.
+ */
+public final class DefaultAllocationPool implements AllocationPool {
+
+    private final IpAddress startIp;
+    private final IpAddress endIp;
+
+    /**
+     * Creates an AllocationPool by using the start IP address and the end IP
+     * address.
+     *
+     * @param startIp the start IP address of the allocation pool
+     * @param endIp the end IP address of the allocation pool
+     */
+    public DefaultAllocationPool(IpAddress startIp, IpAddress endIp) {
+        checkNotNull(startIp, "StartIp cannot be null");
+        checkNotNull(endIp, "EndIp cannot be null");
+        this.startIp = startIp;
+        this.endIp = endIp;
+    }
+
+    @Override
+    public IpAddress startIp() {
+        return startIp;
+    }
+
+    @Override
+    public IpAddress endIp() {
+        return endIp;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(startIp, endIp);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultAllocationPool) {
+            final DefaultAllocationPool other = (DefaultAllocationPool) obj;
+            return Objects.equals(this.startIp, other.startIp)
+                    && Objects.equals(this.endIp, other.endIp);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("startIp", startIp).add("endIp", endIp)
+                .toString();
+    }
+}
+
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultHostRoute.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultHostRoute.java
new file mode 100644
index 0000000..2270a4b
--- /dev/null
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultHostRoute.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.app.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+import java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Host route dictionaries for the subnet.
+ */
+public final class DefaultHostRoute implements HostRoute {
+
+    private final IpAddress nexthop;
+    private final IpPrefix destination;
+
+    /**
+     *
+     * Creates a DefaultHostRoute by using the next hop and the destination.
+     *
+     * @param nexthop of the DefaultHostRoute
+     * @param destination of the DefaultHostRoute
+     */
+    public DefaultHostRoute(IpAddress nexthop, IpPrefix destination) {
+        this.nexthop = nexthop;
+        this.destination = destination;
+    }
+
+    @Override
+    public IpAddress nexthop() {
+        return nexthop;
+    }
+
+    @Override
+    public IpPrefix destination() {
+        return destination;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("nexthop", nexthop)
+                .add("destination", destination).toString();
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(nexthop, destination);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultHostRoute) {
+            final DefaultHostRoute other = (DefaultHostRoute) obj;
+            return Objects.equals(this.nexthop, other.nexthop)
+                    && Objects.equals(this.destination, other.destination);
+        }
+        return false;
+    }
+
+}
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultSubnet.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultSubnet.java
new file mode 100644
index 0000000..c7c6e6f
--- /dev/null
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/DefaultSubnet.java
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.app.vtnrsc;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+import java.util.Objects;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpAddress.Version;
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Default implementation of Subnet interface .
+ */
+public final class DefaultSubnet implements Subnet {
+    private final SubnetId id;
+    private final String subnetName;
+    private final TenantNetworkId networkId;
+    private final TenantId tenantId;
+    private final Version ipVersion;
+    private final IpPrefix cidr;
+    private final IpAddress gatewayIp;
+    private final boolean dhcpEnabled;
+    private final boolean shared;
+    private final Mode ipV6AddressMode;
+    private final Mode ipV6RaMode;
+    private final Iterable<HostRoute> hostRoutes;
+    private final Iterable<AllocationPool> allocationPools;
+
+    /**
+     * Creates a subnet object.
+     *
+     * @param id subnet identifier
+     * @param subnetName the name of subnet
+     * @param networkId network identifier
+     * @param tenantId tenant identifier
+     * @param cidr the cidr
+     * @param gatewayIp gateway ip
+     * @param dhcpEnabled dhcp enabled or not
+     * @param shared indicates whether this network is shared across all
+     *            tenants, By default, only administrative user can change this
+     *            value
+     * @param hostRoutes a collection of host routes
+     * @param ipV6AddressMode ipV6AddressMode
+     * @param ipV6RaMode ipV6RaMode
+     * @param allocationPoolsIt a collection of allocationPools
+     */
+    public DefaultSubnet(SubnetId id, String subnetName,
+                         TenantNetworkId networkId, TenantId tenantId,
+                         Version ipVersion, IpPrefix cidr, IpAddress gatewayIp,
+                         boolean dhcpEnabled, boolean shared,
+                         Iterable<HostRoute> hostRoutes, Mode ipV6AddressMode,
+                         Mode ipV6RaMode,
+                         Iterable<AllocationPool> allocationPoolsIt) {
+        this.id = id;
+        this.subnetName = subnetName;
+        this.networkId = networkId;
+        this.tenantId = tenantId;
+        this.ipVersion = ipVersion;
+        this.cidr = cidr;
+        this.gatewayIp = gatewayIp;
+        this.dhcpEnabled = dhcpEnabled;
+        this.shared = shared;
+        this.ipV6AddressMode = ipV6AddressMode;
+        this.ipV6RaMode = ipV6RaMode;
+        this.hostRoutes = hostRoutes;
+        this.allocationPools = allocationPoolsIt;
+    }
+
+    @Override
+    public SubnetId id() {
+        return id;
+    }
+
+    @Override
+    public String subnetName() {
+        return subnetName;
+    }
+
+    @Override
+    public TenantNetworkId networkId() {
+        return networkId;
+    }
+
+    @Override
+    public TenantId tenantId() {
+        return tenantId;
+    }
+
+    @Override
+    public Version ipVersion() {
+        return ipVersion;
+    }
+
+    @Override
+    public IpPrefix cidr() {
+        return cidr;
+    }
+
+    @Override
+    public IpAddress gatewayIp() {
+        return gatewayIp;
+    }
+
+    @Override
+    public boolean dhcpEnabled() {
+        return dhcpEnabled;
+    }
+
+    @Override
+    public boolean shared() {
+        return shared;
+    }
+
+    @Override
+    public Iterable<HostRoute> hostRoutes() {
+        return hostRoutes;
+    }
+
+    @Override
+    public Mode ipV6AddressMode() {
+        return ipV6AddressMode;
+    }
+
+    @Override
+    public Mode ipV6RaMode() {
+        return ipV6RaMode;
+    }
+
+    @Override
+    public Iterable<AllocationPool> allocationPools() {
+        return allocationPools;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(id, subnetName, ipVersion, cidr, gatewayIp,
+                            dhcpEnabled, shared, tenantId);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultSubnet) {
+            final DefaultSubnet that = (DefaultSubnet) obj;
+            return Objects.equals(this.id, that.id)
+                    && Objects.equals(this.subnetName, that.subnetName)
+                    && Objects.equals(this.ipVersion, that.ipVersion)
+                    && Objects.equals(this.cidr, that.cidr)
+                    && Objects.equals(this.shared, that.shared)
+                    && Objects.equals(this.gatewayIp, that.gatewayIp)
+                    && Objects.equals(this.dhcpEnabled, that.dhcpEnabled);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this).add("id", id).add("subnetName", subnetName)
+                .add("ipVersion", ipVersion).add("cidr", cidr)
+                .add("shared", shared).add("gatewayIp", gatewayIp)
+                .add("dhcpEnabled", dhcpEnabled).toString();
+    }
+
+}
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/Subnet.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/Subnet.java
index f2a5726..87ae549 100644
--- a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/Subnet.java
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/Subnet.java
@@ -32,9 +32,9 @@
     }
 
     /**
-     * Returns the ID of the subnet.
+     * Returns the subnet identifier.
      *
-     * @return id
+     * @return identifier
      */
     SubnetId id();
 
@@ -46,18 +46,16 @@
     String subnetName();
 
     /**
-     * Returns the ID of the attached network.
+     * Returns the network identifier.
      *
-     * @return networkID
+     * @return the network identifier
      */
     TenantNetworkId networkId();
 
     /**
-     * Returns the The ID of the tenant who owns the network. Only
-     * administrative users can specify a tenant ID other than their own. You
-     * cannot change this value through authorization policies.
+     * Returns tenant identifier.
      *
-     * @return tenantID
+     * @return the tenant identifier
      */
     TenantId tenantId();
 
@@ -76,31 +74,31 @@
     IpPrefix cidr();
 
     /**
-     * Returns the gateway IP address..
+     * Returns the gateway IP address.
      *
-     * @return gatewayIP
+     * @return gatewayIp
      */
     IpAddress gatewayIp();
 
     /**
      * Returns true if DHCP is enabled and return false if DHCP is disabled.
      *
-     * @return dhcpEnabled
+     * @return true or false
      */
     boolean dhcpEnabled();
 
     /**
      * Indicates whether this tenantNetwork is shared across all tenants. By
-     * default,only administrative user can change this value.
+     * default, only administrative user can change this value.
      *
-     * @return shared
+     * @return true or false
      */
     boolean shared();
 
     /**
-     * Returns an iterable collections of hostRoutes.
+     * Returns a collection of hostRoutes.
      *
-     * @return hostRoutes collection
+     * @return a collection of hostRoutes
      */
     Iterable<HostRoute> hostRoutes();
 
@@ -108,7 +106,8 @@
      * Returns the ipV6AddressMode. A valid value is dhcpv6-stateful,
      * dhcpv6-stateless, or slaac.
      *
-     * @return ipV6AddressMode
+     * @return ipV6AddressMode whose value is dhcpv6-stateful, dhcpv6-stateless
+     *         or slaac
      */
     Mode ipV6AddressMode();
 
@@ -116,15 +115,15 @@
      * Returns the ipV6RaMode.A valid value is dhcpv6-stateful,
      * dhcpv6-stateless, or slaac.
      *
-     * @return ipV6RaMode
+     * @return ipV6RaMode whose value is dhcpv6-stateful, dhcpv6-stateless or
+     *         slaac
      */
     Mode ipV6RaMode();
 
     /**
-     * Returns an iterable collection of allocation_pools.
+     * Returns a collection of allocation_pools.
      *
-     * @return allocationPools collection
+     * @return a collection of allocationPools
      */
-
     Iterable<AllocationPool> allocationPools();
 }
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/SubnetId.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/SubnetId.java
index 73c2cb2..34a3a3c 100644
--- a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/SubnetId.java
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/SubnetId.java
@@ -20,7 +20,7 @@
 import java.util.Objects;
 
 /**
- * Immutable representation of a subnet identity.
+ * Immutable representation of a subnet identifier.
  */
 public final class SubnetId {
 
@@ -33,15 +33,24 @@
     }
 
     /**
-     * Creates a subnet identifier.
+     * Creates a Subnet identifier.
      *
-     * @param subnetId subnet identifier
-     * @return SubnetId SubnetId
+     * @param subnetId the subnet identifier
+     * @return the subnet identifier
      */
     public static SubnetId subnetId(String subnetId) {
         return new SubnetId(subnetId);
     }
 
+    /**
+     * Returns the subnet identifier.
+     *
+     * @return the subnet identifier
+     */
+    public String subnetId() {
+        return subnetId;
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(subnetId);
@@ -64,5 +73,4 @@
     public String toString() {
         return subnetId;
     }
-
 }
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/subnet/impl/SubnetManager.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/subnet/impl/SubnetManager.java
new file mode 100644
index 0000000..5214691
--- /dev/null
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/subnet/impl/SubnetManager.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.app.vtnrsc.subnet.impl;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static org.slf4j.LoggerFactory.getLogger;
+
+import java.util.Collections;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onlab.util.KryoNamespace;
+import org.onosproject.app.vtnrsc.Subnet;
+import org.onosproject.app.vtnrsc.SubnetId;
+import org.onosproject.app.vtnrsc.subnet.SubnetService;
+import org.onosproject.app.vtnrsc.tenantnetwork.TenantNetworkService;
+import org.onosproject.store.service.EventuallyConsistentMap;
+import org.onosproject.store.service.MultiValuedTimestamp;
+import org.onosproject.store.service.StorageService;
+import org.onosproject.store.service.WallClockTimestamp;
+import org.slf4j.Logger;
+
+/**
+ * Provides implementation of the Subnet service.
+ */
+@Component(immediate = true)
+@Service
+public class SubnetManager implements SubnetService {
+
+    private static final String SUBNET_ID_NULL = "Subnet ID cannot be null";
+    private static final String SUBNET_NOT_NULL = "Subnet cannot be null";
+
+    private final Logger log = getLogger(getClass());
+
+    private EventuallyConsistentMap<SubnetId, Subnet> subnetStore;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected StorageService storageService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected TenantNetworkService tenantNetworkService;
+
+    @Activate
+    public void activate() {
+        KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
+                .register(MultiValuedTimestamp.class);
+        subnetStore = storageService
+                .<SubnetId, Subnet>eventuallyConsistentMapBuilder()
+                .withName("all_subnet").withSerializer(serializer)
+                .withTimestampProvider((k, v) -> new WallClockTimestamp())
+                .build();
+
+        log.info("SubnetManager  started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        subnetStore.destroy();
+        log.info("SubnetManager stopped");
+    }
+
+    @Override
+    public Iterable<Subnet> getSubnets() {
+        return Collections.unmodifiableCollection(subnetStore.values());
+    }
+
+    @Override
+    public Subnet getSubnet(SubnetId subnetId) {
+        checkNotNull(subnetId, SUBNET_ID_NULL);
+        return subnetStore.get(subnetId);
+    }
+
+    @Override
+    public boolean exists(SubnetId subnetId) {
+        checkNotNull(subnetId, SUBNET_ID_NULL);
+        return subnetStore.containsKey(subnetId);
+    }
+
+    @Override
+    public boolean createSubnets(Iterable<Subnet> subnets) {
+        checkNotNull(subnets, SUBNET_NOT_NULL);
+        for (Subnet subnet : subnets) {
+            if (!tenantNetworkService.exists(subnet.networkId())) {
+                log.debug("The network identifier that the subnet {} belong to is not exist",
+                          subnet.networkId().toString(), subnet.id().toString());
+                return false;
+            }
+            subnetStore.put(subnet.id(), subnet);
+            if (!subnetStore.containsKey(subnet.id())) {
+                log.debug("The identified subnet whose identifier is {}  create failed",
+                          subnet.id().toString());
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean updateSubnets(Iterable<Subnet> subnets) {
+        checkNotNull(subnets, SUBNET_NOT_NULL);
+        if (subnets != null) {
+            for (Subnet subnet : subnets) {
+                if (!subnetStore.containsKey(subnet.id())) {
+                    log.debug("The subnet is not exist whose identifier is {}",
+                              subnet.id().toString());
+                    return false;
+                }
+
+                subnetStore.put(subnet.id(), subnet);
+
+                if (!subnet.equals(subnetStore.get(subnet.id()))) {
+                    log.debug("The subnet is updated failed whose identifier is {}",
+                              subnet.id().toString());
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public boolean removeSubnets(Iterable<SubnetId> subnetIds) {
+        checkNotNull(subnetIds, SUBNET_ID_NULL);
+        if (subnetIds != null) {
+            for (SubnetId subnetId : subnetIds) {
+                subnetStore.remove(subnetId);
+                if (subnetStore.containsKey(subnetId)) {
+                    log.debug("The subnet created is failed whose identifier is {}",
+                              subnetId.toString());
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+}
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/AllocationPoolsCodec.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/AllocationPoolsCodec.java
new file mode 100644
index 0000000..8d99c31
--- /dev/null
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/AllocationPoolsCodec.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.app.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.app.vtnrsc.AllocationPool;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Subnet AllocationPool codec.
+ */
+public final class AllocationPoolsCodec extends JsonCodec<AllocationPool> {
+
+    @Override
+    public ObjectNode encode(AllocationPool alocPool, CodecContext context) {
+        checkNotNull(alocPool, "AllocationPools cannot be null");
+        ObjectNode result = context.mapper().createObjectNode()
+                .put("start", alocPool.startIp().toString())
+                .put("end", alocPool.endIp().toString());
+        return result;
+    }
+
+}
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/HostRoutesCodec.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/HostRoutesCodec.java
new file mode 100644
index 0000000..915726e
--- /dev/null
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/HostRoutesCodec.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.app.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.app.vtnrsc.HostRoute;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Subnet HostRoute codec.
+ */
+public final class HostRoutesCodec extends JsonCodec<HostRoute> {
+
+    @Override
+    public ObjectNode encode(HostRoute hostRoute, CodecContext context) {
+        checkNotNull(hostRoute, "HostRoute cannot be null");
+        ObjectNode result = context.mapper().createObjectNode()
+                .put("nexthop", hostRoute.nexthop().toString())
+                .put("destination", hostRoute.destination().toString());
+        return result;
+    }
+
+}
diff --git a/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/SubnetCodec.java b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/SubnetCodec.java
new file mode 100644
index 0000000..f14ec8e
--- /dev/null
+++ b/apps/vtnrsc/src/main/java/org/onosproject/app/vtnrsc/web/SubnetCodec.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.app.vtnrsc.web;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import org.onosproject.app.vtnrsc.Subnet;
+import org.onosproject.codec.CodecContext;
+import org.onosproject.codec.JsonCodec;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Subnet JSON codec.
+ */
+public final class SubnetCodec extends JsonCodec<Subnet> {
+    @Override
+    public ObjectNode encode(Subnet subnet, CodecContext context) {
+        checkNotNull(subnet, "Subnet cannot be null");
+        ObjectNode result = context.mapper().createObjectNode()
+                .put("id", subnet.id().toString())
+                .put("gate_ip", subnet.gatewayIp().toString())
+                .put("network_id", subnet.networkId().toString())
+                .put("name", subnet.subnetName().toString())
+                .put("ip_version", subnet.ipVersion().toString())
+                .put("cidr", subnet.cidr().toString())
+                .put("shared", subnet.shared())
+                .put("enabled_dchp", subnet.dhcpEnabled())
+                .put("tenant_id", subnet.tenantId().toString());
+        result.set("alloction_pools", new AllocationPoolsCodec().encode(subnet
+                .allocationPools(), context));
+        result.set("host_routes",
+                   new HostRoutesCodec().encode(subnet.hostRoutes(), context));
+        return result;
+    }
+}
diff --git a/apps/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java b/apps/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java
new file mode 100644
index 0000000..aa73d26
--- /dev/null
+++ b/apps/vtnweb/src/main/java/org/onosproject/vtnweb/resources/SubnetWebResource.java
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.vtnweb.resources;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+import static javax.ws.rs.core.Response.Status.INTERNAL_SERVER_ERROR;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentMap;
+
+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.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpAddress.Version;
+import org.onlab.packet.IpPrefix;
+import org.onlab.util.ItemNotFoundException;
+import org.onosproject.app.vtnrsc.AllocationPool;
+import org.onosproject.app.vtnrsc.DefaultAllocationPool;
+import org.onosproject.app.vtnrsc.DefaultHostRoute;
+import org.onosproject.app.vtnrsc.DefaultSubnet;
+import org.onosproject.app.vtnrsc.HostRoute;
+import org.onosproject.app.vtnrsc.Subnet;
+import org.onosproject.app.vtnrsc.Subnet.Mode;
+import org.onosproject.app.vtnrsc.SubnetId;
+import org.onosproject.app.vtnrsc.TenantId;
+import org.onosproject.app.vtnrsc.TenantNetworkId;
+import org.onosproject.app.vtnrsc.subnet.SubnetService;
+import org.onosproject.app.vtnrsc.web.SubnetCodec;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.Maps;
+
+@Path("subnets")
+public class SubnetWebResource extends AbstractWebResource {
+    private final Logger log = LoggerFactory.getLogger(SubnetWebResource.class);
+    public static final String SUBNET_NOT_CREATE = "Subnets is failed to create!";
+    public static final String SUBNET_NOT_FOUND = "Subnets is failed to update!";
+    public static final String JSON_NOT_NULL = "JsonNode can not be null";
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response listSubnets() {
+        Iterable<Subnet> subnets = get(SubnetService.class).getSubnets();
+        ObjectNode result = new ObjectMapper().createObjectNode();
+        result.set("subnets", new SubnetCodec().encode(subnets, this));
+        return ok(result.toString()).build();
+    }
+
+    @GET
+    @Path("{subnetUUID}")
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response getSubnet(@PathParam("subnetUUID") String id) {
+
+        if (!get(SubnetService.class).exists(SubnetId.subnetId(id))) {
+            return ok("the subnet does not exists").build();
+        }
+        Subnet sub = nullIsNotFound(get(SubnetService.class)
+                                            .getSubnet(SubnetId.subnetId(id)),
+                                    SUBNET_NOT_FOUND);
+
+        ObjectNode result = new ObjectMapper().createObjectNode();
+        result.set("subnet", new SubnetCodec().encode(sub, this));
+        return ok(result.toString()).build();
+    }
+
+    @POST
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response createSubnet(final InputStream input) {
+
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            JsonNode subnode = mapper.readTree(input);
+            Iterable<Subnet> subnets = createOrUpdateByInputStream(subnode);
+            Boolean result = nullIsNotFound((get(SubnetService.class)
+                                                    .createSubnets(subnets)),
+                                            SUBNET_NOT_CREATE);
+
+            if (!result) {
+                return Response.status(204).entity(SUBNET_NOT_CREATE).build();
+            }
+            return Response.status(202).entity(result.toString()).build();
+        } catch (Exception e) {
+            return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+
+    @PUT
+    @Path("{subnetUUID}")
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response updateSubnet(@PathParam("id") String id,
+                                 final InputStream input) {
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            JsonNode subnode = mapper.readTree(input);
+            Iterable<Subnet> subnets = createOrUpdateByInputStream(subnode);
+            Boolean result = nullIsNotFound(get(SubnetService.class)
+                    .updateSubnets(subnets), SUBNET_NOT_FOUND);
+            if (!result) {
+                return Response.status(204).entity(SUBNET_NOT_FOUND).build();
+            }
+            return Response.status(203).entity(result.toString()).build();
+        } catch (Exception e) {
+            return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+
+    @Path("{subnetUUID}")
+    @DELETE
+    public Response deleteSingleSubnet(@PathParam("subnetUUID") String id)
+            throws IOException {
+        try {
+            SubnetId subId = SubnetId.subnetId(id);
+            Set<SubnetId> subIds = new HashSet<SubnetId>();
+            subIds.add(subId);
+            get(SubnetService.class).removeSubnets(subIds);
+            return Response.status(201).entity("SUCCESS").build();
+        } catch (Exception e) {
+            return Response.status(INTERNAL_SERVER_ERROR).entity(e.toString())
+                    .build();
+        }
+    }
+
+    private Iterable<Subnet> createOrUpdateByInputStream(JsonNode subnode) {
+        checkNotNull(subnode, JSON_NOT_NULL);
+        Iterable<Subnet> subnets = null;
+        JsonNode subnetNodes = subnode.get("subnets");
+        if (subnetNodes == null) {
+            subnetNodes = subnode.get("subnet");
+        }
+        log.debug("subnetNodes is {}", subnetNodes.toString());
+        if (subnetNodes.isArray()) {
+            subnets = changeJsonToSubs(subnetNodes);
+        } else {
+            subnets = changeJsonToSub(subnetNodes);
+        }
+        return subnets;
+    }
+
+    /**
+     * Returns a collection of subnets from subnetNodes.
+     *
+     * @param subnetNodes the subnet json node
+     * @return subnets a collection of subnets
+     */
+    public Iterable<Subnet> changeJsonToSubs(JsonNode subnetNodes) {
+        checkNotNull(subnetNodes, JSON_NOT_NULL);
+        Map<SubnetId, Subnet> subMap = new HashMap<SubnetId, Subnet>();
+        for (JsonNode subnetNode : subnetNodes) {
+            if (subnetNode.hasNonNull("id")) {
+                return null;
+            }
+            SubnetId id = SubnetId.subnetId(subnetNode.get("id").asText());
+            String subnetName = subnetNode.get("name").asText();
+            TenantId tenantId = TenantId.tenantId(subnetNode.get("tenant_id")
+                    .asText());
+            TenantNetworkId networkId = TenantNetworkId.networkId(subnetNode
+                    .get("network_id").asText());
+            Version ipVersion = Version.valueOf(subnetNode.get("ip_version")
+                    .asText());
+            IpPrefix cidr = IpPrefix.valueOf(subnetNode.get("cidr").asText());
+            IpAddress gatewayIp = IpAddress.valueOf(subnetNode
+                    .get("gateway_ip").asText());
+            Boolean dhcpEnabled = subnetNode.get("enable_dhcp").asBoolean();
+            Boolean shared = subnetNode.get("shared").asBoolean();
+            JsonNode hostRoutes = subnetNode.get("host_routes");
+            Iterable<HostRoute> hostRoutesIt = jsonNodeToHostRoutes(hostRoutes);
+            JsonNode allocationPools = subnetNode.get("allocation_pools");
+            Iterable<AllocationPool> allocationPoolsIt = jsonNodeToAllocationPools(allocationPools);
+            Mode ipV6AddressMode = Mode.valueOf(subnetNode
+                    .get("ipv6_address_mode").asText());
+            Mode ipV6RaMode = Mode.valueOf(subnetNode.get("ipv6_ra_mode")
+                    .asText());
+            Subnet subnet = new DefaultSubnet(id, subnetName, networkId,
+                                              tenantId, ipVersion, cidr,
+                                              gatewayIp, dhcpEnabled, shared,
+                                              hostRoutesIt, ipV6AddressMode,
+                                              ipV6RaMode, allocationPoolsIt);
+            subMap.put(id, subnet);
+        }
+        return Collections.unmodifiableCollection(subMap.values());
+    }
+
+    /**
+     * Returns a collection of subnets from subnetNodes.
+     *
+     * @param subnetNodes the subnet json node
+     * @return subnets a collection of subnets
+     */
+    public Iterable<Subnet> changeJsonToSub(JsonNode subnetNodes) {
+        checkNotNull(subnetNodes, JSON_NOT_NULL);
+        Map<SubnetId, Subnet> subMap = new HashMap<SubnetId, Subnet>();
+        SubnetId id = SubnetId.subnetId(subnetNodes.get("id").asText());
+        String subnetName = subnetNodes.get("name").asText();
+        TenantId tenantId = TenantId.tenantId(subnetNodes.get("tenant_id")
+                .asText());
+        TenantNetworkId networkId = TenantNetworkId.networkId(subnetNodes
+                .get("network_id").asText());
+        Version ipVersion = Version.valueOf(subnetNodes.get("ip_version")
+                .asText());
+        IpPrefix cidr = IpPrefix.valueOf(subnetNodes.get("cidr").asText());
+        IpAddress gatewayIp = IpAddress.valueOf(subnetNodes.get("gateway_ip")
+                .asText());
+        Boolean dhcpEnabled = subnetNodes.get("enable_dhcp").asBoolean();
+        Boolean shared = subnetNodes.get("shared").asBoolean();
+        JsonNode hostRoutes = subnetNodes.get("host_routes");
+        Iterable<HostRoute> hostRoutesIt = jsonNodeToHostRoutes(hostRoutes);
+        JsonNode allocationPools = subnetNodes.get("allocation_pools");
+        Iterable<AllocationPool> allocationPoolsIt = jsonNodeToAllocationPools(allocationPools);
+        Mode ipV6AddressMode = Mode.valueOf(subnetNodes
+                .get("ipv6_address_mode").asText());
+        Mode ipV6RaMode = Mode
+                .valueOf(subnetNodes.get("ipv6_ra_mode").asText());
+        Subnet subnet = new DefaultSubnet(id, subnetName, networkId, tenantId,
+                                          ipVersion, cidr, gatewayIp,
+                                          dhcpEnabled, shared, hostRoutesIt,
+                                          ipV6AddressMode, ipV6RaMode,
+                                          allocationPoolsIt);
+        subMap.put(id, subnet);
+        return Collections.unmodifiableCollection(subMap.values());
+    }
+
+    /**
+     * Changes JsonNode alocPools to a collection of the alocPools.
+     *
+     * @param allocationPools the allocationPools JsonNode
+     * @return a collection of allocationPools
+     */
+    public Iterable<AllocationPool> jsonNodeToAllocationPools(JsonNode allocationPools) {
+        checkNotNull(allocationPools, JSON_NOT_NULL);
+        ConcurrentMap<Integer, AllocationPool> alocplMaps = Maps
+                .newConcurrentMap();
+        Integer i = 0;
+        for (JsonNode node : allocationPools) {
+            IpAddress startIp = IpAddress.valueOf(node.get("start").asText());
+            IpAddress endIp = IpAddress.valueOf(node.get("end").asText());
+            AllocationPool alocPls = new DefaultAllocationPool(startIp, endIp);
+            alocplMaps.putIfAbsent(i, alocPls);
+            i++;
+        }
+        return Collections.unmodifiableCollection(alocplMaps.values());
+    }
+
+    /**
+     * Changes hostRoutes JsonNode to a collection of the hostRoutes.
+     *
+     * @param hostRoutes the hostRoutes json node
+     * @return a collection of hostRoutes
+     */
+    public Iterable<HostRoute> jsonNodeToHostRoutes(JsonNode hostRoutes) {
+        checkNotNull(hostRoutes, JSON_NOT_NULL);
+        ConcurrentMap<Integer, HostRoute> hostRouteMaps = Maps
+                .newConcurrentMap();
+        Integer i = 0;
+        for (JsonNode node : hostRoutes) {
+            IpAddress nexthop = IpAddress.valueOf(node.get("nexthop").asText());
+            IpPrefix destination = IpPrefix.valueOf(node.get("destination")
+                    .asText());
+            HostRoute hostRoute = new DefaultHostRoute(nexthop, destination);
+            hostRouteMaps.putIfAbsent(i, hostRoute);
+            i++;
+        }
+        return Collections.unmodifiableCollection(hostRouteMaps.values());
+    }
+
+    /**
+     * Returns the specified item if that items is null; otherwise throws not
+     * found exception.
+     *
+     * @param item item to check
+     * @param <T> item type
+     * @param message not found message
+     * @return item if not null
+     * @throws org.onlab.util.ItemNotFoundException if item is null
+     */
+    protected <T> T nullIsNotFound(T item, String message) {
+        if (item == null) {
+            throw new ItemNotFoundException(message);
+        }
+        return item;
+    }
+
+}
diff --git a/apps/vtnweb/src/main/webapp/WEB-INF/web.xml b/apps/vtnweb/src/main/webapp/WEB-INF/web.xml
index c5547ba..4cc1245 100644
--- a/apps/vtnweb/src/main/webapp/WEB-INF/web.xml
+++ b/apps/vtnweb/src/main/webapp/WEB-INF/web.xml
@@ -30,7 +30,9 @@
         <init-param>
             <param-name>com.sun.jersey.config.property.classnames</param-name>
             <param-value>
-                org.onosproject.vtnweb.resources.TenantNetworkWebResource
+                org.onosproject.vtnweb.resources.TenantNetworkWebResource,
+                org.onosproject.vtnweb.resources.SubnetWebResource,
+                org.onosproject.vtnweb.resources.VirtualPortWebResource
             </param-value>
         </init-param>
         <load-on-startup>1</load-on-startup>