Ray Milkey
Committed by Gerrit Code Review

Implementation of REST POST API for creating intents

- codec for constraint decode
- codec for intent decode
- POST method for intents
- unit tests for codecs and POST method

Change-Id: Ibc0ef8f99a0c0664710a733985424c77010c49b5
Showing 30 changed files with 1166 additions and 201 deletions
...@@ -87,4 +87,29 @@ public abstract class JsonCodec<T> { ...@@ -87,4 +87,29 @@ public abstract class JsonCodec<T> {
87 return result; 87 return result;
88 } 88 }
89 89
90 + /**
91 + * Gets a child Object Node from a parent by name. If the child is not found
92 + * or does nor represent an object, null is returned.
93 + *
94 + * @param parent parent object
95 + * @param childName name of child to query
96 + * @return child object if found, null if not found or if not an object
97 + */
98 + protected static ObjectNode get(ObjectNode parent, String childName) {
99 + JsonNode node = parent.path(childName);
100 + return node.isObject() && !node.isNull() ? (ObjectNode) node : null;
101 + }
102 +
103 + /**
104 + * Gets a child Object Node from a parent by index. If the child is not found
105 + * or does nor represent an object, null is returned.
106 + *
107 + * @param parent parent object
108 + * @param childIndex index of child to query
109 + * @return child object if found, null if not found or if not an object
110 + */
111 + protected static ObjectNode get(JsonNode parent, int childIndex) {
112 + JsonNode node = parent.path(childIndex);
113 + return node.isObject() && !node.isNull() ? (ObjectNode) node : null;
114 + }
90 } 115 }
......
...@@ -55,7 +55,7 @@ public abstract class AnnotatedCodec<T extends Annotated> extends JsonCodec<T> { ...@@ -55,7 +55,7 @@ public abstract class AnnotatedCodec<T extends Annotated> extends JsonCodec<T> {
55 55
56 JsonCodec<Annotations> codec = context.codec(Annotations.class); 56 JsonCodec<Annotations> codec = context.codec(Annotations.class);
57 if (objNode.has("annotations") && objNode.isObject()) { 57 if (objNode.has("annotations") && objNode.isObject()) {
58 - return codec.decode((ObjectNode) objNode.get("annotations"), context); 58 + return codec.decode(get(objNode, "annotations"), context);
59 } else { 59 } else {
60 return DefaultAnnotations.EMPTY; 60 return DefaultAnnotations.EMPTY;
61 } 61 }
......
...@@ -15,6 +15,9 @@ ...@@ -15,6 +15,9 @@
15 */ 15 */
16 package org.onosproject.codec.impl; 16 package org.onosproject.codec.impl;
17 17
18 +import java.util.ArrayList;
19 +import java.util.stream.IntStream;
20 +
18 import org.onosproject.codec.CodecContext; 21 import org.onosproject.codec.CodecContext;
19 import org.onosproject.codec.JsonCodec; 22 import org.onosproject.codec.JsonCodec;
20 import org.onosproject.net.flow.TrafficSelector; 23 import org.onosproject.net.flow.TrafficSelector;
...@@ -23,6 +26,7 @@ import org.onosproject.net.intent.ConnectivityIntent; ...@@ -23,6 +26,7 @@ import org.onosproject.net.intent.ConnectivityIntent;
23 import org.onosproject.net.intent.Constraint; 26 import org.onosproject.net.intent.Constraint;
24 import org.onosproject.net.intent.Intent; 27 import org.onosproject.net.intent.Intent;
25 28
29 +import com.fasterxml.jackson.databind.JsonNode;
26 import com.fasterxml.jackson.databind.node.ArrayNode; 30 import com.fasterxml.jackson.databind.node.ArrayNode;
27 import com.fasterxml.jackson.databind.node.ObjectNode; 31 import com.fasterxml.jackson.databind.node.ObjectNode;
28 32
...@@ -33,6 +37,10 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -33,6 +37,10 @@ import static com.google.common.base.Preconditions.checkNotNull;
33 */ 37 */
34 public final class ConnectivityIntentCodec extends JsonCodec<ConnectivityIntent> { 38 public final class ConnectivityIntentCodec extends JsonCodec<ConnectivityIntent> {
35 39
40 + private static final String CONSTRAINTS = "constraints";
41 + private static final String SELECTOR = "selector";
42 + private static final String TREATMENT = "treatment";
43 +
36 @Override 44 @Override
37 public ObjectNode encode(ConnectivityIntent intent, CodecContext context) { 45 public ObjectNode encode(ConnectivityIntent intent, CodecContext context) {
38 checkNotNull(intent, "Connectivity intent cannot be null"); 46 checkNotNull(intent, "Connectivity intent cannot be null");
...@@ -43,19 +51,19 @@ public final class ConnectivityIntentCodec extends JsonCodec<ConnectivityIntent> ...@@ -43,19 +51,19 @@ public final class ConnectivityIntentCodec extends JsonCodec<ConnectivityIntent>
43 if (intent.selector() != null) { 51 if (intent.selector() != null) {
44 final JsonCodec<TrafficSelector> selectorCodec = 52 final JsonCodec<TrafficSelector> selectorCodec =
45 context.codec(TrafficSelector.class); 53 context.codec(TrafficSelector.class);
46 - result.set("selector", selectorCodec.encode(intent.selector(), context)); 54 + result.set(SELECTOR, selectorCodec.encode(intent.selector(), context));
47 } 55 }
48 56
49 if (intent.treatment() != null) { 57 if (intent.treatment() != null) {
50 final JsonCodec<TrafficTreatment> treatmentCodec = 58 final JsonCodec<TrafficTreatment> treatmentCodec =
51 context.codec(TrafficTreatment.class); 59 context.codec(TrafficTreatment.class);
52 - result.set("treatment", treatmentCodec.encode(intent.treatment(), context)); 60 + result.set(TREATMENT, treatmentCodec.encode(intent.treatment(), context));
53 } 61 }
54 62
55 - result.put("priority", intent.priority()); 63 + result.put(IntentCodec.PRIORITY, intent.priority());
56 64
57 if (intent.constraints() != null) { 65 if (intent.constraints() != null) {
58 - final ArrayNode jsonConstraints = result.putArray("constraints"); 66 + final ArrayNode jsonConstraints = result.putArray(CONSTRAINTS);
59 67
60 if (intent.constraints() != null) { 68 if (intent.constraints() != null) {
61 final JsonCodec<Constraint> constraintCodec = 69 final JsonCodec<Constraint> constraintCodec =
...@@ -70,4 +78,41 @@ public final class ConnectivityIntentCodec extends JsonCodec<ConnectivityIntent> ...@@ -70,4 +78,41 @@ public final class ConnectivityIntentCodec extends JsonCodec<ConnectivityIntent>
70 78
71 return result; 79 return result;
72 } 80 }
81 +
82 + /**
83 + * Extracts connectivity intent specific attributes from a JSON object
84 + * and adds them to a builder.
85 + *
86 + * @param json root JSON object
87 + * @param context code context
88 + * @param builder builder to use for storing the attributes. Constraints,
89 + * selector and treatment are modified by this call.
90 + */
91 + public static void intentAttributes(ObjectNode json, CodecContext context,
92 + ConnectivityIntent.Builder builder) {
93 + JsonNode constraintsJson = json.get(CONSTRAINTS);
94 + if (constraintsJson != null) {
95 + JsonCodec<Constraint> constraintsCodec = context.codec(Constraint.class);
96 + ArrayList<Constraint> constraints = new ArrayList<>(constraintsJson.size());
97 + IntStream.range(0, constraintsJson.size())
98 + .forEach(i -> constraints.add(
99 + constraintsCodec.decode(get(constraintsJson, i),
100 + context)));
101 + builder.constraints(constraints);
102 + }
103 +
104 + ObjectNode selectorJson = get(json, SELECTOR);
105 + if (selectorJson != null) {
106 + JsonCodec<TrafficSelector> selectorCodec = context.codec(TrafficSelector.class);
107 + TrafficSelector selector = selectorCodec.decode(selectorJson, context);
108 + builder.selector(selector);
109 + }
110 +
111 + ObjectNode treatmentJson = get(json, TREATMENT);
112 + if (treatmentJson != null) {
113 + JsonCodec<TrafficTreatment> treatmentCodec = context.codec(TrafficTreatment.class);
114 + TrafficTreatment treatment = treatmentCodec.decode(treatmentJson, context);
115 + builder.treatment(treatment);
116 + }
117 + }
73 } 118 }
......
...@@ -17,18 +17,8 @@ package org.onosproject.codec.impl; ...@@ -17,18 +17,8 @@ package org.onosproject.codec.impl;
17 17
18 import org.onosproject.codec.CodecContext; 18 import org.onosproject.codec.CodecContext;
19 import org.onosproject.codec.JsonCodec; 19 import org.onosproject.codec.JsonCodec;
20 -import org.onosproject.net.DeviceId;
21 -import org.onosproject.net.Link;
22 import org.onosproject.net.intent.Constraint; 20 import org.onosproject.net.intent.Constraint;
23 -import org.onosproject.net.intent.constraint.AnnotationConstraint;
24 -import org.onosproject.net.intent.constraint.BandwidthConstraint;
25 -import org.onosproject.net.intent.constraint.LambdaConstraint;
26 -import org.onosproject.net.intent.constraint.LatencyConstraint;
27 -import org.onosproject.net.intent.constraint.LinkTypeConstraint;
28 -import org.onosproject.net.intent.constraint.ObstacleConstraint;
29 -import org.onosproject.net.intent.constraint.WaypointConstraint;
30 21
31 -import com.fasterxml.jackson.databind.node.ArrayNode;
32 import com.fasterxml.jackson.databind.node.ObjectNode; 22 import com.fasterxml.jackson.databind.node.ObjectNode;
33 23
34 import static com.google.common.base.Preconditions.checkNotNull; 24 import static com.google.common.base.Preconditions.checkNotNull;
...@@ -38,170 +28,36 @@ import static com.google.common.base.Preconditions.checkNotNull; ...@@ -38,170 +28,36 @@ import static com.google.common.base.Preconditions.checkNotNull;
38 */ 28 */
39 public final class ConstraintCodec extends JsonCodec<Constraint> { 29 public final class ConstraintCodec extends JsonCodec<Constraint> {
40 30
41 - /** 31 + protected static final String MISSING_MEMBER_MESSAGE =
42 - * Encodes a latency constraint. 32 + " member is required in Constraint";
43 - * 33 + protected static final String TYPE = "type";
44 - * @param constraint latency constraint to encode 34 + protected static final String TYPES = "types";
45 - * @param context code context 35 + protected static final String INCLUSIVE = "inclusive";
46 - * @return JSON ObjectNode representing the constraint 36 + protected static final String KEY = "key";
47 - */ 37 + protected static final String THRESHOLD = "threshold";
48 - private ObjectNode encodeLatencyConstraint(Constraint constraint, 38 + protected static final String BANDWIDTH = "bandwidth";
49 - CodecContext context) { 39 + protected static final String LAMBDA = "lambda";
50 - checkNotNull(constraint, "Duration constraint cannot be null"); 40 + protected static final String LATENCY_MILLIS = "latencyMillis";
51 - final LatencyConstraint latencyConstraint = 41 + protected static final String OBSTACLES = "obstacles";
52 - (LatencyConstraint) constraint; 42 + protected static final String WAYPOINTS = "waypoints";
53 - return context.mapper().createObjectNode()
54 - .put("latencyMillis", latencyConstraint.latency().toMillis());
55 - }
56 -
57 - /**
58 - * Encodes an obstacle constraint.
59 - *
60 - * @param constraint obstacle constraint to encode
61 - * @param context code context
62 - * @return JSON ObjectNode representing the constraint
63 - */
64 - private ObjectNode encodeObstacleConstraint(Constraint constraint,
65 - CodecContext context) {
66 - checkNotNull(constraint, "Obstacle constraint cannot be null");
67 - final ObstacleConstraint obstacleConstraint =
68 - (ObstacleConstraint) constraint;
69 -
70 - final ObjectNode result = context.mapper().createObjectNode();
71 - final ArrayNode jsonObstacles = result.putArray("obstacles");
72 -
73 - for (DeviceId did : obstacleConstraint.obstacles()) {
74 - jsonObstacles.add(did.toString());
75 - }
76 -
77 - return result;
78 - }
79 -
80 - /**
81 - * Encodes a waypoint constraint.
82 - *
83 - * @param constraint waypoint constraint to encode
84 - * @param context code context
85 - * @return JSON ObjectNode representing the constraint
86 - */
87 - private ObjectNode encodeWaypointConstraint(Constraint constraint,
88 - CodecContext context) {
89 - checkNotNull(constraint, "Waypoint constraint cannot be null");
90 - final WaypointConstraint waypointConstraint =
91 - (WaypointConstraint) constraint;
92 -
93 - final ObjectNode result = context.mapper().createObjectNode();
94 - final ArrayNode jsonWaypoints = result.putArray("waypoints");
95 -
96 - for (DeviceId did : waypointConstraint.waypoints()) {
97 - jsonWaypoints.add(did.toString());
98 - }
99 -
100 - return result;
101 - }
102 -
103 - /**
104 - * Encodes a annotation constraint.
105 - *
106 - * @param constraint annotation constraint to encode
107 - * @param context code context
108 - * @return JSON ObjectNode representing the constraint
109 - */
110 - private ObjectNode encodeAnnotationConstraint(Constraint constraint,
111 - CodecContext context) {
112 - checkNotNull(constraint, "Annotation constraint cannot be null");
113 - final AnnotationConstraint annotationConstraint =
114 - (AnnotationConstraint) constraint;
115 - return context.mapper().createObjectNode()
116 - .put("key", annotationConstraint.key())
117 - .put("threshold", annotationConstraint.threshold());
118 - }
119 43
120 - /** 44 + @Override
121 - * Encodes a bandwidth constraint. 45 + public ObjectNode encode(Constraint constraint, CodecContext context) {
122 - * 46 + checkNotNull(constraint, "Constraint cannot be null");
123 - * @param constraint bandwidth constraint to encode
124 - * @param context code context
125 - * @return JSON ObjectNode representing the constraint
126 - */
127 - private ObjectNode encodeBandwidthConstraint(Constraint constraint,
128 - CodecContext context) {
129 - checkNotNull(constraint, "Bandwidth constraint cannot be null");
130 - final BandwidthConstraint bandwidthConstraint =
131 - (BandwidthConstraint) constraint;
132 - return context.mapper().createObjectNode()
133 - .put("bandwidth", bandwidthConstraint.bandwidth().toDouble());
134 - }
135 -
136 - /**
137 - * Encodes a lambda constraint.
138 - *
139 - * @param constraint lambda constraint to encode
140 - * @param context code context
141 - * @return JSON ObjectNode representing the constraint
142 - */
143 - private ObjectNode encodeLambdaConstraint(Constraint constraint,
144 - CodecContext context) {
145 - checkNotNull(constraint, "Lambda constraint cannot be null");
146 - final LambdaConstraint lambdaConstraint =
147 - (LambdaConstraint) constraint;
148 -
149 - return context.mapper().createObjectNode()
150 - .put("lambda", lambdaConstraint.lambda().toInt());
151 - }
152 -
153 - /**
154 - * Encodes a link type constraint.
155 - *
156 - * @param constraint link type constraint to encode
157 - * @param context code context
158 - * @return JSON ObjectNode representing the constraint
159 - */
160 - private ObjectNode encodeLinkTypeConstraint(Constraint constraint,
161 - CodecContext context) {
162 - checkNotNull(constraint, "Link type constraint cannot be null");
163 -
164 - final LinkTypeConstraint linkTypeConstraint =
165 - (LinkTypeConstraint) constraint;
166 -
167 - final ObjectNode result = context.mapper().createObjectNode()
168 - .put("inclusive", linkTypeConstraint.isInclusive());
169 -
170 - final ArrayNode jsonTypes = result.putArray("types");
171 47
172 - if (linkTypeConstraint.types() != null) { 48 + final EncodeConstraintCodec encodeCodec =
173 - for (Link.Type type : linkTypeConstraint.types()) { 49 + new EncodeConstraintCodec(constraint, context);
174 - jsonTypes.add(type.name());
175 - }
176 - }
177 50
178 - return result; 51 + return encodeCodec.encode();
179 } 52 }
180 53
181 @Override 54 @Override
182 - public ObjectNode encode(Constraint constraint, CodecContext context) { 55 + public Constraint decode(ObjectNode json, CodecContext context) {
183 - checkNotNull(constraint, "Constraint cannot be null"); 56 + checkNotNull(json, "JSON cannot be null");
184 57
185 - final ObjectNode result; 58 + final DecodeConstraintCodec decodeCodec =
186 - if (constraint instanceof BandwidthConstraint) { 59 + new DecodeConstraintCodec(json);
187 - result = encodeBandwidthConstraint(constraint, context);
188 - } else if (constraint instanceof LambdaConstraint) {
189 - result = encodeLambdaConstraint(constraint, context);
190 - } else if (constraint instanceof LinkTypeConstraint) {
191 - result = encodeLinkTypeConstraint(constraint, context);
192 - } else if (constraint instanceof AnnotationConstraint) {
193 - result = encodeAnnotationConstraint(constraint, context);
194 - } else if (constraint instanceof LatencyConstraint) {
195 - result = encodeLatencyConstraint(constraint, context);
196 - } else if (constraint instanceof ObstacleConstraint) {
197 - result = encodeObstacleConstraint(constraint, context);
198 - } else if (constraint instanceof WaypointConstraint) {
199 - result = encodeWaypointConstraint(constraint, context);
200 - } else {
201 - result = context.mapper().createObjectNode();
202 - }
203 60
204 - result.put("type", constraint.getClass().getSimpleName()); 61 + return decodeCodec.decode();
205 - return result;
206 } 62 }
207 } 63 }
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.codec.impl;
17 +
18 +import java.time.Duration;
19 +import java.util.ArrayList;
20 +import java.util.stream.IntStream;
21 +
22 +import org.onlab.util.Bandwidth;
23 +import org.onosproject.net.DeviceId;
24 +import org.onosproject.net.IndexedLambda;
25 +import org.onosproject.net.Link;
26 +import org.onosproject.net.intent.Constraint;
27 +import org.onosproject.net.intent.constraint.AnnotationConstraint;
28 +import org.onosproject.net.intent.constraint.AsymmetricPathConstraint;
29 +import org.onosproject.net.intent.constraint.BandwidthConstraint;
30 +import org.onosproject.net.intent.constraint.LambdaConstraint;
31 +import org.onosproject.net.intent.constraint.LatencyConstraint;
32 +import org.onosproject.net.intent.constraint.LinkTypeConstraint;
33 +import org.onosproject.net.intent.constraint.ObstacleConstraint;
34 +import org.onosproject.net.intent.constraint.WaypointConstraint;
35 +import org.onosproject.net.resource.link.BandwidthResource;
36 +import org.onosproject.net.resource.link.LambdaResource;
37 +
38 +import com.fasterxml.jackson.databind.JsonNode;
39 +import com.fasterxml.jackson.databind.node.ObjectNode;
40 +
41 +import static org.onlab.util.Tools.nullIsIllegal;
42 +
43 +/**
44 + * Constraint JSON decoder.
45 + */
46 +public final class DecodeConstraintCodec {
47 + private final ObjectNode json;
48 +
49 + /**
50 + * Constructs a constraint decoder.
51 + *
52 + * @param json object node to decode
53 + */
54 + public DecodeConstraintCodec(ObjectNode json) {
55 + this.json = json;
56 + }
57 +
58 + /**
59 + * Decodes a link type constraint.
60 + *
61 + * @return link type constraint object.
62 + */
63 + private Constraint decodeLinkTypeConstraint() {
64 + boolean inclusive = nullIsIllegal(json.get(ConstraintCodec.INCLUSIVE),
65 + ConstraintCodec.INCLUSIVE + ConstraintCodec.MISSING_MEMBER_MESSAGE).asBoolean();
66 +
67 + JsonNode types = nullIsIllegal(json.get(ConstraintCodec.TYPES),
68 + ConstraintCodec.TYPES + ConstraintCodec.MISSING_MEMBER_MESSAGE);
69 + if (types.size() < 1) {
70 + throw new IllegalArgumentException(
71 + "types array in link constraint must have at least one value");
72 + }
73 +
74 + ArrayList<Link.Type> typesEntries = new ArrayList<>(types.size());
75 + IntStream.range(0, types.size())
76 + .forEach(index ->
77 + typesEntries.add(Link.Type.valueOf(types.get(index).asText())));
78 +
79 + return new LinkTypeConstraint(inclusive,
80 + typesEntries.toArray(new Link.Type[types.size()]));
81 + }
82 +
83 + /**
84 + * Decodes an annotation constraint.
85 + *
86 + * @return annotation constraint object.
87 + */
88 + private Constraint decodeAnnotationConstraint() {
89 + String key = nullIsIllegal(json.get(ConstraintCodec.KEY),
90 + ConstraintCodec.KEY + ConstraintCodec.MISSING_MEMBER_MESSAGE)
91 + .asText();
92 + double threshold = nullIsIllegal(json.get(ConstraintCodec.THRESHOLD),
93 + ConstraintCodec.THRESHOLD + ConstraintCodec.MISSING_MEMBER_MESSAGE)
94 + .asDouble();
95 +
96 + return new AnnotationConstraint(key, threshold);
97 + }
98 +
99 + /**
100 + * Decodes a lambda constraint.
101 + *
102 + * @return lambda constraint object.
103 + */
104 + private Constraint decodeLambdaConstraint() {
105 + long lambda = nullIsIllegal(json.get(ConstraintCodec.LAMBDA),
106 + ConstraintCodec.LAMBDA + ConstraintCodec.MISSING_MEMBER_MESSAGE)
107 + .asLong();
108 +
109 + return new LambdaConstraint(LambdaResource.valueOf(new IndexedLambda(lambda)));
110 + }
111 +
112 + /**
113 + * Decodes a latency constraint.
114 + *
115 + * @return latency constraint object.
116 + */
117 + private Constraint decodeLatencyConstraint() {
118 + long latencyMillis = nullIsIllegal(json.get(ConstraintCodec.LATENCY_MILLIS),
119 + ConstraintCodec.LATENCY_MILLIS + ConstraintCodec.MISSING_MEMBER_MESSAGE)
120 + .asLong();
121 +
122 + return new LatencyConstraint(Duration.ofMillis(latencyMillis));
123 + }
124 +
125 + /**
126 + * Decodes an obstacle constraint.
127 + *
128 + * @return obstacle constraint object.
129 + */
130 + private Constraint decodeObstacleConstraint() {
131 + JsonNode obstacles = nullIsIllegal(json.get(ConstraintCodec.OBSTACLES),
132 + ConstraintCodec.OBSTACLES + ConstraintCodec.MISSING_MEMBER_MESSAGE);
133 + if (obstacles.size() < 1) {
134 + throw new IllegalArgumentException(
135 + "obstacles array in obstacles constraint must have at least one value");
136 + }
137 +
138 + ArrayList<DeviceId> obstacleEntries = new ArrayList<>(obstacles.size());
139 + IntStream.range(0, obstacles.size())
140 + .forEach(index ->
141 + obstacleEntries.add(DeviceId.deviceId(obstacles.get(index).asText())));
142 +
143 + return new ObstacleConstraint(
144 + obstacleEntries.toArray(new DeviceId[obstacles.size()]));
145 + }
146 +
147 + /**
148 + * Decodes a waypoint constraint.
149 + *
150 + * @return waypoint constraint object.
151 + */
152 + private Constraint decodeWaypointConstraint() {
153 + JsonNode waypoints = nullIsIllegal(json.get(ConstraintCodec.WAYPOINTS),
154 + ConstraintCodec.WAYPOINTS + ConstraintCodec.MISSING_MEMBER_MESSAGE);
155 + if (waypoints.size() < 1) {
156 + throw new IllegalArgumentException(
157 + "obstacles array in obstacles constraint must have at least one value");
158 + }
159 +
160 + ArrayList<DeviceId> waypointEntries = new ArrayList<>(waypoints.size());
161 + IntStream.range(0, waypoints.size())
162 + .forEach(index ->
163 + waypointEntries.add(DeviceId.deviceId(waypoints.get(index).asText())));
164 +
165 + return new WaypointConstraint(
166 + waypointEntries.toArray(new DeviceId[waypoints.size()]));
167 + }
168 +
169 + /**
170 + * Decodes an asymmetric path constraint.
171 + *
172 + * @return asymmetric path constraint object.
173 + */
174 + private Constraint decodeAsymmetricPathConstraint() {
175 + return new AsymmetricPathConstraint();
176 + }
177 +
178 + /**
179 + * Decodes a bandwidth constraint.
180 + *
181 + * @return bandwidth constraint object.
182 + */
183 + private Constraint decodeBandwidthConstraint() {
184 + double bandwidth = nullIsIllegal(json.get(ConstraintCodec.BANDWIDTH),
185 + ConstraintCodec.BANDWIDTH + ConstraintCodec.MISSING_MEMBER_MESSAGE)
186 + .asDouble();
187 +
188 + return new BandwidthConstraint(new BandwidthResource(Bandwidth.bps(bandwidth)));
189 + }
190 +
191 + /**
192 + * Decodes the given constraint.
193 + *
194 + * @return constraint object.
195 + */
196 + public Constraint decode() {
197 + final String type = nullIsIllegal(json.get(ConstraintCodec.TYPE),
198 + ConstraintCodec.TYPE + ConstraintCodec.MISSING_MEMBER_MESSAGE)
199 + .asText();
200 +
201 + if (type.equals(BandwidthConstraint.class.getSimpleName())) {
202 + return decodeBandwidthConstraint();
203 + } else if (type.equals(LambdaConstraint.class.getSimpleName())) {
204 + return decodeLambdaConstraint();
205 + } else if (type.equals(LinkTypeConstraint.class.getSimpleName())) {
206 + return decodeLinkTypeConstraint();
207 + } else if (type.equals(AnnotationConstraint.class.getSimpleName())) {
208 + return decodeAnnotationConstraint();
209 + } else if (type.equals(LatencyConstraint.class.getSimpleName())) {
210 + return decodeLatencyConstraint();
211 + } else if (type.equals(ObstacleConstraint.class.getSimpleName())) {
212 + return decodeObstacleConstraint();
213 + } else if (type.equals(WaypointConstraint.class.getSimpleName())) {
214 + return decodeWaypointConstraint();
215 + } else if (type.equals(AsymmetricPathConstraint.class.getSimpleName())) {
216 + return decodeAsymmetricPathConstraint();
217 + } else if (type.equals(LinkTypeConstraint.class.getSimpleName())) {
218 + return decodeLinkTypeConstraint();
219 + } else if (type.equals(AnnotationConstraint.class.getSimpleName())) {
220 + return decodeAnnotationConstraint();
221 + }
222 + throw new IllegalArgumentException("Instruction type "
223 + + type + " is not supported");
224 + }
225 +}
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.codec.impl;
17 +
18 +import org.onosproject.codec.CodecContext;
19 +import org.onosproject.net.DeviceId;
20 +import org.onosproject.net.Link;
21 +import org.onosproject.net.intent.Constraint;
22 +import org.onosproject.net.intent.constraint.AnnotationConstraint;
23 +import org.onosproject.net.intent.constraint.BandwidthConstraint;
24 +import org.onosproject.net.intent.constraint.LambdaConstraint;
25 +import org.onosproject.net.intent.constraint.LatencyConstraint;
26 +import org.onosproject.net.intent.constraint.LinkTypeConstraint;
27 +import org.onosproject.net.intent.constraint.ObstacleConstraint;
28 +import org.onosproject.net.intent.constraint.WaypointConstraint;
29 +
30 +import com.fasterxml.jackson.databind.node.ArrayNode;
31 +import com.fasterxml.jackson.databind.node.ObjectNode;
32 +
33 +import static com.google.common.base.Preconditions.checkNotNull;
34 +
35 +/**
36 + * Implementation of encoder for constraint JSON codec.
37 + */
38 +public final class EncodeConstraintCodec {
39 +
40 + private final Constraint constraint;
41 + private final CodecContext context;
42 +
43 + /**
44 + * Constructs a constraint encoder.
45 + *
46 + * @param constraint constraint to encode
47 + * @param context to use for look ups
48 + */
49 + public EncodeConstraintCodec(Constraint constraint, CodecContext context) {
50 + this.constraint = constraint;
51 + this.context = context;
52 + }
53 +
54 + /**
55 + * Encodes a latency constraint.
56 + *
57 + * @return JSON ObjectNode representing the constraint
58 + */
59 + private ObjectNode encodeLatencyConstraint() {
60 + checkNotNull(constraint, "Duration constraint cannot be null");
61 + final LatencyConstraint latencyConstraint =
62 + (LatencyConstraint) constraint;
63 + return context.mapper().createObjectNode()
64 + .put("latencyMillis", latencyConstraint.latency().toMillis());
65 + }
66 +
67 + /**
68 + * Encodes an obstacle constraint.
69 + *
70 + * @return JSON ObjectNode representing the constraint
71 + */
72 + private ObjectNode encodeObstacleConstraint() {
73 + checkNotNull(constraint, "Obstacle constraint cannot be null");
74 + final ObstacleConstraint obstacleConstraint =
75 + (ObstacleConstraint) constraint;
76 +
77 + final ObjectNode result = context.mapper().createObjectNode();
78 + final ArrayNode jsonObstacles = result.putArray("obstacles");
79 +
80 + for (DeviceId did : obstacleConstraint.obstacles()) {
81 + jsonObstacles.add(did.toString());
82 + }
83 +
84 + return result;
85 + }
86 +
87 + /**
88 + * Encodes a waypoint constraint.
89 + *
90 + * @return JSON ObjectNode representing the constraint
91 + */
92 + private ObjectNode encodeWaypointConstraint() {
93 + checkNotNull(constraint, "Waypoint constraint cannot be null");
94 + final WaypointConstraint waypointConstraint =
95 + (WaypointConstraint) constraint;
96 +
97 + final ObjectNode result = context.mapper().createObjectNode();
98 + final ArrayNode jsonWaypoints = result.putArray("waypoints");
99 +
100 + for (DeviceId did : waypointConstraint.waypoints()) {
101 + jsonWaypoints.add(did.toString());
102 + }
103 +
104 + return result;
105 + }
106 +
107 + /**
108 + * Encodes a annotation constraint.
109 + *
110 + * @return JSON ObjectNode representing the constraint
111 + */
112 + private ObjectNode encodeAnnotationConstraint() {
113 + checkNotNull(constraint, "Annotation constraint cannot be null");
114 + final AnnotationConstraint annotationConstraint =
115 + (AnnotationConstraint) constraint;
116 + return context.mapper().createObjectNode()
117 + .put("key", annotationConstraint.key())
118 + .put("threshold", annotationConstraint.threshold());
119 + }
120 +
121 + /**
122 + * Encodes a bandwidth constraint.
123 + *
124 + * @return JSON ObjectNode representing the constraint
125 + */
126 + private ObjectNode encodeBandwidthConstraint() {
127 + checkNotNull(constraint, "Bandwidth constraint cannot be null");
128 + final BandwidthConstraint bandwidthConstraint =
129 + (BandwidthConstraint) constraint;
130 + return context.mapper().createObjectNode()
131 + .put("bandwidth", bandwidthConstraint.bandwidth().toDouble());
132 + }
133 +
134 + /**
135 + * Encodes a lambda constraint.
136 + *
137 + * @return JSON ObjectNode representing the constraint
138 + */
139 + private ObjectNode encodeLambdaConstraint() {
140 + checkNotNull(constraint, "Lambda constraint cannot be null");
141 + final LambdaConstraint lambdaConstraint =
142 + (LambdaConstraint) constraint;
143 +
144 + return context.mapper().createObjectNode()
145 + .put("lambda", lambdaConstraint.lambda().toInt());
146 + }
147 +
148 + /**
149 + * Encodes a link type constraint.
150 + *
151 + * @return JSON ObjectNode representing the constraint
152 + */
153 + private ObjectNode encodeLinkTypeConstraint() {
154 + checkNotNull(constraint, "Link type constraint cannot be null");
155 +
156 + final LinkTypeConstraint linkTypeConstraint =
157 + (LinkTypeConstraint) constraint;
158 +
159 + final ObjectNode result = context.mapper().createObjectNode()
160 + .put(ConstraintCodec.INCLUSIVE, linkTypeConstraint.isInclusive());
161 +
162 + final ArrayNode jsonTypes = result.putArray(ConstraintCodec.TYPES);
163 +
164 + if (linkTypeConstraint.types() != null) {
165 + for (Link.Type type : linkTypeConstraint.types()) {
166 + jsonTypes.add(type.name());
167 + }
168 + }
169 +
170 + return result;
171 + }
172 +
173 + /**
174 + * Encodes the constraint in JSON.
175 + *
176 + * @return JSON node
177 + */
178 + public ObjectNode encode() {
179 + final ObjectNode result;
180 + if (constraint instanceof BandwidthConstraint) {
181 + result = encodeBandwidthConstraint();
182 + } else if (constraint instanceof LambdaConstraint) {
183 + result = encodeLambdaConstraint();
184 + } else if (constraint instanceof LinkTypeConstraint) {
185 + result = encodeLinkTypeConstraint();
186 + } else if (constraint instanceof AnnotationConstraint) {
187 + result = encodeAnnotationConstraint();
188 + } else if (constraint instanceof LatencyConstraint) {
189 + result = encodeLatencyConstraint();
190 + } else if (constraint instanceof ObstacleConstraint) {
191 + result = encodeObstacleConstraint();
192 + } else if (constraint instanceof WaypointConstraint) {
193 + result = encodeWaypointConstraint();
194 + } else {
195 + result = context.mapper().createObjectNode();
196 + }
197 +
198 + result.put(ConstraintCodec.TYPE, constraint.getClass().getSimpleName());
199 + return result;
200 + }
201 +}
...@@ -75,14 +75,14 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> { ...@@ -75,14 +75,14 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> {
75 DEVICE_ID + MISSING_MEMBER_MESSAGE).asText()); 75 DEVICE_ID + MISSING_MEMBER_MESSAGE).asText());
76 resultBuilder.forDevice(deviceId); 76 resultBuilder.forDevice(deviceId);
77 77
78 - ObjectNode treatmentJson = (ObjectNode) json.get(TREATMENT); 78 + ObjectNode treatmentJson = get(json, TREATMENT);
79 if (treatmentJson != null) { 79 if (treatmentJson != null) {
80 JsonCodec<TrafficTreatment> treatmentCodec = 80 JsonCodec<TrafficTreatment> treatmentCodec =
81 context.codec(TrafficTreatment.class); 81 context.codec(TrafficTreatment.class);
82 resultBuilder.withTreatment(treatmentCodec.decode(treatmentJson, context)); 82 resultBuilder.withTreatment(treatmentCodec.decode(treatmentJson, context));
83 } 83 }
84 84
85 - ObjectNode selectorJson = (ObjectNode) json.get(SELECTOR); 85 + ObjectNode selectorJson = get(json, SELECTOR);
86 if (selectorJson != null) { 86 if (selectorJson != null) {
87 JsonCodec<TrafficSelector> selectorCodec = 87 JsonCodec<TrafficSelector> selectorCodec =
88 context.codec(TrafficSelector.class); 88 context.codec(TrafficSelector.class);
......
...@@ -17,18 +17,23 @@ package org.onosproject.codec.impl; ...@@ -17,18 +17,23 @@ package org.onosproject.codec.impl;
17 17
18 import org.onosproject.codec.CodecContext; 18 import org.onosproject.codec.CodecContext;
19 import org.onosproject.codec.JsonCodec; 19 import org.onosproject.codec.JsonCodec;
20 +import org.onosproject.net.HostId;
20 import org.onosproject.net.intent.ConnectivityIntent; 21 import org.onosproject.net.intent.ConnectivityIntent;
21 import org.onosproject.net.intent.HostToHostIntent; 22 import org.onosproject.net.intent.HostToHostIntent;
22 23
23 import com.fasterxml.jackson.databind.node.ObjectNode; 24 import com.fasterxml.jackson.databind.node.ObjectNode;
24 25
25 import static com.google.common.base.Preconditions.checkNotNull; 26 import static com.google.common.base.Preconditions.checkNotNull;
27 +import static org.onlab.util.Tools.nullIsIllegal;
26 28
27 /** 29 /**
28 * Host to host intent codec. 30 * Host to host intent codec.
29 */ 31 */
30 public final class HostToHostIntentCodec extends JsonCodec<HostToHostIntent> { 32 public final class HostToHostIntentCodec extends JsonCodec<HostToHostIntent> {
31 33
34 + private static final String ONE = "one";
35 + private static final String TWO = "two";
36 +
32 @Override 37 @Override
33 public ObjectNode encode(HostToHostIntent intent, CodecContext context) { 38 public ObjectNode encode(HostToHostIntent intent, CodecContext context) {
34 checkNotNull(intent, "Host to host intent cannot be null"); 39 checkNotNull(intent, "Host to host intent cannot be null");
...@@ -39,9 +44,27 @@ public final class HostToHostIntentCodec extends JsonCodec<HostToHostIntent> { ...@@ -39,9 +44,27 @@ public final class HostToHostIntentCodec extends JsonCodec<HostToHostIntent> {
39 44
40 final String one = intent.one().toString(); 45 final String one = intent.one().toString();
41 final String two = intent.two().toString(); 46 final String two = intent.two().toString();
42 - result.put("one", one); 47 + result.put(ONE, one);
43 - result.put("two", two); 48 + result.put(TWO, two);
44 49
45 return result; 50 return result;
46 } 51 }
52 +
53 + @Override
54 + public HostToHostIntent decode(ObjectNode json, CodecContext context) {
55 + HostToHostIntent.Builder builder = HostToHostIntent.builder();
56 +
57 + IntentCodec.intentAttributes(json, context, builder);
58 + ConnectivityIntentCodec.intentAttributes(json, context, builder);
59 +
60 + String one = nullIsIllegal(json.get(ONE),
61 + ONE + IntentCodec.MISSING_MEMBER_MESSAGE).asText();
62 + builder.one(HostId.hostId(one));
63 +
64 + String two = nullIsIllegal(json.get(TWO),
65 + TWO + IntentCodec.MISSING_MEMBER_MESSAGE).asText();
66 + builder.two(HostId.hostId(two));
67 +
68 + return builder.build();
69 + }
47 } 70 }
......
...@@ -17,31 +17,46 @@ package org.onosproject.codec.impl; ...@@ -17,31 +17,46 @@ package org.onosproject.codec.impl;
17 17
18 import org.onosproject.codec.CodecContext; 18 import org.onosproject.codec.CodecContext;
19 import org.onosproject.codec.JsonCodec; 19 import org.onosproject.codec.JsonCodec;
20 +import org.onosproject.core.CoreService;
20 import org.onosproject.net.NetworkResource; 21 import org.onosproject.net.NetworkResource;
22 +import org.onosproject.net.intent.HostToHostIntent;
21 import org.onosproject.net.intent.Intent; 23 import org.onosproject.net.intent.Intent;
22 import org.onosproject.net.intent.IntentService; 24 import org.onosproject.net.intent.IntentService;
23 import org.onosproject.net.intent.IntentState; 25 import org.onosproject.net.intent.IntentState;
26 +import org.onosproject.net.intent.PointToPointIntent;
24 27
28 +import com.fasterxml.jackson.databind.JsonNode;
25 import com.fasterxml.jackson.databind.node.ArrayNode; 29 import com.fasterxml.jackson.databind.node.ArrayNode;
26 import com.fasterxml.jackson.databind.node.ObjectNode; 30 import com.fasterxml.jackson.databind.node.ObjectNode;
27 31
28 import static com.google.common.base.Preconditions.checkNotNull; 32 import static com.google.common.base.Preconditions.checkNotNull;
33 +import static org.onlab.util.Tools.nullIsIllegal;
29 34
30 /** 35 /**
31 * Intent JSON codec. 36 * Intent JSON codec.
32 */ 37 */
33 public final class IntentCodec extends JsonCodec<Intent> { 38 public final class IntentCodec extends JsonCodec<Intent> {
34 39
40 + protected static final String TYPE = "type";
41 + protected static final String ID = "id";
42 + protected static final String APP_ID = "appId";
43 + protected static final String DETAILS = "details";
44 + protected static final String STATE = "state";
45 + protected static final String PRIORITY = "priority";
46 + protected static final String RESOURCES = "resources";
47 + protected static final String MISSING_MEMBER_MESSAGE =
48 + " member is required in Intent";
49 +
35 @Override 50 @Override
36 public ObjectNode encode(Intent intent, CodecContext context) { 51 public ObjectNode encode(Intent intent, CodecContext context) {
37 checkNotNull(intent, "Intent cannot be null"); 52 checkNotNull(intent, "Intent cannot be null");
38 final ObjectNode result = context.mapper().createObjectNode() 53 final ObjectNode result = context.mapper().createObjectNode()
39 - .put("type", intent.getClass().getSimpleName()) 54 + .put(TYPE, intent.getClass().getSimpleName())
40 - .put("id", intent.id().toString()) 55 + .put(ID, intent.id().toString())
41 - .put("appId", intent.appId().toString()) 56 + .put(APP_ID, intent.appId().toString())
42 - .put("details", intent.toString()); 57 + .put(DETAILS, intent.toString());
43 58
44 - final ArrayNode jsonResources = result.putArray("resources"); 59 + final ArrayNode jsonResources = result.putArray(RESOURCES);
45 60
46 for (final NetworkResource resource : intent.resources()) { 61 for (final NetworkResource resource : intent.resources()) {
47 jsonResources.add(resource.toString()); 62 jsonResources.add(resource.toString());
...@@ -50,9 +65,47 @@ public final class IntentCodec extends JsonCodec<Intent> { ...@@ -50,9 +65,47 @@ public final class IntentCodec extends JsonCodec<Intent> {
50 IntentService service = context.getService(IntentService.class); 65 IntentService service = context.getService(IntentService.class);
51 IntentState state = service.getIntentState(intent.key()); 66 IntentState state = service.getIntentState(intent.key());
52 if (state != null) { 67 if (state != null) {
53 - result.put("state", state.toString()); 68 + result.put(STATE, state.toString());
54 } 69 }
55 70
56 return result; 71 return result;
57 } 72 }
73 +
74 + @Override
75 + public Intent decode(ObjectNode json, CodecContext context) {
76 + checkNotNull(json, "JSON cannot be null");
77 +
78 + String type = nullIsIllegal(json.get(TYPE),
79 + TYPE + MISSING_MEMBER_MESSAGE).asText();
80 +
81 + if (type.equals(PointToPointIntent.class.getSimpleName())) {
82 + return context.codec(PointToPointIntent.class).decode(json, context);
83 + } else if (type.equals(HostToHostIntent.class.getSimpleName())) {
84 + return context.codec(HostToHostIntent.class).decode(json, context);
85 + }
86 +
87 + throw new IllegalArgumentException("Intent type "
88 + + type + " is not supported");
89 + }
90 +
91 + /**
92 + * Extracts base intent specific attributes from a JSON object
93 + * and adds them to a builder.
94 + *
95 + * @param json root JSON object
96 + * @param context code context
97 + * @param builder builder to use for storing the attributes
98 + */
99 + public static void intentAttributes(ObjectNode json, CodecContext context,
100 + Intent.Builder builder) {
101 + short appId = (short) nullIsIllegal(json.get(IntentCodec.APP_ID),
102 + IntentCodec.TYPE + IntentCodec.MISSING_MEMBER_MESSAGE).asInt();
103 + CoreService service = context.getService(CoreService.class);
104 + builder.appId(service.getAppId(appId));
105 +
106 + JsonNode priorityJson = json.get(IntentCodec.PRIORITY);
107 + if (priorityJson != null) {
108 + builder.priority(priorityJson.asInt());
109 + }
110 + }
58 } 111 }
......
...@@ -70,8 +70,8 @@ public final class LinkCodec extends AnnotatedCodec<Link> { ...@@ -70,8 +70,8 @@ public final class LinkCodec extends AnnotatedCodec<Link> {
70 // TODO: add providerId to JSON if we need to recover them. 70 // TODO: add providerId to JSON if we need to recover them.
71 ProviderId pid = new ProviderId("json", "LinkCodec"); 71 ProviderId pid = new ProviderId("json", "LinkCodec");
72 72
73 - ConnectPoint src = codec.decode((ObjectNode) json.get(SRC), context); 73 + ConnectPoint src = codec.decode(get(json, SRC), context);
74 - ConnectPoint dst = codec.decode((ObjectNode) json.get(DST), context); 74 + ConnectPoint dst = codec.decode(get(json, DST), context);
75 Type type = Type.valueOf(json.get(TYPE).asText()); 75 Type type = Type.valueOf(json.get(TYPE).asText());
76 Annotations annotations = extractAnnotations(json, context); 76 Annotations annotations = extractAnnotations(json, context);
77 77
......
...@@ -24,12 +24,16 @@ import org.onosproject.net.intent.PointToPointIntent; ...@@ -24,12 +24,16 @@ import org.onosproject.net.intent.PointToPointIntent;
24 import com.fasterxml.jackson.databind.node.ObjectNode; 24 import com.fasterxml.jackson.databind.node.ObjectNode;
25 25
26 import static com.google.common.base.Preconditions.checkNotNull; 26 import static com.google.common.base.Preconditions.checkNotNull;
27 +import static org.onlab.util.Tools.nullIsIllegal;
27 28
28 /** 29 /**
29 * Point to point intent codec. 30 * Point to point intent codec.
30 */ 31 */
31 public final class PointToPointIntentCodec extends JsonCodec<PointToPointIntent> { 32 public final class PointToPointIntentCodec extends JsonCodec<PointToPointIntent> {
32 33
34 + private static final String INGRESS_POINT = "ingressPoint";
35 + private static final String EGRESS_POINT = "egressPoint";
36 +
33 @Override 37 @Override
34 public ObjectNode encode(PointToPointIntent intent, CodecContext context) { 38 public ObjectNode encode(PointToPointIntent intent, CodecContext context) {
35 checkNotNull(intent, "Point to point intent cannot be null"); 39 checkNotNull(intent, "Point to point intent cannot be null");
...@@ -45,9 +49,32 @@ public final class PointToPointIntentCodec extends JsonCodec<PointToPointIntent> ...@@ -45,9 +49,32 @@ public final class PointToPointIntentCodec extends JsonCodec<PointToPointIntent>
45 final ObjectNode egress = 49 final ObjectNode egress =
46 connectPointCodec.encode(intent.egressPoint(), context); 50 connectPointCodec.encode(intent.egressPoint(), context);
47 51
48 - result.set("ingressPoint", ingress); 52 + result.set(INGRESS_POINT, ingress);
49 - result.set("egressPoint", egress); 53 + result.set(EGRESS_POINT, egress);
50 54
51 return result; 55 return result;
52 } 56 }
57 +
58 +
59 + @Override
60 + public PointToPointIntent decode(ObjectNode json, CodecContext context) {
61 + PointToPointIntent.Builder builder = PointToPointIntent.builder();
62 +
63 + IntentCodec.intentAttributes(json, context, builder);
64 + ConnectivityIntentCodec.intentAttributes(json, context, builder);
65 +
66 + ObjectNode ingressJson = nullIsIllegal(get(json, INGRESS_POINT),
67 + INGRESS_POINT + IntentCodec.MISSING_MEMBER_MESSAGE);
68 + ConnectPoint ingress = context.codec(ConnectPoint.class)
69 + .decode(ingressJson, context);
70 + builder.ingressPoint(ingress);
71 +
72 + ObjectNode egressJson = nullIsIllegal(get(json, EGRESS_POINT),
73 + EGRESS_POINT + IntentCodec.MISSING_MEMBER_MESSAGE);
74 + ConnectPoint egress = context.codec(ConnectPoint.class)
75 + .decode(egressJson, context);
76 + builder.egressPoint(egress);
77 +
78 + return builder.build();
79 + }
53 } 80 }
......
...@@ -63,7 +63,7 @@ public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { ...@@ -63,7 +63,7 @@ public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> {
63 if (criteriaJson != null) { 63 if (criteriaJson != null) {
64 IntStream.range(0, criteriaJson.size()) 64 IntStream.range(0, criteriaJson.size())
65 .forEach(i -> builder.add( 65 .forEach(i -> builder.add(
66 - criterionCodec.decode((ObjectNode) criteriaJson.get(i), 66 + criterionCodec.decode(get(criteriaJson, i),
67 context))); 67 context)));
68 } 68 }
69 return builder.build(); 69 return builder.build();
......
...@@ -68,7 +68,7 @@ public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { ...@@ -68,7 +68,7 @@ public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> {
68 if (instructionsJson != null) { 68 if (instructionsJson != null) {
69 IntStream.range(0, instructionsJson.size()) 69 IntStream.range(0, instructionsJson.size())
70 .forEach(i -> builder.add( 70 .forEach(i -> builder.add(
71 - instructionsCodec.decode((ObjectNode) instructionsJson.get(i), 71 + instructionsCodec.decode(get(instructionsJson, i),
72 context))); 72 context)));
73 } 73 }
74 return builder.build(); 74 return builder.build();
......
1 +/*
2 + * Copyright 2015 Open Networking Laboratory
3 + *
4 + * Licensed under the Apache License, Version 2.0 (the "License");
5 + * you may not use this file except in compliance with the License.
6 + * You may obtain a copy of the License at
7 + *
8 + * http://www.apache.org/licenses/LICENSE-2.0
9 + *
10 + * Unless required by applicable law or agreed to in writing, software
11 + * distributed under the License is distributed on an "AS IS" BASIS,
12 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 + * See the License for the specific language governing permissions and
14 + * limitations under the License.
15 + */
16 +package org.onosproject.codec.impl;
17 +
18 +import java.io.IOException;
19 +import java.io.InputStream;
20 +
21 +import org.junit.Assert;
22 +import org.junit.Before;
23 +import org.junit.Test;
24 +import org.onosproject.codec.JsonCodec;
25 +import org.onosproject.core.CoreService;
26 +import org.onosproject.net.Link;
27 +import org.onosproject.net.intent.Constraint;
28 +import org.onosproject.net.intent.constraint.AnnotationConstraint;
29 +import org.onosproject.net.intent.constraint.AsymmetricPathConstraint;
30 +import org.onosproject.net.intent.constraint.BandwidthConstraint;
31 +import org.onosproject.net.intent.constraint.LambdaConstraint;
32 +import org.onosproject.net.intent.constraint.LatencyConstraint;
33 +import org.onosproject.net.intent.constraint.LinkTypeConstraint;
34 +import org.onosproject.net.intent.constraint.ObstacleConstraint;
35 +import org.onosproject.net.intent.constraint.WaypointConstraint;
36 +
37 +import com.fasterxml.jackson.databind.JsonNode;
38 +import com.fasterxml.jackson.databind.node.ObjectNode;
39 +
40 +import static com.google.common.base.Preconditions.checkNotNull;
41 +import static org.easymock.EasyMock.createMock;
42 +import static org.easymock.EasyMock.expect;
43 +import static org.easymock.EasyMock.replay;
44 +import static org.hamcrest.MatcherAssert.assertThat;
45 +import static org.hamcrest.Matchers.hasItem;
46 +import static org.hamcrest.Matchers.hasSize;
47 +import static org.hamcrest.Matchers.instanceOf;
48 +import static org.hamcrest.Matchers.is;
49 +import static org.hamcrest.Matchers.notNullValue;
50 +import static org.onosproject.net.NetTestTools.APP_ID;
51 +import static org.onosproject.net.NetTestTools.did;
52 +
53 +/**
54 + * Unit tests for Constraint codec.
55 + */
56 +public class ConstraintCodecTest {
57 +
58 + MockCodecContext context;
59 + JsonCodec<Constraint> constraintCodec;
60 + final CoreService mockCoreService = createMock(CoreService.class);
61 +
62 + /**
63 + * Sets up for each test. Creates a context and fetches the flow rule
64 + * codec.
65 + */
66 + @Before
67 + public void setUp() {
68 + context = new MockCodecContext();
69 + constraintCodec = context.codec(Constraint.class);
70 + assertThat(constraintCodec, notNullValue());
71 +
72 + expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID))
73 + .andReturn(APP_ID).anyTimes();
74 + replay(mockCoreService);
75 + context.registerService(CoreService.class, mockCoreService);
76 + }
77 +
78 + /**
79 + * Reads in a constraint from the given resource and decodes it.
80 + *
81 + * @param resourceName resource to use to read the JSON for the constraint
82 + * @return decoded constraint
83 + */
84 + private Constraint getConstraint(String resourceName) {
85 + InputStream jsonStream = ConstraintCodecTest.class
86 + .getResourceAsStream(resourceName);
87 + try {
88 + JsonNode json = context.mapper().readTree(jsonStream);
89 + assertThat(json, notNullValue());
90 + Constraint constraint = constraintCodec.decode((ObjectNode) json, context);
91 + assertThat(constraint, notNullValue());
92 + return checkNotNull(constraint);
93 + } catch (IOException ioe) {
94 + Assert.fail(ioe.getMessage());
95 + throw new IllegalStateException("cannot happen");
96 + }
97 + }
98 +
99 +
100 + /**
101 + * Tests link type constraint.
102 + */
103 + @Test
104 + public void linkTypeConstraint() {
105 + Constraint constraint = getConstraint("LinkTypeConstraint.json");
106 + assertThat(constraint, instanceOf(LinkTypeConstraint.class));
107 +
108 + LinkTypeConstraint linkTypeConstraint = (LinkTypeConstraint) constraint;
109 + assertThat(linkTypeConstraint.isInclusive(), is(false));
110 + assertThat(linkTypeConstraint.types(), hasSize(2));
111 + assertThat(linkTypeConstraint.types(), hasItem(Link.Type.OPTICAL));
112 + assertThat(linkTypeConstraint.types(), hasItem(Link.Type.DIRECT));
113 + }
114 +
115 + /**
116 + * Tests annotation constraint.
117 + */
118 + @Test
119 + public void annotationConstraint() {
120 + Constraint constraint = getConstraint("AnnotationConstraint.json");
121 + assertThat(constraint, instanceOf(AnnotationConstraint.class));
122 +
123 + AnnotationConstraint annotationConstraint = (AnnotationConstraint) constraint;
124 + assertThat(annotationConstraint.key(), is("key"));
125 + assertThat(annotationConstraint.threshold(), is(123.0D));
126 + }
127 +
128 + /**
129 + * Tests bandwidth constraint.
130 + */
131 + @Test
132 + public void bandwidthConstraint() {
133 + Constraint constraint = getConstraint("BandwidthConstraint.json");
134 + assertThat(constraint, instanceOf(BandwidthConstraint.class));
135 +
136 + BandwidthConstraint bandwidthConstraint = (BandwidthConstraint) constraint;
137 + assertThat(bandwidthConstraint.bandwidth().toDouble(), is(345.678D));
138 + }
139 +
140 + /**
141 + * Tests lambda constraint.
142 + */
143 + @Test
144 + public void lambdaConstraint() {
145 + Constraint constraint = getConstraint("LambdaConstraint.json");
146 + assertThat(constraint, instanceOf(LambdaConstraint.class));
147 +
148 + LambdaConstraint lambdaConstraint = (LambdaConstraint) constraint;
149 + assertThat(lambdaConstraint.lambda().toInt(), is(444));
150 + }
151 +
152 + /**
153 + * Tests latency constraint.
154 + */
155 + @Test
156 + public void latencyConstraint() {
157 + Constraint constraint = getConstraint("LatencyConstraint.json");
158 + assertThat(constraint, instanceOf(LatencyConstraint.class));
159 +
160 + LatencyConstraint latencyConstraint = (LatencyConstraint) constraint;
161 + assertThat(latencyConstraint.latency().toMillis(), is(111L));
162 + }
163 +
164 + /**
165 + * Tests obstacle constraint.
166 + */
167 + @Test
168 + public void obstacleConstraint() {
169 + Constraint constraint = getConstraint("ObstacleConstraint.json");
170 + assertThat(constraint, instanceOf(ObstacleConstraint.class));
171 +
172 + ObstacleConstraint obstacleConstraint = (ObstacleConstraint) constraint;
173 +
174 + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev1")));
175 + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev2")));
176 + assertThat(obstacleConstraint.obstacles(), hasItem(did("dev3")));
177 + }
178 +
179 + /**
180 + * Tests waypoint constaint.
181 + */
182 + @Test
183 + public void waypointConstraint() {
184 + Constraint constraint = getConstraint("WaypointConstraint.json");
185 + assertThat(constraint, instanceOf(WaypointConstraint.class));
186 +
187 + WaypointConstraint waypointConstraint = (WaypointConstraint) constraint;
188 +
189 + assertThat(waypointConstraint.waypoints(), hasItem(did("devA")));
190 + assertThat(waypointConstraint.waypoints(), hasItem(did("devB")));
191 + assertThat(waypointConstraint.waypoints(), hasItem(did("devC")));
192 + }
193 +
194 + /**
195 + * Tests asymmetric path constraint.
196 + */
197 + @Test
198 + public void asymmetricPathConstraint() {
199 + Constraint constraint = getConstraint("AsymmetricPathConstraint.json");
200 + assertThat(constraint, instanceOf(AsymmetricPathConstraint.class));
201 + }
202 +}
...@@ -15,6 +15,8 @@ ...@@ -15,6 +15,8 @@
15 */ 15 */
16 package org.onosproject.codec.impl; 16 package org.onosproject.codec.impl;
17 17
18 +import java.io.IOException;
19 +import java.io.InputStream;
18 import java.time.Duration; 20 import java.time.Duration;
19 import java.util.List; 21 import java.util.List;
20 22
...@@ -26,6 +28,7 @@ import org.onlab.packet.MplsLabel; ...@@ -26,6 +28,7 @@ import org.onlab.packet.MplsLabel;
26 import org.onlab.util.Bandwidth; 28 import org.onlab.util.Bandwidth;
27 import org.onosproject.codec.JsonCodec; 29 import org.onosproject.codec.JsonCodec;
28 import org.onosproject.core.ApplicationId; 30 import org.onosproject.core.ApplicationId;
31 +import org.onosproject.core.CoreService;
29 import org.onosproject.core.DefaultApplicationId; 32 import org.onosproject.core.DefaultApplicationId;
30 import org.onosproject.net.ChannelSpacing; 33 import org.onosproject.net.ChannelSpacing;
31 import org.onosproject.net.ConnectPoint; 34 import org.onosproject.net.ConnectPoint;
...@@ -43,9 +46,13 @@ import org.onosproject.net.flow.TrafficSelector; ...@@ -43,9 +46,13 @@ import org.onosproject.net.flow.TrafficSelector;
43 import org.onosproject.net.flow.TrafficTreatment; 46 import org.onosproject.net.flow.TrafficTreatment;
44 import org.onosproject.net.flow.criteria.Criteria; 47 import org.onosproject.net.flow.criteria.Criteria;
45 import org.onosproject.net.flow.instructions.Instructions; 48 import org.onosproject.net.flow.instructions.Instructions;
49 +import org.onosproject.net.flow.criteria.Criterion;
50 +import org.onosproject.net.flow.criteria.EthCriterion;
51 +import org.onosproject.net.flow.instructions.Instruction;
46 import org.onosproject.net.intent.AbstractIntentTest; 52 import org.onosproject.net.intent.AbstractIntentTest;
47 import org.onosproject.net.intent.Constraint; 53 import org.onosproject.net.intent.Constraint;
48 import org.onosproject.net.intent.HostToHostIntent; 54 import org.onosproject.net.intent.HostToHostIntent;
55 +import org.onosproject.net.intent.Intent;
49 import org.onosproject.net.intent.IntentService; 56 import org.onosproject.net.intent.IntentService;
50 import org.onosproject.net.intent.IntentServiceAdapter; 57 import org.onosproject.net.intent.IntentServiceAdapter;
51 import org.onosproject.net.intent.PointToPointIntent; 58 import org.onosproject.net.intent.PointToPointIntent;
...@@ -59,14 +66,22 @@ import org.onosproject.net.intent.constraint.WaypointConstraint; ...@@ -59,14 +66,22 @@ import org.onosproject.net.intent.constraint.WaypointConstraint;
59 import org.onosproject.net.resource.link.BandwidthResource; 66 import org.onosproject.net.resource.link.BandwidthResource;
60 import org.onosproject.net.resource.link.LambdaResource; 67 import org.onosproject.net.resource.link.LambdaResource;
61 68
69 +import com.fasterxml.jackson.databind.JsonNode;
62 import com.fasterxml.jackson.databind.node.ObjectNode; 70 import com.fasterxml.jackson.databind.node.ObjectNode;
63 import com.google.common.collect.ImmutableList; 71 import com.google.common.collect.ImmutableList;
64 72
73 +import static org.easymock.EasyMock.createMock;
74 +import static org.easymock.EasyMock.expect;
75 +import static org.easymock.EasyMock.replay;
65 import static org.hamcrest.MatcherAssert.assertThat; 76 import static org.hamcrest.MatcherAssert.assertThat;
77 +import static org.hamcrest.Matchers.hasSize;
78 +import static org.hamcrest.Matchers.instanceOf;
79 +import static org.hamcrest.Matchers.is;
66 import static org.hamcrest.Matchers.notNullValue; 80 import static org.hamcrest.Matchers.notNullValue;
67 import static org.onosproject.codec.impl.IntentJsonMatcher.matchesIntent; 81 import static org.onosproject.codec.impl.IntentJsonMatcher.matchesIntent;
68 import static org.onosproject.net.NetTestTools.did; 82 import static org.onosproject.net.NetTestTools.did;
69 import static org.onosproject.net.NetTestTools.hid; 83 import static org.onosproject.net.NetTestTools.hid;
84 +import static org.onosproject.net.flow.instructions.L2ModificationInstruction.ModEtherInstruction;
70 85
71 /** 86 /**
72 * Unit tests for the host to host intent class codec. 87 * Unit tests for the host to host intent class codec.
...@@ -81,11 +96,16 @@ public class IntentCodecTest extends AbstractIntentTest { ...@@ -81,11 +96,16 @@ public class IntentCodecTest extends AbstractIntentTest {
81 final TrafficTreatment emptyTreatment = 96 final TrafficTreatment emptyTreatment =
82 DefaultTrafficTreatment.emptyTreatment(); 97 DefaultTrafficTreatment.emptyTreatment();
83 private final MockCodecContext context = new MockCodecContext(); 98 private final MockCodecContext context = new MockCodecContext();
99 + final CoreService mockCoreService = createMock(CoreService.class);
84 100
85 @Before 101 @Before
86 public void setUpIntentService() { 102 public void setUpIntentService() {
87 final IntentService mockIntentService = new IntentServiceAdapter(); 103 final IntentService mockIntentService = new IntentServiceAdapter();
88 context.registerService(IntentService.class, mockIntentService); 104 context.registerService(IntentService.class, mockIntentService);
105 + context.registerService(CoreService.class, mockCoreService);
106 + expect(mockCoreService.getAppId((short) 2))
107 + .andReturn(new DefaultApplicationId(2, "app"));
108 + replay(mockCoreService);
89 } 109 }
90 110
91 /** 111 /**
...@@ -161,13 +181,13 @@ public class IntentCodecTest extends AbstractIntentTest { ...@@ -161,13 +181,13 @@ public class IntentCodecTest extends AbstractIntentTest {
161 181
162 final List<Constraint> constraints = 182 final List<Constraint> constraints =
163 ImmutableList.of( 183 ImmutableList.of(
164 - new BandwidthConstraint(new BandwidthResource(Bandwidth.bps(1.0))), 184 + new BandwidthConstraint(new BandwidthResource(Bandwidth.bps(1.0))),
165 - new LambdaConstraint(LambdaResource.valueOf(3)), 185 + new LambdaConstraint(LambdaResource.valueOf(3)),
166 - new AnnotationConstraint("key", 33.0), 186 + new AnnotationConstraint("key", 33.0),
167 - new AsymmetricPathConstraint(), 187 + new AsymmetricPathConstraint(),
168 - new LatencyConstraint(Duration.ofSeconds(2)), 188 + new LatencyConstraint(Duration.ofSeconds(2)),
169 - new ObstacleConstraint(did1, did2), 189 + new ObstacleConstraint(did1, did2),
170 - new WaypointConstraint(did3)); 190 + new WaypointConstraint(did3));
171 191
172 final PointToPointIntent intent = 192 final PointToPointIntent intent =
173 PointToPointIntent.builder() 193 PointToPointIntent.builder()
...@@ -188,4 +208,81 @@ public class IntentCodecTest extends AbstractIntentTest { ...@@ -188,4 +208,81 @@ public class IntentCodecTest extends AbstractIntentTest {
188 assertThat(intentJson, matchesIntent(intent)); 208 assertThat(intentJson, matchesIntent(intent));
189 209
190 } 210 }
211 +
212 + /**
213 + * Reads in a rule from the given resource and decodes it.
214 + *
215 + * @param resourceName resource to use to read the JSON for the rule
216 + * @return decoded flow rule
217 + * @throws IOException if processing the resource fails
218 + */
219 + private Intent getIntent(String resourceName, JsonCodec intentCodec) throws IOException {
220 + InputStream jsonStream = FlowRuleCodecTest.class
221 + .getResourceAsStream(resourceName);
222 + JsonNode json = context.mapper().readTree(jsonStream);
223 + assertThat(json, notNullValue());
224 + Intent intent = (Intent) intentCodec.decode((ObjectNode) json, context);
225 + assertThat(intent, notNullValue());
226 + return intent;
227 + }
228 +
229 + /**
230 + * Tests the point to point intent JSON codec.
231 + *
232 + * @throws IOException if JSON processing fails
233 + */
234 + @Test
235 + public void decodePointToPointIntent() throws IOException {
236 + JsonCodec<Intent> intentCodec = context.codec(Intent.class);
237 + assertThat(intentCodec, notNullValue());
238 +
239 + Intent intent = getIntent("PointToPointIntent.json", intentCodec);
240 + assertThat(intent, notNullValue());
241 + assertThat(intent, instanceOf(PointToPointIntent.class));
242 +
243 + PointToPointIntent pointIntent = (PointToPointIntent) intent;
244 + assertThat(pointIntent.priority(), is(55));
245 + assertThat(pointIntent.ingressPoint().deviceId(), is(did("0000000000000001")));
246 + assertThat(pointIntent.ingressPoint().port(), is(PortNumber.portNumber(1)));
247 + assertThat(pointIntent.egressPoint().deviceId(), is(did("0000000000000007")));
248 + assertThat(pointIntent.egressPoint().port(), is(PortNumber.portNumber(2)));
249 +
250 + assertThat(pointIntent.constraints(), hasSize(1));
251 +
252 + assertThat(pointIntent.selector(), notNullValue());
253 + assertThat(pointIntent.selector().criteria(), hasSize(1));
254 + Criterion criterion1 = pointIntent.selector().criteria().iterator().next();
255 + assertThat(criterion1, instanceOf(EthCriterion.class));
256 + EthCriterion ethCriterion = (EthCriterion) criterion1;
257 + assertThat(ethCriterion.mac().toString(), is("11:22:33:44:55:66"));
258 + assertThat(ethCriterion.type().name(), is("ETH_DST"));
259 +
260 + assertThat(pointIntent.treatment(), notNullValue());
261 + assertThat(pointIntent.treatment().allInstructions(), hasSize(1));
262 + Instruction instruction1 = pointIntent.treatment().allInstructions().iterator().next();
263 + assertThat(instruction1, instanceOf(ModEtherInstruction.class));
264 + ModEtherInstruction ethInstruction = (ModEtherInstruction) instruction1;
265 + assertThat(ethInstruction.mac().toString(), is("22:33:44:55:66:77"));
266 + assertThat(ethInstruction.type().toString(), is("L2MODIFICATION"));
267 + assertThat(ethInstruction.subtype().toString(), is("ETH_SRC"));
268 + }
269 +
270 + /**
271 + * Tests the host to host intent JSON codec.
272 + *
273 + * @throws IOException
274 + */
275 + @Test
276 + public void decodeHostToHostIntent() throws IOException {
277 + JsonCodec<Intent> intentCodec = context.codec(Intent.class);
278 + assertThat(intentCodec, notNullValue());
279 +
280 + Intent intent = getIntent("HostToHostIntent.json", intentCodec);
281 + assertThat(intent, notNullValue());
282 + assertThat(intent, instanceOf(HostToHostIntent.class));
283 +
284 + HostToHostIntent hostIntent = (HostToHostIntent) intent;
285 + assertThat(hostIntent.priority(), is(7));
286 + assertThat(hostIntent.constraints(), hasSize(1));
287 + }
191 } 288 }
......
1 +{
2 + "type":"AnnotationConstraint",
3 + "key":"key",
4 + "threshold":123.0
5 +}
1 +{
2 + "type":"BandwidthConstraint",
3 + "bandwidth":345.678
4 +}
1 +{
2 + "type": "HostToHostIntent",
3 + "appId": 2,
4 + "selector": {"criteria": []},
5 + "treatment": {
6 + "instructions": [],
7 + "deferred": []
8 + },
9 + "priority": 7,
10 + "constraints": [
11 + {
12 + "inclusive": false,
13 + "types": ["OPTICAL"],
14 + "type": "LinkTypeConstraint"
15 + }
16 + ],
17 + "one": "00:00:00:00:00:02/-1",
18 + "two": "00:00:00:00:00:05/-1"
19 +}
1 +{
2 + "type":"LatencyConstraint",
3 + "latencyMillis":111
4 +}
1 +{
2 + "inclusive":false,
3 + "types":["DIRECT","OPTICAL"],
4 + "type":"LinkTypeConstraint"
5 +}
1 +{
2 + "type":"ObstacleConstraint",
3 + "obstacles":["of:dev1","of:dev2","of:dev3"]
4 +}
1 +{
2 + "type": "PointToPointIntent",
3 + "appId": 2,
4 + "selector": {
5 + "criteria": [
6 + {
7 + "type": "ETH_DST",
8 + "mac": "11:22:33:44:55:66"
9 + }
10 + ]
11 + },
12 + "treatment": {
13 + "instructions": [
14 + {
15 + "type": "L2MODIFICATION",
16 + "subtype": "ETH_SRC",
17 + "mac": "22:33:44:55:66:77"
18 + }
19 + ],
20 + "deferred": []
21 + },
22 + "priority": 55,
23 + "constraints": [
24 + {
25 + "inclusive": false,
26 + "types": ["OPTICAL"],
27 + "type": "LinkTypeConstraint"
28 + }
29 + ],
30 + "ingressPoint": {
31 + "port": "1",
32 + "device": "of:0000000000000001"
33 + },
34 + "egressPoint": {
35 + "port": "2",
36 + "device": "of:0000000000000007"
37 + }
38 +}
1 +{
2 + "type":"WaypointConstraint",
3 + "waypoints":["of:devA","of:devB","of:devC"]
4 +}
...@@ -15,12 +15,18 @@ ...@@ -15,12 +15,18 @@
15 */ 15 */
16 package org.onosproject.rest.resources; 16 package org.onosproject.rest.resources;
17 17
18 +import java.io.IOException;
19 +import java.io.InputStream;
20 +import java.net.URI;
21 +import java.net.URISyntaxException;
18 import java.util.Objects; 22 import java.util.Objects;
19 import java.util.concurrent.CountDownLatch; 23 import java.util.concurrent.CountDownLatch;
20 import java.util.concurrent.TimeUnit; 24 import java.util.concurrent.TimeUnit;
21 25
26 +import javax.ws.rs.Consumes;
22 import javax.ws.rs.DELETE; 27 import javax.ws.rs.DELETE;
23 import javax.ws.rs.GET; 28 import javax.ws.rs.GET;
29 +import javax.ws.rs.POST;
24 import javax.ws.rs.Path; 30 import javax.ws.rs.Path;
25 import javax.ws.rs.PathParam; 31 import javax.ws.rs.PathParam;
26 import javax.ws.rs.Produces; 32 import javax.ws.rs.Produces;
...@@ -177,4 +183,31 @@ public class IntentsWebResource extends AbstractWebResource { ...@@ -177,4 +183,31 @@ public class IntentsWebResource extends AbstractWebResource {
177 } 183 }
178 } 184 }
179 185
186 + /**
187 + * Creates an intent from a POST of a JSON string and attempts to apply it.
188 + *
189 + * @param stream input JSON
190 + * @return status of the request - CREATED if the JSON is correct,
191 + * BAD_REQUEST if the JSON is invalid
192 + */
193 + @POST
194 + @Consumes(MediaType.APPLICATION_JSON)
195 + @Produces(MediaType.APPLICATION_JSON)
196 + public Response createIntent(InputStream stream) {
197 + URI location;
198 + try {
199 + IntentService service = get(IntentService.class);
200 + ObjectNode root = (ObjectNode) mapper().readTree(stream);
201 + Intent intent = codec(Intent.class).decode(root, this);
202 + service.submit(intent);
203 + location = new URI(Short.toString(intent.appId().id()) + "/"
204 + + Long.toString(intent.id().fingerprint()));
205 + } catch (IOException | URISyntaxException ex) {
206 + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
207 + }
208 + return Response
209 + .created(location)
210 + .build();
211 + }
212 +
180 } 213 }
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
15 */ 15 */
16 package org.onosproject.rest; 16 package org.onosproject.rest;
17 17
18 +import java.io.InputStream;
18 import java.net.HttpURLConnection; 19 import java.net.HttpURLConnection;
19 import java.util.HashMap; 20 import java.util.HashMap;
20 import java.util.HashSet; 21 import java.util.HashSet;
...@@ -107,10 +108,6 @@ public class FlowsResourceTest extends ResourceTest { ...@@ -107,10 +108,6 @@ public class FlowsResourceTest extends ResourceTest {
107 final MockFlowEntry flow5 = new MockFlowEntry(deviceId2, 5); 108 final MockFlowEntry flow5 = new MockFlowEntry(deviceId2, 5);
108 final MockFlowEntry flow6 = new MockFlowEntry(deviceId2, 6); 109 final MockFlowEntry flow6 = new MockFlowEntry(deviceId2, 6);
109 110
110 - private static final String FLOW_JSON = "{\"priority\":1,\"isPermanent\":true,"
111 - + "\"treatment\":{\"instructions\":[ {\"type\":\"OUTPUT\",\"port\":2}]},"
112 - + "\"selector\":{\"criteria\":[ {\"type\":\"ETH_TYPE\",\"ethType\":2054}]}}";
113 -
114 /** 111 /**
115 * Mock class for a flow entry. 112 * Mock class for a flow entry.
116 */ 113 */
...@@ -582,11 +579,12 @@ public class FlowsResourceTest extends ResourceTest { ...@@ -582,11 +579,12 @@ public class FlowsResourceTest extends ResourceTest {
582 replay(mockFlowService); 579 replay(mockFlowService);
583 580
584 WebResource rs = resource(); 581 WebResource rs = resource();
585 - 582 + InputStream jsonStream = IntentsResourceTest.class
583 + .getResourceAsStream("post-flow.json");
586 584
587 ClientResponse response = rs.path("flows/of:0000000000000001") 585 ClientResponse response = rs.path("flows/of:0000000000000001")
588 .type(MediaType.APPLICATION_JSON_TYPE) 586 .type(MediaType.APPLICATION_JSON_TYPE)
589 - .post(ClientResponse.class, FLOW_JSON); 587 + .post(ClientResponse.class, jsonStream);
590 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED)); 588 assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
591 String location = response.getLocation().getPath(); 589 String location = response.getLocation().getPath();
592 assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/")); 590 assertThat(location, Matchers.startsWith("/flows/of:0000000000000001/"));
......
...@@ -15,10 +15,15 @@ ...@@ -15,10 +15,15 @@
15 */ 15 */
16 package org.onosproject.rest; 16 package org.onosproject.rest;
17 17
18 +import java.io.InputStream;
19 +import java.net.HttpURLConnection;
18 import java.util.Collections; 20 import java.util.Collections;
19 import java.util.HashSet; 21 import java.util.HashSet;
20 22
23 +import javax.ws.rs.core.MediaType;
24 +
21 import org.hamcrest.Description; 25 import org.hamcrest.Description;
26 +import org.hamcrest.Matchers;
22 import org.hamcrest.TypeSafeMatcher; 27 import org.hamcrest.TypeSafeMatcher;
23 import org.junit.After; 28 import org.junit.After;
24 import org.junit.Before; 29 import org.junit.Before;
...@@ -42,12 +47,14 @@ import org.onosproject.net.intent.MockIdGenerator; ...@@ -42,12 +47,14 @@ import org.onosproject.net.intent.MockIdGenerator;
42 import com.eclipsesource.json.JsonArray; 47 import com.eclipsesource.json.JsonArray;
43 import com.eclipsesource.json.JsonObject; 48 import com.eclipsesource.json.JsonObject;
44 import com.eclipsesource.json.JsonValue; 49 import com.eclipsesource.json.JsonValue;
50 +import com.sun.jersey.api.client.ClientResponse;
45 import com.sun.jersey.api.client.UniformInterfaceException; 51 import com.sun.jersey.api.client.UniformInterfaceException;
46 import com.sun.jersey.api.client.WebResource; 52 import com.sun.jersey.api.client.WebResource;
47 53
48 import static org.easymock.EasyMock.anyObject; 54 import static org.easymock.EasyMock.anyObject;
49 import static org.easymock.EasyMock.createMock; 55 import static org.easymock.EasyMock.createMock;
50 import static org.easymock.EasyMock.expect; 56 import static org.easymock.EasyMock.expect;
57 +import static org.easymock.EasyMock.expectLastCall;
51 import static org.easymock.EasyMock.replay; 58 import static org.easymock.EasyMock.replay;
52 import static org.easymock.EasyMock.verify; 59 import static org.easymock.EasyMock.verify;
53 import static org.hamcrest.Matchers.containsString; 60 import static org.hamcrest.Matchers.containsString;
...@@ -358,4 +365,29 @@ public class IntentsResourceTest extends ResourceTest { ...@@ -358,4 +365,29 @@ public class IntentsResourceTest extends ResourceTest {
358 containsString("returned a response status of")); 365 containsString("returned a response status of"));
359 } 366 }
360 } 367 }
368 +
369 + /**
370 + * Tests creating an intent with POST.
371 + */
372 + @Test
373 + public void testPost() {
374 + expect(mockCoreService.getAppId((short) 2))
375 + .andReturn(new DefaultApplicationId(2, "app"));
376 + replay(mockCoreService);
377 +
378 + mockIntentService.submit(anyObject());
379 + expectLastCall();
380 + replay(mockIntentService);
381 +
382 + InputStream jsonStream = IntentsResourceTest.class
383 + .getResourceAsStream("post-intent.json");
384 + WebResource rs = resource();
385 +
386 + ClientResponse response = rs.path("intents")
387 + .type(MediaType.APPLICATION_JSON_TYPE)
388 + .post(ClientResponse.class, jsonStream);
389 + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_CREATED));
390 + String location = response.getLocation().getPath();
391 + assertThat(location, Matchers.startsWith("/intents/2/"));
392 + }
361 } 393 }
......
1 +{
2 + "priority": 1,
3 + "isPermanent": true,
4 + "treatment": {
5 + "instructions": [
6 + {
7 + "type": "OUTPUT",
8 + "port": 2
9 + }
10 + ]
11 + },
12 + "selector": {
13 + "criteria": [
14 + {
15 + "type": "ETH_TYPE",
16 + "ethType": 2054
17 + }
18 + ]
19 + }
20 +}
1 +{
2 + "type": "PointToPointIntent",
3 + "appId": 2,
4 + "selector": {
5 + "criteria": [
6 + {
7 + "type": "ETH_DST",
8 + "mac": "11:22:33:44:55:66"
9 + }
10 + ]
11 + },
12 + "treatment": {
13 + "instructions": [
14 + {
15 + "type": "L2MODIFICATION",
16 + "subtype": "ETH_SRC",
17 + "mac": "22:33:44:55:66:77"
18 + }
19 + ],
20 + "deferred": []
21 + },
22 + "priority": 55,
23 + "constraints": [
24 + {
25 + "inclusive": false,
26 + "types": ["OPTICAL"],
27 + "type": "LinkTypeConstraint"
28 + }
29 + ],
30 + "ingressPoint": {
31 + "port": "1",
32 + "device": "of:0000000000000001"
33 + },
34 + "egressPoint": {
35 + "port": "2",
36 + "device": "of:0000000000000007"
37 + }
38 +}