refactor code and service separation for MOAS support

Change-Id: Id00a59a46a30d3a8c976611e637c28fe609c9842
diff --git a/apps/artemis/BUCK b/apps/artemis/BUCK
old mode 100644
new mode 100755
index 82c703a..e06097d
--- a/apps/artemis/BUCK
+++ b/apps/artemis/BUCK
@@ -1,24 +1,36 @@
 COMPILE_DEPS = [
     '//lib:CORE_DEPS',
-    '//lib:NETTY',
     '//lib:JACKSON',
+    '//lib:NETTY',
+    '//lib:netty',
+    '//lib:netty-transport',
     '//lib:org.apache.karaf.shell.console',
     '//cli:onos-cli',
     '//apps/routing-api:onos-apps-routing-api',
     '//apps/routing/common:onos-apps-routing-common',
+    '//protocols/ovsdb/api:onos-protocols-ovsdb-api',
+    '//apps/intentsync:onos-apps-intentsync',
+    '//apps/route-service/api:onos-apps-route-service-api',
+    '//protocols/ovsdb/rfc:onos-protocols-ovsdb-rfc',
     '//lib:okhttp',
     '//lib:okio',
     ':commons-net',
     ':io.socket-client',
     ':json',
-    ':engine.io-client',
-    '//lib:netty',
+    ':engine.io-client'
  ]
 
 BUNDLES = [
     '//apps/artemis:onos-apps-artemis',
     '//apps/routing-api:onos-apps-routing-api',
     '//apps/routing/common:onos-apps-routing-common',
+    '//protocols/ovsdb/api:onos-protocols-ovsdb-api',
+    '//apps/route-service/api:onos-apps-route-service-api',
+    '//protocols/ovsdb/rfc:onos-protocols-ovsdb-rfc'
+]
+
+TEST_DEPS = [
+    '//lib:TEST_ADAPTERS'
 ]
 
 EXCLUDED_BUNDLES = [
@@ -30,8 +42,9 @@
     ':engine.io-client'
 ]
 
-osgi_jar (
+osgi_jar_with_tests (
     deps = COMPILE_DEPS,
+    test_deps = TEST_DEPS,
 )
 
 onos_app (
@@ -42,7 +55,12 @@
     description = 'Artemis',
     included_bundles = BUNDLES,
     excluded_bundles = EXCLUDED_BUNDLES,
-    required_apps = [ 'org.onosproject.sdnip' ],
+    required_apps = [
+        'org.onosproject.sdnip',
+        'org.onosproject.openflow',
+        'org.onosproject.ovsdb',
+        'org.onosproject.drivers.ovsdb'
+    ],
 )
 
 remote_jar (
@@ -79,4 +97,4 @@
   sha1 = '854b49396e1e9f9bb0ab025062ddb49c4ed65ca1',
   maven_coords = 'io.socket:engine.io-client:jar:NON-OSGI:0.8.3',
   visibility = [ 'PUBLIC' ],
-)
+)
\ No newline at end of file
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisDeaggregator.java b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisDeaggregator.java
new file mode 100644
index 0000000..227f68d3
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisDeaggregator.java
@@ -0,0 +1,33 @@
+/*
+ * 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.artemis;
+
+/**
+ * Interface for Deaggregator Service of Artemis.
+ *
+ * When a prefix hijacking is detected, ARTEMIS automatically launches its mitigation service (deaggregator).
+ * Since in Internet routing the most specific prefix is always preferred, ARTEMIS modifies the BGP configuration of
+ * the routers so that they announce deaggregated sub-prefixes of the hijacked prefix (that are most preferred from any
+ * AS). After BGP converges, the hijacking attack is mitigated and traffic flows normally back to the ARTEMIS-protected
+ * AS (the one that runs ARTEMIS). Therefore, ARTEMIS assumes write permissions to the routers of the network, in order
+ * to be able to modify their BGP configuration and mitigate the attack. The purpose of this service is to receive all
+ * hijack events from the detector service and proceed on writing all the new prefixes to be announced by the BGP
+ * Speakers.
+ */
+public interface ArtemisDeaggregator {
+    //TODO: give the ability of other services to announce prefixes to BGP Speakers through this interface
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisDetector.java b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisDetector.java
new file mode 100644
index 0000000..650d32d
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisDetector.java
@@ -0,0 +1,27 @@
+/*
+ * 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.artemis;
+
+/**
+ * Interface for Detector Service of Artemis.
+ *
+ * The detection service combines the information received through the events generated from the monitor service and
+ * the configuration file that includes all the legit BGP paths. The purpose of this interface is to identify given
+ * a BGP update message if there is a BGP hijack or not.
+ */
+public interface ArtemisDetector {
+    //TODO: give the ability to other services to check the legitimacy of a BGP Update message
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisService.java b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisEventListener.java
similarity index 64%
rename from apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisService.java
rename to apps/artemis/src/main/java/org/onosproject/artemis/ArtemisEventListener.java
index 910906c..ced3d56 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisService.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisEventListener.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -13,18 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.onosproject.artemis.impl;
+package org.onosproject.artemis;
+
+import org.onosproject.artemis.impl.ArtemisEvent;
+import org.onosproject.event.EventListener;
 
 /**
- * Artemis Service.
+ * Entity capable of receiving artemis-related events.
  */
-public interface ArtemisService {
-
-    /**
-     * Set logger to print incoming packets or not.
-     *
-     * @param value true to print incoming BGP messages
-     */
-    void setLogger(boolean value);
-
+public interface ArtemisEventListener extends EventListener<ArtemisEvent> {
 }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisMoasAgent.java b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisMoasAgent.java
new file mode 100644
index 0000000..b25c714
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisMoasAgent.java
@@ -0,0 +1,40 @@
+/*
+ * 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.artemis;
+
+import io.netty.channel.ChannelHandlerContext;
+import org.onlab.packet.IpAddress;
+
+/**
+ * MOAS agent that handles remote connections.
+ */
+public interface ArtemisMoasAgent {
+
+    /**
+     * Keep a connection active if MOAS client is legit.
+     *
+     * @param ipAddress remote IP address
+     * @param ctx channel context
+     */
+    void addMoas(IpAddress ipAddress, ChannelHandlerContext ctx);
+
+    /**
+     * Remove MOAS.
+     *
+     * @param ipAddress remote IP address
+     */
+    void removeMoas(IpAddress ipAddress);
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisMonitor.java b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisMonitor.java
new file mode 100755
index 0000000..2d82145
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisMonitor.java
@@ -0,0 +1,28 @@
+/*
+ * 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.artemis;
+
+/**
+ * Interface for Monitor Service of Artemis.
+ *
+ * The monitoring service runs continuously and provides control plane information from the AS itself, the streaming
+ * services can be RIPE RIS, BGPstream, BGPmon and Periscope, which return almost real-time BGP updates for a given
+ * list of prefixes and ASNs. The purpose of this interface is to provide store and provide this BGO information to the
+ * consumers (e.g. Artemis Detector Service).
+ */
+public interface ArtemisMonitor {
+    //TODO: give access to BGP Update messages to other services through this service
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisPacketProcessor.java b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisPacketProcessor.java
new file mode 100644
index 0000000..d4cae92
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisPacketProcessor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.artemis;
+
+import io.netty.channel.ChannelHandlerContext;
+import org.json.JSONObject;
+import org.onosproject.artemis.impl.objects.ArtemisMessage;
+
+/**
+ * Packet processor for artemis messages.
+ */
+public interface ArtemisPacketProcessor {
+
+    /**
+     * Process a packet received from a MOAS client/server.
+     *
+     * @param msg artemis message
+     * @param ctx channel context
+     */
+    void processMoasPacket(ArtemisMessage msg, ChannelHandlerContext ctx);
+
+    /**
+     * Process a BGP Update packet received from a monitor.
+     *
+     * @param msg BGP Update message
+     */
+    void processMonitorPacket(JSONObject msg);
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisService.java b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisService.java
new file mode 100644
index 0000000..37206b0
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/ArtemisService.java
@@ -0,0 +1,36 @@
+/*
+ * 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.artemis;
+
+import org.onosproject.artemis.impl.ArtemisConfig;
+import org.onosproject.artemis.impl.ArtemisEvent;
+import org.onosproject.event.ListenerService;
+
+import java.util.Optional;
+
+/**
+ * The main service/orchestrator of Artemis.
+ */
+public interface ArtemisService extends ListenerService<ArtemisEvent, ArtemisEventListener> {
+
+    /**
+     * Get the current configuration.
+     *
+     * @return config
+     */
+    Optional<ArtemisConfig> getConfig();
+
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisService.java b/apps/artemis/src/main/java/org/onosproject/artemis/BgpSpeakers.java
similarity index 64%
copy from apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisService.java
copy to apps/artemis/src/main/java/org/onosproject/artemis/BgpSpeakers.java
index 910906c..9b333bc 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisService.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/BgpSpeakers.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -13,18 +13,17 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.onosproject.artemis.impl;
+package org.onosproject.artemis;
 
 /**
- * Artemis Service.
+ * Interface for all the types of BGP Speakers.
  */
-public interface ArtemisService {
+public interface BgpSpeakers {
 
     /**
-     * Set logger to print incoming packets or not.
+     * Announces the two new subprefixes on the BGP Speaker.
      *
-     * @param value true to print incoming BGP messages
+     * @param prefixes list of two prefixes
      */
-    void setLogger(boolean value);
-
+    void announceSubPrefixes(String[] prefixes);
 }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/Monitor.java b/apps/artemis/src/main/java/org/onosproject/artemis/Monitors.java
similarity index 62%
rename from apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/Monitor.java
rename to apps/artemis/src/main/java/org/onosproject/artemis/Monitors.java
index 853f1a0..3a5bf22 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/Monitor.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/Monitors.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -13,90 +13,91 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.onosproject.artemis.impl.monitors;
+package org.onosproject.artemis;
 
 import org.onlab.packet.IpPrefix;
 
+import java.util.Arrays;
+import java.util.Optional;
+
 /**
- * Abstract class for Monitors.
+ * Interface for Monitors.
  */
-public abstract class Monitor {
-    /**
-     * Match enum type with monitor type inside configuration to map them.
-     */
-    public enum Types {
-        RIPE {
-            @Override
-            public String toString() {
-                return "ripe";
-            }
-        },
-        EXABGP {
-            @Override
-            public String toString() {
-                return "exabgp";
-            }
-        }
-    }
-
-    IpPrefix prefix;
-    Monitor(IpPrefix prefix) {
-        this.prefix = prefix;
-    }
-
+public interface Monitors {
     /**
      * Get prefix of the specific monitor.
      *
      * @return prefix
      */
-    public IpPrefix getPrefix() {
-        return prefix;
-    }
+    IpPrefix getPrefix();
 
     /**
      * Set prefix for monitor.
      *
      * @param prefix prefix
      */
-    public void setPrefix(IpPrefix prefix) {
-        this.prefix = prefix;
-    }
+    void setPrefix(IpPrefix prefix);
 
     /**
      * Start monitor to begin capturing incoming BGP packets.
      */
-    public abstract void startMonitor();
+    void startMonitor();
 
     /**
      * Stop monitor from capturing incoming BGP packets.
      */
-    public abstract void stopMonitor();
-
-    /**
-     * Get type of monitor.
-     *
-     * @return enum type
-     */
-    public abstract Types getType();
+    void stopMonitor();
 
     /**
      * Check if monitor is running.
      *
      * @return true if running
      */
-    public abstract boolean isRunning();
+    boolean isRunning();
 
     /**
      * Get host alias e.g. IP address, name.
      *
      * @return host alias
      */
-    public abstract String getHost();
+    String getHost();
 
     /**
      * Set alias of host.
      *
      * @param host alias
      */
-    public abstract void setHost(String host);
+    void setHost(String host);
+
+    /**
+     * Match enum type with monitor type inside configuration to map them.
+     */
+    enum Types {
+        RIPE("ripe") {
+            @Override
+            public String toString() {
+                return "ripe";
+            }
+        },
+        EXABGP("exabgp") {
+            @Override
+            public String toString() {
+                return "exabgp";
+            }
+        };
+
+        private String name;
+
+        Types(String name) {
+            this.name = name;
+        }
+
+        public static Types getEnum(String name) {
+            Optional<Types> any = Arrays.stream(Types.values()).filter(typeStr -> typeStr.name.equals(name)).findAny();
+            if (any.isPresent()) {
+                return any.get();
+            }
+            throw new IllegalArgumentException("No enum defined for string: " + name);
+        }
+    }
 }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/cli/LogOptionsCommand.java b/apps/artemis/src/main/java/org/onosproject/artemis/cli/LogOptionsCommand.java
deleted file mode 100644
index 334b4ab..0000000
--- a/apps/artemis/src/main/java/org/onosproject/artemis/cli/LogOptionsCommand.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2015 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.artemis.cli;
-
-import org.apache.karaf.shell.commands.Command;
-import org.apache.karaf.shell.commands.Option;
-import org.onosproject.artemis.impl.ArtemisService;
-import org.onosproject.cli.AbstractShellCommand;
-
-/**
- * CLI to enable or disable BGP Update message logging.
- */
-@Command(scope = "artemis", name = "log-messages",
-    description = "Show RIS messages in logger.")
-public class LogOptionsCommand extends AbstractShellCommand {
-
-    @Option(name = "--enable", aliases = "-e", description = "Enable RIS message logging",
-            required = false, multiValued = false)
-    private boolean enable = false;
-
-    @Option(name = "--disable", aliases = "-d", description = "Disable RIS message logging",
-            required = false, multiValued = false)
-    private boolean disable = false;
-
-    @Override
-    protected void execute() {
-        ArtemisService artemisService = get(ArtemisService.class);
-        if (enable) {
-            artemisService.setLogger(true);
-        } else if (disable) {
-            artemisService.setLogger(false);
-        }
-    }
-}
\ No newline at end of file
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisConfig.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisConfig.java
index 54285a8..b21c5f6 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisConfig.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisConfig.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-present Open Networking Foundation
+ * 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.
@@ -18,8 +18,10 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+import com.google.common.collect.Streams;
 import org.json.JSONArray;
 import org.json.JSONException;
+import org.onlab.packet.IpAddress;
 import org.onlab.packet.IpPrefix;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.net.config.Config;
@@ -31,14 +33,14 @@
 import java.util.Map;
 import java.util.Objects;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
 /**
  * Artemis Configuration Class.
  */
-class ArtemisConfig extends Config<ApplicationId> {
-
+public class ArtemisConfig extends Config<ApplicationId> {
     private static final String PREFIXES = "prefixes";
     /* */
     private static final String PREFIX = "prefix";
@@ -49,18 +51,29 @@
     private static final String NEIGHBOR = "neighbor";
     private static final String ASN = "asn";
     /* */
-
     private static final String MONITORS = "monitors";
     /* */
     private static final String RIPE = "ripe";
     private static final String EXABGP = "exabgp";
     /* */
-
-    private static final String FREQUENCY = "frequency";
-
+    private static final String MOAS_LEGIT = "legit";
+    private static final String TUNNEL_POINTS = "tunnelPoints";
+    private static final String TUNNEL_OVSDB_IP = "ovsdb_ip";
+    private static final String TUNNEL_LOCAL_IP = "local_ip";
+    private static final String TUNNEL_OVS_PORT = "ovs_port";
 
     private final Logger log = LoggerFactory.getLogger(getClass());
 
+    Set<IpPrefix> prefixesToMonitor() {
+        JsonNode prefixesNode = object.path(PREFIXES);
+        if (!prefixesNode.isMissingNode()) {
+            return Streams.stream(prefixesNode)
+                    .map(prefix -> IpPrefix.valueOf(prefix.get(PREFIX).asText()))
+                    .collect(Collectors.toSet());
+        }
+        return null;
+    }
+
     /**
      * Gets the set of monitored prefixes with the details (prefix, paths and MOAS).
      *
@@ -69,8 +82,8 @@
     Set<ArtemisPrefixes> monitoredPrefixes() {
         Set<ArtemisPrefixes> prefixes = Sets.newHashSet();
 
-        JsonNode prefixesNode = object.get(PREFIXES);
-        if (prefixesNode == null) {
+        JsonNode prefixesNode = object.path(PREFIXES);
+        if (prefixesNode.isMissingNode()) {
             log.warn("prefixes field is null!");
             return prefixes;
         }
@@ -78,33 +91,16 @@
         prefixesNode.forEach(jsonNode -> {
             IpPrefix prefix = IpPrefix.valueOf(jsonNode.get(PREFIX).asText());
 
-            Set<Integer> moasNumbers = Sets.newHashSet();
             JsonNode moasNode = jsonNode.get(MOAS);
-            moasNode.forEach(asn ->
-                    moasNumbers.add(asn.asInt())
-            );
+            Set<IpAddress> moasIps = Streams.stream(moasNode)
+                    .map(asn -> IpAddress.valueOf(asn.asText()))
+                    .collect(Collectors.toSet());
 
-            /*
-            "paths" : [{
-                "origin" : 65004,
-                "neighbor" : [{
-                        "asn" : 65002,
-                        "neighbor": [{
-                            "asn" : 65001,
-                        }]
-                }]
-            }]
-            */
-
-            Map<Integer, Map<Integer, Set<Integer>>> paths = Maps.newHashMap();
             JsonNode pathsNode = jsonNode.get(PATHS);
-            pathsNode.forEach(path -> {
-                addPath(paths, path);
-            });
+            Map<Integer, Map<Integer, Set<Integer>>> paths = Maps.newHashMap();
+            pathsNode.forEach(path -> addPath(paths, path));
 
-            // printPaths(paths);
-
-            prefixes.add(new ArtemisPrefixes(prefix, moasNumbers, paths));
+            prefixes.add(new ArtemisPrefixes(prefix, moasIps, paths));
         });
 
         return prefixes;
@@ -146,7 +142,7 @@
                             paths.put(origin, first2second);
                         }
                     });
-                // else append to paths without second neighbor
+                    // else append to paths without second neighbor
                 } else {
                     if (!paths.containsKey(origin)) {
                         Map<Integer, Set<Integer>> first2second = Maps.newHashMap();
@@ -161,7 +157,7 @@
                     }
                 }
             });
-        // else append to paths only the origin
+            // else append to paths only the origin
         } else {
             if (!paths.containsKey(origin)) {
                 paths.put(origin, Maps.newHashMap());
@@ -169,34 +165,17 @@
         }
     }
 
-    /**
-     * Helper function to print the loaded ASN paths.
-     *
-     * @param paths ASN paths to print
-     */
-    private void printPaths(Map<Integer, Map<Integer, Set<Integer>>> paths) {
-        log.warn("------------------------------------");
-        paths.forEach((k, v) -> v.forEach((l, n) -> {
-            n.forEach(p -> log.warn("Origin: " + k + ", 1st: " + l + ", 2nd: " + p));
-        }));
-    }
-
-    /**
-     * Gets the frequency of the detection module in milliseconds.
-     *
-     * @return frequency (ms)
-     */
-    int detectionFrequency() {
-        JsonNode thresholdNode = object.get(FREQUENCY);
-        int threshold = 0;
-
-        if (thresholdNode == null) {
-            log.warn("threshold field is null!");
-            return threshold;
-        }
-
-        return thresholdNode.asInt();
-    }
+//    /**
+//     * Helper function to print the loaded ASN paths.
+//     *
+//     * @param paths ASN paths to print
+//     */
+//    private void printPaths(Map<Integer, Map<Integer, Set<Integer>>> paths) {
+//        log.warn("------------------------------------");
+//        paths.forEach((k, v) -> v.forEach((l, n) -> {
+//            n.forEach(p -> log.warn("Origin: " + k + ", 1st: " + l + ", 2nd: " + p));
+//        }));
+//    }
 
     /**
      * Gets the active route collectors.
@@ -206,36 +185,185 @@
     Map<String, Set<String>> activeMonitors() {
         Map<String, Set<String>> monitors = Maps.newHashMap();
 
-        JsonNode monitorsNode = object.get(MONITORS);
+        JsonNode monitorsNode = object.path(MONITORS);
 
-        JsonNode ripeNode = monitorsNode.path(RIPE);
-        if (!ripeNode.isMissingNode()) {
-            Set<String> hosts = Sets.newHashSet();
-            ripeNode.forEach(host -> hosts.add(host.asText()));
-            monitors.put(RIPE, hosts);
-        }
+        if (!monitorsNode.isMissingNode()) {
+            JsonNode ripeNode = monitorsNode.path(RIPE);
+            if (!ripeNode.isMissingNode()) {
+                Set<String> hosts = Sets.newHashSet();
+                ripeNode.forEach(host -> hosts.add(host.asText()));
+                monitors.put(RIPE, hosts);
+            }
 
-        JsonNode exabgpNode = monitorsNode.path(EXABGP);
-        if (!exabgpNode.isMissingNode()) {
-            Set<String> hosts = Sets.newHashSet();
-            exabgpNode.forEach(host -> hosts.add(host.asText()));
-            monitors.put(EXABGP, hosts);
+            JsonNode exabgpNode = monitorsNode.path(EXABGP);
+            if (!exabgpNode.isMissingNode()) {
+                Set<String> hosts = Sets.newHashSet();
+                exabgpNode.forEach(host -> hosts.add(host.asText()));
+                monitors.put(EXABGP, hosts);
+            }
         }
 
         return monitors;
     }
 
     /**
+     * Get the information about MOAS. Including remote MOAS server IPs, OVSDB ID and local tunnel IP.
+     *
+     * @return MOAS information
+     */
+    MoasInfo moasInfo() {
+        MoasInfo moasInfo = new MoasInfo();
+
+        JsonNode moasNode = object.path(MOAS);
+
+        if (!moasNode.isMissingNode()) {
+            JsonNode legitIpsNode = moasNode.path(MOAS_LEGIT);
+            if (!legitIpsNode.isMissingNode()) {
+                if (legitIpsNode.isArray()) {
+                    moasInfo.setMoasAddresses(
+                            Streams.stream(legitIpsNode)
+                                    .map(ipAddress -> IpAddress.valueOf(ipAddress.asText()))
+                                    .collect(Collectors.toSet())
+                    );
+                } else {
+                    log.warn("Legit MOAS field need to be a list");
+                }
+            } else {
+                log.warn("No IPs for legit MOAS specified in configuration");
+            }
+
+            JsonNode tunnelPointsNode = moasNode.path(TUNNEL_POINTS);
+            if (!tunnelPointsNode.isMissingNode()) {
+                if (tunnelPointsNode.isArray()) {
+                    tunnelPointsNode.forEach(
+                            tunnelPoint -> {
+                                JsonNode idNode = tunnelPoint.path(TUNNEL_OVSDB_IP),
+                                        localNode = tunnelPoint.path(TUNNEL_LOCAL_IP),
+                                        ovsNode = tunnelPoint.path(TUNNEL_OVS_PORT);
+
+                                if (!idNode.isMissingNode() && !localNode.isMissingNode()) {
+                                    moasInfo.addTunnelPoint(
+                                            new MoasInfo.TunnelPoint(
+                                                    IpAddress.valueOf(idNode.asText()),
+                                                    IpAddress.valueOf(localNode.asText()),
+                                                    ovsNode.asText()
+                                            )
+                                    );
+                                } else {
+                                    log.warn("Tunnel point need to have an ID and a Local IP");
+                                }
+                            }
+                    );
+                } else {
+                    log.warn("Tunnel points field need to be a list");
+                }
+            }
+        } else {
+            log.warn("No tunnel points specified in configuration");
+        }
+
+        return moasInfo;
+    }
+
+    /**
+     * Information holder for MOAS.
+     */
+    public static class MoasInfo {
+        private Set<IpAddress> moasAddresses;
+        private Set<TunnelPoint> tunnelPoints;
+
+        public MoasInfo() {
+            moasAddresses = Sets.newConcurrentHashSet();
+            tunnelPoints = Sets.newConcurrentHashSet();
+        }
+
+        public Set<IpAddress> getMoasAddresses() {
+            return moasAddresses;
+        }
+
+        public void setMoasAddresses(Set<IpAddress> moasAddresses) {
+            this.moasAddresses = moasAddresses;
+        }
+
+        public Set<TunnelPoint> getTunnelPoints() {
+            return tunnelPoints;
+        }
+
+        public void setTunnelPoints(Set<TunnelPoint> tunnelPoints) {
+            this.tunnelPoints = tunnelPoints;
+        }
+
+        public TunnelPoint getTunnelPoint() {
+            return tunnelPoints.iterator().next();
+        }
+
+        public void addTunnelPoint(TunnelPoint tunnelPoint) {
+            this.tunnelPoints.add(tunnelPoint);
+        }
+
+        @Override
+        public String toString() {
+            return "MoasInfo{" +
+                    "moasAddresses=" + moasAddresses +
+                    ", tunnelPoints=" + tunnelPoints +
+                    '}';
+        }
+
+        public static class TunnelPoint {
+            private IpAddress ovsdbIp;
+            private IpAddress localIP;
+            private String ovsPort;
+
+            public TunnelPoint(IpAddress ovsdbIp, IpAddress localIP, String ovsPort) {
+                this.ovsdbIp = ovsdbIp;
+                this.localIP = localIP;
+                this.ovsPort = ovsPort;
+            }
+
+            public IpAddress getOvsdbIp() {
+                return ovsdbIp;
+            }
+
+            public void setOvsdbIp(IpAddress ovsdbIp) {
+                this.ovsdbIp = ovsdbIp;
+            }
+
+            public IpAddress getLocalIp() {
+                return localIP;
+            }
+
+            public void setLocalIp(IpAddress localIP) {
+                this.localIP = localIP;
+            }
+
+            public String getOvsPort() {
+                return ovsPort;
+            }
+
+            public void setOvsPort(String ovsPort) {
+                this.ovsPort = ovsPort;
+            }
+
+            @Override
+            public String toString() {
+                return "TunnelPoint{" +
+                        "ovsdbIp='" + ovsdbIp + '\'' +
+                        ", localIP=" + localIP +
+                        ", ovsPort='" + ovsPort + '\'' +
+                        '}';
+            }
+        }
+    }
+
+    /**
      * Configuration for a specific prefix.
      */
-    static class ArtemisPrefixes {
+    public class ArtemisPrefixes {
         private IpPrefix prefix;
-        private Set<Integer> moas;
+        private Set<IpAddress> moas;
         private Map<Integer, Map<Integer, Set<Integer>>> paths;
 
-        private final Logger log = LoggerFactory.getLogger(getClass());
-
-        ArtemisPrefixes(IpPrefix prefix, Set<Integer> moas, Map<Integer, Map<Integer, Set<Integer>>> paths) {
+        ArtemisPrefixes(IpPrefix prefix, Set<IpAddress> moas, Map<Integer, Map<Integer, Set<Integer>>> paths) {
             this.prefix = checkNotNull(prefix);
             this.moas = checkNotNull(moas);
             this.paths = checkNotNull(paths);
@@ -245,7 +373,7 @@
             return prefix;
         }
 
-        protected Set<Integer> moas() {
+        protected Set<IpAddress> moas() {
             return moas;
         }
 
@@ -261,8 +389,8 @@
          *
          * @param path as-path that announces our prefix and found from monitors
          * @return <code>0</code> no bgp hijack detected
-         *         <code>50</code> friendly anycaster announcing our prefix
-         *         <code>100+i</code> BGP hijack type i (0 &lt;= i &lt;=2)
+         * <code>50</code> friendly anycaster announcing our prefix
+         * <code>100+i</code> BGP hijack type i (0 &lt;= i &lt;=2)
          */
         int checkPath(JSONArray path) {
             // TODO add MOAS check
@@ -288,6 +416,15 @@
         }
 
         @Override
+        public String toString() {
+            return "ArtemisPrefixes{" +
+                    "prefix=" + prefix +
+                    ", moas=" + moas +
+                    ", paths=" + paths +
+                    '}';
+        }
+
+        @Override
         public int hashCode() {
             return Objects.hashCode(prefix);
         }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDeaggregatorImpl.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDeaggregatorImpl.java
new file mode 100644
index 0000000..5660644
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDeaggregatorImpl.java
@@ -0,0 +1,473 @@
+/*
+ * 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.artemis.impl;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.util.CharsetUtil;
+import org.apache.commons.lang.exception.ExceptionUtils;
+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.json.JSONObject;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onlab.packet.TpPort;
+import org.onosproject.artemis.ArtemisDeaggregator;
+import org.onosproject.artemis.ArtemisEventListener;
+import org.onosproject.artemis.ArtemisMoasAgent;
+import org.onosproject.artemis.ArtemisPacketProcessor;
+import org.onosproject.artemis.ArtemisService;
+import org.onosproject.artemis.BgpSpeakers;
+import org.onosproject.artemis.impl.bgpspeakers.QuaggaBgpSpeakers;
+import org.onosproject.artemis.impl.moas.MoasClientController;
+import org.onosproject.artemis.impl.moas.MoasServerController;
+import org.onosproject.artemis.impl.objects.ArtemisMessage;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.Port;
+import org.onosproject.net.PortNumber;
+import org.onosproject.net.device.DeviceEvent;
+import org.onosproject.net.device.DeviceListener;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.net.flow.DefaultTrafficSelector;
+import org.onosproject.net.flow.DefaultTrafficTreatment;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.flow.TrafficSelector;
+import org.onosproject.net.flow.TrafficTreatment;
+import org.onosproject.net.flowobjective.DefaultForwardingObjective;
+import org.onosproject.net.flowobjective.FlowObjectiveService;
+import org.onosproject.net.flowobjective.ForwardingObjective;
+import org.onosproject.net.intf.InterfaceService;
+import org.onosproject.ovsdb.controller.OvsdbBridge;
+import org.onosproject.ovsdb.controller.OvsdbClientService;
+import org.onosproject.ovsdb.controller.OvsdbController;
+import org.onosproject.ovsdb.controller.OvsdbInterface;
+import org.onosproject.routing.bgp.BgpInfoService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+
+import static org.onlab.packet.Ethernet.TYPE_IPV4;
+
+@Component(immediate = true)
+@Service
+public class ArtemisDeaggregatorImpl implements ArtemisDeaggregator {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private static final int PRIORITY = 1000;
+
+    /* Services */
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private BgpInfoService bgpInfoService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private ArtemisService artemisService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private OvsdbController ovsdbController;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private DeviceService deviceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private InterfaceService interfaceService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private FlowObjectiveService flowObjectiveService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private FlowRuleService flowRuleService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private CoreService coreService;
+
+    /* Variables */
+    private Set<BgpSpeakers> bgpSpeakers = Sets.newHashSet();
+    private MoasServerController moasServer;
+
+    private Port tunnelPort = null;
+    private ApplicationId appId;
+
+    private IpAddress remoteTunnelIp = null;
+    private IpPrefix remotePrefix = null;
+    private boolean rulesInstalled;
+
+    /* Agent */
+    private InternalMoasAgent moasAgent = new InternalMoasAgent();
+    private InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+    private InternalDeviceListener deviceListener = new InternalDeviceListener();
+
+    private Set<MoasClientController> moasClientControllers = Sets.newConcurrentHashSet();
+
+    private final ArtemisEventListener artemisEventListener = this::handleArtemisEvent;
+
+    @Activate
+    protected void activate() {
+        rulesInstalled = false;
+
+        // FIXME: add other type of BGP Speakers when Dynamic Configuration is available
+        bgpSpeakers.add(new QuaggaBgpSpeakers(bgpInfoService));
+
+        moasServer = new MoasServerController();
+        moasServer.start(moasAgent, packetProcessor);
+
+        deviceService.addListener(deviceListener);
+
+        appId = coreService.getAppId("org.onosproject.artemis");
+
+        // enable OVSDB for the switches that we will install the GRE tunnel
+        artemisService.getConfig().ifPresent(config -> config.moasInfo().getTunnelPoints()
+                .forEach(tunnelPoint -> ovsdbController.connect(tunnelPoint.getOvsdbIp(), TpPort.tpPort(6640)))
+        );
+
+        artemisService.addListener(artemisEventListener);
+
+        log.info("Artemis Deaggregator Service Started");
+
+        /*
+        log.info("interfaces {}", interfaceService.getInterfaces());
+
+        [{
+         "name": "",
+         "connectPoint": "of:000000000000000a/2",
+         "ipAddresses": "[1.1.1.1/30]",
+         "macAddress": "00:00:00:00:00:01"
+        },
+        {
+         "name": "",
+         "connectPoint": "of:000000000000000a/3",
+         "ipAddresses": "[10.0.0.1/8]",
+         "macAddress": "00:00:00:00:00:01"
+        }]
+        */
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        moasServer.stop();
+
+        moasClientControllers.forEach(MoasClientController::stop);
+        moasClientControllers.clear();
+
+        flowRuleService.removeFlowRulesById(appId);
+        deviceService.removeListener(deviceListener);
+
+        remoteTunnelIp = null;
+        remotePrefix = null;
+        tunnelPort = null;
+
+        artemisService.removeListener(artemisEventListener);
+
+        log.info("Artemis Deaggregator Service Stopped");
+    }
+
+    /**
+     * Create a GRE tunnel interface pointing to remote MOAS.
+     *
+     * @param remoteIp remote ip on GRE tunnel
+     */
+    private void createTunnelInterface(IpAddress remoteIp) {
+        ovsdbController.getNodeIds().forEach(nodeId -> artemisService.getConfig().flatMap(config ->
+                config.moasInfo().getTunnelPoints()
+                        .stream()
+                        .filter(tunnelPoint -> tunnelPoint.getOvsdbIp().toString().equals(nodeId.getIpAddress()))
+                        .findFirst()
+        ).ifPresent(tunnelPoint -> {
+            OvsdbClientService ovsdbClient = ovsdbController.getOvsdbClient(nodeId);
+            ovsdbClient.dropInterface("gre-int");
+            Map<String, String> options = Maps.newHashMap();
+            options.put("remote_ip", remoteIp.toString());
+            OvsdbInterface ovsdbInterface = OvsdbInterface.builder()
+                    .name("gre-int")
+                    .options(options)
+                    .type(OvsdbInterface.Type.GRE)
+                    .build();
+            OvsdbBridge mainBridge = ovsdbClient.getBridges().iterator().next();
+            ovsdbClient.createInterface(mainBridge.name(), ovsdbInterface);
+            log.info("Tunnel setup at {} - {}", nodeId, tunnelPoint);
+        }));
+    }
+
+    /**
+     * Install rules.
+     */
+    private void installRules() {
+        log.info("Remote Data {} - {} - {}", tunnelPort, remoteTunnelIp, remotePrefix);
+        // FIXME: currently works only for a simple pair of client-server
+        if (!rulesInstalled && tunnelPort != null && remoteTunnelIp != null) {
+            if (remotePrefix != null) {
+                installServerRules();
+            } else {
+                installClientRules();
+            }
+            rulesInstalled = true;
+        }
+    }
+
+    /**
+     * Rules to be installed on MOAS Client.
+     */
+    private void installClientRules() {
+        log.info("installClientRules");
+        artemisService.getConfig().ifPresent(config -> {
+            // selector
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchEthType(TYPE_IPV4)
+                    .matchIPSrc(remoteTunnelIp.toIpPrefix())
+                    .matchIPDst(config.moasInfo().getTunnelPoint().getLocalIp().toIpPrefix())
+                    .build();
+            // treatment
+            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                    .setOutput(PortNumber.LOCAL)
+                    .build();
+            // forwarding objective builder
+            ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+                    .withSelector(selector)
+                    .withTreatment(treatment)
+                    .withPriority(PRIORITY)
+                    .withFlag(ForwardingObjective.Flag.VERSATILE)
+                    .fromApp(appId)
+                    .add();
+            // send flow objective to specified switch
+            flowObjectiveService.forward(DeviceId.deviceId(tunnelPort.element().id().toString()),
+                    forwardingObjective);
+
+            log.info("Installing flow rule = {}", forwardingObjective);
+        });
+    }
+
+    /**
+     * Rules to be isntalled on MOAS Server.
+     */
+    private void installServerRules() {
+        log.info("installServerRules");
+        artemisService.getConfig().ifPresent(config -> {
+            // selector
+            TrafficSelector selector = DefaultTrafficSelector.builder()
+                    .matchEthType(TYPE_IPV4)
+                    .matchIPDst(remotePrefix)
+                    .build();
+            // treatment
+            TrafficTreatment treatment = DefaultTrafficTreatment.builder()
+                    .setOutput(tunnelPort.number())
+                    .build();
+            // forwarding objective builder
+            ForwardingObjective forwardingObjective = DefaultForwardingObjective.builder()
+                    .withSelector(selector)
+                    .withTreatment(treatment)
+                    .withPriority(PRIORITY)
+                    .withFlag(ForwardingObjective.Flag.VERSATILE)
+                    .fromApp(appId)
+                    .add();
+            // send flow objective to specified switch
+            flowObjectiveService.forward(DeviceId.deviceId(tunnelPort.element().id().toString()),
+                    forwardingObjective);
+
+            log.info("Installing flow rule = {}", forwardingObjective);
+
+            // selector
+            selector = DefaultTrafficSelector.builder()
+                    .matchEthType(TYPE_IPV4)
+                    .matchIPSrc(config.moasInfo().getTunnelPoint().getLocalIp().toIpPrefix())
+                    .matchIPDst(remoteTunnelIp.toIpPrefix())
+                    .build();
+            // treatment
+            treatment = DefaultTrafficTreatment.builder()
+                    // FIXME: find a better way
+                    .setOutput(PortNumber.portNumber(2))
+                    .build();
+            // forwarding objective builder
+            forwardingObjective = DefaultForwardingObjective.builder()
+                    .withSelector(selector)
+                    .withTreatment(treatment)
+                    .withPriority(PRIORITY)
+                    .withFlag(ForwardingObjective.Flag.VERSATILE)
+                    .fromApp(appId)
+                    .add();
+            // send flow objective to specified switch
+            flowObjectiveService.forward(DeviceId.deviceId(tunnelPort.element().id().toString()),
+                    forwardingObjective);
+
+            log.info("Installing flow rule = {}", forwardingObjective);
+        });
+    }
+
+    /**
+     * Handles a artemis event.
+     *
+     * @param event the artemis event
+     */
+    protected void handleArtemisEvent(ArtemisEvent event) {
+        if (event.type().equals(ArtemisEvent.Type.HIJACK_ADDED)) {
+            IpPrefix receivedPrefix = (IpPrefix) event.subject();
+
+            log.info("Deaggregator received a prefix " + receivedPrefix.toString());
+
+            // can only de-aggregate /23 subnets and higher
+            int cidr = receivedPrefix.prefixLength();
+            if (receivedPrefix.prefixLength() < 24) {
+                byte[] octets = receivedPrefix.address().toOctets();
+                int byteGroup = (cidr + 1) / 8,
+                        bitPos = 8 - (cidr + 1) % 8;
+
+                octets[byteGroup] = (byte) (octets[byteGroup] & ~(1 << bitPos));
+                String low = IpPrefix.valueOf(IpAddress.Version.INET, octets, cidr + 1).toString();
+                octets[byteGroup] = (byte) (octets[byteGroup] | (1 << bitPos));
+                String high = IpPrefix.valueOf(IpAddress.Version.INET, octets, cidr + 1).toString();
+
+                String[] prefixes = {low, high};
+                bgpSpeakers.forEach(bgpSpeakers -> bgpSpeakers.announceSubPrefixes(prefixes));
+            } else {
+                log.warn("Initiating MOAS");
+
+                artemisService.getConfig().ifPresent(config -> config.monitoredPrefixes().forEach(artemisPrefixes -> {
+                            log.info("checking if {} > {}", artemisPrefixes.prefix(), receivedPrefix);
+                            if (artemisPrefixes.prefix().contains(receivedPrefix)) {
+                                artemisPrefixes.moas().forEach(moasAddress -> {
+                                            log.info("Creating a client for {}", moasAddress);
+                                            MoasClientController client = new MoasClientController(
+                                                    packetProcessor,
+                                                    moasAddress,
+                                                    config.moasInfo().getTunnelPoints().iterator().next()
+                                                            .getLocalIp(),
+                                                    receivedPrefix);
+                                            log.info("Running client");
+                                            client.run();
+                                            moasClientControllers.add(client);
+                                        }
+                                );
+                            }
+                        }
+                ));
+            }
+
+        }
+    }
+
+    private class InternalPacketProcessor implements ArtemisPacketProcessor {
+        @Override
+        public void processMoasPacket(ArtemisMessage msg, ChannelHandlerContext ctx) {
+            log.info("Received {}", msg);
+            switch (msg.getType()) {
+                case INITIATE_FROM_CLIENT: {
+                    artemisService.getConfig().ifPresent(config -> {
+                        // SERVER SIDE CODE
+                        createTunnelInterface(IpAddress.valueOf(msg.getLocalIp()));
+
+                        ArtemisMessage message = new ArtemisMessage();
+                        message.setType(ArtemisMessage.Type.INITIATE_FROM_SERVER);
+                        message.setLocalIp(
+                                config.moasInfo().getTunnelPoints()
+                                        .iterator()
+                                        .next()
+                                        .getLocalIp()
+                                        .toString());
+
+                        ObjectMapper mapper = new ObjectMapper();
+                        try {
+                            String jsonInString = mapper.writeValueAsString(message);
+                            ByteBuf buffer = Unpooled.copiedBuffer(jsonInString, CharsetUtil.UTF_8);
+                            ctx.writeAndFlush(buffer);
+                        } catch (JsonProcessingException e) {
+                            e.printStackTrace();
+                            log.warn(ExceptionUtils.getFullStackTrace(e));
+                        }
+
+                        remoteTunnelIp = IpAddress.valueOf(msg.getLocalIp());
+                        remotePrefix = IpPrefix.valueOf(msg.getLocalPrefix());
+                    });
+                    break;
+                }
+                case INITIATE_FROM_SERVER: {
+                    // CLIENT SIDE CODE
+                    createTunnelInterface(IpAddress.valueOf(msg.getLocalIp()));
+
+                    remoteTunnelIp = IpAddress.valueOf(msg.getLocalIp());
+
+                    break;
+                }
+                default:
+            }
+
+            installRules();
+        }
+
+        @Override
+        public void processMonitorPacket(JSONObject msg) {
+
+        }
+    }
+
+    private class InternalMoasAgent implements ArtemisMoasAgent {
+
+        @Override
+        public void addMoas(IpAddress ipAddress, ChannelHandlerContext ctx) {
+            Optional<ArtemisConfig> config = artemisService.getConfig();
+            if (config.isPresent() && config.get().moasInfo().getMoasAddresses().contains(ipAddress)) {
+                log.info("Received Moas request from legit IP address");
+            } else {
+                log.info("Received Moas request from unknown IP address; ignoring..");
+                ctx.close();
+            }
+        }
+
+        @Override
+        public void removeMoas(IpAddress ipAddress) {
+
+        }
+    }
+
+    private class InternalDeviceListener implements DeviceListener {
+
+        /*
+            EVENT
+            DefaultDevice{id=of:000000000000000a, type=SWITCH, manufacturer=Nicira, Inc., hwVersion=Open vSwitch,
+            swVersion=2.8.0, serialNumber=None, driver=ovs}
+            DefaultPort{element=of:000000000000000a, number=5, isEnabled=true, type=COPPER, portSpeed=0, annotations=
+            {portMac=96:13:4c:12:ca:8a, portName=gre-int}}
+         */
+        @Override
+        public void event(DeviceEvent event) {
+            switch (event.type()) {
+                case PORT_UPDATED:
+                case PORT_ADDED: {
+                    log.info("event {}", event);
+                    // FIXME: currently only one tunnel is supported
+                    if (event.port().annotations().keys().contains("portName") &&
+                            event.port().annotations().value("portName").equals("gre-int")) {
+                        tunnelPort = event.port();
+
+                        installRules();
+                    }
+                }
+                default:
+            }
+        }
+    }
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDetectorImpl.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDetectorImpl.java
new file mode 100644
index 0000000..09a8d2c
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisDetectorImpl.java
@@ -0,0 +1,105 @@
+/*
+ * 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.artemis.impl;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+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.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.artemis.ArtemisDetector;
+import org.onosproject.artemis.ArtemisEventListener;
+import org.onosproject.artemis.ArtemisService;
+import org.onosproject.core.CoreService;
+import org.onosproject.event.EventDeliveryService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+@Component(immediate = true)
+@Service
+public class ArtemisDetectorImpl implements ArtemisDetector {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    /* Services */
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private ArtemisService artemisService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EventDeliveryService eventDispatcher;
+
+    private final ArtemisEventListener artemisEventListener = this::handleArtemisEvent;
+
+    @Activate
+    protected void activate() {
+        artemisService.addListener(artemisEventListener);
+        log.info("Artemis Detector Service Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        artemisService.removeListener(artemisEventListener);
+        log.info("Artemis Detector Service Stopped");
+    }
+
+    /**
+     * Handles a artemis event.
+     *
+     * @param event the artemis event
+     */
+    void handleArtemisEvent(ArtemisEvent event) {
+        // If an instance was deactivated, check whether we need to roll back the upgrade.
+        if (event.type().equals(ArtemisEvent.Type.BGPUPDATE_ADDED)) {
+            JSONObject take = (JSONObject) event.subject();
+
+            log.info("Received information about monitored prefix " + take.toString());
+            artemisService.getConfig().ifPresent(config ->
+                    config.monitoredPrefixes().forEach(artemisPrefix -> {
+                        try {
+                            IpPrefix prefix = artemisPrefix.prefix(), receivedPrefix;
+
+                            receivedPrefix = IpPrefix.valueOf(take.getString("prefix"));
+
+                            if (prefix.contains(receivedPrefix)) {
+                                JSONArray path = take.getJSONArray("path");
+
+                                int state = artemisPrefix.checkPath(path);
+                                if (state >= 100) {
+                                    log.info("BGP Hijack detected; pushing prefix for hijack Deaggregation");
+                                    eventDispatcher.post(new ArtemisEvent(ArtemisEvent.Type.HIJACK_ADDED,
+                                            receivedPrefix));
+                                } else {
+                                    log.info("BGP Update is legit");
+                                }
+                            }
+                        } catch (JSONException e) {
+                            log.error(ExceptionUtils.getFullStackTrace(e));
+                        }
+                    })
+            );
+        }
+    }
+
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisEvent.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisEvent.java
new file mode 100644
index 0000000..38deac7
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisEvent.java
@@ -0,0 +1,93 @@
+/*
+ * 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.artemis.impl;
+
+import com.google.common.base.MoreObjects;
+import org.onosproject.event.AbstractEvent;
+
+import java.util.Objects;
+
+/**
+ * Artemis event.
+ */
+public class ArtemisEvent extends AbstractEvent<ArtemisEvent.Type, Object> {
+
+    /**
+     * Creates an event of a given type and for the specified state and the
+     * current time.
+     *
+     * @param type    upgrade event type
+     * @param subject upgrade state
+     */
+    protected ArtemisEvent(Type type, Object subject) {
+        super(type, subject);
+    }
+
+    /**
+     * Creates an event of a given type and for the specified state and time.
+     *
+     * @param type    upgrade event type
+     * @param subject upgrade state
+     * @param time    occurrence time
+     */
+    protected ArtemisEvent(Type type, Object subject, long time) {
+        super(type, subject, time);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type(), subject(), time());
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof ArtemisEvent) {
+            final ArtemisEvent other = (ArtemisEvent) obj;
+            return Objects.equals(this.type(), other.type()) &&
+                    Objects.equals(this.subject(), other.subject()) &&
+                    Objects.equals(this.time(), other.time());
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this.getClass())
+                .add("type", type())
+                .add("subject", subject())
+                .add("time", time())
+                .toString();
+    }
+
+    /**
+     * Type of artemis-related events.
+     */
+    public enum Type {
+
+        /**
+         * Indicates that a hijack was detected.
+         */
+        HIJACK_ADDED,
+
+        /**
+         * Indicates that a bgp update message was received.
+         */
+        BGPUPDATE_ADDED,
+    }
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisManager.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisManager.java
index 8d10d2e..c714b05 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisManager.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -13,41 +13,44 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
 package org.onosproject.artemis.impl;
 
-import com.google.common.collect.Sets;
 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.onosproject.artemis.ArtemisEventListener;
+import org.onosproject.artemis.ArtemisService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
+import org.onosproject.event.AbstractListenerManager;
 import org.onosproject.net.config.ConfigFactory;
 import org.onosproject.net.config.NetworkConfigEvent;
 import org.onosproject.net.config.NetworkConfigListener;
 import org.onosproject.net.config.NetworkConfigRegistry;
 import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.config.basics.SubjectFactories;
-import org.onosproject.routing.bgp.BgpInfoService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.util.Map;
 import java.util.Optional;
-import java.util.Set;
-import java.util.Timer;
 
-/**
- * Artemis Component.
- */
 @Component(immediate = true)
 @Service
-public class ArtemisManager implements ArtemisService {
+public class ArtemisManager
+        extends AbstractListenerManager<ArtemisEvent, ArtemisEventListener>
+        implements ArtemisService {
+
     private static final String ARTEMIS_APP_ID = "org.onosproject.artemis";
     private static final Class<ArtemisConfig> CONFIG_CLASS = ArtemisConfig.class;
+    private final Logger log = LoggerFactory.getLogger(getClass());
 
+    private final InternalNetworkConfigListener configListener =
+            new InternalNetworkConfigListener();
+    /* Services */
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     private NetworkConfigRegistry registry;
 
@@ -57,21 +60,12 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     private CoreService coreService;
 
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    private BgpInfoService bgpInfoService;
-
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
+    /* Variables */
     private ApplicationId appId;
-    public static boolean logging = false;
+    private ArtemisConfig artemisConfig;
 
-    private Set<PrefixHandler> prefixHandlers = Sets.newHashSet();
-    private Deaggregator deaggr;
-    private Timer timer;
 
-    private final InternalNetworkConfigListener configListener =
-            new InternalNetworkConfigListener();
-
+    /* Config */
     private ConfigFactory<ApplicationId, ArtemisConfig> artemisConfigFactory =
             new ConfigFactory<ApplicationId, ArtemisConfig>(
                     SubjectFactories.APP_SUBJECT_FACTORY, ArtemisConfig.class, "artemis") {
@@ -86,72 +80,25 @@
         appId = coreService.registerApplication(ARTEMIS_APP_ID);
         configService.addListener(configListener);
         registry.registerConfigFactory(artemisConfigFactory);
-        log.info("Artemis Started");
+
+        eventDispatcher.addSink(ArtemisEvent.class, listenerRegistry);
+
+        log.info("Artemis Service Started");
     }
 
     @Deactivate
     protected void deactivate() {
         configService.removeListener(configListener);
         registry.unregisterConfigFactory(artemisConfigFactory);
-        prefixHandlers.forEach(PrefixHandler::stopPrefixMonitors);
-        log.info("Artemis Stopped");
-    }
 
-    /**
-     * Helper function to start and stop monitors on configuration changes.
-     */
-    private void setUpConfiguration() {
-        ArtemisConfig config = configService.getConfig(appId, CONFIG_CLASS);
+        eventDispatcher.removeSink(ArtemisEvent.class);
 
-        if (config == null) {
-            log.warn("No artemis config available!");
-            return;
-        }
-
-        final Set<ArtemisConfig.ArtemisPrefixes> prefixes = config.monitoredPrefixes();
-        final Integer frequency = config.detectionFrequency();
-        final Map<String, Set<String>> monitors = config.activeMonitors();
-
-        Set<PrefixHandler> toRemove = Sets.newHashSet(prefixHandlers);
-
-        for (ArtemisConfig.ArtemisPrefixes curr : prefixes) {
-            final Optional<PrefixHandler> handler = prefixHandlers
-                    .stream()
-                    .filter(prefixHandler -> prefixHandler.getPrefix().equals(curr.prefix()))
-                    .findFirst();
-
-            if (handler.isPresent()) {
-                PrefixHandler oldHandler = handler.get();
-                oldHandler.changeMonitors(monitors);
-
-                // remove the ones we are going to keep from toRemove list
-                toRemove.remove(oldHandler);
-            } else {
-                // Add new handler
-                PrefixHandler newHandler = new PrefixHandler(curr.prefix(), monitors);
-                newHandler.startPrefixMonitors();
-                prefixHandlers.add(newHandler);
-            }
-        }
-
-        // stop and remove old monitors that do not exist on new configuration
-        toRemove.forEach(PrefixHandler::stopPrefixMonitors);
-        prefixHandlers.removeAll(toRemove);
-
-        // new timer task with updated bgp speakers
-        deaggr = new Deaggregator(bgpInfoService);
-        deaggr.setPrefixes(prefixes);
-
-        if (timer != null) {
-            timer.cancel();
-        }
-        timer = new Timer();
-        timer.scheduleAtFixedRate(deaggr, frequency, frequency);
+        log.info("Artemis Service Stopped");
     }
 
     @Override
-    public void setLogger(boolean value) {
-        logging = value;
+    public Optional<ArtemisConfig> getConfig() {
+        return Optional.ofNullable(artemisConfig);
     }
 
     private class InternalNetworkConfigListener implements NetworkConfigListener {
@@ -160,19 +107,27 @@
         public void event(NetworkConfigEvent event) {
             switch (event.type()) {
                 case CONFIG_REGISTERED:
+                case CONFIG_UNREGISTERED: {
                     break;
-                case CONFIG_UNREGISTERED:
-                    break;
-                case CONFIG_ADDED:
-                case CONFIG_UPDATED:
-                case CONFIG_REMOVED:
+                }
+                case CONFIG_REMOVED: {
                     if (event.configClass() == CONFIG_CLASS) {
-                        setUpConfiguration();
+                        artemisConfig = null;
                     }
                     break;
+                }
+                case CONFIG_UPDATED:
+                case CONFIG_ADDED: {
+                    if (event.configClass() == CONFIG_CLASS) {
+                        event.config().ifPresent(config -> artemisConfig = (ArtemisConfig) config);
+                    }
+                    break;
+                }
                 default:
                     break;
             }
         }
+
     }
+
 }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisMonitorImpl.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisMonitorImpl.java
new file mode 100755
index 0000000..1f4d757
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/ArtemisMonitorImpl.java
@@ -0,0 +1,131 @@
+/*
+ * 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.artemis.impl;
+
+import com.google.common.collect.Sets;
+import io.netty.channel.ChannelHandlerContext;
+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.json.JSONObject;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.artemis.ArtemisMonitor;
+import org.onosproject.artemis.ArtemisPacketProcessor;
+import org.onosproject.artemis.impl.objects.ArtemisMessage;
+import org.onosproject.event.EventDeliveryService;
+import org.onosproject.net.config.NetworkConfigEvent;
+import org.onosproject.net.config.NetworkConfigListener;
+import org.onosproject.net.config.NetworkConfigService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+@Component(immediate = true)
+@Service
+public class ArtemisMonitorImpl implements ArtemisMonitor {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+    private static final Class<ArtemisConfig> CONFIG_CLASS = ArtemisConfig.class;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected EventDeliveryService eventDispatcher;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    private NetworkConfigService configService;
+
+    /* Variables */
+    private Set<PrefixHandler> prefixHandlers = Sets.newHashSet();
+    private InternalPacketProcessor packetProcessor = new InternalPacketProcessor();
+
+    private final InternalNetworkConfigListener configListener =
+            new InternalNetworkConfigListener();
+
+    @Activate
+    protected void activate() {
+        configService.addListener(configListener);
+        log.info("Artemis Monitor Service Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        configService.removeListener(configListener);
+        prefixHandlers.forEach(PrefixHandler::stopPrefixMonitors);
+        prefixHandlers.clear();
+
+        log.info("Artemis Monitor Service Stopped");
+    }
+
+    private class InternalPacketProcessor implements ArtemisPacketProcessor {
+
+        @Override
+        public void processMoasPacket(ArtemisMessage msg, ChannelHandlerContext ctx) {
+
+        }
+
+        @Override
+        public void processMonitorPacket(JSONObject msg) {
+            // TODO: in future maybe store the BGP Update message and propagate it to the cluster instead of Events
+            eventDispatcher.post(new ArtemisEvent(ArtemisEvent.Type.BGPUPDATE_ADDED, msg));
+        }
+    }
+
+    private class InternalNetworkConfigListener implements NetworkConfigListener {
+
+        @Override
+        public void event(NetworkConfigEvent event) {
+            switch (event.type()) {
+                case CONFIG_REGISTERED:
+                case CONFIG_UNREGISTERED: {
+                    break;
+                }
+                case CONFIG_REMOVED: {
+                    if (event.configClass() == CONFIG_CLASS) {
+                        prefixHandlers.forEach(PrefixHandler::stopPrefixMonitors);
+                        prefixHandlers.clear();
+                    }
+                    break;
+                }
+                case CONFIG_UPDATED:
+                case CONFIG_ADDED: {
+                    if (event.configClass() == CONFIG_CLASS) {
+                        event.config().ifPresent(config -> {
+                            ArtemisConfig artemisConfig = (ArtemisConfig) config;
+                            Set<IpPrefix> ipPrefixes = artemisConfig.prefixesToMonitor();
+                            Map<String, Set<String>> monitors = artemisConfig.activeMonitors();
+
+                            prefixHandlers.forEach(PrefixHandler::stopPrefixMonitors);
+                            prefixHandlers.clear();
+                            prefixHandlers = ipPrefixes.stream()
+                                    .map(prefix -> new PrefixHandler(prefix, monitors, packetProcessor))
+                                    .collect(Collectors.toSet());
+
+                            prefixHandlers.forEach(PrefixHandler::startPrefixMonitors);
+                        });
+                    }
+                    break;
+                }
+                default:
+                    break;
+            }
+        }
+
+    }
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/DataHandler.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/DataHandler.java
deleted file mode 100644
index e4eb2cf..0000000
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/DataHandler.java
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * 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.artemis.impl;
-
-import org.json.JSONObject;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.util.ArrayList;
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Helper class that handles BGP Update messages.
- */
-public final class DataHandler {
-    private static final File DATA_FILE = new File("data.json");
-    private static final File HIJACKS_FILE = new File("hijack.json");
-
-    private final AtomicReference<ArrayList<JSONObject>> data = new AtomicReference<ArrayList<JSONObject>>();
-
-    private static DataHandler instance = new DataHandler();
-
-    private DataHandler() {
-        data.set(new ArrayList<>());
-    }
-
-    /**
-     * Singleton for data handler class.
-     *
-     * @return instance of class
-     */
-    public static synchronized DataHandler getInstance() {
-        if (instance == null) {
-            instance = new DataHandler();
-        }
-        return instance;
-    }
-
-    /**
-     * Atomic append a BGP update message to a list.
-     *
-     * @param obj BGP update message
-     */
-    public synchronized void appendData(JSONObject obj) {
-        data.get().add(obj);
-    }
-
-    /**
-     * Atomic read and clear a list of BGP updates.
-     *
-     * @return list of messages that received in 'threshold' period
-     */
-    synchronized ArrayList<JSONObject> getData() {
-        ArrayList<JSONObject> tmp = (ArrayList<JSONObject>) data.get().clone();
-        data.get().clear();
-        return tmp;
-    }
-
-    /**
-     * A serializer to write incoming BGP updates and hijack attempts to json files.
-     */
-    public static class Serializer {
-        private static RandomAccessFile fwData, fwHijack;
-        private static long lengthData, lengthHijack;
-
-        static {
-            try {
-                if (DATA_FILE.exists()) {
-                    fwData = new RandomAccessFile(DATA_FILE, "rw");
-                } else {
-                    fwData = new RandomAccessFile(DATA_FILE, "rw");
-                    fwData.writeBytes("[\n]");
-                }
-                lengthData = fwData.length() - 1;
-
-                if (HIJACKS_FILE.exists()) {
-                    fwHijack = new RandomAccessFile(HIJACKS_FILE, "rw");
-                } else {
-                    fwHijack = new RandomAccessFile(HIJACKS_FILE, "rw");
-                    fwHijack.writeBytes("[\n]");
-                }
-                lengthHijack = fwHijack.length() - 1;
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-
-        /**
-         * Writes BGP update to json file.
-         *
-         * @param data BGP update
-         */
-        public static synchronized void writeData(Object data) {
-            try {
-                String entry = data.toString() + ",\n]";
-                fwData.seek(lengthData);
-                fwData.writeBytes(entry);
-                lengthData += entry.length() - 1;
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-
-        /**
-         * Writes detected BGP hijack to json file.
-         *
-         * @param data BGP update of hijack
-         */
-        static synchronized void writeHijack(Object data) {
-            try {
-                String entry = data.toString() + ",\n]";
-                fwHijack.seek(lengthHijack);
-                fwHijack.writeBytes(entry);
-                lengthHijack += entry.length() - 1;
-            } catch (IOException e) {
-                e.printStackTrace();
-            }
-        }
-    }
-}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/Deaggregator.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/Deaggregator.java
deleted file mode 100644
index b78ade1..0000000
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/Deaggregator.java
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * 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.artemis.impl;
-
-import com.google.common.collect.Sets;
-import org.json.JSONArray;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.onlab.packet.IpAddress;
-import org.onlab.packet.IpPrefix;
-import org.onosproject.artemis.impl.bgpspeakers.BgpSpeakers;
-import org.onosproject.artemis.impl.bgpspeakers.QuaggaBgpSpeakers;
-import org.onosproject.routing.bgp.BgpInfoService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.ArrayList;
-import java.util.Set;
-
-/**
- * Timertask class which detects and mitigates BGP hijacks.
- */
-class Deaggregator extends java.util.TimerTask {
-
-    private final Logger log = LoggerFactory.getLogger(getClass());
-    private Set<ArtemisConfig.ArtemisPrefixes> prefixes = Sets.newHashSet();
-    private Set<BgpSpeakers> bgpSpeakers = Sets.newHashSet();
-
-    Deaggregator(BgpInfoService bgpInfoService) {
-        super();
-        // deaggregator must know the type of the connected BGP speakers and the BGP info.
-        // for this example we only have one Quagga BGP speaker.
-        bgpSpeakers.add(new QuaggaBgpSpeakers(bgpInfoService));
-    }
-
-    @Override
-    public void run() {
-        ArrayList<JSONObject> messagesArray = DataHandler.getInstance().getData();
-//        log.info("Messages size: " + messagesArray.size());
-
-        // Example of BGP Update message:
-        // {
-        //  "path":[65001, 65002, 65004], (origin being last)
-        //  "prefix":"12.0.0.0/8",
-        // }
-
-        prefixes.forEach(prefix -> {
-            IpPrefix monitoredPrefix = prefix.prefix();
-
-            // for each update message in memory check for hijack
-            for (JSONObject tmp : messagesArray) {
-                IpPrefix receivedPrefix = null;
-                try {
-                    receivedPrefix = IpPrefix.valueOf(tmp.getString("prefix"));
-                } catch (JSONException e) {
-                    log.warn("JSONException: " + e.getMessage());
-                    e.printStackTrace();
-                }
-                if (receivedPrefix == null) {
-                    continue;
-                }
-
-                // check if the announced network address is inside our subnet
-                if (monitoredPrefix.contains(receivedPrefix)) {
-                    JSONArray path = null;
-                    try {
-                        path = tmp.getJSONArray("path");
-                    } catch (JSONException e) {
-                        log.warn("JSONException: " + e.getMessage());
-                        e.printStackTrace();
-                    }
-                    if (path == null) {
-                        continue;
-                    }
-
-                    int state = prefix.checkPath(path);
-                    if (state >= 100) {
-                        log.warn("BGP Hijack detected of type " +
-                                (state - 100) + "\n" + tmp.toString());
-                        DataHandler.Serializer.writeHijack(tmp);
-                        // can only de-aggregate /23 subnets and higher
-                        int cidr = receivedPrefix.prefixLength();
-                        if (receivedPrefix.prefixLength() < 24) {
-                            byte[] octets = receivedPrefix.address().toOctets();
-                            int byteGroup = (cidr + 1) / 8,
-                                    bitPos = 8 - (cidr + 1) % 8;
-
-                            octets[byteGroup] = (byte) (octets[byteGroup] & ~(1 << bitPos));
-                            String low = IpPrefix.valueOf(IpAddress.Version.INET, octets, cidr + 1).toString();
-                            octets[byteGroup] = (byte) (octets[byteGroup] | (1 << bitPos));
-                            String high = IpPrefix.valueOf(IpAddress.Version.INET, octets, cidr + 1).toString();
-
-                            String[] prefixes = {low, high};
-                            bgpSpeakers.forEach(bgpSpeakers -> bgpSpeakers.announceSubPrefixes(prefixes));
-                        } else {
-                            log.warn("Cannot announce smaller prefix than /24");
-                        }
-                    }
-                }
-            }
-        });
-    }
-
-    public Set<ArtemisConfig.ArtemisPrefixes> getPrefixes() {
-        return prefixes;
-    }
-
-    public void setPrefixes(Set<ArtemisConfig.ArtemisPrefixes> prefixes) {
-        this.prefixes = prefixes;
-    }
-}
\ No newline at end of file
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/PrefixHandler.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/PrefixHandler.java
index 57553b5..6fa407e 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/PrefixHandler.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/PrefixHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -15,12 +15,12 @@
  */
 package org.onosproject.artemis.impl;
 
-import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import org.onlab.packet.IpPrefix;
-import org.onosproject.artemis.impl.monitors.ExaBgpMonitor;
-import org.onosproject.artemis.impl.monitors.Monitor;
-import org.onosproject.artemis.impl.monitors.RipeMonitor;
+import org.onosproject.artemis.ArtemisPacketProcessor;
+import org.onosproject.artemis.Monitors;
+import org.onosproject.artemis.impl.monitors.ExaBgpMonitors;
+import org.onosproject.artemis.impl.monitors.RipeMonitors;
 
 import java.util.Map;
 import java.util.Objects;
@@ -33,22 +33,23 @@
 class PrefixHandler {
 
     private IpPrefix prefix;
-    private Set<Monitor> prefixMonitors = Sets.newHashSet();
+    private Set<Monitors> prefixMonitors = Sets.newHashSet();
 
     /**
      * Constructor that takes a CIDR-notation string and a list of monitors.
      *
-     * @param prefix   A CIDR-notation string, e.g. "192.168.0.1/24"
-     * @param monitors A map of strings to a set of string for monitors, e.g. "ripe", ["host1","host2",..]
+     * @param prefix          A CIDR-notation string, e.g. "192.168.0.1/24"
+     * @param monitors        A map of strings to a set of string for monitors, e.g. "ripe", ["host1","host2",..]
+     * @param packetProcessor Packet processor
      */
-    PrefixHandler(IpPrefix prefix, Map<String, Set<String>> monitors) {
+    PrefixHandler(IpPrefix prefix, Map<String, Set<String>> monitors, ArtemisPacketProcessor packetProcessor) {
         this.prefix = prefix;
 
         monitors.forEach((type, values) -> {
-            if (type.equals(Monitor.Types.RIPE.toString())) {
-                values.forEach(host -> prefixMonitors.add(new RipeMonitor(prefix, host)));
-            } else if (type.equals(Monitor.Types.EXABGP.toString())) {
-                values.forEach(host -> prefixMonitors.add(new ExaBgpMonitor(prefix, host)));
+            if (Monitors.Types.getEnum(type).equals(Monitors.Types.RIPE)) {
+                values.forEach(host -> prefixMonitors.add(new RipeMonitors(prefix, host, packetProcessor)));
+            } else if (Monitors.Types.getEnum(type).equals(Monitors.Types.EXABGP)) {
+                values.forEach(host -> prefixMonitors.add(new ExaBgpMonitors(prefix, host, packetProcessor)));
             }
         });
     }
@@ -57,14 +58,14 @@
      * Start all monitors for this prefix.
      */
     void startPrefixMonitors() {
-        prefixMonitors.forEach(Monitor::startMonitor);
+        prefixMonitors.forEach(Monitors::startMonitor);
     }
 
     /**
      * Stop all monitors for this prefix.
      */
     void stopPrefixMonitors() {
-        prefixMonitors.forEach(Monitor::stopMonitor);
+        prefixMonitors.forEach(Monitors::stopMonitor);
     }
 
     /**
@@ -76,61 +77,20 @@
         return prefix;
     }
 
-    /**
-     * Changes the monitors based on the new list given.
-     *
-     * @param newMonitors monitors to be added
-     */
-    void changeMonitors(Map<String, Set<String>> newMonitors) {
-        Set<String> newTypes = newMonitors.keySet();
-        Set<Monitor> monToRemove = Sets.newHashSet();
-        Map<String, Set<String>> monToAdd = Maps.newHashMap(newMonitors);
-
-        prefixMonitors.forEach(monitor -> {
-            String oldType = monitor.getType().toString();
-            if (newTypes.contains(oldType)) {
-                Set<String> newHosts = newMonitors.get(oldType);
-                String oldHost = monitor.getHost();
-                if (newHosts.contains(oldHost)) {
-                    monToAdd.remove(oldHost, oldHost);
-                } else {
-                    monToRemove.add(monitor);
-                }
-            } else {
-                monToRemove.add(monitor);
-            }
-        });
-
-        monToRemove.forEach(Monitor::stopMonitor);
-        prefixMonitors.removeAll(monToRemove);
-
-        //TODO
-        monToAdd.forEach((type, values) -> {
-            if (type.equals(Monitor.Types.RIPE.toString())) {
-                values.forEach(host -> prefixMonitors.add(new RipeMonitor(prefix, host)));
-            } else if (type.equals(Monitor.Types.EXABGP.toString())) {
-                values.forEach(host -> prefixMonitors.add(new ExaBgpMonitor(prefix, host)));
-            }
-        });
-
-        startPrefixMonitors();
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+        PrefixHandler that = (PrefixHandler) o;
+        return Objects.equals(prefix, that.prefix);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hashCode(prefix);
+        return Objects.hash(prefix);
     }
-
-    @Override
-    public boolean equals(Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj instanceof PrefixHandler) {
-            final PrefixHandler that = (PrefixHandler) obj;
-            return Objects.equals(this.prefix, that.prefix);
-        }
-        return false;
-    }
-
 }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/BgpSpeakers.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/BgpSpeakers.java
deleted file mode 100644
index a3642ed..0000000
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/BgpSpeakers.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.artemis.impl.bgpspeakers;
-
-import org.onosproject.routing.bgp.BgpInfoService;
-import org.onosproject.routing.bgp.BgpSession;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-import java.util.Collection;
-
-/**
- * Abstract class for all the types of BGP Speakers.
- */
-public abstract class BgpSpeakers {
-
-    final Logger log = LoggerFactory.getLogger(getClass());
-    Collection<BgpSession> bgpSessions;
-
-    BgpSpeakers(BgpInfoService bgpInfoService) {
-        this.bgpSessions = bgpInfoService.getBgpSessions();
-    }
-
-    /**
-     * Abstract function which announces the two new subprefixes on the BGP Speaker.
-     * @param prefixes list of two prefixes
-     */
-    public abstract void announceSubPrefixes(String[] prefixes);
-}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/QuaggaBgpSpeakers.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/QuaggaBgpSpeakers.java
index 462a033..8c95896 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/QuaggaBgpSpeakers.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/QuaggaBgpSpeakers.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -15,8 +15,12 @@
  */
 package org.onosproject.artemis.impl.bgpspeakers;
 
+import org.apache.commons.lang.exception.ExceptionUtils;
 import org.apache.commons.net.telnet.TelnetClient;
+import org.onosproject.artemis.BgpSpeakers;
 import org.onosproject.routing.bgp.BgpInfoService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.InputStream;
 import java.io.PrintStream;
@@ -25,20 +29,23 @@
 /**
  * Quagga interface to connect and announce prefixes.
  */
-public class QuaggaBgpSpeakers extends BgpSpeakers {
+public class QuaggaBgpSpeakers implements BgpSpeakers {
+    // TODO: move this to configuration
     private static final String PASSWORD = "sdnip";
-
+    private final Logger log = LoggerFactory.getLogger(getClass());
     private TelnetClient telnet = new TelnetClient();
     private InputStream in;
     private PrintStream out;
+    private BgpInfoService bgpInfoService;
 
     public QuaggaBgpSpeakers(BgpInfoService bgpInfoService) {
-        super(bgpInfoService);
+        this.bgpInfoService = bgpInfoService;
     }
 
     @Override
     public void announceSubPrefixes(String[] prefixes) {
-        bgpSessions.forEach((session) -> {
+        log.info("Announcing subprefixes: {}", (Object[]) prefixes);
+        bgpInfoService.getBgpSessions().forEach((session) -> {
             String peerIp = session.remoteInfo().ip4Address().toString(),
                     localAs = String.valueOf(session.remoteInfo().as4Number());
             assert peerIp != null;
@@ -59,7 +66,7 @@
 
                 log.info("Announced " + prefixes[0] + " and " + prefixes[1] + " at " + peerIp);
             } catch (Exception e) {
-                log.warn(e.getMessage());
+                log.error(ExceptionUtils.getFullStackTrace(e));
             }
         });
     }
@@ -85,7 +92,7 @@
                 ch = (char) in.read();
             }
         } catch (Exception e) {
-            log.warn(e.getMessage());
+            log.error(ExceptionUtils.getFullStackTrace(e));
         }
         return null;
     }
@@ -100,7 +107,7 @@
             out.println(value);
             out.flush();
         } catch (Exception e) {
-            log.warn(e.getMessage());
+            log.error(ExceptionUtils.getFullStackTrace(e));
         }
     }
 
@@ -108,7 +115,7 @@
      * Configure terminal and announce prefix inside the Quagga router.
      *
      * @param prefixes prefixes to announce
-     * @param localAs ASN of BGP Speaker
+     * @param localAs  ASN of BGP Speaker
      */
     private void announcePrefix(String[] prefixes, String localAs) {
         write("en");
@@ -131,7 +138,7 @@
         try {
             telnet.disconnect();
         } catch (Exception e) {
-            log.warn(e.getMessage());
+            log.error(ExceptionUtils.getFullStackTrace(e));
         }
     }
 }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/package-info.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/package-info.java
index 2dfcb49..4eb19fd 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/package-info.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/bgpspeakers/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientController.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientController.java
new file mode 100644
index 0000000..fccda3e
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientController.java
@@ -0,0 +1,107 @@
+/*
+ * 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.artemis.impl.moas;
+
+import com.google.common.annotations.Beta;
+import io.netty.bootstrap.Bootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioSocketChannel;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.artemis.ArtemisPacketProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * MOAS Client Controller.
+ */
+@Beta
+public class MoasClientController {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private IpAddress host;
+    private EventLoopGroup workerGroup;
+    private MoasClientHandler ach;
+    private ChannelFuture channel;
+    private IpAddress localIp;
+    private IpPrefix localPrefix;
+    private ArtemisPacketProcessor packetProcessor;
+
+    public MoasClientController(ArtemisPacketProcessor packetProcessor,
+                                IpAddress host, IpAddress localIp, IpPrefix localPrefix) {
+        this.host = host;
+        this.ach = null;
+        this.localIp = localIp;
+        this.localPrefix = localPrefix;
+        this.packetProcessor = packetProcessor;
+    }
+
+    /**
+     * Run the MOAS client.
+     */
+    public void run() {
+        try {
+            final Bootstrap bootstrap = createBootstrap();
+
+            ach = new MoasClientHandler(localIp, localPrefix, packetProcessor);
+
+            bootstrap.handler(new ChannelInitializer<SocketChannel>() {
+                @Override
+                public void initChannel(SocketChannel ch) throws Exception {
+                    ch.pipeline().addLast(ach);
+                }
+            });
+
+            channel = bootstrap.connect(host.toInetAddress(), 32323).sync();
+        } catch (Exception e) {
+            log.warn(ExceptionUtils.getFullStackTrace(e));
+        }
+    }
+
+    /**
+     * Bootstrap netty socket.
+     *
+     * @return bootstrap
+     * @throws Exception exception
+     */
+    private Bootstrap createBootstrap() throws Exception {
+        try {
+            workerGroup = new NioEventLoopGroup();
+            return new Bootstrap()
+                    .group(workerGroup)
+                    .channel(NioSocketChannel.class)
+                    .option(ChannelOption.SO_KEEPALIVE, true);
+        } catch (Exception e) {
+            throw new Exception(e);
+        }
+    }
+
+    /**
+     * Stop the MOAS client.
+     */
+    public void stop() {
+        channel.channel().close();
+        workerGroup.shutdownGracefully();
+    }
+
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientHandler.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientHandler.java
new file mode 100644
index 0000000..58954d9
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasClientHandler.java
@@ -0,0 +1,95 @@
+/*
+ * 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.artemis.impl.moas;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.annotations.Beta;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.Unpooled;
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import io.netty.util.CharsetUtil;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.IpPrefix;
+import org.onosproject.artemis.ArtemisPacketProcessor;
+import org.onosproject.artemis.impl.objects.ArtemisMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+/**
+ * MOAS Client channel handler.
+ */
+@Sharable
+@Beta
+public class MoasClientHandler extends ChannelInboundHandlerAdapter {
+
+    private static final Logger log =
+            LoggerFactory.getLogger(MoasClientHandler.class);
+
+    private IpAddress localIp;
+    private IpPrefix localPrefix;
+    private ArtemisPacketProcessor packetProcessor;
+
+    MoasClientHandler(IpAddress localIp, IpPrefix localPrefix, ArtemisPacketProcessor packetProcessor) {
+        this.localIp = localIp;
+        this.packetProcessor = packetProcessor;
+        this.localPrefix = localPrefix;
+    }
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        log.info("Connected to server {}", ctx.channel().remoteAddress());
+
+        ArtemisMessage message = new ArtemisMessage();
+        message.setType(ArtemisMessage.Type.INITIATE_FROM_CLIENT);
+        message.setLocalIp(localIp.toString());
+        message.setLocalPrefix(localPrefix.toString());
+
+        ObjectMapper mapper = new ObjectMapper();
+        try {
+            String jsonInString = mapper.writeValueAsString(message);
+            ByteBuf buffer = Unpooled.copiedBuffer(jsonInString, CharsetUtil.UTF_8);
+            ctx.writeAndFlush(buffer);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+            log.warn(ExceptionUtils.getFullStackTrace(e));
+        }
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws IOException {
+        ByteBuf in = (ByteBuf) msg;
+        String strMsg = in.toString(io.netty.util.CharsetUtil.US_ASCII);
+
+        ObjectMapper mapper = new ObjectMapper();
+        ArtemisMessage actObj = mapper.readValue(strMsg, ArtemisMessage.class);
+
+        packetProcessor.processMoasPacket(actObj, ctx);
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+        log.error(ExceptionUtils.getFullStackTrace(cause));
+        cause.printStackTrace();
+        ctx.close();
+    }
+
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerController.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerController.java
new file mode 100644
index 0000000..c27a134
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerController.java
@@ -0,0 +1,129 @@
+/*
+ * 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.artemis.impl.moas;
+
+import com.google.common.annotations.Beta;
+import io.netty.bootstrap.ServerBootstrap;
+import io.netty.channel.ChannelFuture;
+import io.netty.channel.ChannelInitializer;
+import io.netty.channel.ChannelOption;
+import io.netty.channel.EventLoopGroup;
+import io.netty.channel.nio.NioEventLoopGroup;
+import io.netty.channel.socket.SocketChannel;
+import io.netty.channel.socket.nio.NioServerSocketChannel;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.onosproject.artemis.ArtemisMoasAgent;
+import org.onosproject.artemis.ArtemisPacketProcessor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+
+/**
+ * MOAS Server Controller.
+ */
+@Beta
+public class MoasServerController {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    protected ArtemisMoasAgent deviceAgent;
+    protected ArtemisPacketProcessor packetAgent;
+
+    private EventLoopGroup bossGroup;
+    private EventLoopGroup workerGroup;
+    private ChannelFuture channel;
+    private int port = 32323;
+
+    private boolean isRunning = false;
+
+    /**
+     * Run the MOAS Servcer.
+     */
+    private void run() {
+        final MoasServerController ctrl = this;
+        try {
+            final ServerBootstrap bootstrap = createServerBootStrap();
+
+            bootstrap.childHandler(new ChannelInitializer<SocketChannel>() {
+                @Override
+                public void initChannel(SocketChannel ch) throws Exception {
+                    ch.pipeline().addLast(
+                            new MoasServerHandler(ctrl)
+                    );
+                }
+            });
+
+            channel = bootstrap.bind(port).sync();
+            isRunning = true;
+        } catch (Exception e) {
+            log.warn(ExceptionUtils.getFullStackTrace(e));
+        }
+    }
+
+    /**
+     * Create netty server bootstrap.
+     *
+     * @return bootstrap
+     * @throws Exception exception
+     */
+    private ServerBootstrap createServerBootStrap() throws Exception {
+        try {
+            bossGroup = new NioEventLoopGroup();
+            workerGroup = new NioEventLoopGroup();
+
+            return new ServerBootstrap()
+                    .group(bossGroup, workerGroup)
+                    .channel(NioServerSocketChannel.class)
+                    .option(ChannelOption.SO_REUSEADDR, true)
+                    .childOption(ChannelOption.SO_KEEPALIVE, true)
+                    .childOption(ChannelOption.TCP_NODELAY, true);
+        } catch (Exception e) {
+            throw new Exception(e);
+        }
+    }
+
+    /**
+     * Start Server Controller and initialize agents.
+     *
+     * @param deviceAgent device agent
+     * @param packetAgent packet agen
+     */
+    public void start(ArtemisMoasAgent deviceAgent, ArtemisPacketProcessor packetAgent) {
+        if (isRunning) {
+            stop();
+            this.deviceAgent = deviceAgent;
+            this.packetAgent = packetAgent;
+            run();
+        } else {
+            this.deviceAgent = deviceAgent;
+            this.packetAgent = packetAgent;
+            run();
+        }
+        isRunning = true;
+    }
+
+    /**
+     * Stop Server Controller.
+     */
+    public void stop() {
+        if (isRunning) {
+            channel.channel().close();
+            bossGroup.shutdownGracefully();
+            workerGroup.shutdownGracefully();
+            isRunning = false;
+        }
+    }
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerHandler.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerHandler.java
new file mode 100644
index 0000000..d140416
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/MoasServerHandler.java
@@ -0,0 +1,85 @@
+/*
+ * 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.artemis.impl.moas;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.annotations.Beta;
+import io.netty.buffer.ByteBuf;
+import io.netty.channel.ChannelHandler.Sharable;
+import io.netty.channel.ChannelHandlerContext;
+import io.netty.channel.ChannelInboundHandlerAdapter;
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.onlab.packet.IpAddress;
+import org.onosproject.artemis.impl.objects.ArtemisMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
+
+/**
+ * MOAS Server channel handler.
+ */
+@Sharable
+@Beta
+public class MoasServerHandler extends ChannelInboundHandlerAdapter {
+
+    private static final Logger log =
+            LoggerFactory.getLogger(MoasServerHandler.class);
+
+    private MoasServerController controller;
+
+    MoasServerHandler(MoasServerController controller) {
+        this.controller = controller;
+    }
+
+    @Override
+    public void channelActive(ChannelHandlerContext ctx) throws Exception {
+        final SocketAddress address = ctx.channel().remoteAddress();
+        if (!(address instanceof InetSocketAddress)) {
+            log.warn("Invalid client connection. MOAS is identified based on IP");
+            ctx.close();
+            return;
+        }
+
+        final InetSocketAddress inetAddress = (InetSocketAddress) address;
+        final String host = inetAddress.getHostString();
+        log.info("New client connected to the Server: {}", host);
+
+        controller.deviceAgent.addMoas(IpAddress.valueOf(host), ctx);
+    }
+
+    @Override
+    public void channelRead(ChannelHandlerContext ctx, Object msg) throws IOException {
+        ByteBuf in = (ByteBuf) msg;
+        String strMsg = in.toString(io.netty.util.CharsetUtil.US_ASCII);
+
+        ObjectMapper mapper = new ObjectMapper();
+        ArtemisMessage actObj = mapper.readValue(strMsg, ArtemisMessage.class);
+
+        controller.packetAgent.processMoasPacket(actObj, ctx);
+    }
+
+    @Override
+    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+        log.error(ExceptionUtils.getFullStackTrace(cause));
+        cause.printStackTrace();
+        ctx.close();
+    }
+
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/package-info.java
similarity index 82%
copy from apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java
copy to apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/package-info.java
index b2d0dc4..dfe902f 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/moas/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -15,6 +15,6 @@
  */
 
 /**
- * Artemis CLI commands.
+ * MOAS related package.
  */
-package org.onosproject.artemis.cli;
\ No newline at end of file
+package org.onosproject.artemis.impl.moas;
\ No newline at end of file
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitor.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitors.java
similarity index 79%
rename from apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitor.java
rename to apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitors.java
index 44019d5..5fb9be4 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitor.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/ExaBgpMonitors.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -20,8 +20,8 @@
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.onlab.packet.IpPrefix;
-import org.onosproject.artemis.impl.ArtemisManager;
-import org.onosproject.artemis.impl.DataHandler;
+import org.onosproject.artemis.ArtemisPacketProcessor;
+import org.onosproject.artemis.Monitors;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,17 +29,19 @@
 import java.util.Objects;
 
 /**
- * Implementation of ExaBGP Route Collector Monitor.
+ * Implementation of ExaBGP Route Collector Monitors.
  */
-public class ExaBgpMonitor extends Monitor {
+public class ExaBgpMonitors implements Monitors {
+    private final Logger log = LoggerFactory.getLogger(getClass());
     private String host;
     private Socket socket;
+    private IpPrefix prefix;
+    private ArtemisPacketProcessor packetProcessor;
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
-    public ExaBgpMonitor(IpPrefix prefix, String host) {
-        super(prefix);
+    public ExaBgpMonitors(IpPrefix prefix, String host, ArtemisPacketProcessor packetProcessor) {
         this.host = host;
+        this.prefix = prefix;
+        this.packetProcessor = packetProcessor;
     }
 
     /**
@@ -56,22 +58,20 @@
         }
     }
 
+    /**
+     * ExaBGP message received on the socket.io.
+     *
+     * @param args exabgp message
+     */
     private void onExaMessage(Object[] args) {
         JSONObject message = (JSONObject) args[0];
 
         try {
             if (message.getString("type").equals("A")) {
-                // Write BGP message to a json database
-                DataHandler.Serializer.writeData(args[0]);
-
-                if (ArtemisManager.logging) {
-                    log.info(message.toString());
-                }
-
                 // Example of BGP Update message:
                 // {
                 //  "path":[65001],
-                //  "peer":"1.1.1.1",
+                //  "peer":"1.1.1.s1",
                 //  "prefix":"12.0.0.0/8",
                 //  "host":"exabgp", <-- Can put IP here
                 //  "type":"A",
@@ -85,7 +85,7 @@
                 message.remove("timestamp");
 
                 // Append synchronized message to message list in memory.
-                DataHandler.getInstance().appendData(message);
+                packetProcessor.processMonitorPacket(message);
             }
         } catch (JSONException e) {
             e.printStackTrace();
@@ -93,6 +93,16 @@
     }
 
     @Override
+    public IpPrefix getPrefix() {
+        return prefix;
+    }
+
+    @Override
+    public void setPrefix(IpPrefix prefix) {
+        this.prefix = prefix;
+    }
+
+    @Override
     public void startMonitor() {
         if (!isRunning()) {
             log.info("Starting EXA monitor for " + prefix + " / " + host);
@@ -120,11 +130,6 @@
     }
 
     @Override
-    public Types getType() {
-        return Types.EXABGP;
-    }
-
-    @Override
     public boolean isRunning() {
         return this.socket != null;
     }
@@ -149,8 +154,8 @@
         if (this == obj) {
             return true;
         }
-        if (obj instanceof ExaBgpMonitor) {
-            final ExaBgpMonitor that = (ExaBgpMonitor) obj;
+        if (obj instanceof ExaBgpMonitors) {
+            final ExaBgpMonitors that = (ExaBgpMonitors) obj;
             return Objects.equals(this.prefix, that.prefix) &&
                     Objects.equals(this.host, that.host);
         }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitor.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitors.java
similarity index 82%
rename from apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitor.java
rename to apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitors.java
index 811eece..e848875 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitor.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/RipeMonitors.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -17,11 +17,12 @@
 
 import io.socket.client.IO;
 import io.socket.client.Socket;
+import org.apache.commons.lang.exception.ExceptionUtils;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.onlab.packet.IpPrefix;
-import org.onosproject.artemis.impl.ArtemisManager;
-import org.onosproject.artemis.impl.DataHandler;
+import org.onosproject.artemis.ArtemisPacketProcessor;
+import org.onosproject.artemis.Monitors;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -29,17 +30,19 @@
 import java.util.Objects;
 
 /**
- * Implementation of RIPE Route Collector Monitor.
+ * Implementation of RIPE Route Collector Monitors.
  */
-public class RipeMonitor extends Monitor {
+public class RipeMonitors implements Monitors {
+    private final Logger log = LoggerFactory.getLogger(getClass());
     private String host;
     private Socket socket;
+    private IpPrefix prefix;
+    private ArtemisPacketProcessor packetProcessor;
 
-    private final Logger log = LoggerFactory.getLogger(getClass());
-
-    public RipeMonitor(IpPrefix prefix, String host) {
-        super(prefix);
+    public RipeMonitors(IpPrefix prefix, String host, ArtemisPacketProcessor packetProcessor) {
+        this.prefix = prefix;
         this.host = host;
+        this.packetProcessor = packetProcessor;
     }
 
     /**
@@ -64,6 +67,16 @@
         }
     }
 
+    @Override
+    public IpPrefix getPrefix() {
+        return prefix;
+    }
+
+    @Override
+    public void setPrefix(IpPrefix prefix) {
+        this.prefix = prefix;
+    }
+
     /**
      * socket.io onRisMessage event handler.
      * This event is custom made that triggers when it receives an BGP update/withdraw for our prefix.
@@ -74,13 +87,6 @@
         try {
             JSONObject message = (JSONObject) args[0];
             if (message.getString("type").equals("A")) {
-                // Write BGP message to a json database
-                DataHandler.Serializer.writeData(args[0]);
-
-                if (ArtemisManager.logging) {
-                    log.info(message.toString());
-                }
-
                 // Example of BGP Update message:
                 // {
                 //  "timestamp":1488044022.97,
@@ -101,9 +107,10 @@
                 message.remove("host");
 
                 // Append synchronized message to message list in memory.
-                DataHandler.getInstance().appendData(message);
+                packetProcessor.processMonitorPacket(message);
             }
         } catch (JSONException e) {
+            log.error(ExceptionUtils.getFullStackTrace(e));
             e.printStackTrace();
         }
         socket.emit("ping");
@@ -122,6 +129,7 @@
                 this.socket.on(Socket.EVENT_PONG, args -> socket.emit("ping"));
                 this.socket.on("ris_message", this::onRisMessage);
             } catch (URISyntaxException e) {
+                log.error(ExceptionUtils.getFullStackTrace(e));
                 e.printStackTrace();
             }
 
@@ -141,11 +149,6 @@
     }
 
     @Override
-    public Types getType() {
-        return Types.RIPE;
-    }
-
-    @Override
     public boolean isRunning() {
         return this.socket != null;
     }
@@ -170,8 +173,8 @@
         if (this == obj) {
             return true;
         }
-        if (obj instanceof RipeMonitor) {
-            final RipeMonitor that = (RipeMonitor) obj;
+        if (obj instanceof RipeMonitors) {
+            final RipeMonitors that = (RipeMonitors) obj;
             return Objects.equals(this.prefix, that.prefix) &&
                     Objects.equals(this.host, that.host);
         }
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/package-info.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/package-info.java
index 8804874..d47aa36 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/package-info.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/monitors/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/objects/ArtemisMessage.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/objects/ArtemisMessage.java
new file mode 100644
index 0000000..78d4e44
--- /dev/null
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/objects/ArtemisMessage.java
@@ -0,0 +1,80 @@
+/*
+ * 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.artemis.impl.objects;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.fasterxml.jackson.annotation.JsonPropertyOrder;
+
+import java.io.Serializable;
+
+/**
+ * Messages that are exchanged between the two MOAS entities.
+ */
+@JsonInclude(JsonInclude.Include.NON_NULL)
+@JsonPropertyOrder({
+        "type", "localIp", "localPrefix"
+})
+public class ArtemisMessage implements Serializable {
+
+    @JsonProperty("type")
+    private Type type;
+
+    @JsonProperty("localIp")
+    private String localIp;
+
+    @JsonProperty("localPrefix")
+    private String localPrefix;
+
+    public Type getType() {
+        return type;
+    }
+
+    public void setType(Type type) {
+        this.type = type;
+    }
+
+    public String getLocalIp() {
+        return localIp;
+    }
+
+    public void setLocalIp(String localIp) {
+        this.localIp = localIp;
+    }
+
+    public String getLocalPrefix() {
+        return localPrefix;
+    }
+
+    public void setLocalPrefix(String localPrefix) {
+        this.localPrefix = localPrefix;
+    }
+
+    @Override
+    public String toString() {
+        return "ArtemisMessage{" +
+                "type=" + type +
+                ", localIp=" + localIp +
+                ", localPrefix=" + localPrefix +
+                '}';
+    }
+
+    public enum Type {
+        INITIATE_FROM_CLIENT,
+        INITIATE_FROM_SERVER
+    }
+}
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/objects/package-info.java
similarity index 82%
copy from apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java
copy to apps/artemis/src/main/java/org/onosproject/artemis/impl/objects/package-info.java
index b2d0dc4..65b1b22 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/objects/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -15,6 +15,6 @@
  */
 
 /**
- * Artemis CLI commands.
+ * Custom objects.
  */
-package org.onosproject.artemis.cli;
\ No newline at end of file
+package org.onosproject.artemis.impl.objects;
\ No newline at end of file
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/impl/package-info.java b/apps/artemis/src/main/java/org/onosproject/artemis/impl/package-info.java
index 13f5fc3..633afc5 100644
--- a/apps/artemis/src/main/java/org/onosproject/artemis/impl/package-info.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/impl/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -15,6 +15,6 @@
  */
 
 /**
- * Artemis component.
+ * Implementation classes.
  */
 package org.onosproject.artemis.impl;
\ No newline at end of file
diff --git a/apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java b/apps/artemis/src/main/java/org/onosproject/artemis/package-info.java
old mode 100644
new mode 100755
similarity index 83%
rename from apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java
rename to apps/artemis/src/main/java/org/onosproject/artemis/package-info.java
index b2d0dc4..07d5aab
--- a/apps/artemis/src/main/java/org/onosproject/artemis/cli/package-info.java
+++ b/apps/artemis/src/main/java/org/onosproject/artemis/package-info.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2016-present Open Networking Foundation
+ * 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.
@@ -15,6 +15,6 @@
  */
 
 /**
- * Artemis CLI commands.
+ * Artemis.
  */
-package org.onosproject.artemis.cli;
\ No newline at end of file
+package org.onosproject.artemis;
\ No newline at end of file
diff --git a/apps/artemis/src/main/resources/OSGI-INF/blueprint/shell-config.xml b/apps/artemis/src/main/resources/OSGI-INF/blueprint/shell-config.xml
old mode 100644
new mode 100755
index adf71ca..af1af5a
--- a/apps/artemis/src/main/resources/OSGI-INF/blueprint/shell-config.xml
+++ b/apps/artemis/src/main/resources/OSGI-INF/blueprint/shell-config.xml
@@ -16,9 +16,6 @@
 <blueprint xmlns="http://www.osgi.org/xmlns/blueprint/v1.0.0">
 
     <command-bundle xmlns="http://karaf.apache.org/xmlns/shell/v1.1.0">
-        <command>
-          <action class="org.onosproject.artemis.cli.LogOptionsCommand"/>
-        </command>
     </command-bundle>
 
 </blueprint>
diff --git a/tools/tutorials/artemis/topo.py b/tools/tutorials/artemis/artemis-topo.py
similarity index 100%
rename from tools/tutorials/artemis/topo.py
rename to tools/tutorials/artemis/artemis-topo.py
diff --git a/tools/tutorials/artemis/configs/network-cfg.json b/tools/tutorials/artemis/configs/network-cfg.json
index 8b5d56f..35380ce 100644
--- a/tools/tutorials/artemis/configs/network-cfg.json
+++ b/tools/tutorials/artemis/configs/network-cfg.json
@@ -1,5 +1,75 @@
 {
-    "ports" : {
+    "apps": {
+        "org.onosproject.artemis": {
+            "artemis": {
+                "moas": { },
+                "monitors": {
+                    "exabgp": [
+                        "192.168.1.2:5000"
+                    ],
+                    "ripe": []
+                },
+                "prefixes": [
+                    {
+                        "moas": [ ],
+                        "paths": [
+                            {
+                                "neighbor": [
+                                    {
+                                        "asn": 65002,
+                                        "neighbor": [
+                                            65001
+                                        ]
+                                    }
+                                ],
+                                "origin": 65004
+                            }
+                        ],
+                        "prefix": "40.0.0.0/8"
+                    }
+                ]
+            }
+        },
+        "org.onosproject.reactive.routing": {
+            "reactiveRouting": {
+                "ip4LocalPrefixes": [
+                    {
+                        "ipPrefix" : "40.0.0.0/24",
+                        "type" : "PUBLIC",
+                        "gatewayIp" : "40.0.0.1"
+                    },
+                    {
+                        "ipPrefix" : "150.1.3.0/30",
+                        "type" : "PRIVATE",
+                        "gatewayIp" : "150.1.3.2"
+                    }
+                ],
+                "ip6LocalPrefixes": [],
+                "virtualGatewayMacAddress": "e2:f5:32:16:9a:46"
+            }
+        },
+        "org.onosproject.router": {
+            "bgp": {
+                "bgpSpeakers" : [
+                    {
+                        "name" : "speaker1",
+                        "connectPoint" : "of:00002a45d713e141/4",
+                        "peers" : [
+                            "150.1.3.1"
+                        ]
+                    }
+                ]
+            }
+        }
+    },
+    "devices": {
+        "ovsdb:192.168.0.2": {
+            "basic": {
+                "driver": "ovs"
+            }
+        }
+    },
+    "ports": {
         "of:00002a45d713e141/2" : {
             "interfaces" : [
                 {
@@ -18,67 +88,5 @@
                 }
             ]
         }
-    },
-    "apps" : {
-        "org.onosproject.router" : {
-            "bgp" : {
-                "bgpSpeakers" : [
-                    {
-                        "name" : "speaker1",
-                        "connectPoint" : "of:00002a45d713e141/4",
-                        "peers" : [
-                            "150.1.3.1"
-                        ]
-                    }
-                ]
-            }
-        },
-        "org.onosproject.reactive.routing" : {
-            "reactiveRouting" : {
-                "ip4LocalPrefixes" : [
-                    {
-                        "ipPrefix" : "40.0.0.0/24",
-                        "type" : "PUBLIC",
-                        "gatewayIp" : "40.0.0.1"
-                    },
-                    {
-                        "ipPrefix" : "150.1.3.0/30",
-                        "type" : "PRIVATE",
-                        "gatewayIp" : "150.1.3.2"
-                    }
-                ],
-                "ip6LocalPrefixes" : [
-                ],
-                "virtualGatewayMacAddress" : "e2:f5:32:16:9a:46"
-            }
-        },
-        "org.onosproject.artemis" : {
-            "artemis" : {
-                "prefixes" : [ 
-                    {
-                        "prefix" : "40.0.0.0/8",
-                        "paths" : [ 
-                            {
-                                "origin" : 65004,
-                                "neighbor" : [
-                                    {
-                                        "asn" : 65002,
-                                        "neighbor": [
-                                            65001
-                                        ]
-                                    }
-                                ]
-                            }
-                        ],
-                        "moas" : [ ]
-                    }
-                ],
-                "frequency" : 3000,
-                "monitors" : {
-                    "ripe" : [ ],
-                    "exabgp": [ "192.168.1.2:5000" ]
-                }
-            }
-        }
     }
-}
+}
\ No newline at end of file