Initial import of CFM and SOAM api

Change-Id: Icf5cc2d5fb34b75460e80e8cced0d70265bcd33b
diff --git a/apps/cfm/src/main/java/org/onosproject/cfm/impl/MepWebResource.java b/apps/cfm/src/main/java/org/onosproject/cfm/impl/MepWebResource.java
new file mode 100644
index 0000000..2486df0
--- /dev/null
+++ b/apps/cfm/src/main/java/org/onosproject/cfm/impl/MepWebResource.java
@@ -0,0 +1,343 @@
+/*
+ * 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.cfm.impl;
+
+import java.io.InputStream;
+import java.net.URI;
+import java.util.Collection;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.PUT;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.onosproject.cfm.web.MepCodec;
+import org.onosproject.codec.JsonCodec;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceAssociation;
+import org.onosproject.incubator.net.l2monitoring.cfm.MaintenanceDomain;
+import org.onosproject.incubator.net.l2monitoring.cfm.Mep;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepEntry;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLbCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.MepLtCreate;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MaIdShort;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdId;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MdIdCharStr;
+import org.onosproject.incubator.net.l2monitoring.cfm.identifier.MepId;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmConfigException;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMdService;
+import org.onosproject.incubator.net.l2monitoring.cfm.service.CfmMepService;
+import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+/**
+ * Layer 2 CFM Maintenance Association Endpoint (MEP) web resource.
+ */
+@Path("md/{md_name}/ma/{ma_name}/mep")
+public class MepWebResource extends AbstractWebResource {
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    /**
+     * Get all MEPs by MD name, MA name.
+     *
+     * @param mdName The name of a Maintenance Domain
+     * @param maName The name of a Maintenance Association belonging to the MD
+     * @return 200 OK with a list of MEPS or 500 on error
+     */
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response getAllMepsForMa(@PathParam("md_name") String mdName,
+            @PathParam("ma_name") String maName) {
+        log.debug("GET all Meps called for MA {}", mdName + "/" + maName);
+        try {
+            MdId mdId = MdIdCharStr.asMdId(mdName);
+            MaIdShort maId = MaIdCharStr.asMaId(maName);
+            Collection<MepEntry> mepCollection = get(CfmMepService.class).getAllMeps(mdId, maId);
+            ArrayNode an = mapper().createArrayNode();
+            an.add(codec(MepEntry.class).encode(mepCollection, this));
+            return ok(mapper().createObjectNode().set("meps", an)).build();
+        } catch (CfmConfigException e) {
+            log.error("Get all Meps on {} failed because of exception",
+                    mdName + "/" + maName, e);
+            return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
+        }
+
+    }
+
+    /**
+     * Get MEP by MD name, MA name and Mep Id.
+     *
+     * @param mdName The name of a Maintenance Domain
+     * @param maName The name of a Maintenance Association belonging to the MD
+     * @param mepId The Id of the MEP
+     * @return 200 OK with details of the MEP or 500 on error
+     */
+    @GET
+    @Path("{mep_id}")
+    @Produces(MediaType.APPLICATION_JSON)
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response getMep(@PathParam("md_name") String mdName,
+            @PathParam("ma_name") String maName,
+            @PathParam("mep_id") short mepId) {
+        log.debug("GET called for MEP {}", mdName + "/" + maName + "/" + mepId);
+        try {
+            MdId mdId = MdIdCharStr.asMdId(mdName);
+            MaIdShort maId = MaIdCharStr.asMaId(maName);
+            MepEntry mepEntry = get(CfmMepService.class)
+                    .getMep(mdId, maId, MepId.valueOf(mepId));
+            if (mepEntry == null) {
+                return Response.serverError().entity("{ \"failure\":\"MEP " +
+                        mdName + "/" + maName + "/" + mepId + " not found\" }").build();
+            }
+            ObjectNode node = mapper().createObjectNode();
+            node.set("mep", codec(MepEntry.class).encode(mepEntry, this));
+            return ok(node).build();
+        } catch (CfmConfigException e) {
+            log.error("Get Mep {} failed because of exception",
+                    mdName + "/" + maName + "/" + mepId, e);
+            return Response.serverError().entity("{ \"failure\":\"" + e.toString() + "\" }").build();
+        }
+    }
+
+    /**
+     * Delete MEP by MD name, MA name and Mep Id.
+     *
+     * @param mdName The name of a Maintenance Domain
+     * @param maName The name of a Maintenance Association belonging to the MD
+     * @param mepIdShort The Id of the MEP
+     * @return 200 OK or 304 if not found, or 500 on error
+     */
+    @DELETE
+    @Path("{mep_id}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response deleteMep(@PathParam("md_name") String mdName,
+            @PathParam("ma_name") String maName,
+            @PathParam("mep_id") short mepIdShort) {
+        log.debug("DELETE called for MEP " + mdName + "/" + maName + "/" + mepIdShort);
+        try {
+            MdId mdId = MdIdCharStr.asMdId(mdName);
+            MaIdShort maId = MaIdCharStr.asMaId(maName);
+            boolean deleted = get(CfmMepService.class)
+                    .deleteMep(mdId, maId, MepId.valueOf(mepIdShort));
+            if (!deleted) {
+                return Response.notModified(mdName + "/" + maName + "/" +
+                        mepIdShort + " did not exist").build();
+            } else {
+                return ok("{ \"success\":\"deleted " + mdName + "/" + maName +
+                        "/" + mepIdShort + "\" }").build();
+            }
+        } catch (CfmConfigException e) {
+            log.error("Delete Mep {} failed because of exception ",
+                    mdName + "/" + maName + "/" + mepIdShort, e);
+            return Response.serverError().entity("{ \"failure\":\"" +
+                    e.toString() + "\" }").build();
+        }
+    }
+
+    /**
+     * Create MEP with MD name, MA name and Mep Json.
+     *
+     * @param mdName The name of a Maintenance Domain
+     * @param maName The name of a Maintenance Association belonging to the MD
+     * @param input A JSON formatted input stream specifying the Mep parameters
+     * @return 201 Created or 304 if already exists or 500 on error
+     */
+    @POST
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response createMep(@PathParam("md_name") String mdName,
+                              @PathParam("ma_name") String maName, InputStream input) {
+        log.debug("POST called to Create Mep");
+        try {
+            MdId mdId = MdIdCharStr.asMdId(mdName);
+            MaIdShort maId = MaIdCharStr.asMaId(maName);
+            MaintenanceAssociation ma = get(CfmMdService.class).getMaintenanceAssociation(mdId, maId).get();
+
+            ObjectMapper mapper = new ObjectMapper();
+            JsonNode cfg = mapper.readTree(input);
+            JsonCodec<Mep> mepCodec = codec(Mep.class);
+
+            Mep mep = ((MepCodec) mepCodec).decode((ObjectNode) cfg, this, mdName, maName);
+
+            Boolean issuccess = get(CfmMepService.class).createMep(mdId, maId, mep);
+            if (!issuccess) {
+                return Response.notModified(mdName + "/" + ma.maId() + "/" + mep.mepId() +
+                        " already exists").build();
+            }
+            return Response
+                    .created(new URI("md/" + mdName + "/ma/" + ma.maId() + "/mep/" + mep.mepId()))
+                    .entity("{ \"success\":\"mep " + mdName + "/" + ma.maId() + "/" + mep.mepId() + " created\" }")
+                    .build();
+        } catch (Exception | CfmConfigException e) {
+            log.error("Create Mep on " + mdName + "/" + maName + " failed because of exception {}",
+                      e.toString());
+            return Response.serverError()
+                    .entity("{ \"failure\":\"" + e.toString() + "\" }")
+                    .build();
+        }
+    }
+
+    /**
+     * Transmit Loopback on MEP with MD name, MA name and Mep Id.
+     *
+     * @param mdName The name of a Maintenance Domain
+     * @param maName The name of a Maintenance Association belonging to the MD
+     * @param mepIdShort The id of a MEP belonging to the MA
+     * @param input A JSON formatted input stream specifying the Mep parameters
+     * @return 202 Received with success message or 500 on error
+     */
+    @PUT
+    @Path("{mep_id}/transmit-loopback")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response transmitLoopback(
+            @PathParam("md_name") String mdName,
+            @PathParam("ma_name") String maName,
+            @PathParam("mep_id") short mepIdShort,
+            InputStream input) {
+        log.debug("PUT called to Transmit Loopback on Mep");
+
+        MdId mdId = MdIdCharStr.asMdId(mdName);
+        MaIdShort maId = MaIdCharStr.asMaId(maName);
+        MaintenanceDomain md = get(CfmMdService.class).getMaintenanceDomain(mdId).get();
+        MaintenanceAssociation ma = get(CfmMdService.class)
+                .getMaintenanceAssociation(mdId, maId).get();
+
+        MepId mepId = MepId.valueOf(mepIdShort);
+
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            JsonNode cfg = mapper.readTree(input);
+            JsonCodec<MepLbCreate> mepLbCreateCodec = codec(MepLbCreate.class);
+
+            MepLbCreate lbCreate = mepLbCreateCodec.decode((ObjectNode) cfg, this);
+            get(CfmMepService.class).transmitLoopback(md.mdId(), ma.maId(), mepId, lbCreate);
+        } catch (Exception | CfmConfigException e) {
+            log.error("Transmit Loopback on " + mdName + "/" + maName +
+                    "/{} failed", String.valueOf(mepIdShort), e);
+            return Response.serverError()
+                  .entity("{ \"failure\":\"" + e.toString() + "\" }")
+                  .build();
+        }
+
+        return Response.accepted()
+            .entity("{ \"success\":\"Loopback on MEP " + mdName + "/" + ma.maId() + "/"
+                    + mepId.id() + " started\" }").build();
+    }
+
+    /**
+     * Abort Loopback on MEP with MD name, MA name and Mep Id.
+     *
+     * @param mdName The name of a Maintenance Domain
+     * @param maName The name of a Maintenance Association belonging to the MD
+     * @param mepIdShort The id of a MEP belonging to the MA
+     * @return 202 Received with success message or 500 on error
+     */
+    @PUT
+    @Path("{mep_id}/abort-loopback")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response abortLoopback(
+            @PathParam("md_name") String mdName,
+            @PathParam("ma_name") String maName,
+            @PathParam("mep_id") short mepIdShort) {
+        log.debug("PUT called to Abort Loopback on Mep");
+
+        MdId mdId = MdIdCharStr.asMdId(mdName);
+        MaIdShort maId = MaIdCharStr.asMaId(maName);
+        MaintenanceDomain md = get(CfmMdService.class).getMaintenanceDomain(mdId).get();
+        MaintenanceAssociation ma = get(CfmMdService.class)
+                .getMaintenanceAssociation(mdId, maId).get();
+
+        MepId mepId = MepId.valueOf(mepIdShort);
+
+        try {
+            get(CfmMepService.class).abortLoopback(md.mdId(), ma.maId(), mepId);
+        } catch (CfmConfigException e) {
+            log.error("Abort Loopback on " + mdName + "/" + maName +
+                    "/{} failed", String.valueOf(mepIdShort), e);
+            return Response.serverError()
+                  .entity("{ \"failure\":\"" + e.toString() + "\" }")
+                  .build();
+        }
+
+        return Response.accepted()
+            .entity("{ \"success\":\"Loopback on MEP " + mdName + "/" + ma.maId() + "/"
+                    + mepId.id() + " aborted\" }").build();
+    }
+
+    /**
+     * Transmit Linktrace on MEP with MD name, MA name and Mep Id.
+     *
+     * @param mdName The name of a Maintenance Domain
+     * @param maName The name of a Maintenance Association belonging to the MD
+     * @param mepIdShort The id of a MEP belonging to the MA
+     * @param input A JSON formatted input stream specifying the Linktrace parameters
+     * @return 202 Received with success message or 500 on error
+     */
+    @PUT
+    @Path("{mep_id}/transmit-linktrace")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response transmitLinktrace(
+            @PathParam("md_name") String mdName,
+            @PathParam("ma_name") String maName,
+            @PathParam("mep_id") short mepIdShort,
+            InputStream input) {
+        log.debug("PUT called to Transmit Linktrace on Mep");
+
+        MdId mdId = MdIdCharStr.asMdId(mdName);
+        MaIdShort maId = MaIdCharStr.asMaId(maName);
+        MaintenanceDomain md = get(CfmMdService.class).getMaintenanceDomain(mdId).get();
+        MaintenanceAssociation ma = get(CfmMdService.class)
+                .getMaintenanceAssociation(mdId, maId).get();
+
+        MepId mepId = MepId.valueOf(mepIdShort);
+
+        try {
+            ObjectMapper mapper = new ObjectMapper();
+            JsonNode cfg = mapper.readTree(input);
+            JsonCodec<MepLtCreate> mepLtCreateCodec = codec(MepLtCreate.class);
+
+            MepLtCreate ltCreate = mepLtCreateCodec.decode((ObjectNode) cfg, this);
+            get(CfmMepService.class).transmitLinktrace(md.mdId(), ma.maId(), mepId, ltCreate);
+        } catch (Exception | CfmConfigException e) {
+            log.error("Transmit Linktrace on " + mdName + "/" + maName +
+                    "/{} failed", String.valueOf(mepIdShort), e);
+            return Response.serverError()
+                    .entity("{ \"failure\":\"" + e.toString() + "\" }")
+                    .build();
+        }
+
+        return Response.accepted()
+                .entity("{ \"success\":\"Linktrace on MEP " + mdName + "/" + ma.maId() + "/"
+                        + mepId.id() + " started\" }").build();
+    }
+}