Committed by
Gerrit Code Review
REST API to create flows
Change-Id: I5d001782249c0eab249d7aa857ae465da95b5955
Showing
22 changed files
with
815 additions
and
164 deletions
... | @@ -35,6 +35,7 @@ import org.onosproject.net.Path; | ... | @@ -35,6 +35,7 @@ import org.onosproject.net.Path; |
35 | import org.onosproject.net.Port; | 35 | import org.onosproject.net.Port; |
36 | import org.onosproject.net.driver.Driver; | 36 | import org.onosproject.net.driver.Driver; |
37 | import org.onosproject.net.flow.FlowEntry; | 37 | import org.onosproject.net.flow.FlowEntry; |
38 | +import org.onosproject.net.flow.FlowRule; | ||
38 | import org.onosproject.net.flow.TrafficSelector; | 39 | import org.onosproject.net.flow.TrafficSelector; |
39 | import org.onosproject.net.flow.TrafficTreatment; | 40 | import org.onosproject.net.flow.TrafficTreatment; |
40 | import org.onosproject.net.flow.criteria.Criterion; | 41 | import org.onosproject.net.flow.criteria.Criterion; |
... | @@ -83,6 +84,7 @@ public class CodecManager implements CodecService { | ... | @@ -83,6 +84,7 @@ public class CodecManager implements CodecService { |
83 | registerCodec(Intent.class, new IntentCodec()); | 84 | registerCodec(Intent.class, new IntentCodec()); |
84 | registerCodec(ConnectivityIntent.class, new ConnectivityIntentCodec()); | 85 | registerCodec(ConnectivityIntent.class, new ConnectivityIntentCodec()); |
85 | registerCodec(FlowEntry.class, new FlowEntryCodec()); | 86 | registerCodec(FlowEntry.class, new FlowEntryCodec()); |
87 | + registerCodec(FlowRule.class, new FlowRuleCodec()); | ||
86 | registerCodec(TrafficTreatment.class, new TrafficTreatmentCodec()); | 88 | registerCodec(TrafficTreatment.class, new TrafficTreatmentCodec()); |
87 | registerCodec(TrafficSelector.class, new TrafficSelectorCodec()); | 89 | registerCodec(TrafficSelector.class, new TrafficSelectorCodec()); |
88 | registerCodec(Instruction.class, new InstructionCodec()); | 90 | registerCodec(Instruction.class, new InstructionCodec()); | ... | ... |
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
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.onlab.packet.IpAddress; | ||
19 | +import org.onlab.packet.MacAddress; | ||
20 | +import org.onlab.packet.MplsLabel; | ||
21 | +import org.onlab.packet.VlanId; | ||
22 | +import org.onosproject.net.ChannelSpacing; | ||
23 | +import org.onosproject.net.GridType; | ||
24 | +import org.onosproject.net.Lambda; | ||
25 | +import org.onosproject.net.OchSignal; | ||
26 | +import org.onosproject.net.PortNumber; | ||
27 | +import org.onosproject.net.flow.instructions.Instruction; | ||
28 | +import org.onosproject.net.flow.instructions.Instructions; | ||
29 | +import org.onosproject.net.flow.instructions.L0ModificationInstruction; | ||
30 | +import org.onosproject.net.flow.instructions.L2ModificationInstruction; | ||
31 | +import org.onosproject.net.flow.instructions.L3ModificationInstruction; | ||
32 | + | ||
33 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
34 | + | ||
35 | +import static org.onlab.util.Tools.nullIsIllegal; | ||
36 | + | ||
37 | +/** | ||
38 | + * Decoding portion of the instruction codec. | ||
39 | + */ | ||
40 | +public final class DecodeInstructionCodec { | ||
41 | + private final ObjectNode json; | ||
42 | + | ||
43 | + /** | ||
44 | + * Creates a decode instruction codec object. | ||
45 | + * | ||
46 | + * @param json JSON object to decode | ||
47 | + */ | ||
48 | + public DecodeInstructionCodec(ObjectNode json) { | ||
49 | + this.json = json; | ||
50 | + } | ||
51 | + | ||
52 | + /** | ||
53 | + * Decodes a Layer 2 instruction. | ||
54 | + * | ||
55 | + * @return instruction object decoded from the JSON | ||
56 | + * @throws IllegalArgumentException if the JSON is invalid | ||
57 | + */ | ||
58 | + private Instruction decodeL2() { | ||
59 | + String subType = json.get(InstructionCodec.SUBTYPE).asText(); | ||
60 | + | ||
61 | + if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC.name())) { | ||
62 | + String mac = nullIsIllegal(json.get(InstructionCodec.MAC), | ||
63 | + InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); | ||
64 | + return Instructions.modL2Src(MacAddress.valueOf(mac)); | ||
65 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST.name())) { | ||
66 | + String mac = nullIsIllegal(json.get(InstructionCodec.MAC), | ||
67 | + InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); | ||
68 | + return Instructions.modL2Dst(MacAddress.valueOf(mac)); | ||
69 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_ID.name())) { | ||
70 | + short vlanId = (short) nullIsIllegal(json.get(InstructionCodec.VLAN_ID), | ||
71 | + InstructionCodec.VLAN_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
72 | + return Instructions.modVlanId(VlanId.vlanId(vlanId)); | ||
73 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PCP.name())) { | ||
74 | + byte vlanPcp = (byte) nullIsIllegal(json.get(InstructionCodec.VLAN_PCP), | ||
75 | + InstructionCodec.VLAN_PCP + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
76 | + return Instructions.modVlanPcp(vlanPcp); | ||
77 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_LABEL.name())) { | ||
78 | + int label = nullIsIllegal(json.get(InstructionCodec.MPLS_LABEL), | ||
79 | + InstructionCodec.MPLS_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
80 | + return Instructions.modMplsLabel(MplsLabel.mplsLabel(label)); | ||
81 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_PUSH.name())) { | ||
82 | + return Instructions.pushMpls(); | ||
83 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_POP.name())) { | ||
84 | + return Instructions.popMpls(); | ||
85 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name())) { | ||
86 | + return Instructions.decMplsTtl(); | ||
87 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_POP.name())) { | ||
88 | + return Instructions.popVlan(); | ||
89 | + } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) { | ||
90 | + return Instructions.pushVlan(); | ||
91 | + } | ||
92 | + throw new IllegalArgumentException("L2 Instruction subtype " | ||
93 | + + subType + " is not supported"); | ||
94 | + } | ||
95 | + | ||
96 | + /** | ||
97 | + * Decodes a Layer 3 instruction. | ||
98 | + * | ||
99 | + * @return instruction object decoded from the JSON | ||
100 | + * @throws IllegalArgumentException if the JSON is invalid | ||
101 | + */ | ||
102 | + private Instruction decodeL3() { | ||
103 | + String subType = json.get(InstructionCodec.SUBTYPE).asText(); | ||
104 | + | ||
105 | + if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_SRC.name())) { | ||
106 | + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), | ||
107 | + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); | ||
108 | + return Instructions.modL3Src(ip); | ||
109 | + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_DST.name())) { | ||
110 | + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), | ||
111 | + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); | ||
112 | + return Instructions.modL3Dst(ip); | ||
113 | + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_SRC.name())) { | ||
114 | + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), | ||
115 | + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); | ||
116 | + return Instructions.modL3IPv6Src(ip); | ||
117 | + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_DST.name())) { | ||
118 | + IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP), | ||
119 | + InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText()); | ||
120 | + return Instructions.modL3IPv6Dst(ip); | ||
121 | + } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_FLABEL.name())) { | ||
122 | + int flowLabel = nullIsIllegal(json.get(InstructionCodec.FLOW_LABEL), | ||
123 | + InstructionCodec.FLOW_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
124 | + return Instructions.modL3IPv6FlowLabel(flowLabel); | ||
125 | + } | ||
126 | + throw new IllegalArgumentException("L3 Instruction subtype " | ||
127 | + + subType + " is not supported"); | ||
128 | + } | ||
129 | + | ||
130 | + /** | ||
131 | + * Decodes a Layer 0 instruction. | ||
132 | + * | ||
133 | + * @return instruction object decoded from the JSON | ||
134 | + * @throws IllegalArgumentException if the JSON is invalid | ||
135 | + */ | ||
136 | + private Instruction decodeL0() { | ||
137 | + String subType = json.get(InstructionCodec.SUBTYPE).asText(); | ||
138 | + | ||
139 | + | ||
140 | + if (subType.equals(L0ModificationInstruction.L0SubType.LAMBDA.name())) { | ||
141 | + int lambda = nullIsIllegal(json.get(InstructionCodec.LAMBDA), | ||
142 | + InstructionCodec.LAMBDA + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
143 | + return Instructions.modL0Lambda(Lambda.indexedLambda(lambda)); | ||
144 | + } else if (subType.equals(L0ModificationInstruction.L0SubType.OCH.name())) { | ||
145 | + String gridTypeString = nullIsIllegal(json.get(InstructionCodec.GRID_TYPE), | ||
146 | + InstructionCodec.GRID_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); | ||
147 | + GridType gridType = GridType.valueOf(gridTypeString); | ||
148 | + if (gridType == null) { | ||
149 | + throw new IllegalArgumentException("Unknown grid type " | ||
150 | + + gridTypeString); | ||
151 | + } | ||
152 | + String channelSpacingString = nullIsIllegal(json.get(InstructionCodec.CHANNEL_SPACING), | ||
153 | + InstructionCodec.CHANNEL_SPACING + InstructionCodec.MISSING_MEMBER_MESSAGE).asText(); | ||
154 | + ChannelSpacing channelSpacing = ChannelSpacing.valueOf(channelSpacingString); | ||
155 | + if (channelSpacing == null) { | ||
156 | + throw new IllegalArgumentException("Unknown channel spacing " | ||
157 | + + channelSpacingString); | ||
158 | + } | ||
159 | + int spacingMultiplier = nullIsIllegal(json.get(InstructionCodec.SPACING_MULTIPLIER), | ||
160 | + InstructionCodec.SPACING_MULTIPLIER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
161 | + int slotGranularity = nullIsIllegal(json.get(InstructionCodec.SLOT_GRANULARITY), | ||
162 | + InstructionCodec.SLOT_GRANULARITY + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt(); | ||
163 | + return Instructions.modL0Lambda(new OchSignal(gridType, channelSpacing, | ||
164 | + spacingMultiplier, slotGranularity)); | ||
165 | + } | ||
166 | + throw new IllegalArgumentException("L0 Instruction subtype " | ||
167 | + + subType + " is not supported"); | ||
168 | + } | ||
169 | + | ||
170 | + /** | ||
171 | + * Decodes the JSON into an instruction object. | ||
172 | + * | ||
173 | + * @return Criterion object | ||
174 | + * @throws IllegalArgumentException if the JSON is invalid | ||
175 | + */ | ||
176 | + public Instruction decode() { | ||
177 | + String type = json.get(InstructionCodec.TYPE).asText(); | ||
178 | + | ||
179 | + if (type.equals(Instruction.Type.OUTPUT.name())) { | ||
180 | + PortNumber portNumber = | ||
181 | + PortNumber.portNumber(nullIsIllegal(json.get(InstructionCodec.PORT), | ||
182 | + InstructionCodec.PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong()); | ||
183 | + return Instructions.createOutput(portNumber); | ||
184 | + } else if (type.equals(Instruction.Type.DROP.name())) { | ||
185 | + return Instructions.createDrop(); | ||
186 | + } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) { | ||
187 | + return decodeL0(); | ||
188 | + } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) { | ||
189 | + return decodeL2(); | ||
190 | + } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) { | ||
191 | + return decodeL3(); | ||
192 | + } | ||
193 | + throw new IllegalArgumentException("Instruction type " | ||
194 | + + type + " is not supported"); | ||
195 | + } | ||
196 | + | ||
197 | +} |
This diff is collapsed. Click to expand it.
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.OchSignal; | ||
20 | +import org.onosproject.net.flow.instructions.Instruction; | ||
21 | +import org.onosproject.net.flow.instructions.Instructions; | ||
22 | +import org.onosproject.net.flow.instructions.L0ModificationInstruction; | ||
23 | +import org.onosproject.net.flow.instructions.L2ModificationInstruction; | ||
24 | +import org.onosproject.net.flow.instructions.L3ModificationInstruction; | ||
25 | +import org.slf4j.Logger; | ||
26 | +import org.slf4j.LoggerFactory; | ||
27 | + | ||
28 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
29 | + | ||
30 | +/** | ||
31 | + * JSON encoding of Instructions. | ||
32 | + */ | ||
33 | +public final class EncodeInstructionCodec { | ||
34 | + protected static final Logger log = LoggerFactory.getLogger(EncodeInstructionCodec.class); | ||
35 | + private final Instruction instruction; | ||
36 | + private final CodecContext context; | ||
37 | + | ||
38 | + /** | ||
39 | + * Creates an instruction object encoder. | ||
40 | + * | ||
41 | + * @param instruction instruction to encode | ||
42 | + * @param context codec context for the encoding | ||
43 | + */ | ||
44 | + public EncodeInstructionCodec(Instruction instruction, CodecContext context) { | ||
45 | + this.instruction = instruction; | ||
46 | + this.context = context; | ||
47 | + } | ||
48 | + | ||
49 | + | ||
50 | + /** | ||
51 | + * Encode an L0 modification instruction. | ||
52 | + * | ||
53 | + * @param result json node that the instruction attributes are added to | ||
54 | + */ | ||
55 | + private void encodeL0(ObjectNode result) { | ||
56 | + L0ModificationInstruction instruction = | ||
57 | + (L0ModificationInstruction) this.instruction; | ||
58 | + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); | ||
59 | + | ||
60 | + switch (instruction.subtype()) { | ||
61 | + case LAMBDA: | ||
62 | + final L0ModificationInstruction.ModLambdaInstruction modLambdaInstruction = | ||
63 | + (L0ModificationInstruction.ModLambdaInstruction) instruction; | ||
64 | + result.put(InstructionCodec.LAMBDA, modLambdaInstruction.lambda()); | ||
65 | + break; | ||
66 | + | ||
67 | + case OCH: | ||
68 | + L0ModificationInstruction.ModOchSignalInstruction ochSignalInstruction = | ||
69 | + (L0ModificationInstruction.ModOchSignalInstruction) instruction; | ||
70 | + OchSignal ochSignal = ochSignalInstruction.lambda(); | ||
71 | + result.put(InstructionCodec.GRID_TYPE, ochSignal.gridType().name()); | ||
72 | + result.put(InstructionCodec.CHANNEL_SPACING, ochSignal.channelSpacing().name()); | ||
73 | + result.put(InstructionCodec.SPACING_MULTIPLIER, ochSignal.spacingMultiplier()); | ||
74 | + result.put(InstructionCodec.SLOT_GRANULARITY, ochSignal.slotGranularity()); | ||
75 | + break; | ||
76 | + | ||
77 | + default: | ||
78 | + log.info("Cannot convert L0 subtype of {}", instruction.subtype()); | ||
79 | + } | ||
80 | + } | ||
81 | + | ||
82 | + /** | ||
83 | + * Encode an L2 modification instruction. | ||
84 | + * | ||
85 | + * @param result json node that the instruction attributes are added to | ||
86 | + */ | ||
87 | + private void encodeL2(ObjectNode result) { | ||
88 | + L2ModificationInstruction instruction = | ||
89 | + (L2ModificationInstruction) this.instruction; | ||
90 | + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); | ||
91 | + | ||
92 | + switch (instruction.subtype()) { | ||
93 | + case ETH_SRC: | ||
94 | + case ETH_DST: | ||
95 | + final L2ModificationInstruction.ModEtherInstruction modEtherInstruction = | ||
96 | + (L2ModificationInstruction.ModEtherInstruction) instruction; | ||
97 | + result.put(InstructionCodec.MAC, modEtherInstruction.mac().toString()); | ||
98 | + break; | ||
99 | + | ||
100 | + case VLAN_ID: | ||
101 | + final L2ModificationInstruction.ModVlanIdInstruction modVlanIdInstruction = | ||
102 | + (L2ModificationInstruction.ModVlanIdInstruction) instruction; | ||
103 | + result.put(InstructionCodec.VLAN_ID, modVlanIdInstruction.vlanId().toShort()); | ||
104 | + break; | ||
105 | + | ||
106 | + case VLAN_PCP: | ||
107 | + final L2ModificationInstruction.ModVlanPcpInstruction modVlanPcpInstruction = | ||
108 | + (L2ModificationInstruction.ModVlanPcpInstruction) instruction; | ||
109 | + result.put(InstructionCodec.VLAN_PCP, modVlanPcpInstruction.vlanPcp()); | ||
110 | + break; | ||
111 | + | ||
112 | + case MPLS_LABEL: | ||
113 | + final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction = | ||
114 | + (L2ModificationInstruction.ModMplsLabelInstruction) instruction; | ||
115 | + result.put(InstructionCodec.MPLS_LABEL, modMplsLabelInstruction.label()); | ||
116 | + break; | ||
117 | + | ||
118 | + case MPLS_PUSH: | ||
119 | + final L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions = | ||
120 | + (L2ModificationInstruction.PushHeaderInstructions) instruction; | ||
121 | + | ||
122 | + result.put(InstructionCodec.ETHERNET_TYPE, pushHeaderInstructions.ethernetType()); | ||
123 | + break; | ||
124 | + | ||
125 | + default: | ||
126 | + log.info("Cannot convert L2 subtype of {}", instruction.subtype()); | ||
127 | + break; | ||
128 | + } | ||
129 | + } | ||
130 | + | ||
131 | + /** | ||
132 | + * Encode an L3 modification instruction. | ||
133 | + * | ||
134 | + * @param result json node that the instruction attributes are added to | ||
135 | + */ | ||
136 | + private void encodeL3(ObjectNode result) { | ||
137 | + L3ModificationInstruction instruction = | ||
138 | + (L3ModificationInstruction) this.instruction; | ||
139 | + result.put(InstructionCodec.SUBTYPE, instruction.subtype().name()); | ||
140 | + switch (instruction.subtype()) { | ||
141 | + case IPV4_SRC: | ||
142 | + case IPV4_DST: | ||
143 | + case IPV6_SRC: | ||
144 | + case IPV6_DST: | ||
145 | + final L3ModificationInstruction.ModIPInstruction modIPInstruction = | ||
146 | + (L3ModificationInstruction.ModIPInstruction) instruction; | ||
147 | + result.put(InstructionCodec.IP, modIPInstruction.ip().toString()); | ||
148 | + break; | ||
149 | + | ||
150 | + case IPV6_FLABEL: | ||
151 | + final L3ModificationInstruction.ModIPv6FlowLabelInstruction | ||
152 | + modFlowLabelInstruction = | ||
153 | + (L3ModificationInstruction.ModIPv6FlowLabelInstruction) instruction; | ||
154 | + result.put(InstructionCodec.FLOW_LABEL, modFlowLabelInstruction.flowLabel()); | ||
155 | + break; | ||
156 | + | ||
157 | + default: | ||
158 | + log.info("Cannot convert L3 subtype of {}", instruction.subtype()); | ||
159 | + break; | ||
160 | + } | ||
161 | + } | ||
162 | + | ||
163 | + /** | ||
164 | + * Encodes the given instruction into JSON. | ||
165 | + * | ||
166 | + * @return JSON object node representing the instruction | ||
167 | + */ | ||
168 | + public ObjectNode encode() { | ||
169 | + final ObjectNode result = context.mapper().createObjectNode() | ||
170 | + .put(InstructionCodec.TYPE, instruction.type().toString()); | ||
171 | + | ||
172 | + switch (instruction.type()) { | ||
173 | + case OUTPUT: | ||
174 | + final Instructions.OutputInstruction outputInstruction = | ||
175 | + (Instructions.OutputInstruction) instruction; | ||
176 | + result.put(InstructionCodec.PORT, outputInstruction.port().toLong()); | ||
177 | + break; | ||
178 | + | ||
179 | + case DROP: | ||
180 | + break; | ||
181 | + | ||
182 | + case L0MODIFICATION: | ||
183 | + encodeL0(result); | ||
184 | + break; | ||
185 | + | ||
186 | + case L2MODIFICATION: | ||
187 | + encodeL2(result); | ||
188 | + break; | ||
189 | + | ||
190 | + case L3MODIFICATION: | ||
191 | + encodeL3(result); | ||
192 | + break; | ||
193 | + | ||
194 | + default: | ||
195 | + log.info("Cannot convert instruction type of {}", instruction.type()); | ||
196 | + break; | ||
197 | + } | ||
198 | + return result; | ||
199 | + } | ||
200 | + | ||
201 | +} |
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.codec.JsonCodec; | ||
20 | +import org.onosproject.core.CoreService; | ||
21 | +import org.onosproject.net.DeviceId; | ||
22 | +import org.onosproject.net.flow.DefaultFlowRule; | ||
23 | +import org.onosproject.net.flow.FlowRule; | ||
24 | +import org.onosproject.net.flow.TrafficSelector; | ||
25 | +import org.onosproject.net.flow.TrafficTreatment; | ||
26 | + | ||
27 | +import com.fasterxml.jackson.databind.node.ObjectNode; | ||
28 | + | ||
29 | +import static org.onlab.util.Tools.nullIsIllegal; | ||
30 | + | ||
31 | +/** | ||
32 | + * Flow rule JSON codec. | ||
33 | + */ | ||
34 | +public final class FlowRuleCodec extends JsonCodec<FlowRule> { | ||
35 | + | ||
36 | + private static final String APP_ID = "appId"; | ||
37 | + private static final String PRIORITY = "priority"; | ||
38 | + private static final String TIMEOUT = "timeout"; | ||
39 | + private static final String IS_PERMANENT = "isPermanent"; | ||
40 | + private static final String DEVICE_ID = "deviceId"; | ||
41 | + private static final String TREATMENT = "treatment"; | ||
42 | + private static final String SELECTOR = "selector"; | ||
43 | + private static final String MISSING_MEMBER_MESSAGE = | ||
44 | + " member is required in FlowRule"; | ||
45 | + | ||
46 | + | ||
47 | + @Override | ||
48 | + public FlowRule decode(ObjectNode json, CodecContext context) { | ||
49 | + if (json == null || !json.isObject()) { | ||
50 | + return null; | ||
51 | + } | ||
52 | + | ||
53 | + FlowRule.Builder resultBuilder = new DefaultFlowRule.Builder(); | ||
54 | + | ||
55 | + short appId = nullIsIllegal(json.get(APP_ID), | ||
56 | + APP_ID + MISSING_MEMBER_MESSAGE).shortValue(); | ||
57 | + CoreService coreService = context.getService(CoreService.class); | ||
58 | + resultBuilder.fromApp(coreService.getAppId(appId)); | ||
59 | + | ||
60 | + int priority = nullIsIllegal(json.get(PRIORITY), | ||
61 | + PRIORITY + MISSING_MEMBER_MESSAGE).asInt(); | ||
62 | + resultBuilder.withPriority(priority); | ||
63 | + | ||
64 | + boolean isPermanent = nullIsIllegal(json.get(IS_PERMANENT), | ||
65 | + IS_PERMANENT + MISSING_MEMBER_MESSAGE).asBoolean(); | ||
66 | + if (isPermanent) { | ||
67 | + resultBuilder.makePermanent(); | ||
68 | + } else { | ||
69 | + resultBuilder.makeTemporary(nullIsIllegal(json.get(TIMEOUT), | ||
70 | + TIMEOUT | ||
71 | + + MISSING_MEMBER_MESSAGE | ||
72 | + + " if the flow is temporary").asInt()); | ||
73 | + } | ||
74 | + | ||
75 | + DeviceId deviceId = DeviceId.deviceId(nullIsIllegal(json.get(DEVICE_ID), | ||
76 | + DEVICE_ID + MISSING_MEMBER_MESSAGE).asText()); | ||
77 | + resultBuilder.forDevice(deviceId); | ||
78 | + | ||
79 | + ObjectNode treatmentJson = (ObjectNode) json.get(TREATMENT); | ||
80 | + if (treatmentJson != null) { | ||
81 | + JsonCodec<TrafficTreatment> treatmentCodec = | ||
82 | + context.codec(TrafficTreatment.class); | ||
83 | + resultBuilder.withTreatment(treatmentCodec.decode(treatmentJson, context)); | ||
84 | + } | ||
85 | + | ||
86 | + ObjectNode selectorJson = (ObjectNode) json.get(SELECTOR); | ||
87 | + if (selectorJson != null) { | ||
88 | + JsonCodec<TrafficSelector> selectorCodec = | ||
89 | + context.codec(TrafficSelector.class); | ||
90 | + resultBuilder.withSelector(selectorCodec.decode(selectorJson, context)); | ||
91 | + } | ||
92 | + | ||
93 | + return resultBuilder.build(); | ||
94 | + } | ||
95 | +} |
... | @@ -17,12 +17,7 @@ package org.onosproject.codec.impl; | ... | @@ -17,12 +17,7 @@ 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.OchSignal; | ||
21 | import org.onosproject.net.flow.instructions.Instruction; | 20 | import org.onosproject.net.flow.instructions.Instruction; |
22 | -import org.onosproject.net.flow.instructions.Instructions; | ||
23 | -import org.onosproject.net.flow.instructions.L0ModificationInstruction; | ||
24 | -import org.onosproject.net.flow.instructions.L2ModificationInstruction; | ||
25 | -import org.onosproject.net.flow.instructions.L3ModificationInstruction; | ||
26 | import org.slf4j.Logger; | 21 | import org.slf4j.Logger; |
27 | import org.slf4j.LoggerFactory; | 22 | import org.slf4j.LoggerFactory; |
28 | 23 | ||
... | @@ -37,159 +32,39 @@ public final class InstructionCodec extends JsonCodec<Instruction> { | ... | @@ -37,159 +32,39 @@ public final class InstructionCodec extends JsonCodec<Instruction> { |
37 | 32 | ||
38 | protected static final Logger log = LoggerFactory.getLogger(InstructionCodec.class); | 33 | protected static final Logger log = LoggerFactory.getLogger(InstructionCodec.class); |
39 | 34 | ||
40 | - /** | 35 | + protected static final String TYPE = "type"; |
41 | - * Encode an L0 modification instruction. | 36 | + protected static final String SUBTYPE = "subtype"; |
42 | - * | 37 | + protected static final String PORT = "port"; |
43 | - * @param result json node that the instruction attributes are added to | 38 | + protected static final String MAC = "mac"; |
44 | - * @param instruction The L0 instruction | 39 | + protected static final String VLAN_ID = "vlanId"; |
45 | - */ | 40 | + protected static final String VLAN_PCP = "vlanPcp"; |
46 | - private void encodeL0(ObjectNode result, L0ModificationInstruction instruction) { | 41 | + protected static final String MPLS_LABEL = "label"; |
47 | - result.put("subtype", instruction.subtype().name()); | 42 | + protected static final String IP = "ip"; |
43 | + protected static final String FLOW_LABEL = "flowLabel"; | ||
44 | + protected static final String LAMBDA = "lambda"; | ||
45 | + protected static final String GRID_TYPE = "gridType"; | ||
46 | + protected static final String CHANNEL_SPACING = "channelSpacing"; | ||
47 | + protected static final String SPACING_MULTIPLIER = "spacingMultiplier"; | ||
48 | + protected static final String SLOT_GRANULARITY = "slotGranularity"; | ||
49 | + protected static final String ETHERNET_TYPE = "ethernetType"; | ||
50 | + | ||
51 | + protected static final String MISSING_MEMBER_MESSAGE = | ||
52 | + " member is required in Instruction"; | ||
48 | 53 | ||
49 | - switch (instruction.subtype()) { | ||
50 | - case LAMBDA: | ||
51 | - final L0ModificationInstruction.ModLambdaInstruction modLambdaInstruction = | ||
52 | - (L0ModificationInstruction.ModLambdaInstruction) instruction; | ||
53 | - result.put("lambda", modLambdaInstruction.lambda()); | ||
54 | - break; | ||
55 | - | ||
56 | - case OCH: | ||
57 | - L0ModificationInstruction.ModOchSignalInstruction ochSignalInstruction = | ||
58 | - (L0ModificationInstruction.ModOchSignalInstruction) instruction; | ||
59 | - OchSignal ochSignal = ochSignalInstruction.lambda(); | ||
60 | - result.put("gridType", ochSignal.gridType().name()); | ||
61 | - result.put("channelSpacing", ochSignal.channelSpacing().name()); | ||
62 | - result.put("spacingMultiplier", ochSignal.spacingMultiplier()); | ||
63 | - result.put("slotGranularity", ochSignal.slotGranularity()); | ||
64 | - break; | ||
65 | - | ||
66 | - default: | ||
67 | - log.info("Cannot convert L0 subtype of {}", instruction.subtype()); | ||
68 | - } | ||
69 | - } | ||
70 | - | ||
71 | - /** | ||
72 | - * Encode an L2 modification instruction. | ||
73 | - * | ||
74 | - * @param result json node that the instruction attributes are added to | ||
75 | - * @param instruction The L2 instruction | ||
76 | - * @param context context of the request | ||
77 | - */ | ||
78 | - private void encodeL2(ObjectNode result, | ||
79 | - L2ModificationInstruction instruction, | ||
80 | - CodecContext context) { | ||
81 | - result.put("subtype", instruction.subtype().name()); | ||
82 | - | ||
83 | - switch (instruction.subtype()) { | ||
84 | - case ETH_SRC: | ||
85 | - case ETH_DST: | ||
86 | - final L2ModificationInstruction.ModEtherInstruction modEtherInstruction = | ||
87 | - (L2ModificationInstruction.ModEtherInstruction) instruction; | ||
88 | - result.put("mac", modEtherInstruction.mac().toString()); | ||
89 | - break; | ||
90 | - | ||
91 | - case VLAN_ID: | ||
92 | - final L2ModificationInstruction.ModVlanIdInstruction modVlanIdInstruction = | ||
93 | - (L2ModificationInstruction.ModVlanIdInstruction) instruction; | ||
94 | - result.put("vlanId", modVlanIdInstruction.vlanId().toShort()); | ||
95 | - break; | ||
96 | - | ||
97 | - case VLAN_PCP: | ||
98 | - final L2ModificationInstruction.ModVlanPcpInstruction modVlanPcpInstruction = | ||
99 | - (L2ModificationInstruction.ModVlanPcpInstruction) instruction; | ||
100 | - result.put("vlanPcp", modVlanPcpInstruction.vlanPcp()); | ||
101 | - break; | ||
102 | - | ||
103 | - case MPLS_LABEL: | ||
104 | - final L2ModificationInstruction.ModMplsLabelInstruction modMplsLabelInstruction = | ||
105 | - (L2ModificationInstruction.ModMplsLabelInstruction) instruction; | ||
106 | - result.put("label", modMplsLabelInstruction.label()); | ||
107 | - break; | ||
108 | - | ||
109 | - case MPLS_PUSH: | ||
110 | - final L2ModificationInstruction.PushHeaderInstructions pushHeaderInstructions = | ||
111 | - (L2ModificationInstruction.PushHeaderInstructions) instruction; | ||
112 | - | ||
113 | - result.put("ethernetType", pushHeaderInstructions.ethernetType()); | ||
114 | - break; | ||
115 | - | ||
116 | - default: | ||
117 | - log.info("Cannot convert L2 subtype of {}", instruction.subtype()); | ||
118 | - break; | ||
119 | - } | ||
120 | - } | ||
121 | - | ||
122 | - /** | ||
123 | - * Encode an L3 modification instruction. | ||
124 | - * | ||
125 | - * @param result json node that the instruction attributes are added to | ||
126 | - * @param instruction The L3 instruction | ||
127 | - */ | ||
128 | - private void encodeL3(ObjectNode result, L3ModificationInstruction instruction) { | ||
129 | - result.put("subtype", instruction.subtype().name()); | ||
130 | - switch (instruction.subtype()) { | ||
131 | - case IPV4_SRC: | ||
132 | - case IPV4_DST: | ||
133 | - case IPV6_SRC: | ||
134 | - case IPV6_DST: | ||
135 | - final L3ModificationInstruction.ModIPInstruction modIPInstruction = | ||
136 | - (L3ModificationInstruction.ModIPInstruction) instruction; | ||
137 | - result.put("ip", modIPInstruction.ip().toString()); | ||
138 | - break; | ||
139 | - | ||
140 | - case IPV6_FLABEL: | ||
141 | - final L3ModificationInstruction.ModIPv6FlowLabelInstruction | ||
142 | - modFlowLabelInstruction = | ||
143 | - (L3ModificationInstruction.ModIPv6FlowLabelInstruction) instruction; | ||
144 | - result.put("flowLabel", modFlowLabelInstruction.flowLabel()); | ||
145 | - break; | ||
146 | - | ||
147 | - default: | ||
148 | - log.info("Cannot convert L3 subtype of {}", instruction.subtype()); | ||
149 | - break; | ||
150 | - } | ||
151 | - } | ||
152 | 54 | ||
153 | @Override | 55 | @Override |
154 | public ObjectNode encode(Instruction instruction, CodecContext context) { | 56 | public ObjectNode encode(Instruction instruction, CodecContext context) { |
155 | checkNotNull(instruction, "Instruction cannot be null"); | 57 | checkNotNull(instruction, "Instruction cannot be null"); |
156 | 58 | ||
157 | - final ObjectNode result = context.mapper().createObjectNode() | 59 | + return new EncodeInstructionCodec(instruction, context).encode(); |
158 | - .put("type", instruction.type().toString()); | 60 | + } |
159 | - | ||
160 | - | ||
161 | - switch (instruction.type()) { | ||
162 | - case OUTPUT: | ||
163 | - final Instructions.OutputInstruction outputInstruction = | ||
164 | - (Instructions.OutputInstruction) instruction; | ||
165 | - result.put("port", outputInstruction.port().toLong()); | ||
166 | - break; | ||
167 | - | ||
168 | - case DROP: | ||
169 | - break; | ||
170 | - | ||
171 | - case L0MODIFICATION: | ||
172 | - final L0ModificationInstruction l0ModificationInstruction = | ||
173 | - (L0ModificationInstruction) instruction; | ||
174 | - encodeL0(result, l0ModificationInstruction); | ||
175 | - break; | ||
176 | - | ||
177 | - case L2MODIFICATION: | ||
178 | - final L2ModificationInstruction l2ModificationInstruction = | ||
179 | - (L2ModificationInstruction) instruction; | ||
180 | - encodeL2(result, l2ModificationInstruction, context); | ||
181 | - break; | ||
182 | - | ||
183 | - case L3MODIFICATION: | ||
184 | - final L3ModificationInstruction l3ModificationInstruction = | ||
185 | - (L3ModificationInstruction) instruction; | ||
186 | - encodeL3(result, l3ModificationInstruction); | ||
187 | - break; | ||
188 | 61 | ||
189 | - default: | 62 | + @Override |
190 | - log.info("Cannot convert instruction type of {}", instruction.type()); | 63 | + public Instruction decode(ObjectNode json, CodecContext context) { |
191 | - break; | 64 | + if (json == null || !json.isObject()) { |
65 | + return null; | ||
192 | } | 66 | } |
193 | - return result; | 67 | + |
68 | + return new DecodeInstructionCodec(json).decode(); | ||
194 | } | 69 | } |
195 | } | 70 | } | ... | ... |
... | @@ -15,11 +15,15 @@ | ... | @@ -15,11 +15,15 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.codec.impl; | 16 | package org.onosproject.codec.impl; |
17 | 17 | ||
18 | +import java.util.stream.IntStream; | ||
19 | + | ||
18 | import org.onosproject.codec.CodecContext; | 20 | import org.onosproject.codec.CodecContext; |
19 | import org.onosproject.codec.JsonCodec; | 21 | import org.onosproject.codec.JsonCodec; |
22 | +import org.onosproject.net.flow.DefaultTrafficSelector; | ||
20 | import org.onosproject.net.flow.TrafficSelector; | 23 | import org.onosproject.net.flow.TrafficSelector; |
21 | import org.onosproject.net.flow.criteria.Criterion; | 24 | import org.onosproject.net.flow.criteria.Criterion; |
22 | 25 | ||
26 | +import com.fasterxml.jackson.databind.JsonNode; | ||
23 | import com.fasterxml.jackson.databind.node.ArrayNode; | 27 | import com.fasterxml.jackson.databind.node.ArrayNode; |
24 | import com.fasterxml.jackson.databind.node.ObjectNode; | 28 | import com.fasterxml.jackson.databind.node.ObjectNode; |
25 | 29 | ||
... | @@ -29,12 +33,14 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -29,12 +33,14 @@ import static com.google.common.base.Preconditions.checkNotNull; |
29 | * Traffic selector codec. | 33 | * Traffic selector codec. |
30 | */ | 34 | */ |
31 | public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { | 35 | public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { |
36 | + private static final String CRITERIA = "criteria"; | ||
37 | + | ||
32 | @Override | 38 | @Override |
33 | public ObjectNode encode(TrafficSelector selector, CodecContext context) { | 39 | public ObjectNode encode(TrafficSelector selector, CodecContext context) { |
34 | checkNotNull(selector, "Traffic selector cannot be null"); | 40 | checkNotNull(selector, "Traffic selector cannot be null"); |
35 | 41 | ||
36 | final ObjectNode result = context.mapper().createObjectNode(); | 42 | final ObjectNode result = context.mapper().createObjectNode(); |
37 | - final ArrayNode jsonCriteria = result.putArray("criteria"); | 43 | + final ArrayNode jsonCriteria = result.putArray(CRITERIA); |
38 | 44 | ||
39 | if (selector.criteria() != null) { | 45 | if (selector.criteria() != null) { |
40 | final JsonCodec<Criterion> criterionCodec = | 46 | final JsonCodec<Criterion> criterionCodec = |
... | @@ -46,4 +52,20 @@ public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { | ... | @@ -46,4 +52,20 @@ public final class TrafficSelectorCodec extends JsonCodec<TrafficSelector> { |
46 | 52 | ||
47 | return result; | 53 | return result; |
48 | } | 54 | } |
55 | + | ||
56 | + @Override | ||
57 | + public TrafficSelector decode(ObjectNode json, CodecContext context) { | ||
58 | + final JsonCodec<Criterion> criterionCodec = | ||
59 | + context.codec(Criterion.class); | ||
60 | + | ||
61 | + JsonNode criteriaJson = json.get(CRITERIA); | ||
62 | + TrafficSelector.Builder builder = DefaultTrafficSelector.builder(); | ||
63 | + if (criteriaJson != null) { | ||
64 | + IntStream.range(0, criteriaJson.size()) | ||
65 | + .forEach(i -> builder.add( | ||
66 | + criterionCodec.decode((ObjectNode) criteriaJson.get(i), | ||
67 | + context))); | ||
68 | + } | ||
69 | + return builder.build(); | ||
70 | + } | ||
49 | } | 71 | } | ... | ... |
... | @@ -15,11 +15,15 @@ | ... | @@ -15,11 +15,15 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.codec.impl; | 16 | package org.onosproject.codec.impl; |
17 | 17 | ||
18 | +import java.util.stream.IntStream; | ||
19 | + | ||
18 | import org.onosproject.codec.CodecContext; | 20 | import org.onosproject.codec.CodecContext; |
19 | import org.onosproject.codec.JsonCodec; | 21 | import org.onosproject.codec.JsonCodec; |
22 | +import org.onosproject.net.flow.DefaultTrafficTreatment; | ||
20 | import org.onosproject.net.flow.TrafficTreatment; | 23 | import org.onosproject.net.flow.TrafficTreatment; |
21 | import org.onosproject.net.flow.instructions.Instruction; | 24 | import org.onosproject.net.flow.instructions.Instruction; |
22 | 25 | ||
26 | +import com.fasterxml.jackson.databind.JsonNode; | ||
23 | import com.fasterxml.jackson.databind.node.ArrayNode; | 27 | import com.fasterxml.jackson.databind.node.ArrayNode; |
24 | import com.fasterxml.jackson.databind.node.ObjectNode; | 28 | import com.fasterxml.jackson.databind.node.ObjectNode; |
25 | 29 | ||
... | @@ -29,12 +33,14 @@ import static com.google.common.base.Preconditions.checkNotNull; | ... | @@ -29,12 +33,14 @@ import static com.google.common.base.Preconditions.checkNotNull; |
29 | * Traffic treatment codec. | 33 | * Traffic treatment codec. |
30 | */ | 34 | */ |
31 | public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { | 35 | public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { |
36 | + private static final String INSTRUCTIONS = "instructions"; | ||
37 | + | ||
32 | @Override | 38 | @Override |
33 | public ObjectNode encode(TrafficTreatment treatment, CodecContext context) { | 39 | public ObjectNode encode(TrafficTreatment treatment, CodecContext context) { |
34 | checkNotNull(treatment, "Traffic treatment cannot be null"); | 40 | checkNotNull(treatment, "Traffic treatment cannot be null"); |
35 | 41 | ||
36 | final ObjectNode result = context.mapper().createObjectNode(); | 42 | final ObjectNode result = context.mapper().createObjectNode(); |
37 | - final ArrayNode jsonInstructions = result.putArray("instructions"); | 43 | + final ArrayNode jsonInstructions = result.putArray(INSTRUCTIONS); |
38 | 44 | ||
39 | final JsonCodec<Instruction> instructionCodec = | 45 | final JsonCodec<Instruction> instructionCodec = |
40 | context.codec(Instruction.class); | 46 | context.codec(Instruction.class); |
... | @@ -51,4 +57,20 @@ public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { | ... | @@ -51,4 +57,20 @@ public final class TrafficTreatmentCodec extends JsonCodec<TrafficTreatment> { |
51 | 57 | ||
52 | return result; | 58 | return result; |
53 | } | 59 | } |
60 | + | ||
61 | + @Override | ||
62 | + public TrafficTreatment decode(ObjectNode json, CodecContext context) { | ||
63 | + final JsonCodec<Instruction> instructionsCodec = | ||
64 | + context.codec(Instruction.class); | ||
65 | + | ||
66 | + JsonNode instructionsJson = json.get(INSTRUCTIONS); | ||
67 | + TrafficTreatment.Builder builder = DefaultTrafficTreatment.builder(); | ||
68 | + if (instructionsJson != null) { | ||
69 | + IntStream.range(0, instructionsJson.size()) | ||
70 | + .forEach(i -> builder.add( | ||
71 | + instructionsCodec.decode((ObjectNode) instructionsJson.get(i), | ||
72 | + context))); | ||
73 | + } | ||
74 | + return builder.build(); | ||
75 | + } | ||
54 | } | 76 | } | ... | ... |
... | @@ -72,8 +72,10 @@ public class CriterionCodecTest { | ... | @@ -72,8 +72,10 @@ public class CriterionCodecTest { |
72 | */ | 72 | */ |
73 | @Test | 73 | @Test |
74 | public void checkCriterionTypes() throws Exception { | 74 | public void checkCriterionTypes() throws Exception { |
75 | + EncodeCriterionCodec encoder = new EncodeCriterionCodec( | ||
76 | + Criteria.dummy(), context); | ||
75 | EnumMap<Criterion.Type, Object> formatMap = | 77 | EnumMap<Criterion.Type, Object> formatMap = |
76 | - getField(criterionCodec, "formatMap"); | 78 | + getField(encoder, "formatMap"); |
77 | assertThat(formatMap, notNullValue()); | 79 | assertThat(formatMap, notNullValue()); |
78 | 80 | ||
79 | for (Criterion.Type type : Criterion.Type.values()) { | 81 | for (Criterion.Type type : Criterion.Type.values()) { | ... | ... |
This diff is collapsed. Click to expand it.
... | @@ -38,6 +38,8 @@ public class ImmutableCodecsTest { | ... | @@ -38,6 +38,8 @@ public class ImmutableCodecsTest { |
38 | assertThatClassIsImmutable(ConnectPointCodec.class); | 38 | assertThatClassIsImmutable(ConnectPointCodec.class); |
39 | assertThatClassIsImmutable(ConstraintCodec.class); | 39 | assertThatClassIsImmutable(ConstraintCodec.class); |
40 | assertThatClassIsImmutable(CriterionCodec.class); | 40 | assertThatClassIsImmutable(CriterionCodec.class); |
41 | + assertThatClassIsImmutable(EncodeCriterionCodec.class); | ||
42 | + assertThatClassIsImmutable(DecodeCriterionCodec.class); | ||
41 | assertThatClassIsImmutable(DeviceCodec.class); | 43 | assertThatClassIsImmutable(DeviceCodec.class); |
42 | assertThatClassIsImmutable(EthernetCodec.class); | 44 | assertThatClassIsImmutable(EthernetCodec.class); |
43 | assertThatClassIsImmutable(FlowEntryCodec.class); | 45 | assertThatClassIsImmutable(FlowEntryCodec.class); |
... | @@ -45,6 +47,8 @@ public class ImmutableCodecsTest { | ... | @@ -45,6 +47,8 @@ public class ImmutableCodecsTest { |
45 | assertThatClassIsImmutable(HostLocationCodec.class); | 47 | assertThatClassIsImmutable(HostLocationCodec.class); |
46 | assertThatClassIsImmutable(HostToHostIntentCodec.class); | 48 | assertThatClassIsImmutable(HostToHostIntentCodec.class); |
47 | assertThatClassIsImmutable(InstructionCodec.class); | 49 | assertThatClassIsImmutable(InstructionCodec.class); |
50 | + assertThatClassIsImmutable(EncodeInstructionCodec.class); | ||
51 | + assertThatClassIsImmutable(DecodeInstructionCodec.class); | ||
48 | assertThatClassIsImmutable(IntentCodec.class); | 52 | assertThatClassIsImmutable(IntentCodec.class); |
49 | assertThatClassIsImmutable(LinkCodec.class); | 53 | assertThatClassIsImmutable(LinkCodec.class); |
50 | assertThatClassIsImmutable(PathCodec.class); | 54 | assertThatClassIsImmutable(PathCodec.class); |
... | @@ -54,5 +58,6 @@ public class ImmutableCodecsTest { | ... | @@ -54,5 +58,6 @@ public class ImmutableCodecsTest { |
54 | assertThatClassIsImmutable(TopologyCodec.class); | 58 | assertThatClassIsImmutable(TopologyCodec.class); |
55 | assertThatClassIsImmutable(TrafficSelectorCodec.class); | 59 | assertThatClassIsImmutable(TrafficSelectorCodec.class); |
56 | assertThatClassIsImmutable(TrafficTreatmentCodec.class); | 60 | assertThatClassIsImmutable(TrafficTreatmentCodec.class); |
61 | + assertThatClassIsImmutable(FlowRuleCodec.class); | ||
57 | } | 62 | } |
58 | } | 63 | } | ... | ... |
1 | +{ | ||
2 | + "appId":-29467, | ||
3 | + "priority":1, | ||
4 | + "isPermanent":"false", | ||
5 | + "timeout":1, | ||
6 | + "deviceId":"of:0000000000000001", | ||
7 | + "selector": | ||
8 | + {"criteria": | ||
9 | + [ | ||
10 | + {"type":"IN_PORT", "port":23}, | ||
11 | + {"type":"IN_PHY_PORT", "port":44}, | ||
12 | + {"type":"METADATA", "metadata":123456}, | ||
13 | + {"type":"ETH_TYPE","ethType":2054}, | ||
14 | + {"type":"ETH_SRC","mac":"00:11:22:33:44:55"}, | ||
15 | + {"type":"ETH_DST","mac":"00:11:22:33:44:55"}, | ||
16 | + {"type":"VLAN_VID","vlanId":777}, | ||
17 | + {"type":"VLAN_PCP","priority":3}, | ||
18 | + {"type":"IP_DSCP","ipDscp":2}, | ||
19 | + {"type":"IP_ECN","ipEcn":1}, | ||
20 | + {"type":"IP_PROTO","protocol":4}, | ||
21 | + {"type":"IPV4_SRC", "ip":"1.2.0.0/32"}, | ||
22 | + {"type":"IPV4_DST", "ip":"2.2.0.0/32"}, | ||
23 | + {"type":"IPV6_SRC", "ip":"3.2.0.0/32"}, | ||
24 | + {"type":"IPV6_DST", "ip":"4.2.0.0/32"}, | ||
25 | + {"type":"TCP_SRC", "tcpPort":80}, | ||
26 | + {"type":"TCP_DST", "tcpPort":443}, | ||
27 | + {"type":"UDP_SRC", "udpPort":180}, | ||
28 | + {"type":"UDP_DST", "udpPort":1443}, | ||
29 | + {"type":"SCTP_SRC", "sctpPort":280}, | ||
30 | + {"type":"SCTP_DST", "sctpPort":2443}, | ||
31 | + {"type":"ICMPV4_TYPE", "icmpType":24}, | ||
32 | + {"type":"ICMPV4_CODE", "icmpCode":16}, | ||
33 | + {"type":"ICMPV6_TYPE", "icmpv6Type":14}, | ||
34 | + {"type":"ICMPV6_CODE", "icmpv6Code":6}, | ||
35 | + {"type":"IPV6_FLABEL", "flowLabel":8}, | ||
36 | + {"type":"IPV6_ND_TARGET", "targetAddress":"1111:2222:3333:4444:5555:6666:7777:8888"}, | ||
37 | + {"type":"IPV6_ND_SLL", "mac":"00:11:22:33:44:56"}, | ||
38 | + {"type":"IPV6_ND_TLL", "mac":"00:11:22:33:44:57"}, | ||
39 | + {"type":"MPLS_LABEL", "label":123}, | ||
40 | + {"type":"IPV6_EXTHDR", "exthdrFlags":99}, | ||
41 | + {"type":"OCH_SIGID", "lambda":122} | ||
42 | + ] | ||
43 | + } | ||
44 | +} |
1 | +{ | ||
2 | + "appId":-29467, | ||
3 | + "priority":1, | ||
4 | + "isPermanent":"false", | ||
5 | + "timeout":1, | ||
6 | + "deviceId":"of:0000000000000001", | ||
7 | + "treatment": | ||
8 | + { | ||
9 | + "instructions": | ||
10 | + [ | ||
11 | + {"type":"OUTPUT","port":-3}, | ||
12 | + {"type":"DROP"}, | ||
13 | + {"type":"L2MODIFICATION","subtype":"ETH_SRC","mac":"12:34:56:78:90:12"}, | ||
14 | + {"type":"L2MODIFICATION","subtype":"ETH_DST","mac":"98:76:54:32:01:00"}, | ||
15 | + {"type":"L2MODIFICATION","subtype":"VLAN_ID","vlanId":22}, | ||
16 | + {"type":"L2MODIFICATION","subtype":"VLAN_PCP","vlanPcp":1}, | ||
17 | + {"type":"L2MODIFICATION","subtype":"MPLS_LABEL","label":777}, | ||
18 | + {"type":"L2MODIFICATION","subtype":"MPLS_PUSH"}, | ||
19 | + {"type":"L2MODIFICATION","subtype":"MPLS_POP"}, | ||
20 | + {"type":"L2MODIFICATION","subtype":"DEC_MPLS_TTL"}, | ||
21 | + {"type":"L2MODIFICATION","subtype":"VLAN_POP"}, | ||
22 | + {"type":"L2MODIFICATION","subtype":"VLAN_PUSH"}, | ||
23 | + {"type":"L3MODIFICATION","subtype":"IPV4_SRC", "ip":"1.2.3.4"}, | ||
24 | + {"type":"L3MODIFICATION","subtype":"IPV4_DST", "ip":"1.2.3.3"}, | ||
25 | + {"type":"L3MODIFICATION","subtype":"IPV6_SRC", "ip":"1.2.3.2"}, | ||
26 | + {"type":"L3MODIFICATION","subtype":"IPV6_DST", "ip":"1.2.3.1"}, | ||
27 | + {"type":"L3MODIFICATION","subtype":"IPV6_FLABEL", "flowLabel":8}, | ||
28 | + {"type":"L0MODIFICATION","subtype":"LAMBDA","lambda":7}, | ||
29 | + {"type":"L0MODIFICATION","subtype":"OCH","gridType":"DWDM", | ||
30 | + "channelSpacing":"CHL_100GHZ","spacingMultiplier":4,"slotGranularity":8} | ||
31 | + ], | ||
32 | + "deferred":[] | ||
33 | + }, | ||
34 | + "selector": {"criteria":[{"type":"ETH_TYPE","ethType":2054}]} | ||
35 | +} |
1 | +{ | ||
2 | + "appId":-29467, | ||
3 | + "priority":1, | ||
4 | + "isPermanent":"false", | ||
5 | + "timeout":1, | ||
6 | + "deviceId":"of:0000000000000001", | ||
7 | + "selector": | ||
8 | + {"criteria": | ||
9 | + [ | ||
10 | + {"type":"OCH_SIGID", | ||
11 | + "ochSignalId": | ||
12 | + { | ||
13 | + "gridType":"CWDM", | ||
14 | + "channelSpacing":"CHL_25GHZ", | ||
15 | + "spacingMultiplier":3, | ||
16 | + "slotGranularity":4 | ||
17 | + } | ||
18 | + } | ||
19 | + ] | ||
20 | + } | ||
21 | +} |
... | @@ -123,7 +123,7 @@ public abstract class Tools { | ... | @@ -123,7 +123,7 @@ public abstract class Tools { |
123 | } | 123 | } |
124 | 124 | ||
125 | /** | 125 | /** |
126 | - * Returns the specified item if that items is null; otherwise throws | 126 | + * Returns the specified item if that item is not null; otherwise throws |
127 | * not found exception. | 127 | * not found exception. |
128 | * | 128 | * |
129 | * @param item item to check | 129 | * @param item item to check |
... | @@ -140,6 +140,23 @@ public abstract class Tools { | ... | @@ -140,6 +140,23 @@ public abstract class Tools { |
140 | } | 140 | } |
141 | 141 | ||
142 | /** | 142 | /** |
143 | + * Returns the specified item if that item is not null; otherwise throws | ||
144 | + * bad argument exception. | ||
145 | + * | ||
146 | + * @param item item to check | ||
147 | + * @param message not found message | ||
148 | + * @param <T> item type | ||
149 | + * @return item if not null | ||
150 | + * @throws IllegalArgumentException if item is null | ||
151 | + */ | ||
152 | + public static <T> T nullIsIllegal(T item, String message) { | ||
153 | + if (item == null) { | ||
154 | + throw new IllegalArgumentException(message); | ||
155 | + } | ||
156 | + return item; | ||
157 | + } | ||
158 | + | ||
159 | + /** | ||
143 | * Converts a string from hex to long. | 160 | * Converts a string from hex to long. |
144 | * | 161 | * |
145 | * @param string hex number in string form; sans 0x | 162 | * @param string hex number in string form; sans 0x | ... | ... |
web/api/src/main/java/org/onosproject/rest/exceptions/IllegalArgumentExceptionMapper.java
0 → 100644
1 | +/* | ||
2 | + * Copyright 2014-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.rest.exceptions; | ||
17 | + | ||
18 | +import javax.ws.rs.core.Response; | ||
19 | + | ||
20 | +/** | ||
21 | + * Mapper for illegal argument exceptions to the BAD_REQUEST response code. | ||
22 | + */ | ||
23 | +public class IllegalArgumentExceptionMapper extends AbstractMapper<IllegalArgumentException> { | ||
24 | + @Override | ||
25 | + protected Response.Status responseStatus() { | ||
26 | + return Response.Status.BAD_REQUEST; | ||
27 | + } | ||
28 | +} | ||
29 | + |
... | @@ -15,22 +15,29 @@ | ... | @@ -15,22 +15,29 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.rest.resources; | 16 | package org.onosproject.rest.resources; |
17 | 17 | ||
18 | -import com.fasterxml.jackson.databind.node.ArrayNode; | 18 | +import java.io.IOException; |
19 | -import com.fasterxml.jackson.databind.node.ObjectNode; | 19 | +import java.io.InputStream; |
20 | + | ||
21 | +import javax.ws.rs.Consumes; | ||
22 | +import javax.ws.rs.GET; | ||
23 | +import javax.ws.rs.POST; | ||
24 | +import javax.ws.rs.Path; | ||
25 | +import javax.ws.rs.PathParam; | ||
26 | +import javax.ws.rs.Produces; | ||
27 | +import javax.ws.rs.core.MediaType; | ||
28 | +import javax.ws.rs.core.Response; | ||
29 | + | ||
20 | import org.onlab.util.ItemNotFoundException; | 30 | import org.onlab.util.ItemNotFoundException; |
21 | import org.onosproject.net.Device; | 31 | import org.onosproject.net.Device; |
22 | import org.onosproject.net.DeviceId; | 32 | import org.onosproject.net.DeviceId; |
23 | import org.onosproject.net.device.DeviceService; | 33 | import org.onosproject.net.device.DeviceService; |
24 | import org.onosproject.net.flow.FlowEntry; | 34 | import org.onosproject.net.flow.FlowEntry; |
35 | +import org.onosproject.net.flow.FlowRule; | ||
25 | import org.onosproject.net.flow.FlowRuleService; | 36 | import org.onosproject.net.flow.FlowRuleService; |
26 | import org.onosproject.rest.AbstractWebResource; | 37 | import org.onosproject.rest.AbstractWebResource; |
27 | 38 | ||
28 | -import javax.ws.rs.GET; | 39 | +import com.fasterxml.jackson.databind.node.ArrayNode; |
29 | -import javax.ws.rs.Path; | 40 | +import com.fasterxml.jackson.databind.node.ObjectNode; |
30 | -import javax.ws.rs.PathParam; | ||
31 | -import javax.ws.rs.Produces; | ||
32 | -import javax.ws.rs.core.MediaType; | ||
33 | -import javax.ws.rs.core.Response; | ||
34 | 41 | ||
35 | /** | 42 | /** |
36 | * REST resource for interacting with the inventory of flows. | 43 | * REST resource for interacting with the inventory of flows. |
... | @@ -113,4 +120,27 @@ public class FlowsWebResource extends AbstractWebResource { | ... | @@ -113,4 +120,27 @@ public class FlowsWebResource extends AbstractWebResource { |
113 | } | 120 | } |
114 | return ok(root).build(); | 121 | return ok(root).build(); |
115 | } | 122 | } |
123 | + | ||
124 | + /** | ||
125 | + * Creates a flow rule from a POST of a JSON string and attempts to apply it. | ||
126 | + * | ||
127 | + * @param stream input JSON | ||
128 | + * @return status of the request - ACCEPTED if the JSON is correct, | ||
129 | + * BAD_REQUEST if the JSON is invalid | ||
130 | + */ | ||
131 | + @POST | ||
132 | + @Consumes(MediaType.APPLICATION_JSON) | ||
133 | + @Produces(MediaType.APPLICATION_JSON) | ||
134 | + public Response createFlow(InputStream stream) { | ||
135 | + try { | ||
136 | + FlowRuleService service = get(FlowRuleService.class); | ||
137 | + ObjectNode root = (ObjectNode) mapper().readTree(stream); | ||
138 | + FlowRule rule = codec(FlowRule.class).decode(root, this); | ||
139 | + service.applyFlowRules(rule); | ||
140 | + } catch (IOException ex) { | ||
141 | + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build(); | ||
142 | + } | ||
143 | + return Response.status(Response.Status.ACCEPTED).build(); | ||
144 | + } | ||
145 | + | ||
116 | } | 146 | } | ... | ... |
... | @@ -61,6 +61,7 @@ | ... | @@ -61,6 +61,7 @@ |
61 | org.onosproject.rest.exceptions.ServerErrorMapper, | 61 | org.onosproject.rest.exceptions.ServerErrorMapper, |
62 | org.onosproject.rest.exceptions.BadRequestMapper, | 62 | org.onosproject.rest.exceptions.BadRequestMapper, |
63 | org.onosproject.rest.exceptions.WebApplicationExceptionMapper, | 63 | org.onosproject.rest.exceptions.WebApplicationExceptionMapper, |
64 | + org.onosproject.rest.exceptions.IllegalArgumentExceptionMapper, | ||
64 | org.onosproject.rest.resources.JsonBodyWriter, | 65 | org.onosproject.rest.resources.JsonBodyWriter, |
65 | 66 | ||
66 | org.onosproject.rest.resources.ApplicationsWebResource, | 67 | org.onosproject.rest.resources.ApplicationsWebResource, | ... | ... |
... | @@ -15,10 +15,13 @@ | ... | @@ -15,10 +15,13 @@ |
15 | */ | 15 | */ |
16 | package org.onosproject.rest; | 16 | package org.onosproject.rest; |
17 | 17 | ||
18 | +import java.net.HttpURLConnection; | ||
18 | import java.util.HashMap; | 19 | import java.util.HashMap; |
19 | import java.util.HashSet; | 20 | import java.util.HashSet; |
20 | import java.util.Set; | 21 | import java.util.Set; |
21 | 22 | ||
23 | +import javax.ws.rs.core.MediaType; | ||
24 | + | ||
22 | import org.hamcrest.Description; | 25 | import org.hamcrest.Description; |
23 | import org.hamcrest.TypeSafeMatcher; | 26 | import org.hamcrest.TypeSafeMatcher; |
24 | import org.junit.After; | 27 | import org.junit.After; |
... | @@ -30,11 +33,13 @@ import org.onlab.packet.MacAddress; | ... | @@ -30,11 +33,13 @@ import org.onlab.packet.MacAddress; |
30 | import org.onlab.rest.BaseResource; | 33 | import org.onlab.rest.BaseResource; |
31 | import org.onosproject.codec.CodecService; | 34 | import org.onosproject.codec.CodecService; |
32 | import org.onosproject.codec.impl.CodecManager; | 35 | import org.onosproject.codec.impl.CodecManager; |
36 | +import org.onosproject.core.CoreService; | ||
33 | import org.onosproject.core.DefaultGroupId; | 37 | import org.onosproject.core.DefaultGroupId; |
34 | import org.onosproject.core.GroupId; | 38 | import org.onosproject.core.GroupId; |
35 | import org.onosproject.net.DefaultDevice; | 39 | import org.onosproject.net.DefaultDevice; |
36 | import org.onosproject.net.Device; | 40 | import org.onosproject.net.Device; |
37 | import org.onosproject.net.DeviceId; | 41 | import org.onosproject.net.DeviceId; |
42 | +import org.onosproject.net.NetTestTools; | ||
38 | import org.onosproject.net.device.DeviceService; | 43 | import org.onosproject.net.device.DeviceService; |
39 | import org.onosproject.net.flow.DefaultTrafficSelector; | 44 | import org.onosproject.net.flow.DefaultTrafficSelector; |
40 | import org.onosproject.net.flow.DefaultTrafficTreatment; | 45 | import org.onosproject.net.flow.DefaultTrafficTreatment; |
... | @@ -51,12 +56,15 @@ import org.onosproject.net.flow.instructions.Instructions; | ... | @@ -51,12 +56,15 @@ import org.onosproject.net.flow.instructions.Instructions; |
51 | import com.eclipsesource.json.JsonArray; | 56 | import com.eclipsesource.json.JsonArray; |
52 | import com.eclipsesource.json.JsonObject; | 57 | import com.eclipsesource.json.JsonObject; |
53 | import com.google.common.collect.ImmutableSet; | 58 | import com.google.common.collect.ImmutableSet; |
59 | +import com.sun.jersey.api.client.ClientResponse; | ||
54 | import com.sun.jersey.api.client.UniformInterfaceException; | 60 | import com.sun.jersey.api.client.UniformInterfaceException; |
55 | import com.sun.jersey.api.client.WebResource; | 61 | import com.sun.jersey.api.client.WebResource; |
56 | 62 | ||
57 | import static org.easymock.EasyMock.anyObject; | 63 | import static org.easymock.EasyMock.anyObject; |
64 | +import static org.easymock.EasyMock.anyShort; | ||
58 | import static org.easymock.EasyMock.createMock; | 65 | import static org.easymock.EasyMock.createMock; |
59 | import static org.easymock.EasyMock.expect; | 66 | import static org.easymock.EasyMock.expect; |
67 | +import static org.easymock.EasyMock.expectLastCall; | ||
60 | import static org.easymock.EasyMock.replay; | 68 | import static org.easymock.EasyMock.replay; |
61 | import static org.easymock.EasyMock.verify; | 69 | import static org.easymock.EasyMock.verify; |
62 | import static org.hamcrest.Matchers.containsString; | 70 | import static org.hamcrest.Matchers.containsString; |
... | @@ -72,6 +80,8 @@ import static org.junit.Assert.fail; | ... | @@ -72,6 +80,8 @@ import static org.junit.Assert.fail; |
72 | */ | 80 | */ |
73 | public class FlowsResourceTest extends ResourceTest { | 81 | public class FlowsResourceTest extends ResourceTest { |
74 | final FlowRuleService mockFlowService = createMock(FlowRuleService.class); | 82 | final FlowRuleService mockFlowService = createMock(FlowRuleService.class); |
83 | + CoreService mockCoreService = createMock(CoreService.class); | ||
84 | + | ||
75 | final HashMap<DeviceId, Set<FlowEntry>> rules = new HashMap<>(); | 85 | final HashMap<DeviceId, Set<FlowEntry>> rules = new HashMap<>(); |
76 | 86 | ||
77 | final DeviceService mockDeviceService = createMock(DeviceService.class); | 87 | final DeviceService mockDeviceService = createMock(DeviceService.class); |
... | @@ -245,6 +255,11 @@ public class FlowsResourceTest extends ResourceTest { | ... | @@ -245,6 +255,11 @@ public class FlowsResourceTest extends ResourceTest { |
245 | expect(mockDeviceService.getDevices()) | 255 | expect(mockDeviceService.getDevices()) |
246 | .andReturn(ImmutableSet.of(device1, device2)); | 256 | .andReturn(ImmutableSet.of(device1, device2)); |
247 | 257 | ||
258 | + // Mock Core Service | ||
259 | + expect(mockCoreService.getAppId(anyShort())) | ||
260 | + .andReturn(NetTestTools.APP_ID).anyTimes(); | ||
261 | + replay(mockCoreService); | ||
262 | + | ||
248 | // Register the services needed for the test | 263 | // Register the services needed for the test |
249 | final CodecManager codecService = new CodecManager(); | 264 | final CodecManager codecService = new CodecManager(); |
250 | codecService.activate(); | 265 | codecService.activate(); |
... | @@ -252,7 +267,8 @@ public class FlowsResourceTest extends ResourceTest { | ... | @@ -252,7 +267,8 @@ public class FlowsResourceTest extends ResourceTest { |
252 | new TestServiceDirectory() | 267 | new TestServiceDirectory() |
253 | .add(FlowRuleService.class, mockFlowService) | 268 | .add(FlowRuleService.class, mockFlowService) |
254 | .add(DeviceService.class, mockDeviceService) | 269 | .add(DeviceService.class, mockDeviceService) |
255 | - .add(CodecService.class, codecService); | 270 | + .add(CodecService.class, codecService) |
271 | + .add(CoreService.class, mockCoreService); | ||
256 | 272 | ||
257 | BaseResource.setServiceDirectory(testDirectory); | 273 | BaseResource.setServiceDirectory(testDirectory); |
258 | } | 274 | } |
... | @@ -263,6 +279,7 @@ public class FlowsResourceTest extends ResourceTest { | ... | @@ -263,6 +279,7 @@ public class FlowsResourceTest extends ResourceTest { |
263 | @After | 279 | @After |
264 | public void tearDownTest() { | 280 | public void tearDownTest() { |
265 | verify(mockFlowService); | 281 | verify(mockFlowService); |
282 | + verify(mockCoreService); | ||
266 | } | 283 | } |
267 | 284 | ||
268 | /** | 285 | /** |
... | @@ -542,4 +559,27 @@ public class FlowsResourceTest extends ResourceTest { | ... | @@ -542,4 +559,27 @@ public class FlowsResourceTest extends ResourceTest { |
542 | containsString("returned a response status of")); | 559 | containsString("returned a response status of")); |
543 | } | 560 | } |
544 | } | 561 | } |
562 | + | ||
563 | + /** | ||
564 | + * Tests creating a flow with POST. | ||
565 | + */ | ||
566 | + @Test | ||
567 | + public void testPost() { | ||
568 | + String json = "{\"appId\":2,\"priority\":1,\"isPermanent\":true," | ||
569 | + + "\"deviceId\":\"of:0000000000000001\"," | ||
570 | + + "\"treatment\":{\"instructions\":[ {\"type\":\"OUTPUT\",\"port\":2}]}," | ||
571 | + + "\"selector\":{\"criteria\":[ {\"type\":\"ETH_TYPE\",\"ethType\":2054}]}}"; | ||
572 | + | ||
573 | + mockFlowService.applyFlowRules(anyObject()); | ||
574 | + expectLastCall(); | ||
575 | + replay(mockFlowService); | ||
576 | + | ||
577 | + WebResource rs = resource(); | ||
578 | + | ||
579 | + | ||
580 | + ClientResponse response = rs.path("flows/") | ||
581 | + .type(MediaType.APPLICATION_JSON_TYPE) | ||
582 | + .post(ClientResponse.class, json); | ||
583 | + assertThat(response.getStatus(), is(HttpURLConnection.HTTP_ACCEPTED)); | ||
584 | + } | ||
545 | } | 585 | } | ... | ... |
-
Please register or login to post a comment