From ee65a236a5ce73f0087bfc7f40b6da5edef14483 Mon Sep 17 00:00:00 2001 From: Jian Li Date: Wed, 29 Mar 2017 14:15:30 +0900 Subject: [PATCH] [ONOS-6170] Implement codec for MappingAction primitives Change-Id: I8f92b05c814158285e97616bdaa8f24de7064833 --- .../mapping/web/MappingCodecRegistrator.java | 4 + .../codec/DecodeMappingActionCodecHelper.java | 97 +++++++++++ .../codec/EncodeMappingActionCodecHelper.java | 117 ++++++++++++++ .../mapping/web/codec/MappingActionCodec.java | 50 ++++++ .../web/codec/MappingActionCodecTest.java | 141 ++++++++++++++++ .../web/codec/MappingActionJsonMatcher.java | 150 ++++++++++++++++++ 6 files changed, 559 insertions(+) create mode 100644 apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/DecodeMappingActionCodecHelper.java create mode 100644 apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/EncodeMappingActionCodecHelper.java create mode 100644 apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/MappingActionCodec.java create mode 100644 apps/mappingmanagement/web/src/test/java/org/onosproject/mapping/web/codec/MappingActionCodecTest.java create mode 100644 apps/mappingmanagement/web/src/test/java/org/onosproject/mapping/web/codec/MappingActionJsonMatcher.java diff --git a/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/MappingCodecRegistrator.java b/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/MappingCodecRegistrator.java index 9540cc885a..9354cd8d4e 100644 --- a/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/MappingCodecRegistrator.java +++ b/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/MappingCodecRegistrator.java @@ -21,8 +21,10 @@ import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.ReferenceCardinality; import org.onosproject.codec.CodecService; +import org.onosproject.mapping.actions.MappingAction; import org.onosproject.mapping.addresses.MappingAddress; import org.onosproject.mapping.instructions.MappingInstruction; +import org.onosproject.mapping.web.codec.MappingActionCodec; import org.onosproject.mapping.web.codec.MappingAddressCodec; import org.onosproject.mapping.web.codec.MappingInstructionCodec; import org.slf4j.Logger; @@ -44,6 +46,7 @@ public class MappingCodecRegistrator { public void activate() { codecService.registerCodec(MappingAddress.class, new MappingAddressCodec()); codecService.registerCodec(MappingInstruction.class, new MappingInstructionCodec()); + codecService.registerCodec(MappingAction.class, new MappingActionCodec()); log.info("Started"); } @@ -52,6 +55,7 @@ public class MappingCodecRegistrator { public void deactivate() { codecService.unregisterCodec(MappingAddress.class); codecService.unregisterCodec(MappingInstruction.class); + codecService.unregisterCodec(MappingAction.class); log.info("Stopped"); } diff --git a/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/DecodeMappingActionCodecHelper.java b/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/DecodeMappingActionCodecHelper.java new file mode 100644 index 0000000000..64c58fbd77 --- /dev/null +++ b/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/DecodeMappingActionCodecHelper.java @@ -0,0 +1,97 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.mapping.web.codec; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.mapping.actions.MappingAction; +import org.onosproject.mapping.actions.MappingActions; + +import static org.onlab.util.Tools.nullIsIllegal; + +/** + * Decode portion of the mapping action codec. + */ +public final class DecodeMappingActionCodecHelper { + private final ObjectNode json; + + /** + * Creates a decode mapping action codec object. + * + * @param json JSON object to decode + */ + public DecodeMappingActionCodecHelper(ObjectNode json) { + this.json = json; + } + + /** + * Decodes a no mapping action. + * + * @return mapping action object decoded from the JSON + */ + private MappingAction decodeNoAction() { + return MappingActions.noAction(); + } + + /** + * Decodes a forward mapping action. + * + * @return mapping action object decoded from the JSON + */ + private MappingAction decodeForwardAction() { + return MappingActions.forward(); + } + + /** + * Decodes a native forward mapping action. + * + * @return mapping action object decoded from the JSON + */ + private MappingAction decodeNativeForwardAction() { + return MappingActions.nativeForward(); + } + + /** + * Decodes a drop mapping action. + * + * @return mapping action object decoded from the JSON + */ + private MappingAction decodeDropAction() { + return MappingActions.drop(); + } + + /** + * Decodes the JSON into a mapping action object. + * + * @return MappingAction object + * @throws IllegalArgumentException if the JSON is invalid + */ + public MappingAction decode() { + String type = nullIsIllegal(json.get(MappingActionCodec.TYPE), + MappingActionCodec.TYPE + MappingActionCodec.ERROR_MESSAGE).asText(); + + if (type.equals(MappingAction.Type.DROP.name())) { + return decodeDropAction(); + } else if (type.equals(MappingAction.Type.FORWARD.name())) { + return decodeForwardAction(); + } else if (type.equals(MappingAction.Type.NATIVE_FORWARD.name())) { + return decodeNativeForwardAction(); + } else if (type.equals(MappingAction.Type.NO_ACTION.name())) { + return decodeNoAction(); + } + throw new IllegalArgumentException("MappingAction type " + + type + " is not supported"); + } +} diff --git a/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/EncodeMappingActionCodecHelper.java b/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/EncodeMappingActionCodecHelper.java new file mode 100644 index 0000000000..370de808dc --- /dev/null +++ b/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/EncodeMappingActionCodecHelper.java @@ -0,0 +1,117 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.mapping.web.codec; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.codec.CodecContext; +import org.onosproject.mapping.actions.MappingAction; +import org.onosproject.mapping.actions.NoMappingAction; +import org.onosproject.mapping.actions.DropMappingAction; +import org.onosproject.mapping.actions.ForwardMappingAction; +import org.onosproject.mapping.actions.NativeForwardMappingAction; +import org.slf4j.Logger; + +import static org.slf4j.LoggerFactory.getLogger; + +/** + * Encode portion of the mapping action codec. + */ +public final class EncodeMappingActionCodecHelper { + protected static final Logger log = getLogger(EncodeMappingActionCodecHelper.class); + private final MappingAction action; + private final CodecContext context; + + /** + * Creates a mapping action object encoder. + * + * @param action mapping action to encode + * @param context codec context for the encoding + */ + public EncodeMappingActionCodecHelper(MappingAction action, + CodecContext context) { + this.action = action; + this.context = context; + } + + /** + * Encodes a no mapping action. + * + * @param result json node that the mapping action attributes are added to + */ + private void encodeNoMappingAction(ObjectNode result) { + NoMappingAction noMappingAction = (NoMappingAction) action; + result.put(MappingActionCodec.TYPE, noMappingAction.type().name()); + } + + /** + * Encodes a drop mapping action. + * + * @param result json node that the mapping action attributes are added to + */ + private void encodeDropMappingAction(ObjectNode result) { + DropMappingAction dropMappingAction = (DropMappingAction) action; + result.put(MappingActionCodec.TYPE, dropMappingAction.type().name()); + } + + /** + * Encodes a forward mapping action. + * + * @param result json node that the mapping action attributes are added to + */ + private void encodeForwardMappingAction(ObjectNode result) { + ForwardMappingAction forwardMappingAction = (ForwardMappingAction) action; + result.put(MappingActionCodec.TYPE, forwardMappingAction.type().name()); + } + + /** + * Encodes a native forward mapping action. + * + * @param result json node that the mapping action attributes are added to + */ + private void encodeNativeForwardMappingAction(ObjectNode result) { + NativeForwardMappingAction nativeMappingAction = (NativeForwardMappingAction) action; + result.put(MappingActionCodec.TYPE, nativeMappingAction.type().name()); + } + + /** + * Encodes the given mapping instruction into JSON. + * + * @return JSON object node representing the mapping action + */ + public ObjectNode encode() { + final ObjectNode result = context.mapper().createObjectNode() + .put(MappingActionCodec.TYPE, action.type().toString()); + + switch (action.type()) { + case DROP: + encodeDropMappingAction(result); + break; + case FORWARD: + encodeForwardMappingAction(result); + break; + case NATIVE_FORWARD: + encodeNativeForwardMappingAction(result); + break; + case NO_ACTION: + encodeNoMappingAction(result); + break; + default: + log.info("Cannot convert mapping action type of {}", action.type()); + break; + } + return result; + } +} diff --git a/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/MappingActionCodec.java b/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/MappingActionCodec.java new file mode 100644 index 0000000000..169d819827 --- /dev/null +++ b/apps/mappingmanagement/web/src/main/java/org/onosproject/mapping/web/codec/MappingActionCodec.java @@ -0,0 +1,50 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.mapping.web.codec; + +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.JsonCodec; +import org.onosproject.mapping.actions.MappingAction; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Mapping action codec. + */ +public final class MappingActionCodec extends JsonCodec { + + protected static final Logger log = + LoggerFactory.getLogger(MappingActionCodec.class); + + protected static final String TYPE = "type"; + protected static final String ERROR_MESSAGE = + " not specified in MappingAction"; + + @Override + public ObjectNode encode(MappingAction action, CodecContext context) { + EncodeMappingActionCodecHelper encoder = + new EncodeMappingActionCodecHelper(action, context); + return encoder.encode(); + } + + @Override + public MappingAction decode(ObjectNode json, CodecContext context) { + DecodeMappingActionCodecHelper decoder = + new DecodeMappingActionCodecHelper(json); + return decoder.decode(); + } +} diff --git a/apps/mappingmanagement/web/src/test/java/org/onosproject/mapping/web/codec/MappingActionCodecTest.java b/apps/mappingmanagement/web/src/test/java/org/onosproject/mapping/web/codec/MappingActionCodecTest.java new file mode 100644 index 0000000000..86d259dc1e --- /dev/null +++ b/apps/mappingmanagement/web/src/test/java/org/onosproject/mapping/web/codec/MappingActionCodecTest.java @@ -0,0 +1,141 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.mapping.web.codec; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.onosproject.codec.CodecContext; +import org.onosproject.codec.CodecService; +import org.onosproject.codec.JsonCodec; +import org.onosproject.codec.impl.CodecManager; +import org.onosproject.mapping.actions.MappingAction; +import org.onosproject.mapping.actions.MappingActions; +import org.onosproject.mapping.actions.NoMappingAction; +import org.onosproject.mapping.actions.DropMappingAction; +import org.onosproject.mapping.actions.ForwardMappingAction; +import org.onosproject.mapping.actions.NativeForwardMappingAction; +import org.onosproject.mapping.web.MappingCodecRegistrator; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.notNullValue; +import static org.onosproject.mapping.web.codec.MappingActionJsonMatcher.matchesAction; + +/** + * Unit tests for MappingActionCodec. + */ +public class MappingActionCodecTest { + + private CodecContext context; + private JsonCodec actionCodec; + private MappingCodecRegistrator registrator; + + /** + * Sets up for each test. + * Creates a context and fetches the mapping action codec. + */ + @Before + public void setUp() { + CodecManager manager = new CodecManager(); + registrator = new MappingCodecRegistrator(); + registrator.codecService = manager; + registrator.activate(); + + context = new MappingActionCodecTest.MappingTestContext(registrator.codecService); + actionCodec = context.codec(MappingAction.class); + assertThat(actionCodec, notNullValue()); + } + + /** + * Deactivates the codec registrator. + */ + @After + public void tearDown() { + registrator.deactivate(); + } + + /** + * Tests the encoding of no mapping action. + */ + @Test + public void noActionTest() { + final NoMappingAction action = MappingActions.noAction(); + final ObjectNode actionJson = actionCodec.encode(action, context); + assertThat(actionJson, matchesAction(action)); + } + + /** + * Tests the encoding of drop mapping action. + */ + @Test + public void dropActionTest() { + final DropMappingAction action = MappingActions.drop(); + final ObjectNode actionJson = actionCodec.encode(action, context); + assertThat(actionJson, matchesAction(action)); + } + + /** + * Tests the encoding of forward mapping action. + */ + @Test + public void forwardActionTest() { + final ForwardMappingAction action = MappingActions.forward(); + final ObjectNode actionJson = actionCodec.encode(action, context); + assertThat(actionJson, matchesAction(action)); + } + + /** + * Tests the encoding of native forwarding mapping action. + */ + @Test + public void nativeForwardActionTest() { + final NativeForwardMappingAction action = MappingActions.nativeForward(); + final ObjectNode actionJson = actionCodec.encode(action, context); + assertThat(actionJson, matchesAction(action)); + } + + /** + * Test mapping codec context. + */ + private class MappingTestContext implements CodecContext { + private final ObjectMapper mapper = new ObjectMapper(); + private final CodecService manager; + + /** + * Constructs a new mock codec context. + */ + public MappingTestContext(CodecService manager) { + this.manager = manager; + } + + @Override + public ObjectMapper mapper() { + return mapper; + } + + @Override + public JsonCodec codec(Class entityClass) { + return manager.getCodec(entityClass); + } + + @Override + public T getService(Class serviceClass) { + return null; + } + } +} diff --git a/apps/mappingmanagement/web/src/test/java/org/onosproject/mapping/web/codec/MappingActionJsonMatcher.java b/apps/mappingmanagement/web/src/test/java/org/onosproject/mapping/web/codec/MappingActionJsonMatcher.java new file mode 100644 index 0000000000..94ba91eb44 --- /dev/null +++ b/apps/mappingmanagement/web/src/test/java/org/onosproject/mapping/web/codec/MappingActionJsonMatcher.java @@ -0,0 +1,150 @@ +/* + * Copyright 2017-present Open Networking Laboratory + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.onosproject.mapping.web.codec; + +import com.fasterxml.jackson.databind.JsonNode; +import org.hamcrest.Description; +import org.hamcrest.TypeSafeDiagnosingMatcher; +import org.onosproject.mapping.actions.MappingAction; +import org.onosproject.mapping.actions.NoMappingAction; +import org.onosproject.mapping.actions.DropMappingAction; +import org.onosproject.mapping.actions.ForwardMappingAction; +import org.onosproject.mapping.actions.NativeForwardMappingAction; +/** + * Hamcrest matcher for mapping actions. + */ +public final class MappingActionJsonMatcher + extends TypeSafeDiagnosingMatcher { + + private final MappingAction action; + + /** + * A default constructor. + * + * @param action mapping action + */ + private MappingActionJsonMatcher(MappingAction action) { + this.action = action; + } + + /** + * Matches the contents of a no mapping action. + * + * @param node JSON action to match + * @param description object used for recording errors + * @return true if contents match, false otherwise + */ + private boolean matchNoAction(JsonNode node, Description description) { + NoMappingAction actionToMatch = (NoMappingAction) action; + final String jsonType = node.get(MappingActionCodec.TYPE).textValue(); + if (!actionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + return true; + } + + /** + * Matches the contents of a drop mapping action. + * + * @param node JSON action to match + * @param description object used for recording errors + * @return true if the contents match, false otherwise + */ + private boolean matchDropAction(JsonNode node, Description description) { + DropMappingAction actionToMatch = (DropMappingAction) action; + final String jsonType = node.get(MappingActionCodec.TYPE).textValue(); + if (!actionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + return true; + } + + /** + * Matches the contents of a forward mapping action. + * + * @param node JSON action to match + * @param description object used for recording errors + * @return true if the contents match, false otherwise + */ + private boolean matchForwardAction(JsonNode node, Description description) { + ForwardMappingAction actionToMatch = (ForwardMappingAction) action; + final String jsonType = node.get(MappingActionCodec.TYPE).textValue(); + if (!actionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + return true; + } + + /** + * Matches the contents of a native forward mapping action. + * + * @param node JSON action to match + * @param description object used for recording errors + * @return true if the contents match, false otherwise + */ + private boolean matchNativeForwardAction(JsonNode node, Description description) { + NativeForwardMappingAction actionToMatch = (NativeForwardMappingAction) action; + final String jsonType = node.get(MappingActionCodec.TYPE).textValue(); + if (!actionToMatch.type().name().equals(jsonType)) { + description.appendText("type was " + jsonType); + return false; + } + return true; + } + + @Override + protected boolean matchesSafely(JsonNode jsonNode, Description description) { + + // check type + final JsonNode jsonTypeNode = jsonNode.get(MappingActionCodec.TYPE); + final String jsonType = jsonTypeNode.textValue(); + final String type = action.type().name(); + if (!jsonType.equals(type)) { + description.appendText("type was " + type); + return false; + } + + if (action instanceof NoMappingAction) { + return matchNoAction(jsonNode, description); + } else if (action instanceof DropMappingAction) { + return matchDropAction(jsonNode, description); + } else if (action instanceof ForwardMappingAction) { + return matchForwardAction(jsonNode, description); + } else if (action instanceof NativeForwardMappingAction) { + return matchNativeForwardAction(jsonNode, description); + } + + return false; + } + + @Override + public void describeTo(Description description) { + description.appendText(action.toString()); + } + + /** + * Factory to allocate a mapping action matcher. + * + * @param action action object we are looking for + * @return matcher + */ + public static MappingActionJsonMatcher matchesAction(MappingAction action) { + return new MappingActionJsonMatcher(action); + } +}