From 738248cda591e5253e107080ffea1fd4a3e02645 Mon Sep 17 00:00:00 2001 From: Shigeru Yasuda Date: Wed, 9 Jul 2014 22:17:17 +0900 Subject: [PATCH] Bug 1234: Force to use legacy OF plugin if it is installed. This patch enables to prioritize AD-SAL protocol plugin services, and gives higher priority to legacy OF plugin than sal-compatibility. This patch never affects integration.git artifacts because legacy OF plugin is filtered out if MD-SAL OF plugin is installed. Change-Id: Iee40a6f724db2105f2ec36014a10872bad824e86 Signed-off-by: Shigeru Yasuda --- .../openflow/internal/Activator.java | 12 +- .../controller/sal/utils/GlobalConstants.java | 8 +- .../internal/DataPacketService.java | 63 +---- .../internal/FlowProgrammerService.java | 121 ++++------ .../internal/ProtocolService.java | 223 ++++++++++++++++++ .../implementation/internal/ReadService.java | 157 +++++------- .../implementation/ProtocolServiceTest.java | 199 ++++++++++++++++ 7 files changed, 549 insertions(+), 234 deletions(-) create mode 100644 opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ProtocolService.java create mode 100644 opendaylight/sal/implementation/src/test/java/org/opendaylight/controller/sal/implementation/ProtocolServiceTest.java diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java index 4a6a291e6a..d92c57bd8a 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/Activator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 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, @@ -57,6 +57,10 @@ public class Activator extends ComponentActivatorAbstractBase { protected static final Logger logger = LoggerFactory .getLogger(Activator.class); + /** + * Priority to determine whether to override existing protocol service. + */ + private static final int PLUGIN_PRIORITY = 10; /** * Function that is used to communicate to dependency manager the list of @@ -136,6 +140,8 @@ public class Activator extends ComponentActivatorAbstractBase { // Set the protocolPluginType property which will be used // by SAL props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), Node.NodeIDType.OPENFLOW); + props.put(GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(), + Integer.valueOf(PLUGIN_PRIORITY)); c.setInterface(IPluginInDataPacketService.class.getName(), props); // Hook the services coming in from SAL, as optional in // case SAL is not yet there, could happen @@ -165,6 +171,8 @@ public class Activator extends ComponentActivatorAbstractBase { // Set the protocolPluginType property which will be used // by SAL props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), Node.NodeIDType.OPENFLOW); + props.put(GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(), + Integer.valueOf(PLUGIN_PRIORITY)); c.setInterface(new String[] { IReadFilterInternalListener.class.getName(), IPluginInReadService.class.getName() }, props); @@ -256,6 +264,8 @@ public class Activator extends ComponentActivatorAbstractBase { // Set the protocolPluginType property which will be used // by SAL props.put(GlobalConstants.PROTOCOLPLUGINTYPE.toString(), Node.NodeIDType.OPENFLOW); + props.put(GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(), + Integer.valueOf(PLUGIN_PRIORITY)); c.setInterface( new String[] { IPluginInFlowProgrammerService.class.getName(), IMessageListener.class.getName(), IContainerListener.class.getName(), IInventoryShimExternalListener.class.getName(), diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/GlobalConstants.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/GlobalConstants.java index 174f2546ba..ceb4553470 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/GlobalConstants.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/GlobalConstants.java @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 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, @@ -20,7 +19,8 @@ public enum GlobalConstants { STATICVLAN("staticvlan"), CLUSTERINGSERVICES("clusteringservices"), STARTUPHOME("configuration/startup/"), - PROTOCOLPLUGINTYPE("protocolPluginType"); + PROTOCOLPLUGINTYPE("protocolPluginType"), + PROTOCOLPLUGINPRIORITY("protocolPluginPriority"); private GlobalConstants(String name) { this.name = name; @@ -31,4 +31,4 @@ public enum GlobalConstants { public String toString() { return name; } -} \ No newline at end of file +} diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/DataPacketService.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/DataPacketService.java index e9039261a3..0c9ebab8c3 100644 --- a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/DataPacketService.java +++ b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/DataPacketService.java @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 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, @@ -40,7 +39,6 @@ import org.opendaylight.controller.sal.packet.LinkEncap; import org.opendaylight.controller.sal.packet.Packet; import org.opendaylight.controller.sal.packet.PacketResult; import org.opendaylight.controller.sal.packet.RawPacket; -import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.NetUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,9 +57,9 @@ public class DataPacketService implements IPluginOutDataPacketService, * adding a new service, removing a service, going through all of * them maybe different. */ - private ConcurrentHashMap + private ConcurrentHashMap> pluginInDataService = - new ConcurrentHashMap(); + new ConcurrentHashMap>(); private Map statistics = new HashMap(); /** @@ -186,11 +184,11 @@ public class DataPacketService implements IPluginOutDataPacketService, String t = p.getNode() .getType(); // Now locate the TX dispatcher - IPluginInDataPacketService s = pluginInDataService - .get(t); - if (s != null) { + ProtocolService service = + pluginInDataService.get(t); + if (service != null) { try { - s.transmitDataPacket(pkt); + service.getService().transmitDataPacket(pkt); increaseStat("TXPacketSuccess"); } catch (Exception e) { increaseStat("TXPacketFailedForException"); @@ -207,54 +205,11 @@ public class DataPacketService implements IPluginOutDataPacketService, } void setPluginInDataService(Map props, IPluginInDataPacketService s) { - if (this.pluginInDataService == null) { - logger.error("pluginInDataService store null"); - return; - } - String type = null; - logger.trace("Received setPluginInDataService request"); - for (Object e : props.entrySet()) { - Map.Entry entry = (Map.Entry) e; - logger.trace("Prop key:({}) value:({})",entry.getKey(), entry.getValue()); - } - - Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString()); - if (value instanceof String) { - type = (String) value; - } - if (type == null) { - logger.error("Received a PluginInDataService without any " - + "protocolPluginType provided"); - } else { - this.pluginInDataService.put(type, s); - logger.debug("Stored the PluginInDataService for type: {}", type); - } + ProtocolService.set(this.pluginInDataService, props, s, logger); } void unsetPluginInDataService(Map props, IPluginInDataPacketService s) { - if (this.pluginInDataService == null) { - logger.error("pluginInDataService store null"); - return; - } - - String type = null; - logger.trace("Received unsetPluginInDataService request"); - for (Object e : props.entrySet()) { - Map.Entry entry = (Map.Entry) e; - logger.trace("Prop key:({}) value:({})",entry.getKey(), entry.getValue()); - } - - Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString()); - if (value instanceof String) { - type = (String) value; - } - if (type == null) { - logger.error("Received a PluginInDataService without any " - + "protocolPluginType provided"); - } else if (this.pluginInDataService.get(type).equals(s)) { - this.pluginInDataService.remove(type); - logger.debug("Removed the PluginInDataService for type: {}", type); - } + ProtocolService.unset(this.pluginInDataService, props, s, logger); } void setListenDataPacket(Map props, IListenDataPacket s) { diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java index 854125b356..60a7882bda 100644 --- a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java +++ b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/FlowProgrammerService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 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, @@ -38,7 +38,6 @@ import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerSe import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.IPProtocols; import org.opendaylight.controller.sal.utils.NodeConnectorCreator; import org.opendaylight.controller.sal.utils.Status; @@ -58,12 +57,12 @@ public class FlowProgrammerService implements IFlowProgrammerService, protected static final Logger logger = LoggerFactory .getLogger(FlowProgrammerService.class); - private ConcurrentHashMap pluginFlowProgrammer; + private ConcurrentHashMap> pluginFlowProgrammer; private Set listener; private AtomicLong seq; public FlowProgrammerService() { - pluginFlowProgrammer = new ConcurrentHashMap(); + pluginFlowProgrammer = new ConcurrentHashMap>(); listener = new HashSet(); seq = new AtomicLong(); /* @@ -117,58 +116,11 @@ public class FlowProgrammerService implements IFlowProgrammerService, // Set the reference to the plugin flow programmer public void setService(Map props, IPluginInFlowProgrammerService s) { - if (this.pluginFlowProgrammer == null) { - logger.error("pluginFlowProgrammer store null"); - return; - } - - if (logger.isTraceEnabled()) { - logger.trace("Got a service set request {}", s); - for (Map.Entry entry : props.entrySet()) { - logger.trace("Prop key:({}) value:({})", entry.getKey(), entry.getValue()); - } - } - - String type = null; - Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString()); - if (value instanceof String) { - type = (String) value; - } - if (type == null) { - logger.error("Received a pluginFlowProgrammer without any " - + "protocolPluginType provided"); - } else { - this.pluginFlowProgrammer.put(type, s); - logger.debug("Stored the pluginFlowProgrammer for type: {}", type); - } + ProtocolService.set(this.pluginFlowProgrammer, props, s, logger); } public void unsetService(Map props, IPluginInFlowProgrammerService s) { - if (this.pluginFlowProgrammer == null) { - logger.error("pluginFlowProgrammer store null"); - return; - } - - logger.debug("Received unsetpluginFlowProgrammer request"); - if (logger.isTraceEnabled()) { - logger.trace("Got a service set request {}", s); - for (Map.Entry entry : props.entrySet()) { - logger.trace("Prop key:({}) value:({})", entry.getKey(), entry.getValue()); - } - } - - String type = null; - Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString()); - if (value instanceof String) { - type = (String) value; - } - if (type == null) { - logger.error("Received a pluginFlowProgrammer without any " - + "protocolPluginType provided"); - } else if (this.pluginFlowProgrammer.get(type).equals(s)) { - this.pluginFlowProgrammer.remove(type); - logger.debug("Removed the pluginFlowProgrammer for type: {}", type); - } + ProtocolService.unset(this.pluginFlowProgrammer, props, s, logger); } public void setListener(IFlowProgrammerListener s) { @@ -182,9 +134,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status addFlow(Node node, Flow flow) { if (pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()).addFlow( - node, flow); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().addFlow(node, flow); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -193,9 +146,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status removeFlow(Node node, Flow flow) { if (pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()) - .removeFlow(node, flow); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().removeFlow(node, flow); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -204,9 +158,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status removeAllFlows(Node node) { if (pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()) - .removeAllFlows(node); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().removeAllFlows(node); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -215,9 +170,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) { if (pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()) - .modifyFlow(node, oldFlow, newFlow); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().modifyFlow(node, oldFlow, newFlow); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -226,9 +182,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status addFlowAsync(Node node, Flow flow) { if (pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()).addFlowAsync( - node, flow, getNextRid()); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().addFlowAsync(node, flow, getNextRid()); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -237,9 +194,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status removeFlowAsync(Node node, Flow flow) { if (pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()) - .removeFlowAsync(node, flow, getNextRid()); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().removeFlowAsync(node, flow, getNextRid()); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -248,9 +206,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status modifyFlowAsync(Node node, Flow oldFlow, Flow newFlow) { if (pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()) - .modifyFlowAsync(node, oldFlow, newFlow, getNextRid()); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().modifyFlowAsync(node, oldFlow, newFlow, getNextRid()); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -508,9 +467,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status syncSendBarrierMessage(Node node) { if (this.pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()) - .syncSendBarrierMessage(node); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().syncSendBarrierMessage(node); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -519,9 +479,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, @Override public Status asyncSendBarrierMessage(Node node) { if (this.pluginFlowProgrammer != null) { - if (this.pluginFlowProgrammer.get(node.getType()) != null) { - return this.pluginFlowProgrammer.get(node.getType()) - .asyncSendBarrierMessage(node); + ProtocolService service = + this.pluginFlowProgrammer.get(node.getType()); + if (service != null) { + return service.getService().asyncSendBarrierMessage(node); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ProtocolService.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ProtocolService.java new file mode 100644 index 0000000000..e9dc2ad0ee --- /dev/null +++ b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ProtocolService.java @@ -0,0 +1,223 @@ +/* + * Copyright (c) 2014 NEC Corporation 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.implementation.internal; + +import java.util.Map; +import java.util.concurrent.ConcurrentMap; + +import org.slf4j.Logger; + +import org.opendaylight.controller.sal.utils.GlobalConstants; + +/** + * An instance of this class keeps a protocol plugin service handler. + * + * @param Type of protocol plugin service. + */ +public final class ProtocolService { + /** + * Default priority value. + */ + private static final int DEFAULT_PRIORITY = 0; + + /** + * A protocol plugin service handler. + */ + private final T service; + + /** + * A priority value assigned to this protocol plugin. + */ + private final int priority; + + /** + * Set protocol plugin service. + * + * @param map A map that keeps protocol plugin services. + * @param props Service properties. + * @param s Protocol plugin service. + * @param logger A logger instance. + * @param Type of protocol plugin service. + */ + public static void set(ConcurrentMap> map, + Map props, S s, Logger logger) { + if (map == null) { + logger.error("Protocol plugin service store is null."); + return; + } + if (s == null) { + logger.error("Protocol plugin service is null."); + return; + } + if (props == null) { + logger.error("Service property is null."); + return; + } + + if (logger.isTraceEnabled()) { + logger.trace("Received set service request: {}", s); + for (Map.Entry entry: props.entrySet()) { + logger.trace("Prop key:({}) value:({})", entry.getKey(), + entry.getValue()); + } + } + + Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString()); + if (!(value instanceof String)) { + logger.error("Unexpected protocol type: {}", value); + return; + } + + String type = (String)value; + ProtocolService service = new ProtocolService(props, s); + ProtocolService old = map.putIfAbsent(type, service); + while (old != null) { + // Compare priority value. + if (old.getPriority() >= service.getPriority()) { + logger.trace("Protocol plugin service for {} is already set: " + + "current={}, requested={}", type, old, service); + return; + } + + if (map.replace(type, old, service)) { + break; + } + old = map.putIfAbsent(type, service); + } + + logger.debug("Stored protocol plugin service for {}: {}", + type, service); + } + + /** + * Unset protocol plugin service. + * + * @param map A map that keeps protocol plugin services. + * @param props Service properties. + * @param s Protocol plugin service. + * @param logger A logger instance. + * @param Type of protocol plugin service. + */ + public static void unset(ConcurrentMap> map, + Map props, S s, Logger logger) { + if (map == null) { + logger.error("Protocol plugin service store is null."); + return; + } + if (s == null) { + logger.error("Protocol plugin service is null."); + return; + } + if (props == null) { + logger.error("Service property is null."); + return; + } + + if (logger.isTraceEnabled()) { + logger.trace("Received unset service request: {}", s); + for (Map.Entry entry: props.entrySet()) { + logger.trace("Prop key:({}) value:({})", + entry.getKey(), entry.getValue()); + } + } + + Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString()); + if (!(value instanceof String)) { + logger.error("Unexpected protocol type {}: service={}", value, s); + return; + } + + String type = (String)value; + ProtocolService plugin = new ProtocolService(props, s); + if (map.remove(type, plugin)) { + logger.debug("Removed protocol plugin service for {}: {}", + type, plugin); + } else { + logger.trace("Ignore unset service request for {}: {}", + type, plugin); + } + } + + /** + * Constructor. + * + * @param props Protocol plugin service properties. + * @param s A protocol plugin service handler. + */ + public ProtocolService(Map props, T s) { + service = s; + + String key = GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(); + Object value = props.get(key); + if (value instanceof Integer) { + priority = ((Integer)value).intValue(); + } else { + priority = DEFAULT_PRIORITY; + } + } + + /** + * Return a protocol plugin service handler. + * + * @return A protocol plugin service handler. + */ + public T getService() { + return service; + } + + /** + * Return a priority value assigned to this protocol plugin. + * + * @return A priority value. + */ + public int getPriority() { + return priority; + } + + /** + * Determine whether the given object is identical to this object. + * + * @param o An object to be compared. + * @return {@code true} if identical. Otherwise {@code false}. + */ + @Override + public boolean equals(Object o) { + if (o == this) { + return true; + } + if (o == null || o.getClass() != getClass()) { + return false; + } + + ProtocolService plugin = (ProtocolService)o; + return (service.equals(plugin.service) && priority == plugin.priority); + } + + /** + * Return the hash code of this object. + * + * @return The hash code. + */ + @Override + public int hashCode() { + return service.hashCode() + (priority * 31); + } + + /** + * Return a string representation of this instance. + * + * @return A string representation of this instance. + */ + @Override + public String toString() { + StringBuilder builder = new StringBuilder("[service="); + return builder.append(service).append(", priority=").append(priority). + append(']').toString(); + } +} diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java index 12de35f536..356c0e57c8 100644 --- a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java +++ b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/ReadService.java @@ -1,6 +1,5 @@ - /* - * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. + * Copyright (c) 2013-2014 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, @@ -43,7 +42,6 @@ import org.opendaylight.controller.sal.reader.NodeConnectorStatistics; import org.opendaylight.controller.sal.reader.NodeDescription; import org.opendaylight.controller.sal.reader.NodeTableStatistics; import org.opendaylight.controller.sal.utils.EtherTypes; -import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.sal.utils.IPProtocols; import org.opendaylight.controller.sal.utils.NodeConnectorCreator; import org.opendaylight.controller.sal.utils.NodeCreator; @@ -60,8 +58,8 @@ import org.slf4j.LoggerFactory; public class ReadService implements IReadService, CommandProvider, IPluginOutReadService { protected static final Logger logger = LoggerFactory.getLogger(ReadService.class); - private ConcurrentHashMap pluginReader = - new ConcurrentHashMap(); + private ConcurrentHashMap> pluginReader = + new ConcurrentHashMap>(); private Set readerListeners = new CopyOnWriteArraySet(); @@ -107,58 +105,13 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea // Set the reference to the plugin flow Reader service public void setService(Map props, IPluginInReadService s) { - if (this.pluginReader == null) { - logger.error("pluginReader store null"); - return; - } - - logger.trace("Got a service set request {}", s); - String type = null; - for (Object e : props.entrySet()) { - Map.Entry entry = (Map.Entry) e; - logger.trace("Prop key:({}) value:({})", entry.getKey(), - entry.getValue()); - } - - Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString()); - if (value instanceof String) { - type = (String) value; - } - if (type == null) { - logger.error("Received a pluginReader without any " - + "protocolPluginType provided"); - } else { - this.pluginReader.put(type, s); - logger.debug("Stored the pluginReader for type: {}", type); - } + ProtocolService.set(this.pluginReader, props, s, logger); } public void unsetService(Map props, IPluginInReadService s) { - if (this.pluginReader == null) { - logger.error("pluginReader store null"); - return; - } - - String type = null; - logger.debug("Received unsetpluginReader request"); - for (Object e : props.entrySet()) { - Map.Entry entry = (Map.Entry) e; - logger.trace("Prop key:({}) value:({})", entry.getKey(), - entry.getValue()); - } - - Object value = props.get(GlobalConstants.PROTOCOLPLUGINTYPE.toString()); - if (value instanceof String) { - type = (String) value; - } - if (type == null) { - logger.error("Received a pluginReader without any " - + "protocolPluginType provided"); - } else if (this.pluginReader.get(type).equals(s)) { - this.pluginReader.remove(type); - logger.debug("Removed the pluginReader for type: {}", type); - } + ProtocolService.unset(this.pluginReader, props, s, logger); } + public void setReaderListener(IReadServiceListener service) { logger.trace("Got a listener set request {}", service); this.readerListeners.add(service); @@ -172,9 +125,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public FlowOnNode readFlow(Node node, Flow flow) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readFlow(node, flow, true); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readFlow(node, flow, true); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -184,9 +138,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public FlowOnNode nonCachedReadFlow(Node node, Flow flow) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readFlow(node, flow, false); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readFlow(node, flow, false); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -196,9 +151,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public List readAllFlows(Node node) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readAllFlow(node, true); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readAllFlow(node, true); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -208,9 +164,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public List nonCachedReadAllFlows(Node node) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readAllFlow(node, false); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readAllFlow(node, false); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -220,9 +177,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public NodeDescription readDescription(Node node) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readDescription(node, true); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readDescription(node, true); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -232,9 +190,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public NodeDescription nonCachedReadDescription(Node node) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readDescription(node, false); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readDescription(node, false); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -245,9 +204,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea public NodeConnectorStatistics readNodeConnector(NodeConnector connector) { Node node = connector.getNode(); if (pluginReader != null && node != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readNodeConnector(connector, true); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readNodeConnector(connector, true); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -259,9 +219,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea NodeConnector connector) { Node node = connector.getNode(); if (pluginReader != null && node != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readNodeConnector(connector, false); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readNodeConnector(connector, false); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -271,9 +232,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public List readNodeConnectors(Node node) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readAllNodeConnector(node, true); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readAllNodeConnector(node, true); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -283,9 +245,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public List readNodeTable(Node node) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readAllNodeTable(node, true); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readAllNodeTable(node, true); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -297,9 +260,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea public NodeTableStatistics nonCachedReadNodeTable(NodeTable table) { Node node = table.getNode(); if (pluginReader != null && node != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readNodeTable(table, false); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readNodeTable(table, false); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -310,9 +274,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea public NodeTableStatistics readNodeTable(NodeTable table) { Node node = table.getNode(); if (pluginReader != null && node != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readNodeTable(table, true); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readNodeTable(table, true); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -322,9 +287,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea @Override public List nonCachedReadNodeConnectors(Node node) { if (pluginReader != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .readAllNodeConnector(node, false); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().readAllNodeConnector(node, false); } } logger.warn("Plugin {} unavailable", node.getType()); @@ -335,9 +301,10 @@ public class ReadService implements IReadService, CommandProvider, IPluginOutRea public long getTransmitRate(NodeConnector connector) { Node node = connector.getNode(); if (pluginReader != null && node != null) { - if (this.pluginReader.get(node.getType()) != null) { - return this.pluginReader.get(node.getType()) - .getTransmitRate(connector); + ProtocolService service = + this.pluginReader.get(node.getType()); + if (service != null) { + return service.getService().getTransmitRate(connector); } } logger.warn("Plugin {} unavailable", node.getType()); diff --git a/opendaylight/sal/implementation/src/test/java/org/opendaylight/controller/sal/implementation/ProtocolServiceTest.java b/opendaylight/sal/implementation/src/test/java/org/opendaylight/controller/sal/implementation/ProtocolServiceTest.java new file mode 100644 index 0000000000..079350bcc9 --- /dev/null +++ b/opendaylight/sal/implementation/src/test/java/org/opendaylight/controller/sal/implementation/ProtocolServiceTest.java @@ -0,0 +1,199 @@ +/* + * Copyright (c) 2014 NEC Corporation 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.implementation; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.opendaylight.controller.sal.implementation.internal.ProtocolService; +import org.opendaylight.controller.sal.utils.GlobalConstants; + +/** + * Unit test for {@link ProtocolService}. + */ +public class ProtocolServiceTest { + private static final Logger LOG = + LoggerFactory.getLogger(ProtocolServiceTest.class); + + @Test + public void testInstance() { + HashSet> set = new HashSet<>(); + TestService sv1 = new TestService(); + HashMap prop1 = new HashMap<>(); + + ProtocolService ps1 = + new ProtocolService(prop1, sv1); + assertEquals(sv1, ps1.getService()); + // Default priority is 0. + assertEquals(0, ps1.getPriority()); + assertTrue(set.add(ps1)); + assertFalse(set.add(ps1)); + + // Specify the same service and priority. + String priKey = GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(); + prop1.put(priKey, Integer.valueOf(0)); + ProtocolService ps2 = + new ProtocolService(prop1, sv1); + assertEquals(sv1, ps2.getService()); + assertEquals(0, ps2.getPriority()); + assertEquals(ps1, ps2); + assertFalse(set.add(ps1)); + + // Specify different priority. + prop1.put(priKey, Integer.valueOf(Integer.MAX_VALUE)); + ps2 = new ProtocolService(prop1, sv1); + assertEquals(sv1, ps2.getService()); + assertEquals(Integer.MAX_VALUE, ps2.getPriority()); + assertFalse(ps1.equals(ps2)); + assertTrue(set.add(ps2)); + assertFalse(set.add(ps2)); + + // Specify another service. + TestService sv2 = new TestService(); + prop1.put(priKey, Integer.valueOf(0)); + ps2 = new ProtocolService(prop1, sv2); + assertEquals(sv2, ps2.getService()); + assertEquals(0, ps2.getPriority()); + assertFalse(ps1.equals(ps2)); + assertTrue(set.add(ps2)); + assertFalse(set.add(ps2)); + } + + @Test + public void testSetUnsetError() { + ConcurrentMap> services = + new ConcurrentHashMap<>(); + TestService sv = new TestService(); + Map props = new HashMap<>(); + + // null service. + ProtocolService.set(services, props, null, LOG); + assertTrue(services.isEmpty()); + + ProtocolService.unset(services, props, null, LOG); + assertTrue(services.isEmpty()); + + // null service property. + ProtocolService.set(services, null, sv, LOG); + assertTrue(services.isEmpty()); + + ProtocolService.unset(services, null, sv, LOG); + assertTrue(services.isEmpty()); + + // Type is not specified. + ProtocolService.set(services, props, sv, LOG); + assertTrue(services.isEmpty()); + + ProtocolService.unset(services, props, sv, LOG); + assertTrue(services.isEmpty()); + + // null service map. + final String typeKey = GlobalConstants.PROTOCOLPLUGINTYPE.toString(); + assertEquals(null, props.put(typeKey, "OF")); + ProtocolService.set(null, props, sv, LOG); + assertTrue(services.isEmpty()); + + ProtocolService.unset(null, props, sv, LOG); + assertTrue(services.isEmpty()); + } + + @Test + public void testSetUnset() { + ConcurrentMap> serviceMap = + new ConcurrentHashMap<>(); + ConcurrentMap> expected = + new ConcurrentHashMap<>(); + + final String typeKey = GlobalConstants.PROTOCOLPLUGINTYPE.toString(); + final String priKey = GlobalConstants.PROTOCOLPLUGINPRIORITY.toString(); + final String[] protocols = {"OF", "PE", "PK"}; + final int basePri = 0; + final int loop = 5; + + // Should override the service if higher priority is specified. + for (String proto: protocols) { + for (int pri = basePri - loop + 1; pri <= basePri; pri++) { + TestService sv = new TestService(); + Map props = new HashMap<>(); + assertEquals(null, props.put(typeKey, proto)); + assertEquals(null, props.put(priKey, Integer.valueOf(pri))); + ProtocolService.set(serviceMap, props, sv, LOG); + + ProtocolService service = serviceMap.get(proto); + assertNotNull(service); + assertEquals(sv, service.getService()); + assertEquals(pri, service.getPriority()); + + ProtocolService service1 = + new ProtocolService(props, sv); + expected.put(proto, service1); + assertEquals(expected, serviceMap); + + // Unset service request should be ignored if different + // parameters are specified. + TestService another = new TestService(); + ProtocolService.unset(serviceMap, props, another, LOG); + assertEquals(expected, serviceMap); + + props.put(priKey, Integer.valueOf(Integer.MAX_VALUE)); + ProtocolService.unset(serviceMap, props, sv, LOG); + assertEquals(expected, serviceMap); + } + } + + // Should reject the set service request if lower priority is specified. + for (String proto: protocols) { + for (int pri = basePri - loop; pri < basePri; pri++) { + TestService sv = new TestService(); + Map props = new HashMap<>(); + assertEquals(null, props.put(typeKey, proto)); + assertEquals(null, props.put(priKey, Integer.valueOf(pri))); + ProtocolService.set(serviceMap, props, sv, LOG); + assertEquals(expected, serviceMap); + } + } + + // Unset protocol services. + for (String proto: protocols) { + ProtocolService service = expected.remove(proto); + assertNotNull(service); + + ITestService sv = service.getService(); + Map props = new HashMap<>(); + assertEquals(null, props.put(typeKey, proto)); + assertEquals(null, props.put(priKey, Integer.valueOf(basePri))); + ProtocolService.unset(serviceMap, props, sv, LOG); + assertEquals(expected, serviceMap); + + // Should be ignored if the specified service does not exist. + ProtocolService.unset(serviceMap, props, sv, LOG); + assertEquals(expected, serviceMap); + } + + assertTrue(serviceMap.isEmpty()); + } +} + +interface ITestService { +} + +class TestService implements ITestService { +} -- 2.36.6