Jian Li
Committed by Thomas Vachuska

[ONOS-4530] Allow to specify appId when insert FlowRule through REST

- Augment FlowRuleCodec to encode FlowRule
- Add unit test for encode method of FlowRuleCodec
- Add getFlowByAppId and removeFlowByAppId methods in FlowsWebResource
- Add more unit tests for FlowWebResource
- Add FlowRules.json swagger doc
- Rename Flows.json to FlowEntries.json, correct FlowEntries.json

Change-Id: Ic3ec390c13a349e51ae4208adbc478564b6724ba
...@@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode; ...@@ -19,6 +19,7 @@ import com.fasterxml.jackson.databind.JsonNode;
19 import com.fasterxml.jackson.databind.node.ObjectNode; 19 import com.fasterxml.jackson.databind.node.ObjectNode;
20 import org.onosproject.codec.CodecContext; 20 import org.onosproject.codec.CodecContext;
21 import org.onosproject.codec.JsonCodec; 21 import org.onosproject.codec.JsonCodec;
22 +import org.onosproject.core.ApplicationId;
22 import org.onosproject.core.CoreService; 23 import org.onosproject.core.CoreService;
23 import org.onosproject.net.DeviceId; 24 import org.onosproject.net.DeviceId;
24 import org.onosproject.net.flow.DefaultFlowRule; 25 import org.onosproject.net.flow.DefaultFlowRule;
...@@ -26,6 +27,7 @@ import org.onosproject.net.flow.FlowRule; ...@@ -26,6 +27,7 @@ import org.onosproject.net.flow.FlowRule;
26 import org.onosproject.net.flow.TrafficSelector; 27 import org.onosproject.net.flow.TrafficSelector;
27 import org.onosproject.net.flow.TrafficTreatment; 28 import org.onosproject.net.flow.TrafficTreatment;
28 29
30 +import static com.google.common.base.Preconditions.checkNotNull;
29 import static org.onlab.util.Tools.nullIsIllegal; 31 import static org.onlab.util.Tools.nullIsIllegal;
30 32
31 /** 33 /**
...@@ -36,6 +38,7 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> { ...@@ -36,6 +38,7 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> {
36 private static final String PRIORITY = "priority"; 38 private static final String PRIORITY = "priority";
37 private static final String TIMEOUT = "timeout"; 39 private static final String TIMEOUT = "timeout";
38 private static final String IS_PERMANENT = "isPermanent"; 40 private static final String IS_PERMANENT = "isPermanent";
41 + private static final String APP_ID = "appId";
39 private static final String TABLE_ID = "tableId"; 42 private static final String TABLE_ID = "tableId";
40 private static final String DEVICE_ID = "deviceId"; 43 private static final String DEVICE_ID = "deviceId";
41 private static final String TREATMENT = "treatment"; 44 private static final String TREATMENT = "treatment";
...@@ -44,6 +47,37 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> { ...@@ -44,6 +47,37 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> {
44 " member is required in FlowRule"; 47 " member is required in FlowRule";
45 public static final String REST_APP_ID = "org.onosproject.rest"; 48 public static final String REST_APP_ID = "org.onosproject.rest";
46 49
50 + @Override
51 + public ObjectNode encode(FlowRule flowRule, CodecContext context) {
52 + checkNotNull(flowRule, "Flow rule cannot be null");
53 +
54 + CoreService service = context.getService(CoreService.class);
55 + ApplicationId appId = service.getAppId(flowRule.appId());
56 + String strAppId = (appId == null) ? "<none>" : appId.name();
57 +
58 + final ObjectNode result = context.mapper().createObjectNode()
59 + .put("id", Long.toString(flowRule.id().value()))
60 + .put("tableId", flowRule.tableId())
61 + .put("appId", strAppId)
62 + .put("priority", flowRule.priority())
63 + .put("timeout", flowRule.timeout())
64 + .put("isPermanent", flowRule.isPermanent())
65 + .put("deviceId", flowRule.deviceId().toString());
66 +
67 + if (flowRule.treatment() != null) {
68 + final JsonCodec<TrafficTreatment> treatmentCodec =
69 + context.codec(TrafficTreatment.class);
70 + result.set("treatment", treatmentCodec.encode(flowRule.treatment(), context));
71 + }
72 +
73 + if (flowRule.selector() != null) {
74 + final JsonCodec<TrafficSelector> selectorCodec =
75 + context.codec(TrafficSelector.class);
76 + result.set("selector", selectorCodec.encode(flowRule.selector(), context));
77 + }
78 +
79 + return result;
80 + }
47 81
48 @Override 82 @Override
49 public FlowRule decode(ObjectNode json, CodecContext context) { 83 public FlowRule decode(ObjectNode json, CodecContext context) {
...@@ -54,8 +88,9 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> { ...@@ -54,8 +88,9 @@ public final class FlowRuleCodec extends JsonCodec<FlowRule> {
54 FlowRule.Builder resultBuilder = new DefaultFlowRule.Builder(); 88 FlowRule.Builder resultBuilder = new DefaultFlowRule.Builder();
55 89
56 CoreService coreService = context.getService(CoreService.class); 90 CoreService coreService = context.getService(CoreService.class);
57 - resultBuilder.fromApp(coreService 91 + JsonNode appIdJson = json.get(APP_ID);
58 - .registerApplication(REST_APP_ID)); 92 + String appId = appIdJson != null ? appIdJson.asText() : REST_APP_ID;
93 + resultBuilder.fromApp(coreService.registerApplication(appId));
59 94
60 int priority = nullIsIllegal(json.get(PRIORITY), 95 int priority = nullIsIllegal(json.get(PRIORITY),
61 PRIORITY + MISSING_MEMBER_MESSAGE).asInt(); 96 PRIORITY + MISSING_MEMBER_MESSAGE).asInt();
......
...@@ -17,6 +17,8 @@ package org.onosproject.codec.impl; ...@@ -17,6 +17,8 @@ package org.onosproject.codec.impl;
17 17
18 import com.fasterxml.jackson.databind.JsonNode; 18 import com.fasterxml.jackson.databind.JsonNode;
19 import com.fasterxml.jackson.databind.node.ObjectNode; 19 import com.fasterxml.jackson.databind.node.ObjectNode;
20 +import org.hamcrest.Description;
21 +import org.hamcrest.TypeSafeDiagnosingMatcher;
20 import org.junit.Before; 22 import org.junit.Before;
21 import org.junit.Test; 23 import org.junit.Test;
22 import org.onlab.packet.EthType; 24 import org.onlab.packet.EthType;
...@@ -29,12 +31,14 @@ import org.onlab.packet.VlanId; ...@@ -29,12 +31,14 @@ import org.onlab.packet.VlanId;
29 import org.onosproject.codec.JsonCodec; 31 import org.onosproject.codec.JsonCodec;
30 import org.onosproject.core.CoreService; 32 import org.onosproject.core.CoreService;
31 import org.onosproject.net.ChannelSpacing; 33 import org.onosproject.net.ChannelSpacing;
34 +import org.onosproject.net.DeviceId;
32 import org.onosproject.net.GridType; 35 import org.onosproject.net.GridType;
33 import org.onosproject.net.Lambda; 36 import org.onosproject.net.Lambda;
34 import org.onosproject.net.OchSignal; 37 import org.onosproject.net.OchSignal;
35 import org.onosproject.net.OchSignalType; 38 import org.onosproject.net.OchSignalType;
36 import org.onosproject.net.OduSignalType; 39 import org.onosproject.net.OduSignalType;
37 import org.onosproject.net.PortNumber; 40 import org.onosproject.net.PortNumber;
41 +import org.onosproject.net.flow.DefaultFlowRule;
38 import org.onosproject.net.flow.FlowRule; 42 import org.onosproject.net.flow.FlowRule;
39 import org.onosproject.net.flow.criteria.Criterion; 43 import org.onosproject.net.flow.criteria.Criterion;
40 import org.onosproject.net.flow.criteria.EthCriterion; 44 import org.onosproject.net.flow.criteria.EthCriterion;
...@@ -75,6 +79,7 @@ import java.io.InputStream; ...@@ -75,6 +79,7 @@ import java.io.InputStream;
75 import java.util.SortedMap; 79 import java.util.SortedMap;
76 import java.util.TreeMap; 80 import java.util.TreeMap;
77 81
82 +import static org.easymock.EasyMock.anyShort;
78 import static org.easymock.EasyMock.createMock; 83 import static org.easymock.EasyMock.createMock;
79 import static org.easymock.EasyMock.expect; 84 import static org.easymock.EasyMock.expect;
80 import static org.easymock.EasyMock.replay; 85 import static org.easymock.EasyMock.replay;
...@@ -105,6 +110,7 @@ public class FlowRuleCodecTest { ...@@ -105,6 +110,7 @@ public class FlowRuleCodecTest {
105 110
106 expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID)) 111 expect(mockCoreService.registerApplication(FlowRuleCodec.REST_APP_ID))
107 .andReturn(APP_ID).anyTimes(); 112 .andReturn(APP_ID).anyTimes();
113 + expect(mockCoreService.getAppId(anyShort())).andReturn(APP_ID).anyTimes();
108 replay(mockCoreService); 114 replay(mockCoreService);
109 context.registerService(CoreService.class, mockCoreService); 115 context.registerService(CoreService.class, mockCoreService);
110 } 116 }
...@@ -166,6 +172,118 @@ public class FlowRuleCodecTest { ...@@ -166,6 +172,118 @@ public class FlowRuleCodecTest {
166 SortedMap<String, Instruction> instructions = new TreeMap<>(); 172 SortedMap<String, Instruction> instructions = new TreeMap<>();
167 173
168 /** 174 /**
175 + * Checks that a simple rule encodes properly.
176 + */
177 + @Test
178 + public void testFlowRuleEncode() {
179 +
180 + DeviceId deviceId = DeviceId.deviceId("of:000000000000000a");
181 + FlowRule permFlowRule = DefaultFlowRule.builder()
182 + .withCookie(1)
183 + .forTable(1)
184 + .withPriority(1)
185 + .makePermanent()
186 + .forDevice(deviceId).build();
187 +
188 + FlowRule tempFlowRule = DefaultFlowRule.builder()
189 + .withCookie(1)
190 + .forTable(1)
191 + .withPriority(1)
192 + .makeTemporary(1000)
193 + .forDevice(deviceId).build();
194 +
195 + ObjectNode permFlowRuleJson = flowRuleCodec.encode(permFlowRule, context);
196 + ObjectNode tempFlowRuleJson = flowRuleCodec.encode(tempFlowRule, context);
197 +
198 + assertThat(permFlowRuleJson, FlowRuleJsonMatcher.matchesFlowRule(permFlowRule));
199 + assertThat(tempFlowRuleJson, FlowRuleJsonMatcher.matchesFlowRule(tempFlowRule));
200 + }
201 +
202 + private static final class FlowRuleJsonMatcher extends TypeSafeDiagnosingMatcher<JsonNode> {
203 +
204 + private final FlowRule flowRule;
205 +
206 + private FlowRuleJsonMatcher(FlowRule flowRule) {
207 + this.flowRule = flowRule;
208 + }
209 +
210 + @Override
211 + protected boolean matchesSafely(JsonNode jsonNode, Description description) {
212 +
213 + // check id
214 + long jsonId = jsonNode.get("id").asLong();
215 + long id = flowRule.id().id();
216 + if (jsonId != id) {
217 + description.appendText("flow rule id was " + jsonId);
218 + return false;
219 + }
220 +
221 + // TODO: need to check application ID
222 +
223 + // check tableId
224 + int jsonTableId = jsonNode.get("tableId").asInt();
225 + int tableId = flowRule.tableId();
226 + if (jsonTableId != tableId) {
227 + description.appendText("table id was " + jsonId);
228 + return false;
229 + }
230 +
231 + // check priority
232 + int jsonPriority = jsonNode.get("priority").asInt();
233 + int priority = flowRule.priority();
234 + if (jsonPriority != priority) {
235 + description.appendText("priority was " + jsonPriority);
236 + return false;
237 + }
238 +
239 + // check timeout
240 + int jsonTimeout = jsonNode.get("timeout").asInt();
241 + int timeout = flowRule.timeout();
242 + if (jsonTimeout != timeout) {
243 + description.appendText("timeout was " + jsonTimeout);
244 + return false;
245 + }
246 +
247 + // check isPermanent
248 + boolean jsonIsPermanent = jsonNode.get("isPermanent").asBoolean();
249 + boolean isPermanent = flowRule.isPermanent();
250 + if (jsonIsPermanent != isPermanent) {
251 + description.appendText("isPermanent was " + jsonIsPermanent);
252 + return false;
253 + }
254 +
255 + // check deviceId
256 + String jsonDeviceId = jsonNode.get("deviceId").asText();
257 + String deviceId = flowRule.deviceId().toString();
258 + if (!jsonDeviceId.equals(deviceId)) {
259 + description.appendText("deviceId was " + jsonDeviceId);
260 + return false;
261 + }
262 +
263 + // TODO: need to check traffic treatment
264 +
265 + // TODO: need to check selector
266 +
267 + return true;
268 + }
269 +
270 + @Override
271 + public void describeTo(Description description) {
272 + description.appendText(flowRule.toString());
273 + }
274 +
275 + /**
276 + * Factory to allocate a flow rule matcher.
277 + *
278 + * @param flowRule flow rule object we are looking for
279 + * @return matcher
280 + */
281 + public static FlowRuleJsonMatcher matchesFlowRule(FlowRule flowRule) {
282 + return new FlowRuleJsonMatcher(flowRule);
283 + }
284 + }
285 +
286 + /**
169 * Looks up an instruction in the instruction map based on type and subtype. 287 * Looks up an instruction in the instruction map based on type and subtype.
170 * 288 *
171 * @param type type string 289 * @param type type string
......
...@@ -21,6 +21,8 @@ import com.fasterxml.jackson.databind.node.ObjectNode; ...@@ -21,6 +21,8 @@ import com.fasterxml.jackson.databind.node.ObjectNode;
21 import com.google.common.collect.ArrayListMultimap; 21 import com.google.common.collect.ArrayListMultimap;
22 import com.google.common.collect.ListMultimap; 22 import com.google.common.collect.ListMultimap;
23 import org.onlab.util.ItemNotFoundException; 23 import org.onlab.util.ItemNotFoundException;
24 +import org.onosproject.app.ApplicationService;
25 +import org.onosproject.core.ApplicationId;
24 import org.onosproject.net.Device; 26 import org.onosproject.net.Device;
25 import org.onosproject.net.DeviceId; 27 import org.onosproject.net.DeviceId;
26 import org.onosproject.net.device.DeviceService; 28 import org.onosproject.net.device.DeviceService;
...@@ -36,6 +38,7 @@ import javax.ws.rs.POST; ...@@ -36,6 +38,7 @@ import javax.ws.rs.POST;
36 import javax.ws.rs.Path; 38 import javax.ws.rs.Path;
37 import javax.ws.rs.PathParam; 39 import javax.ws.rs.PathParam;
38 import javax.ws.rs.Produces; 40 import javax.ws.rs.Produces;
41 +import javax.ws.rs.QueryParam;
39 import javax.ws.rs.core.Context; 42 import javax.ws.rs.core.Context;
40 import javax.ws.rs.core.MediaType; 43 import javax.ws.rs.core.MediaType;
41 import javax.ws.rs.core.Response; 44 import javax.ws.rs.core.Response;
...@@ -61,6 +64,7 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -61,6 +64,7 @@ public class FlowsWebResource extends AbstractWebResource {
61 64
62 private static final String DEVICE_NOT_FOUND = "Device is not found"; 65 private static final String DEVICE_NOT_FOUND = "Device is not found";
63 private static final String FLOW_NOT_FOUND = "Flow is not found"; 66 private static final String FLOW_NOT_FOUND = "Flow is not found";
67 + private static final String APP_ID_NOT_FOUND = "Application Id is not found";
64 private static final String FLOWS = "flows"; 68 private static final String FLOWS = "flows";
65 private static final String DEVICE_ID = "deviceId"; 69 private static final String DEVICE_ID = "deviceId";
66 private static final String FLOW_ID = "flowId"; 70 private static final String FLOW_ID = "flowId";
...@@ -73,7 +77,7 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -73,7 +77,7 @@ public class FlowsWebResource extends AbstractWebResource {
73 * Gets all flow entries. Returns array of all flow rules in the system. 77 * Gets all flow entries. Returns array of all flow rules in the system.
74 * 78 *
75 * @return 200 OK with a collection of flows 79 * @return 200 OK with a collection of flows
76 - * @onos.rsModel Flows 80 + * @onos.rsModel FlowEntries
77 */ 81 */
78 @GET 82 @GET
79 @Produces(MediaType.APPLICATION_JSON) 83 @Produces(MediaType.APPLICATION_JSON)
...@@ -107,10 +111,15 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -107,10 +111,15 @@ public class FlowsWebResource extends AbstractWebResource {
107 @POST 111 @POST
108 @Consumes(MediaType.APPLICATION_JSON) 112 @Consumes(MediaType.APPLICATION_JSON)
109 @Produces(MediaType.APPLICATION_JSON) 113 @Produces(MediaType.APPLICATION_JSON)
110 - public Response createFlows(InputStream stream) { 114 + public Response createFlows(@QueryParam("appId") String appId, InputStream stream) {
111 try { 115 try {
112 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); 116 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
113 ArrayNode flowsArray = (ArrayNode) jsonTree.get(FLOWS); 117 ArrayNode flowsArray = (ArrayNode) jsonTree.get(FLOWS);
118 +
119 + if (appId != null) {
120 + flowsArray.forEach(flowJson -> ((ObjectNode) flowJson).put("appId", appId));
121 + }
122 +
114 List<FlowRule> rules = codec(FlowRule.class).decode(flowsArray, this); 123 List<FlowRule> rules = codec(FlowRule.class).decode(flowsArray, this);
115 service.applyFlowRules(rules.toArray(new FlowRule[rules.size()])); 124 service.applyFlowRules(rules.toArray(new FlowRule[rules.size()]));
116 rules.forEach(flowRule -> { 125 rules.forEach(flowRule -> {
...@@ -131,10 +140,11 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -131,10 +140,11 @@ public class FlowsWebResource extends AbstractWebResource {
131 * 140 *
132 * @param deviceId device identifier 141 * @param deviceId device identifier
133 * @return 200 OK with a collection of flows of given device 142 * @return 200 OK with a collection of flows of given device
134 - * @onos.rsModel Flows 143 + * @onos.rsModel FlowEntries
135 */ 144 */
136 @GET 145 @GET
137 @Produces(MediaType.APPLICATION_JSON) 146 @Produces(MediaType.APPLICATION_JSON)
147 + // TODO: we need to add "/device" suffix to the path to differentiate with appId
138 @Path("{deviceId}") 148 @Path("{deviceId}")
139 public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) { 149 public Response getFlowByDeviceId(@PathParam("deviceId") String deviceId) {
140 final Iterable<FlowEntry> flowEntries = 150 final Iterable<FlowEntry> flowEntries =
...@@ -150,13 +160,13 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -150,13 +160,13 @@ public class FlowsWebResource extends AbstractWebResource {
150 } 160 }
151 161
152 /** 162 /**
153 - * Gets flow rule. Returns the flow entry specified by the device id and 163 + * Gets flow rules. Returns the flow entry specified by the device id and
154 * flow rule id. 164 * flow rule id.
155 * 165 *
156 * @param deviceId device identifier 166 * @param deviceId device identifier
157 * @param flowId flow rule identifier 167 * @param flowId flow rule identifier
158 - * @return 200 OK with a flows of given device and flow 168 + * @return 200 OK with a collection of flows of given device and flow
159 - * @onos.rsModel Flows 169 + * @onos.rsModel FlowEntries
160 */ 170 */
161 @GET 171 @GET
162 @Produces(MediaType.APPLICATION_JSON) 172 @Produces(MediaType.APPLICATION_JSON)
...@@ -178,6 +188,43 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -178,6 +188,43 @@ public class FlowsWebResource extends AbstractWebResource {
178 } 188 }
179 189
180 /** 190 /**
191 + * Gets flow rules generated by an application.
192 + * Returns the flow rule specified by the application id.
193 + *
194 + * @param appId application identifier
195 + * @return 200 OK with a collection of flows of given application id
196 + * @onos.rsModel FlowRules
197 + */
198 + @GET
199 + @Produces(MediaType.APPLICATION_JSON)
200 + @Path("application/{appId}")
201 + public Response getFlowByAppId(@PathParam("appId") String appId) {
202 + final ApplicationService appService = get(ApplicationService.class);
203 + final ApplicationId idInstant = nullIsNotFound(appService.getId(appId), APP_ID_NOT_FOUND);
204 + final Iterable<FlowRule> flowRules = service.getFlowRulesById(idInstant);
205 +
206 + flowRules.forEach(flow -> flowsNode.add(codec(FlowRule.class).encode(flow, this)));
207 + return ok(root).build();
208 + }
209 +
210 + /**
211 + * Removes flow rules by application ID.
212 + * Removes a collection of flow rules generated by the given application.
213 + *
214 + * @param appId application identifier
215 + * @return 204 NO CONTENT
216 + */
217 + @DELETE
218 + @Produces(MediaType.APPLICATION_JSON)
219 + @Path("application/{appId}")
220 + public Response removeFlowByAppId(@PathParam("appId") String appId) {
221 + final ApplicationService appService = get(ApplicationService.class);
222 + final ApplicationId idInstant = nullIsNotFound(appService.getId(appId), APP_ID_NOT_FOUND);
223 + service.removeFlowRulesById(idInstant);
224 + return Response.noContent().build();
225 + }
226 +
227 + /**
181 * Creates new flow rule. Creates and installs a new flow rule for the 228 * Creates new flow rule. Creates and installs a new flow rule for the
182 * specified device. <br> 229 * specified device. <br>
183 * Instructions description: 230 * Instructions description:
...@@ -187,6 +234,7 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -187,6 +234,7 @@ public class FlowsWebResource extends AbstractWebResource {
187 * https://wiki.onosproject.org/display/ONOS/Flow+Rule+Criteria 234 * https://wiki.onosproject.org/display/ONOS/Flow+Rule+Criteria
188 * 235 *
189 * @param deviceId device identifier 236 * @param deviceId device identifier
237 + * @param appId application identifier
190 * @param stream flow rule JSON 238 * @param stream flow rule JSON
191 * @return status of the request - CREATED if the JSON is correct, 239 * @return status of the request - CREATED if the JSON is correct,
192 * BAD_REQUEST if the JSON is invalid 240 * BAD_REQUEST if the JSON is invalid
...@@ -197,6 +245,7 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -197,6 +245,7 @@ public class FlowsWebResource extends AbstractWebResource {
197 @Consumes(MediaType.APPLICATION_JSON) 245 @Consumes(MediaType.APPLICATION_JSON)
198 @Produces(MediaType.APPLICATION_JSON) 246 @Produces(MediaType.APPLICATION_JSON)
199 public Response createFlow(@PathParam("deviceId") String deviceId, 247 public Response createFlow(@PathParam("deviceId") String deviceId,
248 + @QueryParam("appId") String appId,
200 InputStream stream) { 249 InputStream stream) {
201 try { 250 try {
202 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream); 251 ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
...@@ -207,6 +256,11 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -207,6 +256,11 @@ public class FlowsWebResource extends AbstractWebResource {
207 "Invalid deviceId in flow creation request"); 256 "Invalid deviceId in flow creation request");
208 } 257 }
209 jsonTree.put("deviceId", deviceId); 258 jsonTree.put("deviceId", deviceId);
259 +
260 + if (appId != null) {
261 + jsonTree.put("appId", appId);
262 + }
263 +
210 FlowRule rule = codec(FlowRule.class).decode(jsonTree, this); 264 FlowRule rule = codec(FlowRule.class).decode(jsonTree, this);
211 service.applyFlowRules(rule); 265 service.applyFlowRules(rule);
212 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder() 266 UriBuilder locationBuilder = uriInfo.getBaseUriBuilder()
...@@ -223,7 +277,7 @@ public class FlowsWebResource extends AbstractWebResource { ...@@ -223,7 +277,7 @@ public class FlowsWebResource extends AbstractWebResource {
223 } 277 }
224 278
225 /** 279 /**
226 - * Remove flow rule. Removes the specified flow rule. 280 + * Removes flow rule. Removes the specified flow rule.
227 * 281 *
228 * @param deviceId device identifier 282 * @param deviceId device identifier
229 * @param flowId flow rule identifier 283 * @param flowId flow rule identifier
......
...@@ -135,9 +135,6 @@ ...@@ -135,9 +135,6 @@
135 } 135 }
136 } 136 }
137 } 137 }
138 - }
139 - }
140 - }
141 }, 138 },
142 "selector": { 139 "selector": {
143 "type": "object", 140 "type": "object",
...@@ -158,14 +155,14 @@ ...@@ -158,14 +155,14 @@
158 "properties": { 155 "properties": {
159 "type": { 156 "type": {
160 "type": "string", 157 "type": "string",
161 - "description":"Ethernet field name", 158 + "description": "Ethernet field name",
162 "example": "ETH_TYPE" 159 "example": "ETH_TYPE"
163 }, 160 },
164 "ethType": { 161 "ethType": {
165 "type": "int64", 162 "type": "int64",
166 "format": "int64", 163 "format": "int64",
167 "example": "0x88cc", 164 "example": "0x88cc",
168 - "description":"Ethernet frame type" 165 + "description": "Ethernet frame type"
169 }, 166 },
170 "mac": { 167 "mac": {
171 "type": "string", 168 "type": "string",
...@@ -175,13 +172,13 @@ ...@@ -175,13 +172,13 @@
175 "type": "int64", 172 "type": "int64",
176 "format": "int64", 173 "format": "int64",
177 "example": 1, 174 "example": 1,
178 - "description":"Match port" 175 + "description": "Match port"
179 }, 176 },
180 "metadata": { 177 "metadata": {
181 "type": "Hex16", 178 "type": "Hex16",
182 "format": "Hex16", 179 "format": "Hex16",
183 "example": "0xabcdL", 180 "example": "0xabcdL",
184 - "description":"Metadata passed between tables" 181 + "description": "Metadata passed between tables"
185 }, 182 },
186 "vlanId": { 183 "vlanId": {
187 "type": "uint16", 184 "type": "uint16",
...@@ -192,116 +189,116 @@ ...@@ -192,116 +189,116 @@
192 "type": "int64", 189 "type": "int64",
193 "format": "int64", 190 "format": "int64",
194 "example": 1, 191 "example": 1,
195 - "description":"VLAN priority." 192 + "description": "VLAN priority."
196 }, 193 },
197 "ipDscp": { 194 "ipDscp": {
198 "type": "byte", 195 "type": "byte",
199 "format": "byte", 196 "format": "byte",
200 - "description":"IP DSCP (6 bits in ToS field)" 197 + "description": "IP DSCP (6 bits in ToS field)"
201 }, 198 },
202 "ipEcn": { 199 "ipEcn": {
203 "type": "byte", 200 "type": "byte",
204 "format": "byte", 201 "format": "byte",
205 - "description":"IP ECN (2 bits in ToS field)." 202 + "description": "IP ECN (2 bits in ToS field)."
206 }, 203 },
207 "protocol": { 204 "protocol": {
208 "type": "uint16", 205 "type": "uint16",
209 "format": "uint16", 206 "format": "uint16",
210 "example": 1, 207 "example": 1,
211 - "description":"IP protocol" 208 + "description": "IP protocol"
212 }, 209 },
213 "ip": { 210 "ip": {
214 "type": "string", 211 "type": "string",
215 "example": "10.1.1.0/24", 212 "example": "10.1.1.0/24",
216 - "description":"IP source address" 213 + "description": "IP source address"
217 }, 214 },
218 "tcpPort": { 215 "tcpPort": {
219 "type": "integer", 216 "type": "integer",
220 "format": "uint16", 217 "format": "uint16",
221 "example": 1, 218 "example": 1,
222 - "description":"TCP source address" 219 + "description": "TCP source address"
223 }, 220 },
224 "udpPort": { 221 "udpPort": {
225 "type": "uint16", 222 "type": "uint16",
226 "format": "uint16", 223 "format": "uint16",
227 "example": 1, 224 "example": 1,
228 - "description":"UDP source address" 225 + "description": "UDP source address"
229 }, 226 },
230 "sctpPort": { 227 "sctpPort": {
231 "type": "uint16", 228 "type": "uint16",
232 "format": "uint16", 229 "format": "uint16",
233 "example": 1, 230 "example": 1,
234 - "description":"SCTP source address" 231 + "description": "SCTP source address"
235 }, 232 },
236 "icmpType": { 233 "icmpType": {
237 "type": "uint16", 234 "type": "uint16",
238 "format": "uint16", 235 "format": "uint16",
239 "example": 1, 236 "example": 1,
240 - "description":"Internet Control Message Protocol for IPV4 code (RFC0792)" 237 + "description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
241 }, 238 },
242 "icmpCode": { 239 "icmpCode": {
243 "type": "uint16", 240 "type": "uint16",
244 "format": "uint16", 241 "format": "uint16",
245 "example": 1, 242 "example": 1,
246 - "description":"Internet Control Message Protocol for IPV4 code (RFC0792)" 243 + "description": "Internet Control Message Protocol for IPV4 code (RFC0792)"
247 }, 244 },
248 "flowLabel": { 245 "flowLabel": {
249 "type": "Hex16", 246 "type": "Hex16",
250 "format": "Hex16", 247 "format": "Hex16",
251 "example": "0xffffe", 248 "example": "0xffffe",
252 - "description":"IPv6 Flow Label (RFC 6437)" 249 + "description": "IPv6 Flow Label (RFC 6437)"
253 }, 250 },
254 "icmpv6Type": { 251 "icmpv6Type": {
255 "type": "uint16", 252 "type": "uint16",
256 "format": "uint16", 253 "format": "uint16",
257 "example": 1, 254 "example": 1,
258 - "description":"Internet Control Message Protocol for IPV6 type (RFC2463)" 255 + "description": "Internet Control Message Protocol for IPV6 type (RFC2463)"
259 }, 256 },
260 "icmpv6Code": { 257 "icmpv6Code": {
261 "type": "uint16", 258 "type": "uint16",
262 "format": "uint16", 259 "format": "uint16",
263 "example": 1, 260 "example": 1,
264 - "description":"Internet Control Message Protocol for IPV6 code (RFC2463)" 261 + "description": "Internet Control Message Protocol for IPV6 code (RFC2463)"
265 }, 262 },
266 "targetAddress": { 263 "targetAddress": {
267 "type": "String", 264 "type": "String",
268 "example": "10.1.1.0/24", 265 "example": "10.1.1.0/24",
269 - "description":"IPv6 Neighbor discovery target address" 266 + "description": "IPv6 Neighbor discovery target address"
270 }, 267 },
271 "label": { 268 "label": {
272 "type": "int32", 269 "type": "int32",
273 "format": "int32", 270 "format": "int32",
274 "example": 1, 271 "example": 1,
275 - "description":"MPLS label" 272 + "description": "MPLS label"
276 }, 273 },
277 "exthdrFlags": { 274 "exthdrFlags": {
278 "type": "int64", 275 "type": "int64",
279 "format": "int64", 276 "format": "int64",
280 "example": 1, 277 "example": 1,
281 - "description":"IPv6 extension header pseudo-field" 278 + "description": "IPv6 extension header pseudo-field"
282 }, 279 },
283 "lambda": { 280 "lambda": {
284 "type": "int64", 281 "type": "int64",
285 "format": "int64", 282 "format": "int64",
286 "example": 1, 283 "example": 1,
287 - "description":"wavelength abstraction" 284 + "description": "wavelength abstraction"
288 }, 285 },
289 "gridType": { 286 "gridType": {
290 "type": "String", 287 "type": "String",
291 "example": "DWDM", 288 "example": "DWDM",
292 - "description":"Type of wavelength grid" 289 + "description": "Type of wavelength grid"
293 }, 290 },
294 "channelSpacing": { 291 "channelSpacing": {
295 "type": "int64", 292 "type": "int64",
296 "format": "int64", 293 "format": "int64",
297 "example": 100, 294 "example": 100,
298 - "description":"Optical channel spacing" 295 + "description": "Optical channel spacing"
299 }, 296 },
300 "spacingMultiplier": { 297 "spacingMultiplier": {
301 "type": "integer", 298 "type": "integer",
302 "format": "int64", 299 "format": "int64",
303 "example": 4, 300 "example": 4,
304 - "description":"Optical channel spacing multiplier" 301 + "description": "Optical channel spacing multiplier"
305 }, 302 },
306 "slotGranularity": { 303 "slotGranularity": {
307 "type": "int64", 304 "type": "int64",
...@@ -312,42 +309,42 @@ ...@@ -312,42 +309,42 @@
312 "type": "integer", 309 "type": "integer",
313 "format": "int64", 310 "format": "int64",
314 "example": 1, 311 "example": 1,
315 - "description":"Optical channel signal ID" 312 + "description": "Optical channel signal ID"
316 }, 313 },
317 "tunnelId": { 314 "tunnelId": {
318 "type": "int64", 315 "type": "int64",
319 "format": "int64", 316 "format": "int64",
320 "example": 5, 317 "example": 5,
321 - "description":"Tunnel ID" 318 + "description": "Tunnel ID"
322 }, 319 },
323 "ochSignalType": { 320 "ochSignalType": {
324 "type": "int64", 321 "type": "int64",
325 "format": "int64", 322 "format": "int64",
326 "example": 1, 323 "example": 1,
327 - "description":"Optical channel signal type" 324 + "description": "Optical channel signal type"
328 }, 325 },
329 "oduSignalId": { 326 "oduSignalId": {
330 "type": "int64", 327 "type": "int64",
331 "format": "int64", 328 "format": "int64",
332 "example": 1, 329 "example": 1,
333 - "description":"ODU (Optical channel Data Unit) signal ID." 330 + "description": "ODU (Optical channel Data Unit) signal ID."
334 }, 331 },
335 "tributaryPortNumber": { 332 "tributaryPortNumber": {
336 "type": "int64", 333 "type": "int64",
337 "format": "int64", 334 "format": "int64",
338 "example": 11, 335 "example": 11,
339 - "description":"OPU (Optical channel Payload Unit) port number." 336 + "description": "OPU (Optical channel Payload Unit) port number."
340 }, 337 },
341 "tributarySlotLen": { 338 "tributarySlotLen": {
342 "type": "int64", 339 "type": "int64",
343 "format": "int64", 340 "format": "int64",
344 "example": 80, 341 "example": 80,
345 - "description":"OPU (Optical channel Payload Unit) slot length." 342 + "description": "OPU (Optical channel Payload Unit) slot length."
346 }, 343 },
347 "tributarySlotBitmap": { 344 "tributarySlotBitmap": {
348 "type": "array", 345 "type": "array",
349 "title": "tributarySlotBitmap", 346 "title": "tributarySlotBitmap",
350 - "description":"OPU (Optical channel Payload Unit) slot bitmap.", 347 + "description": "OPU (Optical channel Payload Unit) slot bitmap.",
351 "required": [ 348 "required": [
352 "byte", 349 "byte",
353 "port" 350 "port"
...@@ -362,7 +359,10 @@ ...@@ -362,7 +359,10 @@
362 "type": "int64", 359 "type": "int64",
363 "format": "int64", 360 "format": "int64",
364 "example": 4, 361 "example": 4,
365 - "description":"ODU (Optical channel Data Unit) signal type." 362 + "description": "ODU (Optical channel Data Unit) signal type."
363 + }
364 + }
365 + }
366 } 366 }
367 } 367 }
368 } 368 }
......
This diff is collapsed. Click to expand it.