Move routing from incubator to a separate app

Change-Id: I961d10af99c572b1f8d9b3d37c6f52dd04422007
diff --git a/apps/route-service/api/BUCK b/apps/route-service/api/BUCK
new file mode 100644
index 0000000..68eeacf
--- /dev/null
+++ b/apps/route-service/api/BUCK
@@ -0,0 +1,13 @@
+COMPILE_DEPS = [
+    '//lib:CORE_DEPS',
+]
+
+TEST_DEPS = [
+    '//lib:TEST',
+    '//core/api:onos-api-tests',
+]
+
+osgi_jar_with_tests (
+    deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
+)
diff --git a/apps/route-service/api/pom.xml b/apps/route-service/api/pom.xml
new file mode 100644
index 0000000..f136855
--- /dev/null
+++ b/apps/route-service/api/pom.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2015-present Open Networking Foundation
+  ~
+  ~ 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.
+  -->
+<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>
+        <artifactId>onos-app-route-service</artifactId>
+        <groupId>org.onosproject</groupId>
+        <version>1.11.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>onos-app-route-service-api</artifactId>
+    <packaging>bundle</packaging>
+
+    <url>http://onosproject.org</url>
+
+    <description>Route Service Application API</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-incubator-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-api</artifactId>
+            <classifier>tests</classifier>
+            <scope>test</scope>
+        </dependency>
+
+    </dependencies>
+
+
+</project>
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/InternalRouteEvent.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/InternalRouteEvent.java
new file mode 100644
index 0000000..899e54f
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/InternalRouteEvent.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onosproject.event.AbstractEvent;
+
+/**
+ * Route event for signalling between the store and the manager.
+ */
+public class InternalRouteEvent extends
+        AbstractEvent<InternalRouteEvent.Type, RouteSet> {
+
+    /**
+     * Internal route event type.
+     */
+    public enum Type {
+        /**
+         * Indicates a route was added to the store.
+         */
+        ROUTE_ADDED,
+
+        /**
+         * Indicates a route was removed from the store.
+         */
+        ROUTE_REMOVED
+    }
+
+    /**
+     * Creates a new internal route event.
+     *
+     * @param type route event type
+     * @param subject route set
+     */
+    public InternalRouteEvent(Type type, RouteSet subject) {
+        super(type, subject);
+    }
+
+    protected InternalRouteEvent(Type type, RouteSet subject, long time) {
+        super(type, subject, time);
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/NextHopData.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/NextHopData.java
new file mode 100644
index 0000000..f3b7da7
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/NextHopData.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onlab.packet.MacAddress;
+import org.onosproject.net.ConnectPoint;
+import org.onosproject.net.Host;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Stores next hop information.
+ */
+public class NextHopData {
+
+    private final MacAddress mac;
+    private final ConnectPoint location;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param mac MAC address
+     * @param location Connect point
+     */
+    public NextHopData(MacAddress mac, ConnectPoint location) {
+        this.mac = mac;
+        this.location = location;
+    }
+
+    /**
+     * Returns the MAC address.
+     *
+     * @return MAC address
+     */
+    public MacAddress mac() {
+        return mac;
+    }
+
+    /**
+     * Returns the location.
+     *
+     * @return Connect point
+     */
+    public ConnectPoint location() {
+        return location;
+    }
+
+    /**
+     * Creates a new instance from a host.
+     *
+     * @param host Host information
+     * @return NextHopData instance
+     */
+    public static NextHopData fromHost(Host host) {
+        return new NextHopData(host.mac(), host.location());
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mac, location);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof NextHopData)) {
+            return false;
+        }
+
+        NextHopData that = (NextHopData) other;
+
+        return Objects.equals(this.mac, that.mac) &&
+                Objects.equals(this.location, that.location);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("mac", mac)
+                .add("location", location)
+                .toString();
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/ResolvedRoute.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/ResolvedRoute.java
new file mode 100644
index 0000000..828827d
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/ResolvedRoute.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ConnectPoint;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Represents a route with the next hop MAC address resolved.
+ */
+public class ResolvedRoute {
+
+    private final Route route;
+    private final MacAddress nextHopMac;
+    private final VlanId nextHopVlan;
+    private final ConnectPoint location;
+
+    /**
+     * Creates a new resolved route.
+     *
+     * @param route input route
+     * @param nextHopMac next hop MAC address
+     * @param location connect point where the next hop connects to
+     */
+    public ResolvedRoute(Route route, MacAddress nextHopMac, ConnectPoint location) {
+        this(route, nextHopMac, VlanId.NONE, location);
+    }
+
+    /**
+     * Creates a new resolved route.
+     *
+     * @param route input route
+     * @param nextHopMac next hop MAC address
+     * @param nextHopVlan next hop VLAN ID
+     * @param location connect point where the next hop connects to
+     */
+    public ResolvedRoute(Route route, MacAddress nextHopMac, VlanId nextHopVlan,
+                         ConnectPoint location) {
+        this.route = route;
+        this.nextHopMac = nextHopMac;
+        this.nextHopVlan = nextHopVlan;
+        this.location = location;
+    }
+
+    /**
+     * Returns the original route.
+     *
+     * @return route
+     */
+    public Route route() {
+        return route;
+    }
+
+    /**
+     * Returns the IP prefix.
+     *
+     * @return IP prefix
+     */
+    public IpPrefix prefix() {
+        return route.prefix();
+    }
+
+    /**
+     * Returns the next hop IP address.
+     *
+     * @return IP address
+     */
+    public IpAddress nextHop() {
+        return route.nextHop();
+    }
+
+    /**
+     * Returns the next hop MAC address.
+     *
+     * @return MAC address
+     */
+    public MacAddress nextHopMac() {
+        return nextHopMac;
+    }
+
+    /**
+     * Returns the next hop VLAN ID.
+     *
+     * @return VLAN ID
+     */
+    public VlanId nextHopVlan() {
+        return nextHopVlan;
+    }
+
+    /**
+     * Returns the next hop location.
+     *
+     * @return connect point where the next hop attaches to
+     */
+    public ConnectPoint location() {
+        return location;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(route, nextHopMac, nextHopVlan, location);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof ResolvedRoute)) {
+            return false;
+        }
+
+        ResolvedRoute that = (ResolvedRoute) other;
+
+        return Objects.equals(this.route, that.route) &&
+                Objects.equals(this.nextHopMac, that.nextHopMac) &&
+                Objects.equals(this.nextHopVlan, that.nextHopVlan) &&
+                Objects.equals(this.location, that.location);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("route", route)
+                .add("nextHopMac", nextHopMac)
+                .add("nextHopVlan", nextHopVlan)
+                .add("location", location)
+                .toString();
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/Route.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/Route.java
new file mode 100644
index 0000000..f542252
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/Route.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.cluster.NodeId;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Represents a route.
+ */
+public class Route {
+
+    private static final String VERSION_MISMATCH =
+            "Prefix and next hop must be in the same address family";
+
+    private static final NodeId UNDEFINED = new NodeId("-");
+
+    /**
+     * Source of the route.
+     */
+    public enum Source {
+        /**
+         * Route came from the iBGP route source.
+         */
+        BGP,
+
+        /**
+         * Route came from the FPM route source.
+         */
+        FPM,
+
+        /**
+         * Route can from the static route source.
+         */
+        STATIC,
+
+        /**
+         * Route source was not defined.
+         */
+        UNDEFINED
+    }
+
+    private final Source source;
+    private final IpPrefix prefix;
+    private final IpAddress nextHop;
+    private final NodeId sourceNode;
+
+    /**
+     * Creates a route.
+     *
+     * @param source route source
+     * @param prefix IP prefix
+     * @param nextHop next hop IP address
+     */
+    public Route(Source source, IpPrefix prefix, IpAddress nextHop) {
+        this(source, prefix, nextHop, UNDEFINED);
+    }
+
+    /**
+     * Creates a route.
+     *
+     * @param source route source
+     * @param prefix IP prefix
+     * @param nextHop next hop IP address
+     * @param sourceNode ONOS node the route was sourced from
+     */
+    public Route(Source source, IpPrefix prefix, IpAddress nextHop, NodeId sourceNode) {
+        checkNotNull(prefix);
+        checkNotNull(nextHop);
+        checkArgument(prefix.version().equals(nextHop.version()), VERSION_MISMATCH);
+
+        this.source = checkNotNull(source);
+        this.prefix = prefix;
+        this.nextHop = nextHop;
+        this.sourceNode = checkNotNull(sourceNode);
+    }
+
+    /**
+     * Returns the route source.
+     *
+     * @return route source
+     */
+    public Source source() {
+        return source;
+    }
+
+    /**
+     * Returns the IP prefix of the route.
+     *
+     * @return IP prefix
+     */
+    public IpPrefix prefix() {
+        return prefix;
+    }
+
+    /**
+     * Returns the next hop IP address.
+     *
+     * @return next hop
+     */
+    public IpAddress nextHop() {
+        return nextHop;
+    }
+
+    /**
+     * Returns the ONOS node the route was sourced from.
+     *
+     * @return ONOS node ID
+     */
+    public NodeId sourceNode() {
+        return sourceNode;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(prefix, nextHop);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof Route)) {
+            return false;
+        }
+
+        Route that = (Route) other;
+
+        return Objects.equals(this.prefix, that.prefix) &&
+                Objects.equals(this.nextHop, that.nextHop);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("prefix", prefix)
+                .add("nextHop", nextHop)
+                .toString();
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteAdminService.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteAdminService.java
new file mode 100644
index 0000000..8886169
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteAdminService.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import java.util.Collection;
+
+/**
+ * Service allowing mutation of unicast routing state.
+ */
+public interface RouteAdminService extends RouteService {
+
+    /**
+     * Updates the given routes in the route service.
+     *
+     * @param routes collection of routes to update
+     */
+    void update(Collection<Route> routes);
+
+    /**
+     * Withdraws the given routes from the route service.
+     *
+     * @param routes collection of routes to withdraw
+     */
+    void withdraw(Collection<Route> routes);
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteConfig.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteConfig.java
new file mode 100644
index 0000000..cc77b59
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteConfig.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ImmutableSet;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+
+import java.util.Set;
+
+/**
+ * Route configuration object for Route Service.
+ */
+public class RouteConfig extends Config<ApplicationId> {
+    private static final String PREFIX = "prefix";
+    private static final String NEXTHOP = "nextHop";
+
+    /**
+     * Returns all routes in this configuration.
+     *
+     * @return A set of route.
+     */
+    public Set<Route> getRoutes() {
+        ImmutableSet.Builder<Route> routes = ImmutableSet.builder();
+        array.forEach(route -> {
+            try {
+                IpPrefix prefix = IpPrefix.valueOf(route.path(PREFIX).asText());
+                IpAddress nextHop = IpAddress.valueOf(route.path(NEXTHOP).asText());
+                routes.add(new Route(Route.Source.STATIC, prefix, nextHop));
+            } catch (IllegalArgumentException e) {
+                // Ignores routes that cannot be parsed correctly
+            }
+        });
+        return routes.build();
+    }
+
+    @Override
+    public boolean isValid() {
+        array.forEach(routeNode -> {
+            if (!routeNode.isObject()) {
+                throw new IllegalArgumentException("Not object node");
+            }
+            ObjectNode route = (ObjectNode) routeNode;
+            isIpPrefix(route, PREFIX, FieldPresence.MANDATORY);
+            isIpAddress(route, NEXTHOP, FieldPresence.MANDATORY);
+        });
+        return true;
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteEvent.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteEvent.java
new file mode 100644
index 0000000..0428beb
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteEvent.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.joda.time.LocalDateTime;
+import org.onosproject.event.AbstractEvent;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Describes an event about a route.
+ */
+public class RouteEvent extends AbstractEvent<RouteEvent.Type, ResolvedRoute> {
+
+    private final ResolvedRoute prevSubject;
+    private final Collection<ResolvedRoute> alternativeRoutes;
+
+    /**
+     * Route event type.
+     */
+    public enum Type {
+
+        /**
+         * Route is new and the next hop is resolved.
+         * <p>
+         * The subject of this event should be the route being added.
+         * The prevSubject of this event should be null.
+         * </p>
+         */
+        ROUTE_ADDED,
+
+        /**
+         * Route has updated information.
+         * <p>
+         * The subject of this event should be the new route.
+         * The prevSubject of this event should be the old route.
+         * </p>
+         */
+        ROUTE_UPDATED,
+
+        /**
+         * Route was removed or the next hop becomes unresolved.
+         * <p>
+         * The subject of this event should be the route being removed.
+         * The prevSubject of this event should be null.
+         * </p>
+         */
+        ROUTE_REMOVED,
+
+        /**
+         * The set of alternative routes for the subject's prefix has changed,
+         * but the best route is still the same.
+         * <p>
+         * The subject is the best route for the prefix (which has already been
+         * notified in a previous event).
+         * The prevSubject of this event is null.
+         * The alternatives contains the new set of alternative routes.
+         * </p>
+         */
+        ALTERNATIVE_ROUTES_CHANGED
+    }
+
+    /**
+     * Creates a new route event without specifying previous subject.
+     *
+     * @param type event type
+     * @param subject event subject
+     */
+    public RouteEvent(Type type, ResolvedRoute subject) {
+        this(type, subject, null, Collections.emptySet());
+    }
+
+    /**
+     * Creates a new route event without specifying previous subject.
+     *
+     * @param type event type
+     * @param subject event subject
+     * @param alternatives alternative routes for subject's prefix
+     */
+    public RouteEvent(Type type, ResolvedRoute subject, Collection<ResolvedRoute> alternatives) {
+        this(type, subject, null, alternatives);
+    }
+
+    /**
+     * Creates a new route event.
+     *
+     * @param type event type
+     * @param subject event subject
+     * @param time event time
+     */
+    protected RouteEvent(Type type, ResolvedRoute subject, long time) {
+        super(type, subject, time);
+        this.prevSubject = null;
+
+        this.alternativeRoutes = Collections.emptySet();
+    }
+
+    /**
+     * Creates a new route event with previous subject.
+     *
+     * @param type event type
+     * @param subject event subject
+     * @param prevSubject previous subject
+     */
+    public RouteEvent(Type type, ResolvedRoute subject, ResolvedRoute prevSubject) {
+        this(type, subject, prevSubject, Collections.emptySet());
+    }
+
+    /**
+     * Creates a new route event with a previous subject and alternative routes.
+     *
+     * @param type event type
+     * @param subject event subject
+     * @param prevSubject previous subject
+     * @param alternatives alternative routes for subject's prefix
+     */
+    public RouteEvent(Type type, ResolvedRoute subject, ResolvedRoute prevSubject,
+                      Collection<ResolvedRoute> alternatives) {
+        super(type, subject);
+        this.prevSubject = prevSubject;
+        this.alternativeRoutes = alternatives;
+    }
+
+    /**
+     * Returns the previous subject of the event.
+     *
+     * @return previous subject to which this event pertains
+     */
+    public ResolvedRoute prevSubject() {
+        return prevSubject;
+    }
+
+    /**
+     * Returns the set of alternative routes for the subject's prefix.
+     *
+     * @return alternative routes
+     */
+    public Collection<ResolvedRoute> alternatives() {
+        return alternativeRoutes;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(subject(), type(), prevSubject(), alternativeRoutes);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof RouteEvent)) {
+            return false;
+        }
+
+        RouteEvent that = (RouteEvent) other;
+
+        return Objects.equals(this.subject(), that.subject()) &&
+                Objects.equals(this.type(), that.type()) &&
+                Objects.equals(this.prevSubject, that.prevSubject) &&
+                Objects.equals(this.alternativeRoutes, that.alternativeRoutes);
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("time", new LocalDateTime(time()))
+                .add("type", type())
+                .add("subject", subject())
+                .add("prevSubject", prevSubject)
+                .add("alternatives", alternativeRoutes)
+                .toString();
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteInfo.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteInfo.java
new file mode 100644
index 0000000..0969162
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteInfo.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import com.google.common.annotations.Beta;
+import org.onlab.packet.IpPrefix;
+
+import java.util.Objects;
+import java.util.Optional;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * Routing information for a given prefix.
+ */
+@Beta
+public class RouteInfo {
+
+    private final IpPrefix prefix;
+    private final ResolvedRoute bestRoute;
+    private final Set<ResolvedRoute> allRoutes;
+
+    /**
+     * Creates a new route info object.
+     *
+     * @param prefix IP prefix
+     * @param bestRoute best route for this prefix if one exists
+     * @param allRoutes all known routes for this prefix
+     */
+    @Beta
+    public RouteInfo(IpPrefix prefix, ResolvedRoute bestRoute, Set<ResolvedRoute> allRoutes) {
+        this.prefix = checkNotNull(prefix);
+        this.bestRoute = bestRoute;
+        this.allRoutes = checkNotNull(allRoutes);
+    }
+
+    /**
+     * Returns the IP prefix.
+     *
+     * @return IP prefix
+     */
+    public IpPrefix prefix() {
+        return prefix;
+    }
+
+    /**
+     * Returns the best route for this prefix if one exists.
+     *
+     * @return optional best route
+     */
+    public Optional<ResolvedRoute> bestRoute() {
+        return Optional.ofNullable(bestRoute);
+    }
+
+    /**
+     * Returns all routes for this prefix.
+     *
+     * @return all routes
+     */
+    public Set<ResolvedRoute> allRoutes() {
+        return allRoutes;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(prefix, bestRoute, allRoutes);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof RouteInfo)) {
+            return false;
+        }
+
+        RouteInfo that = (RouteInfo) other;
+
+        return Objects.equals(this.prefix, that.prefix) &&
+                Objects.equals(this.bestRoute, that.bestRoute) &&
+                Objects.equals(this.allRoutes, that.allRoutes);
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteListener.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteListener.java
new file mode 100644
index 0000000..063f335
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteListener.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onosproject.event.EventListener;
+
+/**
+ * Listener for route events.
+ */
+public interface RouteListener extends EventListener<RouteEvent> {
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteService.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteService.java
new file mode 100644
index 0000000..c626e47
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteService.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onlab.packet.IpAddress;
+import org.onosproject.event.ListenerService;
+
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Unicast IP route service.
+ */
+public interface RouteService extends ListenerService<RouteEvent, RouteListener> {
+
+    /**
+     * Returns information about all routes in the given route table.
+     *
+     * @param id route table ID
+     * @return collection of route information
+     */
+    Collection<RouteInfo> getRoutes(RouteTableId id);
+
+    /**
+     * Returns the set of route tables in the system.
+     *
+     * @return collection of route table IDs.
+     */
+    Collection<RouteTableId> getRouteTables();
+
+    /**
+     * Performs a longest prefix lookup on the given IP address.
+     *
+     * @param ip IP address to look up
+     * @return most specific matching route, if one exists
+     */
+    Optional<ResolvedRoute> longestPrefixLookup(IpAddress ip);
+
+    /**
+     * Performs a longest prefix match on the given IP address. The call will
+     * return the route with the most specific prefix that contains the given
+     * IP address.
+     *
+     * @param ip IP address
+     * @return longest prefix matched route
+     * @deprecated in Kingfisher release. Use {{@link #longestPrefixLookup(IpAddress)}}
+     * instead.
+     */
+    @Deprecated
+    Route longestPrefixMatch(IpAddress ip);
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteSet.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteSet.java
new file mode 100644
index 0000000..f464e5d
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteSet.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import com.google.common.collect.ImmutableSet;
+import org.onlab.packet.IpPrefix;
+
+import java.util.Objects;
+import java.util.Set;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * A set of routes for a particular prefix in a route table.
+ */
+public class RouteSet {
+    private final RouteTableId tableId;
+
+    private final IpPrefix prefix;
+    private final Set<Route> routes;
+
+    /**
+     * Creates a new route set.
+     *
+     * @param tableId route table ID
+     * @param prefix IP prefix
+     * @param routes routes for the given prefix
+     */
+    public RouteSet(RouteTableId tableId, IpPrefix prefix, Set<Route> routes) {
+        this.tableId = checkNotNull(tableId);
+        this.prefix = checkNotNull(prefix);
+        this.routes = ImmutableSet.copyOf(checkNotNull(routes));
+    }
+
+    /**
+     * Returns the route table ID.
+     *
+     * @return route table ID
+     */
+    public RouteTableId tableId() {
+        return tableId;
+    }
+
+    /**
+     * Returns the IP prefix.
+     *
+     * @return IP prefix
+     */
+    public IpPrefix prefix() {
+        return prefix;
+    }
+
+    /**
+     * Returns the set of routes.
+     *
+     * @return routes
+     */
+    public Set<Route> routes() {
+        return routes;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(tableId, prefix, routes);
+    }
+
+    @Override
+    public boolean equals(Object other) {
+        if (this == other) {
+            return true;
+        }
+
+        if (!(other instanceof RouteSet)) {
+            return false;
+        }
+
+        RouteSet that = (RouteSet) other;
+
+        return Objects.equals(this.tableId, that.tableId) &&
+                Objects.equals(this.prefix, that.prefix) &&
+                Objects.equals(this.routes, that.routes);
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteStore.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteStore.java
new file mode 100644
index 0000000..6866762
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteStore.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import com.google.common.annotations.Beta;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.store.Store;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Unicast route store.
+ */
+public interface RouteStore extends Store<InternalRouteEvent, RouteStoreDelegate> {
+
+    /**
+     * Adds or updates the given route in the store.
+     *
+     * @param route route to add or update
+     */
+    void updateRoute(Route route);
+
+    /**
+     * Removes the given route from the store.
+     *
+     * @param route route to remove
+     */
+    void removeRoute(Route route);
+
+    /**
+     * Returns the IDs for all route tables in the store.
+     *
+     * @return route table IDs
+     */
+    Set<RouteTableId> getRouteTables();
+
+    /**
+     * Returns the routes in the given route table, grouped by prefix.
+     *
+     * @param table route table ID
+     * @return routes
+     */
+    Collection<RouteSet> getRoutes(RouteTableId table);
+
+    /**
+     * Returns the routes that point to the given next hop IP address.
+     *
+     * @param ip IP address of the next hop
+     * @return routes for the given next hop
+     */
+    // TODO think about including route table info
+    Collection<Route> getRoutesForNextHop(IpAddress ip);
+
+    /**
+     * Returns the set of routes in the default route table for the given prefix.
+     *
+     * @param prefix IP prefix
+     * @return route set
+     */
+    // TODO needs to be generalizable across route tables
+    @Beta
+    RouteSet getRoutes(IpPrefix prefix);
+
+    /**
+     * Returns the name of this route store.
+     *
+     * @return the name of this route store
+     */
+    default String name() {
+        return getClass().getName();
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteStoreDelegate.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteStoreDelegate.java
new file mode 100644
index 0000000..e9c5b00
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteStoreDelegate.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onosproject.store.StoreDelegate;
+
+/**
+ * Route store delegate abstraction.
+ */
+public interface RouteStoreDelegate extends StoreDelegate<InternalRouteEvent> {
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteTableId.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteTableId.java
new file mode 100644
index 0000000..b522e6c
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteTableId.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import java.util.Objects;
+
+/**
+ * Identifier for a routing table.
+ */
+public class RouteTableId {
+    private final String name;
+
+    /**
+     * Creates a new route table ID.
+     *
+     * @param name unique name for the route table
+     */
+    public RouteTableId(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Returns the name of the route table.
+     *
+     * @return table name
+     */
+    public String name() {
+        return name;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+
+        if (obj instanceof RouteTableId) {
+            RouteTableId that = (RouteTableId) obj;
+
+            return Objects.equals(this.name, that.name);
+        }
+        return false;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(name);
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteTools.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteTools.java
new file mode 100644
index 0000000..5264719
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/RouteTools.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onlab.packet.IpPrefix;
+
+/**
+ * Routing tools.
+ */
+public final class RouteTools {
+
+    private RouteTools() {
+    }
+
+    /**
+     * Creates a binary string representation of an IP prefix.
+     *
+     * For each string, we put a extra "0" in the front. The purpose of
+     * doing this is to store the default route inside InvertedRadixTree.
+     *
+     * @param ipPrefix the IP prefix to use
+     * @return the binary string representation
+     */
+    public static String createBinaryString(IpPrefix ipPrefix) {
+        byte[] octets = ipPrefix.address().toOctets();
+        StringBuilder result = new StringBuilder(ipPrefix.prefixLength());
+        result.append("0");
+        for (int i = 0; i < ipPrefix.prefixLength(); i++) {
+            int byteOffset = i / Byte.SIZE;
+            int bitOffset = i % Byte.SIZE;
+            int mask = 1 << (Byte.SIZE - 1 - bitOffset);
+            byte value = octets[byteOffset];
+            boolean isSet = ((value & mask) != 0);
+            result.append(isSet ? "1" : "0");
+        }
+        return result.toString();
+    }
+}
diff --git a/apps/route-service/api/src/main/java/org/onosproject/routeservice/package-info.java b/apps/route-service/api/src/main/java/org/onosproject/routeservice/package-info.java
new file mode 100644
index 0000000..5bfe5ba
--- /dev/null
+++ b/apps/route-service/api/src/main/java/org/onosproject/routeservice/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.
+ */
+
+/**
+ * Unicast routing service.
+ */
+package org.onosproject.routeservice;
diff --git a/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteConfigTest.java b/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteConfigTest.java
new file mode 100644
index 0000000..1e48420
--- /dev/null
+++ b/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteConfigTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableSet;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.TestApplicationId;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.net.config.Config;
+import org.onosproject.net.config.ConfigApplyDelegate;
+
+import java.io.InputStream;
+import java.util.Set;
+
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.*;
+
+/**
+ * Tests for class {@link RouteConfigTest}.
+ */
+public class RouteConfigTest {
+    private static final String KEY = "org.onosproject.routing";
+
+    private static final IpPrefix PREFIX1 = IpPrefix.valueOf("10.0.0.1/24");
+    private static final IpPrefix PREFIX2 = IpPrefix.valueOf("20.0.0.1/24");
+    private static final IpPrefix PREFIX3 = IpPrefix.valueOf("30.0.0.1/24");
+    private static final IpAddress NEXTHOP1 = IpAddress.valueOf("192.168.1.1");
+    private static final IpAddress NEXTHOP2 = IpAddress.valueOf("192.168.2.1");
+    private static final Route ROUTE1 = new Route(Route.Source.STATIC, PREFIX1, NEXTHOP1);
+    private static final Route ROUTE2 = new Route(Route.Source.STATIC, PREFIX2, NEXTHOP1);
+    private static final Route ROUTE3 = new Route(Route.Source.STATIC, PREFIX3, NEXTHOP2);
+    private static final Set<Route> EXPECTED_ROUTES = ImmutableSet.of(ROUTE1, ROUTE2, ROUTE3);
+    private static final Set<Route> UNEXPECTED_ROUTES = ImmutableSet.of(ROUTE1, ROUTE2);
+
+    private RouteConfig config;
+
+    @Before
+    public void setUp() throws Exception {
+        InputStream jsonStream = RouteConfigTest.class
+                .getResourceAsStream("/route-config.json");
+        ApplicationId subject = new TestApplicationId(KEY);
+        ObjectMapper mapper = new ObjectMapper();
+        JsonNode jsonNode = mapper.readTree(jsonStream);
+        ConfigApplyDelegate delegate = new MockDelegate();
+
+        config = new RouteConfig();
+        config.init(subject, KEY, jsonNode, mapper, delegate);
+    }
+
+    @Test
+    public void getRoutes() throws Exception {
+        assertThat(config.getRoutes(), is(EXPECTED_ROUTES));
+        assertThat(config.getRoutes(), not(UNEXPECTED_ROUTES));
+    }
+
+    private class MockDelegate implements ConfigApplyDelegate {
+        @Override
+        public void onApply(Config config) {
+        }
+    }
+}
diff --git a/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteServiceAdapter.java b/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteServiceAdapter.java
new file mode 100644
index 0000000..1d6ec19
--- /dev/null
+++ b/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteServiceAdapter.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2016-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onlab.packet.IpAddress;
+
+import java.util.Collection;
+import java.util.Optional;
+
+/**
+ * Adapter class for the route service.
+ */
+public class RouteServiceAdapter implements RouteAdminService {
+    @Override
+    public void update(Collection<Route> routes) {
+
+    }
+
+    @Override
+    public void withdraw(Collection<Route> routes) {
+
+    }
+
+    @Override
+    public Collection<RouteInfo> getRoutes(RouteTableId id) {
+        return null;
+    }
+
+    @Override
+    public Collection<RouteTableId> getRouteTables() {
+        return null;
+    }
+
+    @Override
+    public Route longestPrefixMatch(IpAddress ip) {
+        return null;
+    }
+
+    @Override
+    public Optional<ResolvedRoute> longestPrefixLookup(IpAddress ip) {
+        return null;
+    }
+
+    @Override
+    public void addListener(RouteListener listener) {
+
+    }
+
+    @Override
+    public void removeListener(RouteListener listener) {
+
+    }
+}
diff --git a/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteStoreAdapter.java b/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteStoreAdapter.java
new file mode 100644
index 0000000..bf9e527
--- /dev/null
+++ b/apps/route-service/api/src/test/java/org/onosproject/routeservice/RouteStoreAdapter.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2017-present Open Networking Foundation
+ *
+ * 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.routeservice;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * Adapter class for the route store.
+ */
+public class RouteStoreAdapter implements RouteStore {
+    @Override
+    public void updateRoute(Route route) {
+
+    }
+
+    @Override
+    public void removeRoute(Route route) {
+
+    }
+
+    @Override
+    public Set<RouteTableId> getRouteTables() {
+        return null;
+    }
+
+    @Override
+    public Collection<RouteSet> getRoutes(RouteTableId table) {
+        return null;
+    }
+
+    @Override
+    public Collection<Route> getRoutesForNextHop(IpAddress ip) {
+        return null;
+    }
+
+    @Override
+    public RouteSet getRoutes(IpPrefix prefix) {
+        return null;
+    }
+
+    @Override
+    public void setDelegate(RouteStoreDelegate delegate) {
+
+    }
+
+    @Override
+    public void unsetDelegate(RouteStoreDelegate delegate) {
+
+    }
+
+    @Override
+    public boolean hasDelegate() {
+        return false;
+    }
+}
diff --git a/apps/route-service/api/src/test/resources/route-config.json b/apps/route-service/api/src/test/resources/route-config.json
new file mode 100644
index 0000000..9675f12
--- /dev/null
+++ b/apps/route-service/api/src/test/resources/route-config.json
@@ -0,0 +1,14 @@
+[
+  {
+    "prefix": "10.0.0.1/24",
+    "nextHop": "192.168.1.1"
+  },
+  {
+    "prefix": "20.0.0.1/24",
+    "nextHop": "192.168.1.1"
+  },
+  {
+    "prefix": "30.0.0.1/24",
+    "nextHop": "192.168.2.1"
+  }
+]
\ No newline at end of file