--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>\r
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">\r
+ <modelVersion>4.0.0</modelVersion>\r
+ <parent>\r
+ <groupId>org.opendaylight.controller</groupId>\r
+ <artifactId>commons.opendaylight</artifactId>\r
+ <version>1.4.0-SNAPSHOT</version>\r
+ <relativePath>../../commons/opendaylight</relativePath>\r
+ </parent>\r
+\r
+ <artifactId>concepts</artifactId>\r
+ <version>0.5.0-SNAPSHOT</version>\r
+ <packaging>bundle</packaging>\r
+\r
+ <build>\r
+ <plugins>\r
+ <plugin>\r
+ <groupId>org.apache.felix</groupId>\r
+ <artifactId>maven-bundle-plugin</artifactId>\r
+ <version>2.3.6</version>\r
+ <extensions>true</extensions>\r
+ <configuration>\r
+ <instructions>\r
+ <Import-Package>\r
+ org.slf4j,\r
+ org.osgi.framework,\r
+ org.apache.commons.lang3.builder,\r
+ org.apache.felix.dm,\r
+ org.apache.commons.lang3.tuple,\r
+ javax.xml.bind.annotation,\r
+ javax.xml.bind.annotation.adapters\r
+ </Import-Package>\r
+ <Export-Package>\r
+ org.opendaylight.controller.concepts.transform\r
+ </Export-Package>\r
+ </instructions>\r
+ <manifestLocation>${project.basedir}/META-INF</manifestLocation>\r
+ </configuration>\r
+ </plugin>\r
+ </plugins>\r
+ </build>\r
+ <dependencies>\r
+ <dependency>\r
+ <groupId>junit</groupId>\r
+ <artifactId>junit</artifactId>\r
+ <version>4.8.1</version>\r
+ <scope>test</scope>\r
+ </dependency>\r
+ </dependencies>\r
+</project>\r
--- /dev/null
+\r
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.concepts.tranform;\r
+\r
+public interface Acceptor<I> {\r
+\r
+ /**\r
+ * \r
+ * @param input\r
+ * @return true if input is accepted.\r
+ */\r
+ boolean isAcceptable(I input);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.concepts.tranform;\r
+\r
+import java.util.Collection;\r
+/**\r
+ * \r
+ * @author Tony Tkacik\r
+ *\r
+ * @param <I>\r
+ * @param <P>\r
+ */\r
+public interface AggregateTransformer<I,P> extends Transformer<I,P> {\r
+\r
+ Collection<P> transformAll(Collection<? extends I> inputs);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.concepts.tranform;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Map;\r
+import java.util.concurrent.ConcurrentHashMap;\r
+\r
+\r
+/**\r
+ * Transformer which aggregates multiple implementations of\r
+ * {@link InputClassBasedTransformer}.\r
+ * \r
+ * The transformation process is driven by {@link Class} of input. The selection\r
+ * of used {@link InputClassBasedTransformer} is done by using the {@link Class}\r
+ * of input as a key to select the transformer.\r
+ * \r
+ * This approach provides quick resolution of transformer, but does not support\r
+ * registering a super type of input to provide transformation support for all\r
+ * subclasses, one must register a new instance of transformer for each valid\r
+ * input class.\r
+ * \r
+ * If you need more flexible selection of transformation consider using\r
+ * {@link CompositeConditionalTransformer} which is slower but most flexible or\r
+ * {@link RuleBasedTransformer} which provides declarative approach for\r
+ * transformation.\r
+ * \r
+ * See {@link #transform(Object)} for more information about tranformation\r
+ * process.\r
+ * \r
+ * @author Tony Tkacik <ttkacik@cisco.com>\r
+ * \r
+ * @param <I>\r
+ * Input super-type\r
+ * @param <P>\r
+ * Product\r
+ */\r
+public abstract class CompositeClassBasedTransformer<I, P> implements\r
+ InputClassBasedTransformer<I, I, P>,\r
+ AggregateTransformer<I, P> {\r
+\r
+ private Map<Class<? extends I>, InputClassBasedTransformer<I, ? extends I, P>> transformers = new ConcurrentHashMap<Class<? extends I>, InputClassBasedTransformer<I, ? extends I, P>>();\r
+\r
+ /**\r
+ * Transforms an input into instance of Product class.\r
+ * \r
+ * The final registered transformer is the one which match following\r
+ * condition:\r
+ * \r
+ * <code>input.getClass() == transformer.getInputClass()</code>\r
+ * \r
+ * This means that transformers are not resolved by class hierarchy, only\r
+ * selected based on final class of the input. If you need more flexible\r
+ * selection of transformation consider using\r
+ * {@link CompositeConditionalTransformer} which is slower but more\r
+ * flexible.\r
+ * \r
+ */\r
+ @Override\r
+ public P transform(I input) {\r
+ @SuppressWarnings("unchecked")\r
+ InputClassBasedTransformer<I, I, P> transformer = (InputClassBasedTransformer<I, I, P>) transformers\r
+ .get(input.getClass());\r
+ if (transformer == null)\r
+ throw new IllegalArgumentException("Transformation of: " + input\r
+ + " is not supported");\r
+ return transformer.transform(input);\r
+ }\r
+\r
+ /**\r
+ * Registers a new transformer.\r
+ * \r
+ * The transformer is registered for class returned by\r
+ * {@link InputClassBasedTransformer#getInputClass()}. Only one transformer\r
+ * can be registered for particular input class.\r
+ * \r
+ */\r
+ public void addTransformer(\r
+ InputClassBasedTransformer<I, ? extends I, P> transformer)\r
+ throws IllegalStateException {\r
+ if (transformer == null)\r
+ throw new IllegalArgumentException("Transformer should not be null");\r
+ if (transformer.getInputClass() == null)\r
+ throw new IllegalArgumentException(\r
+ "Transformer should specify input class.");\r
+ transformers.put(transformer.getInputClass(), transformer);\r
+ }\r
+\r
+ /**\r
+ * Removes an registered transformer.\r
+ * \r
+ * Note: Removal is currently unsupported.\r
+ * \r
+ * @param transformer\r
+ * Tranformer to be removed.\r
+ * @throws IllegalArgumentException\r
+ * If the provided transformer is null or is not registered.\r
+ */\r
+ public void removeTransformer(\r
+ InputClassBasedTransformer<I, ? extends I, P> transformer)\r
+ throws IllegalArgumentException {\r
+ throw new UnsupportedOperationException("Not implemented yet");\r
+ }\r
+ \r
+ @Override\r
+ public Collection<P> transformAll(Collection<? extends I> inputs) {\r
+ Collection<P> ret = new ArrayList<P>();\r
+ for (I i : inputs) {\r
+ ret.add(transform(i));\r
+ }\r
+ return ret;\r
+ }\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.concepts.tranform;\r
+\r
+import java.util.ArrayList;\r
+import java.util.Collection;\r
+import java.util.Comparator;\r
+import java.util.Set;\r
+import java.util.TreeSet;\r
+\r
+/**\r
+ * Composite transformer which aggregates multiple implementation and selects\r
+ * the one which accepts the input.\r
+ * \r
+ * \r
+ * @author Tony Tkacik\r
+ * \r
+ * @param <I>\r
+ * Input class for transformation\r
+ * @param <P>\r
+ * Product of transformation\r
+ */\r
+public class CompositeConditionalTransformer<I, P> implements\r
+ SimpleConditionalTransformer<I, P>,\r
+ AggregateTransformer<I,P> {\r
+\r
+ private final Comparator<TransformerWithPriority<I, P>> comparator = new Comparator<TransformerWithPriority<I, P>>() {\r
+\r
+ @Override\r
+ public int compare(TransformerWithPriority<I, P> o1,\r
+ TransformerWithPriority<I, P> o2) {\r
+ return Integer.compare(o1.priority, o2.priority);\r
+ }\r
+\r
+ };\r
+ private final Set<TransformerWithPriority<I, P>> transformers;\r
+\r
+ public CompositeConditionalTransformer() {\r
+ // FIXME: Add Ordering\r
+ transformers = new TreeSet<TransformerWithPriority<I, P>>(comparator);\r
+ }\r
+\r
+ @Override\r
+ public boolean isAcceptable(I input) {\r
+ for (SimpleConditionalTransformer<I, P> trans : transformers) {\r
+ if (trans.isAcceptable(input)) {\r
+ return true;\r
+ }\r
+ }\r
+ return false;\r
+ }\r
+\r
+ @Override\r
+ public P transform(I input) {\r
+ for (SimpleConditionalTransformer<I, P> trans : transformers) {\r
+ if (trans.isAcceptable(input)) {\r
+ return trans.transform(input);\r
+ }\r
+ }\r
+ throw new IllegalStateException(\r
+ "Transformer for provided input is not available.");\r
+ }\r
+\r
+ public void addTransformer(SimpleConditionalTransformer<I, P> transformer,\r
+ int priority) throws IllegalStateException {\r
+ if (transformer == null) {\r
+ throw new IllegalArgumentException(\r
+ "transformer should not be null.");\r
+ }\r
+ TransformerWithPriority<I, P> withPriority = new TransformerWithPriority<I, P>(\r
+ transformer, priority);\r
+ if (false == transformers.add(withPriority)) {\r
+ throw new IllegalStateException("transformer " + transformer\r
+ + "already registered");\r
+ }\r
+ }\r
+\r
+ public void removeTransformer(SimpleConditionalTransformer<I, P> transformer)\r
+ throws IllegalArgumentException {\r
+ if (transformer == null) {\r
+ throw new IllegalArgumentException(\r
+ "transformer should not be null.");\r
+ }\r
+ if (false == transformers.remove(transformer)) {\r
+ throw new IllegalStateException("transformer " + transformer\r
+ + "already registered");\r
+ }\r
+ }\r
+\r
+ @Override\r
+ public Collection<P> transformAll(Collection<? extends I> inputs) {\r
+ Collection<P> ret = new ArrayList<P>();\r
+ for (I i : inputs) {\r
+ ret.add(transform(i));\r
+ }\r
+ return ret;\r
+ }\r
+\r
+ private static class TransformerWithPriority<I, P> implements\r
+ SimpleConditionalTransformer<I, P> {\r
+ final int priority;\r
+ final SimpleConditionalTransformer<I, P> transformer;\r
+ \r
+ public TransformerWithPriority(\r
+ SimpleConditionalTransformer<I, P> transformer, int priority) {\r
+ this.priority = priority;\r
+ this.transformer = transformer;\r
+ }\r
+ \r
+ @Override\r
+ public int hashCode() {\r
+ final int prime = 31;\r
+ int result = 1;\r
+ result = prime * result\r
+ + ((transformer == null) ? 0 : transformer.hashCode());\r
+ return result;\r
+ }\r
+ \r
+ @Override\r
+ public boolean equals(Object obj) {\r
+ if (this == obj)\r
+ return true;\r
+ if (obj == null)\r
+ return false;\r
+ if (getClass() != obj.getClass())\r
+ return false;\r
+ TransformerWithPriority<?,?> other = (TransformerWithPriority<?,?>) obj;\r
+ if (transformer == null) {\r
+ if (other.transformer != null)\r
+ return false;\r
+ } else if (!transformer.equals(other.transformer))\r
+ return false;\r
+ return true;\r
+ }\r
+ \r
+ @Override\r
+ public boolean isAcceptable(I input) {\r
+ return transformer.isAcceptable(input);\r
+ }\r
+ \r
+ @Override\r
+ public P transform(I input) {\r
+ return transformer.transform(input);\r
+ }\r
+ \r
+ \r
+ \r
+ \r
+ \r
+ }\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.concepts.tranform;\r
+\r
+/**\r
+ * Input class based transformer\r
+ * \r
+ * {@link Transformer} which accepts / transforms only specific classes of\r
+ * input, and is useful if the selection of transformer should be based on the\r
+ * class of the input and there is one-to-one mapping between input class and\r
+ * transformer.\r
+ * \r
+ * \r
+ * @author Tony Tkacik\r
+ * \r
+ * @param <S>\r
+ * Common supertype of input\r
+ * @param <I>\r
+ * Concrete type of input\r
+ * @param <P>\r
+ * Product\r
+ */\r
+public interface InputClassBasedTransformer<S, I extends S, P> extends\r
+ Transformer<I, P> {\r
+\r
+ /**\r
+ * Returns an {@link Class} of input which is acceptable for transformation.\r
+ * \r
+ * @return {@link Class} of input which is acceptable for transformation.\r
+ */\r
+ Class<? extends S> getInputClass();\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.concepts.tranform;\r
+\r
+import java.util.Set;\r
+\r
+/**\r
+ * Transformer with set of acceptance rules\r
+ * \r
+ * The transformer provides a set of {@link Acceptor}s, which could be used to\r
+ * verify if the input will produce result using the transformer.\r
+ * \r
+ * The transormer is able to produce result if ANY of associated\r
+ * {@link Acceptor}s accepted result.\r
+ * \r
+ * @author Tony Tkacik\r
+ * \r
+ * @param <I>\r
+ * Input class for transformation\r
+ * @param <P>\r
+ * Product of transformation\r
+ */\r
+public interface RuleBasedTransformer<I, P> extends Transformer<I, P> {\r
+\r
+ /**\r
+ * Set of {@link Acceptor}, which could be used to verify if the input is\r
+ * usable by transformer.\r
+ * \r
+ * The transformer is able to produce result if ANY of associated\r
+ * {@link Acceptor}s accepted result.\r
+ * \r
+ * @return Set of input acceptance rules associated to this transformer.\r
+ */\r
+ Set<Acceptor<I>> getRules();\r
+\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.concepts.tranform;\r
+\r
+/**\r
+ * Simple condition-based transformer\r
+ * \r
+ * The transformer provides {@link #isAcceptable(Object)} method,\r
+ * which could be used to query transformer if the input will produce\r
+ * result.\r
+ * \r
+ * This interface is simplified version of {@link RuleBasedTransformer} - does not\r
+ * provide decoupling of Acceptance rule from transformer, and should be used only\r
+ * for simple use-cases.\r
+ * \r
+ * @author Tony Tkacik\r
+ *\r
+ * @param <I> Input class for transformation\r
+ * @param <P> Product of transformation\r
+ */\r
+public interface SimpleConditionalTransformer<I,P> extends Transformer<I, P>, Acceptor<I> {\r
+\r
+\r
+ /**\r
+ * Checks if the input is acceptable \r
+ * for processing by the transformer.\r
+ * \r
+ * @return true it the input is acceptable for processing by transformer.\r
+ */\r
+ @Override\r
+ public boolean isAcceptable(I input);\r
+}\r
--- /dev/null
+/*\r
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.\r
+ *\r
+ * This program and the accompanying materials are made available under the\r
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,\r
+ * and is available at http://www.eclipse.org/legal/epl-v10.html\r
+ */\r
+\r
+package org.opendaylight.controller.concepts.tranform;\r
+\r
+/**\r
+ * Factory which produces product based on input object\r
+ * \r
+ * @author Tony Tkacik\r
+ *\r
+ * @param <I> Input\r
+ * @param <P> Product\r
+ */\r
+public interface Transformer<I,P> {\r
+ /**\r
+ * Transforms input into instance of product.\r
+ * \r
+ * @param input Input which drives transformation\r
+ * @return Instance of product which was created from supplied input.\r
+ */\r
+ P transform(I input);\r
+}\r
<module>../../samples/simpleforwarding</module>
<module>../../samples/loadbalancer</module>
<module>../../samples/northbound/loadbalancer</module>
+ <module>../../commons/concepts</module>
</modules>
<build>
private String getJsonResult(String restUrl, String method) {
// initialize response code to indicate error
httpResponseCode = 400;
-
+
try {
- URL url = new URL(restUrl);
-
- this.users.getAuthorizationList();
- this.users.authenticate("admin", "admin");
- String authString = "admin:admin";
- byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
- String authStringEnc = new String(authEncBytes);
-
- HttpURLConnection connection = (HttpURLConnection)url.openConnection();
- connection.setRequestMethod(method);
- connection.setRequestProperty("Authorization", "Basic "
- + authStringEnc);
- connection.setRequestProperty("Content-Type", "application/json");
- connection.setRequestProperty("Accept", "application/json");
-
- connection.connect();
- connection.getContentType();
-
- // Response code for success should be 2xx
- httpResponseCode = connection.getResponseCode();
-
- InputStream is = connection.getInputStream();
- BufferedReader rd = new BufferedReader(new InputStreamReader(is,
- Charset.forName("UTF-8")));
- StringBuilder sb = new StringBuilder();
- int cp;
- while ((cp = rd.read()) != -1) {
- sb.append((char) cp);
- }
- is.close();
- connection.disconnect();
- return sb.toString();
- } catch (Exception e) {
- return null;
- }
-
- }
+ URL url = new URL(restUrl);
+
+ this.users.getAuthorizationList();
+ this.users.authenticate("admin", "admin");
+ String authString = "admin:admin";
+ byte[] authEncBytes = Base64.encodeBase64(authString.getBytes());
+ String authStringEnc = new String(authEncBytes);
+
+ HttpURLConnection connection = (HttpURLConnection) url
+ .openConnection();
+ connection.setRequestMethod(method);
+ connection.setRequestProperty("Authorization", "Basic "
+ + authStringEnc);
+ connection.setRequestProperty("Content-Type", "application/json");
+ connection.setRequestProperty("Accept", "application/json");
+
+ connection.connect();
+ connection.getContentType();
+
+ // Response code for success should be 2xx
+ httpResponseCode = connection.getResponseCode();
+
+ InputStream is = connection.getInputStream();
+ BufferedReader rd = new BufferedReader(new InputStreamReader(is,
+ Charset.forName("UTF-8")));
+ StringBuilder sb = new StringBuilder();
+ int cp;
+ while ((cp = rd.read()) != -1) {
+ sb.append((char) cp);
+ }
+ is.close();
+ connection.disconnect();
+ return sb.toString();
+ } catch (Exception e) {
+ return null;
+ }
+
+ }
@Test
public void testStatistics() {
-
+ String actionTypes[] = { "drop", "loopback", "flood", "floodAll",
+ "controller", "swPath", "hwPath", "output", "setDlSrc",
+ "setDlDst", "setDlType", "setVlanId", "setVlanPcp",
+ "setVlanCfi", "popVlan", "pushVlan", "setNwSrc", "setNwDst",
+ "setNwTos", "setTpSrc", "setTpDst" };
System.out.println("Starting Statistics JAXB client.");
String baseURL = "http://127.0.0.1:8080/controller/nb/v2/statistics/default/";
try {
- String actionTypes[] = { "drop", "loopback", "flood", "floodAll",
- "controller", "swPath", "hwPath", "output", "setDlSrc",
- "setDlDst", "setDlType", "setVlanId", "setVlanPcp",
- "setVlanCfi", "popVlan", "pushVlan", "setNwSrc",
- "setNwDst", "setNwTos", "setTpSrc", "setTpDst" };
String result = getJsonResult(baseURL + "flowstats");
JSONTokener jt = new JSONTokener(result);
JSONObject json = new JSONObject(jt);
for (int i = 0; i < flowStats.length(); i++) {
JSONObject flowStat = flowStats.getJSONObject(i);
- Assert.assertTrue(flowStat.getInt("tableId") == 1);
- Assert.assertTrue(flowStat.getInt("durationSeconds") == 40);
- Assert.assertTrue(flowStat.getInt("durationNanoseconds") == 400);
- Assert.assertTrue(flowStat.getInt("packetCount") == 200);
- Assert.assertTrue(flowStat.getInt("byteCount") == 100);
-
- // test that flow information is correct
- JSONObject flow = flowStat.getJSONObject("flow");
- Assert.assertTrue(flow.getInt("priority") == 3500);
- Assert.assertTrue(flow.getInt("idleTimeout") == 1000);
- Assert.assertTrue(flow.getInt("hardTimeout") == 2000);
- Assert.assertTrue(flow.getInt("id") == 12345);
-
- JSONObject match = (flow.getJSONObject("match")
- .getJSONObject("matchField"));
- Assert.assertTrue(match.getString("type").equals("NW_DST"));
- Assert.assertTrue(match.getString("value").equals("1.1.1.1"));
-
- JSONObject act = flow.getJSONObject("actions");
- Assert.assertTrue(act.getString("@type").equals(actionTypes[i]));
-
- if (act.getString("@type").equals("output")) {
- JSONObject port = act.getJSONObject("port");
- JSONObject port_node = port.getJSONObject("node");
- Assert.assertTrue(port.getInt("@id") == 51966);
- Assert.assertTrue(port.getString("@type").equals("STUB"));
- Assert.assertTrue(port_node.getInt("@id") == 51966);
- Assert.assertTrue(port_node.getString("@type").equals(
- "STUB"));
- }
-
- if (act.getString("@type").equals("setDlSrc")) {
- byte srcMatch[] = { (byte) 5, (byte) 4, (byte) 3, (byte) 2,
- (byte) 1 };
- String src = act.getString("address");
- byte srcBytes[] = new byte[5];
- srcBytes[0] = Byte.parseByte(src.substring(0, 2));
- srcBytes[1] = Byte.parseByte(src.substring(2, 4));
- srcBytes[2] = Byte.parseByte(src.substring(4, 6));
- srcBytes[3] = Byte.parseByte(src.substring(6, 8));
- srcBytes[4] = Byte.parseByte(src.substring(8, 10));
- Assert.assertTrue(Arrays.equals(srcBytes, srcMatch));
- }
-
- if (act.getString("@type").equals("setDlDst")) {
- byte dstMatch[] = { (byte) 1, (byte) 2, (byte) 3, (byte) 4,
- (byte) 5 };
- String dst = act.getString("address");
- byte dstBytes[] = new byte[5];
- dstBytes[0] = Byte.parseByte(dst.substring(0, 2));
- dstBytes[1] = Byte.parseByte(dst.substring(2, 4));
- dstBytes[2] = Byte.parseByte(dst.substring(4, 6));
- dstBytes[3] = Byte.parseByte(dst.substring(6, 8));
- dstBytes[4] = Byte.parseByte(dst.substring(8, 10));
- Assert.assertTrue(Arrays.equals(dstBytes, dstMatch));
- }
- if (act.getString("@type").equals("setDlType"))
- Assert.assertTrue(act.getInt("dlType") == 10);
- if (act.getString("@type").equals("setVlanId"))
- Assert.assertTrue(act.getInt("vlanId") == 2);
- if (act.getString("@type").equals("setVlanPcp"))
- Assert.assertTrue(act.getInt("pcp") == 3);
- if (act.getString("@type").equals("setVlanCfi"))
- Assert.assertTrue(act.getInt("cfi") == 1);
-
- if (act.getString("@type").equals("setNwSrc"))
- Assert.assertTrue(act.getString("address")
- .equals("2.2.2.2"));
- if (act.getString("@type").equals("setNwDst"))
- Assert.assertTrue(act.getString("address")
- .equals("1.1.1.1"));
-
- if (act.getString("@type").equals("pushVlan")) {
- int head = act.getInt("VlanHeader");
- // parsing vlan header
- int id = head & 0xfff;
- int cfi = (head >> 12) & 0x1;
- int pcp = (head >> 13) & 0x7;
- int tag = (head >> 16) & 0xffff;
- Assert.assertTrue(id == 1234);
- Assert.assertTrue(cfi == 1);
- Assert.assertTrue(pcp == 1);
- Assert.assertTrue(tag == 0x8100);
- }
- if (act.getString("@type").equals("setNwTos"))
- Assert.assertTrue(act.getInt("tos") == 16);
- if (act.getString("@type").equals("setTpSrc"))
- Assert.assertTrue(act.getInt("port") == 4201);
- if (act.getString("@type").equals("setTpDst"))
- Assert.assertTrue(act.getInt("port") == 8080);
+ testFlowStat(flowStat, actionTypes[i]);
+
}
// for /controller/nb/v2/statistics/default/portstats
Assert.assertTrue(portStat.getInt("receiveCrcError") == 1);
Assert.assertTrue(portStat.getInt("collisionCount") == 4);
- // String result = getJsonResult(baseURL+"flowstats/STUB/51966");
- // System.out.println(result);
+ // test for getting one specific node's stats
+ result = getJsonResult(baseURL + "flowstats/STUB/51966");
+ jt = new JSONTokener(result);
+ json = new JSONObject(jt);
+ node = json.getJSONObject("node");
+ // test that node was returned properly
+ Assert.assertTrue(node.getInt("@id") == 0xCAFE);
+ Assert.assertTrue(node.getString("@type").equals("STUB"));
+
+ // test that flow statistics results are correct
+ flowStats = json.getJSONArray("flowStat");
+ for (int i = 0; i < flowStats.length(); i++) {
+ JSONObject flowStat = flowStats.getJSONObject(i);
+ testFlowStat(flowStat, actionTypes[i]);
+ }
+
+ result = getJsonResult(baseURL + "portstats/STUB/51966");
+ jt = new JSONTokener(result);
+ json = new JSONObject(jt);
+ node2 = json.getJSONObject("node");
+ // test that node was returned properly
+ Assert.assertTrue(node2.getInt("@id") == 0xCAFE);
+ Assert.assertTrue(node2.getString("@type").equals("STUB"));
+
+ // test that port statistic results are correct
+ portStat = json.getJSONObject("portStat");
+ Assert.assertTrue(portStat.getInt("receivePackets") == 250);
+ Assert.assertTrue(portStat.getInt("transmitPackets") == 500);
+ Assert.assertTrue(portStat.getInt("receiveBytes") == 1000);
+ Assert.assertTrue(portStat.getInt("transmitBytes") == 5000);
+ Assert.assertTrue(portStat.getInt("receiveDrops") == 2);
+ Assert.assertTrue(portStat.getInt("transmitDrops") == 50);
+ Assert.assertTrue(portStat.getInt("receiveErrors") == 3);
+ Assert.assertTrue(portStat.getInt("transmitErrors") == 10);
+ Assert.assertTrue(portStat.getInt("receiveFrameError") == 5);
+ Assert.assertTrue(portStat.getInt("receiveOverRunError") == 6);
+ Assert.assertTrue(portStat.getInt("receiveCrcError") == 1);
+ Assert.assertTrue(portStat.getInt("collisionCount") == 4);
} catch (Exception e) {
// Got an unexpected exception
}
}
+ private void testFlowStat(JSONObject flowStat, String actionType) {
+ try {
+ Assert.assertTrue(flowStat.getInt("tableId") == 1);
+ Assert.assertTrue(flowStat.getInt("durationSeconds") == 40);
+ Assert.assertTrue(flowStat.getInt("durationNanoseconds") == 400);
+ Assert.assertTrue(flowStat.getInt("packetCount") == 200);
+ Assert.assertTrue(flowStat.getInt("byteCount") == 100);
+
+ // test that flow information is correct
+ JSONObject flow = flowStat.getJSONObject("flow");
+ Assert.assertTrue(flow.getInt("priority") == 3500);
+ Assert.assertTrue(flow.getInt("idleTimeout") == 1000);
+ Assert.assertTrue(flow.getInt("hardTimeout") == 2000);
+ Assert.assertTrue(flow.getInt("id") == 12345);
+
+ JSONObject match = (flow.getJSONObject("match")
+ .getJSONObject("matchField"));
+ Assert.assertTrue(match.getString("type").equals("NW_DST"));
+ Assert.assertTrue(match.getString("value").equals("1.1.1.1"));
+
+ JSONObject act = flow.getJSONObject("actions");
+ Assert.assertTrue(act.getString("@type").equals(actionType));
+
+ if (act.getString("@type").equals("output")) {
+ JSONObject port = act.getJSONObject("port");
+ JSONObject port_node = port.getJSONObject("node");
+ Assert.assertTrue(port.getInt("@id") == 51966);
+ Assert.assertTrue(port.getString("@type").equals("STUB"));
+ Assert.assertTrue(port_node.getInt("@id") == 51966);
+ Assert.assertTrue(port_node.getString("@type").equals("STUB"));
+ }
+
+ if (act.getString("@type").equals("setDlSrc")) {
+ byte srcMatch[] = { (byte) 5, (byte) 4, (byte) 3, (byte) 2,
+ (byte) 1 };
+ String src = act.getString("address");
+ byte srcBytes[] = new byte[5];
+ srcBytes[0] = Byte.parseByte(src.substring(0, 2));
+ srcBytes[1] = Byte.parseByte(src.substring(2, 4));
+ srcBytes[2] = Byte.parseByte(src.substring(4, 6));
+ srcBytes[3] = Byte.parseByte(src.substring(6, 8));
+ srcBytes[4] = Byte.parseByte(src.substring(8, 10));
+ Assert.assertTrue(Arrays.equals(srcBytes, srcMatch));
+ }
+
+ if (act.getString("@type").equals("setDlDst")) {
+ byte dstMatch[] = { (byte) 1, (byte) 2, (byte) 3, (byte) 4,
+ (byte) 5 };
+ String dst = act.getString("address");
+ byte dstBytes[] = new byte[5];
+ dstBytes[0] = Byte.parseByte(dst.substring(0, 2));
+ dstBytes[1] = Byte.parseByte(dst.substring(2, 4));
+ dstBytes[2] = Byte.parseByte(dst.substring(4, 6));
+ dstBytes[3] = Byte.parseByte(dst.substring(6, 8));
+ dstBytes[4] = Byte.parseByte(dst.substring(8, 10));
+ Assert.assertTrue(Arrays.equals(dstBytes, dstMatch));
+ }
+ if (act.getString("@type").equals("setDlType"))
+ Assert.assertTrue(act.getInt("dlType") == 10);
+ if (act.getString("@type").equals("setVlanId"))
+ Assert.assertTrue(act.getInt("vlanId") == 2);
+ if (act.getString("@type").equals("setVlanPcp"))
+ Assert.assertTrue(act.getInt("pcp") == 3);
+ if (act.getString("@type").equals("setVlanCfi"))
+ Assert.assertTrue(act.getInt("cfi") == 1);
+
+ if (act.getString("@type").equals("setNwSrc"))
+ Assert.assertTrue(act.getString("address").equals("2.2.2.2"));
+ if (act.getString("@type").equals("setNwDst"))
+ Assert.assertTrue(act.getString("address").equals("1.1.1.1"));
+
+ if (act.getString("@type").equals("pushVlan")) {
+ int head = act.getInt("VlanHeader");
+ // parsing vlan header
+ int id = head & 0xfff;
+ int cfi = (head >> 12) & 0x1;
+ int pcp = (head >> 13) & 0x7;
+ int tag = (head >> 16) & 0xffff;
+ Assert.assertTrue(id == 1234);
+ Assert.assertTrue(cfi == 1);
+ Assert.assertTrue(pcp == 1);
+ Assert.assertTrue(tag == 0x8100);
+ }
+ if (act.getString("@type").equals("setNwTos"))
+ Assert.assertTrue(act.getInt("tos") == 16);
+ if (act.getString("@type").equals("setTpSrc"))
+ Assert.assertTrue(act.getInt("port") == 4201);
+ if (act.getString("@type").equals("setTpDst"))
+ Assert.assertTrue(act.getInt("port") == 8080);
+ } catch (Exception e) {
+ Assert.assertTrue(false);
+ }
+ }
+
// Configure the OSGi container
@Configuration
public Option[] config() {
import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase;
import org.opendaylight.controller.sal.core.IContainerListener;
+import org.opendaylight.controller.sal.utils.INodeFactory;
import org.opendaylight.controller.sal.core.Node;
import org.opendaylight.controller.sal.core.NodeConnector;
import org.opendaylight.controller.sal.discovery.IDiscoveryService;
}
public Object[] getGlobalImplementations() {
- Object[] res = { FlowProgrammerService.class };
+ Object[] res = { FlowProgrammerService.class, StubNodeFactory.class };
return res;
}
props.put("protocolPluginType", "STUB");
c.setInterface(IPluginInFlowProgrammerService.class.getName(), props);
}
+ if (imp.equals(StubNodeFactory.class)) {
+ // export the service to be used by SAL
+ Dictionary<String, Object> props = new Hashtable<String, Object>();
+ // Set the protocolPluginType property which will be used
+ // by SAL
+ props.put("protocolPluginType", "STUB");
+ props.put("protocolName", "STUB");
+ c.setInterface(INodeFactory.class.getName(), props);
+ }
}
}
--- /dev/null
+package org.opendaylight.controller.protocol_plugins.stub.internal;
+
+import org.opendaylight.controller.sal.core.ConstructionException;
+import org.opendaylight.controller.sal.utils.INodeFactory;
+import org.opendaylight.controller.sal.core.Node;
+
+public class StubNodeFactory implements INodeFactory
+ {
+ void init() {
+ }
+
+ /**
+ * Function called by the dependency manager when at least one dependency
+ * become unsatisfied or when the component is shutting down because for
+ * example bundle is being stopped.
+ *
+ */
+ void destroy() {
+ }
+
+ /**
+ * Function called by dependency manager after "init ()" is called and after
+ * the services provided by the class are registered in the service registry
+ *
+ */
+ void start() {
+ }
+
+ /**
+ * Function called by the dependency manager before the services exported by
+ * the component are unregistered, this will be followed by a "destroy ()"
+ * calls
+ *
+ */
+ void stop() {
+ }
+
+ public Node fromString(String nodeId, String nodeType){
+ if(nodeType.equals("STUB"))
+ try{
+ return new Node("STUB", Integer.parseInt(nodeId));
+ } catch(ConstructionException e)
+ {
+ return null;
+ }
+ return null;
+ }
+}
import javax.xml.bind.annotation.XmlRootElement;
import org.opendaylight.controller.sal.utils.HexEncode;
+import org.opendaylight.controller.sal.utils.INodeFactory;
+import org.opendaylight.controller.sal.utils.ServiceHelper;
/**
* Describe a generic network element in multiple SDNs technologies. A
return null;
}
} else {
- // We need to lookup via OSGi service registry for an
- // handler for this
+ //Use INodeFactory to create a Node of registered Node type.
+ //The protocol plugin being used depends on typeStr.
+ INodeFactory f = (INodeFactory) ServiceHelper
+ .getGlobalInstance(INodeFactory.class, new Node(), "(protocolName="+typeStr+")");
+ if(f==null)
+ return null;
+ return f.fromString(IDStr, typeStr);
}
- return null;
}
}
--- /dev/null
+
+/*
+ * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.controller.sal.utils;
+
+import org.opendaylight.controller.sal.core.Node;
+
+/**
+ * @file INodeFactory.java
+ *
+ * @brief Define the interface to be called when looking up custom node types
+ *
+ */
+
+public interface INodeFactory {
+ /**
+ * Method to get custom node types from protocol plugins
+ *
+ */
+ public Node fromString(String nodeId, String nodeType);
+}