From: Alessandro Boch Date: Fri, 19 Apr 2013 02:15:54 +0000 (+0000) Subject: Merge "Refactor frontend JS" X-Git-Tag: releasepom-0.1.0~555 X-Git-Url: https://git.opendaylight.org/gerrit/gitweb?p=controller.git;a=commitdiff_plain;h=4a5b8b61c06c7091a7de5ed9df7456fa325dd909;hp=3591b13ae3e6f237db9e4b63cb3b07e020f576ca Merge "Refactor frontend JS" --- diff --git a/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java b/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java index 9da0970340..8578e8492e 100644 --- a/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java +++ b/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/Activator.java @@ -21,6 +21,7 @@ import org.opendaylight.controller.forwardingrulesmanager.IForwardingRulesManage import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase; import org.opendaylight.controller.sal.core.IContainer; import org.opendaylight.controller.sal.core.IContainerListener; +import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener; import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService; import org.opendaylight.controller.sal.utils.GlobalConstants; import org.opendaylight.controller.switchmanager.IInventoryListener; @@ -98,14 +99,16 @@ public class Activator extends ComponentActivatorAbstractBase { IForwardingRulesManager.class.getName(), IInventoryListener.class.getName(), ICacheUpdateAware.class.getName(), - IConfigurationContainerAware.class.getName() }; + IConfigurationContainerAware.class.getName(), + IFlowProgrammerListener.class.getName()}; } else { interfaces = new String[] { ISwitchManagerAware.class.getName(), IForwardingRulesManager.class.getName(), IInventoryListener.class.getName(), ICacheUpdateAware.class.getName(), - IConfigurationContainerAware.class.getName() }; + IConfigurationContainerAware.class.getName(), + IFlowProgrammerListener.class.getName()}; } c.setInterface(interfaces, props); diff --git a/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java b/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java index 6cdc785a19..58f1e18730 100644 --- a/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java +++ b/opendaylight/forwardingrulesmanager/src/main/java/org/opendaylight/controller/forwardingrulesmanager/internal/ForwardingRulesManagerImpl.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -60,6 +59,7 @@ import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.Property; import org.opendaylight.controller.sal.core.UpdateType; import org.opendaylight.controller.sal.flowprogrammer.Flow; +import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener; import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService; import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; @@ -91,7 +91,8 @@ import org.slf4j.LoggerFactory; public class ForwardingRulesManagerImpl implements IForwardingRulesManager, PortGroupChangeListener, IContainerListener, ISwitchManagerAware, IConfigurationContainerAware, IInventoryListener, IObjectReader, - ICacheUpdateAware, CommandProvider { + ICacheUpdateAware, CommandProvider, + IFlowProgrammerListener { private static final String SAVE = "Save"; private static final String NODEDOWN = "Node is Down"; private static final Logger log = LoggerFactory @@ -107,18 +108,18 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, private boolean inContainerMode; // being used by default instance only /* * Flow database. It's the software view of what was installed on the - * switch. It is indexed by node. For convenience a version indexed - * by group name is also maintained. The core element is a class which - * contains the flow entry pushed by the functional modules and the - * respective container flow merged version. In absence of container - * flows, the two flow entries are the same. + * switch. It is indexed by node. For convenience a version indexed by group + * name is also maintained. The core element is a class which contains the + * flow entry pushed by the functional modules and the respective container + * flow merged version. In absence of container flows, the two flow entries + * are the same. */ private ConcurrentMap> nodeFlows; private ConcurrentMap> groupFlows; /* - * Inactive flow list. This is for the global instance of FRM - * It will contain all the flow entries which were installed on the - * global container when the first container is created. + * Inactive flow list. This is for the global instance of FRM It will + * contain all the flow entries which were installed on the global container + * when the first container is created. */ private List inactiveFlows; @@ -131,54 +132,56 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, private ISwitchManager switchManager; /** - * Adds a flow entry onto the network node - * It runs various validity checks and derive the final container flows - * merged entries that will be attempted to be installed - * - * @param flowEntry the original flow entry application requested to add + * Adds a flow entry onto the network node It runs various validity checks + * and derive the final container flows merged entries that will be + * attempted to be installed + * + * @param flowEntry + * the original flow entry application requested to add * @return */ private Status addEntry(FlowEntry flowEntry) { // Sanity Check if (flowEntry == null || flowEntry.getNode() == null) { - String msg = "Invalid FlowEntry"; + String msg = "Invalid FlowEntry"; log.warn(msg + ": " + flowEntry); return new Status(StatusCode.NOTACCEPTABLE, msg); } /* - * Derive the container flow merged entries to install - * In presence of N container flows, we may end up with - * N different entries to install... + * Derive the container flow merged entries to install In presence of N + * container flows, we may end up with N different entries to install... */ - List toInstallList = deriveInstallEntries(flowEntry - .clone(), container.getContainerFlows()); + List toInstallList = deriveInstallEntries( + flowEntry.clone(), container.getContainerFlows()); // Container Flow conflict Check if (toInstallList.isEmpty()) { - String msg = "Flow Entry conflicts with all Container Flows"; - log.warn(msg); + String msg = "Flow Entry conflicts with all Container Flows"; + log.warn(msg); return new Status(StatusCode.CONFLICT, msg); } // Derive the list of entries good to be installed List toInstallSafe = new ArrayList(); for (FlowEntryInstall entry : toInstallList) { - // Conflict Check: Verify new entry would not overwrite existing ones + // Conflict Check: Verify new entry would not overwrite existing + // ones if (findMatch(entry.getInstall(), false) != null) { - log.warn("Operation Rejected: A flow with same match " + - "and priority exists on the target node"); + log.warn("Operation Rejected: A flow with same match " + + "and priority exists on the target node"); log.trace("Aborting to install " + entry); continue; } toInstallSafe.add(entry); } - // Declare failure if all the container flow merged entries clash with existing entries + // Declare failure if all the container flow merged entries clash with + // existing entries if (toInstallSafe.size() == 0) { - String msg = "A flow with same match and priority exists " + - "on the target node"; - log.warn(msg); + String msg = "A flow with same match and priority exists " + + "on the target node"; + log.warn(msg); return new Status(StatusCode.CONFLICT, msg); } @@ -188,7 +191,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, for (FlowEntryInstall installEntry : toInstallList) { // Install and update database - Status ret = addEntriesInternal(installEntry); + Status ret = addEntriesInternal(installEntry); if (ret.isSuccess()) { oneSucceded = true; @@ -206,12 +209,14 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, * of container flow merged flow entries good to be installed on this * container. If the list of container flows is null or empty, the install * entry list will contain only one entry, the original flow entry. If the - * flow entry is congruent with all the N container flows, then the output + * flow entry is congruent with all the N container flows, then the output * install entry list will contain N entries. If the output list is empty, * it means the passed flow entry conflicts with all the container flows. - * - * @param cFlowList The list of container flows - * @return the list of container flow merged entries good to be installed on this container + * + * @param cFlowList + * The list of container flows + * @return the list of container flow merged entries good to be installed on + * this container */ private List deriveInstallEntries(FlowEntry request, List cFlowList) { @@ -224,7 +229,8 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, toInstallList.add(new FlowEntryInstall(request.clone(), null)); } else { // Create the list of entries to be installed. If the flow entry is - // not congruent with any container flow, no install entries will be created + // not congruent with any container flow, no install entries will be + // created for (ContainerFlow cFlow : container.getContainerFlows()) { if (cFlow.allowsFlow(request.getFlow())) { toInstallList.add(new FlowEntryInstall(request.clone(), @@ -236,49 +242,50 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } /** - * Modify a flow entry with a new one - * It runs various validity check and derive the final container flows - * merged flow entries to work with - * + * Modify a flow entry with a new one It runs various validity check and + * derive the final container flows merged flow entries to work with + * * @param currentFlowEntry * @param newFlowEntry * @return Success or error string */ private Status modifyEntry(FlowEntry currentFlowEntry, FlowEntry newFlowEntry) { - Status retExt; + Status retExt; // Sanity checks if (currentFlowEntry == null || currentFlowEntry.getNode() == null || newFlowEntry == null || newFlowEntry.getNode() == null) { - String msg ="Modify: Invalid FlowEntry"; + String msg = "Modify: Invalid FlowEntry"; log.warn(msg + ": {} or {} ", currentFlowEntry, newFlowEntry); return new Status(StatusCode.NOTACCEPTABLE, msg); } if (!currentFlowEntry.getNode().equals(newFlowEntry.getNode()) || !currentFlowEntry.getFlowName().equals( newFlowEntry.getFlowName())) { - String msg = "Modify: Incompatible Flow Entries"; - log.warn(msg +": {} and {}", currentFlowEntry, newFlowEntry); + String msg = "Modify: Incompatible Flow Entries"; + log.warn(msg + ": {} and {}", currentFlowEntry, newFlowEntry); return new Status(StatusCode.NOTACCEPTABLE, msg); } // Equality Check if (currentFlowEntry.equals(newFlowEntry)) { - String msg = "Modify skipped as flows are the same"; + String msg = "Modify skipped as flows are the same"; log.debug(msg + ": " + currentFlowEntry + " and " + newFlowEntry); return new Status(StatusCode.SUCCESS, msg); } - // Conflict Check: Verify the new entry would not conflict with another existing one - // This is a loose check on the previous original flow entry requests. No check + // Conflict Check: Verify the new entry would not conflict with another + // existing one + // This is a loose check on the previous original flow entry requests. + // No check // on the container flow merged flow entries (if any) yet FlowEntryInstall sameMatchOriginalEntry = findMatch(newFlowEntry, true); if (sameMatchOriginalEntry != null && !sameMatchOriginalEntry.getOriginal().equals( currentFlowEntry)) { - String msg = "Operation Rejected: Another flow with same match " + - "and priority exists on the target node"; + String msg = "Operation Rejected: Another flow with same match " + + "and priority exists on the target node"; log.warn(msg); return new Status(StatusCode.CONFLICT, msg); } @@ -290,8 +297,8 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, newFlowEntry.clone(), container.getContainerFlows()); if (toInstallList.isEmpty()) { - String msg = "Modify Operation Rejected: The new entry " + - "conflicts with all the container flows"; + String msg = "Modify Operation Rejected: The new entry " + + "conflicts with all the container flows"; log.warn(msg); return new Status(StatusCode.CONFLICT, msg); } @@ -302,32 +309,32 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, * This is only possible when the new entry and current entry have * different match. In this scenario the modification would ultimately * be handled as a remove and add operations in the protocol plugin. - * + * * Also, if any of the new flow entries would clash with an existing * one, we cannot proceed with the modify operation, because it would * fail for some entries and leave stale entries on the network node. - * Modify path can be taken only if it can be performed completely, - * for all entries. - * - * So, for the above two cases, to simplify, let's decouple the modify in: - * 1) remove current entries - * 2) install new entries + * Modify path can be taken only if it can be performed completely, for + * all entries. + * + * So, for the above two cases, to simplify, let's decouple the modify + * in: 1) remove current entries 2) install new entries */ boolean decouple = false; if (installedList.size() != toInstallList.size()) { - log.info("Modify: New flow entry does not satisfy the same " + - "number of container flows as the original entry does"); + log.info("Modify: New flow entry does not satisfy the same " + + "number of container flows as the original entry does"); decouple = true; } List toInstallSafe = new ArrayList(); for (FlowEntryInstall installEntry : toInstallList) { - // Conflict Check: Verify the new entry would not overwrite another existing one - FlowEntryInstall sameMatchEntry = findMatch(installEntry - .getInstall(), false); + // Conflict Check: Verify the new entry would not overwrite another + // existing one + FlowEntryInstall sameMatchEntry = findMatch( + installEntry.getInstall(), false); if (sameMatchEntry != null && !sameMatchEntry.getOriginal().equals(currentFlowEntry)) { - log.info("Modify: new container flow merged flow entry " + - "clashes with existing flow"); + log.info("Modify: new container flow merged flow entry " + + "clashes with existing flow"); decouple = true; } else { toInstallSafe.add(installEntry); @@ -347,13 +354,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, /* * The two list have the same size and the entries to install do not * clash with any existing flow on the network node. We assume here - * (and might be wrong) that the same container flows that were satisfied - * by the current entries are the same that are satisfied by the new - * entries. Let's take the risk for now. - * + * (and might be wrong) that the same container flows that were + * satisfied by the current entries are the same that are satisfied + * by the new entries. Let's take the risk for now. + * * Note: modification has to be complete. If any entry modification - * fails, we need to stop, restore the already modified entries, - * and declare failure. + * fails, we need to stop, restore the already modified entries, and + * declare failure. */ Status retModify; int i = 0; @@ -370,8 +377,8 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } // Check if uncompleted modify if (i < size) { - log.warn("Unable to perform a complete modify for all " + - "the container flows merged entries"); + log.warn("Unable to perform a complete modify for all " + + "the container flows merged entries"); // Restore original entries int j = 0; while (j < i) { @@ -386,7 +393,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } // Fatal error, recovery failed if (j < i) { - String msg = "Flow recovery failed ! Unrecoverable Error"; + String msg = "Flow recovery failed ! Unrecoverable Error"; log.error(msg); return new Status(StatusCode.INTERNALERROR, msg); } @@ -397,9 +404,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, /** * This is the function that modifies the final container flows merged - * entries on the network node and update the database. It expects that - * all the validity checks are passed - * + * entries on the network node and update the database. It expects that all + * the validity checks are passed + * * @param currentEntries * @param newEntries * @return @@ -412,12 +419,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, .getFlow()); if (!status.isSuccess()) { - log.warn("SDN Plugin failed to program the flow: " + status.getDescription()); + log.warn("SDN Plugin failed to program the flow: " + + status.getDescription()); return status; } - log.trace("Modified {} => {}", currentEntries.getInstall(), newEntries - .getInstall()); + log.trace("Modified {} => {}", currentEntries.getInstall(), + newEntries.getInstall()); // Update DB updateLocalDatabase(currentEntries, false); @@ -429,29 +437,29 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, /** * Remove a flow entry. If the entry is not present in the software view * (entry or node not present), it return successfully - * + * * @param flowEntry * @return */ private Status removeEntry(FlowEntry flowEntry) { Status error = new Status(null, null); - + // Sanity Check if (flowEntry == null || flowEntry.getNode() == null) { - String msg = "Invalid FlowEntry"; + String msg = "Invalid FlowEntry"; log.warn(msg + ": " + flowEntry); return new Status(StatusCode.NOTACCEPTABLE, msg); } // Derive the container flows merged installed entries - List installedList = deriveInstallEntries(flowEntry - .clone(), container.getContainerFlows()); + List installedList = deriveInstallEntries( + flowEntry.clone(), container.getContainerFlows()); Set flowsOnNode = nodeFlows.get(flowEntry.getNode()); boolean atLeastOneRemoved = false; for (FlowEntryInstall entry : installedList) { if (flowsOnNode == null) { - String msg = "Removal skipped (Node down)"; + String msg = "Removal skipped (Node down or Flow not on Node)"; log.debug(msg + " for flow entry " + flowEntry); return new Status(StatusCode.SUCCESS, msg); } @@ -483,20 +491,21 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } /* - * No worries if full removal failed. Consistency checker will - * take care of removing the stale entries later, or adjusting - * the software database if not in sync with hardware + * No worries if full removal failed. Consistency checker will take care + * of removing the stale entries later, or adjusting the software + * database if not in sync with hardware */ - return (atLeastOneRemoved) ? - new Status(StatusCode.SUCCESS, null) : error; + return (atLeastOneRemoved) ? new Status(StatusCode.SUCCESS, null) + : error; } /** * This is the function that removes the final container flows merged entry * from the network node and update the database. It expects that all the * validity checks are passed - * - * @param entry the FlowEntryInstall + * + * @param entry + * the FlowEntryInstall * @return "Success" or error string */ private Status removeEntryInternal(FlowEntryInstall entry) { @@ -504,13 +513,12 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, entry.toBeDeleted(); // Remove from node - Status status = - programmer.removeFlow(entry.getNode(), - entry.getInstall().getFlow()); + Status status = programmer.removeFlow(entry.getNode(), entry + .getInstall().getFlow()); if (!status.isSuccess()) { - log.warn("SDN Plugin failed to remove the flow: " + - status.getDescription()); + log.warn("SDN Plugin failed to remove the flow: " + + status.getDescription()); return status; } log.trace("Removed {}", entry.getInstall()); @@ -526,18 +534,19 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, * on the network node and updates the database. It expects that all the * validity and conflict checks are passed. That means it does not check * whether this flow would conflict or overwrite an existing one. - * - * @param entry the FlowEntryInstall + * + * @param entry + * the FlowEntryInstall * @return "Success" or error string */ private Status addEntriesInternal(FlowEntryInstall entry) { // Install the flow on the network node - Status status = programmer.addFlow(entry.getNode(), - entry.getInstall().getFlow()); + Status status = programmer.addFlow(entry.getNode(), entry.getInstall() + .getFlow()); if (!status.isSuccess()) { - log.warn("SDN Plugin failed to program the flow: " + - status.getDescription()); + log.warn("SDN Plugin failed to program the flow: " + + status.getDescription()); return status; } @@ -550,19 +559,21 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } /** - * Returns true if the flow conflicts with all the container's flows. - * This means that if the function returns true, the passed flow entry - * is congruent with at least one container flow, hence it is good to - * be installed on this container. - * + * Returns true if the flow conflicts with all the container's flows. This + * means that if the function returns true, the passed flow entry is + * congruent with at least one container flow, hence it is good to be + * installed on this container. + * * @param flowEntry - * @return true if flow conflicts with all the container flows, false otherwise + * @return true if flow conflicts with all the container flows, false + * otherwise */ private boolean entryConflictsWithContainerFlows(FlowEntry flowEntry) { List cFlowList = container.getContainerFlows(); // Validity check and avoid unnecessary computation - // Also takes care of default container where no container flows are present + // Also takes care of default container where no container flows are + // present if (cFlowList == null || cFlowList.isEmpty()) { return false; } @@ -702,9 +713,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, @Override public Status installFlowEntry(FlowEntry flowEntry) { - Status status; + Status status; if (inContainerMode) { - String msg = "Controller in container mode: Install Refused"; + String msg = "Controller in container mode: Install Refused"; status = new Status(StatusCode.NOTACCEPTABLE, msg); log.warn(msg); } else { @@ -715,13 +726,13 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, @Override public Status uninstallFlowEntry(FlowEntry entry) { - Status status; + Status status; if (inContainerMode) { - String msg = "Controller in container mode: Uninstall Refused"; + String msg = "Controller in container mode: Uninstall Refused"; status = new Status(StatusCode.NOTACCEPTABLE, msg); log.warn(msg); } else { - status = removeEntry(entry); + status = removeEntry(entry); } return status; } @@ -729,7 +740,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, @Override public Status modifyFlowEntry(FlowEntry currentFlowEntry, FlowEntry newFlowEntry) { - Status status = null; + Status status = null; if (inContainerMode) { String msg = "Controller in container mode: Modify Refused"; status = new Status(StatusCode.NOTACCEPTABLE, msg); @@ -745,11 +756,11 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, /* * Run a loose check on the installed entries to decide whether to go * with a add or modify method. A loose check means only check against - * the original flow entry requests and not against the installed - * flow entries which are the result of the original entry merged with - * the container flow(s) (if any). The modifyFlowEntry method in - * presence of conflicts with the Container flows (if any) would revert - * back to a delete + add pattern + * the original flow entry requests and not against the installed flow + * entries which are the result of the original entry merged with the + * container flow(s) (if any). The modifyFlowEntry method in presence of + * conflicts with the Container flows (if any) would revert back to a + * delete + add pattern */ FlowEntryInstall currentFlowEntries = findMatch(newFlowEntry, true); @@ -762,16 +773,18 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } /** - * Try to find in the database if a Flow with the same Match and priority - * of the passed one already exists for the specified network node. - * Flow, priority and network node are all specified in the FlowEntry - * If found, the respective FlowEntryInstall Object is returned - * - * @param flowEntry the FlowEntry to be tested against the ones installed - * @param looseCheck if true, the function will run the check against the - * original flow entry portion of the installed entries + * Try to find in the database if a Flow with the same Match and priority of + * the passed one already exists for the specified network node. Flow, + * priority and network node are all specified in the FlowEntry If found, + * the respective FlowEntryInstall Object is returned + * + * @param flowEntry + * the FlowEntry to be tested against the ones installed + * @param looseCheck + * if true, the function will run the check against the original + * flow entry portion of the installed entries * @return null if not found, otherwise the FlowEntryInstall which contains - * the existing flow entry + * the existing flow entry */ private FlowEntryInstall findMatch(FlowEntry flowEntry, boolean looseCheck) { Flow flow = flowEntry.getFlow(); @@ -797,12 +810,11 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } /** - * Updates all installed flows because the container flow got updated - * This is obtained in two phases on per node basis: - * 1) Uninstall of all flows - * 2) Reinstall of all flows - * This is needed because a new container flows merged flow may conflict with an existing - * old container flows merged flow on the network node + * Updates all installed flows because the container flow got updated This + * is obtained in two phases on per node basis: 1) Uninstall of all flows 2) + * Reinstall of all flows This is needed because a new container flows + * merged flow may conflict with an existing old container flows merged flow + * on the network node */ private void updateFlowsContainerFlow() { List oldCouples = new ArrayList(); @@ -814,16 +826,19 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, if (entry.getValue() == null) { continue; } - // Create a set of old entries and one of original entries to be reinstalled + // Create a set of old entries and one of original entries to be + // reinstalled for (FlowEntryInstall oldCouple : entry.getValue()) { oldCouples.add(oldCouple); toReinstall.add(oldCouple.getOriginal()); } - // Remove the old couples. No validity checks to be run, use the internal remove + // Remove the old couples. No validity checks to be run, use the + // internal remove for (FlowEntryInstall oldCouple : oldCouples) { this.removeEntryInternal(oldCouple); } - // Reinstall the original flow entries, via the regular path: new cFlow merge + validations + // Reinstall the original flow entries, via the regular path: new + // cFlow merge + validations for (FlowEntry flowEntry : toReinstall) { this.installFlowEntry(flowEntry); } @@ -919,7 +934,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, flowName); } else { log.warn("Failed to add ports {} to Flow entry {}: " - + error.getDescription(), portList, + + error.getDescription(), portList, currentFlowEntry.toString()); } return; @@ -949,16 +964,15 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, flowName); } else { log.warn("Failed to remove ports {} from Flow entry {}: " - + status.getDescription(), portList, + + status.getDescription(), portList, currentFlowEntry.toString()); } return; } } - log - .warn( - "Failed to remove ports from Flow {} on Node {}: Entry Not Found", - flowName, node); + log.warn( + "Failed to remove ports from Flow {} on Node {}: Entry Not Found", + flowName, node); } /* @@ -979,10 +993,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } } if (currentFlowEntry == null) { - log - .warn( - "Failed to replace output port for flow {} on node {}: Entry Not Found", - flowName, node); + log.warn( + "Failed to replace output port for flow {} on node {}: Entry Not Found", + flowName, node); return; } @@ -1036,37 +1049,36 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, @SuppressWarnings("deprecation") private void allocateCaches() { if (this.clusterContainerService == null) { - log - .warn("Un-initialized clusterContainerService, can't create cache"); + log.warn("Un-initialized clusterContainerService, can't create cache"); return; } log.debug("FRM allocateCaches for Container {}", container); try { - clusterContainerService.createCache("frm.nodeFlows", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + clusterContainerService.createCache("frm.nodeFlows", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); - clusterContainerService.createCache("frm.groupFlows", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + clusterContainerService.createCache("frm.groupFlows", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); - clusterContainerService.createCache("frm.staticFlows", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + clusterContainerService.createCache("frm.staticFlows", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); - clusterContainerService.createCache("frm.flowsSaveEvent", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + clusterContainerService.createCache("frm.flowsSaveEvent", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); clusterContainerService.createCache("frm.staticFlowsOrdinal", EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); - clusterContainerService.createCache("frm.portGroupConfigs", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + clusterContainerService.createCache("frm.portGroupConfigs", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); - clusterContainerService.createCache("frm.portGroupData", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + clusterContainerService.createCache("frm.portGroupData", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); - clusterContainerService.createCache("frm.TSPolicies", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + clusterContainerService.createCache("frm.TSPolicies", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); } catch (CacheConfigException cce) { log.error("FRM CacheConfigException"); @@ -1075,13 +1087,12 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } } - @SuppressWarnings( { "unchecked", "deprecation" }) + @SuppressWarnings({ "unchecked", "deprecation" }) private void retrieveCaches() { ConcurrentMap map; if (this.clusterContainerService == null) { - log - .warn("un-initialized clusterContainerService, can't retrieve cache"); + log.warn("un-initialized clusterContainerService, can't retrieve cache"); return; } @@ -1091,89 +1102,80 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, if (map != null) { nodeFlows = (ConcurrentMap>) map; } else { - log - .error( - "FRM Cache frm.nodeFlows allocation failed for Container {}", - container); + log.error( + "FRM Cache frm.nodeFlows allocation failed for Container {}", + container); } map = clusterContainerService.getCache("frm.groupFlows"); if (map != null) { groupFlows = (ConcurrentMap>) map; } else { - log - .error( - "FRM Cache frm.groupFlows allocation failed for Container {}", - container); + log.error( + "FRM Cache frm.groupFlows allocation failed for Container {}", + container); } map = clusterContainerService.getCache("frm.staticFlows"); if (map != null) { staticFlows = (ConcurrentMap) map; } else { - log - .error( - "FRM Cache frm.staticFlows allocation failed for Container {}", - container); + log.error( + "FRM Cache frm.staticFlows allocation failed for Container {}", + container); } map = clusterContainerService.getCache("frm.flowsSaveEvent"); if (map != null) { flowsSaveEvent = (ConcurrentMap) map; } else { - log - .error( - "FRM Cache frm.flowsSaveEvent allocation failed for Container {}", - container); + log.error( + "FRM Cache frm.flowsSaveEvent allocation failed for Container {}", + container); } map = clusterContainerService.getCache("frm.staticFlowsOrdinal"); if (map != null) { staticFlowsOrdinal = (ConcurrentMap) map; } else { - log - .error( - "FRM Cache frm.staticFlowsOrdinal allocation failed for Container {}", - container); + log.error( + "FRM Cache frm.staticFlowsOrdinal allocation failed for Container {}", + container); } map = clusterContainerService.getCache("frm.portGroupConfigs"); if (map != null) { portGroupConfigs = (ConcurrentMap) map; } else { - log - .error( - "FRM Cache frm.portGroupConfigs allocation failed for Container {}", - container); + log.error( + "FRM Cache frm.portGroupConfigs allocation failed for Container {}", + container); } map = clusterContainerService.getCache("frm.portGroupData"); if (map != null) { portGroupData = (ConcurrentMap>) map; } else { - log - .error( - "FRM Cache frm.portGroupData allocation failed for Container {}", - container); + log.error( + "FRM Cache frm.portGroupData allocation failed for Container {}", + container); } map = clusterContainerService.getCache("frm.TSPolicies"); if (map != null) { TSPolicies = (ConcurrentMap) map; } else { - log - .error( - "FRM Cache frm.TSPolicies allocation failed for Container {}", - container); + log.error( + "FRM Cache frm.TSPolicies allocation failed for Container {}", + container); } } @SuppressWarnings("deprecation") - private void destroyCaches() { + private void destroyCaches() { if (this.clusterContainerService == null) { - log - .warn("Un-initialized clusterContainerService, can't destroy cache"); + log.warn("Un-initialized clusterContainerService, can't destroy cache"); return; } @@ -1263,9 +1265,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, * multiple entry configuration (PortGroup) and hardware installation is * NOT done directly on this event. 3. The User prefers to retain the * configuration in Controller and skip hardware installation. - * + * * Hence it is safe to update the StaticFlow DB at this point. - * + * * Note : For the case of PortGrouping, it is essential to have this DB * populated before the PortGroupListeners can query for the DB * triggered using portGroupChanged event... @@ -1293,7 +1295,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, if (config.getNode().equals(node)) { if (config.installInHw() && !config.getStatus().equals( - StatusCode.SUCCESS.toString())) { + StatusCode.SUCCESS.toString())) { Status status = this.addEntry(config.getFlowEntry()); config.setStatus(status.getDescription()); } @@ -1305,27 +1307,27 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, log.trace("Updating Static Flow configs on node down: " + node); List toRemove = new ArrayList(); - for (Entry entry : staticFlows.entrySet()) { + for (Entry entry : staticFlows.entrySet()) { - FlowConfig config = entry.getValue(); + FlowConfig config = entry.getValue(); if (config.isPortGroupEnabled()) { continue; } - + if (config.installInHw() && config.getNode().equals(node)) { - if (config.isInternalFlow()) { - // Take note of this controller generated static flow - toRemove.add(entry.getKey()); - } else { - config.setStatus(NODEDOWN); - } + if (config.isInternalFlow()) { + // Take note of this controller generated static flow + toRemove.add(entry.getKey()); + } else { + config.setStatus(NODEDOWN); + } } } - // Remove controller generated static flows for this node + // Remove controller generated static flows for this node for (Integer index : toRemove) { - staticFlows.remove(index); - } + staticFlows.remove(index); + } } private void updateStaticFlowConfigsOnContainerModeChange(UpdateType update) { @@ -1339,8 +1341,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, if (config.installInHw()) { switch (update) { case ADDED: - config - .setStatus("Removed from node because in container mode"); + config.setStatus("Removed from node because in container mode"); break; case REMOVED: config.setStatus(StatusCode.SUCCESS.toString()); @@ -1354,15 +1355,15 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, public Status removeStaticFlow(FlowConfig config) { /* * No config.isInternal() check as NB does not take this path and GUI - * cannot issue a delete on an internal generated flow. We need this path - * to be accessible when switch mode is changed from proactive to + * cannot issue a delete on an internal generated flow. We need this + * path to be accessible when switch mode is changed from proactive to * reactive, so that we can remove the internal generated LLDP and ARP * punt flows */ for (Map.Entry entry : staticFlows.entrySet()) { if (entry.getValue().isByNameAndNodeIdEqual(config)) { // Program the network node - Status status = this.removeEntry(config.getFlowEntry()); + Status status = this.removeEntry(config.getFlowEntry()); // Update configuration database if programming was successful if (status.isSuccess()) { staticFlows.remove(entry.getKey()); @@ -1380,14 +1381,14 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, public Status removeStaticFlow(String name, Node node) { for (Map.Entry mapEntry : staticFlows.entrySet()) { FlowConfig entry = mapEntry.getValue(); - Status status = new Status(null,null); + Status status = new Status(null, null); if (entry.isByNameAndNodeIdEqual(name, node)) { // Validity check for api3 entry point if (entry.isInternalFlow()) { - String msg = "Invalid operation: Controller generated " + - "flow cannot be deleted"; - log.warn(msg); - return new Status(StatusCode.NOTACCEPTABLE, msg); + String msg = "Invalid operation: Controller generated " + + "flow cannot be deleted"; + log.warn(msg); + return new Status(StatusCode.NOTACCEPTABLE, msg); } if (!entry.isPortGroupEnabled()) { // Program the network node @@ -1409,17 +1410,16 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, public Status modifyStaticFlow(FlowConfig newFlowConfig) { // Validity check for api3 entry point if (newFlowConfig.isInternalFlow()) { - String msg = "Invalid operation: Controller generated flow " + - "cannot be modified"; - log.warn(msg); + String msg = "Invalid operation: Controller generated flow " + + "cannot be modified"; + log.warn(msg); return new Status(StatusCode.NOTACCEPTABLE, msg); } // Validity Check StringBuffer resultStr = new StringBuffer(); if (!newFlowConfig.isValid(container, resultStr)) { - String msg = "Invalid Configuration (" + resultStr.toString() - + ")"; + String msg = "Invalid Configuration (" + resultStr.toString() + ")"; newFlowConfig.setStatus(msg); log.warn(msg); return new Status(StatusCode.BADREQUEST, msg); @@ -1438,22 +1438,22 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } if (oldFlowConfig == null) { - String msg = "Attempt to modify a non existing static flow"; - log.warn(msg); - return new Status(StatusCode.NOTFOUND, msg); + String msg = "Attempt to modify a non existing static flow"; + log.warn(msg); + return new Status(StatusCode.NOTFOUND, msg); } // Do not attempt to reinstall the flow, warn user if (newFlowConfig.equals(oldFlowConfig)) { - String msg = "No modification detected"; - log.info("Static flow modification skipped: " + msg); + String msg = "No modification detected"; + log.info("Static flow modification skipped: " + msg); return new Status(StatusCode.SUCCESS, msg); } // If flow is installed, program the network node Status status = new Status(StatusCode.SUCCESS, "Saved in config"); if (oldFlowConfig.installInHw()) { - status = this.modifyEntry(oldFlowConfig.getFlowEntry(), + status = this.modifyEntry(oldFlowConfig.getFlowEntry(), newFlowConfig.getFlowEntry()); } @@ -1466,26 +1466,24 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, return status; } + @Override + public Status toggleStaticFlowStatus(String name, Node node) { + return toggleStaticFlowStatus(getStaticFlow(name, node)); + } - - @Override - public Status toggleStaticFlowStatus(String name, Node node) { - return toggleStaticFlowStatus(getStaticFlow(name, node)); - } - @Override public Status toggleStaticFlowStatus(FlowConfig config) { - if (config == null) { - String msg = "Invalid request: null flow config"; - log.warn(msg); - return new Status(StatusCode.BADREQUEST, msg); - } + if (config == null) { + String msg = "Invalid request: null flow config"; + log.warn(msg); + return new Status(StatusCode.BADREQUEST, msg); + } // Validity check for api3 entry point if (config.isInternalFlow()) { - String msg = "Invalid operation: Controller generated flow " + - "cannot be modified"; - log.warn(msg); - return new Status(StatusCode.NOTACCEPTABLE, msg); + String msg = "Invalid operation: Controller generated flow " + + "cannot be modified"; + log.warn(msg); + return new Status(StatusCode.NOTACCEPTABLE, msg); } for (Map.Entry entry : staticFlows.entrySet()) { @@ -1510,15 +1508,14 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } } return new Status(StatusCode.NOTFOUND, - "Unable to locate the entry. Failed to toggle status"); + "Unable to locate the entry. Failed to toggle status"); } /** - * Uninstall all the Flow Entries present in the software view - * A copy of each entry is stored in the inactive list so - * that it can be re-applied when needed - * This function is called on the default container instance of FRM only - * when the first container is created + * Uninstall all the Flow Entries present in the software view A copy of + * each entry is stored in the inactive list so that it can be re-applied + * when needed This function is called on the default container instance of + * FRM only when the first container is created */ private void uninstallAllFlowEntries() { log.info("Uninstalling all flows"); @@ -1535,26 +1532,27 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, for (FlowEntry flowEntry : inactiveFlows) { Status status = this.removeEntry(flowEntry); if (!status.isSuccess()) { - log.warn("Failed to remove entry: {}: " + - status.getDescription(), flowEntry); + log.warn( + "Failed to remove entry: {}: " + + status.getDescription(), flowEntry); } } } /** - * Re-install all the Flow Entries present in the inactive list - * The inactive list will be empty at the end of this call - * This function is called on the default container instance of FRM only - * when the last container is deleted + * Re-install all the Flow Entries present in the inactive list The inactive + * list will be empty at the end of this call This function is called on the + * default container instance of FRM only when the last container is deleted */ private void reinstallAllFlowEntries() { log.info("Reinstalling all inactive flows"); for (FlowEntry flowEntry : this.inactiveFlows) { - Status status = this.addEntry(flowEntry); + Status status = this.addEntry(flowEntry); if (!status.isSuccess()) { - log.warn("Failed to install entry: {}: " + - status.getDescription(), flowEntry); + log.warn( + "Failed to install entry: {}: " + + status.getDescription(), flowEntry); } } @@ -1746,8 +1744,9 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, allowLLDP.setName("**Punt LLDP"); allowLLDP.setPriority("1"); allowLLDP.setNode(node); - allowLLDP.setEtherType("0x" - + Integer.toHexString(EtherTypes.LLDP.intValue()) + allowLLDP + .setEtherType("0x" + + Integer.toHexString(EtherTypes.LLDP.intValue()) .toUpperCase()); allowLLDP.setActions(puntAction); defaultConfigs.add(allowLLDP); @@ -1776,7 +1775,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, /** * Remove from the databases all the flows installed on the node - * + * * @param node */ private synchronized void cleanDatabaseForNode(Node node) { @@ -1819,10 +1818,10 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, public void notifyNode(Node node, UpdateType type, Map propMap) { switch (type) { - case ADDED: + case ADDED: addStaticFlowsToSwitch(node); break; - case REMOVED: + case REMOVED: cleanDatabaseForNode(node); updateStaticFlowConfigsOnNodeDown(node); break; @@ -1833,7 +1832,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, @Override public void notifyNodeConnector(NodeConnector nodeConnector, - UpdateType type, Map propMap) { + UpdateType type, Map propMap) { } private FlowConfig getDerivedFlowConfig(FlowConfig original, @@ -1887,8 +1886,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, @Override public void portGroupChanged(PortGroupConfig config, Map data, boolean add) { - log.info("PortGroup Changed for :" + config + " Data: " - + portGroupData); + log.info("PortGroup Changed for :" + config + " Data: " + portGroupData); Map existingData = portGroupData.get(config); if (existingData != null) { for (Map.Entry entry : data.entrySet()) { @@ -1896,20 +1894,20 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, if (existingPortGroup == null) { if (add) { existingData.put(entry.getKey(), entry.getValue()); - addPortGroupFlows(config, entry.getKey(), entry - .getValue()); + addPortGroupFlows(config, entry.getKey(), + entry.getValue()); } } else { if (add) { existingPortGroup.getPorts().addAll( entry.getValue().getPorts()); - addPortGroupFlows(config, entry.getKey(), entry - .getValue()); + addPortGroupFlows(config, entry.getKey(), + entry.getValue()); } else { existingPortGroup.getPorts().removeAll( entry.getValue().getPorts()); - removePortGroupFlows(config, entry.getKey(), entry - .getValue()); + removePortGroupFlows(config, entry.getKey(), + entry.getValue()); } } } @@ -2063,15 +2061,15 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, /** * Function called by the dependency manager when all the required * dependencies are satisfied - * + * */ void init() { frmAware = Collections .synchronizedSet(new HashSet()); - frmFileName = GlobalConstants.STARTUPHOME.toString() + "frm_staticflows_" - + this.getContainerName() + ".conf"; - portGroupFileName = GlobalConstants.STARTUPHOME.toString() + "portgroup_" - + this.getContainerName() + ".conf"; + frmFileName = GlobalConstants.STARTUPHOME.toString() + + "frm_staticflows_" + this.getContainerName() + ".conf"; + portGroupFileName = GlobalConstants.STARTUPHOME.toString() + + "portgroup_" + this.getContainerName() + ".conf"; inContainerMode = false; @@ -2098,7 +2096,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, * 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() { destroyCaches(); @@ -2107,7 +2105,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, /** * 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() { /* @@ -2123,7 +2121,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, * 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() { } @@ -2158,8 +2156,8 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, public void containerFlowUpdated(String containerName, ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) { /* - * Whether it is an addition or removal, we have to recompute the - * merged flows entries taking into account all the current container flows + * Whether it is an addition or removal, we have to recompute the merged + * flows entries taking into account all the current container flows * because flow merging is not an injective function */ updateFlowsContainerFlow(); @@ -2315,7 +2313,7 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, @Override public Status saveConfiguration() { - return saveConfig(); + return saveConfig(); } public void _frmNodeFlows(CommandInterpreter ci) { @@ -2361,4 +2359,28 @@ public class ForwardingRulesManagerImpl implements IForwardingRulesManager, } } + @Override + public void flowRemoved(Node node, Flow flow) { + log.trace("Received flow removed notification on {} for {}", node, flow); + // For flow entry identification, only match and priority matter + FlowEntry toFind = new FlowEntry("any", "any", flow, node); + FlowEntryInstall installedEntry = this.findMatch(toFind, false); + if (installedEntry == null) { + log.trace("Entry is not know to us"); + return; + } + + // Update Static flow status + for (Map.Entry entry : staticFlows.entrySet()) { + FlowConfig conf = entry.getValue(); + if (conf.isByNameAndNodeIdEqual(installedEntry.getFlowName(), node)) { + // Update Configuration database + conf.toggleStatus(); + break; + } + } + // Update software views + this.updateLocalDatabase(installedEntry, false); + } + } diff --git a/opendaylight/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/HostTracker.java b/opendaylight/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/HostTracker.java index 7046e343e7..371dca6969 100644 --- a/opendaylight/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/HostTracker.java +++ b/opendaylight/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/HostTracker.java @@ -201,7 +201,7 @@ public class HostTracker implements IfIptoHost, IfHostListener, logger.debug("Retrieving cache for HostTrackerIH"); inactiveStaticHosts = (ConcurrentMap) this.clusterContainerService .getCache("hostTrackerIH"); - if (hostsDB == null) { + if (inactiveStaticHosts == null) { logger.error("Cache couldn't be retrieved for HostTrackerIH"); } logger.debug("Cache was successfully retrieved for HostTrackerIH"); diff --git a/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java b/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java index d79c4dab89..2275ee98da 100644 --- a/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java +++ b/opendaylight/northbound/hosttracker/src/main/java/org/opendaylight/controller/hosttracker/northbound/HostTrackerNorthbound.java @@ -14,6 +14,7 @@ import java.net.UnknownHostException; import java.util.List; import java.util.Set; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.DefaultValue; diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java new file mode 100644 index 0000000000..307176590f --- /dev/null +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/IFlowProgrammerNotifier.java @@ -0,0 +1,22 @@ +/* + * 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.protocol_plugin.openflow; + +import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService; + +/** + * Interface which defines the methods exposed by the Flow Programmer Notifier. + * Their implementation relays the asynchronous messages received from the + * network nodes to the the SAL Flow Programmer Notifier Service on the proper + * container. + */ +public interface IFlowProgrammerNotifier extends + IPluginOutFlowProgrammerService { + +} diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java index f3004acaba..32cdeaa614 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/Controller.java @@ -9,6 +9,7 @@ package org.opendaylight.controller.protocol_plugin.openflow.core.internal; +import java.io.FileNotFoundException; import java.io.IOException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; @@ -338,6 +339,28 @@ public class Controller implements IController, CommandProvider { } } + public void _controllerShowConnConfig(CommandInterpreter ci) { + String str = System.getProperty("secureChannelEnabled"); + if ((str != null) && (str.trim().equalsIgnoreCase("true"))) { + ci.print("The Controller and Switch should communicate through TLS connetion.\n"); + + String keyStoreFile = System.getProperty("controllerKeyStore"); + String trustStoreFile = System.getProperty("controllerTrustStore"); + if ((keyStoreFile == null) || keyStoreFile.trim().isEmpty()) { + ci.print("controllerKeyStore not specified in ./configuration/config.ini\n"); + } else { + ci.print("controllerKeyStore=" + keyStoreFile + "\n"); + } + if ((trustStoreFile == null) || trustStoreFile.trim().isEmpty()) { + ci.print("controllerTrustStore not specified in ./configuration/config.ini\n"); + } else { + ci.print("controllerTrustStore=" + trustStoreFile + "\n"); + } + } else { + ci.print("The Controller and Switch should communicate through TCP connetion.\n"); + } + } + private void registerWithOSGIConsole() { BundleContext bundleContext = FrameworkUtil.getBundle(this.getClass()) .getBundleContext(); @@ -351,6 +374,7 @@ public class Controller implements IController, CommandProvider { help.append("--Open Flow Controller --\n"); help.append("\tcontrollerShowSwitches\n"); help.append("\tcontrollerReset\n"); + help.append("\tcontrollerShowConnConfig\n"); return help.toString(); } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/MessageReadWriteService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/MessageReadWriteService.java index fb34b0f063..8e611924e4 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/MessageReadWriteService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/MessageReadWriteService.java @@ -69,6 +69,8 @@ public class MessageReadWriteService implements IMessageReadWrite { newBuffer.put(outBuffer); outBuffer = newBuffer; } + } + synchronized (outBuffer) { msg.writeTo(outBuffer); if (!socket.isOpen()) { diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java index ddc87bc530..bb8ba04fb8 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SecureMessageReadWriteService.java @@ -10,6 +10,7 @@ package org.opendaylight.controller.protocol_plugin.openflow.core.internal; import java.io.FileInputStream; +import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.AsynchronousCloseException; @@ -74,11 +75,36 @@ public class SecureMessageReadWriteService implements IMessageReadWrite { * @throws Exception */ private void createSecureChannel(SocketChannel socket) throws Exception { - String keyStoreFile = System.getProperty("controllerKeyStore").trim(); - String keyStorePassword = System.getProperty("controllerKeyStorePassword").trim(); - String trustStoreFile = System.getProperty("controllerTrustStore").trim(); - String trustStorePassword = System.getProperty("controllerTrustStorePassword").trim(); - + String keyStoreFile = System.getProperty("controllerKeyStore"); + String keyStorePassword = System.getProperty("controllerKeyStorePassword"); + String trustStoreFile = System.getProperty("controllerTrustStore"); + String trustStorePassword = System.getProperty("controllerTrustStorePassword"); + + if (keyStoreFile != null) { + keyStoreFile = keyStoreFile.trim(); + } + if ((keyStoreFile == null) || keyStoreFile.isEmpty()) { + throw new FileNotFoundException("controllerKeyStore not specified in ./configuration/config.ini"); + } + if (keyStorePassword != null) { + keyStorePassword = keyStorePassword.trim(); + } + if ((keyStorePassword == null) || keyStorePassword.isEmpty()) { + throw new FileNotFoundException("controllerKeyStorePassword not specified in ./configuration/config.ini"); + } + if (trustStoreFile != null) { + trustStoreFile = trustStoreFile.trim(); + } + if ((trustStoreFile == null) || trustStoreFile.isEmpty()) { + throw new FileNotFoundException("controllerTrustStore not specified in ./configuration/config.ini"); + } + if (trustStorePassword != null) { + trustStorePassword = trustStorePassword.trim(); + } + if ((trustStorePassword == null) || trustStorePassword.isEmpty()) { + throw new FileNotFoundException("controllerTrustStorePassword not specified in ./configuration/config.ini"); + } + KeyStore ks = KeyStore.getInstance("JKS"); KeyStore ts = KeyStore.getInstance("JKS"); KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509"); @@ -126,6 +152,8 @@ public class SecureMessageReadWriteService implements IMessageReadWrite { newBuffer.put(myAppData); myAppData = newBuffer; } + } + synchronized (myAppData) { msg.writeTo(myAppData); myAppData.flip(); sslEngineResult = sslEngine.wrap(myAppData, myNetData); diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchHandler.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchHandler.java index cba8b1d4f1..5913ad0dd9 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchHandler.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/core/internal/SwitchHandler.java @@ -9,7 +9,7 @@ package org.opendaylight.controller.protocol_plugin.openflow.core.internal; -import java.io.IOException; +import java.net.SocketException; import java.nio.channels.AsynchronousCloseException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; @@ -249,7 +249,9 @@ public class SwitchHandler implements ISwitch { @Override public Integer asyncSend(OFMessage msg, int xid) { msg.setXid(xid); - transmitQ.add(new PriorityMessage(msg, 0)); + if (transmitQ != null) { + transmitQ.add(new PriorityMessage(msg, 0)); + } return xid; } @@ -280,13 +282,17 @@ public class SwitchHandler implements ISwitch { @Override public Integer asyncFastSend(OFMessage msg, int xid) { msg.setXid(xid); - transmitQ.add(new PriorityMessage(msg, 1)); + if (transmitQ != null) { + transmitQ.add(new PriorityMessage(msg, 1)); + } return xid; } public void resumeSend() { try { - msgReadWriteService.resumeSend(); + if (msgReadWriteService != null) { + msgReadWriteService.resumeSend(); + } } catch (Exception e) { reportError(e); } @@ -445,7 +451,9 @@ public class SwitchHandler implements ISwitch { } private void reportError(Exception e) { - if (e instanceof AsynchronousCloseException) { + if (e instanceof AsynchronousCloseException || + e instanceof InterruptedException || + e instanceof SocketException) { logger.debug("Caught exception {}", e.getMessage()); } else { logger.warn("Caught exception {}", e.getMessage()); @@ -739,6 +747,8 @@ public class SwitchHandler implements ISwitch { logger.trace("Message sent: {}", pmsg.toString()); } Thread.sleep(10); + } catch (InterruptedException ie) { + reportError(new InterruptedException("PriorityMessageTransmit thread interrupted")); } catch (Exception e) { reportError(e); } 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 45c0211787..26471a7f75 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,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -15,6 +14,7 @@ import java.util.Hashtable; import org.apache.felix.dm.Component; import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketListen; import org.opendaylight.controller.protocol_plugin.openflow.IDataPacketMux; +import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier; import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimExternalListener; import org.opendaylight.controller.protocol_plugin.openflow.IInventoryShimInternalListener; import org.opendaylight.controller.protocol_plugin.openflow.IOFStatisticsManager; @@ -23,12 +23,14 @@ import org.opendaylight.controller.protocol_plugin.openflow.IRefreshInternalProv import org.opendaylight.controller.protocol_plugin.openflow.IStatisticsListener; import org.opendaylight.controller.protocol_plugin.openflow.ITopologyServiceShimListener; import org.opendaylight.controller.protocol_plugin.openflow.core.IController; +import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener; import org.opendaylight.controller.protocol_plugin.openflow.core.internal.Controller; import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase; import org.opendaylight.controller.sal.core.IContainerListener; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.discovery.IDiscoveryService; import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService; +import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService; import org.opendaylight.controller.sal.inventory.IPluginInInventoryService; import org.opendaylight.controller.sal.inventory.IPluginOutInventoryService; import org.opendaylight.controller.sal.packet.IPluginInDataPacketService; @@ -42,92 +44,98 @@ import org.slf4j.LoggerFactory; /** * Openflow protocol plugin Activator - * - * + * + * */ public class Activator extends ComponentActivatorAbstractBase { protected static final Logger logger = LoggerFactory .getLogger(Activator.class); /** - * Function called when the activator starts just after some - * initializations are done by the - * ComponentActivatorAbstractBase. - * + * Function called when the activator starts just after some initializations + * are done by the ComponentActivatorAbstractBase. + * */ public void init() { } /** - * Function called when the activator stops just before the - * cleanup done by ComponentActivatorAbstractBase - * + * Function called when the activator stops just before the cleanup done by + * ComponentActivatorAbstractBase + * */ public void destroy() { } /** - * Function that is used to communicate to dependency manager the - * list of known implementations for services inside a container - * - * + * Function that is used to communicate to dependency manager the list of + * known implementations for services inside a container + * + * * @return An array containing all the CLASS objects that will be - * instantiated in order to get an fully working implementation - * Object + * instantiated in order to get an fully working implementation + * Object */ public Object[] getImplementations() { Object[] res = { TopologyServices.class, DataPacketServices.class, - InventoryService.class, ReadService.class }; + InventoryService.class, ReadService.class, + FlowProgrammerNotifier.class }; return res; } /** - * Function that is called when configuration of the dependencies - * is required. - * - * @param c dependency manager Component object, used for - * configuring the dependencies exported and imported - * @param imp Implementation class that is being configured, - * needed as long as the same routine can configure multiple - * implementations - * @param containerName The containerName being configured, this allow - * also optional per-container different behavior if needed, usually - * should not be the case though. + * Function that is called when configuration of the dependencies is + * required. + * + * @param c + * dependency manager Component object, used for configuring the + * dependencies exported and imported + * @param imp + * Implementation class that is being configured, needed as long + * as the same routine can configure multiple implementations + * @param containerName + * The containerName being configured, this allow also optional + * per-container different behavior if needed, usually should not + * be the case though. */ public void configureInstance(Component c, Object imp, String containerName) { if (imp.equals(TopologyServices.class)) { // export the service to be used by SAL - c.setInterface(new String[] { - IPluginInTopologyService.class.getName(), - ITopologyServiceShimListener.class.getName() }, null); + c.setInterface( + new String[] { IPluginInTopologyService.class.getName(), + ITopologyServiceShimListener.class.getName() }, + null); // Hook the services coming in from SAL, as optional in // case SAL is not yet there, could happen - c.add(createContainerServiceDependency(containerName).setService( - IPluginOutTopologyService.class).setCallbacks( - "setPluginOutTopologyService", - "unsetPluginOutTopologyService").setRequired(false)); - c.add(createServiceDependency().setService( - IRefreshInternalProvider.class).setCallbacks( - "setRefreshInternalProvider", - "unsetRefreshInternalProvider").setRequired(false)); + c.add(createContainerServiceDependency(containerName) + .setService(IPluginOutTopologyService.class) + .setCallbacks("setPluginOutTopologyService", + "unsetPluginOutTopologyService").setRequired(false)); + c.add(createServiceDependency() + .setService(IRefreshInternalProvider.class) + .setCallbacks("setRefreshInternalProvider", + "unsetRefreshInternalProvider").setRequired(false)); } if (imp.equals(InventoryService.class)) { // export the service - c.setInterface(new String[] { - IPluginInInventoryService.class.getName(), - IStatisticsListener.class.getName(), - IInventoryShimInternalListener.class.getName() }, null); + c.setInterface( + new String[] { IPluginInInventoryService.class.getName(), + IStatisticsListener.class.getName(), + IInventoryShimInternalListener.class.getName() }, + null); // Now lets add a service dependency to make sure the // provider of service exists - c.add(createServiceDependency().setService(IController.class, - "(name=Controller)").setCallbacks("setController", - "unsetController").setRequired(true)); - c.add(createContainerServiceDependency(containerName).setService( - IPluginOutInventoryService.class).setCallbacks( - "setPluginOutInventoryServices", - "unsetPluginOutInventoryServices").setRequired(false)); + c.add(createServiceDependency() + .setService(IController.class, "(name=Controller)") + .setCallbacks("setController", "unsetController") + .setRequired(true)); + c.add(createContainerServiceDependency(containerName) + .setService(IPluginOutInventoryService.class) + .setCallbacks("setPluginOutInventoryServices", + "unsetPluginOutInventoryServices") + .setRequired(false)); } if (imp.equals(DataPacketServices.class)) { @@ -139,17 +147,19 @@ public class Activator extends ComponentActivatorAbstractBase { c.setInterface(IPluginInDataPacketService.class.getName(), props); // Hook the services coming in from SAL, as optional in // case SAL is not yet there, could happen - c.add(createServiceDependency().setService(IController.class, - "(name=Controller)").setCallbacks("setController", - "unsetController").setRequired(true)); + c.add(createServiceDependency() + .setService(IController.class, "(name=Controller)") + .setCallbacks("setController", "unsetController") + .setRequired(true)); // This is required for the transmission to happen properly c.add(createServiceDependency().setService(IDataPacketMux.class) .setCallbacks("setIDataPacketMux", "unsetIDataPacketMux") .setRequired(true)); - c.add(createContainerServiceDependency(containerName).setService( - IPluginOutDataPacketService.class).setCallbacks( - "setPluginOutDataPacketService", - "unsetPluginOutDataPacketService").setRequired(false)); + c.add(createContainerServiceDependency(containerName) + .setService(IPluginOutDataPacketService.class) + .setCallbacks("setPluginOutDataPacketService", + "unsetPluginOutDataPacketService") + .setRequired(false)); } if (imp.equals(ReadService.class)) { @@ -159,21 +169,36 @@ public class Activator extends ComponentActivatorAbstractBase { // by SAL props.put("protocolPluginType", Node.NodeIDType.OPENFLOW); c.setInterface(IPluginInReadService.class.getName(), props); - c.add(createServiceDependency().setService( - IPluginReadServiceFilter.class).setCallbacks("setService", - "unsetService").setRequired(true)); + c.add(createServiceDependency() + .setService(IPluginReadServiceFilter.class) + .setCallbacks("setService", "unsetService") + .setRequired(true)); + } + + if (imp.equals(FlowProgrammerNotifier.class)) { + // export the service to be used by SAL + Dictionary props = new Hashtable(); + // Set the protocolPluginType property which will be used + // by SAL + props.put("protocolPluginType", Node.NodeIDType.OPENFLOW); + c.setInterface(IFlowProgrammerNotifier.class.getName(), props); + + c.add(createContainerServiceDependency(containerName) + .setService(IPluginOutFlowProgrammerService.class) + .setCallbacks("setPluginOutFlowProgrammerService", + "unsetPluginOutFlowProgrammerService") + .setRequired(true)); } } /** - * Function that is used to communicate to dependency manager the - * list of known implementations for services that are container - * independent. - * - * + * Function that is used to communicate to dependency manager the list of + * known implementations for services that are container independent. + * + * * @return An array containing all the CLASS objects that will be - * instantiated in order to get an fully working implementation - * Object + * instantiated in order to get an fully working implementation + * Object */ public Object[] getGlobalImplementations() { Object[] res = { Controller.class, OFStatisticsManager.class, @@ -184,14 +209,15 @@ public class Activator extends ComponentActivatorAbstractBase { } /** - * Function that is called when configuration of the dependencies - * is required. - * - * @param c dependency manager Component object, used for - * configuring the dependencies exported and imported - * @param imp Implementation class that is being configured, - * needed as long as the same routine can configure multiple - * implementations + * Function that is called when configuration of the dependencies is + * required. + * + * @param c + * dependency manager Component object, used for configuring the + * dependencies exported and imported + * @param imp + * Implementation class that is being configured, needed as long + * as the same routine can configure multiple implementations */ public void configureGlobalInstance(Component c, Object imp) { @@ -208,26 +234,39 @@ public class Activator extends ComponentActivatorAbstractBase { // Set the protocolPluginType property which will be used // by SAL props.put("protocolPluginType", Node.NodeIDType.OPENFLOW); - c.setInterface(IPluginInFlowProgrammerService.class - .getName(), props); + c.setInterface( + new String[] { + IPluginInFlowProgrammerService.class.getName(), + IMessageListener.class.getName(), + IContainerListener.class.getName() }, props); + + c.add(createServiceDependency() + .setService(IController.class, "(name=Controller)") + .setCallbacks("setController", "unsetController") + .setRequired(true)); + + c.add(createServiceDependency() + .setService(IFlowProgrammerNotifier.class) + .setCallbacks("setFlowProgrammerNotifier", + "unsetsetFlowProgrammerNotifier") + .setRequired(false)); - c.add(createServiceDependency().setService(IController.class, - "(name=Controller)").setCallbacks("setController", - "unsetController").setRequired(true)); } if (imp.equals(ReadServiceFilter.class)) { - c.setInterface(new String[] { - IPluginReadServiceFilter.class.getName(), - IContainerListener.class.getName() }, null); + c.setInterface( + new String[] { IPluginReadServiceFilter.class.getName(), + IContainerListener.class.getName() }, null); - c.add(createServiceDependency().setService(IController.class, - "(name=Controller)").setCallbacks("setController", - "unsetController").setRequired(true)); - c.add(createServiceDependency().setService( - IOFStatisticsManager.class).setCallbacks("setService", - "unsetService").setRequired(true)); + c.add(createServiceDependency() + .setService(IController.class, "(name=Controller)") + .setCallbacks("setController", "unsetController") + .setRequired(true)); + c.add(createServiceDependency() + .setService(IOFStatisticsManager.class) + .setCallbacks("setService", "unsetService") + .setRequired(true)); } if (imp.equals(OFStatisticsManager.class)) { @@ -235,34 +274,38 @@ public class Activator extends ComponentActivatorAbstractBase { c.setInterface(new String[] { IOFStatisticsManager.class.getName(), IInventoryShimExternalListener.class.getName() }, null); - c.add(createServiceDependency().setService(IController.class, - "(name=Controller)").setCallbacks("setController", - "unsetController").setRequired(true)); - c.add(createServiceDependency().setService( - IStatisticsListener.class) - .setCallbacks("setStatisticsListener", - "unsetStatisticsListener").setRequired(false)); + c.add(createServiceDependency() + .setService(IController.class, "(name=Controller)") + .setCallbacks("setController", "unsetController") + .setRequired(true)); + c.add(createServiceDependency() + .setService(IStatisticsListener.class) + .setCallbacks("setStatisticsListener", + "unsetStatisticsListener").setRequired(false)); } if (imp.equals(DiscoveryService.class)) { // export the service - c.setInterface(new String[] { - IInventoryShimExternalListener.class.getName(), - IDataPacketListen.class.getName(), - IContainerListener.class.getName() }, null); - - c.add(createServiceDependency().setService(IController.class, - "(name=Controller)").setCallbacks("setController", - "unsetController").setRequired(true)); + c.setInterface( + new String[] { + IInventoryShimExternalListener.class.getName(), + IDataPacketListen.class.getName(), + IContainerListener.class.getName() }, null); + + c.add(createServiceDependency() + .setService(IController.class, "(name=Controller)") + .setCallbacks("setController", "unsetController") + .setRequired(true)); c.add(createContainerServiceDependency( - GlobalConstants.DEFAULT.toString()).setService( - IPluginInInventoryService.class).setCallbacks( - "setPluginInInventoryService", - "unsetPluginInInventoryService").setRequired(true)); + GlobalConstants.DEFAULT.toString()) + .setService(IPluginInInventoryService.class) + .setCallbacks("setPluginInInventoryService", + "unsetPluginInInventoryService").setRequired(true)); c.add(createServiceDependency().setService(IDataPacketMux.class) .setCallbacks("setIDataPacketMux", "unsetIDataPacketMux") .setRequired(true)); - c.add(createServiceDependency().setService(IDiscoveryService.class) + c.add(createServiceDependency() + .setService(IDiscoveryService.class) .setCallbacks("setDiscoveryService", "unsetDiscoveryService").setRequired(true)); } @@ -274,15 +317,18 @@ public class Activator extends ComponentActivatorAbstractBase { IContainerListener.class.getName(), IInventoryShimExternalListener.class.getName() }, null); - c.add(createServiceDependency().setService(IController.class, - "(name=Controller)").setCallbacks("setController", - "unsetController").setRequired(true)); - c.add(createServiceDependency().setService( - IPluginOutDataPacketService.class).setCallbacks( - "setPluginOutDataPacketService", - "unsetPluginOutDataPacketService").setRequired(false)); + c.add(createServiceDependency() + .setService(IController.class, "(name=Controller)") + .setCallbacks("setController", "unsetController") + .setRequired(true)); + c.add(createServiceDependency() + .setService(IPluginOutDataPacketService.class) + .setCallbacks("setPluginOutDataPacketService", + "unsetPluginOutDataPacketService") + .setRequired(false)); // See if there is any local packet dispatcher - c.add(createServiceDependency().setService(IDataPacketListen.class) + c.add(createServiceDependency() + .setService(IDataPacketListen.class) .setCallbacks("setIDataPacketListen", "unsetIDataPacketListen").setRequired(false)); } @@ -291,31 +337,35 @@ public class Activator extends ComponentActivatorAbstractBase { c.setInterface(new String[] { IContainerListener.class.getName() }, null); - c.add(createServiceDependency().setService(IController.class, - "(name=Controller)").setCallbacks("setController", - "unsetController").setRequired(true)); - c.add(createServiceDependency().setService( - IInventoryShimInternalListener.class).setCallbacks( - "setInventoryShimInternalListener", - "unsetInventoryShimInternalListener").setRequired(true)); - c.add(createServiceDependency().setService( - IInventoryShimExternalListener.class).setCallbacks( - "setInventoryShimExternalListener", - "unsetInventoryShimExternalListener").setRequired(false)); + c.add(createServiceDependency() + .setService(IController.class, "(name=Controller)") + .setCallbacks("setController", "unsetController") + .setRequired(true)); + c.add(createServiceDependency() + .setService(IInventoryShimInternalListener.class) + .setCallbacks("setInventoryShimInternalListener", + "unsetInventoryShimInternalListener") + .setRequired(true)); + c.add(createServiceDependency() + .setService(IInventoryShimExternalListener.class) + .setCallbacks("setInventoryShimExternalListener", + "unsetInventoryShimExternalListener") + .setRequired(false)); } if (imp.equals(TopologyServiceShim.class)) { c.setInterface(new String[] { IDiscoveryService.class.getName(), IContainerListener.class.getName(), IRefreshInternalProvider.class.getName() }, null); - c.add(createServiceDependency().setService( - ITopologyServiceShimListener.class).setCallbacks( - "setTopologyServiceShimListener", - "unsetTopologyServiceShimListener").setRequired(true)); - c.add(createServiceDependency().setService( - IOFStatisticsManager.class).setCallbacks( - "setStatisticsManager", "unsetStatisticsManager") - .setRequired(false)); + c.add(createServiceDependency() + .setService(ITopologyServiceShimListener.class) + .setCallbacks("setTopologyServiceShimListener", + "unsetTopologyServiceShimListener") + .setRequired(true)); + c.add(createServiceDependency() + .setService(IOFStatisticsManager.class) + .setCallbacks("setStatisticsManager", + "unsetStatisticsManager").setRequired(false)); } } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java index 7e89cd0a42..47ce283331 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowConverter.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -71,9 +70,6 @@ import org.opendaylight.controller.sal.utils.NodeConnectorCreator; /** * Utility class for converting a SAL Flow into the OF flow and vice-versa - * - * - * */ public class FlowConverter { private Flow flow; // SAL Flow @@ -99,8 +95,9 @@ public class FlowConverter { } /** - * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions form (V6Match) - * + * Returns the match in OF 1.0 (OFMatch) form or OF 1.0 + IPv6 extensions + * form (V6Match) + * * @return */ public OFMatch getOFMatch() { @@ -173,11 +170,11 @@ public class FlowConverter { } if (match.isPresent(MatchType.NW_TOS)) { /* - * OF 1.0 switch expects the TOS as the 6 msb in the byte. - * it is actually the DSCP field followed by a zero ECN + * OF 1.0 switch expects the TOS as the 6 msb in the byte. it is + * actually the DSCP field followed by a zero ECN */ byte tos = (Byte) match.getField(MatchType.NW_TOS).getValue(); - byte dscp = (byte)((int)tos << 2); + byte dscp = (byte) ((int) tos << 2); if (!isIPv6) { ofMatch.setNetworkTypeOfService(dscp); wildcards &= ~OFMatch.OFPFW_NW_TOS; @@ -261,6 +258,7 @@ public class FlowConverter { /** * Returns the list of actions in OF 1.0 form + * * @return */ public List getOFActions() { @@ -303,7 +301,8 @@ public class FlowConverter { if (action.getType() == ActionType.CONTROLLER) { OFActionOutput ofAction = new OFActionOutput(); ofAction.setPort(OFPort.OFPP_CONTROLLER.getValue()); - // We want the whole frame hitting the match be sent to the controller + // We want the whole frame hitting the match be sent to the + // controller ofAction.setMaxLength((short) 0xffff); actionsList.add(ofAction); actionsLength += OFActionOutput.MINIMUM_LENGTH; @@ -408,7 +407,7 @@ public class FlowConverter { continue; } if (action.getType() == ActionType.SET_NEXT_HOP) { - //TODO + // TODO continue; } } @@ -417,9 +416,9 @@ public class FlowConverter { } /** - * Utility to convert a SAL flow to an OF 1.0 (OFFlowMod) or - * to an OF 1.0 + IPv6 extension (V6FlowMod) Flow modifier Message - * + * Utility to convert a SAL flow to an OF 1.0 (OFFlowMod) or to an OF 1.0 + + * IPv6 extension (V6FlowMod) Flow modifier Message + * * @param sw * @param command * @param port @@ -447,6 +446,14 @@ public class FlowConverter { if (port != null) { ((OFFlowMod) fm).setOutPort(port); } + if (command == OFFlowMod.OFPFC_ADD + || command == OFFlowMod.OFPFC_MODIFY + || command == OFFlowMod.OFPFC_MODIFY_STRICT) { + if (flow.getIdleTimeout() != 0 || flow.getHardTimeout() != 0) { + // Instruct switch to let controller know when flow expires + ((OFFlowMod) fm).setFlags((short) 1); + } + } } else { ((V6FlowMod) fm).setVendor(); ((V6FlowMod) fm).setMatch((V6Match) ofMatch); @@ -463,6 +470,14 @@ public class FlowConverter { if (port != null) { ((V6FlowMod) fm).setOutPort(port); } + if (command == OFFlowMod.OFPFC_ADD + || command == OFFlowMod.OFPFC_MODIFY + || command == OFFlowMod.OFPFC_MODIFY_STRICT) { + if (flow.getIdleTimeout() != 0 || flow.getHardTimeout() != 0) { + // Instruct switch to let controller know when flow expires + ((V6FlowMod) fm).setFlags((short) 1); + } + } } return fm; } @@ -472,8 +487,8 @@ public class FlowConverter { Match salMatch = new Match(); /* - * Installed flow may not have a Match defined - * like in case of a drop all flow + * Installed flow may not have a Match defined like in case of a + * drop all flow */ if (ofMatch != null) { if (!isIPv6) { @@ -512,38 +527,35 @@ public class FlowConverter { if (ofMatch.getNetworkSource() != 0) { salMatch.setField(MatchType.NW_SRC, NetUtils .getInetAddress(ofMatch.getNetworkSource()), - NetUtils.getInetNetworkMask(ofMatch - .getNetworkSourceMaskLen(), false)); + NetUtils.getInetNetworkMask( + ofMatch.getNetworkSourceMaskLen(), + false)); } if (ofMatch.getNetworkDestination() != 0) { - salMatch - .setField( - MatchType.NW_DST, - NetUtils.getInetAddress(ofMatch - .getNetworkDestination()), - NetUtils - .getInetNetworkMask( - ofMatch - .getNetworkDestinationMaskLen(), - false)); + salMatch.setField(MatchType.NW_DST, + NetUtils.getInetAddress(ofMatch + .getNetworkDestination()), + NetUtils.getInetNetworkMask( + ofMatch.getNetworkDestinationMaskLen(), + false)); } if (ofMatch.getNetworkTypeOfService() != 0) { - int dscp = NetUtils.getUnsignedByte( - ofMatch.getNetworkTypeOfService()); - byte tos = (byte)(dscp >> 2); + int dscp = NetUtils.getUnsignedByte(ofMatch + .getNetworkTypeOfService()); + byte tos = (byte) (dscp >> 2); salMatch.setField(MatchType.NW_TOS, tos); } if (ofMatch.getNetworkProtocol() != 0) { - salMatch.setField(MatchType.NW_PROTO, ofMatch - .getNetworkProtocol()); + salMatch.setField(MatchType.NW_PROTO, + ofMatch.getNetworkProtocol()); } if (ofMatch.getTransportSource() != 0) { - salMatch.setField(MatchType.TP_SRC, ((Short) ofMatch - .getTransportSource())); + salMatch.setField(MatchType.TP_SRC, + ((Short) ofMatch.getTransportSource())); } if (ofMatch.getTransportDestination() != 0) { - salMatch.setField(MatchType.TP_DST, ((Short) ofMatch - .getTransportDestination())); + salMatch.setField(MatchType.TP_DST, + ((Short) ofMatch.getTransportDestination())); } } else { // Compute OF1.0 + IPv6 extensions Match @@ -581,32 +593,32 @@ public class FlowConverter { .getDataLayerVirtualLanPriorityCodePoint()); } if (v6Match.getNetworkSrc() != null) { - salMatch.setField(MatchType.NW_SRC, v6Match - .getNetworkSrc(), v6Match - .getNetworkSourceMask()); + salMatch.setField(MatchType.NW_SRC, + v6Match.getNetworkSrc(), + v6Match.getNetworkSourceMask()); } if (v6Match.getNetworkDest() != null) { - salMatch.setField(MatchType.NW_DST, v6Match - .getNetworkDest(), v6Match - .getNetworkDestinationMask()); + salMatch.setField(MatchType.NW_DST, + v6Match.getNetworkDest(), + v6Match.getNetworkDestinationMask()); } if (v6Match.getNetworkTypeOfService() != 0) { - int dscp = NetUtils.getUnsignedByte( - v6Match.getNetworkTypeOfService()); - byte tos = (byte) (dscp >> 2); + int dscp = NetUtils.getUnsignedByte(v6Match + .getNetworkTypeOfService()); + byte tos = (byte) (dscp >> 2); salMatch.setField(MatchType.NW_TOS, tos); } if (v6Match.getNetworkProtocol() != 0) { - salMatch.setField(MatchType.NW_PROTO, v6Match - .getNetworkProtocol()); + salMatch.setField(MatchType.NW_PROTO, + v6Match.getNetworkProtocol()); } if (v6Match.getTransportSource() != 0) { - salMatch.setField(MatchType.TP_SRC, ((Short) v6Match - .getTransportSource())); + salMatch.setField(MatchType.TP_SRC, + ((Short) v6Match.getTransportSource())); } if (v6Match.getTransportDestination() != 0) { - salMatch.setField(MatchType.TP_DST, ((Short) v6Match - .getTransportDestination())); + salMatch.setField(MatchType.TP_DST, + ((Short) v6Match.getTransportDestination())); } } } @@ -635,10 +647,12 @@ public class FlowConverter { } else if (ofPort == OFPort.OFPP_NORMAL.getValue()) { salAction = new HwPath(); } else if (ofPort == OFPort.OFPP_TABLE.getValue()) { - salAction = new HwPath(); //TODO: we do not handle table in sal for now + salAction = new HwPath(); // TODO: we do not handle + // table in sal for now } else { - salAction = new Output(NodeConnectorCreator - .createOFNodeConnector(ofPort, node)); + salAction = new Output( + NodeConnectorCreator.createOFNodeConnector( + ofPort, node)); } } else if (ofAction instanceof OFActionVirtualLanIdentifier) { salAction = new SetVlanId( diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java new file mode 100644 index 0000000000..594164ddcf --- /dev/null +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerNotifier.java @@ -0,0 +1,86 @@ +/* + * 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.protocol_plugin.openflow.internal; + +import org.apache.felix.dm.Component; +import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier; +import org.opendaylight.controller.sal.core.Node; +import org.opendaylight.controller.sal.flowprogrammer.Flow; +import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Flow Programmer Notifier class for relaying asynchronous messages received + * from the network node to the listeners on the proper container + */ +public class FlowProgrammerNotifier implements IFlowProgrammerNotifier { + protected static final Logger logger = LoggerFactory + .getLogger(FlowProgrammerNotifier.class); + private IPluginOutFlowProgrammerService salNotifier; + + public FlowProgrammerNotifier() { + salNotifier = null; + } + + void init(Component c) { + logger.debug("INIT called!"); + } + + /** + * 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() { + logger.debug("DESTROY called!"); + } + + /** + * 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() { + logger.debug("START called!"); + } + + /** + * 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() { + logger.debug("STOP called!"); + } + + public void setPluginOutFlowProgrammerService( + IPluginOutFlowProgrammerService s) { + this.salNotifier = s; + } + + public void unsetPluginOutFlowProgrammerService( + IPluginOutFlowProgrammerService s) { + if (this.salNotifier == s) { + this.salNotifier = null; + } + } + + @Override + public void flowRemoved(Node node, Flow flow) { + if (salNotifier != null) { + salNotifier.flowRemoved(node, flow); + } else { + logger.warn("Unable to relay switch message to upper layer"); + } + } + +} diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java index b30b5c76c1..2926c22c43 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/FlowProgrammerService.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -9,32 +8,59 @@ package org.opendaylight.controller.protocol_plugin.openflow.internal; +import java.nio.ByteBuffer; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.opendaylight.controller.protocol_plugin.openflow.IFlowProgrammerNotifier; import org.opendaylight.controller.protocol_plugin.openflow.core.IController; +import org.opendaylight.controller.protocol_plugin.openflow.core.IMessageListener; import org.opendaylight.controller.protocol_plugin.openflow.core.ISwitch; +import org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension.V6Error; import org.openflow.protocol.OFError; import org.openflow.protocol.OFFlowMod; +import org.openflow.protocol.OFFlowRemoved; import org.openflow.protocol.OFMessage; import org.openflow.protocol.OFPort; +import org.openflow.protocol.OFType; +import org.openflow.protocol.action.OFAction; +import org.opendaylight.controller.sal.core.ContainerFlow; +import org.opendaylight.controller.sal.core.IContainerListener; import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.Node.NodeIDType; +import org.opendaylight.controller.sal.core.NodeConnector; +import org.opendaylight.controller.sal.core.UpdateType; import org.opendaylight.controller.sal.flowprogrammer.Flow; import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService; +import org.opendaylight.controller.sal.match.Match; +import org.opendaylight.controller.sal.match.MatchType; +import org.opendaylight.controller.sal.utils.GlobalConstants; +import org.opendaylight.controller.sal.utils.NodeCreator; import org.opendaylight.controller.sal.utils.StatusCode; import org.opendaylight.controller.sal.utils.Status; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Represents the openflow plugin component in charge of programming the flows - * on the switch. It servers the install requests coming from the SAL layer. - * - * - * + * the flow programming and relay them to functional modules above SAL. */ -public class FlowProgrammerService implements IPluginInFlowProgrammerService { +public class FlowProgrammerService implements IPluginInFlowProgrammerService, + IMessageListener, IContainerListener { + private static final Logger log = LoggerFactory + .getLogger(FlowProgrammerService.class); private IController controller; + private ConcurrentMap flowProgrammerNotifiers; + private Map> containerToNc; public FlowProgrammerService() { controller = null; + flowProgrammerNotifiers = new ConcurrentHashMap(); } public void setController(IController core) { @@ -47,37 +73,61 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { } } + public void setFlowProgrammerNotifier(Map props, + IFlowProgrammerNotifier s) { + if (props == null || props.get("containerName") == null) { + log.error("Didn't receive the service correct properties"); + return; + } + String containerName = (String) props.get("containerName"); + this.flowProgrammerNotifiers.put(containerName, s); + } + + public void unsetFlowProgrammerNotifier(Map props, + IFlowProgrammerNotifier s) { + if (props == null || props.get("containerName") == null) { + log.error("Didn't receive the service correct properties"); + return; + } + String containerName = (String) props.get("containerName"); + if (this.flowProgrammerNotifiers != null + && this.flowProgrammerNotifiers.containsKey(containerName) + && this.flowProgrammerNotifiers.get(containerName) == s) { + this.flowProgrammerNotifiers.remove(containerName); + } + } + /** * Function called by the dependency manager when all the required * dependencies are satisfied - * + * */ void init() { + this.controller.addMessageListener(OFType.FLOW_REMOVED, this); } /** - * 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. - * + * 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 - * + * 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 - * + * 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() { } @@ -86,8 +136,8 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { public Status addFlow(Node node, Flow flow) { String action = "add"; if (!node.getType().equals(NodeIDType.OPENFLOW)) { - return new Status(StatusCode.NOTACCEPTABLE, - errorString("send", action, "Invalid node type")); + return new Status(StatusCode.NOTACCEPTABLE, errorString("send", + action, "Invalid node type")); } if (controller != null) { @@ -101,41 +151,52 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { */ Object result = sw.syncSend(msg); if (result instanceof Boolean) { - return ((Boolean) result == Boolean.TRUE) ? - new Status(StatusCode.SUCCESS, null) - : new Status(StatusCode.TIMEOUT, - errorString(null, action, - "Request Timed Out")); + return ((Boolean) result == Boolean.TRUE) ? new Status( + StatusCode.SUCCESS, null) : new Status( + StatusCode.TIMEOUT, errorString(null, action, + "Request Timed Out")); } else if (result instanceof OFError) { - return new Status(StatusCode.INTERNALERROR, - errorString("program", action, Utils - .getOFErrorString((OFError) result))); + OFError res = (OFError) result; + if (res.getErrorType() == V6Error.NICIRA_VENDOR_ERRORTYPE) { + V6Error er = new V6Error(res); + byte[] b = res.getError(); + ByteBuffer bb = ByteBuffer.allocate(b.length); + bb.put(b); + bb.rewind(); + er.readFrom(bb); + return new Status(StatusCode.INTERNALERROR, + errorString("program", action, + "Vendor Extension Internal Error")); + } + return new Status(StatusCode.INTERNALERROR, errorString( + "program", action, Utils.getOFErrorString(res))); } else { - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal Error")); + return new Status(StatusCode.INTERNALERROR, errorString( + "send", action, "Internal Error")); } } else { return new Status(StatusCode.GONE, errorString("send", action, - "Switch is not available")); + "Switch is not available")); } } - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal plugin error")); + return new Status(StatusCode.INTERNALERROR, errorString("send", action, + "Internal plugin error")); } @Override public Status modifyFlow(Node node, Flow oldFlow, Flow newFlow) { String action = "modify"; if (!node.getType().equals(NodeIDType.OPENFLOW)) { - return new Status(StatusCode.NOTACCEPTABLE, - errorString("send", action, "Invalid node type")); + return new Status(StatusCode.NOTACCEPTABLE, errorString("send", + action, "Invalid node type")); } if (controller != null) { ISwitch sw = controller.getSwitch((Long) node.getID()); if (sw != null) { OFMessage msg1 = null, msg2 = null; - // If priority and match portion are the same, send a modification message + // If priority and match portion are the same, send a + // modification message if (oldFlow.getPriority() != newFlow.getPriority() || !oldFlow.getMatch().equals(newFlow.getMatch())) { msg1 = new FlowConverter(oldFlow).getOFFlowMod( @@ -153,34 +214,32 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { Object result = sw.syncSend(msg1); if (result instanceof Boolean) { if ((Boolean) result == Boolean.FALSE) { - return new Status(StatusCode.TIMEOUT, - errorString(null, action, - "Request Timed Out")); + return new Status(StatusCode.TIMEOUT, errorString(null, + action, "Request Timed Out")); } else if (msg2 == null) { return new Status(StatusCode.SUCCESS, null); } } else if (result instanceof OFError) { - return new Status(StatusCode.INTERNALERROR, - errorString("program", action, Utils - .getOFErrorString((OFError) result))); + return new Status(StatusCode.INTERNALERROR, errorString( + "program", action, + Utils.getOFErrorString((OFError) result))); } else { - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal Error")); + return new Status(StatusCode.INTERNALERROR, errorString( + "send", action, "Internal Error")); } if (msg2 != null) { action = "add"; result = sw.syncSend(msg2); if (result instanceof Boolean) { - return ((Boolean) result == Boolean.TRUE) ? - new Status(StatusCode.SUCCESS, null) - : new Status(StatusCode.TIMEOUT, - errorString(null, action, - "Request Timed Out")); + return ((Boolean) result == Boolean.TRUE) ? new Status( + StatusCode.SUCCESS, null) : new Status( + StatusCode.TIMEOUT, errorString(null, action, + "Request Timed Out")); } else if (result instanceof OFError) { return new Status(StatusCode.INTERNALERROR, errorString("program", action, Utils - .getOFErrorString((OFError) result))); + .getOFErrorString((OFError) result))); } else { return new Status(StatusCode.INTERNALERROR, errorString("send", action, "Internal Error")); @@ -191,16 +250,16 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { "Switch is not available")); } } - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal plugin error")); + return new Status(StatusCode.INTERNALERROR, errorString("send", action, + "Internal plugin error")); } @Override public Status removeFlow(Node node, Flow flow) { String action = "remove"; if (!node.getType().equals(NodeIDType.OPENFLOW)) { - return new Status(StatusCode.NOTACCEPTABLE, - errorString("send", action, "Invalid node type")); + return new Status(StatusCode.NOTACCEPTABLE, errorString("send", + action, "Invalid node type")); } if (controller != null) { ISwitch sw = controller.getSwitch((Long) node.getID()); @@ -209,26 +268,25 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { OFFlowMod.OFPFC_DELETE_STRICT, OFPort.OFPP_NONE); Object result = sw.syncSend(msg); if (result instanceof Boolean) { - return ((Boolean) result == Boolean.TRUE) ? - new Status(StatusCode.SUCCESS, null) - : new Status(StatusCode.TIMEOUT, - errorString(null, action, - "Request Timed Out")); + return ((Boolean) result == Boolean.TRUE) ? new Status( + StatusCode.SUCCESS, null) : new Status( + StatusCode.TIMEOUT, errorString(null, action, + "Request Timed Out")); } else if (result instanceof OFError) { - return new Status(StatusCode.INTERNALERROR, - errorString("program", action, Utils - .getOFErrorString((OFError) result))); + return new Status(StatusCode.INTERNALERROR, errorString( + "program", action, + Utils.getOFErrorString((OFError) result))); } else { - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal Error")); + return new Status(StatusCode.INTERNALERROR, errorString( + "send", action, "Internal Error")); } } else { - return new Status(StatusCode.GONE, errorString("send", action, + return new Status(StatusCode.GONE, errorString("send", action, "Switch is not available")); } } - return new Status(StatusCode.INTERNALERROR, - errorString("send", action, "Internal plugin error")); + return new Status(StatusCode.INTERNALERROR, errorString("send", action, + "Internal plugin error")); } @Override @@ -242,4 +300,82 @@ public class FlowProgrammerService implements IPluginInFlowProgrammerService { + " flow message: " : action + " the flow: ") + cause; } + @Override + public void receive(ISwitch sw, OFMessage msg) { + if (msg instanceof OFFlowRemoved) { + handleFlowRemovedMessage(sw, (OFFlowRemoved) msg); + } + } + + private void handleFlowRemovedMessage(ISwitch sw, OFFlowRemoved msg) { + Node node = NodeCreator.createOFNode(sw.getId()); + Flow flow = new FlowConverter(msg.getMatch(), + new ArrayList(0)).getFlow(node); + flow.setPriority(msg.getPriority()); + flow.setIdleTimeout(msg.getIdleTimeout()); + flow.setId(msg.getCookie()); + + Match match = flow.getMatch(); + NodeConnector inPort = match.isPresent(MatchType.IN_PORT) ? (NodeConnector) match + .getField(MatchType.IN_PORT).getValue() : null; + + for (Map.Entry containerNotifier : flowProgrammerNotifiers + .entrySet()) { + String container = containerNotifier.getKey(); + IFlowProgrammerNotifier notifier = containerNotifier.getValue(); + /* + * Switch only provide us with the match information. For now let's + * try to identify the container membership only from the input port + * match field. In any case, upper layer consumers can derive + * whether the notification was not for them. More sophisticated + * filtering can be added later on. + */ + if (inPort == null + || container.equals(GlobalConstants.DEFAULT.toString()) + || this.containerToNc.get(container).contains(inPort)) { + notifier.flowRemoved(node, flow); + } + } + } + + @Override + public void tagUpdated(String containerName, Node n, short oldTag, + short newTag, UpdateType t) { + + } + + @Override + public void containerFlowUpdated(String containerName, + ContainerFlow previousFlow, ContainerFlow currentFlow, UpdateType t) { + } + + @Override + public void nodeConnectorUpdated(String containerName, NodeConnector p, + UpdateType type) { + Set target = null; + + switch (type) { + case ADDED: + if (!containerToNc.containsKey(containerName)) { + containerToNc.put(containerName, new HashSet()); + } + containerToNc.get(containerName).add(p); + break; + case CHANGED: + break; + case REMOVED: + target = containerToNc.get(containerName); + if (target != null) { + target.remove(p); + } + break; + default: + } + + } + + @Override + public void containerModeUpdated(UpdateType t) { + + } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java index bc61f3b071..73dcea574a 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/OFStatisticsManager.java @@ -137,7 +137,7 @@ public class OFStatisticsManager implements IOFStatisticsManager, .getLast()); long timePeriod = (long) (factoredSamples * portStatsPeriod) / (long) tickPeriod; - average = (8 * increment) / timePeriod; + average = (8L * increment) / timePeriod; return average; } } diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java index ab7ab2eca8..a811f6529e 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/internal/TopologyServiceShim.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -46,9 +45,9 @@ import org.opendaylight.controller.sal.discovery.IDiscoveryService; import org.opendaylight.controller.sal.utils.GlobalConstants; /** - * The class describes a shim layer that relays the topology events from OpenFlow - * core to various listeners. The notifications are filtered based on container - * configurations. + * The class describes a shim layer that relays the topology events from + * OpenFlow core to various listeners. The notifications are filtered based on + * container configurations. */ public class TopologyServiceShim implements IDiscoveryService, IContainerListener, CommandProvider, IRefreshInternalProvider { @@ -56,7 +55,7 @@ public class TopologyServiceShim implements IDiscoveryService, .getLogger(TopologyServiceShim.class); private ConcurrentMap topologyServiceShimListeners = new ConcurrentHashMap(); private ConcurrentMap> containerMap = new ConcurrentHashMap>(); - private ConcurrentMap>>> edgeMap = new ConcurrentHashMap>>>(); + private ConcurrentMap>>> edgeMap = new ConcurrentHashMap>>>(); private BlockingQueue notifyQ; private Thread notifyThread; @@ -69,7 +68,8 @@ public class TopologyServiceShim implements IDiscoveryService, private Thread bwUtilNotifyThread; private BlockingQueue bwUtilNotifyQ; private List connectorsOverUtilized; - private float bwThresholdFactor = (float) 0.8; // Threshold = 80% of link bandwidth + private float bwThresholdFactor = (float) 0.8; // Threshold = 80% of link + // bandwidth class NotifyEntry { String container; @@ -98,8 +98,9 @@ public class TopologyServiceShim implements IDiscoveryService, ITopologyServiceShimListener topologServiceShimListener = topologyServiceShimListeners .get(entry.container); - topologServiceShimListener.edgeUpdate(entry.edgeProps - .getLeft(), entry.type, entry.edgeProps.getRight()); + topologServiceShimListener.edgeUpdate( + entry.edgeProps.getLeft(), entry.type, + entry.edgeProps.getRight()); entry = null; } catch (InterruptedException e1) { @@ -136,7 +137,7 @@ public class TopologyServiceShim implements IDiscoveryService, try { UtilizationUpdate update = notifyQ.take(); NodeConnector connector = update.connector; - Set containerList = edgeMap.keySet();//.get(connector); + Set containerList = edgeMap.keySet(); for (String container : containerList) { Map>> edgePropsMap = edgeMap .get(container); @@ -154,10 +155,9 @@ public class TopologyServiceShim implements IDiscoveryService, } } } catch (InterruptedException e1) { - logger - .warn( - "Edge Bandwidth Utilization Notify Thread interrupted", - e1.getMessage()); + logger.warn( + "Edge Bandwidth Utilization Notify Thread interrupted", + e1.getMessage()); if (shuttingDown) { return; } @@ -171,7 +171,7 @@ public class TopologyServiceShim implements IDiscoveryService, /** * Function called by the dependency manager when all the required * dependencies are satisfied - * + * */ void init() { logger.trace("Init called"); @@ -212,10 +212,10 @@ public class TopologyServiceShim implements IDiscoveryService, } /** - * Continuously polls the transmit bit rate for all the node connectors - * from statistics manager and trigger the warning notification upward - * when the transmit rate is above a threshold which is a percentage of - * the edge bandwidth + * Continuously polls the transmit bit rate for all the node connectors from + * statistics manager and trigger the warning notification upward when the + * transmit rate is above a threshold which is a percentage of the edge + * bandwidth */ protected void pollTxBitRates() { Map>> globalContainerEdges = edgeMap @@ -226,7 +226,8 @@ public class TopologyServiceShim implements IDiscoveryService, for (NodeConnector connector : globalContainerEdges.keySet()) { // Skip if node connector belongs to production switch - if (connector.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) { + if (connector.getType().equals( + NodeConnector.NodeConnectorIDType.PRODUCTION)) { continue; } @@ -277,10 +278,10 @@ public class TopologyServiceShim implements IDiscoveryService, } /** - * 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. - * + * 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() { logger.trace("DESTROY called!"); @@ -289,10 +290,9 @@ public class TopologyServiceShim implements IDiscoveryService, } /** - * Function called by dependency manager after "init ()" is called - * and after the services provided by the class are registered in - * the service registry - * + * 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() { logger.trace("START called!"); @@ -303,10 +303,10 @@ public class TopologyServiceShim implements IDiscoveryService, } /** - * Function called by the dependency manager before the services - * exported by the component are unregistered, this will be - * followed by a "destroy ()" calls - * + * 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() { logger.trace("STOP called!"); @@ -327,7 +327,7 @@ public class TopologyServiceShim implements IDiscoveryService, } if ((this.topologyServiceShimListeners != null) && !this.topologyServiceShimListeners - .containsKey(containerName)) { + .containsKey(containerName)) { this.topologyServiceShimListeners.put(containerName, s); logger.trace("Added topologyServiceShimListener for container:" + containerName); @@ -346,11 +346,9 @@ public class TopologyServiceShim implements IDiscoveryService, return; } if ((this.topologyServiceShimListeners != null) - && this.topologyServiceShimListeners - .containsKey(containerName) - && this.topologyServiceShimListeners - .get(containerName).equals(s) - ) { + && this.topologyServiceShimListeners.containsKey(containerName) + && this.topologyServiceShimListeners.get(containerName).equals( + s)) { this.topologyServiceShimListeners.remove(containerName); logger.trace("Removed topologyServiceShimListener for container: " + containerName); @@ -393,7 +391,7 @@ public class TopologyServiceShim implements IDiscoveryService, private void notifyEdge(String container, Edge edge, UpdateType type, Set props) { - Map>> edgePropsMap = edgeMap + ConcurrentMap>> edgePropsMap = edgeMap .get(container); NodeConnector src = edge.getTailNodeConnector(); Pair> edgeProps = new ImmutablePair>( @@ -403,7 +401,7 @@ public class TopologyServiceShim implements IDiscoveryService, case ADDED: case CHANGED: if (edgePropsMap == null) { - edgePropsMap = new HashMap>>(); + edgePropsMap = new ConcurrentHashMap>>(); } else { if (edgePropsMap.containsKey(src) && edgePropsMap.get(src).equals(edgeProps)) { @@ -460,8 +458,7 @@ public class TopologyServiceShim implements IDiscoveryService, NodeConnector src = edge.getTailNodeConnector(), dst = edge .getHeadNodeConnector(); - if (!src.getType().equals( - NodeConnector.NodeConnectorIDType.PRODUCTION)) { + if (!src.getType().equals(NodeConnector.NodeConnectorIDType.PRODUCTION)) { /* Find the common containers for both ends */ List srcContainers = this.containerMap.get(src), dstContainers = this.containerMap .get(dst), cmnContainers = null; @@ -545,8 +542,8 @@ public class TopologyServiceShim implements IDiscoveryService, public String getHelp() { StringBuffer help = new StringBuffer(); help.append("---Topology Service Shim---\n"); - help - .append("\t pem [container] - Print edgeMap entries for a given container\n"); + help.append("\t pem [container] - Print edgeMap entries"); + help.append(" for a given container\n"); return help.toString(); } @@ -594,16 +591,15 @@ public class TopologyServiceShim implements IDiscoveryService, } /** - * This method will trigger topology updates to be sent - * toward SAL. SAL then pushes the updates to ALL the applications - * that have registered as listeners for this service. SAL has no - * way of knowing which application requested for the refresh. - * - * As an example of this case, is stopping and starting the - * Topology Manager. When the topology Manager is stopped, - * and restarted, it will no longer have the latest topology. - * Hence, a request is sent here. - * + * This method will trigger topology updates to be sent toward SAL. SAL then + * pushes the updates to ALL the applications that have registered as + * listeners for this service. SAL has no way of knowing which application + * requested for the refresh. + * + * As an example of this case, is stopping and starting the Topology + * Manager. When the topology Manager is stopped, and restarted, it will no + * longer have the latest topology. Hence, a request is sent here. + * * @param containerName * @return void */ @@ -615,9 +611,10 @@ public class TopologyServiceShim implements IDiscoveryService, } /** - * Reading the current topology database, the method will replay - * all the edge updates for the ITopologyServiceShimListener instance - * in the given container, which will in turn publish them toward SAL. + * Reading the current topology database, the method will replay all the + * edge updates for the ITopologyServiceShimListener instance in the given + * container, which will in turn publish them toward SAL. + * * @param containerName */ private void TopologyBulkUpdate(String containerName) { diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Error.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Error.java new file mode 100644 index 0000000000..4f0dbd5ca5 --- /dev/null +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6Error.java @@ -0,0 +1,80 @@ +package org.opendaylight.controller.protocol_plugin.openflow.vendorextension.v6extension; + +import java.nio.ByteBuffer; + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; +import org.openflow.protocol.OFError; + +public class V6Error extends OFError { + private static final long serialVersionUID = 1L; + public static int MINIMUM_LENGTH = 20;//OfHdr(8) + NXET_VENDOR(2) + NXEC_VENDOR_ERROR(2) + struct nx_vendor_error(8) + public static final short NICIRA_VENDOR_ERRORTYPE = (short)0xb0c2; + protected int V6VendorId; + protected short V6VendorErrorType; + protected short V6VendorErrorCode; + protected byte[] V6ErrorData; + + public V6Error(OFError e) { + this.length = (short)e.getLengthU(); + this.errorType = e.getErrorType(); + this.errorCode = e.getErrorCode(); + this.xid = e.getXid(); + } + + @Override + public void readFrom(ByteBuffer data) { + this.V6VendorId = data.getInt(); + this.V6VendorErrorType = data.getShort(); + this.V6VendorErrorCode = data.getShort(); + int dataLength = this.getLengthU() - MINIMUM_LENGTH; + if (dataLength > 0) { + this.V6ErrorData = new byte[dataLength]; + data.get(this.V6ErrorData); + } + } + + /** + * @return the V6VendorId + */ + public int getVendorId() { + return V6VendorId; + } + + /** + * @return the V6VendorErrorType + */ + public short getVendorErrorType() { + return V6VendorErrorType; + } + + /** + * @return the VendorErrorType + */ + public short getVendorErrorCode() { + return V6VendorErrorCode; + } + + /** + * @return the Error Bytes + */ + public byte[] getError() { + return V6ErrorData; + } + + @Override + public int hashCode() { + return HashCodeBuilder.reflectionHashCode(this); + } + + @Override + public String toString() { + return "V6Error[" + ReflectionToStringBuilder.toString(this) + "]"; + } + + @Override + public boolean equals(Object obj) { + return EqualsBuilder.reflectionEquals(this, obj); + } +} diff --git a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java index 47bb2213aa..888d2e63ed 100644 --- a/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java +++ b/opendaylight/protocol_plugins/openflow/src/main/java/org/opendaylight/controller/protocol_plugin/openflow/vendorextension/v6extension/V6FlowMod.java @@ -13,6 +13,7 @@ import java.nio.ByteBuffer; import java.util.LinkedList; import java.util.List; +import org.apache.commons.lang3.builder.ReflectionToStringBuilder; import org.openflow.protocol.OFPacketOut; import org.openflow.protocol.OFPort; import org.openflow.protocol.OFVendor; @@ -20,8 +21,6 @@ import org.openflow.protocol.action.OFAction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.apache.commons.lang3.builder.ReflectionToStringBuilder; - /** * This class is used to create IPv6 Vendor Extension messages. Specfically, It * defines the methods used in creation of Vendor specific IPv6 Flow Mod message. @@ -148,6 +147,22 @@ public class V6FlowMod extends OFVendor implements Cloneable { super.setVendor(V6StatsRequest.NICIRA_VENDOR_ID); } + /** + * Get flags + * @return + */ + public short getFlags() { + return flags; + } + + /** + * Set flags + * @param flags + */ + public void setFlags(short flags) { + this.flags = flags; + } + /** * This method forms the Vendor extension IPv6 Flow Mod message.It uses the * fields in V6FlowMod class, and writes the data according to vendor @@ -167,7 +182,7 @@ public class V6FlowMod extends OFVendor implements Cloneable { data.putShort(this.priority); data.putInt(OFPacketOut.BUFFER_ID_NONE); data.putShort(outPort); /* output_port */ - data.putShort((short) 0); /* flags */ + data.putShort(flags); /* flags */ match_len = this.match.getIPv6MatchLen(); data.putShort(match_len); byte[] pad = new byte[6]; diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java index cabe571258..8f6cfa4251 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/authorization/IResourceAuthorization.java @@ -18,7 +18,7 @@ import org.opendaylight.controller.sal.utils.Status; * Interface for applications which maintain an authorization * database for their resources. Respective application web bundle * and User Manager make use of this interface to retrieve - * authorization information at user or and role level + * authorization information at user or and role level. */ public interface IResourceAuthorization { @@ -90,15 +90,27 @@ public interface IResourceAuthorization { public List getResourceGroups(); /** - * Assign a resource group to a user group (role) + * Assign a resource group to a role * - * @param groupName the object expressing the resource group name and the access privilege - * @param role the user group (role) name + * @param groupName the name of the resource group + * @param privilege the access privilege role will have on the resource group + * @param role the role name * @return the status of the request */ + @Deprecated public Status assignResourceGroupToRole(String groupName, Privilege privilege, String role); + /** + * Assign a resource group to a role. The access privilege on the resources + * is inferred by the AppRoleLevel associated to role. + * + * @param groupName the name of the resource group + * @param role the role name + * @return the status of the request + */ + public Status assignResourceGroupToRole(String groupName, String role); + /** * Unassign the passed resource group from the specified role * diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerListener.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerListener.java new file mode 100644 index 0000000000..c66a3de474 --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerListener.java @@ -0,0 +1,19 @@ +/* + * 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.flowprogrammer; + +/** + * This interface defines the methods the SAL service which relay to the + * functional modules the asynchronous messages related to flow programming + * coming from the network nodes. + */ +public interface IFlowProgrammerListener extends + IPluginOutFlowProgrammerService { + +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java index 956942c09c..69972d6776 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IFlowProgrammerService.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -13,15 +12,13 @@ import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.utils.Status; /** - * Interface for installing/removing flows on a network node - * - * - * + * Interface that defines the methods available to the functional modules above + * SAL for installing/modifying/removing flows on a network node */ public interface IFlowProgrammerService { /** * Add a flow to the network node - * + * * @param node * @param flow */ @@ -29,7 +26,7 @@ public interface IFlowProgrammerService { /** * Modify existing flow on the switch - * + * * @param node * @param flow */ @@ -37,6 +34,7 @@ public interface IFlowProgrammerService { /** * Remove the flow from the network node + * * @param node * @param flow */ @@ -44,6 +42,7 @@ public interface IFlowProgrammerService { /** * Remove all flows present on the network node + * * @param node */ Status removeAllFlows(Node node); diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java index 1fb99e0ab9..79924fc3dd 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginInFlowProgrammerService.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -13,40 +12,39 @@ import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.utils.Status; /** - * @file IPluginOutFlowProgrammer.java - * - * @brief Flow programmer interface to be implemented by protocol plugins - * - * - * + * @file IPluginOutFlowProgrammer.java + * + * @brief Flow programmer interface to be implemented by protocol plugins */ public interface IPluginInFlowProgrammerService { /** * Add a flow to the network node - * + * * @param node * @param flow */ - Status addFlow(Node node, Flow flow); + Status addFlow(Node node, Flow flow); /** * Modify existing flow on the switch - * + * * @param node * @param flow */ - Status modifyFlow(Node node, Flow oldFlow, Flow newFlow); + Status modifyFlow(Node node, Flow oldFlow, Flow newFlow); /** * Remove the flow from the network node + * * @param node * @param flow */ - Status removeFlow(Node node, Flow flow); + Status removeFlow(Node node, Flow flow); /** * Remove all flows present on the network node + * * @param node */ - Status removeAllFlows(Node node); + Status removeAllFlows(Node node); } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginOutFlowProgrammerService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginOutFlowProgrammerService.java new file mode 100644 index 0000000000..2836f77afa --- /dev/null +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/flowprogrammer/IPluginOutFlowProgrammerService.java @@ -0,0 +1,31 @@ +/* + * 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.flowprogrammer; + +import org.opendaylight.controller.sal.core.Node; + +/** + * This interface defines the methods the protocol plugin must implement to + * inform the SAL layer about the asynchronous messages related to flow + * programming coming from the network nodes. + */ +public interface IPluginOutFlowProgrammerService { + /** + * Inform SAL that the flow on the specified node has been removed Consumer + * has to expect this notification only for flows which were installed with + * an idle or hard timeout specified. + * + * @param node + * the network node on which the flow got removed + * @param flow + * the flow that got removed. Note: It may contain only the Match + * and flow parameters fields. Actions may not be present. + */ + public void flowRemoved(Node node, Flow flow); +} diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java index 12e772890e..175a11718b 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchField.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -16,48 +15,51 @@ import javax.xml.bind.annotation.XmlAccessorType; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; -import org.apache.commons.lang3.builder.EqualsBuilder; -import org.apache.commons.lang3.builder.HashCodeBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Represents the generic matching field - * + * */ @XmlRootElement @XmlAccessorType(XmlAccessType.NONE) - public class MatchField implements Cloneable, Serializable { - private static final long serialVersionUID = 1L; - private static final Logger logger = LoggerFactory + private static final long serialVersionUID = 1L; + private static final Logger logger = LoggerFactory .getLogger(MatchField.class); - private MatchType type; // the field we want to match + private MatchType type; // the field we want to match private Object value; // the value of the field we want to match - private Object mask; // the value of the mask we want to match on the specified field + private Object mask; // the value of the mask we want to match on the + // specified field private transient boolean isValid; // To satisfy JAXB + @SuppressWarnings("unused") private MatchField() { } + /** * Mask based match constructor - * + * * @param type * @param value - * @param mask has to be of the same class type of value. A null mask means full match + * @param mask + * has to be of the same class type of value. A null mask means + * full match */ public MatchField(MatchType type, Object value, Object mask) { this.type = type; this.value = value; this.mask = mask; - this.isValid = checkValueType() && checkValues(); // Keep this logic, value checked only if type check is fine + // Keep this logic, value checked only if type check is fine + this.isValid = checkValueType() && checkValues(); } /** * Full match constructor - * + * * @param type * @param value */ @@ -65,54 +67,56 @@ public class MatchField implements Cloneable, Serializable { this.type = type; this.value = value; this.mask = null; - this.isValid = checkValueType() && checkValues(); // Keep this logic, value checked only if type check is fine + // Keep this logic, value checked only if type check is fine + this.isValid = checkValueType() && checkValues(); } /** * Returns the value set for this match field - * + * * @return */ public Object getValue() { return value; } - - @XmlElement(name="value") + + @XmlElement(name = "value") private String getValueString() { - return type.stringify(value); + return type.stringify(value); } /** * Returns the type field this match field object is for - * + * * @return */ public MatchType getType() { return type; } - @XmlElement(name="type") + @XmlElement(name = "type") private String getTypeString() { - return type.toString(); + return type.toString(); } /** - * Returns the mask value set for this field match - * A null mask means this is a full match + * Returns the mask value set for this field match A null mask means this is + * a full match + * * @return */ public Object getMask() { return mask; } - - @XmlElement(name="mask") + + @XmlElement(name = "mask") private String getMaskString() { - return type.stringify(mask); + return type.stringify(mask); } /** * Returns the bitmask set for this field match - * + * * @return */ public long getBitMask() { @@ -121,7 +125,7 @@ public class MatchField implements Cloneable, Serializable { /** * Returns whether the field match configuration is valid or not - * + * * @return */ public boolean isValid() { @@ -190,17 +194,36 @@ public class MatchField implements Cloneable, Serializable { } @Override - public int hashCode() { - return HashCodeBuilder.reflectionHashCode(this); + public String toString() { + return type + "(" + getValueString() + "," + getMaskString() + ")"; } @Override - public boolean equals(Object obj) { - return EqualsBuilder.reflectionEquals(this, obj); + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((mask == null) ? 0 : mask.hashCode()); + result = prime * result + ((type == null) ? 0 : type.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; } @Override - public String toString() { - return type + "(" + getValueString() + "," + getMaskString() + ")"; + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + MatchField other = (MatchField) obj; + if (type != other.type) { + return false; + } + return (type.equalValues(this.value, other.value) && type.equalMasks( + this.mask, other.mask)); } } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java index 93e5a5874c..5ad4bd5b66 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/match/MatchType.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -10,31 +9,33 @@ package org.opendaylight.controller.sal.match; import java.net.InetAddress; +import java.util.Arrays; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.utils.HexEncode; import org.opendaylight.controller.sal.utils.NetUtils; /** - * Represents the binding between the id, the value and mask type and the range values - * of the elements type that can be matched on the network frame/packet/message - * - * - * + * Represents the binding between the id, the value and mask type and the range + * values of the elements type that can be matched on the network + * frame/packet/message + * + * + * */ public enum MatchType { - IN_PORT("inPort", 1 << 0, NodeConnector.class, 1, 0), - DL_SRC("dlSrc", 1 << 1, Byte[].class, 0, 0xffffffffffffL), - DL_DST("dlDst", 1 << 2, Byte[].class, 0, 0xffffffffffffL), + IN_PORT("inPort", 1 << 0, NodeConnector.class, 1, 0), + DL_SRC("dlSrc", 1 << 1, Byte[].class, 0, 0xffffffffffffL), + DL_DST("dlDst", 1 << 2, Byte[].class, 0, 0xffffffffffffL), DL_VLAN("dlVlan", 1 << 3, Short.class, 1, 0xfff), // 2 bytes DL_VLAN_PR("dlVlanPriority", 1 << 4, Byte.class, 0, 0x7), // 3 bits - DL_OUTER_VLAN("dlOuterVlan", 1 << 5, Short.class, 1, 0xfff), - DL_OUTER_VLAN_PR("dlOuterVlanPriority", 1 << 6, Short.class, 0, 0x7), + DL_OUTER_VLAN("dlOuterVlan", 1 << 5, Short.class, 1, 0xfff), + DL_OUTER_VLAN_PR("dlOuterVlanPriority", 1 << 6, Short.class, 0, 0x7), DL_TYPE("dlType", 1 << 7, Short.class, 0, 0xffff), // 2 bytes NW_TOS("nwTOS", 1 << 8, Byte.class, 0, 0x3f), // 6 bits (DSCP field) NW_PROTO("nwProto", 1 << 9, Byte.class, 0, 0xff), // 1 byte - NW_SRC("nwSrc", 1 << 10, InetAddress.class, 0, 0), - NW_DST("nwDst", 1 << 11, InetAddress.class, 0, 0), + NW_SRC("nwSrc", 1 << 10, InetAddress.class, 0, 0), + NW_DST("nwDst", 1 << 11, InetAddress.class, 0, 0), TP_SRC("tpSrc", 1 << 12, Short.class, 1, 0xffff), // 2 bytes TP_DST("tpDst", 1 << 13, Short.class, 1, 0xffff); // 2 bytes @@ -71,7 +72,8 @@ public enum MatchType { } /** - * Perform the assignment type validation + * Perform the assignment type validation + * * @param value * @param mask * @return @@ -85,7 +87,8 @@ public enum MatchType { Class e = this.dataType(); Class g = value.getClass(); - // This is all what we need, if value type is same of match required type + // This is all what we need, if value type is same of match required + // type if (g.equals(e)) { return true; } @@ -116,6 +119,7 @@ public enum MatchType { /** * Perform the value and mask range validation + * * @param value * @param mask * @return @@ -158,12 +162,13 @@ public enum MatchType { /** * Return the mask value in 64 bits bitmask form + * * @param mask * @return */ public long getBitMask(Object mask) { if (this.dataType == InetAddress.class) { - //TODO handle Inet v4 and v6 v6 will have a second upper mask + // TODO handle Inet v4 and v6 v6 will have a second upper mask return 0; } if (this.dataType() == Byte[].class) { @@ -173,7 +178,6 @@ public enum MatchType { byte mac[] = (byte[]) mask; long bitmask = 0; for (short i = 0; i < 6; i++) { - // bitmask |= (((long)mac[i] & 0xffL) << (long)((5-i)*8)); bitmask |= (((long) mac[i] & 0xffL) << ((5 - i) * 8)); } return bitmask; @@ -193,32 +197,76 @@ public enum MatchType { return 0L; } - public String stringify(Object value) { - if (value == null) { - return null; - } - - switch (this) { - case DL_DST: - case DL_SRC: - return HexEncode.bytesToHexStringFormat((byte[])value); - case DL_TYPE: - case DL_VLAN: - return ((Integer) NetUtils.getUnsignedShort((Short)value)) - .toString(); - case NW_SRC: - case NW_DST: - return ((InetAddress)value).getHostAddress(); - case NW_TOS: - return ((Integer) NetUtils.getUnsignedByte((Byte)value)) - .toString(); - case TP_SRC: - case TP_DST: - return ((Integer) NetUtils.getUnsignedShort((Short)value)) - .toString(); - default: - break; - } - return value.toString(); - } + public String stringify(Object value) { + if (value == null) { + return null; + } + + switch (this) { + case DL_DST: + case DL_SRC: + return HexEncode.bytesToHexStringFormat((byte[]) value); + case DL_TYPE: + case DL_VLAN: + return ((Integer) NetUtils.getUnsignedShort((Short) value)) + .toString(); + case NW_SRC: + case NW_DST: + return ((InetAddress) value).getHostAddress(); + case NW_TOS: + return ((Integer) NetUtils.getUnsignedByte((Byte) value)) + .toString(); + case TP_SRC: + case TP_DST: + return ((Integer) NetUtils.getUnsignedShort((Short) value)) + .toString(); + default: + break; + } + return value.toString(); + } + + public boolean equalValues(Object a, Object b) { + if (a == b) { + return true; + } + if (a == null || b == null) { + return false; + } + switch (this) { + case DL_DST: + case DL_SRC: + return Arrays.equals((byte[]) a, (byte[]) b); + default: + return a.equals(b); + } + } + + public boolean equalMasks(Object a, Object b) { + if (a == b) { + return true; + } + switch (this) { + case NW_SRC: + case NW_DST: + /* + * For network address mask, network node may return full mask for + * flows the controller generated with a null mask object + */ + byte maskBytes[] = null; + if (a == null) { + maskBytes = ((InetAddress) b).getAddress(); + } else if (b == null) { + maskBytes = ((InetAddress) a).getAddress(); + } + if (maskBytes != null) { + return (NetUtils.getSubnetMaskLength(maskBytes) == 0); + } + default: + if (a == null) { + return false; + } + return a.equals(b); + } + } } diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java index 7ea9360300..b183240d43 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/topology/IPluginOutTopologyService.java @@ -42,6 +42,7 @@ public interface IPluginOutTopologyService { /** * Called when an Edge utilization is above the safety threshold * configured on the controller + * * @param edge */ public void edgeOverUtilized(Edge edge); diff --git a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java index 9893a06e02..503e08e714 100644 --- a/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java +++ b/opendaylight/sal/api/src/main/java/org/opendaylight/controller/sal/utils/Status.java @@ -10,74 +10,98 @@ package org.opendaylight.controller.sal.utils; /** * Represents the return object of the osgi service interfaces function calls. - * It contains a code {@code StatusCode} representing the result of the call - * and a string which describes a failure reason (if any) in human readable form. + * It contains a code {@code StatusCode} representing the result of the call and + * a string which describes a failure reason (if any) in human readable form. */ public class Status { - StatusCode code; - String description; - - /** - * Generates an instance of the Status class. - * - * @param errorCode The status code. If passed as null, code will be - * stored as {@code StatusCode.UNDEFINED} - * @param description The human readable description of the status. If passed - * as null, description will be inferred by the code - */ - public Status(StatusCode errorCode, String description) { - this.code = (errorCode != null)? errorCode : StatusCode.UNDEFINED; - this.description = (description != null)? description : this.code.toString(); - } - - /** - * Returns the status code - * @return the {@code StatusCode} representing the status code - */ - public StatusCode getCode() { - return code; - } - - /** - * Returns a human readable description of the failure if any - * @return a string representing the reason of failure - */ - public String getDescription() { - return description; - } - - /** - * Tells whether the status is successful - * @return true if the Status code is {@code StatusCode.SUCCESS} - */ - public boolean isSuccess() { - return code == StatusCode.SUCCESS; - } - - @Override - public String toString() { - return code + ": " + description; - } + StatusCode code; + String description; - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((code == null) ? 0 : code.hashCode()); - return result; - } + /** + * Generates an instance of the Status class. This is used as return code + * for internal API2 function calls. This constructor allows to specify, + * beside the Status Code, a custom human readable description to add more + * information about the status. + * + * @param errorCode + * The status code. If passed as null, code will be stored as + * {@code StatusCode.UNDEFINED} + * @param description + * The human readable description of the status. If passed as + * null, description will be inferred by the code + */ + public Status(StatusCode errorCode, String description) { + this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED; + this.description = (description != null) ? description : this.code + .toString(); + } - @Override - public boolean equals(Object obj) { - if (this == obj) - return true; - if (obj == null) - return false; - if (getClass() != obj.getClass()) - return false; - Status other = (Status) obj; - if (code != other.code) - return false; - return true; - } + /** + * Generates an instance of the Status class based on the passed StatusCode + * only. The description field of the Status object will be inferred by the + * status code. + * + * @param errorCode + * The status code. If passed as null, code will be stored as + * {@code StatusCode.UNDEFINED} + */ + public Status(StatusCode errorCode) { + this.code = (errorCode != null) ? errorCode : StatusCode.UNDEFINED; + this.description = (description != null) ? description : this.code + .toString(); + } + + /** + * Returns the status code + * + * @return the {@code StatusCode} representing the status code + */ + public StatusCode getCode() { + return code; + } + + /** + * Returns a human readable description of the failure if any + * + * @return a string representing the reason of failure + */ + public String getDescription() { + return description; + } + + /** + * Tells whether the status is successful + * + * @return true if the Status code is {@code StatusCode.SUCCESS} + */ + public boolean isSuccess() { + return code == StatusCode.SUCCESS; + } + + @Override + public String toString() { + return code + ": " + description; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((code == null) ? 0 : code.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Status other = (Status) obj; + if (code != other.code) + return false; + return true; + } } diff --git a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java index 722f993518..f257befd3c 100644 --- a/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java +++ b/opendaylight/sal/api/src/test/java/org/opendaylight/controller/sal/match/MatchTest.java @@ -304,6 +304,49 @@ public class MatchTest { } } + @Test + public void testEqualityNetMask() throws Exception { + + InetAddress srcIP = InetAddress.getByName("1.1.1.1"); + InetAddress ipMask = InetAddress.getByName("255.255.255.255"); + InetAddress srcIP2 = InetAddress.getByName("1.1.1.1"); + InetAddress ipMask2 = null; + short ethertype = EtherTypes.IPv4.shortValue(); + short ethertype2 = EtherTypes.IPv4.shortValue(); + + /* + * Create a SAL Flow aFlow + */ + Match match1 = new Match(); + Match match2 = new Match(); + + match1.setField(MatchType.DL_TYPE, ethertype); + match1.setField(MatchType.NW_SRC, srcIP, ipMask); + + match2.setField(MatchType.DL_TYPE, ethertype2); + match2.setField(MatchType.NW_SRC, srcIP2, ipMask2); + + Assert.assertTrue(match1.equals(match2)); + + ipMask2 = InetAddress.getByName("255.255.255.255"); + match2.setField(MatchType.NW_SRC, srcIP2, ipMask2); + + srcIP = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355"); + srcIP2 = InetAddress.getByName("2001:420:281:1004:407a:57f4:4d15:c355"); + ipMask = null; + ipMask2 = InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff"); + ethertype = EtherTypes.IPv6.shortValue(); + ethertype2 = EtherTypes.IPv6.shortValue(); + + match1.setField(MatchType.DL_TYPE, ethertype); + match1.setField(MatchType.NW_SRC, srcIP, ipMask); + + match2.setField(MatchType.DL_TYPE, ethertype2); + match2.setField(MatchType.NW_SRC, srcIP2, ipMask2); + + Assert.assertTrue(match1.equals(match2)); + } + @Test public void testCloning() throws Exception { Node node = NodeCreator.createOFNode(7l); diff --git a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java index 1d7732af44..99690802e3 100644 --- a/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java +++ b/opendaylight/sal/implementation/src/main/java/org/opendaylight/controller/sal/implementation/internal/Activator.java @@ -1,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -10,8 +9,10 @@ package org.opendaylight.controller.sal.implementation.internal; import org.opendaylight.controller.sal.core.ComponentActivatorAbstractBase; +import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener; import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService; import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService; +import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService; import org.opendaylight.controller.sal.inventory.IInventoryService; import org.opendaylight.controller.sal.inventory.IListenInventoryUpdates; import org.opendaylight.controller.sal.inventory.IPluginInInventoryService; @@ -35,32 +36,31 @@ public class Activator extends ComponentActivatorAbstractBase { .getLogger(Activator.class); /** - * Function called when the activator starts just after some - * initializations are done by the - * ComponentActivatorAbstractBase. - * + * Function called when the activator starts just after some initializations + * are done by the ComponentActivatorAbstractBase. + * */ public void init() { } /** - * Function called when the activator stops just before the - * cleanup done by ComponentActivatorAbstractBase - * + * Function called when the activator stops just before the cleanup done by + * ComponentActivatorAbstractBase + * */ public void destroy() { } /** - * Function that is used to communicate to dependency manager the - * list of known implementations for services inside a container - * - * + * Function that is used to communicate to dependency manager the list of + * known implementations for services inside a container + * + * * @return An array containing all the CLASS objects that will be - * instantiated in order to get an fully working implementation - * Object + * instantiated in order to get an fully working implementation + * Object */ public Object[] getImplementations() { Object[] res = { Topology.class, Inventory.class, @@ -70,97 +70,107 @@ public class Activator extends ComponentActivatorAbstractBase { } /** - * Function that is called when configuration of the dependencies - * is required. - * - * @param c dependency manager Component object, used for - * configuring the dependencies exported and imported - * @param imp Implementation class that is being configured, - * needed as long as the same routine can configure multiple - * implementations - * @param containerName The containerName being configured, this allow - * also optional per-container different behavior if needed, usually - * should not be the case though. + * Function that is called when configuration of the dependencies is + * required. + * + * @param c + * dependency manager Component object, used for configuring the + * dependencies exported and imported + * @param imp + * Implementation class that is being configured, needed as long + * as the same routine can configure multiple implementations + * @param containerName + * The containerName being configured, this allow also optional + * per-container different behavior if needed, usually should not + * be the case though. */ public void configureInstance(Component c, Object imp, String containerName) { if (imp.equals(Topology.class)) { // export the service for Apps and Plugins - c.setInterface(new String[] { - IPluginOutTopologyService.class.getName(), - ITopologyService.class.getName() }, null); + c.setInterface( + new String[] { IPluginOutTopologyService.class.getName(), + ITopologyService.class.getName() }, null); // There can be multiple Topology listeners or there could // be none, hence the dependency is optional - c.add(createContainerServiceDependency(containerName).setService( - IListenTopoUpdates.class).setCallbacks("setUpdateService", - "unsetUpdateService").setRequired(false)); + c.add(createContainerServiceDependency(containerName) + .setService(IListenTopoUpdates.class) + .setCallbacks("setUpdateService", "unsetUpdateService") + .setRequired(false)); // There can be multiple southbound plugins or there could // be none, the dependency is optional - c.add(createContainerServiceDependency(containerName).setService( - IPluginInTopologyService.class).setCallbacks( - "setPluginService", "unsetPluginService") + c.add(createContainerServiceDependency(containerName) + .setService(IPluginInTopologyService.class) + .setCallbacks("setPluginService", "unsetPluginService") .setRequired(false)); } if (imp.equals(Inventory.class)) { // export the service - c.setInterface(new String[] { - IPluginOutInventoryService.class.getName(), - IInventoryService.class.getName() }, null); + c.setInterface( + new String[] { IPluginOutInventoryService.class.getName(), + IInventoryService.class.getName() }, null); // Now lets add a service dependency to make sure the // provider of service exists - c.add(createContainerServiceDependency(containerName).setService( - IListenInventoryUpdates.class).setCallbacks( - "setUpdateService", "unsetUpdateService") + c.add(createContainerServiceDependency(containerName) + .setService(IListenInventoryUpdates.class) + .setCallbacks("setUpdateService", "unsetUpdateService") .setRequired(false)); - c - .add(createContainerServiceDependency(containerName) - .setService(IPluginInInventoryService.class) - .setCallbacks("setPluginService", - "unsetPluginService").setRequired(true)); + c.add(createContainerServiceDependency(containerName) + .setService(IPluginInInventoryService.class) + .setCallbacks("setPluginService", "unsetPluginService") + .setRequired(true)); } if (imp.equals(FlowProgrammerService.class)) { - // It is the provider of IFlowProgrammerService - c.setInterface(IFlowProgrammerService.class.getName(), null); - //It is also the consumer of IPluginInFlowProgrammerService - c.add(createServiceDependency().setService( - IPluginInFlowProgrammerService.class).setCallbacks( - "setService", "unsetService").setRequired(true)); + c.setInterface( + new String[] { IFlowProgrammerService.class.getName(), + IPluginOutFlowProgrammerService.class.getName() }, + null); + + c.add(createServiceDependency() + .setService(IPluginInFlowProgrammerService.class) + .setCallbacks("setService", "unsetService") + .setRequired(false)); + c.add(createServiceDependency() + .setService(IFlowProgrammerListener.class) + .setCallbacks("setListener", "unsetListener") + .setRequired(false)); } if (imp.equals(ReadService.class)) { // It is the provider of IReadService c.setInterface(IReadService.class.getName(), null); - //It is also the consumer of IPluginInReadService - c.add(createContainerServiceDependency(containerName).setService( - IPluginInReadService.class).setCallbacks("setService", - "unsetService").setRequired(true)); + // It is also the consumer of IPluginInReadService + c.add(createContainerServiceDependency(containerName) + .setService(IPluginInReadService.class) + .setCallbacks("setService", "unsetService") + .setRequired(true)); } /************************/ /* DATA PACKET SERVICES */ /************************/ if (imp.equals(DataPacketService.class)) { - c.setInterface(new String[] { - IPluginOutDataPacketService.class.getName(), - IDataPacketService.class.getName() }, null); + c.setInterface( + new String[] { IPluginOutDataPacketService.class.getName(), + IDataPacketService.class.getName() }, null); // Optionally use PluginInDataService if any southbound // protocol plugin exists - c.add(createContainerServiceDependency(containerName).setService( - IPluginInDataPacketService.class).setCallbacks( - "setPluginInDataService", "unsetPluginInDataService") - .setRequired(false)); + c.add(createContainerServiceDependency(containerName) + .setService(IPluginInDataPacketService.class) + .setCallbacks("setPluginInDataService", + "unsetPluginInDataService").setRequired(false)); // Optionally listed to IListenDataPacket services - c.add(createContainerServiceDependency(containerName).setService( - IListenDataPacket.class).setCallbacks( - "setListenDataPacket", "unsetListenDataPacket") - .setRequired(false)); + c.add(createContainerServiceDependency(containerName) + .setService(IListenDataPacket.class) + .setCallbacks("setListenDataPacket", + "unsetListenDataPacket").setRequired(false)); } } } 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 d2a49b9208..0cc2a1943d 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,4 +1,3 @@ - /* * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved. * @@ -14,7 +13,9 @@ import java.util.concurrent.ConcurrentHashMap; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; +import java.util.Set; import org.eclipse.osgi.framework.console.CommandInterpreter; import org.eclipse.osgi.framework.console.CommandProvider; @@ -29,8 +30,10 @@ import org.opendaylight.controller.sal.core.Node; import org.opendaylight.controller.sal.core.NodeConnector; import org.opendaylight.controller.sal.core.Node.NodeIDType; import org.opendaylight.controller.sal.flowprogrammer.Flow; +import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerListener; import org.opendaylight.controller.sal.flowprogrammer.IFlowProgrammerService; import org.opendaylight.controller.sal.flowprogrammer.IPluginInFlowProgrammerService; +import org.opendaylight.controller.sal.flowprogrammer.IPluginOutFlowProgrammerService; import org.opendaylight.controller.sal.match.Match; import org.opendaylight.controller.sal.match.MatchType; import org.opendaylight.controller.sal.utils.StatusCode; @@ -44,35 +47,37 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** - * The SAL Flow Programmer Service. It dispatches the flow programming - * requests to the proper SDN protocol plugin - * - * - * + * The SAL Flow Programmer Service. It dispatches the flow programming requests + * to the proper SDN protocol plugin and it notifies about asynchronous messages + * received from the network node related to flow programming. */ public class FlowProgrammerService implements IFlowProgrammerService, - CommandProvider { + IPluginOutFlowProgrammerService, CommandProvider { protected static final Logger logger = LoggerFactory .getLogger(FlowProgrammerService.class); - private ConcurrentHashMap - pluginFlowProgrammer = - new ConcurrentHashMap(); + private ConcurrentHashMap pluginFlowProgrammer; + private Set listener; + + public FlowProgrammerService() { + pluginFlowProgrammer = new ConcurrentHashMap(); + listener = new HashSet(); + } /** * Function called by the dependency manager when all the required * dependencies are satisfied - * + * */ void init() { logger.debug("INIT called!"); } /** - * 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. - * + * 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() { // Clear previous registration to avoid they are left hanging @@ -81,10 +86,9 @@ public class FlowProgrammerService implements IFlowProgrammerService, } /** - * Function called by dependency manager after "init ()" is called - * and after the services provided by the class are registered in - * the service registry - * + * 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() { logger.debug("START called!"); @@ -93,10 +97,10 @@ public class FlowProgrammerService implements IFlowProgrammerService, } /** - * Function called by the dependency manager before the services - * exported by the component are unregistered, this will be - * followed by a "destroy ()" calls - * + * 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() { logger.debug("STOP called!"); @@ -113,8 +117,8 @@ public class FlowProgrammerService implements IFlowProgrammerService, String type = null; for (Object e : props.entrySet()) { Map.Entry entry = (Map.Entry) e; - logger.trace("Prop key:({}) value:({})",entry.getKey(), - entry.getValue()); + logger.trace("Prop key:({}) value:({})", entry.getKey(), + entry.getValue()); } Object value = props.get("protocolPluginType"); @@ -126,12 +130,11 @@ public class FlowProgrammerService implements IFlowProgrammerService, + "protocolPluginType provided"); } else { this.pluginFlowProgrammer.put(type, s); - logger.debug("Stored the pluginFlowProgrammer for type: {}",type); + logger.debug("Stored the pluginFlowProgrammer for type: {}", type); } } - public void unsetService(Map props, - IPluginInFlowProgrammerService s) { + public void unsetService(Map props, IPluginInFlowProgrammerService s) { if (this.pluginFlowProgrammer == null) { logger.error("pluginFlowProgrammer store null"); return; @@ -141,8 +144,8 @@ public class FlowProgrammerService implements IFlowProgrammerService, logger.debug("Received unsetpluginFlowProgrammer request"); for (Object e : props.entrySet()) { Map.Entry entry = (Map.Entry) e; - logger.trace("Prop key:({}) value:({})",entry.getKey(), - entry.getValue()); + logger.trace("Prop key:({}) value:({})", entry.getKey(), + entry.getValue()); } Object value = props.get("protocoloPluginType"); @@ -158,12 +161,20 @@ public class FlowProgrammerService implements IFlowProgrammerService, } } + public void setListener(IFlowProgrammerListener s) { + this.listener.add(s); + } + + public void unsetListener(IFlowProgrammerListener s) { + this.listener.remove(s); + } + @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); + return this.pluginFlowProgrammer.get(node.getType()).addFlow( + node, flow); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -174,7 +185,7 @@ public class FlowProgrammerService implements IFlowProgrammerService, if (pluginFlowProgrammer != null) { if (this.pluginFlowProgrammer.get(node.getType()) != null) { return this.pluginFlowProgrammer.get(node.getType()) - .removeFlow(node, flow); + .removeFlow(node, flow); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -185,7 +196,7 @@ public class FlowProgrammerService implements IFlowProgrammerService, if (pluginFlowProgrammer != null) { if (this.pluginFlowProgrammer.get(node.getType()) != null) { return this.pluginFlowProgrammer.get(node.getType()) - .removeAllFlows(node); + .removeAllFlows(node); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); @@ -196,12 +207,19 @@ public class FlowProgrammerService implements IFlowProgrammerService, if (pluginFlowProgrammer != null) { if (this.pluginFlowProgrammer.get(node.getType()) != null) { return this.pluginFlowProgrammer.get(node.getType()) - .modifyFlow(node, oldFlow, newFlow); + .modifyFlow(node, oldFlow, newFlow); } } return new Status(StatusCode.NOSERVICE, "Plugin unuvailable"); } + @Override + public void flowRemoved(Node node, Flow flow) { + for (IFlowProgrammerListener l : listener) { + l.flowRemoved(node, flow); + } + } + // ---------------- OSGI TEST CODE ------------------------------// private void registerWithOSGIConsole() { @@ -215,10 +233,8 @@ public class FlowProgrammerService implements IFlowProgrammerService, public String getHelp() { StringBuffer help = new StringBuffer(); help.append("---SAL Flow Programmer testing commands---\n"); - help - .append("\t addflow - Add a sample flow to the openflow switch \n"); - help - .append("\t removeflow - Remove the sample flow from the openflow switch \n"); + help.append("\t addflow - Add a sample flow to the openflow switch \n"); + help.append("\t removeflow - Remove the sample flow from the openflow switch \n"); return help.toString(); } @@ -256,8 +272,8 @@ public class FlowProgrammerService implements IFlowProgrammerService, Flow flowA = getSampleFlow(node); Flow flowB = getSampleFlow(node); Match matchB = flowB.getMatch(); - matchB.setField(MatchType.NW_DST, InetAddress - .getByName("190.190.190.190")); + matchB.setField(MatchType.NW_DST, + InetAddress.getByName("190.190.190.190")); flowB.setMatch(matchB); ci.println(this.modifyFlow(node, flowA, flowB)); } @@ -380,15 +396,17 @@ public class FlowProgrammerService implements IFlowProgrammerService, .getByName("2001:420:281:1004:407a:57f4:4d15:c355"); InetAddress dstIP = InetAddress .getByName("2001:420:281:1004:e123:e688:d655:a1b0"); - InetAddress ipMask = null; //InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0"); V6Match implementation assumes no mask is specified - InetAddress ipMask2 = null; //InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0"); + InetAddress ipMask = null; // InetAddress.getByName("ffff:ffff:ffff:ffff:0:0:0:0"); + // V6Match implementation assumes no mask is + // specified + InetAddress ipMask2 = null; // InetAddress.getByName("ffff:ffff:ffff:ffff:ffff:ffff:ffff:0"); short ethertype = EtherTypes.IPv6.shortValue(); short vlan = (short) 27; byte vlanPr = (byte) 3; Byte tos = 4; byte proto = IPProtocols.UDP.byteValue(); short src = (short) 5500; - //short dst = 80; + // short dst = 80; /* * Create a SAL Flow aFlow @@ -399,13 +417,16 @@ public class FlowProgrammerService implements IFlowProgrammerService, match.setField(MatchType.DL_DST, dstMac); match.setField(MatchType.DL_TYPE, ethertype); match.setField(MatchType.DL_VLAN, vlan); - match.setField(MatchType.DL_VLAN_PR, vlanPr); //V6Match does not handle this properly... + match.setField(MatchType.DL_VLAN_PR, vlanPr); // V6Match does not handle + // this properly... match.setField(MatchType.NW_SRC, srcIP, ipMask); match.setField(MatchType.NW_DST, dstIP, ipMask2); match.setField(MatchType.NW_TOS, tos); match.setField(MatchType.NW_PROTO, proto); - match.setField(MatchType.TP_SRC, src); //V6Match does not handle this properly... - //match.setField(MatchType.TP_DST, dst); V6Match does not handle this properly... + match.setField(MatchType.TP_SRC, src); // V6Match does not handle this + // properly... + // match.setField(MatchType.TP_DST, dst); V6Match does not handle this + // properly... List actions = new ArrayList(); actions.add(new Output(oport)); @@ -418,4 +439,5 @@ public class FlowProgrammerService implements IFlowProgrammerService, return flow; } + } diff --git a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/yang/types/test/GeneratedTypesTest.java b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/yang/types/test/GeneratedTypesTest.java index 077db920f5..4480f25316 100644 --- a/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/yang/types/test/GeneratedTypesTest.java +++ b/opendaylight/sal/yang-prototype/code-generator/binding-generator-impl/src/test/java/org/opendaylight/controller/sal/binding/yang/types/test/GeneratedTypesTest.java @@ -7,12 +7,12 @@ */ package org.opendaylight.controller.sal.binding.yang.types.test; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import java.util.List; import java.util.Set; +import org.junit.Ignore; import org.junit.Test; import org.opendaylight.controller.sal.binding.generator.api.BindingGenerator; import org.opendaylight.controller.sal.binding.generator.impl.BindingGeneratorImpl; @@ -52,7 +52,8 @@ public class GeneratedTypesTest { assertTrue(genTypes != null); assertEquals(11, genTypes.size()); } - + + @Ignore @Test public void testLeafrefResolving() { final String topologyPath = getClass().getResource( @@ -82,19 +83,19 @@ public class GeneratedTypesTest { topologyPath, interfacesPath, inetTypesPath, yangTypesPath); assertTrue(context != null); assertEquals(4, context.getModules().size()); - + final BindingGenerator bindingGen = new BindingGeneratorImpl(); final List genTypes = bindingGen.generateTypes(context); - + assertEquals(21, genTypes.size()); assertTrue(genTypes != null); - + for (final Type genType : genTypes) { if (genType.getName().equals("Interface") && genType instanceof GeneratedType) { // System.out.println(((GeneratedType)genType).getMethodDefinitions().toString()); } else if (genType.getName().equals("NetworkLink") && genType instanceof GeneratedType) { // System.out.println(((GeneratedType)genType).getMethodDefinitions().toString()); - } + } } } diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/pom.xml b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/pom.xml index f7810fec78..33d1053f7d 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/pom.xml +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct/pom.xml @@ -38,7 +38,7 @@ org.opendaylight.controller - yang-to-sources + maven-yang 1.0 test-jar diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_combined/pom.xml b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_combined/pom.xml index 190e2c184b..4fd10ea70f 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_combined/pom.xml +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_combined/pom.xml @@ -49,7 +49,7 @@ org.opendaylight.controller - yang-to-sources + maven-yang 1.0 test-jar diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_resources/pom.xml b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_resources/pom.xml index 03ae399362..acb8e6036a 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_resources/pom.xml +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/Correct_resources/pom.xml @@ -38,7 +38,7 @@ org.opendaylight.controller - yang-to-sources + maven-yang 1.0 test-jar diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/NoYangFiles/pom.xml b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/NoYangFiles/pom.xml index 561946e71b..a64c759394 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/NoYangFiles/pom.xml +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/NoYangFiles/pom.xml @@ -38,7 +38,7 @@ org.opendaylight.controller - yang-to-sources + maven-yang 1.0 test-jar diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml index 54b1c748a4..88829dff0c 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator/pom.xml @@ -46,7 +46,7 @@ org.opendaylight.controller - yang-to-sources + maven-yang 1.0 test-jar diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator_resources/pom.xml b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator_resources/pom.xml index 503b45f478..9d4175d2df 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator_resources/pom.xml +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin-it/src/test/resources/UnknownGenerator_resources/pom.xml @@ -46,7 +46,7 @@ org.opendaylight.controller - yang-to-sources + maven-yang 1.0 test-jar diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/pom.xml b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/pom.xml index 1dd5691411..f9e3a9a6ff 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/pom.xml +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/pom.xml @@ -9,6 +9,14 @@ maven-yang-plugin maven-plugin + + This plugin is a wrapper for "yang to source code" generation. + It can be configured by a set of third-party code generators and resource providers. + For further info see available goals. + Sample usage: + + TODO: add sample usage when finished + @@ -55,6 +63,16 @@ + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.2 + + + + diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java index f6602e6aae..85f2d8905d 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/ConfigArg.java @@ -12,7 +12,7 @@ import java.io.File; import com.google.common.base.Preconditions; /** - * Complex configuration arguments + * Base complex configuration arguments */ public abstract class ConfigArg { @@ -31,6 +31,9 @@ public abstract class ConfigArg { public abstract void check(); + /** + * Configuration argument for resource generator class and output directory. + */ public static final class ResourceProviderArg extends ConfigArg { private String resourceProviderClass; @@ -59,7 +62,7 @@ public abstract class ConfigArg { } /** - * Transfer object for code generator class and output directory. + * Configuration argument for code generator class and output directory. */ public static final class CodeGeneratorArg extends ConfigArg { private String codeGeneratorClass; diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToResourcesMojo.java b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToResourcesMojo.java index 7bb49dc0df..b4490499cf 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToResourcesMojo.java +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToResourcesMojo.java @@ -23,14 +23,40 @@ import org.opendaylight.controller.yang2sources.spi.ResourceGenerator; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Maps; +/** + * Generate resources from yang files using user provided set of + * {@link ResourceGenerator}s. Can be used to copy yang files that served as + * blueprint for code generation into resources directory. Steps of this + * process: + *
    + *
  1. List yang files from {@link #yangFilesRootDir} (If this goal is in the + * same execution as generate-sources, the same cached list will be used and the + * root folder will not be searched for yang files twice)
  2. + *
  3. For each {@link ResourceGenerator} from {@link #resourceProviders}:
  4. + *
      + *
    1. Instantiate using default constructor
    2. + *
    3. Call {@link ResourceGenerator#generateResourceFiles(Collection, File)}
    4. + *
    + *
+ */ @Mojo(name = "generate-resources", defaultPhase = LifecyclePhase.GENERATE_RESOURCES) public final class YangToResourcesMojo extends AbstractMojo { private static final String LOG_PREFIX = "yang-to-resources:"; + /** + * Classes implementing {@link ResourceGenerator} interface. An instance + * will be created out of every class using default constructor. Method + * {@link ResourceGenerator#generateResourceFiles(Collection, File)} will be + * called on every instance. + */ @Parameter(required = true) private ResourceProviderArg[] resourceProviders; + /** + * Source directory that will be recursively searched for yang files (ending + * with .yang suffix). + */ @Parameter(required = true) private String yangFilesRootDir; diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java index 29282988d6..32ad2abb10 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang-plugin/src/main/java/org/opendaylight/controller/yang2sources/plugin/YangToSourcesMojo.java @@ -29,14 +29,37 @@ import org.opendaylight.controller.yang2sources.spi.CodeGenerator; import com.google.common.annotations.VisibleForTesting; import com.google.common.collect.Maps; +/** + * Generate sources from yang files using user provided set of + * {@link CodeGenerator}s. Steps of this process: + *
    + *
  1. List yang files from {@link #yangFilesRootDir}
  2. + *
  3. Process yang files using {@link YangModelParserImpl}
  4. + *
  5. For each {@link CodeGenerator} from {@link #codeGenerators}:
  6. + *
      + *
    1. Instantiate using default constructor
    2. + *
    3. Call {@link CodeGenerator#generateSources(SchemaContext, File)}
    4. + *
    + *
+ */ @Mojo(name = "generate-sources", defaultPhase = LifecyclePhase.GENERATE_SOURCES) public final class YangToSourcesMojo extends AbstractMojo { private static final String LOG_PREFIX = "yang-to-sources:"; + /** + * Classes implementing {@link CodeGenerator} interface. An instance will be + * created out of every class using default constructor. Method + * {@link CodeGenerator#generateSources(SchemaContext, File)} will be called + * on every instance. + */ @Parameter(required = true) private CodeGeneratorArg[] codeGenerators; + /** + * Source directory that will be recursively searched for yang files (ending + * with .yang suffix). + */ @Parameter(required = true) private String yangFilesRootDir; diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java b/opendaylight/sal/yang-prototype/code-generator/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java index 2b39320989..534c37de10 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/CodeGenerator.java @@ -12,7 +12,21 @@ import java.util.Collection; import org.opendaylight.controller.yang.model.api.SchemaContext; +/** + * Classes implementing this interface can be submitted to maven-yang-plugin's + * generate-sources goal. + */ public interface CodeGenerator { + /** + * Generate sources from provided {@link SchemaContext} + * + * @param context + * parsed from yang files + * @param outputBaseDir + * expected output directory for generated sources configured by + * user + * @return collection of files that were generated from schema context + */ Collection generateSources(SchemaContext context, File outputBaseDir); } diff --git a/opendaylight/sal/yang-prototype/code-generator/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/ResourceGenerator.java b/opendaylight/sal/yang-prototype/code-generator/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/ResourceGenerator.java index 9095155b0c..2638dc33b0 100644 --- a/opendaylight/sal/yang-prototype/code-generator/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/ResourceGenerator.java +++ b/opendaylight/sal/yang-prototype/code-generator/maven-yang/src/main/java/org/opendaylight/controller/yang2sources/spi/ResourceGenerator.java @@ -10,7 +10,20 @@ package org.opendaylight.controller.yang2sources.spi; import java.io.File; import java.util.Collection; +/** + * Classes implementing this interface can be submitted to maven-yang-plugin's + * generate-resources goal. + */ public interface ResourceGenerator { + /** + * Generate resources (e.g. copy files into resources folder) from provided + * list of yang files + * + * @param resources + * list of parsed yang files + * @param outputBaseDir + * expected output directory for resources configured by user + */ void generateResourceFiles(Collection resources, File outputBaseDir); } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/AbstractTypeAwareBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/AbstractTypeAwareBuilder.java new file mode 100644 index 0000000000..35446ced15 --- /dev/null +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/AbstractTypeAwareBuilder.java @@ -0,0 +1,32 @@ +package org.opendaylight.controller.yang.model.parser.builder.api; + +import org.opendaylight.controller.yang.model.api.TypeDefinition; + +public class AbstractTypeAwareBuilder implements TypeAwareBuilder { + + protected TypeDefinition type; + protected TypeDefinitionBuilder typedef; + + @Override + public TypeDefinition getType() { + return type; + } + + @Override + public TypeDefinitionBuilder getTypedef() { + return typedef; + } + + @Override + public void setType(TypeDefinition type) { + this.type = type; + this.typedef = null; + } + + @Override + public void setType(TypeDefinitionBuilder typedef) { + this.typedef = typedef; + this.type = null; + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/TypeAwareBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/TypeAwareBuilder.java index ac51e5796d..73f2cf28ca 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/TypeAwareBuilder.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/TypeAwareBuilder.java @@ -15,7 +15,12 @@ import org.opendaylight.controller.yang.model.api.TypeDefinition; */ public interface TypeAwareBuilder { - TypeDefinition getType(); - void setType(TypeDefinition type); + TypeDefinition getType(); + + TypeDefinitionBuilder getTypedef(); + + void setType(TypeDefinition type); + + void setType(TypeDefinitionBuilder typedef); } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/TypeDefinitionBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/TypeDefinitionBuilder.java index a303b969a6..a18fa8b4d6 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/TypeDefinitionBuilder.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/api/TypeDefinitionBuilder.java @@ -7,22 +7,59 @@ */ package org.opendaylight.controller.yang.model.parser.builder.api; +import java.util.List; + import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.model.api.SchemaPath; +import org.opendaylight.controller.yang.model.api.Status; import org.opendaylight.controller.yang.model.api.TypeDefinition; +import org.opendaylight.controller.yang.model.api.type.LengthConstraint; +import org.opendaylight.controller.yang.model.api.type.PatternConstraint; +import org.opendaylight.controller.yang.model.api.type.RangeConstraint; +import org.opendaylight.controller.yang.model.parser.builder.impl.UnknownSchemaNodeBuilder; /** * Interface for builders of 'typedef' statement. */ -public interface TypeDefinitionBuilder { +public interface TypeDefinitionBuilder extends TypeAwareBuilder, + SchemaNodeBuilder { + + TypeDefinition build(); QName getQName(); - TypeDefinition getBaseType(); + SchemaPath getPath(); - TypeDefinition build(); + String getDescription(); - void setUnits(String units); + String getReference(); + + Status getStatus(); + + List getRanges(); + + void setRanges(List ranges); + + List getLengths(); + + void setLengths(List lengths); + + List getPatterns(); + + void setPatterns(List patterns); + + Integer getFractionDigits(); + + void setFractionDigits(Integer fractionDigits); + + List getUnknownNodes(); + + Object getDefaultValue(); void setDefaultValue(Object defaultValue); + String getUnits(); + + void setUnits(String units); + } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ContainerSchemaNodeBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ContainerSchemaNodeBuilder.java index 9b965daae6..eed8437fdd 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ContainerSchemaNodeBuilder.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ContainerSchemaNodeBuilder.java @@ -55,28 +55,28 @@ public class ContainerSchemaNodeBuilder extends AbstractChildNodeBuilder @Override public ContainerSchemaNode build() { // CHILD NODES - Map childs = new HashMap(); + final Map childs = new HashMap(); for (DataSchemaNodeBuilder node : childNodes) { childs.put(node.getQName(), node.build()); } instance.setChildNodes(childs); // GROUPINGS - Set groupingDefinitions = new HashSet(); + final Set groupingDefinitions = new HashSet(); for (GroupingBuilder builder : groupings) { groupingDefinitions.add(builder.build()); } instance.setGroupings(groupingDefinitions); // TYPEDEFS - Set> typedefs = new HashSet>(); + final Set> typedefs = new HashSet>(); for (TypeDefinitionBuilder entry : addedTypedefs) { typedefs.add(entry.build()); } instance.setTypeDefinitions(typedefs); // USES - Set uses = new HashSet(); + final Set uses = new HashSet(); for (UsesNodeBuilder builder : addedUsesNodes) { uses.add(builder.build()); } @@ -84,7 +84,7 @@ public class ContainerSchemaNodeBuilder extends AbstractChildNodeBuilder // UNKNOWN NODES final List unknownNodes = new ArrayList(); - for(UnknownSchemaNodeBuilder b : addedUnknownNodes) { + for (UnknownSchemaNodeBuilder b : addedUnknownNodes) { unknownNodes.add(b.build()); } instance.setUnknownSchemaNodes(unknownNodes); @@ -169,7 +169,7 @@ public class ContainerSchemaNodeBuilder extends AbstractChildNodeBuilder private Set groupings = Collections.emptySet(); private Set> typeDefinitions = Collections.emptySet(); private Set uses = Collections.emptySet(); - private List unknownSchemaNodes = Collections.emptyList(); + private List unknownNodes = Collections.emptyList(); private boolean presence; private ContainerSchemaNodeImpl(QName qname) { @@ -330,12 +330,13 @@ public class ContainerSchemaNodeBuilder extends AbstractChildNodeBuilder @Override public List getUnknownSchemaNodes() { - return unknownSchemaNodes; + return unknownNodes; } - private void setUnknownSchemaNodes(List unknownSchemaNodes) { - if(unknownSchemaNodes != null) { - this.unknownSchemaNodes = unknownSchemaNodes; + private void setUnknownSchemaNodes( + List unknownSchemaNodes) { + if (unknownSchemaNodes != null) { + this.unknownNodes = unknownSchemaNodes; } } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafListSchemaNodeBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafListSchemaNodeBuilder.java index 5a9fdb5815..12c976b774 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafListSchemaNodeBuilder.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafListSchemaNodeBuilder.java @@ -18,18 +18,17 @@ import org.opendaylight.controller.yang.model.api.SchemaPath; import org.opendaylight.controller.yang.model.api.Status; import org.opendaylight.controller.yang.model.api.TypeDefinition; import org.opendaylight.controller.yang.model.api.UnknownSchemaNode; +import org.opendaylight.controller.yang.model.parser.builder.api.AbstractTypeAwareBuilder; import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder; import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder; -public class LeafListSchemaNodeBuilder implements SchemaNodeBuilder, - TypeAwareBuilder, DataSchemaNodeBuilder { +public class LeafListSchemaNodeBuilder extends AbstractTypeAwareBuilder implements SchemaNodeBuilder, + DataSchemaNodeBuilder { private final LeafListSchemaNodeImpl instance; private final QName qname; - private final ConstraintsBuilder constraintsBuilder = new ConstraintsBuilder(); + private final ConstraintsBuilder constraints = new ConstraintsBuilder(); private final List addedUnknownNodes = new ArrayList(); - private TypeDefinition type; LeafListSchemaNodeBuilder(QName qname) { this.qname = qname; @@ -38,7 +37,21 @@ public class LeafListSchemaNodeBuilder implements SchemaNodeBuilder, @Override public LeafListSchemaNode build() { - instance.setConstraints(constraintsBuilder.build()); + instance.setConstraints(constraints.build()); + + if(type == null) { + instance.setType(typedef.build()); + } else { + instance.setType(type); + } + + // UNKNOWN NODES + final List unknownNodes = new ArrayList(); + for (UnknownSchemaNodeBuilder b : addedUnknownNodes) { + unknownNodes.add(b.build()); + } + instance.setUnknownSchemaNodes(unknownNodes); + return instance; } @@ -69,17 +82,6 @@ public class LeafListSchemaNodeBuilder implements SchemaNodeBuilder, } } - @Override - public TypeDefinition getType() { - return type; - } - - @Override - public void setType(TypeDefinition type) { - this.type = type; - instance.setType(type); - } - @Override public void setAugmenting(boolean augmenting) { instance.setAugmenting(augmenting); @@ -92,7 +94,7 @@ public class LeafListSchemaNodeBuilder implements SchemaNodeBuilder, @Override public ConstraintsBuilder getConstraintsBuilder() { - return constraintsBuilder; + return constraints; } public void setUserOrdered(boolean userOrdered) { @@ -112,10 +114,11 @@ public class LeafListSchemaNodeBuilder implements SchemaNodeBuilder, private Status status = Status.CURRENT; private boolean augmenting; private boolean configuration; - private ConstraintDefinition constraints; + private ConstraintDefinition constraintsDef; private TypeDefinition type; private boolean userOrdered; - private List unknownSchemaNodes = Collections.emptyList(); + private List unknownNodes = Collections + .emptyList(); private LeafListSchemaNodeImpl(QName qname) { this.qname = qname; @@ -182,11 +185,11 @@ public class LeafListSchemaNodeBuilder implements SchemaNodeBuilder, @Override public ConstraintDefinition getConstraints() { - return constraints; + return constraintsDef; } - private void setConstraints(ConstraintDefinition constraints) { - this.constraints = constraints; + private void setConstraints(ConstraintDefinition constraintsDef) { + this.constraintsDef = constraintsDef; } @Override @@ -209,12 +212,13 @@ public class LeafListSchemaNodeBuilder implements SchemaNodeBuilder, @Override public List getUnknownSchemaNodes() { - return unknownSchemaNodes; + return unknownNodes; } - private void setUnknownSchemaNodes(List unknownSchemaNodes) { - if(unknownSchemaNodes != null) { - this.unknownSchemaNodes = unknownSchemaNodes; + private void setUnknownSchemaNodes( + List unknownNodes) { + if (unknownNodes != null) { + this.unknownNodes = unknownNodes; } } @@ -268,7 +272,7 @@ public class LeafListSchemaNodeBuilder implements SchemaNodeBuilder, sb.append(", status=" + status); sb.append(", augmenting=" + augmenting); sb.append(", configuration=" + configuration); - sb.append(", constraints=" + constraints); + sb.append(", constraints=" + constraintsDef); sb.append(", type=" + type); sb.append(", userOrdered=" + userOrdered); sb.append("]"); diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafSchemaNodeBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafSchemaNodeBuilder.java index bd18ba50a3..6146550257 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafSchemaNodeBuilder.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafSchemaNodeBuilder.java @@ -18,18 +18,16 @@ import org.opendaylight.controller.yang.model.api.SchemaPath; import org.opendaylight.controller.yang.model.api.Status; import org.opendaylight.controller.yang.model.api.TypeDefinition; import org.opendaylight.controller.yang.model.api.UnknownSchemaNode; +import org.opendaylight.controller.yang.model.parser.builder.api.AbstractTypeAwareBuilder; import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder; import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder; - -public class LeafSchemaNodeBuilder implements DataSchemaNodeBuilder, - SchemaNodeBuilder, TypeAwareBuilder { +public class LeafSchemaNodeBuilder extends AbstractTypeAwareBuilder implements DataSchemaNodeBuilder, + SchemaNodeBuilder { private final QName qname; private final LeafSchemaNodeImpl instance; - private final ConstraintsBuilder constraintsBuilder = new ConstraintsBuilder(); + private final ConstraintsBuilder constraints = new ConstraintsBuilder(); private final List addedUnknownNodes = new ArrayList(); - private TypeDefinition type; LeafSchemaNodeBuilder(QName qname) { this.qname = qname; @@ -38,6 +36,12 @@ public class LeafSchemaNodeBuilder implements DataSchemaNodeBuilder, @Override public LeafSchemaNode build() { + if(type == null) { + instance.setType(typedef.build()); + } else { + instance.setType(type); + } + // UNKNOWN NODES final List unknownNodes = new ArrayList(); for(UnknownSchemaNodeBuilder b : addedUnknownNodes) { @@ -45,7 +49,7 @@ public class LeafSchemaNodeBuilder implements DataSchemaNodeBuilder, } instance.setUnknownSchemaNodes(unknownNodes); - instance.setConstraints(constraintsBuilder.build()); + instance.setConstraints(constraints.build()); return instance; } @@ -88,23 +92,12 @@ public class LeafSchemaNodeBuilder implements DataSchemaNodeBuilder, @Override public ConstraintsBuilder getConstraintsBuilder() { - return constraintsBuilder; - } - - @Override - public TypeDefinition getType() { - return type; - } - - @Override - public void setType(TypeDefinition type) { - this.type = type; - instance.setType(type); + return constraints; } @Override - public void addUnknownSchemaNode(UnknownSchemaNodeBuilder unknownSchemaNodeBuilder) { - addedUnknownNodes.add(unknownSchemaNodeBuilder); + public void addUnknownSchemaNode(UnknownSchemaNodeBuilder unknownNode) { + addedUnknownNodes.add(unknownNode); } private class LeafSchemaNodeImpl implements LeafSchemaNode { @@ -115,9 +108,9 @@ public class LeafSchemaNodeBuilder implements DataSchemaNodeBuilder, private Status status = Status.CURRENT; private boolean augmenting; private boolean configuration; - private ConstraintDefinition constraints; + private ConstraintDefinition constraintsDef; private TypeDefinition type; - private List unknownSchemaNodes = Collections.emptyList(); + private List unknownNodes = Collections.emptyList(); private LeafSchemaNodeImpl(QName qname) { this.qname = qname; @@ -186,11 +179,11 @@ public class LeafSchemaNodeBuilder implements DataSchemaNodeBuilder, @Override public ConstraintDefinition getConstraints() { - return constraints; + return constraintsDef; } - private void setConstraints(ConstraintDefinition constraints) { - this.constraints = constraints; + private void setConstraints(ConstraintDefinition constraintsDef) { + this.constraintsDef = constraintsDef; } @Override @@ -204,12 +197,12 @@ public class LeafSchemaNodeBuilder implements DataSchemaNodeBuilder, @Override public List getUnknownSchemaNodes() { - return unknownSchemaNodes; + return unknownNodes; } - private void setUnknownSchemaNodes(List unknownSchemaNodes) { - if(unknownSchemaNodes != null) { - this.unknownSchemaNodes = unknownSchemaNodes; + private void setUnknownSchemaNodes(List unknownNodes) { + if(unknownNodes != null) { + this.unknownNodes = unknownNodes; } } @@ -263,9 +256,9 @@ public class LeafSchemaNodeBuilder implements DataSchemaNodeBuilder, sb.append(", status=" + status); sb.append(", augmenting=" + augmenting); sb.append(", configuration=" + configuration); - sb.append(", constraints=" + constraints); + sb.append(", constraints=" + constraintsDef); sb.append(", type=" + type); - sb.append(", constraints=" + constraints); + sb.append(", constraints=" + constraintsDef); sb.append("]"); return sb.toString(); } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ModuleBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ModuleBuilder.java index d22295ae66..86adcdd71d 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ModuleBuilder.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/ModuleBuilder.java @@ -1,1049 +1,1046 @@ -/* - * 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.yang.model.parser.builder.impl; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import org.opendaylight.controller.yang.common.QName; -import org.opendaylight.controller.yang.model.api.AugmentationSchema; -import org.opendaylight.controller.yang.model.api.DataSchemaNode; -import org.opendaylight.controller.yang.model.api.Deviation; -import org.opendaylight.controller.yang.model.api.ExtensionDefinition; -import org.opendaylight.controller.yang.model.api.FeatureDefinition; -import org.opendaylight.controller.yang.model.api.GroupingDefinition; -import org.opendaylight.controller.yang.model.api.IdentitySchemaNode; -import org.opendaylight.controller.yang.model.api.Module; -import org.opendaylight.controller.yang.model.api.ModuleImport; -import org.opendaylight.controller.yang.model.api.NotificationDefinition; -import org.opendaylight.controller.yang.model.api.RpcDefinition; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.UsesNode; -import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.Builder; -import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionAwareBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder; - -/** - * This builder builds Module object. If this module is dependent on external - * module/modules, these dependencies must be resolved before module is built, - * otherwise result may not be valid. - */ -public class ModuleBuilder implements Builder { - - private final ModuleImpl instance; - private final String name; - private String prefix; - private Date revision; - - private final Set imports = new HashSet(); - private Set augmentations; - - /** - * All nodes, that can contain other nodes - */ - private final Map, Builder> moduleNodes = new HashMap, Builder>(); - - /** - * Holds all child (DataSchemaNode) nodes: anyxml, choice, case, container, - * list, leaf, leaf-list. - */ - private final Map, DataSchemaNodeBuilder> addedChilds = new HashMap, DataSchemaNodeBuilder>(); - - private final Map, GroupingBuilder> addedGroupings = new HashMap, GroupingBuilder>(); - private final Set addedAugments = new HashSet(); - private final Map, UsesNodeBuilder> addedUsesNodes = new HashMap, UsesNodeBuilder>(); - private final Map, RpcDefinitionBuilder> addedRpcs = new HashMap, RpcDefinitionBuilder>(); - private final Set addedNotifications = new HashSet(); - private final Set addedIdentities = new HashSet(); - private final Map, FeatureBuilder> addedFeatures = new HashMap, FeatureBuilder>(); - private final Map addedDeviations = new HashMap(); - private final Map, TypeDefinitionBuilder> addedTypedefs = new HashMap, TypeDefinitionBuilder>(); - private final List addedExtensions = new ArrayList(); - - private final Map, TypeAwareBuilder> dirtyNodes = new HashMap, TypeAwareBuilder>(); - private final Map, UnionTypeBuilder> unionTypes = new HashMap, UnionTypeBuilder>(); - - public ModuleBuilder(String name) { - this.name = name; - instance = new ModuleImpl(name); - } - - - /** - * Build new Module object based on this builder. - */ - @Override - public Module build() { - instance.setImports(imports); - - // TYPEDEFS - final Set> typedefs = buildModuleTypedefs(addedTypedefs); - instance.setTypeDefinitions(typedefs); - - // CHILD NODES - final Map childNodes = buildModuleChildNodes(addedChilds); - instance.setChildNodes(childNodes); - - // GROUPINGS - final Set groupings = buildModuleGroupings(addedGroupings); - instance.setGroupings(groupings); - - // USES - final Set usesNodeDefinitions = buildUsesNodes(addedUsesNodes); - instance.setUses(usesNodeDefinitions); - - // FEATURES - final Set features = buildModuleFeatures(addedFeatures); - instance.setFeatures(features); - - // NOTIFICATIONS - final Set notifications = new HashSet(); - for (NotificationBuilder entry : addedNotifications) { - notifications.add((NotificationDefinition) entry.build()); - } - instance.setNotifications(notifications); - - // AUGMENTATIONS - instance.setAugmentations(augmentations); - - // RPCs - final Set rpcs = buildModuleRpcs(addedRpcs); - instance.setRpcs(rpcs); - - // DEVIATIONS - final Set deviations = new HashSet(); - for (Map.Entry entry : addedDeviations - .entrySet()) { - deviations.add(entry.getValue().build()); - } - instance.setDeviations(deviations); - - // EXTENSIONS - final List extensions = new ArrayList(); - for(ExtensionBuilder b : addedExtensions) { - extensions.add(b.build()); - } - instance.setExtensionSchemaNodes(extensions); - - // IDENTITIES - final Set identities = new HashSet(); - for(IdentitySchemaNodeBuilder idBuilder : addedIdentities) { - identities.add(idBuilder.build()); - } - instance.setIdentities(identities); - - return instance; - } - - public Builder getNode(List path) { - return moduleNodes.get(path); - } - - public Map, TypeAwareBuilder> getDirtyNodes() { - return dirtyNodes; - } - - public Set getAddedAugments() { - return addedAugments; - } - - public Set getAddedIdentities() { - return addedIdentities; - } - - public String getName() { - return name; - } - - public String getPrefix() { - return prefix; - } - - public Date getRevision() { - return revision; - } - - public void addDirtyNode(List path) { - List dirtyNodePath = new ArrayList(path); - TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) moduleNodes - .get(dirtyNodePath); - dirtyNodes.put(dirtyNodePath, nodeBuilder); - } - - public void setNamespace(URI namespace) { - instance.setNamespace(namespace); - } - - public void setRevision(Date revision) { - this.revision = revision; - instance.setRevision(revision); - } - - public void setPrefix(String prefix) { - this.prefix = prefix; - instance.setPrefix(prefix); - } - - public void setYangVersion(String yangVersion) { - instance.setYangVersion(yangVersion); - } - - public void setDescription(String description) { - instance.setDescription(description); - } - - public void setReference(String reference) { - instance.setReference(reference); - } - - public void setOrganization(String organization) { - instance.setOrganization(organization); - } - - public void setContact(String contact) { - instance.setContact(contact); - } - - public void setAugmentations(Set augmentations) { - this.augmentations = augmentations; - } - - public boolean addModuleImport(final String moduleName, - final Date revision, final String prefix) { - ModuleImport moduleImport = createModuleImport(moduleName, revision, - prefix); - return imports.add(moduleImport); - } - - public Set getModuleImports() { - return imports; - } - - public ExtensionBuilder addExtension(QName qname) { - ExtensionBuilder builder = new ExtensionBuilder(qname); - return builder; - } - - public ContainerSchemaNodeBuilder addContainerNode(QName containerName, - List parentPath) { - List pathToNode = new ArrayList(parentPath); - - ContainerSchemaNodeBuilder containerBuilder = new ContainerSchemaNodeBuilder( - containerName); - - ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes - .get(pathToNode); - if (parent != null) { - if(parent instanceof AugmentationSchemaBuilder) { - containerBuilder.setAugmenting(true); - } - parent.addChildNode(containerBuilder); - } - - pathToNode.add(containerName.getLocalName()); - moduleNodes.put(pathToNode, containerBuilder); - addedChilds.put(pathToNode, containerBuilder); - - return containerBuilder; - } - - public ListSchemaNodeBuilder addListNode(QName listName, - List parentPath) { - List pathToNode = new ArrayList(parentPath); - - ListSchemaNodeBuilder listBuilder = new ListSchemaNodeBuilder(listName); - - ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes - .get(pathToNode); - if (parent != null) { - if(parent instanceof AugmentationSchemaBuilder) { - listBuilder.setAugmenting(true); - } - parent.addChildNode(listBuilder); - } - - pathToNode.add(listName.getLocalName()); - moduleNodes.put(pathToNode, listBuilder); - addedChilds.put(pathToNode, listBuilder); - - return listBuilder; - } - - public LeafSchemaNodeBuilder addLeafNode(QName leafName, - List parentPath) { - List pathToNode = new ArrayList(parentPath); - - LeafSchemaNodeBuilder leafBuilder = new LeafSchemaNodeBuilder(leafName); - - ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes.get(pathToNode); - if (parent != null) { - if(parent instanceof AugmentationSchemaBuilder) { - leafBuilder.setAugmenting(true); - } - parent.addChildNode(leafBuilder); - } - - pathToNode.add(leafName.getLocalName()); - addedChilds.put(pathToNode, leafBuilder); - moduleNodes.put(pathToNode, leafBuilder); - - return leafBuilder; - } - - public LeafListSchemaNodeBuilder addLeafListNode(QName leafListName, - List parentPath) { - List pathToNode = new ArrayList(parentPath); - - LeafListSchemaNodeBuilder leafListBuilder = new LeafListSchemaNodeBuilder( - leafListName); - ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes.get(pathToNode); - if (parent != null) { - if(parent instanceof AugmentationSchemaBuilder) { - leafListBuilder.setAugmenting(true); - } - parent.addChildNode(leafListBuilder); - } - - pathToNode.add(leafListName.getLocalName()); - addedChilds.put(pathToNode, leafListBuilder); - moduleNodes.put(pathToNode, leafListBuilder); - - return leafListBuilder; - } - - public GroupingBuilder addGrouping(QName qname, List parentPath) { - List pathToGroup = new ArrayList(parentPath); - - GroupingBuilder builder = new GroupingBuilderImpl(qname); - ChildNodeBuilder parentNodeBuilder = (ChildNodeBuilder) moduleNodes.get(pathToGroup); - if (parentNodeBuilder != null) { - parentNodeBuilder.addGrouping(builder); - } - - pathToGroup.add(qname.getLocalName()); - moduleNodes.put(pathToGroup, builder); - addedGroupings.put(pathToGroup, builder); - - return builder; - } - - public AugmentationSchemaBuilder addAugment(String name, - List parentPath) { - List pathToAugment = new ArrayList(parentPath); - - AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(name); - - // augment can only be in 'module' or 'uses' statement - UsesNodeBuilder parent = addedUsesNodes.get(pathToAugment); - if (parent != null) { - parent.addAugment(builder); - } - - pathToAugment.add(name); - moduleNodes.put(pathToAugment, builder); - addedAugments.add(builder); - - return builder; - } - - public UsesNodeBuilder addUsesNode(String groupingPathStr, - List parentPath) { - List pathToUses = new ArrayList(parentPath); - - UsesNodeBuilder usesBuilder = new UsesNodeBuilderImpl(groupingPathStr); - - ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes.get(pathToUses); - if (parent != null) { - if(parent instanceof AugmentationSchemaBuilder) { - usesBuilder.setAugmenting(true); - } - parent.addUsesNode(usesBuilder); - } - - pathToUses.add(groupingPathStr); - addedUsesNodes.put(pathToUses, usesBuilder); - - return usesBuilder; - } - - public RpcDefinitionBuilder addRpc(QName qname, List parentPath) { - List pathToRpc = new ArrayList(parentPath); - - RpcDefinitionBuilder rpcBuilder = new RpcDefinitionBuilder(qname); - - pathToRpc.add(qname.getLocalName()); - addedRpcs.put(pathToRpc, rpcBuilder); - - QName inputQName = new QName(qname.getNamespace(), qname.getRevision(), - qname.getPrefix(), "input"); - ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(inputQName); - List pathToInput = new ArrayList(pathToRpc); - pathToInput.add("input"); - moduleNodes.put(pathToInput, inputBuilder); - rpcBuilder.setInput(inputBuilder); - - QName outputQName = new QName(qname.getNamespace(), - qname.getRevision(), qname.getPrefix(), "output"); - ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(outputQName); - List pathToOutput = new ArrayList(pathToRpc); - pathToOutput.add("output"); - moduleNodes.put(pathToOutput, outputBuilder); - rpcBuilder.setOutput(outputBuilder); - - return rpcBuilder; - } - - public NotificationBuilder addNotification(QName notificationName, - List parentPath) { - List pathToNotification = new ArrayList(parentPath); - - NotificationBuilder notificationBuilder = new NotificationBuilder( - notificationName); - - pathToNotification.add(notificationName.getLocalName()); - moduleNodes.put(pathToNotification, notificationBuilder); - addedNotifications.add(notificationBuilder); - - return notificationBuilder; - } - - public FeatureBuilder addFeature(QName featureName, List parentPath) { - List pathToFeature = new ArrayList(parentPath); - pathToFeature.add(featureName.getLocalName()); - - FeatureBuilder builder = new FeatureBuilder(featureName); - addedFeatures.put(pathToFeature, builder); - return builder; - } - - public TypedefBuilder addTypedef(QName typeDefName, List parentPath) { - List pathToType = new ArrayList(parentPath); - TypedefBuilder builder = new TypedefBuilder(typeDefName); - TypeDefinitionAwareBuilder parent = (TypeDefinitionAwareBuilder) moduleNodes.get(pathToType); - if (parent != null) { - parent.addTypedef(builder); - } - pathToType.add(typeDefName.getLocalName()); - addedTypedefs.put(pathToType, builder); - moduleNodes.put(pathToType, builder); - return builder; - } - - public Set getModuleTypedefs() { - Set typedefs = new HashSet(); - for (Map.Entry, TypeDefinitionBuilder> entry : addedTypedefs.entrySet()) { - if (entry.getKey().size() == 2) { - typedefs.add(entry.getValue()); - } - } - return typedefs; - } - - public void setType(TypeDefinition type, List parentPath) { - TypeAwareBuilder parent = (TypeAwareBuilder) moduleNodes.get(parentPath); - parent.setType(type); - } - - public void addUnionType(List parentPath) { - TypeAwareBuilder parent = (TypeAwareBuilder) moduleNodes.get(parentPath); - UnionTypeBuilder union = new UnionTypeBuilder(); - parent.setType(union.build()); - - List path = new ArrayList(parentPath); - path.add("union"); - - unionTypes.put(path, union); - moduleNodes.put(path, union); - } - - public DeviationBuilder addDeviation(String targetPath) { - DeviationBuilder builder = new DeviationBuilder(targetPath); - addedDeviations.put(targetPath, builder); - return builder; - } - - public IdentitySchemaNodeBuilder addIdentity(QName qname) { - IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(qname); - addedIdentities.add(builder); - - return builder; - } - - public void addConfiguration(boolean configuration, List parentPath) { - Builder builder = moduleNodes.get(parentPath); - if (builder instanceof DeviationBuilder) { - // skip - // TODO - } else { - DataSchemaNodeBuilder configBuilder = (DataSchemaNodeBuilder) moduleNodes.get(parentPath); - configBuilder.setConfiguration(configuration); - } - } - - public UnknownSchemaNodeBuilder addUnknownSchemaNode(QName qname, List parentPath) { - UnknownSchemaNodeBuilder builder = new UnknownSchemaNodeBuilder(qname); - return builder; - } - - - private class ModuleImpl implements Module { - private URI namespace; - private final String name; - private Date revision; - private String prefix; - private String yangVersion; - private String description; - private String reference; - private String organization; - private String contact; - private Set imports = Collections.emptySet(); - private Set features = Collections.emptySet(); - private Set> typeDefinitions = Collections.emptySet(); - private Set notifications = Collections.emptySet(); - private Set augmentations = Collections.emptySet(); - private Set rpcs = Collections.emptySet(); - private Set deviations = Collections.emptySet(); - private Map childNodes = Collections.emptyMap(); - private Set groupings = Collections.emptySet(); - private Set uses = Collections.emptySet(); - private List extensionSchemaNodes = Collections.emptyList(); - private Set identities = Collections.emptySet(); - - private ModuleImpl(String name) { - this.name = name; - } - - @Override - public URI getNamespace() { - return namespace; - } - - private void setNamespace(URI namespace) { - this.namespace = namespace; - } - - @Override - public String getName() { - return name; - } - - @Override - public Date getRevision() { - return revision; - } - - private void setRevision(Date revision) { - this.revision = revision; - } - - @Override - public String getPrefix() { - return prefix; - } - - private void setPrefix(String prefix) { - this.prefix = prefix; - } - - @Override - public String getYangVersion() { - return yangVersion; - } - - private void setYangVersion(String yangVersion) { - this.yangVersion = yangVersion; - } - - @Override - public String getDescription() { - return description; - } - - private void setDescription(String description) { - this.description = description; - } - - @Override - public String getReference() { - return reference; - } - - private void setReference(String reference) { - this.reference = reference; - } - - @Override - public String getOrganization() { - return organization; - } - - private void setOrganization(String organization) { - this.organization = organization; - } - - @Override - public String getContact() { - return contact; - } - - private void setContact(String contact) { - this.contact = contact; - } - - @Override - public Set getImports() { - return imports; - } - - private void setImports(Set imports) { - if(imports != null) { - this.imports = imports; - } - } - - @Override - public Set getFeatures() { - return features; - } - - private void setFeatures(Set features) { - if(features != null) { - this.features = features; - } - } - - @Override - public Set> getTypeDefinitions() { - return typeDefinitions; - } - - private void setTypeDefinitions(Set> typeDefinitions) { - if(typeDefinitions != null) { - this.typeDefinitions = typeDefinitions; - } - } - - @Override - public Set getNotifications() { - return notifications; - } - - private void setNotifications(Set notifications) { - if(notifications != null) { - this.notifications = notifications; - } - } - - @Override - public Set getAugmentations() { - return augmentations; - } - - private void setAugmentations(Set augmentations) { - if(augmentations != null) { - this.augmentations = augmentations; - } - } - - @Override - public Set getRpcs() { - return rpcs; - } - - private void setRpcs(Set rpcs) { - if(rpcs != null) { - this.rpcs = rpcs; - } - } - - @Override - public Set getDeviations() { - return deviations; - } - - private void setDeviations(Set deviations) { - if(deviations != null) { - this.deviations = deviations; - } - } - - @Override - public Set getChildNodes() { - return new HashSet(childNodes.values()); - } - - private void setChildNodes(Map childNodes) { - if(childNodes != null) { - this.childNodes = childNodes; - } - } - - @Override - public Set getGroupings() { - return groupings; - } - - private void setGroupings(Set groupings) { - if(groupings != null) { - this.groupings = groupings; - } - } - - @Override - public Set getUses() { - return uses; - } - - private void setUses(Set uses) { - if(uses != null) { - this.uses = uses; - } - } - - @Override - public List getExtensionSchemaNodes() { - return extensionSchemaNodes; - } - - private void setExtensionSchemaNodes(List extensionSchemaNodes) { - if(extensionSchemaNodes != null) { - this.extensionSchemaNodes = extensionSchemaNodes; - } - } - - @Override - public Set getIdentities() { - return identities; - } - - private void setIdentities(Set identities) { - if(identities != null) { - this.identities = identities; - } - } - - @Override - public DataSchemaNode getDataChildByName(QName name) { - return childNodes.get(name); - } - - @Override - public DataSchemaNode getDataChildByName(String name) { - DataSchemaNode result = null; - for (Map.Entry entry : childNodes.entrySet()) { - if (entry.getKey().getLocalName().equals(name)) { - result = entry.getValue(); - break; - } - } - return result; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((namespace == null) ? 0 : namespace.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((revision == null) ? 0 : revision.hashCode()); - result = prime * result + ((prefix == null) ? 0 : prefix.hashCode()); - result = prime * result + ((yangVersion == null) ? 0 : yangVersion.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - ModuleImpl other = (ModuleImpl) obj; - if (namespace == null) { - if (other.namespace != null) { - return false; - } - } else if (!namespace.equals(other.namespace)) { - return false; - } - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (revision == null) { - if (other.revision != null) { - return false; - } - } else if (!revision.equals(other.revision)) { - return false; - } - if (prefix == null) { - if (other.prefix != null) { - return false; - } - } else if (!prefix.equals(other.prefix)) { - return false; - } - if (yangVersion == null) { - if (other.yangVersion != null) { - return false; - } - } else if (!yangVersion.equals(other.yangVersion)) { - return false; - } - return true; - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder( - ModuleImpl.class.getSimpleName()); - sb.append("[\n"); - sb.append("name=" + name + ",\n"); - sb.append("namespace=" + namespace + ",\n"); - sb.append("revision=" + revision + ",\n"); - sb.append("prefix=" + prefix + ",\n"); - sb.append("yangVersion=" + yangVersion + ",\n"); - sb.append("description=" + description + ",\n"); - sb.append("reference=" + reference + ",\n"); - sb.append("organization=" + organization + ",\n"); - sb.append("contact=" + contact + ",\n"); - sb.append("childNodes=" + childNodes.values() + ",\n"); - sb.append("groupings=" + groupings + ",\n"); - sb.append("imports=" + imports + ",\n"); - sb.append("features=" + features + ",\n"); - sb.append("typeDefinitions=" + typeDefinitions + ",\n"); - sb.append("notifications=" + notifications + ",\n"); - sb.append("augmentations=" + augmentations + ",\n"); - sb.append("rpcs=" + rpcs + ",\n"); - sb.append("deviations=" + deviations + "\n"); - sb.append("uses=" + uses + "\n"); - sb.append("]"); - return sb.toString(); - } - } - - private ModuleImport createModuleImport(final String moduleName, - final Date revision, final String prefix) { - ModuleImport moduleImport = new ModuleImport() { - @Override - public String getModuleName() { - return moduleName; - } - - @Override - public Date getRevision() { - return revision; - } - - @Override - public String getPrefix() { - return prefix; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((moduleName == null) ? 0 : moduleName.hashCode()); - result = prime * result - + ((revision == null) ? 0 : revision.hashCode()); - result = prime * result - + ((prefix == null) ? 0 : prefix.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - ModuleImport other = (ModuleImport) obj; - if (getModuleName() == null) { - if (other.getModuleName() != null) { - return false; - } - } else if (!getModuleName().equals(other.getModuleName())) { - return false; - } - if (getRevision() == null) { - if (other.getRevision() != null) { - return false; - } - } else if (!getRevision().equals(other.getRevision())) { - return false; - } - if (getPrefix() == null) { - if (other.getPrefix() != null) { - return false; - } - } else if (!getPrefix().equals(other.getPrefix())) { - return false; - } - return true; - } - - @Override - public String toString() { - return "ModuleImport[moduleName=" + moduleName + ", revision=" - + revision + ", prefix=" + prefix + "]"; - } - }; - return moduleImport; - } - - /** - * Traverse through given addedChilds and add only direct module childs. - * Direct module child path size is 2 (1. module name, 2. child name). - * - * @param addedChilds - * @return map of children, where key is child QName and value is child - * itself - */ - private Map buildModuleChildNodes( - Map, DataSchemaNodeBuilder> addedChilds) { - final Map childNodes = new HashMap(); - for (Map.Entry, DataSchemaNodeBuilder> entry : addedChilds - .entrySet()) { - if (entry.getKey().size() == 2) { - DataSchemaNode node = entry.getValue().build(); - QName qname = entry.getValue().getQName(); - childNodes.put(qname, node); - } - } - return childNodes; - } - - /** - * Traverse through given addedGroupings and add only direct module - * groupings. Direct module grouping path size is 2 (1. module name, 2. - * grouping name). - * - * @param addedGroupings - * @return set of built GroupingDefinition objects - */ - private Set buildModuleGroupings( - Map, GroupingBuilder> addedGroupings) { - final Set groupings = new HashSet(); - for (Map.Entry, GroupingBuilder> entry : addedGroupings - .entrySet()) { - if (entry.getKey().size() == 2) { - groupings.add(entry.getValue().build()); - } - } - return groupings; - } - - /** - * Traverse through given addedRpcs and build RpcDefinition objects. - * - * @param addedRpcs - * @return set of built RpcDefinition objects - */ - private Set buildModuleRpcs( - Map, RpcDefinitionBuilder> addedRpcs) { - final Set rpcs = new HashSet(); - RpcDefinitionBuilder builder; - for (Map.Entry, RpcDefinitionBuilder> entry : addedRpcs - .entrySet()) { - builder = entry.getValue(); - RpcDefinition rpc = builder.build(); - rpcs.add(rpc); - } - return rpcs; - } - - /** - * Traverse through given addedTypedefs and add only direct module typedef - * statements. Direct module typedef path size is 2 (1. module name, 2. - * typedef name). - * - * @param addedTypedefs - * @return set of built module typedef statements - */ - private Set> buildModuleTypedefs( - Map, TypeDefinitionBuilder> addedTypedefs) { - Set> typedefs = new HashSet>(); - for (Map.Entry, TypeDefinitionBuilder> entry : addedTypedefs - .entrySet()) { - if (entry.getKey().size() == 2) { - TypeDefinition> node = entry - .getValue().build(); - typedefs.add(node); - } - } - return typedefs; - } - - /** - * Traverse through given addedUsesNodes and add only direct module uses - * nodes. Direct module uses node path size is 2 (1. module name, 2. uses - * name). - * - * @param addedUsesNodes - * @return set of built module uses nodes - */ - private Set buildUsesNodes( - Map, UsesNodeBuilder> addedUsesNodes) { - final Set usesNodeDefinitions = new HashSet(); - for (Map.Entry, UsesNodeBuilder> entry : addedUsesNodes - .entrySet()) { - if (entry.getKey().size() == 2) { - usesNodeDefinitions.add(entry.getValue().build()); - } - } - return usesNodeDefinitions; - } - - /** - * Traverse through given addedFeatures and add only direct module features. - * Direct module feature path size is 2 (1. module name, 2. feature name). - * - * @param addedFeatures - * @return set of built module features - */ - private Set buildModuleFeatures( - Map, FeatureBuilder> addedFeatures) { - Set features = new HashSet(); - for (Map.Entry, FeatureBuilder> entry : addedFeatures - .entrySet()) { - if (entry.getKey().size() == 2) { - features.add(entry.getValue().build()); - } - } - return features; - } - -} +/* + * 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.yang.model.parser.builder.impl; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.model.api.AugmentationSchema; +import org.opendaylight.controller.yang.model.api.DataSchemaNode; +import org.opendaylight.controller.yang.model.api.Deviation; +import org.opendaylight.controller.yang.model.api.ExtensionDefinition; +import org.opendaylight.controller.yang.model.api.FeatureDefinition; +import org.opendaylight.controller.yang.model.api.GroupingDefinition; +import org.opendaylight.controller.yang.model.api.IdentitySchemaNode; +import org.opendaylight.controller.yang.model.api.Module; +import org.opendaylight.controller.yang.model.api.ModuleImport; +import org.opendaylight.controller.yang.model.api.NotificationDefinition; +import org.opendaylight.controller.yang.model.api.RpcDefinition; +import org.opendaylight.controller.yang.model.api.TypeDefinition; +import org.opendaylight.controller.yang.model.api.UsesNode; +import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.Builder; +import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionAwareBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder; +import org.opendaylight.controller.yang.model.parser.util.YangParseException; + +/** + * This builder builds Module object. If this module is dependent on external + * module/modules, these dependencies must be resolved before module is built, + * otherwise result may not be valid. + */ +public class ModuleBuilder implements Builder { + + private final ModuleImpl instance; + private final String name; + private String prefix; + private Date revision; + + private final Set imports = new HashSet(); + private Set augmentations; + + /** + * All nodes, that can contain other nodes + */ + private final Map, Builder> moduleNodes = new HashMap, Builder>(); + + /** + * Holds all child (DataSchemaNode) nodes: anyxml, choice, case, container, + * list, leaf, leaf-list. + */ + private final Map, DataSchemaNodeBuilder> addedChilds = new HashMap, DataSchemaNodeBuilder>(); + + private final Map, GroupingBuilder> addedGroupings = new HashMap, GroupingBuilder>(); + private final Set addedAugments = new HashSet(); + private final Map, UsesNodeBuilder> addedUsesNodes = new HashMap, UsesNodeBuilder>(); + private final Map, RpcDefinitionBuilder> addedRpcs = new HashMap, RpcDefinitionBuilder>(); + private final Set addedNotifications = new HashSet(); + private final Set addedIdentities = new HashSet(); + private final Map, FeatureBuilder> addedFeatures = new HashMap, FeatureBuilder>(); + private final Map addedDeviations = new HashMap(); + private final Map, TypeDefinitionBuilder> addedTypedefs = new HashMap, TypeDefinitionBuilder>(); + private final List addedExtensions = new ArrayList(); + + private final Map, TypeAwareBuilder> dirtyNodes = new HashMap, TypeAwareBuilder>(); + + public ModuleBuilder(String name) { + this.name = name; + instance = new ModuleImpl(name); + } + + + /** + * Build new Module object based on this builder. + */ + @Override + public Module build() { + instance.setImports(imports); + + // TYPEDEFS + final Set> typedefs = buildModuleTypedefs(addedTypedefs); + instance.setTypeDefinitions(typedefs); + + // CHILD NODES + final Map childNodes = buildModuleChildNodes(addedChilds); + instance.setChildNodes(childNodes); + + // GROUPINGS + final Set groupings = buildModuleGroupings(addedGroupings); + instance.setGroupings(groupings); + + // USES + final Set usesDefinitions = buildUsesNodes(addedUsesNodes); + instance.setUses(usesDefinitions); + + // FEATURES + final Set features = buildModuleFeatures(addedFeatures); + instance.setFeatures(features); + + // NOTIFICATIONS + final Set notifications = new HashSet(); + for (NotificationBuilder entry : addedNotifications) { + notifications.add((NotificationDefinition) entry.build()); + } + instance.setNotifications(notifications); + + // AUGMENTATIONS + instance.setAugmentations(augmentations); + + // RPCs + final Set rpcs = buildModuleRpcs(addedRpcs); + instance.setRpcs(rpcs); + + // DEVIATIONS + final Set deviations = new HashSet(); + for (Map.Entry entry : addedDeviations + .entrySet()) { + deviations.add(entry.getValue().build()); + } + instance.setDeviations(deviations); + + // EXTENSIONS + final List extensions = new ArrayList(); + for(ExtensionBuilder b : addedExtensions) { + extensions.add(b.build()); + } + instance.setExtensionSchemaNodes(extensions); + + // IDENTITIES + final Set identities = new HashSet(); + for(IdentitySchemaNodeBuilder idBuilder : addedIdentities) { + identities.add(idBuilder.build()); + } + instance.setIdentities(identities); + + return instance; + } + + public Builder getNode(List path) { + return moduleNodes.get(path); + } + + public Map, TypeAwareBuilder> getDirtyNodes() { + return dirtyNodes; + } + + public Set getAddedAugments() { + return addedAugments; + } + + public Set getAddedIdentities() { + return addedIdentities; + } + + public String getName() { + return name; + } + + public String getPrefix() { + return prefix; + } + + public Date getRevision() { + return revision; + } + + public void addDirtyNode(List path) { + List dirtyNodePath = new ArrayList(path); + TypeAwareBuilder nodeBuilder = (TypeAwareBuilder) moduleNodes + .get(dirtyNodePath); + dirtyNodes.put(dirtyNodePath, nodeBuilder); + } + + public void setNamespace(URI namespace) { + instance.setNamespace(namespace); + } + + public void setRevision(Date revision) { + this.revision = revision; + instance.setRevision(revision); + } + + public void setPrefix(String prefix) { + this.prefix = prefix; + instance.setPrefix(prefix); + } + + public void setYangVersion(String yangVersion) { + instance.setYangVersion(yangVersion); + } + + public void setDescription(String description) { + instance.setDescription(description); + } + + public void setReference(String reference) { + instance.setReference(reference); + } + + public void setOrganization(String organization) { + instance.setOrganization(organization); + } + + public void setContact(String contact) { + instance.setContact(contact); + } + + public void setAugmentations(Set augmentations) { + this.augmentations = augmentations; + } + + public boolean addModuleImport(final String moduleName, + final Date revision, final String prefix) { + ModuleImport moduleImport = createModuleImport(moduleName, revision, + prefix); + return imports.add(moduleImport); + } + + public Set getModuleImports() { + return imports; + } + + public ExtensionBuilder addExtension(QName qname) { + return new ExtensionBuilder(qname); + } + + public ContainerSchemaNodeBuilder addContainerNode(QName containerName, + List parentPath) { + List pathToNode = new ArrayList(parentPath); + + ContainerSchemaNodeBuilder containerBuilder = new ContainerSchemaNodeBuilder( + containerName); + + ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes + .get(pathToNode); + if (parent != null) { + if(parent instanceof AugmentationSchemaBuilder) { + containerBuilder.setAugmenting(true); + } + parent.addChildNode(containerBuilder); + } + + pathToNode.add(containerName.getLocalName()); + moduleNodes.put(pathToNode, containerBuilder); + addedChilds.put(pathToNode, containerBuilder); + + return containerBuilder; + } + + public ListSchemaNodeBuilder addListNode(QName listName, + List parentPath) { + List pathToNode = new ArrayList(parentPath); + + ListSchemaNodeBuilder listBuilder = new ListSchemaNodeBuilder(listName); + + ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes + .get(pathToNode); + if (parent != null) { + if(parent instanceof AugmentationSchemaBuilder) { + listBuilder.setAugmenting(true); + } + parent.addChildNode(listBuilder); + } + + pathToNode.add(listName.getLocalName()); + moduleNodes.put(pathToNode, listBuilder); + addedChilds.put(pathToNode, listBuilder); + + return listBuilder; + } + + public LeafSchemaNodeBuilder addLeafNode(QName leafName, + List parentPath) { + List pathToNode = new ArrayList(parentPath); + + LeafSchemaNodeBuilder leafBuilder = new LeafSchemaNodeBuilder(leafName); + + ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes.get(pathToNode); + if (parent != null) { + if(parent instanceof AugmentationSchemaBuilder) { + leafBuilder.setAugmenting(true); + } + parent.addChildNode(leafBuilder); + } + + pathToNode.add(leafName.getLocalName()); + addedChilds.put(pathToNode, leafBuilder); + moduleNodes.put(pathToNode, leafBuilder); + + return leafBuilder; + } + + public LeafListSchemaNodeBuilder addLeafListNode(QName leafListName, + List parentPath) { + List pathToNode = new ArrayList(parentPath); + + LeafListSchemaNodeBuilder leafListBuilder = new LeafListSchemaNodeBuilder( + leafListName); + ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes.get(pathToNode); + if (parent != null) { + if(parent instanceof AugmentationSchemaBuilder) { + leafListBuilder.setAugmenting(true); + } + parent.addChildNode(leafListBuilder); + } + + pathToNode.add(leafListName.getLocalName()); + addedChilds.put(pathToNode, leafListBuilder); + moduleNodes.put(pathToNode, leafListBuilder); + + return leafListBuilder; + } + + public GroupingBuilder addGrouping(QName qname, List parentPath) { + List pathToGroup = new ArrayList(parentPath); + + GroupingBuilder builder = new GroupingBuilderImpl(qname); + ChildNodeBuilder parentNodeBuilder = (ChildNodeBuilder) moduleNodes.get(pathToGroup); + if (parentNodeBuilder != null) { + parentNodeBuilder.addGrouping(builder); + } + + pathToGroup.add(qname.getLocalName()); + moduleNodes.put(pathToGroup, builder); + addedGroupings.put(pathToGroup, builder); + + return builder; + } + + public AugmentationSchemaBuilder addAugment(String name, + List parentPath) { + List pathToAugment = new ArrayList(parentPath); + + AugmentationSchemaBuilder builder = new AugmentationSchemaBuilderImpl(name); + + // augment can only be in 'module' or 'uses' statement + UsesNodeBuilder parent = addedUsesNodes.get(pathToAugment); + if (parent != null) { + parent.addAugment(builder); + } + + pathToAugment.add(name); + moduleNodes.put(pathToAugment, builder); + addedAugments.add(builder); + + return builder; + } + + public UsesNodeBuilder addUsesNode(String groupingPathStr, + List parentPath) { + List pathToUses = new ArrayList(parentPath); + + UsesNodeBuilder usesBuilder = new UsesNodeBuilderImpl(groupingPathStr); + + ChildNodeBuilder parent = (ChildNodeBuilder) moduleNodes.get(pathToUses); + if (parent != null) { + parent.addUsesNode(usesBuilder); + } + + pathToUses.add(groupingPathStr); + addedUsesNodes.put(pathToUses, usesBuilder); + + return usesBuilder; + } + + public RpcDefinitionBuilder addRpc(QName qname, List parentPath) { + List pathToRpc = new ArrayList(parentPath); + + RpcDefinitionBuilder rpcBuilder = new RpcDefinitionBuilder(qname); + + pathToRpc.add(qname.getLocalName()); + addedRpcs.put(pathToRpc, rpcBuilder); + + QName inputQName = new QName(qname.getNamespace(), qname.getRevision(), + qname.getPrefix(), "input"); + ContainerSchemaNodeBuilder inputBuilder = new ContainerSchemaNodeBuilder(inputQName); + List pathToInput = new ArrayList(pathToRpc); + pathToInput.add("input"); + moduleNodes.put(pathToInput, inputBuilder); + rpcBuilder.setInput(inputBuilder); + + QName outputQName = new QName(qname.getNamespace(), + qname.getRevision(), qname.getPrefix(), "output"); + ContainerSchemaNodeBuilder outputBuilder = new ContainerSchemaNodeBuilder(outputQName); + List pathToOutput = new ArrayList(pathToRpc); + pathToOutput.add("output"); + moduleNodes.put(pathToOutput, outputBuilder); + rpcBuilder.setOutput(outputBuilder); + + return rpcBuilder; + } + + public NotificationBuilder addNotification(QName notificationName, + List parentPath) { + List pathToNotification = new ArrayList(parentPath); + + NotificationBuilder builder = new NotificationBuilder( + notificationName); + + pathToNotification.add(notificationName.getLocalName()); + moduleNodes.put(pathToNotification, builder); + addedNotifications.add(builder); + + return builder; + } + + public FeatureBuilder addFeature(QName featureName, List parentPath) { + List pathToFeature = new ArrayList(parentPath); + pathToFeature.add(featureName.getLocalName()); + + FeatureBuilder builder = new FeatureBuilder(featureName); + addedFeatures.put(pathToFeature, builder); + return builder; + } + + public TypedefBuilder addTypedef(QName typeDefName, List parentPath) { + List pathToType = new ArrayList(parentPath); + TypedefBuilder builder = new TypedefBuilder(typeDefName); + TypeDefinitionAwareBuilder parent = (TypeDefinitionAwareBuilder) moduleNodes.get(pathToType); + if (parent != null) { + parent.addTypedef(builder); + } + pathToType.add(typeDefName.getLocalName()); + addedTypedefs.put(pathToType, builder); + moduleNodes.put(pathToType, builder); + return builder; + } + + public Set getModuleTypedefs() { + Set typedefs = new HashSet(); + for (Map.Entry, TypeDefinitionBuilder> entry : addedTypedefs.entrySet()) { + if (entry.getKey().size() == 2) { + typedefs.add(entry.getValue()); + } + } + return typedefs; + } + + public void setType(TypeDefinition type, List parentPath) { + TypeAwareBuilder parent = (TypeAwareBuilder) moduleNodes.get(parentPath); + if(parent == null) { + throw new YangParseException("Failed to set type '"+ type.getQName().getLocalName() +"'. Parent node not found."); + } + parent.setType(type); + } + + public void addUnionType(List parentPath) { + TypeAwareBuilder parent = (TypeAwareBuilder) moduleNodes.get(parentPath); + UnionTypeBuilder union = new UnionTypeBuilder(); + parent.setType(union); + + List path = new ArrayList(parentPath); + path.add("union"); + + moduleNodes.put(path, union); + } + + public DeviationBuilder addDeviation(String targetPath) { + DeviationBuilder builder = new DeviationBuilder(targetPath); + addedDeviations.put(targetPath, builder); + return builder; + } + + public IdentitySchemaNodeBuilder addIdentity(QName qname) { + IdentitySchemaNodeBuilder builder = new IdentitySchemaNodeBuilder(qname); + addedIdentities.add(builder); + return builder; + } + + public void addConfiguration(boolean configuration, List parentPath) { + Builder builder = moduleNodes.get(parentPath); + if (builder instanceof DeviationBuilder) { + // skip + // TODO + } else { + DataSchemaNodeBuilder configBuilder = (DataSchemaNodeBuilder) moduleNodes.get(parentPath); + configBuilder.setConfiguration(configuration); + } + } + + public UnknownSchemaNodeBuilder addUnknownSchemaNode(QName qname, List parentPath) { + return new UnknownSchemaNodeBuilder(qname); + } + + + private class ModuleImpl implements Module { + private URI namespace; + private final String name; + private Date revision; + private String prefix; + private String yangVersion; + private String description; + private String reference; + private String organization; + private String contact; + private Set imports = Collections.emptySet(); + private Set features = Collections.emptySet(); + private Set> typeDefinitions = Collections.emptySet(); + private Set notifications = Collections.emptySet(); + private Set augmentations = Collections.emptySet(); + private Set rpcs = Collections.emptySet(); + private Set deviations = Collections.emptySet(); + private Map childNodes = Collections.emptyMap(); + private Set groupings = Collections.emptySet(); + private Set uses = Collections.emptySet(); + private List extensionNodes = Collections.emptyList(); + private Set identities = Collections.emptySet(); + + private ModuleImpl(String name) { + this.name = name; + } + + @Override + public URI getNamespace() { + return namespace; + } + + private void setNamespace(URI namespace) { + this.namespace = namespace; + } + + @Override + public String getName() { + return name; + } + + @Override + public Date getRevision() { + return revision; + } + + private void setRevision(Date revision) { + this.revision = revision; + } + + @Override + public String getPrefix() { + return prefix; + } + + private void setPrefix(String prefix) { + this.prefix = prefix; + } + + @Override + public String getYangVersion() { + return yangVersion; + } + + private void setYangVersion(String yangVersion) { + this.yangVersion = yangVersion; + } + + @Override + public String getDescription() { + return description; + } + + private void setDescription(String description) { + this.description = description; + } + + @Override + public String getReference() { + return reference; + } + + private void setReference(String reference) { + this.reference = reference; + } + + @Override + public String getOrganization() { + return organization; + } + + private void setOrganization(String organization) { + this.organization = organization; + } + + @Override + public String getContact() { + return contact; + } + + private void setContact(String contact) { + this.contact = contact; + } + + @Override + public Set getImports() { + return imports; + } + + private void setImports(Set imports) { + if(imports != null) { + this.imports = imports; + } + } + + @Override + public Set getFeatures() { + return features; + } + + private void setFeatures(Set features) { + if(features != null) { + this.features = features; + } + } + + @Override + public Set> getTypeDefinitions() { + return typeDefinitions; + } + + private void setTypeDefinitions(Set> typeDefinitions) { + if(typeDefinitions != null) { + this.typeDefinitions = typeDefinitions; + } + } + + @Override + public Set getNotifications() { + return notifications; + } + + private void setNotifications(Set notifications) { + if(notifications != null) { + this.notifications = notifications; + } + } + + @Override + public Set getAugmentations() { + return augmentations; + } + + private void setAugmentations(Set augmentations) { + if(augmentations != null) { + this.augmentations = augmentations; + } + } + + @Override + public Set getRpcs() { + return rpcs; + } + + private void setRpcs(Set rpcs) { + if(rpcs != null) { + this.rpcs = rpcs; + } + } + + @Override + public Set getDeviations() { + return deviations; + } + + private void setDeviations(Set deviations) { + if(deviations != null) { + this.deviations = deviations; + } + } + + @Override + public Set getChildNodes() { + return new HashSet(childNodes.values()); + } + + private void setChildNodes(Map childNodes) { + if(childNodes != null) { + this.childNodes = childNodes; + } + } + + @Override + public Set getGroupings() { + return groupings; + } + + private void setGroupings(Set groupings) { + if(groupings != null) { + this.groupings = groupings; + } + } + + @Override + public Set getUses() { + return uses; + } + + private void setUses(Set uses) { + if(uses != null) { + this.uses = uses; + } + } + + @Override + public List getExtensionSchemaNodes() { + return extensionNodes; + } + + private void setExtensionSchemaNodes(List extensionSchemaNodes) { + if(extensionSchemaNodes != null) { + this.extensionNodes = extensionSchemaNodes; + } + } + + @Override + public Set getIdentities() { + return identities; + } + + private void setIdentities(Set identities) { + if(identities != null) { + this.identities = identities; + } + } + + @Override + public DataSchemaNode getDataChildByName(QName name) { + return childNodes.get(name); + } + + @Override + public DataSchemaNode getDataChildByName(String name) { + DataSchemaNode result = null; + for (Map.Entry entry : childNodes.entrySet()) { + if (entry.getKey().getLocalName().equals(name)) { + result = entry.getValue(); + break; + } + } + return result; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((namespace == null) ? 0 : namespace.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((revision == null) ? 0 : revision.hashCode()); + result = prime * result + ((prefix == null) ? 0 : prefix.hashCode()); + result = prime * result + ((yangVersion == null) ? 0 : yangVersion.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ModuleImpl other = (ModuleImpl) obj; + if (namespace == null) { + if (other.namespace != null) { + return false; + } + } else if (!namespace.equals(other.namespace)) { + return false; + } + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + if (revision == null) { + if (other.revision != null) { + return false; + } + } else if (!revision.equals(other.revision)) { + return false; + } + if (prefix == null) { + if (other.prefix != null) { + return false; + } + } else if (!prefix.equals(other.prefix)) { + return false; + } + if (yangVersion == null) { + if (other.yangVersion != null) { + return false; + } + } else if (!yangVersion.equals(other.yangVersion)) { + return false; + } + return true; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder( + ModuleImpl.class.getSimpleName()); + sb.append("[\n"); + sb.append("name=" + name + ",\n"); + sb.append("namespace=" + namespace + ",\n"); + sb.append("revision=" + revision + ",\n"); + sb.append("prefix=" + prefix + ",\n"); + sb.append("yangVersion=" + yangVersion + ",\n"); + sb.append("description=" + description + ",\n"); + sb.append("reference=" + reference + ",\n"); + sb.append("organization=" + organization + ",\n"); + sb.append("contact=" + contact + ",\n"); + sb.append("childNodes=" + childNodes.values() + ",\n"); + sb.append("groupings=" + groupings + ",\n"); + sb.append("imports=" + imports + ",\n"); + sb.append("features=" + features + ",\n"); + sb.append("typeDefinitions=" + typeDefinitions + ",\n"); + sb.append("notifications=" + notifications + ",\n"); + sb.append("augmentations=" + augmentations + ",\n"); + sb.append("rpcs=" + rpcs + ",\n"); + sb.append("deviations=" + deviations + "\n"); + sb.append("uses=" + uses + "\n"); + sb.append("]"); + return sb.toString(); + } + } + + private ModuleImport createModuleImport(final String moduleName, + final Date revision, final String prefix) { + ModuleImport moduleImport = new ModuleImport() { + @Override + public String getModuleName() { + return moduleName; + } + + @Override + public Date getRevision() { + return revision; + } + + @Override + public String getPrefix() { + return prefix; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((moduleName == null) ? 0 : moduleName.hashCode()); + result = prime * result + + ((revision == null) ? 0 : revision.hashCode()); + result = prime * result + + ((prefix == null) ? 0 : prefix.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + ModuleImport other = (ModuleImport) obj; + if (getModuleName() == null) { + if (other.getModuleName() != null) { + return false; + } + } else if (!getModuleName().equals(other.getModuleName())) { + return false; + } + if (getRevision() == null) { + if (other.getRevision() != null) { + return false; + } + } else if (!getRevision().equals(other.getRevision())) { + return false; + } + if (getPrefix() == null) { + if (other.getPrefix() != null) { + return false; + } + } else if (!getPrefix().equals(other.getPrefix())) { + return false; + } + return true; + } + + @Override + public String toString() { + return "ModuleImport[moduleName=" + moduleName + ", revision=" + + revision + ", prefix=" + prefix + "]"; + } + }; + return moduleImport; + } + + /** + * Traverse through given addedChilds and add only direct module childs. + * Direct module child path size is 2 (1. module name, 2. child name). + * + * @param addedChilds + * @return map of children, where key is child QName and value is child + * itself + */ + private Map buildModuleChildNodes( + Map, DataSchemaNodeBuilder> addedChilds) { + final Map childNodes = new HashMap(); + for (Map.Entry, DataSchemaNodeBuilder> entry : addedChilds.entrySet()) { + List path = entry.getKey(); + DataSchemaNodeBuilder child = entry.getValue(); + if (path.size() == 2) { + DataSchemaNode node = child.build(); + QName qname = node.getQName(); + childNodes.put(qname, node); + } + } + return childNodes; + } + + /** + * Traverse through given addedGroupings and add only direct module + * groupings. Direct module grouping path size is 2 (1. module name, 2. + * grouping name). + * + * @param addedGroupings + * @return set of built GroupingDefinition objects + */ + private Set buildModuleGroupings( + Map, GroupingBuilder> addedGroupings) { + final Set groupings = new HashSet(); + for (Map.Entry, GroupingBuilder> entry : addedGroupings + .entrySet()) { + if (entry.getKey().size() == 2) { + groupings.add(entry.getValue().build()); + } + } + return groupings; + } + + /** + * Traverse through given addedRpcs and build RpcDefinition objects. + * + * @param addedRpcs + * @return set of built RpcDefinition objects + */ + private Set buildModuleRpcs( + Map, RpcDefinitionBuilder> addedRpcs) { + final Set rpcs = new HashSet(); + RpcDefinitionBuilder builder; + for (Map.Entry, RpcDefinitionBuilder> entry : addedRpcs + .entrySet()) { + builder = entry.getValue(); + RpcDefinition rpc = builder.build(); + rpcs.add(rpc); + } + return rpcs; + } + + /** + * Traverse through given addedTypedefs and add only direct module typedef + * statements. Direct module typedef path size is 2 (1. module name, 2. + * typedef name). + * + * @param addedTypedefs + * @return set of built module typedef statements + */ + private Set> buildModuleTypedefs( + Map, TypeDefinitionBuilder> addedTypedefs) { + Set> typedefs = new HashSet>(); + for (Map.Entry, TypeDefinitionBuilder> entry : addedTypedefs.entrySet()) { + List key = entry.getKey(); + TypeDefinitionBuilder typedefBuilder = entry.getValue(); + if (key.size() == 2) { + TypeDefinition> node = typedefBuilder.build(); + typedefs.add(node); + } + } + return typedefs; + } + + /** + * Traverse through given addedUsesNodes and add only direct module uses + * nodes. Direct module uses node path size is 2 (1. module name, 2. uses + * name). + * + * @param addedUsesNodes + * @return set of built module uses nodes + */ + private Set buildUsesNodes( + Map, UsesNodeBuilder> addedUsesNodes) { + final Set usesNodeDefinitions = new HashSet(); + for (Map.Entry, UsesNodeBuilder> entry : addedUsesNodes + .entrySet()) { + if (entry.getKey().size() == 2) { + usesNodeDefinitions.add(entry.getValue().build()); + } + } + return usesNodeDefinitions; + } + + /** + * Traverse through given addedFeatures and add only direct module features. + * Direct module feature path size is 2 (1. module name, 2. feature name). + * + * @param addedFeatures + * @return set of built module features + */ + private Set buildModuleFeatures( + Map, FeatureBuilder> addedFeatures) { + Set features = new HashSet(); + for (Map.Entry, FeatureBuilder> entry : addedFeatures + .entrySet()) { + if (entry.getKey().size() == 2) { + features.add(entry.getValue().build()); + } + } + return features; + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/TypedefBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/TypedefBuilder.java index f8020b1524..64df8c265a 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/TypedefBuilder.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/TypedefBuilder.java @@ -7,6 +7,7 @@ */ package org.opendaylight.controller.yang.model.parser.builder.impl; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -15,18 +16,25 @@ import org.opendaylight.controller.yang.model.api.SchemaPath; import org.opendaylight.controller.yang.model.api.Status; import org.opendaylight.controller.yang.model.api.TypeDefinition; import org.opendaylight.controller.yang.model.api.UnknownSchemaNode; -import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder; +import org.opendaylight.controller.yang.model.api.type.LengthConstraint; +import org.opendaylight.controller.yang.model.api.type.PatternConstraint; +import org.opendaylight.controller.yang.model.api.type.RangeConstraint; +import org.opendaylight.controller.yang.model.parser.builder.api.AbstractTypeAwareBuilder; import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder; +import org.opendaylight.controller.yang.model.parser.util.YangParseException; +import org.opendaylight.controller.yang.model.util.ExtendedType; import org.opendaylight.controller.yang.model.util.UnknownType; -import org.opendaylight.controller.yang.model.util.YangTypesConverter; - -public class TypedefBuilder implements TypeDefinitionBuilder, - SchemaNodeBuilder, TypeAwareBuilder { +public class TypedefBuilder extends AbstractTypeAwareBuilder implements + TypeDefinitionBuilder { private final QName qname; private SchemaPath schemaPath; - private TypeDefinition baseType; + + private final List addedUnknownNodes = new ArrayList(); + private List ranges = Collections.emptyList(); + private List lengths = Collections.emptyList(); + private List patterns = Collections.emptyList(); + private Integer fractionDigits = null; private String description; private String reference; @@ -34,36 +42,41 @@ public class TypedefBuilder implements TypeDefinitionBuilder, private String units; private Object defaultValue; - TypedefBuilder(QName qname) { + public TypedefBuilder(QName qname) { this.qname = qname; } @Override public TypeDefinition> build() { - final TypeDefinition type = YangTypesConverter - .javaTypeForBaseYangType(qname); - if (type != null) { - return type; + TypeDefinition result = null; + ExtendedType.Builder typeBuilder = null; + if ((type == null || type instanceof UnknownType) && typedef == null) { + throw new YangParseException("Unresolved type: '" + + qname.getLocalName() + "'."); + } + if (type == null || type instanceof UnknownType) { + typeBuilder = new ExtendedType.Builder(qname, typedef.build(), + description, reference); } else { - if (baseType != null) { - // typedef - TypeDefinitionImpl instance = new TypeDefinitionImpl(qname); - instance.setDescription(description); - instance.setReference(reference); - instance.setStatus(status); - instance.setPath(schemaPath); - instance.setBaseType(baseType); - instance.setUnits(units); - instance.setDefaultValue(defaultValue); - return instance; - } else { - // type - final UnknownType.Builder unknownBuilder = new UnknownType.Builder( - qname, description, reference); - unknownBuilder.status(status); - return unknownBuilder.build(); - } + typeBuilder = new ExtendedType.Builder(qname, type, description, + reference); + } + typeBuilder.status(status); + typeBuilder.units(units); + typeBuilder.defaultValue(defaultValue); + + typeBuilder.ranges(ranges); + typeBuilder.lengths(lengths); + typeBuilder.patterns(patterns); + + // UNKNOWN NODES + final List unknownNodes = new ArrayList(); + for (UnknownSchemaNodeBuilder b : addedUnknownNodes) { + unknownNodes.add(b.build()); } + typeBuilder.unknownSchemaNodes(unknownNodes); + result = typeBuilder.build(); + return result; } @Override @@ -71,21 +84,41 @@ public class TypedefBuilder implements TypeDefinitionBuilder, return qname; } + @Override + public SchemaPath getPath() { + return schemaPath; + } + @Override public void setPath(final SchemaPath schemaPath) { this.schemaPath = schemaPath; } + @Override + public String getDescription() { + return description; + } + @Override public void setDescription(final String description) { this.description = description; } + @Override + public String getReference() { + return reference; + } + @Override public void setReference(final String reference) { this.reference = reference; } + @Override + public Status getStatus() { + return status; + } + @Override public void setStatus(final Status status) { if (status != null) { @@ -93,221 +126,93 @@ public class TypedefBuilder implements TypeDefinitionBuilder, } } + @Override + public String getUnits() { + return units; + } + @Override public void setUnits(String units) { this.units = units; } @Override - public void setDefaultValue(Object defaultValue) { - this.defaultValue = defaultValue; + public Object getDefaultValue() { + return defaultValue; } @Override - public TypeDefinition getType() { - return baseType; + public void setDefaultValue(Object defaultValue) { + this.defaultValue = defaultValue; } @Override - public void setType(TypeDefinition baseType) { - this.baseType = baseType; + public List getUnknownNodes() { + return addedUnknownNodes; } @Override - public TypeDefinition getBaseType() { - return baseType; + public void addUnknownSchemaNode(UnknownSchemaNodeBuilder unknownNode) { + addedUnknownNodes.add(unknownNode); } @Override - public void addUnknownSchemaNode(UnknownSchemaNodeBuilder unknownSchemaNodeBuilder) { - // TODO + public List getRanges() { + return ranges; } - private static class TypeDefinitionImpl> - implements TypeDefinition { - - private final QName qname; - private SchemaPath path; - private String description; - private String reference; - private Status status = Status.CURRENT; - private Object defaultValue; - private T baseType; - private String units; - private List unknownSchemaNodes = Collections.emptyList(); - - private TypeDefinitionImpl(QName qname) { - this.qname = qname; - } - - @Override - public QName getQName() { - return qname; - } - - @Override - public SchemaPath getPath() { - return path; - } - - private void setPath(SchemaPath path) { - this.path = path; - } - - @Override - public String getDescription() { - return description; - } - - private void setDescription(String description) { - this.description = description; - } - - @Override - public String getReference() { - return reference; - } - - private void setReference(String reference) { - this.reference = reference; - } - - @Override - public Status getStatus() { - return status; - } - - private void setStatus(Status status) { - this.status = status; - } - - @Override - public T getBaseType() { - return baseType; - } - - private void setBaseType(T type) { - this.baseType = type; - } - - @Override - public String getUnits() { - return units; + @Override + public void setRanges(List ranges) { + if (ranges != null) { + this.ranges = ranges; } + } - private void setUnits(String units) { - this.units = units; - } + @Override + public List getLengths() { + return lengths; + } - @Override - public Object getDefaultValue() { - return defaultValue; + @Override + public void setLengths(List lengths) { + if (lengths != null) { + this.lengths = lengths; } + } - private void setDefaultValue(Object defaultValue) { - this.defaultValue = defaultValue; - } + @Override + public List getPatterns() { + return patterns; + } - @Override - public List getUnknownSchemaNodes() { - return unknownSchemaNodes; + @Override + public void setPatterns(List patterns) { + if (patterns != null) { + this.patterns = patterns; } + } - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((qname == null) ? 0 : qname.hashCode()); - result = prime * result + ((path == null) ? 0 : path.hashCode()); - result = prime * result - + ((description == null) ? 0 : description.hashCode()); - result = prime * result - + ((reference == null) ? 0 : reference.hashCode()); - result = prime * result - + ((status == null) ? 0 : status.hashCode()); - result = prime * result - + ((baseType == null) ? 0 : baseType.hashCode()); - result = prime * result + ((units == null) ? 0 : units.hashCode()); - return result; - } + @Override + public Integer getFractionDigits() { + return fractionDigits; + } - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - TypeDefinitionImpl other = (TypeDefinitionImpl) obj; - if (qname == null) { - if (other.qname != null) { - return false; - } - } else if (!qname.equals(other.qname)) { - return false; - } - if (path == null) { - if (other.path != null) { - return false; - } - } else if (!path.equals(other.path)) { - return false; - } - if (description == null) { - if (other.description != null) { - return false; - } - } else if (!description.equals(other.description)) { - return false; - } - if (reference == null) { - if (other.reference != null) { - return false; - } - } else if (!reference.equals(other.reference)) { - return false; - } - if (status == null) { - if (other.status != null) { - return false; - } - } else if (!status.equals(other.status)) { - return false; - } - if (baseType == null) { - if (other.baseType != null) { - return false; - } - } else if (!baseType.equals(other.baseType)) { - return false; - } - if (units == null) { - if (other.units != null) { - return false; - } - } else if (!units.equals(other.units)) { - return false; - } - return true; - } + @Override + public void setFractionDigits(Integer fractionDigits) { + this.fractionDigits = fractionDigits; + } - @Override - public String toString() { - final StringBuilder sb = new StringBuilder( - TypeDefinitionImpl.class.getSimpleName()); - sb.append("["); - sb.append("qname=" + qname); - sb.append(", path=" + path); - sb.append(", description=" + description); - sb.append(", reference=" + reference); - sb.append(", status=" + status); - sb.append(", baseType=" + baseType + "]"); - return sb.toString(); + @Override + public String toString() { + String result = "TypedefBuilder[" + qname.getLocalName(); + result += ", type="; + if (type == null) { + result += typedef; + } else { + result += type; } + result += "]"; + return result; } } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/UnionTypeBuilder.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/UnionTypeBuilder.java index 4e0cb506f2..697fb399b0 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/UnionTypeBuilder.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/builder/impl/UnionTypeBuilder.java @@ -8,17 +8,29 @@ package org.opendaylight.controller.yang.model.parser.builder.impl; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.model.api.SchemaPath; +import org.opendaylight.controller.yang.model.api.Status; import org.opendaylight.controller.yang.model.api.TypeDefinition; +import org.opendaylight.controller.yang.model.api.type.LengthConstraint; +import org.opendaylight.controller.yang.model.api.type.PatternConstraint; +import org.opendaylight.controller.yang.model.api.type.RangeConstraint; +import org.opendaylight.controller.yang.model.parser.builder.api.AbstractTypeAwareBuilder; import org.opendaylight.controller.yang.model.parser.builder.api.Builder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder; import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder; import org.opendaylight.controller.yang.model.util.UnionType; -public class UnionTypeBuilder implements TypeAwareBuilder, TypeDefinitionBuilder, Builder { - +/** + * Builder for YANG union type. User can add type to this union as + * TypeDefinition object (resolved type) or in form of TypeDefinitionBuilder. + * When build is called, types in builder form will be transformed to + * TypeDefinition objects and add to resolved types. + */ +public class UnionTypeBuilder extends AbstractTypeAwareBuilder implements + TypeDefinitionBuilder, Builder { private final List> types; private final List typedefs; private final UnionType instance; @@ -35,7 +47,16 @@ public class UnionTypeBuilder implements TypeAwareBuilder, TypeDefinitionBuilder @Override public TypeDefinition getType() { - return instance; + return null; + } + + public List getTypedefs() { + return Collections.unmodifiableList(typedefs); + } + + @Override + public TypeDefinitionBuilder getTypedef() { + return null; } @Override @@ -43,18 +64,45 @@ public class UnionTypeBuilder implements TypeAwareBuilder, TypeDefinitionBuilder types.add(type); } - public void addType(TypeDefinitionBuilder tdb) { + @Override + public void setType(TypeDefinitionBuilder tdb) { typedefs.add(tdb); } @Override public UnionType build() { - for(TypeDefinitionBuilder tdb : typedefs) { + for (TypeDefinitionBuilder tdb : typedefs) { types.add(tdb.build()); } return instance; } + @Override + public void setPath(SchemaPath schemaPath) { + // TODO Auto-generated method stub + } + + @Override + public void setDescription(String description) { + // TODO Auto-generated method stub + } + + @Override + public void setReference(String reference) { + // TODO Auto-generated method stub + } + + @Override + public void setStatus(Status status) { + // TODO Auto-generated method stub + } + + @Override + public void addUnknownSchemaNode( + UnknownSchemaNodeBuilder unknownSchemaNodeBuilder) { + // TODO Auto-generated method stub + } + @Override public QName getQName() { // TODO Auto-generated method stub @@ -62,21 +110,108 @@ public class UnionTypeBuilder implements TypeAwareBuilder, TypeDefinitionBuilder } @Override - public TypeDefinition getBaseType() { + public SchemaPath getPath() { // TODO Auto-generated method stub return null; } @Override - public void setUnits(String units) { + public String getDescription() { + // TODO Auto-generated method stub + return null; + } + + @Override + public String getReference() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Status getStatus() { + // TODO Auto-generated method stub + return null; + } + + @Override + public List getRanges() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setRanges(List ranges) { + // TODO Auto-generated method stub + } + + @Override + public List getLengths() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setLengths(List lengths) { + // TODO Auto-generated method stub + } + + @Override + public List getPatterns() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setPatterns(List patterns) { + // TODO Auto-generated method stub + } + + @Override + public Integer getFractionDigits() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setFractionDigits(Integer fractionDigits) { // TODO Auto-generated method stub + } + @Override + public List getUnknownNodes() { + // TODO Auto-generated method stub + return null; + } + + @Override + public Object getDefaultValue() { + // TODO Auto-generated method stub + return null; } @Override public void setDefaultValue(Object defaultValue) { // TODO Auto-generated method stub + } + + @Override + public String getUnits() { + // TODO Auto-generated method stub + return null; + } + @Override + public void setUnits(String units) { + // TODO Auto-generated method stub + } + + @Override + public String toString() { + String result = "UnionTypeBuilder["; + result += ", types=" + types; + result += ", typedefs=" + typedefs; + result += "]"; + return result; } } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserImpl.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserImpl.java index 5cc9f8e4aa..27a65c1168 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserImpl.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserImpl.java @@ -1,812 +1,788 @@ -/* - * 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.yang.model.parser.impl; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; - -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.ParseTreeWalker; -import org.opendaylight.controller.antlrv4.code.gen.YangLexer; -import org.opendaylight.controller.antlrv4.code.gen.YangParser; -import org.opendaylight.controller.yang.common.QName; -import org.opendaylight.controller.yang.model.api.AugmentationSchema; -import org.opendaylight.controller.yang.model.api.DataSchemaNode; -import org.opendaylight.controller.yang.model.api.ExtensionDefinition; -import org.opendaylight.controller.yang.model.api.Module; -import org.opendaylight.controller.yang.model.api.ModuleImport; -import org.opendaylight.controller.yang.model.api.NotificationDefinition; -import org.opendaylight.controller.yang.model.api.RpcDefinition; -import org.opendaylight.controller.yang.model.api.SchemaContext; -import org.opendaylight.controller.yang.model.api.SchemaPath; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit; -import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.LengthConstraint; -import org.opendaylight.controller.yang.model.api.type.PatternConstraint; -import org.opendaylight.controller.yang.model.api.type.RangeConstraint; -import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition; -import org.opendaylight.controller.yang.model.parser.api.YangModelParser; -import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder; -import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder; -import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder; -import org.opendaylight.controller.yang.model.util.BaseConstraints; -import org.opendaylight.controller.yang.model.util.BinaryType; -import org.opendaylight.controller.yang.model.util.BitsType; -import org.opendaylight.controller.yang.model.util.StringType; -import org.opendaylight.controller.yang.model.util.UnknownType; -import org.opendaylight.controller.yang.model.util.YangTypesConverter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class YangModelParserImpl implements YangModelParser { - - private static final Logger logger = LoggerFactory - .getLogger(YangModelParserImpl.class); - - @Override - public Module parseYangModel(String yangFile) { - final Map> modules = resolveModuleBuildersFromStreams(yangFile); - Set result = build(modules); - return result.iterator().next(); - } - - @Override - public Set parseYangModels(String... yangFiles) { - final Map> modules = resolveModuleBuildersFromStreams(yangFiles); - Set result = build(modules); - return result; - } - - @Override - public Set parseYangModelsFromStreams( - InputStream... yangModelStreams) { - final Map> modules = resolveModuleBuildersFromStreams(yangModelStreams); - Set result = build(modules); - return result; - } - - @Override - public SchemaContext resolveSchemaContext(Set modules) { - return new SchemaContextImpl(modules); - } - - private Map> resolveModuleBuildersFromStreams( - String... yangFiles) { - InputStream[] streams = new InputStream[yangFiles.length]; - for (int i = 0; i < yangFiles.length; i++) { - final String yangFileName = yangFiles[i]; - final File yangFile = new File(yangFileName); - FileInputStream inStream = null; - try { - inStream = new FileInputStream(yangFile); - } catch (FileNotFoundException e) { - logger.warn("Exception while reading yang stream: " + inStream, - e); - } - streams[i] = inStream; - } - return resolveModuleBuildersFromStreams(streams); - } - - private Map> resolveModuleBuildersFromStreams( - InputStream... yangFiles) { - final Map> modules = new HashMap>(); - final ParseTreeWalker walker = new ParseTreeWalker(); - final List trees = parseStreams(yangFiles); - final ModuleBuilder[] builders = new ModuleBuilder[trees.size()]; - - for (int i = 0; i < trees.size(); i++) { - final YangModelParserListenerImpl yangModelParser = new YangModelParserListenerImpl(); - walker.walk(yangModelParser, trees.get(i)); - builders[i] = yangModelParser.getModuleBuilder(); - } - - for (ModuleBuilder builder : builders) { - final String builderName = builder.getName(); - Date builderRevision = builder.getRevision(); - if (builderRevision == null) { - builderRevision = createEpochTime(); - } - TreeMap builderByRevision = modules - .get(builderName); - if (builderByRevision == null) { - builderByRevision = new TreeMap(); - } - builderByRevision.put(builderRevision, builder); - modules.put(builderName, builderByRevision); - } - return modules; - } - - private List parseStreams(InputStream... yangStreams) { - List trees = new ArrayList(); - for (InputStream yangStream : yangStreams) { - trees.add(parseStream(yangStream)); - } - return trees; - } - - private ParseTree parseStream(InputStream yangStream) { - ParseTree result = null; - try { - final ANTLRInputStream input = new ANTLRInputStream(yangStream); - final YangLexer lexer = new YangLexer(input); - final CommonTokenStream tokens = new CommonTokenStream(lexer); - final YangParser parser = new YangParser(tokens); - result = parser.yang(); - } catch (IOException e) { - logger.warn("Exception while reading yang file: " + yangStream, e); - } - return result; - } - - private Set build(Map> modules) { - // first validate - for (Map.Entry> entry : modules - .entrySet()) { - for (Map.Entry childEntry : entry.getValue() - .entrySet()) { - ModuleBuilder moduleBuilder = childEntry.getValue(); - validateBuilder(modules, moduleBuilder); - } - } - // then build - final Set result = new HashSet(); - for (Map.Entry> entry : modules - .entrySet()) { - final Map modulesByRevision = new HashMap(); - for (Map.Entry childEntry : entry.getValue() - .entrySet()) { - ModuleBuilder moduleBuilder = childEntry.getValue(); - modulesByRevision.put(childEntry.getKey(), - moduleBuilder.build()); - result.add(moduleBuilder.build()); - } - } - - return result; - } - - private void validateBuilder( - Map> modules, - ModuleBuilder builder) { - resolveTypedefs(modules, builder); - resolveAugments(modules, builder); - resolveIdentities(modules, builder); - } - - /** - * Search for dirty nodes (node which contains UnknownType) and resolve - * unknown types. - * - * @param modules - * all available modules - * @param module - * current module - */ - private void resolveTypedefs( - Map> modules, - ModuleBuilder module) { - Map, TypeAwareBuilder> dirtyNodes = module.getDirtyNodes(); - if (dirtyNodes.size() == 0) { - return; - } else { - for (Map.Entry, TypeAwareBuilder> entry : dirtyNodes - .entrySet()) { - TypeAwareBuilder typeToResolve = entry.getValue(); - - if (typeToResolve instanceof UnionTypeBuilder) { - resolveUnionTypeBuilder(modules, module, - (UnionTypeBuilder) typeToResolve); - } else { - UnknownType ut = (UnknownType) typeToResolve.getType(); - TypeDefinition resolvedType = findTargetType(ut, - modules, module); - typeToResolve.setType(resolvedType); - } - } - } - } - - private UnionTypeBuilder resolveUnionTypeBuilder( - Map> modules, - ModuleBuilder builder, UnionTypeBuilder unionTypeBuilderToResolve) { - List> resolvedTypes = new ArrayList>(); - List> typesToRemove = new ArrayList>(); - - for (TypeDefinition td : unionTypeBuilderToResolve.getTypes()) { - if (td instanceof UnknownType) { - TypeDefinition resolvedType = findTargetType( - (UnknownType) td, modules, builder); - resolvedTypes.add(resolvedType); - typesToRemove.add(td); - } - } - - List> unionTypeBuilderTypes = unionTypeBuilderToResolve - .getTypes(); - unionTypeBuilderTypes.addAll(resolvedTypes); - unionTypeBuilderTypes.removeAll(typesToRemove); - - return unionTypeBuilderToResolve; - } - - private TypeDefinition findTargetType(UnknownType ut, - Map> modules, - ModuleBuilder builder) { - - Map foundedTypeDefinitionBuilder = findTypeDefinitionBuilderWithConstraints( - modules, ut, builder); - TypeDefinitionBuilder targetType = foundedTypeDefinitionBuilder - .entrySet().iterator().next().getKey(); - TypeConstraints constraints = foundedTypeDefinitionBuilder.entrySet() - .iterator().next().getValue(); - - TypeDefinition targetTypeBaseType = targetType.getBaseType(); - - // RANGE - List ranges = ut.getRangeStatements(); - resolveRanges(ranges, targetType, modules, builder); - // LENGTH - List lengths = ut.getLengthStatements(); - resolveLengths(lengths, targetType, modules, builder); - // PATTERN - List patterns = ut.getPatterns(); - // Fraction Digits - Integer fractionDigits = ut.getFractionDigits(); - - targetTypeBaseType = mergeConstraints(targetTypeBaseType, constraints, ranges, lengths, - patterns, fractionDigits); - - return targetTypeBaseType; - } - - /** - * Merge curent constraints with founded type constraints - * - * @param targetTypeBaseType - * @param constraints - * @param ranges - * @param lengths - * @param patterns - * @param fractionDigits - */ - private TypeDefinition mergeConstraints(TypeDefinition targetTypeBaseType, - TypeConstraints constraints, List ranges, - List lengths, List patterns, - Integer fractionDigits) { - String targetTypeBaseTypeName = targetTypeBaseType.getQName() - .getLocalName(); - // enumeration, leafref and identityref omitted because they have no - // restrictions - if (targetTypeBaseType instanceof DecimalTypeDefinition) { - List fullRanges = new ArrayList(); - fullRanges.addAll(constraints.getRanges()); - fullRanges.addAll(ranges); - Integer fd = fractionDigits == null ? constraints - .getFractionDigits() : fractionDigits; - targetTypeBaseType = YangTypesConverter - .javaTypeForBaseYangDecimal64Type(fullRanges, fd); - } else if (targetTypeBaseType instanceof IntegerTypeDefinition) { - List fullRanges = new ArrayList(); - fullRanges.addAll(constraints.getRanges()); - fullRanges.addAll(ranges); - if (targetTypeBaseTypeName.startsWith("int")) { - targetTypeBaseType = YangTypesConverter - .javaTypeForBaseYangSignedIntegerType( - targetTypeBaseTypeName, fullRanges); - } else { - targetTypeBaseType = YangTypesConverter - .javaTypeForBaseYangUnsignedIntegerType( - targetTypeBaseTypeName, fullRanges); - } - } else if (targetTypeBaseType instanceof StringTypeDefinition) { - List fullLengths = new ArrayList(); - fullLengths.addAll(constraints.getLengths()); - fullLengths.addAll(lengths); - List fullPatterns = new ArrayList(); - fullPatterns.addAll(constraints.getPatterns()); - fullPatterns.addAll(patterns); - targetTypeBaseType = new StringType(fullLengths, fullPatterns); - } else if (targetTypeBaseType instanceof BitsTypeDefinition) { - BitsTypeDefinition bitsType = (BitsTypeDefinition) targetTypeBaseType; - List bits = bitsType.getBits(); - targetTypeBaseType = new BitsType(bits); - } else if (targetTypeBaseType instanceof BinaryTypeDefinition) { - targetTypeBaseType = new BinaryType(null, lengths, null); - } - return targetTypeBaseType; - } - - private TypeDefinitionBuilder findTypeDefinitionBuilder( - Map> modules, - UnknownType unknownType, ModuleBuilder builder) { - Map result = findTypeDefinitionBuilderWithConstraints( - modules, unknownType, builder); - return result.entrySet().iterator().next().getKey(); - } - - private Map findTypeDefinitionBuilderWithConstraints( - Map> modules, - UnknownType unknownType, ModuleBuilder builder) { - return findTypeDefinitionBuilderWithConstraints(new TypeConstraints(), - modules, unknownType, builder); - } - - /** - * Traverse through all referenced types chain until base YANG type is - * founded. - * - * @param constraints - * current type constraints - * @param modules - * all available modules - * @param unknownType - * unknown type - * @param builder - * current module - * @return map, where key is type referenced and value is its constraints - */ - private Map findTypeDefinitionBuilderWithConstraints( - TypeConstraints constraints, - Map> modules, - UnknownType unknownType, ModuleBuilder builder) { - Map result = new HashMap(); - QName unknownTypeQName = unknownType.getQName(); - String unknownTypeName = unknownTypeQName.getLocalName(); - String unknownTypePrefix = unknownTypeQName.getPrefix(); - - // search for module which contains referenced typedef - ModuleBuilder dependentModuleBuilder; - if (unknownTypePrefix.equals(builder.getPrefix())) { - dependentModuleBuilder = builder; - } else { - dependentModuleBuilder = findDependentModule(modules, builder, - unknownTypePrefix); - } - - // pull all typedef statements from dependent module... - final Set typedefs = dependentModuleBuilder - .getModuleTypedefs(); - // and search for referenced typedef - TypeDefinitionBuilder lookedUpBuilder = null; - for (TypeDefinitionBuilder tdb : typedefs) { - QName qname = tdb.getQName(); - if (qname.getLocalName().equals(unknownTypeName)) { - lookedUpBuilder = tdb; - break; - } - } - - // if referenced type is UnknownType again, search recursively with - // current constraints - TypeDefinition referencedType = lookedUpBuilder.getBaseType(); - if (referencedType instanceof UnknownType) { - UnknownType unknown = (UnknownType) lookedUpBuilder.getBaseType(); - - final List ranges = unknown.getRangeStatements(); - constraints.addRanges(ranges); - final List lengths = unknown - .getLengthStatements(); - constraints.addLengths(lengths); - final List patterns = unknown.getPatterns(); - constraints.addPatterns(patterns); - return findTypeDefinitionBuilderWithConstraints(constraints, - modules, unknown, dependentModuleBuilder); - } else { - // pull restriction from this base type and add them to - // 'constraints' - if (referencedType instanceof DecimalTypeDefinition) { - constraints.addRanges(((DecimalTypeDefinition) referencedType) - .getRangeStatements()); - constraints - .setFractionDigits(((DecimalTypeDefinition) referencedType) - .getFractionDigits()); - } else if (referencedType instanceof IntegerTypeDefinition) { - constraints.addRanges(((IntegerTypeDefinition) referencedType) - .getRangeStatements()); - } else if (referencedType instanceof StringTypeDefinition) { - constraints.addPatterns(((StringTypeDefinition) referencedType) - .getPatterns()); - } else if (referencedType instanceof BinaryTypeDefinition) { - constraints.addLengths(((BinaryTypeDefinition) referencedType) - .getLengthConstraints()); - } - result.put(lookedUpBuilder, constraints); - return result; - } - } - - /** - * Go through all augmentation definitions and resolve them. This means find - * referenced node and add child nodes to it. - * - * @param modules - * all available modules - * @param module - * current module - */ - private void resolveAugments( - Map> modules, - ModuleBuilder module) { - Set augmentBuilders = module - .getAddedAugments(); - - Set augments = new HashSet(); - for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) { - SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath(); - String prefix = null; - List augmentTargetPath = new ArrayList(); - - for (QName pathPart : augmentTargetSchemaPath.getPath()) { - prefix = pathPart.getPrefix(); - augmentTargetPath.add(pathPart.getLocalName()); - } - ModuleBuilder dependentModule = findDependentModule(modules, - module, prefix); - // - augmentTargetPath.add(0, dependentModule.getName()); - // - - - AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule - .getNode(augmentTargetPath); - AugmentationSchema result = augmentBuilder.build(); - augmentTarget.addAugmentation(result); - fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget); - augments.add(result); - } - module.setAugmentations(augments); - } - - /** - * Add all augment's child nodes to given target. - * - * @param augment - * @param target - */ - private void fillAugmentTarget(AugmentationSchemaBuilder augment, - ChildNodeBuilder target) { - for (DataSchemaNodeBuilder builder : augment.getChildNodes()) { - builder.setAugmenting(true); - target.addChildNode(builder); - } - } - - /** - * Go through identity statements defined in current module and resolve - * their 'base' statement if present. - * - * @param modules - * all modules - * @param module - * module being resolved - */ - private void resolveIdentities( - Map> modules, - ModuleBuilder module) { - Set identities = module.getAddedIdentities(); - for (IdentitySchemaNodeBuilder identity : identities) { - String baseIdentityName = identity.getBaseIdentityName(); - if (baseIdentityName != null) { - String baseIdentityPrefix = null; - String baseIdentityLocalName = null; - if (baseIdentityName.contains(":")) { - String[] splitted = baseIdentityName.split(":"); - baseIdentityPrefix = splitted[0]; - baseIdentityLocalName = splitted[1]; - } else { - baseIdentityPrefix = module.getPrefix(); - baseIdentityLocalName = baseIdentityName; - } - ModuleBuilder dependentModule; - if (baseIdentityPrefix.equals(module.getPrefix())) { - dependentModule = module; - } else { - dependentModule = findDependentModule(modules, module, - baseIdentityPrefix); - } - - Set dependentModuleIdentities = dependentModule - .getAddedIdentities(); - for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) { - if (idBuilder.getQName().getLocalName() - .equals(baseIdentityLocalName)) { - identity.setBaseIdentity(idBuilder); - } - } - } - } - } - - /** - * Find dependent module based on given prefix - * - * @param modules - * all available modules - * @param module - * current module - * @param prefix - * target module prefix - * @return dependent module builder - */ - private ModuleBuilder findDependentModule( - Map> modules, - ModuleBuilder module, String prefix) { - ModuleImport dependentModuleImport = getModuleImport(module, prefix); - String dependentModuleName = dependentModuleImport.getModuleName(); - Date dependentModuleRevision = dependentModuleImport.getRevision(); - - TreeMap moduleBuildersByRevision = modules - .get(dependentModuleName); - ModuleBuilder dependentModule; - if (dependentModuleRevision == null) { - dependentModule = moduleBuildersByRevision.lastEntry().getValue(); - } else { - dependentModule = moduleBuildersByRevision - .get(dependentModuleRevision); - } - return dependentModule; - } - - /** - * Get module import referenced by given prefix. - * - * @param builder - * module to search - * @param prefix - * prefix associated with import - * @return ModuleImport based on given prefix - */ - private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) { - ModuleImport moduleImport = null; - for (ModuleImport mi : builder.getModuleImports()) { - if (mi.getPrefix().equals(prefix)) { - moduleImport = mi; - break; - } - } - return moduleImport; - } - - /** - * Helper method for resolving special 'min' or 'max' values in range - * constraint - * - * @param ranges - * ranges to resolve - * @param targetType - * target type - * @param modules - * all available modules - * @param builder - * current module - */ - private void resolveRanges(List ranges, - TypeDefinitionBuilder targetType, - Map> modules, - ModuleBuilder builder) { - if (ranges != null && ranges.size() > 0) { - Long min = (Long) ranges.get(0).getMin(); - Long max = (Long) ranges.get(ranges.size() - 1).getMax(); - // if range contains one of the special values 'min' or 'max' - if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) { - Long[] values = parseRangeConstraint(targetType, modules, - builder); - if (min.equals(Long.MIN_VALUE)) { - min = values[0]; - RangeConstraint oldFirst = ranges.get(0); - RangeConstraint newFirst = BaseConstraints.rangeConstraint( - min, oldFirst.getMax(), oldFirst.getDescription(), - oldFirst.getReference()); - ranges.set(0, newFirst); - } - if (max.equals(Long.MAX_VALUE)) { - max = values[1]; - RangeConstraint oldLast = ranges.get(ranges.size() - 1); - RangeConstraint newLast = BaseConstraints.rangeConstraint( - oldLast.getMin(), max, oldLast.getDescription(), - oldLast.getReference()); - ranges.set(ranges.size() - 1, newLast); - } - } - } - } - - /** - * Helper method for resolving special 'min' or 'max' values in length - * constraint - * - * @param lengths - * lengths to resolve - * @param targetType - * target type - * @param modules - * all available modules - * @param builder - * current module - */ - private void resolveLengths(List lengths, - TypeDefinitionBuilder targetType, - Map> modules, - ModuleBuilder builder) { - if (lengths != null && lengths.size() > 0) { - Long min = lengths.get(0).getMin().longValue(); - Long max = lengths.get(lengths.size() - 1).getMax().longValue(); - // if length contains one of the special values 'min' or 'max' - if (min.equals(Long.MIN_VALUE) || max.equals(Long.MAX_VALUE)) { - Long[] values = parseRangeConstraint(targetType, modules, - builder); - if (min.equals(Long.MIN_VALUE)) { - min = values[0]; - LengthConstraint oldFirst = lengths.get(0); - LengthConstraint newFirst = BaseConstraints - .lengthConstraint(min, oldFirst.getMax(), - oldFirst.getDescription(), - oldFirst.getReference()); - lengths.set(0, newFirst); - } - if (max.equals(Long.MAX_VALUE)) { - max = values[1]; - LengthConstraint oldLast = lengths.get(lengths.size() - 1); - LengthConstraint newLast = BaseConstraints - .lengthConstraint(oldLast.getMin(), max, - oldLast.getDescription(), - oldLast.getReference()); - lengths.set(lengths.size() - 1, newLast); - } - } - } - } - - private Long[] parseRangeConstraint(TypeDefinitionBuilder targetType, - Map> modules, - ModuleBuilder builder) { - TypeDefinition targetBaseType = targetType.getBaseType(); - - if (targetBaseType instanceof IntegerTypeDefinition) { - IntegerTypeDefinition itd = (IntegerTypeDefinition) targetBaseType; - List ranges = itd.getRangeStatements(); - Long min = (Long) ranges.get(0).getMin(); - Long max = (Long) ranges.get(ranges.size() - 1).getMax(); - return new Long[] { min, max }; - } else if (targetBaseType instanceof DecimalTypeDefinition) { - DecimalTypeDefinition dtd = (DecimalTypeDefinition) targetBaseType; - List ranges = dtd.getRangeStatements(); - Long min = (Long) ranges.get(0).getMin(); - Long max = (Long) ranges.get(ranges.size() - 1).getMax(); - return new Long[] { min, max }; - } else { - return parseRangeConstraint( - findTypeDefinitionBuilder(modules, - (UnknownType) targetBaseType, builder), modules, - builder); - } - } - - private Date createEpochTime() { - Calendar c = Calendar.getInstance(); - c.setTimeInMillis(0); - return c.getTime(); - } - - private static class SchemaContextImpl implements SchemaContext { - private final Set modules; - - private SchemaContextImpl(Set modules) { - this.modules = modules; - } - - @Override - public Set getDataDefinitions() { - final Set dataDefs = new HashSet(); - for (Module m : modules) { - dataDefs.addAll(m.getChildNodes()); - } - return dataDefs; - } - - @Override - public Set getModules() { - return modules; - } - - @Override - public Set getNotifications() { - final Set notifications = new HashSet(); - for (Module m : modules) { - notifications.addAll(m.getNotifications()); - } - return notifications; - } - - @Override - public Set getOperations() { - final Set rpcs = new HashSet(); - for (Module m : modules) { - rpcs.addAll(m.getRpcs()); - } - return rpcs; - } - - @Override - public Set getExtensions() { - final Set extensions = new HashSet(); - for (Module m : modules) { - extensions.addAll(m.getExtensionSchemaNodes()); - } - return extensions; - } - } - - private static class TypeConstraints { - private final List ranges = new ArrayList(); - private final List lengths = new ArrayList(); - private final List patterns = new ArrayList(); - private Integer fractionDigits; - - public List getRanges() { - return ranges; - } - - public void addRanges(List ranges) { - this.ranges.addAll(0, ranges); - } - - public List getLengths() { - return lengths; - } - - public void addLengths(List lengths) { - this.lengths.addAll(0, lengths); - } - - public List getPatterns() { - return patterns; - } - - public void addPatterns(List patterns) { - this.patterns.addAll(0, patterns); - } - - public Integer getFractionDigits() { - return fractionDigits; - } - - public void setFractionDigits(Integer fractionDigits) { - if (fractionDigits != null) { - this.fractionDigits = fractionDigits; - } - } - } - -} +/* + * 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.yang.model.parser.impl; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; + +import org.antlr.v4.runtime.ANTLRInputStream; +import org.antlr.v4.runtime.CommonTokenStream; +import org.antlr.v4.runtime.tree.ParseTree; +import org.antlr.v4.runtime.tree.ParseTreeWalker; +import org.opendaylight.controller.antlrv4.code.gen.YangLexer; +import org.opendaylight.controller.antlrv4.code.gen.YangParser; +import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.model.api.AugmentationSchema; +import org.opendaylight.controller.yang.model.api.DataSchemaNode; +import org.opendaylight.controller.yang.model.api.ExtensionDefinition; +import org.opendaylight.controller.yang.model.api.Module; +import org.opendaylight.controller.yang.model.api.ModuleImport; +import org.opendaylight.controller.yang.model.api.NotificationDefinition; +import org.opendaylight.controller.yang.model.api.RpcDefinition; +import org.opendaylight.controller.yang.model.api.SchemaContext; +import org.opendaylight.controller.yang.model.api.SchemaPath; +import org.opendaylight.controller.yang.model.api.TypeDefinition; +import org.opendaylight.controller.yang.model.api.type.BinaryTypeDefinition; +import org.opendaylight.controller.yang.model.api.type.DecimalTypeDefinition; +import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition; +import org.opendaylight.controller.yang.model.api.type.LengthConstraint; +import org.opendaylight.controller.yang.model.api.type.PatternConstraint; +import org.opendaylight.controller.yang.model.api.type.RangeConstraint; +import org.opendaylight.controller.yang.model.api.type.StringTypeDefinition; +import org.opendaylight.controller.yang.model.parser.api.YangModelParser; +import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationSchemaBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.AugmentationTargetBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.ChildNodeBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.DataSchemaNodeBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.TypeAwareBuilder; +import org.opendaylight.controller.yang.model.parser.builder.api.TypeDefinitionBuilder; +import org.opendaylight.controller.yang.model.parser.builder.impl.IdentitySchemaNodeBuilder; +import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder; +import org.opendaylight.controller.yang.model.parser.builder.impl.TypedefBuilder; +import org.opendaylight.controller.yang.model.parser.builder.impl.UnionTypeBuilder; +import org.opendaylight.controller.yang.model.parser.util.TypeConstraints; +import org.opendaylight.controller.yang.model.parser.util.YangParseException; +import org.opendaylight.controller.yang.model.util.ExtendedType; +import org.opendaylight.controller.yang.model.util.UnknownType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class YangModelParserImpl implements YangModelParser { + + private static final Logger logger = LoggerFactory + .getLogger(YangModelParserImpl.class); + + @Override + public Module parseYangModel(final String yangFile) { + final Map> modules = resolveModuleBuildersFromStreams(yangFile); + final Set result = build(modules); + return result.iterator().next(); + } + + @Override + public Set parseYangModels(final String... yangFiles) { + final Map> modules = resolveModuleBuildersFromStreams(yangFiles); + return build(modules); + } + + @Override + public Set parseYangModelsFromStreams( + final InputStream... yangModelStreams) { + final Map> modules = resolveModuleBuildersFromStreams(yangModelStreams); + return build(modules); + } + + @Override + public SchemaContext resolveSchemaContext(final Set modules) { + return new SchemaContextImpl(modules); + } + + private Map> resolveModuleBuildersFromStreams( + String... yangFiles) { + InputStream[] streams = new InputStream[yangFiles.length]; + FileInputStream inStream = null; + for (int i = 0; i < yangFiles.length; i++) { + final String yangFileName = yangFiles[i]; + final File yangFile = new File(yangFileName); + try { + inStream = new FileInputStream(yangFile); + } catch (FileNotFoundException e) { + logger.warn("Exception while reading yang stream: " + inStream, + e); + } + streams[i] = inStream; + } + return resolveModuleBuildersFromStreams(streams); + } + + private Map> resolveModuleBuildersFromStreams( + InputStream... yangFiles) { + final Map> modules = new HashMap>(); + final ParseTreeWalker walker = new ParseTreeWalker(); + final List trees = parseStreams(yangFiles); + final ModuleBuilder[] builders = new ModuleBuilder[trees.size()]; + + YangModelParserListenerImpl yangModelParser = null; + for (int i = 0; i < trees.size(); i++) { + yangModelParser = new YangModelParserListenerImpl(); + walker.walk(yangModelParser, trees.get(i)); + builders[i] = yangModelParser.getModuleBuilder(); + } + + for (ModuleBuilder builder : builders) { + final String builderName = builder.getName(); + Date builderRevision = builder.getRevision(); + if (builderRevision == null) { + builderRevision = createEpochTime(); + } + TreeMap builderByRevision = modules + .get(builderName); + if (builderByRevision == null) { + builderByRevision = new TreeMap(); + } + builderByRevision.put(builderRevision, builder); + modules.put(builderName, builderByRevision); + } + return modules; + } + + private List parseStreams(InputStream... yangStreams) { + final List trees = new ArrayList(); + for (InputStream yangStream : yangStreams) { + trees.add(parseStream(yangStream)); + } + return trees; + } + + private ParseTree parseStream(InputStream yangStream) { + ParseTree result = null; + try { + final ANTLRInputStream input = new ANTLRInputStream(yangStream); + final YangLexer lexer = new YangLexer(input); + final CommonTokenStream tokens = new CommonTokenStream(lexer); + final YangParser parser = new YangParser(tokens); + result = parser.yang(); + } catch (IOException e) { + logger.warn("Exception while reading yang file: " + yangStream, e); + } + return result; + } + + private Set build(Map> modules) { + // validate + for (Map.Entry> entry : modules + .entrySet()) { + for (Map.Entry childEntry : entry.getValue() + .entrySet()) { + ModuleBuilder moduleBuilder = childEntry.getValue(); + validateModule(modules, moduleBuilder); + } + } + + // build + final Set result = new HashSet(); + for (Map.Entry> entry : modules + .entrySet()) { + final Map modulesByRevision = new HashMap(); + for (Map.Entry childEntry : entry.getValue() + .entrySet()) { + ModuleBuilder moduleBuilder = childEntry.getValue(); + Module module = moduleBuilder.build(); + modulesByRevision.put(childEntry.getKey(), module); + result.add(module); + } + } + return result; + } + + private void validateModule( + Map> modules, + ModuleBuilder builder) { + resolveDirtyNodes(modules, builder); + resolveAugments(modules, builder); + resolveIdentities(modules, builder); + } + + /** + * Search for dirty nodes (node which contains UnknownType) and resolve + * unknown types. + * + * @param modules + * all available modules + * @param module + * current module + */ + private void resolveDirtyNodes( + Map> modules, + ModuleBuilder module) { + final Map, TypeAwareBuilder> dirtyNodes = module + .getDirtyNodes(); + if (!dirtyNodes.isEmpty()) { + for (Map.Entry, TypeAwareBuilder> entry : dirtyNodes + .entrySet()) { + + TypeAwareBuilder typeToResolve = entry.getValue(); + if (typeToResolve instanceof UnionTypeBuilder) { + UnionTypeBuilder union = (UnionTypeBuilder) typeToResolve; + List> unionTypes = union.getTypes(); + List toRemove = new ArrayList(); + for (TypeDefinition td : unionTypes) { + if (td instanceof UnknownType) { + UnknownType unknownType = (UnknownType) td; + TypeDefinitionBuilder resolvedType = findTargetTypeUnion( + typeToResolve, unknownType, modules, module); + union.setType(resolvedType); + toRemove.add(unknownType); + } + } + unionTypes.removeAll(toRemove); + } else { + TypeDefinitionBuilder resolvedType = findTargetType( + typeToResolve, modules, module); + typeToResolve.setType(resolvedType); + } + } + } + } + + private TypeDefinitionBuilder findTargetType( + TypeAwareBuilder typeToResolve, + Map> modules, + ModuleBuilder builder) { + TypeConstraints constraints = new TypeConstraints(); + + TypeDefinitionBuilder targetType = findTypedef(typeToResolve, modules, + builder); + TypeConstraints tConstraints = findConstraints(typeToResolve, + constraints, modules, builder); + targetType.setRanges(tConstraints.getRange()); + targetType.setLengths(tConstraints.getLength()); + targetType.setPatterns(tConstraints.getPatterns()); + targetType.setFractionDigits(tConstraints.getFractionDigits()); + + return targetType; + } + + private TypeDefinitionBuilder findTargetTypeUnion( + TypeAwareBuilder typeToResolve, UnknownType unknownType, + Map> modules, + ModuleBuilder builder) { + TypeConstraints constraints = new TypeConstraints(); + + TypeDefinitionBuilder targetType = findTypedefUnion(typeToResolve, + unknownType, modules, builder); + TypeConstraints tConstraints = findConstraints(typeToResolve, + constraints, modules, builder); + targetType.setRanges(tConstraints.getRange()); + targetType.setLengths(tConstraints.getLength()); + targetType.setPatterns(tConstraints.getPatterns()); + targetType.setFractionDigits(tConstraints.getFractionDigits()); + + return targetType; + } + + private TypeDefinitionBuilder findTypedef(TypeAwareBuilder typeToResolve, + Map> modules, + ModuleBuilder builder) { + + TypeDefinition baseTypeToResolve = typeToResolve.getType(); + if (baseTypeToResolve != null + && !(baseTypeToResolve instanceof UnknownType)) { + return (TypeDefinitionBuilder) typeToResolve; + } + + UnknownType unknownType = (UnknownType) typeToResolve.getType(); + + QName unknownTypeQName = unknownType.getQName(); + String unknownTypeName = unknownTypeQName.getLocalName(); + String unknownTypePrefix = unknownTypeQName.getPrefix(); + + // search for module which contains referenced typedef + ModuleBuilder dependentModule = findDependentModule(modules, builder, + unknownTypePrefix); + TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder( + dependentModule.getModuleTypedefs(), unknownTypeName); + + TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder( + lookedUpBuilder, typeToResolve instanceof TypeDefinitionBuilder); + TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder( + lookedUpBuilderCopy, modules, dependentModule); + return resolvedCopy; + } + + private TypeDefinitionBuilder findTypedefUnion( + TypeAwareBuilder typeToResolve, UnknownType unknownType, + Map> modules, + ModuleBuilder builder) { + + TypeDefinition baseTypeToResolve = typeToResolve.getType(); + if (baseTypeToResolve != null + && !(baseTypeToResolve instanceof UnknownType)) { + return (TypeDefinitionBuilder) typeToResolve; + } + + QName unknownTypeQName = unknownType.getQName(); + String unknownTypeName = unknownTypeQName.getLocalName(); + String unknownTypePrefix = unknownTypeQName.getPrefix(); + + // search for module which contains referenced typedef + ModuleBuilder dependentModule = findDependentModule(modules, builder, + unknownTypePrefix); + TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder( + dependentModule.getModuleTypedefs(), unknownTypeName); + + TypeDefinitionBuilder lookedUpBuilderCopy = copyTypedefBuilder( + lookedUpBuilder, typeToResolve instanceof TypeDefinitionBuilder); + TypeDefinitionBuilder resolvedCopy = resolveCopiedBuilder( + lookedUpBuilderCopy, modules, dependentModule); + return resolvedCopy; + } + + private TypeDefinitionBuilder copyTypedefBuilder(TypeDefinitionBuilder old, + boolean seekByTypedefBuilder) { + if (old instanceof UnionTypeBuilder) { + UnionTypeBuilder oldUnion = (UnionTypeBuilder) old; + UnionTypeBuilder newUnion = new UnionTypeBuilder(); + for (TypeDefinition td : oldUnion.getTypes()) { + newUnion.setType(td); + } + for (TypeDefinitionBuilder tdb : oldUnion.getTypedefs()) { + newUnion.setType(copyTypedefBuilder(tdb, true)); + } + return newUnion; + } + + QName oldQName = old.getQName(); + QName newQName = new QName(oldQName.getNamespace(), + oldQName.getRevision(), oldQName.getPrefix(), + oldQName.getLocalName()); + TypeDefinitionBuilder tdb = new TypedefBuilder(newQName); + + tdb.setRanges(old.getRanges()); + tdb.setLengths(old.getLengths()); + tdb.setPatterns(old.getPatterns()); + + TypeDefinition oldType = old.getType(); + if (oldType == null) { + tdb.setType(old.getTypedef()); + } else { + tdb.setType(oldType); + } + + if (!seekByTypedefBuilder) { + tdb.setDescription(old.getDescription()); + tdb.setReference(old.getReference()); + tdb.setStatus(old.getStatus()); + tdb.setDefaultValue(old.getDefaultValue()); + tdb.setUnits(old.getUnits()); + } + return tdb; + } + + private TypeDefinitionBuilder resolveCopiedBuilder( + TypeDefinitionBuilder copied, + Map> modules, + ModuleBuilder builder) { + + if (copied instanceof UnionTypeBuilder) { + UnionTypeBuilder union = (UnionTypeBuilder) copied; + List> unionTypes = union.getTypes(); + List toRemove = new ArrayList(); + for (TypeDefinition td : unionTypes) { + if (td instanceof UnknownType) { + UnknownType unknownType = (UnknownType) td; + TypeDefinitionBuilder resolvedType = findTargetTypeUnion( + union, unknownType, modules, builder); + union.setType(resolvedType); + toRemove.add(unknownType); + } + } + unionTypes.removeAll(toRemove); + + return union; + } + + TypeDefinition base = copied.getType(); + TypeDefinitionBuilder baseTdb = copied.getTypedef(); + if (base != null && !(base instanceof UnknownType)) { + return copied; + } else if (base instanceof UnknownType) { + UnknownType unknownType = (UnknownType) base; + QName unknownTypeQName = unknownType.getQName(); + String unknownTypePrefix = unknownTypeQName.getPrefix(); + ModuleBuilder dependentModule = findDependentModule(modules, + builder, unknownTypePrefix); + TypeDefinitionBuilder unknownTypeBuilder = findTypedef(copied, + modules, dependentModule); + copied.setType(unknownTypeBuilder); + return copied; + } else if (base == null && baseTdb != null) { + // make a copy of baseTypeDef and call again + TypeDefinitionBuilder baseTdbCopy = copyTypedefBuilder(baseTdb, + true); + TypeDefinitionBuilder baseTdbCopyResolved = resolveCopiedBuilder( + baseTdbCopy, modules, builder); + copied.setType(baseTdbCopyResolved); + return copied; + } else { + throw new IllegalStateException( + "TypeDefinitionBuilder in unexpected state"); + } + } + + private TypeDefinitionBuilder findTypedef(QName unknownTypeQName, + Map> modules, + ModuleBuilder builder) { + + String unknownTypeName = unknownTypeQName.getLocalName(); + String unknownTypePrefix = unknownTypeQName.getPrefix(); + + // search for module which contains referenced typedef + ModuleBuilder dependentModule = findDependentModule(modules, builder, + unknownTypePrefix); + + TypeDefinitionBuilder lookedUpBuilder = findTypedefBuilder( + dependentModule.getModuleTypedefs(), unknownTypeName); + + TypeDefinitionBuilder copied = copyTypedefBuilder(lookedUpBuilder, true); + return copied; + } + + private TypeConstraints findConstraints(TypeAwareBuilder typeToResolve, + TypeConstraints constraints, + Map> modules, + ModuleBuilder builder) { + + // union type cannot be restricted + if (typeToResolve instanceof UnionTypeBuilder) { + return constraints; + } + + // if referenced type is UnknownType again, search recursively with + // current constraints + TypeDefinition referencedType = typeToResolve.getType(); + if (referencedType == null) { + TypeDefinitionBuilder tdb = (TypeDefinitionBuilder) typeToResolve; + final List ranges = tdb.getRanges(); + constraints.addRanges(ranges); + final List lengths = tdb.getLengths(); + constraints.addLengths(lengths); + final List patterns = tdb.getPatterns(); + constraints.addPatterns(patterns); + final Integer fractionDigits = tdb.getFractionDigits(); + constraints.setFractionDigits(fractionDigits); + return constraints; + } else if (referencedType instanceof ExtendedType) { + ExtendedType ext = (ExtendedType) referencedType; + final List ranges = ext.getRanges(); + constraints.addRanges(ranges); + final List lengths = ext.getLengths(); + constraints.addLengths(lengths); + final List patterns = ext.getPatterns(); + constraints.addPatterns(patterns); + final Integer fractionDigits = ext.getFractionDigits(); + constraints.setFractionDigits(fractionDigits); + return findConstraints( + findTypedef(ext.getQName(), modules, builder), constraints, + modules, builder); + } else if (referencedType instanceof UnknownType) { + UnknownType unknown = (UnknownType) referencedType; + + final List ranges = unknown.getRangeStatements(); + constraints.addRanges(ranges); + final List lengths = unknown + .getLengthStatements(); + constraints.addLengths(lengths); + final List patterns = unknown.getPatterns(); + constraints.addPatterns(patterns); + final Integer fractionDigits = unknown.getFractionDigits(); + constraints.setFractionDigits(fractionDigits); + + String unknownTypePrefix = unknown.getQName().getPrefix(); + if (unknownTypePrefix == null || "".equals(unknownTypePrefix)) { + unknownTypePrefix = builder.getPrefix(); + } + ModuleBuilder dependentModule = findDependentModule(modules, + builder, unknown.getQName().getPrefix()); + TypeDefinitionBuilder unknownTypeBuilder = findTypedef( + unknown.getQName(), modules, builder); + return findConstraints(unknownTypeBuilder, constraints, modules, + dependentModule); + } else { + // HANDLE BASE YANG TYPE + mergeConstraints(referencedType, constraints); + return constraints; + } + + } + + /** + * Go through all typedef statements from given module and search for one + * with given name + * + * @param typedefs + * typedef statements to search + * @param name + * name of searched typedef + * @return typedef with name equals to given name + */ + private TypeDefinitionBuilder findTypedefBuilder( + Set typedefs, String name) { + TypeDefinitionBuilder result = null; + for (TypeDefinitionBuilder td : typedefs) { + if (td.getQName().getLocalName().equals(name)) { + result = td; + break; + } + } + if (result == null) { + throw new YangParseException( + "Target module does not contain typedef '" + name + "'."); + } + return result; + } + + /** + * Pull restriction from referenced type and add them to given constraints + * + * @param referencedType + * @param constraints + */ + private void mergeConstraints(TypeDefinition referencedType, + TypeConstraints constraints) { + + if (referencedType instanceof DecimalTypeDefinition) { + constraints.addRanges(((DecimalTypeDefinition) referencedType) + .getRangeStatements()); + constraints + .setFractionDigits(((DecimalTypeDefinition) referencedType) + .getFractionDigits()); + } else if (referencedType instanceof IntegerTypeDefinition) { + constraints.addRanges(((IntegerTypeDefinition) referencedType) + .getRangeStatements()); + } else if (referencedType instanceof StringTypeDefinition) { + constraints.addPatterns(((StringTypeDefinition) referencedType) + .getPatterns()); + constraints.addLengths(((StringTypeDefinition) referencedType) + .getLengthStatements()); + } else if (referencedType instanceof BinaryTypeDefinition) { + constraints.addLengths(((BinaryTypeDefinition) referencedType) + .getLengthConstraints()); + } + } + + /** + * Go through all augmentation definitions and resolve them. This means find + * referenced node and add child nodes to it. + * + * @param modules + * all available modules + * @param module + * current module + */ + private void resolveAugments( + Map> modules, + ModuleBuilder module) { + Set augmentBuilders = module + .getAddedAugments(); + + Set augments = new HashSet(); + for (AugmentationSchemaBuilder augmentBuilder : augmentBuilders) { + SchemaPath augmentTargetSchemaPath = augmentBuilder.getTargetPath(); + String prefix = null; + List augmentTargetPath = new ArrayList(); + + for (QName pathPart : augmentTargetSchemaPath.getPath()) { + prefix = pathPart.getPrefix(); + augmentTargetPath.add(pathPart.getLocalName()); + } + ModuleBuilder dependentModule = findDependentModule(modules, + module, prefix); + augmentTargetPath.add(0, dependentModule.getName()); + + AugmentationTargetBuilder augmentTarget = (AugmentationTargetBuilder) dependentModule + .getNode(augmentTargetPath); + AugmentationSchema result = augmentBuilder.build(); + augmentTarget.addAugmentation(result); + fillAugmentTarget(augmentBuilder, (ChildNodeBuilder) augmentTarget); + augments.add(result); + } + module.setAugmentations(augments); + } + + /** + * Add all augment's child nodes to given target. + * + * @param augment + * @param target + */ + private void fillAugmentTarget(AugmentationSchemaBuilder augment, + ChildNodeBuilder target) { + for (DataSchemaNodeBuilder builder : augment.getChildNodes()) { + builder.setAugmenting(true); + target.addChildNode(builder); + } + } + + /** + * Go through identity statements defined in current module and resolve + * their 'base' statement if present. + * + * @param modules + * all modules + * @param module + * module being resolved + */ + private void resolveIdentities( + Map> modules, + ModuleBuilder module) { + Set identities = module.getAddedIdentities(); + for (IdentitySchemaNodeBuilder identity : identities) { + String baseIdentityName = identity.getBaseIdentityName(); + if (baseIdentityName != null) { + String baseIdentityPrefix = null; + String baseIdentityLocalName = null; + if (baseIdentityName.contains(":")) { + String[] splitted = baseIdentityName.split(":"); + baseIdentityPrefix = splitted[0]; + baseIdentityLocalName = splitted[1]; + } else { + baseIdentityPrefix = module.getPrefix(); + baseIdentityLocalName = baseIdentityName; + } + ModuleBuilder dependentModule = findDependentModule(modules, + module, baseIdentityPrefix); + + Set dependentModuleIdentities = dependentModule + .getAddedIdentities(); + for (IdentitySchemaNodeBuilder idBuilder : dependentModuleIdentities) { + if (idBuilder.getQName().getLocalName() + .equals(baseIdentityLocalName)) { + identity.setBaseIdentity(idBuilder); + } + } + } + } + } + + /** + * Find dependent module based on given prefix + * + * @param modules + * all available modules + * @param module + * current module + * @param prefix + * target module prefix + * @return + */ + private ModuleBuilder findDependentModule( + Map> modules, + ModuleBuilder module, String prefix) { + ModuleBuilder dependentModule = null; + Date dependentModuleRevision = null; + + if (prefix.equals(module.getPrefix())) { + dependentModule = module; + } else { + ModuleImport dependentModuleImport = getModuleImport(module, prefix); + if (dependentModuleImport == null) { + throw new YangParseException("No import found with prefix '" + + prefix + "' in module " + module.getName() + "'."); + } + String dependentModuleName = dependentModuleImport.getModuleName(); + dependentModuleRevision = dependentModuleImport.getRevision(); + + TreeMap moduleBuildersByRevision = modules + .get(dependentModuleName); + if (dependentModuleRevision == null) { + dependentModule = moduleBuildersByRevision.lastEntry() + .getValue(); + } else { + dependentModule = moduleBuildersByRevision + .get(dependentModuleRevision); + } + } + + if (dependentModule == null) { + throw new YangParseException( + "Failed to find dependent module with prefix '" + prefix + + "' and revision '" + dependentModuleRevision + + "'."); + } + return dependentModule; + } + + /** + * Get module import referenced by given prefix. + * + * @param builder + * module to search + * @param prefix + * prefix associated with import + * @return ModuleImport based on given prefix + */ + private ModuleImport getModuleImport(ModuleBuilder builder, String prefix) { + ModuleImport moduleImport = null; + for (ModuleImport mi : builder.getModuleImports()) { + if (mi.getPrefix().equals(prefix)) { + moduleImport = mi; + break; + } + } + return moduleImport; + } + + private Date createEpochTime() { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(0); + return calendar.getTime(); + } + + private static class SchemaContextImpl implements SchemaContext { + private final Set modules; + + private SchemaContextImpl(Set modules) { + this.modules = modules; + } + + @Override + public Set getDataDefinitions() { + final Set dataDefs = new HashSet(); + for (Module m : modules) { + dataDefs.addAll(m.getChildNodes()); + } + return dataDefs; + } + + @Override + public Set getModules() { + return modules; + } + + @Override + public Set getNotifications() { + final Set notifications = new HashSet(); + for (Module m : modules) { + notifications.addAll(m.getNotifications()); + } + return notifications; + } + + @Override + public Set getOperations() { + final Set rpcs = new HashSet(); + for (Module m : modules) { + rpcs.addAll(m.getRpcs()); + } + return rpcs; + } + + @Override + public Set getExtensions() { + final Set extensions = new HashSet(); + for (Module m : modules) { + extensions.addAll(m.getExtensionSchemaNodes()); + } + return extensions; + } + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerImpl.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerImpl.java index 6ff69eee51..6d51868d98 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerImpl.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerImpl.java @@ -13,15 +13,14 @@ import java.net.URI; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Stack; -import java.util.TreeMap; import org.antlr.v4.runtime.tree.ParseTree; import org.opendaylight.controller.antlrv4.code.gen.YangParser; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext; import org.opendaylight.controller.antlrv4.code.gen.YangParser.Base_stmtContext; import org.opendaylight.controller.antlrv4.code.gen.YangParser.Contact_stmtContext; import org.opendaylight.controller.antlrv4.code.gen.YangParser.Container_stmtContext; @@ -47,7 +46,6 @@ import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtCont import org.opendaylight.controller.antlrv4.code.gen.YangParser.Revision_stmtsContext; import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext; import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Union_specificationContext; import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yang_version_stmtContext; import org.opendaylight.controller.antlrv4.code.gen.YangParserBaseListener; import org.opendaylight.controller.yang.common.QName; @@ -88,7 +86,6 @@ final class YangModelParserListenerImpl extends YangParserBaseListener { "yyyy-mm-dd"); private final Stack actualPath = new Stack(); - @Override public void enterModule_stmt(YangParser.Module_stmtContext ctx) { moduleName = stringFromNode(ctx); @@ -123,7 +120,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener { @Override public void enterModule_header_stmts(final Module_header_stmtsContext ctx) { super.enterModule_header_stmts(ctx); - + String yangVersion = null; for (int i = 0; i < ctx.getChildCount(); ++i) { final ParseTree treeNode = ctx.getChild(i); @@ -138,7 +135,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener { yangVersion = stringFromNode(treeNode); } } - + if (yangVersion == null) { yangVersion = "1"; } @@ -204,7 +201,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener { logger.warn(message); } } - + @Override public void enterImport_stmt(Import_stmtContext ctx) { super.enterImport_stmt(ctx); @@ -260,10 +257,23 @@ final class YangModelParserListenerImpl extends YangParserBaseListener { @Override public void enterExtension_stmt(YangParser.Extension_stmtContext ctx) { - String argument = stringFromNode(ctx); - QName qname = new QName(namespace, revision, yangModelPrefix, argument); + String extName = stringFromNode(ctx); + QName qname = new QName(namespace, revision, yangModelPrefix, extName); ExtensionBuilder builder = moduleBuilder.addExtension(qname); parseSchemaNodeArgs(ctx, builder); + + String argument = null; + boolean yin = false; + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Argument_stmtContext) { + argument = stringFromNode(child); + yin = parseYinValue((Argument_stmtContext) child); + break; + } + } + builder.setArgument(argument); + builder.setYinElement(yin); } @Override @@ -290,20 +300,7 @@ final class YangModelParserListenerImpl extends YangParserBaseListener { @Override public void enterType_stmt(YangParser.Type_stmtContext ctx) { String typeName = stringFromNode(ctx); - QName typeQName; - if (typeName.contains(":")) { - String[] splittedName = typeName.split(":"); - String prefix = splittedName[0]; - String name = splittedName[1]; - if (prefix.equals(yangModelPrefix)) { - typeQName = new QName(namespace, revision, prefix, name); - } else { - typeQName = new QName(null, null, prefix, name); - } - } else { - typeQName = new QName(namespace, revision, yangModelPrefix, - typeName); - } + QName typeQName = parseQName(typeName); TypeDefinition type = null; Type_body_stmtsContext typeBody = null; @@ -315,38 +312,46 @@ final class YangModelParserListenerImpl extends YangParserBaseListener { } // if this is base yang type... - if(YangTypesConverter.isBaseYangType(typeName)) { + if (YangTypesConverter.isBaseYangType(typeName)) { if (typeBody == null) { // if there are no constraints, just grab default base yang type type = YangTypesConverter.javaTypeForBaseYangType(typeName); - moduleBuilder.setType(type, actualPath); + moduleBuilder.setType(type, getActualPath()); } else { - if(typeName.equals("union")) { - List types = new ArrayList(); - for(int i = 0; i < typeBody.getChildCount(); i++) { - ParseTree unionSpec = typeBody.getChild(i); - if(unionSpec instanceof Union_specificationContext) { - for(int j = 0; j < unionSpec.getChildCount(); j++) { - ParseTree typeSpec = unionSpec.getChild(j); - types.add(stringFromNode(typeSpec)); - } - } - } - moduleBuilder.addUnionType(actualPath); + if ("union".equals(typeName)) { + moduleBuilder.addUnionType(getActualPath()); } else { - type = parseTypeBody(typeName, typeBody, actualPath, namespace, revision, yangModelPrefix); - moduleBuilder.setType(type, actualPath); + type = parseTypeBody(typeName, typeBody, getActualPath(), + namespace, revision, yangModelPrefix); + moduleBuilder.setType(type, getActualPath()); } } } else { type = parseUnknownTypeBody(typeQName, typeBody); // mark parent node of this type statement as dirty - moduleBuilder.addDirtyNode(actualPath); - moduleBuilder.setType(type, actualPath); + moduleBuilder.addDirtyNode(getActualPath()); + moduleBuilder.setType(type, getActualPath()); } updatePath(typeName); + } + private QName parseQName(String typeName) { + QName typeQName; + if (typeName.contains(":")) { + String[] splittedName = typeName.split(":"); + String prefix = splittedName[0]; + String name = splittedName[1]; + if (prefix.equals(yangModelPrefix)) { + typeQName = new QName(namespace, revision, prefix, name); + } else { + typeQName = new QName(null, null, prefix, name); + } + } else { + typeQName = new QName(namespace, revision, yangModelPrefix, + typeName); + } + return typeQName; } @Override diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/TypeConstraints.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/TypeConstraints.java index 9e5fcbe771..0f26da886b 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/TypeConstraints.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/TypeConstraints.java @@ -8,6 +8,7 @@ package org.opendaylight.controller.yang.model.parser.util; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.opendaylight.controller.yang.model.api.type.LengthConstraint; @@ -29,6 +30,11 @@ public final class TypeConstraints { } public List getRange() { + if(ranges.isEmpty()) { + List result = Collections.emptyList(); + return result; + } + List resolved = ranges.get(0); RangeConstraint firstRange = resolved.get(0); RangeConstraint lastRange = resolved.get(resolved.size() - 1); @@ -103,6 +109,11 @@ public final class TypeConstraints { } public List getLength() { + if(lengths.isEmpty()) { + List result = Collections.emptyList(); + return result; + } + List resolved = lengths.get(0); LengthConstraint firstLength = resolved.get(0); LengthConstraint lastLength = resolved.get(resolved.size() - 1); @@ -185,7 +196,7 @@ public final class TypeConstraints { } public void setFractionDigits(Integer fractionDigits) { - if (fractionDigits != null) { + if (this.fractionDigits == null) { this.fractionDigits = fractionDigits; } } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangModelBuilderUtil.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangModelBuilderUtil.java index 89422ff9c6..cbeed0959e 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangModelBuilderUtil.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangModelBuilderUtil.java @@ -1,1115 +1,1124 @@ -/* - * 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/eplv10.html - */ -package org.opendaylight.controller.yang.model.parser.util; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Stack; - -import org.antlr.v4.runtime.tree.ParseTree; -import org.opendaylight.controller.antlrv4.code.gen.YangParser; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bit_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bits_specificationContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Decimal64_specificationContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_specificationContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leafref_specificationContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Length_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Max_elements_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Min_elements_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Must_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Numerical_restrictionsContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Path_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Pattern_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Position_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Range_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_argContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.String_restrictionsContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.Units_stmtContext; -import org.opendaylight.controller.antlrv4.code.gen.YangParser.When_stmtContext; -import org.opendaylight.controller.yang.common.QName; -import org.opendaylight.controller.yang.model.api.RevisionAwareXPath; -import org.opendaylight.controller.yang.model.api.SchemaPath; -import org.opendaylight.controller.yang.model.api.Status; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.UnknownSchemaNode; -import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.LengthConstraint; -import org.opendaylight.controller.yang.model.api.type.PatternConstraint; -import org.opendaylight.controller.yang.model.api.type.RangeConstraint; -import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit; -import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuilder; -import org.opendaylight.controller.yang.model.parser.builder.impl.ConstraintsBuilder; -import org.opendaylight.controller.yang.model.util.BaseConstraints; -import org.opendaylight.controller.yang.model.util.BinaryType; -import org.opendaylight.controller.yang.model.util.BitsType; -import org.opendaylight.controller.yang.model.util.EnumerationType; -import org.opendaylight.controller.yang.model.util.InstanceIdentifier; -import org.opendaylight.controller.yang.model.util.Leafref; -import org.opendaylight.controller.yang.model.util.RevisionAwareXPathImpl; -import org.opendaylight.controller.yang.model.util.StringType; -import org.opendaylight.controller.yang.model.util.UnknownType; -import org.opendaylight.controller.yang.model.util.YangTypesConverter; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class YangModelBuilderUtil { - - private static final Logger logger = LoggerFactory - .getLogger(YangModelBuilderUtil.class); - - /** - * Parse given tree and get first string value. - * - * @param treeNode - * tree to parse - * @return first string value from given tree - */ - public static String stringFromNode(final ParseTree treeNode) { - final String result = ""; - for (int i = 0; i < treeNode.getChildCount(); ++i) { - if (treeNode.getChild(i) instanceof StringContext) { - final StringContext context = (StringContext) treeNode - .getChild(i); - if (context != null) { - return context.getChild(0).getText().replace("\"", ""); - } - } - } - return result; - } - - /** - * Parse 'description', 'reference' and 'status' statements and fill in - * given builder. - * - * @param ctx - * context to parse - * @param builder - * builder to fill in with parsed statements - */ - public static void parseSchemaNodeArgs(ParseTree ctx, - SchemaNodeBuilder builder) { - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Description_stmtContext) { - String desc = stringFromNode(child); - builder.setDescription(desc); - } else if (child instanceof Reference_stmtContext) { - String ref = stringFromNode(child); - builder.setReference(ref); - } else if (child instanceof Status_stmtContext) { - Status status = parseStatus((Status_stmtContext) child); - builder.setStatus(status); - } - } - } - - /** - * Parse given context and return its value; - * - * @param ctx - * status context - * @return value parsed from context - */ - public static Status parseStatus(Status_stmtContext ctx) { - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree statusArg = ctx.getChild(i); - if (statusArg instanceof Status_argContext) { - String statusArgStr = stringFromNode(statusArg); - if (statusArgStr.equals("current")) { - return Status.CURRENT; - } else if (statusArgStr.equals("deprecated")) { - return Status.DEPRECATED; - } else if (statusArgStr.equals("obsolete")) { - return Status.OBSOLETE; - } else { - logger.warn("Invalid 'status' statement: " + statusArgStr); - } - } - } - return null; - } - - /** - * Parse given tree and returns units statement as string. - * - * @param ctx - * context to parse - * @return value of units statement as string or null if there is no units - * statement - */ - public static String parseUnits(ParseTree ctx) { - String units = null; - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Units_stmtContext) { - units = stringFromNode(child); - break; - } - } - return units; - } - - /** - * Create SchemaPath object from given path list with namespace, revision - * and prefix based on given values. - * - * @param actualPath - * @param namespace - * @param revision - * @param prefix - * @return SchemaPath object. - */ - public static SchemaPath createActualSchemaPath(List actualPath, - URI namespace, Date revision, String prefix) { - final List path = new ArrayList(); - QName qname; - for (String pathElement : actualPath) { - qname = new QName(namespace, revision, prefix, pathElement); - path.add(qname); - } - return new SchemaPath(path, true); - } - - /** - * Create SchemaPath from given string. - * - * @param augmentPath - * string representation of path - * @return SchemaPath object - */ - public static SchemaPath parseAugmentPath(String augmentPath) { - boolean absolute = augmentPath.startsWith("/"); - String[] splittedPath = augmentPath.split("/"); - List path = new ArrayList(); - QName name; - for (String pathElement : splittedPath) { - if (pathElement.length() > 0) { - String[] splittedElement = pathElement.split(":"); - if (splittedElement.length == 1) { - name = new QName(null, null, null, splittedElement[0]); - } else { - name = new QName(null, null, splittedElement[0], - splittedElement[1]); - } - path.add(name); - } - } - return new SchemaPath(path, absolute); - } - - /** - * Create java.util.List of QName objects from given key definition as - * string. - * - * @param keyDefinition - * key definition as string - * @param namespace - * current namespace - * @param revision - * current revision - * @param prefix - * current prefix - * @return YANG list key as java.util.List of QName objects - */ - public static List createListKey(String keyDefinition, - URI namespace, Date revision, String prefix) { - List key = new ArrayList(); - String[] splittedKey = keyDefinition.split(" "); - - QName qname = null; - for (String keyElement : splittedKey) { - if (keyElement.length() != 0) { - qname = new QName(namespace, revision, prefix, keyElement); - key.add(qname); - } - } - return key; - } - - private static List getEnumConstants( - Type_body_stmtsContext ctx, List path, URI namespace, - Date revision, String prefix) { - List enumConstants = new ArrayList(); - - out: for (int j = 0; j < ctx.getChildCount(); j++) { - ParseTree enumSpecChild = ctx.getChild(j); - if (enumSpecChild instanceof Enum_specificationContext) { - for (int k = 0; k < enumSpecChild.getChildCount(); k++) { - ParseTree enumChild = enumSpecChild.getChild(k); - if (enumChild instanceof Enum_stmtContext) { - enumConstants.add(createEnumPair( - (Enum_stmtContext) enumChild, k, path, - namespace, revision, prefix)); - if (k == enumSpecChild.getChildCount() - 1) { - break out; - } - } - } - } - } - return enumConstants; - } - - private static EnumTypeDefinition.EnumPair createEnumPair( - Enum_stmtContext ctx, final int value, List path, - final URI namespace, final Date revision, final String prefix) { - final String name = stringFromNode(ctx); - final QName qname = new QName(namespace, revision, prefix, name); - String description = null; - String reference = null; - Status status = null; - List enumPairPath = new ArrayList(path); - enumPairPath.add(name); - - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Description_stmtContext) { - description = stringFromNode(child); - } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); - } else if (child instanceof Status_stmtContext) { - status = parseStatus((Status_stmtContext) child); - } - } - - EnumPairImpl result = new EnumPairImpl(); - result.qname = qname; - result.path = createActualSchemaPath(enumPairPath, namespace, revision, - prefix); - result.description = description; - result.reference = reference; - result.status = status; - // TODO: extensionSchemaNodes - result.name = name; - result.value = value; - return result; - } - - private static class EnumPairImpl implements EnumTypeDefinition.EnumPair { - - private QName qname; - private SchemaPath path; - private String description; - private String reference; - private Status status; - private List extensionSchemaNodes = Collections - .emptyList(); - private String name; - private Integer value; - - @Override - public QName getQName() { - return qname; - } - - @Override - public SchemaPath getPath() { - return path; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public String getReference() { - return reference; - } - - @Override - public Status getStatus() { - return status; - } - - @Override - public List getUnknownSchemaNodes() { - return extensionSchemaNodes; - } - - @Override - public String getName() { - return name; - } - - @Override - public Integer getValue() { - return value; - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result + ((qname == null) ? 0 : qname.hashCode()); - result = prime * result + ((path == null) ? 0 : path.hashCode()); - result = prime * result - + ((description == null) ? 0 : description.hashCode()); - result = prime * result - + ((reference == null) ? 0 : reference.hashCode()); - result = prime * result - + ((status == null) ? 0 : status.hashCode()); - result = prime - * result - + ((extensionSchemaNodes == null) ? 0 - : extensionSchemaNodes.hashCode()); - result = prime * result + ((name == null) ? 0 : name.hashCode()); - result = prime * result + ((value == null) ? 0 : value.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - EnumPairImpl other = (EnumPairImpl) obj; - if (qname == null) { - if (other.qname != null) { - return false; - } - } else if (!qname.equals(other.qname)) { - return false; - } - if (path == null) { - if (other.path != null) { - return false; - } - } else if (!path.equals(other.path)) { - return false; - } - if (description == null) { - if (other.description != null) { - return false; - } - } else if (!description.equals(other.description)) { - return false; - } - if (reference == null) { - if (other.reference != null) { - return false; - } - } else if (!reference.equals(other.reference)) { - return false; - } - if (status == null) { - if (other.status != null) { - return false; - } - } else if (!status.equals(other.status)) { - return false; - } - if (extensionSchemaNodes == null) { - if (other.extensionSchemaNodes != null) { - return false; - } - } else if (!extensionSchemaNodes.equals(other.extensionSchemaNodes)) { - return false; - } - if (name == null) { - if (other.name != null) { - return false; - } - } else if (!name.equals(other.name)) { - return false; - } - if (value == null) { - if (other.value != null) { - return false; - } - } else if (!value.equals(other.value)) { - return false; - } - return true; - } - - @Override - public String toString() { - return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name=" - + name + ", value=" + value + "]"; - } - }; - - private static List getRangeConstraints( - Type_body_stmtsContext ctx) { - final List rangeConstraints = new ArrayList(); - for (int j = 0; j < ctx.getChildCount(); j++) { - ParseTree numRestrChild = ctx.getChild(j); - if (numRestrChild instanceof Numerical_restrictionsContext) { - for (int k = 0; k < numRestrChild.getChildCount(); k++) { - ParseTree rangeChild = numRestrChild.getChild(k); - if (rangeChild instanceof Range_stmtContext) { - rangeConstraints - .addAll(parseRangeConstraints((Range_stmtContext) rangeChild)); - break; - } - } - } - } - return rangeConstraints; - } - - private static List parseRangeConstraints( - Range_stmtContext ctx) { - List rangeConstraints = new ArrayList(); - String description = null; - String reference = null; - - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Description_stmtContext) { - description = stringFromNode(child); - } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); - } - } - - String rangeStr = stringFromNode(ctx); - String trimmed = rangeStr.replace(" ", ""); - String[] splittedRange = trimmed.split("\\|"); - for (String rangeDef : splittedRange) { - String[] splittedRangeDef = rangeDef.split("\\.\\."); - Long min; - Long max; - if (splittedRangeDef.length == 1) { - min = max = parseRangeValue(splittedRangeDef[0]); - } else { - min = parseRangeValue(splittedRangeDef[0]); - max = parseRangeValue(splittedRangeDef[1]); - } - RangeConstraint range = BaseConstraints.rangeConstraint(min, max, - description, reference); - rangeConstraints.add(range); - } - - return rangeConstraints; - } - - private static List getLengthConstraints( - Type_body_stmtsContext ctx) { - List lengthConstraints = new ArrayList(); - for (int j = 0; j < ctx.getChildCount(); j++) { - ParseTree stringRestrChild = ctx.getChild(j); - if (stringRestrChild instanceof String_restrictionsContext) { - for (int k = 0; k < stringRestrChild.getChildCount(); k++) { - ParseTree lengthChild = stringRestrChild.getChild(k); - if (lengthChild instanceof Length_stmtContext) { - lengthConstraints - .addAll(parseLengthConstraints((Length_stmtContext) lengthChild)); - } - } - } - } - return lengthConstraints; - } - - private static List parseLengthConstraints( - Length_stmtContext ctx) { - List lengthConstraints = new ArrayList(); - String description = null; - String reference = null; - - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Description_stmtContext) { - description = stringFromNode(child); - } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); - } - } - - String lengthStr = stringFromNode(ctx); - String trimmed = lengthStr.replace(" ", ""); - String[] splittedRange = trimmed.split("\\|"); - for (String rangeDef : splittedRange) { - String[] splittedRangeDef = rangeDef.split("\\.\\."); - Long min; - Long max; - if (splittedRangeDef.length == 1) { - min = max = parseRangeValue(splittedRangeDef[0]); - } else { - min = parseRangeValue(splittedRangeDef[0]); - max = parseRangeValue(splittedRangeDef[1]); - } - LengthConstraint range = BaseConstraints.lengthConstraint(min, max, - description, reference); - lengthConstraints.add(range); - } - - return lengthConstraints; - } - - private static Long parseRangeValue(String value) { - Long result = null; - if (value.equals("min")) { - result = Long.MIN_VALUE; - } else if (value.equals("max")) { - result = Long.MAX_VALUE; - } else { - result = Long.valueOf(value); - } - return result; - } - - private static List getPatternConstraint( - Type_body_stmtsContext ctx) { - List patterns = new ArrayList(); - - out: for (int j = 0; j < ctx.getChildCount(); j++) { - ParseTree stringRestrChild = ctx.getChild(j); - if (stringRestrChild instanceof String_restrictionsContext) { - for (int k = 0; k < stringRestrChild.getChildCount(); k++) { - ParseTree lengthChild = stringRestrChild.getChild(k); - if (lengthChild instanceof Pattern_stmtContext) { - patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild)); - if (k == lengthChild.getChildCount() - 1) { - break out; - } - } - } - } - } - return patterns; - } - - /** - * Internal helper method. - * - * @param ctx - * pattern context - * @return PatternConstraint object - */ - private static PatternConstraint parsePatternConstraint( - Pattern_stmtContext ctx) { - String description = null; - String reference = null; - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Description_stmtContext) { - description = stringFromNode(child); - } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); - } - } - String pattern = patternStringFromNode(ctx); - return BaseConstraints.patternConstraint(pattern, description, - reference); - } - - public static String patternStringFromNode(final Pattern_stmtContext treeNode) { - String result = ""; - for (int i = 0; i < treeNode.getChildCount(); ++i) { - ParseTree child = treeNode.getChild(i); - if (child instanceof StringContext) { - for(int j = 0; j < child.getChildCount(); j++) { - if(j % 2 == 0) { - String patternToken = child.getChild(j).getText(); - result += patternToken.substring(1, patternToken.length()-1); - } - } - } - } - return result; - } - - private static Integer getFractionDigits(Type_body_stmtsContext ctx) { - for (int j = 0; j < ctx.getChildCount(); j++) { - ParseTree dec64specChild = ctx.getChild(j); - if (dec64specChild instanceof Decimal64_specificationContext) { - return parseFractionDigits((Decimal64_specificationContext) dec64specChild); - } - } - return null; - } - - private static Integer parseFractionDigits( - Decimal64_specificationContext ctx) { - for (int k = 0; k < ctx.getChildCount(); k++) { - ParseTree fdChild = ctx.getChild(k); - if (fdChild instanceof Fraction_digits_stmtContext) { - return Integer.valueOf(stringFromNode(fdChild)); - } - } - return null; - } - - private static List getBits( - Type_body_stmtsContext ctx, List actualPath, URI namespace, - Date revision, String prefix) { - List bits = new ArrayList(); - for (int j = 0; j < ctx.getChildCount(); j++) { - ParseTree bitsSpecChild = ctx.getChild(j); - if (bitsSpecChild instanceof Bits_specificationContext) { - for (int k = 0; k < bitsSpecChild.getChildCount(); k++) { - ParseTree bitChild = bitsSpecChild.getChild(k); - if (bitChild instanceof Bit_stmtContext) { - bits.add(parseBit((Bit_stmtContext) bitChild, - actualPath, namespace, revision, prefix)); - } - } - } - } - return bits; - } - - private static boolean isRequireInstance(Type_body_stmtsContext ctx) { - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Require_instance_stmtContext) { - for (int j = 0; j < child.getChildCount(); j++) { - ParseTree reqArg = child.getChild(j); - if (reqArg instanceof Require_instance_argContext) { - return Boolean.valueOf(stringFromNode(reqArg)); - } - } - } - } - return false; - } - - private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, - List actualPath, final URI namespace, final Date revision, - final String prefix) { - String name = stringFromNode(ctx); - final QName qname = new QName(namespace, revision, prefix, name); - Long position = null; - - String description = null; - String reference = null; - Status status = Status.CURRENT; - - Stack bitPath = new Stack(); - bitPath.addAll(actualPath); - bitPath.add(name); - - SchemaPath schemaPath = createActualSchemaPath(bitPath, namespace, - revision, prefix); - - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Position_stmtContext) { - String positionStr = stringFromNode(child); - position = Long.valueOf(positionStr); - if (position < 0 || position > 4294967295L) { - throw new IllegalArgumentException( - "position value MUST be in the range 0 to 4294967295, but was: " - + position); - } - } else if (child instanceof Description_stmtContext) { - description = stringFromNode(child); - } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); - } else if (child instanceof Status_stmtContext) { - status = parseStatus((Status_stmtContext) child); - } - } - - // TODO: extensionDefinitions - return createBit(qname, schemaPath, description, reference, status, - null, position); - } - - private static BitsTypeDefinition.Bit createBit(final QName qname, - final SchemaPath schemaPath, final String description, - final String reference, final Status status, - final List extensionDefinitions, - final Long position) { - return new BitsTypeDefinition.Bit() { - - @Override - public QName getQName() { - return qname; - } - - @Override - public SchemaPath getPath() { - return schemaPath; - } - - @Override - public String getDescription() { - return description; - } - - @Override - public String getReference() { - return reference; - } - - @Override - public Status getStatus() { - return status; - } - - @Override - public List getUnknownSchemaNodes() { - return extensionDefinitions; - } - - @Override - public Long getPosition() { - return position; - } - - @Override - public String getName() { - return qname.getLocalName(); - } - - @Override - public int hashCode() { - final int prime = 31; - int result = 1; - result = prime * result - + ((qname == null) ? 0 : qname.hashCode()); - result = prime * result - + ((schemaPath == null) ? 0 : schemaPath.hashCode()); - result = prime * result - + ((description == null) ? 0 : description.hashCode()); - result = prime * result - + ((reference == null) ? 0 : reference.hashCode()); - result = prime * result - + ((status == null) ? 0 : status.hashCode()); - result = prime * result - + ((position == null) ? 0 : position.hashCode()); - result = prime - * result - + ((extensionDefinitions == null) ? 0 - : extensionDefinitions.hashCode()); - return result; - } - - @Override - public boolean equals(Object obj) { - if (this == obj) { - return true; - } - if (obj == null) { - return false; - } - if (getClass() != obj.getClass()) { - return false; - } - Bit other = (Bit) obj; - if (qname == null) { - if (other.getQName() != null) { - return false; - } - } else if (!qname.equals(other.getQName())) { - return false; - } - if (schemaPath == null) { - if (other.getPath() != null) { - return false; - } - } else if (!schemaPath.equals(other.getPath())) { - return false; - } - if (description == null) { - if (other.getDescription() != null) { - return false; - } - } else if (!description.equals(other.getDescription())) { - return false; - } - if (reference == null) { - if (other.getReference() != null) { - return false; - } - } else if (!reference.equals(other.getReference())) { - return false; - } - if (status == null) { - if (other.getStatus() != null) { - return false; - } - } else if (!status.equals(other.getStatus())) { - return false; - } - if (extensionDefinitions == null) { - if (other.getUnknownSchemaNodes() != null) { - return false; - } - } else if (!extensionDefinitions.equals(other - .getUnknownSchemaNodes())) { - return false; - } - if (position == null) { - if (other.getPosition() != null) { - return false; - } - } else if (!position.equals(other.getPosition())) { - return false; - } - return true; - } - - @Override - public String toString() { - return Bit.class.getSimpleName() + "[name=" - + qname.getLocalName() + ", position=" + position + "]"; - } - }; - } - - /** - * Parse orderedby statement. - * - * @param childNode - * Ordered_by_stmtContext - * @return true, if orderedby contains value 'user' or false otherwise - */ - public static boolean parseUserOrdered(Ordered_by_stmtContext childNode) { - boolean result = false; - for (int j = 0; j < childNode.getChildCount(); j++) { - ParseTree orderArg = childNode.getChild(j); - if (orderArg instanceof Ordered_by_argContext) { - String orderStr = stringFromNode(orderArg); - if (orderStr.equals("system")) { - result = false; - } else if (orderStr.equals("user")) { - result = true; - } else { - logger.warn("Invalid 'orderedby' statement."); - } - } - } - return result; - } - - /** - * Parse given config context and return true if it contains string 'true', - * false otherwise. - * - * @param ctx - * config context to parse. - * @return true if given context contains string 'true', false otherwise - */ - public static boolean parseConfig(final Config_stmtContext ctx) { - if (ctx != null) { - for (int i = 0; i < ctx.getChildCount(); ++i) { - final ParseTree configContext = ctx.getChild(i); - if (configContext instanceof Config_argContext) { - final String value = stringFromNode(configContext); - if (value.equals("true")) { - return true; - } - } - } - } - return false; - } - - /** - * Parse given type body and creates UnknownType definition. - * - * @param typedefQName - * qname of current type - * @param ctx - * type body - * @return UnknownType object with constraints from parsed type body - */ - public static TypeDefinition parseUnknownTypeBody(QName typedefQName, - Type_body_stmtsContext ctx) { - UnknownType.Builder ut = new UnknownType.Builder(typedefQName); - - if (ctx != null) { - List rangeStatements = getRangeConstraints(ctx); - List lengthStatements = getLengthConstraints(ctx); - List patternStatements = getPatternConstraint(ctx); - Integer fractionDigits = getFractionDigits(ctx); - - ut.rangeStatements(rangeStatements); - ut.lengthStatements(lengthStatements); - ut.patterns(patternStatements); - ut.fractionDigits(fractionDigits); - } - - return ut.build(); - } - - /** - * Create TypeDefinition object based on given type name and type body. - * - * @param typeName - * name of type - * @param typeBody - * type body - * @param actualPath - * current path in schema - * @param namespace - * current namespace - * @param revision - * current revision - * @param prefix - * current prefix - * @return TypeDefinition object based on parsed values. - */ - public static TypeDefinition parseTypeBody(String typeName, - Type_body_stmtsContext typeBody, List actualPath, - URI namespace, Date revision, String prefix) { - TypeDefinition type = null; - - List rangeStatements = getRangeConstraints(typeBody); - Integer fractionDigits = getFractionDigits(typeBody); - List lengthStatements = getLengthConstraints(typeBody); - List patternStatements = getPatternConstraint(typeBody); - List enumConstants = getEnumConstants(typeBody, actualPath, namespace, revision, prefix); - - if (typeName.equals("decimal64")) { - type = YangTypesConverter.javaTypeForBaseYangDecimal64Type( - rangeStatements, fractionDigits); - } else if (typeName.startsWith("int")) { - type = YangTypesConverter.javaTypeForBaseYangSignedIntegerType(typeName, - rangeStatements); - } else if(typeName.startsWith("uint")) { - type = YangTypesConverter.javaTypeForBaseYangUnsignedIntegerType(typeName, - rangeStatements); - } else if (typeName.equals("enumeration")) { - type = new EnumerationType(enumConstants); - } else if (typeName.equals("string")) { - type = new StringType(lengthStatements, patternStatements); - } else if (typeName.equals("bits")) { - type = new BitsType(getBits(typeBody, actualPath, namespace, - revision, prefix)); - } else if (typeName.equals("leafref")) { - final String path = parseLeafrefPath(typeBody); - final boolean absolute = path.startsWith("/"); - RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, - absolute); - type = new Leafref(actualPath, namespace, revision, xpath); - } else if (typeName.equals("binary")) { - type = new BinaryType(null, lengthStatements, null); - } else if (typeName.equals("instance-identifier")) { - boolean requireInstance = isRequireInstance(typeBody); - type = new InstanceIdentifier(null, requireInstance); - } - return type; - } - - private static String parseLeafrefPath(Type_body_stmtsContext ctx) { - for (int i = 0; i < ctx.getChildCount(); i++) { - ParseTree child = ctx.getChild(i); - if (child instanceof Leafref_specificationContext) { - for (int j = 0; j < child.getChildCount(); j++) { - ParseTree leafRefSpec = child.getChild(j); - if (leafRefSpec instanceof Path_stmtContext) { - return stringFromNode(leafRefSpec); - } - } - } - } - return null; - } - - /** - * Internal helper method for parsing Must_stmtContext. - * - * @param ctx - * Must_stmtContext - * @return an array of strings with following fields: [0] must text [1] - * description [2] reference - */ - public static String[] parseMust(YangParser.Must_stmtContext ctx) { - String[] params = new String[3]; - - String mustText = ""; - String description = null; - String reference = null; - for (int i = 0; i < ctx.getChildCount(); ++i) { - ParseTree child = ctx.getChild(i); - if (child instanceof StringContext) { - final StringContext context = (StringContext) child; - for (int j = 0; j < context.getChildCount(); j++) { - String mustPart = context.getChild(j).getText(); - if (j == 0) { - mustText += mustPart - .substring(0, mustPart.length() - 1); - continue; - } - if (j % 2 == 0) { - mustText += mustPart.substring(1); - } - } - } else if (child instanceof Description_stmtContext) { - description = stringFromNode(child); - } else if (child instanceof Reference_stmtContext) { - reference = stringFromNode(child); - } - } - params[0] = mustText; - params[1] = description; - params[2] = reference; - - return params; - } - - /** - * Parse given tree and set constraints to given builder. - * - * @param ctx - * Context to search. - * @param constraintsBuilder - * ConstraintsBuilder to fill. - */ - public static void parseConstraints(ParseTree ctx, - ConstraintsBuilder constraintsBuilder) { - for (int i = 0; i < ctx.getChildCount(); ++i) { - final ParseTree childNode = ctx.getChild(i); - if (childNode instanceof Max_elements_stmtContext) { - Integer max = Integer.valueOf(stringFromNode(childNode)); - constraintsBuilder.setMinElements(max); - } else if (childNode instanceof Min_elements_stmtContext) { - Integer min = Integer.valueOf(stringFromNode(childNode)); - constraintsBuilder.setMinElements(min); - } else if (childNode instanceof Must_stmtContext) { - String[] mustParams = parseMust((Must_stmtContext) childNode); - constraintsBuilder.addMustDefinition(mustParams[0], - mustParams[1], mustParams[2]); - } else if (childNode instanceof Mandatory_stmtContext) { - for (int j = 0; j < childNode.getChildCount(); j++) { - ParseTree mandatoryTree = ctx.getChild(j); - if (mandatoryTree instanceof Mandatory_argContext) { - Boolean mandatory = Boolean - .valueOf(stringFromNode(mandatoryTree)); - constraintsBuilder.setMandatory(mandatory); - } - } - } else if (childNode instanceof When_stmtContext) { - constraintsBuilder.addWhenCondition(stringFromNode(childNode)); - } - } - } - -} +/* + * 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/eplv10.html + */ +package org.opendaylight.controller.yang.model.parser.util; + +import java.net.URI; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Stack; + +import org.antlr.v4.runtime.tree.ParseTree; +import org.opendaylight.controller.antlrv4.code.gen.YangParser; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Argument_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bit_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Bits_specificationContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_argContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Config_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Decimal64_specificationContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Description_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_specificationContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Enum_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Fraction_digits_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Leafref_specificationContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Length_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_argContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Mandatory_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Max_elements_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Min_elements_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Must_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Numerical_restrictionsContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_argContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Ordered_by_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Path_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Pattern_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Position_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Range_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Reference_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_argContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Require_instance_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_argContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Status_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.StringContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.String_restrictionsContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Type_body_stmtsContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Units_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.When_stmtContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_argContext; +import org.opendaylight.controller.antlrv4.code.gen.YangParser.Yin_element_stmtContext; +import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.model.api.RevisionAwareXPath; +import org.opendaylight.controller.yang.model.api.SchemaPath; +import org.opendaylight.controller.yang.model.api.Status; +import org.opendaylight.controller.yang.model.api.TypeDefinition; +import org.opendaylight.controller.yang.model.api.UnknownSchemaNode; +import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition; +import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit; +import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition; +import org.opendaylight.controller.yang.model.api.type.LengthConstraint; +import org.opendaylight.controller.yang.model.api.type.PatternConstraint; +import org.opendaylight.controller.yang.model.api.type.RangeConstraint; +import org.opendaylight.controller.yang.model.parser.builder.api.SchemaNodeBuilder; +import org.opendaylight.controller.yang.model.parser.builder.impl.ConstraintsBuilder; +import org.opendaylight.controller.yang.model.util.BaseConstraints; +import org.opendaylight.controller.yang.model.util.BinaryType; +import org.opendaylight.controller.yang.model.util.BitsType; +import org.opendaylight.controller.yang.model.util.EnumerationType; +import org.opendaylight.controller.yang.model.util.InstanceIdentifier; +import org.opendaylight.controller.yang.model.util.Leafref; +import org.opendaylight.controller.yang.model.util.RevisionAwareXPathImpl; +import org.opendaylight.controller.yang.model.util.StringType; +import org.opendaylight.controller.yang.model.util.UnknownType; +import org.opendaylight.controller.yang.model.util.YangTypesConverter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class YangModelBuilderUtil { + + private static final Logger logger = LoggerFactory + .getLogger(YangModelBuilderUtil.class); + + /** + * Parse given tree and get first string value. + * + * @param treeNode + * tree to parse + * @return first string value from given tree + */ + public static String stringFromNode(final ParseTree treeNode) { + final String result = ""; + for (int i = 0; i < treeNode.getChildCount(); ++i) { + if (treeNode.getChild(i) instanceof StringContext) { + final StringContext context = (StringContext) treeNode + .getChild(i); + if (context != null) { + return context.getChild(0).getText().replace("\"", ""); + } + } + } + return result; + } + + /** + * Parse 'description', 'reference' and 'status' statements and fill in + * given builder. + * + * @param ctx + * context to parse + * @param builder + * builder to fill in with parsed statements + */ + public static void parseSchemaNodeArgs(ParseTree ctx, + SchemaNodeBuilder builder) { + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Description_stmtContext) { + String desc = stringFromNode(child); + builder.setDescription(desc); + } else if (child instanceof Reference_stmtContext) { + String ref = stringFromNode(child); + builder.setReference(ref); + } else if (child instanceof Status_stmtContext) { + Status status = parseStatus((Status_stmtContext) child); + builder.setStatus(status); + } + } + } + + /** + * Parse given context and return its value; + * + * @param ctx + * status context + * @return value parsed from context + */ + public static Status parseStatus(Status_stmtContext ctx) { + Status result = null; + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree statusArg = ctx.getChild(i); + if (statusArg instanceof Status_argContext) { + String statusArgStr = stringFromNode(statusArg); + if ("current".equals(statusArgStr)) { + result = Status.CURRENT; + } else if ("deprecated".equals(statusArgStr)) { + result = Status.DEPRECATED; + } else if ("obsolete".equals(statusArgStr)) { + result = Status.OBSOLETE; + } else { + logger.warn("Invalid 'status' statement: " + statusArgStr); + } + } + } + return result; + } + + /** + * Parse given tree and returns units statement as string. + * + * @param ctx + * context to parse + * @return value of units statement as string or null if there is no units + * statement + */ + public static String parseUnits(ParseTree ctx) { + String units = null; + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Units_stmtContext) { + units = stringFromNode(child); + break; + } + } + return units; + } + + /** + * Create SchemaPath object from given path list with namespace, revision + * and prefix based on given values. + * + * @param actualPath + * current position in model + * @param namespace + * @param revision + * @param prefix + * @return SchemaPath object. + */ + public static SchemaPath createActualSchemaPath(List actualPath, + URI namespace, Date revision, String prefix) { + final List path = new ArrayList(); + QName qname; + // start from index 1 - module name ommited + for (int i = 1; i < actualPath.size(); i++) { + qname = new QName(namespace, revision, prefix, actualPath.get(i)); + path.add(qname); + } + return new SchemaPath(path, true); + } + + /** + * Create SchemaPath from given string. + * + * @param augmentPath + * string representation of path + * @return SchemaPath object + */ + public static SchemaPath parseAugmentPath(String augmentPath) { + boolean absolute = augmentPath.startsWith("/"); + String[] splittedPath = augmentPath.split("/"); + List path = new ArrayList(); + QName name; + for (String pathElement : splittedPath) { + if (pathElement.length() > 0) { + String[] splittedElement = pathElement.split(":"); + if (splittedElement.length == 1) { + name = new QName(null, null, null, splittedElement[0]); + } else { + name = new QName(null, null, splittedElement[0], + splittedElement[1]); + } + path.add(name); + } + } + return new SchemaPath(path, absolute); + } + + /** + * Create java.util.List of QName objects from given key definition as + * string. + * + * @param keyDefinition + * key definition as string + * @param namespace + * current namespace + * @param revision + * current revision + * @param prefix + * current prefix + * @return YANG list key as java.util.List of QName objects + */ + public static List createListKey(String keyDefinition, + URI namespace, Date revision, String prefix) { + List key = new ArrayList(); + String[] splittedKey = keyDefinition.split(" "); + + QName qname = null; + for (String keyElement : splittedKey) { + if (keyElement.length() != 0) { + qname = new QName(namespace, revision, prefix, keyElement); + key.add(qname); + } + } + return key; + } + + private static List getEnumConstants( + Type_body_stmtsContext ctx, List path, URI namespace, + Date revision, String prefix) { + List enumConstants = new ArrayList(); + + out: for (int j = 0; j < ctx.getChildCount(); j++) { + ParseTree enumSpecChild = ctx.getChild(j); + if (enumSpecChild instanceof Enum_specificationContext) { + for (int k = 0; k < enumSpecChild.getChildCount(); k++) { + ParseTree enumChild = enumSpecChild.getChild(k); + if (enumChild instanceof Enum_stmtContext) { + enumConstants.add(createEnumPair( + (Enum_stmtContext) enumChild, k, path, + namespace, revision, prefix)); + if (k == enumSpecChild.getChildCount() - 1) { + break out; + } + } + } + } + } + return enumConstants; + } + + private static EnumTypeDefinition.EnumPair createEnumPair( + Enum_stmtContext ctx, final int value, List path, + final URI namespace, final Date revision, final String prefix) { + final String name = stringFromNode(ctx); + final QName qname = new QName(namespace, revision, prefix, name); + String description = null; + String reference = null; + Status status = null; + List enumPairPath = new ArrayList(path); + enumPairPath.add(name); + + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Description_stmtContext) { + description = stringFromNode(child); + } else if (child instanceof Reference_stmtContext) { + reference = stringFromNode(child); + } else if (child instanceof Status_stmtContext) { + status = parseStatus((Status_stmtContext) child); + } + } + + EnumPairImpl result = new EnumPairImpl(); + result.qname = qname; + result.path = createActualSchemaPath(enumPairPath, namespace, revision, + prefix); + result.description = description; + result.reference = reference; + result.status = status; + result.name = name; + result.value = value; + return result; + } + + private static class EnumPairImpl implements EnumTypeDefinition.EnumPair { + private QName qname; + private SchemaPath path; + private String description; + private String reference; + private Status status; + private List extensionSchemaNodes = Collections + .emptyList(); + private String name; + private Integer value; + + @Override + public QName getQName() { + return qname; + } + + @Override + public SchemaPath getPath() { + return path; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getReference() { + return reference; + } + + @Override + public Status getStatus() { + return status; + } + + @Override + public List getUnknownSchemaNodes() { + return extensionSchemaNodes; + } + + @Override + public String getName() { + return name; + } + + @Override + public Integer getValue() { + return value; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((qname == null) ? 0 : qname.hashCode()); + result = prime * result + ((path == null) ? 0 : path.hashCode()); + result = prime + * result + + ((extensionSchemaNodes == null) ? 0 + : extensionSchemaNodes.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + ((value == null) ? 0 : value.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + EnumPairImpl other = (EnumPairImpl) obj; + if (qname == null) { + if (other.qname != null) { + return false; + } + } else if (!qname.equals(other.qname)) { + return false; + } + if (path == null) { + if (other.path != null) { + return false; + } + } else if (!path.equals(other.path)) { + return false; + } + if (extensionSchemaNodes == null) { + if (other.extensionSchemaNodes != null) { + return false; + } + } else if (!extensionSchemaNodes.equals(other.extensionSchemaNodes)) { + return false; + } + if (name == null) { + if (other.name != null) { + return false; + } + } else if (!name.equals(other.name)) { + return false; + } + if (value == null) { + if (other.value != null) { + return false; + } + } else if (!value.equals(other.value)) { + return false; + } + return true; + } + + @Override + public String toString() { + return EnumTypeDefinition.EnumPair.class.getSimpleName() + "[name=" + + name + ", value=" + value + "]"; + } + }; + + private static List getRangeConstraints( + Type_body_stmtsContext ctx) { + final List rangeConstraints = new ArrayList(); + for (int j = 0; j < ctx.getChildCount(); j++) { + ParseTree numRestrChild = ctx.getChild(j); + if (numRestrChild instanceof Numerical_restrictionsContext) { + for (int k = 0; k < numRestrChild.getChildCount(); k++) { + ParseTree rangeChild = numRestrChild.getChild(k); + if (rangeChild instanceof Range_stmtContext) { + rangeConstraints + .addAll(parseRangeConstraints((Range_stmtContext) rangeChild)); + break; + } + } + } + } + return rangeConstraints; + } + + private static List parseRangeConstraints( + Range_stmtContext ctx) { + List rangeConstraints = new ArrayList(); + String description = null; + String reference = null; + + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Description_stmtContext) { + description = stringFromNode(child); + } else if (child instanceof Reference_stmtContext) { + reference = stringFromNode(child); + } + } + + String rangeStr = stringFromNode(ctx); + String trimmed = rangeStr.replace(" ", ""); + String[] splittedRange = trimmed.split("\\|"); + for (String rangeDef : splittedRange) { + String[] splittedRangeDef = rangeDef.split("\\.\\."); + Number min; + Number max; + if (splittedRangeDef.length == 1) { + min = max = parseRangeValue(splittedRangeDef[0]); + } else { + min = parseRangeValue(splittedRangeDef[0]); + max = parseRangeValue(splittedRangeDef[1]); + } + RangeConstraint range = BaseConstraints.rangeConstraint(min, max, + description, reference); + rangeConstraints.add(range); + } + + return rangeConstraints; + } + + private static List getLengthConstraints( + Type_body_stmtsContext ctx) { + List lengthConstraints = new ArrayList(); + for (int j = 0; j < ctx.getChildCount(); j++) { + ParseTree stringRestrChild = ctx.getChild(j); + if (stringRestrChild instanceof String_restrictionsContext) { + for (int k = 0; k < stringRestrChild.getChildCount(); k++) { + ParseTree lengthChild = stringRestrChild.getChild(k); + if (lengthChild instanceof Length_stmtContext) { + lengthConstraints + .addAll(parseLengthConstraints((Length_stmtContext) lengthChild)); + } + } + } + } + return lengthConstraints; + } + + private static List parseLengthConstraints( + Length_stmtContext ctx) { + List lengthConstraints = new ArrayList(); + String description = null; + String reference = null; + + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Description_stmtContext) { + description = stringFromNode(child); + } else if (child instanceof Reference_stmtContext) { + reference = stringFromNode(child); + } + } + + String lengthStr = stringFromNode(ctx); + String trimmed = lengthStr.replace(" ", ""); + String[] splittedRange = trimmed.split("\\|"); + for (String rangeDef : splittedRange) { + String[] splittedRangeDef = rangeDef.split("\\.\\."); + Number min; + Number max; + if (splittedRangeDef.length == 1) { + min = max = parseRangeValue(splittedRangeDef[0]); + } else { + min = parseRangeValue(splittedRangeDef[0]); + max = parseRangeValue(splittedRangeDef[1]); + } + LengthConstraint range = BaseConstraints.lengthConstraint(min, max, + description, reference); + lengthConstraints.add(range); + } + + return lengthConstraints; + } + + private static Number parseRangeValue(String value) { + Number result = null; + if ("min".equals(value) || "max".equals(value)) { + result = new UnknownBoundaryNumber(value); + } else { + try { + result = Long.valueOf(value); + } catch (NumberFormatException e) { + throw new YangParseException("Unable to parse range value '" + + value + "'.", e); + } + } + return result; + } + + private static List getPatternConstraint( + Type_body_stmtsContext ctx) { + List patterns = new ArrayList(); + + out: for (int j = 0; j < ctx.getChildCount(); j++) { + ParseTree stringRestrChild = ctx.getChild(j); + if (stringRestrChild instanceof String_restrictionsContext) { + for (int k = 0; k < stringRestrChild.getChildCount(); k++) { + ParseTree lengthChild = stringRestrChild.getChild(k); + if (lengthChild instanceof Pattern_stmtContext) { + patterns.add(parsePatternConstraint((Pattern_stmtContext) lengthChild)); + if (k == lengthChild.getChildCount() - 1) { + break out; + } + } + } + } + } + return patterns; + } + + /** + * Internal helper method. + * + * @param ctx + * pattern context + * @return PatternConstraint object + */ + private static PatternConstraint parsePatternConstraint( + Pattern_stmtContext ctx) { + String description = null; + String reference = null; + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Description_stmtContext) { + description = stringFromNode(child); + } else if (child instanceof Reference_stmtContext) { + reference = stringFromNode(child); + } + } + String pattern = patternStringFromNode(ctx); + return BaseConstraints.patternConstraint(pattern, description, + reference); + } + + /** + * Parse given context and return pattern value. + * + * @param ctx + * context to parse + * @return pattern value as String + */ + public static String patternStringFromNode(final Pattern_stmtContext ctx) { + StringBuilder result = new StringBuilder(); + for (int i = 0; i < ctx.getChildCount(); ++i) { + ParseTree child = ctx.getChild(i); + if (child instanceof StringContext) { + for (int j = 0; j < child.getChildCount(); j++) { + if (j % 2 == 0) { + String patternToken = child.getChild(j).getText(); + result.append(patternToken.substring(1, + patternToken.length() - 1)); + } + } + } + } + return result.toString(); + } + + private static Integer getFractionDigits(Type_body_stmtsContext ctx) { + Integer result = null; + for (int j = 0; j < ctx.getChildCount(); j++) { + ParseTree dec64specChild = ctx.getChild(j); + if (dec64specChild instanceof Decimal64_specificationContext) { + result = parseFractionDigits((Decimal64_specificationContext) dec64specChild); + } + } + return result; + } + + private static Integer parseFractionDigits( + Decimal64_specificationContext ctx) { + Integer result = null; + for (int k = 0; k < ctx.getChildCount(); k++) { + ParseTree fdChild = ctx.getChild(k); + if (fdChild instanceof Fraction_digits_stmtContext) { + String value = stringFromNode(fdChild); + try { + result = Integer.valueOf(value); + } catch (NumberFormatException e) { + throw new YangParseException( + "Unable to parse fraction digits value '" + value + + "'.", e); + } + } + } + return result; + } + + private static List getBits( + Type_body_stmtsContext ctx, List actualPath, URI namespace, + Date revision, String prefix) { + List bits = new ArrayList(); + for (int j = 0; j < ctx.getChildCount(); j++) { + ParseTree bitsSpecChild = ctx.getChild(j); + if (bitsSpecChild instanceof Bits_specificationContext) { + long highestPosition = -1; + for (int k = 0; k < bitsSpecChild.getChildCount(); k++) { + ParseTree bitChild = bitsSpecChild.getChild(k); + if (bitChild instanceof Bit_stmtContext) { + Bit bit = parseBit((Bit_stmtContext) bitChild, + highestPosition, actualPath, namespace, + revision, prefix); + if (bit.getPosition() > highestPosition) { + highestPosition = bit.getPosition(); + } + bits.add(bit); + } + } + } + } + return bits; + } + + private static BitsTypeDefinition.Bit parseBit(final Bit_stmtContext ctx, + long highestPosition, List actualPath, final URI namespace, + final Date revision, final String prefix) { + String name = stringFromNode(ctx); + final QName qname = new QName(namespace, revision, prefix, name); + Long position = null; + + String description = null; + String reference = null; + Status status = Status.CURRENT; + + Stack bitPath = new Stack(); + bitPath.addAll(actualPath); + bitPath.add(name); + + SchemaPath schemaPath = createActualSchemaPath(bitPath, namespace, + revision, prefix); + + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Position_stmtContext) { + String positionStr = stringFromNode(child); + position = Long.valueOf(positionStr); + } else if (child instanceof Description_stmtContext) { + description = stringFromNode(child); + } else if (child instanceof Reference_stmtContext) { + reference = stringFromNode(child); + } else if (child instanceof Status_stmtContext) { + status = parseStatus((Status_stmtContext) child); + } + } + + if (position == null) { + position = highestPosition + 1; + } + if (position < 0 || position > 4294967295L) { + throw new YangParseException( + "Error on bit '" + + name + + "': the position value MUST be in the range 0 to 4294967295"); + } + + final List extensionNodes = Collections.emptyList(); + return createBit(qname, schemaPath, description, reference, status, + extensionNodes, position); + } + + private static BitsTypeDefinition.Bit createBit(final QName qname, + final SchemaPath schemaPath, final String description, + final String reference, final Status status, + final List unknownNodes, final Long position) { + return new BitsTypeDefinition.Bit() { + + @Override + public QName getQName() { + return qname; + } + + @Override + public SchemaPath getPath() { + return schemaPath; + } + + @Override + public String getDescription() { + return description; + } + + @Override + public String getReference() { + return reference; + } + + @Override + public Status getStatus() { + return status; + } + + @Override + public List getUnknownSchemaNodes() { + return unknownNodes; + } + + @Override + public Long getPosition() { + return position; + } + + @Override + public String getName() { + return qname.getLocalName(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + + ((qname == null) ? 0 : qname.hashCode()); + result = prime * result + + ((schemaPath == null) ? 0 : schemaPath.hashCode()); + result = prime * result + + ((position == null) ? 0 : position.hashCode()); + result = prime + * result + + ((unknownNodes == null) ? 0 : unknownNodes.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + Bit other = (Bit) obj; + if (qname == null) { + if (other.getQName() != null) { + return false; + } + } else if (!qname.equals(other.getQName())) { + return false; + } + if (schemaPath == null) { + if (other.getPath() != null) { + return false; + } + } else if (!schemaPath.equals(other.getPath())) { + return false; + } + if (unknownNodes == null) { + if (other.getUnknownSchemaNodes() != null) { + return false; + } + } else if (!unknownNodes.equals(other.getUnknownSchemaNodes())) { + return false; + } + if (position == null) { + if (other.getPosition() != null) { + return false; + } + } else if (!position.equals(other.getPosition())) { + return false; + } + return true; + } + + @Override + public String toString() { + return Bit.class.getSimpleName() + "[name=" + + qname.getLocalName() + ", position=" + position + "]"; + } + }; + } + + /** + * Parse orderedby statement. + * + * @param childNode + * Ordered_by_stmtContext + * @return true, if orderedby contains value 'user' or false otherwise + */ + public static boolean parseUserOrdered(Ordered_by_stmtContext childNode) { + boolean result = false; + for (int j = 0; j < childNode.getChildCount(); j++) { + ParseTree orderArg = childNode.getChild(j); + if (orderArg instanceof Ordered_by_argContext) { + String orderStr = stringFromNode(orderArg); + if ("system".equals(orderStr)) { + result = false; + } else if ("user".equals(orderStr)) { + result = true; + } else { + logger.warn("Invalid 'orderedby' statement."); + } + } + } + return result; + } + + /** + * Parse given config context and return true if it contains string 'true', + * false otherwise. + * + * @param ctx + * config context to parse. + * @return true if given context contains string 'true', false otherwise + */ + public static boolean parseConfig(final Config_stmtContext ctx) { + boolean result = false; + if (ctx != null) { + for (int i = 0; i < ctx.getChildCount(); ++i) { + final ParseTree configContext = ctx.getChild(i); + if (configContext instanceof Config_argContext) { + final String value = stringFromNode(configContext); + if ("true".equals(value)) { + result = true; + break; + } + } + } + } + return result; + } + + /** + * Parse given type body and creates UnknownType definition. + * + * @param typedefQName + * qname of current type + * @param ctx + * type body + * @return UnknownType object with constraints from parsed type body + */ + public static TypeDefinition parseUnknownTypeBody(QName typedefQName, + Type_body_stmtsContext ctx) { + UnknownType.Builder unknownType = new UnknownType.Builder(typedefQName); + + if (ctx != null) { + List rangeStatements = getRangeConstraints(ctx); + List lengthStatements = getLengthConstraints(ctx); + List patternStatements = getPatternConstraint(ctx); + Integer fractionDigits = getFractionDigits(ctx); + + unknownType.rangeStatements(rangeStatements); + unknownType.lengthStatements(lengthStatements); + unknownType.patterns(patternStatements); + unknownType.fractionDigits(fractionDigits); + } + + return unknownType.build(); + } + + /** + * Create TypeDefinition object based on given type name and type body. + * + * @param typeName + * name of type + * @param typeBody + * type body + * @param actualPath + * current path in schema + * @param namespace + * current namespace + * @param revision + * current revision + * @param prefix + * current prefix + * @return TypeDefinition object based on parsed values. + */ + public static TypeDefinition parseTypeBody(String typeName, + Type_body_stmtsContext typeBody, List actualPath, + URI namespace, Date revision, String prefix) { + TypeDefinition type = null; + + List rangeStatements = getRangeConstraints(typeBody); + Integer fractionDigits = getFractionDigits(typeBody); + List lengthStatements = getLengthConstraints(typeBody); + List patternStatements = getPatternConstraint(typeBody); + List enumConstants = getEnumConstants( + typeBody, actualPath, namespace, revision, prefix); + + if ("decimal64".equals(typeName)) { + type = YangTypesConverter.javaTypeForBaseYangDecimal64Type( + rangeStatements, fractionDigits); + } else if (typeName.startsWith("int")) { + type = YangTypesConverter.javaTypeForBaseYangSignedIntegerType( + typeName, rangeStatements); + } else if (typeName.startsWith("uint")) { + type = YangTypesConverter.javaTypeForBaseYangUnsignedIntegerType( + typeName, rangeStatements); + } else if ("enumeration".equals(typeName)) { + type = new EnumerationType(enumConstants); + } else if ("string".equals(typeName)) { + type = new StringType(lengthStatements, patternStatements); + } else if ("bits".equals(typeName)) { + type = new BitsType(getBits(typeBody, actualPath, namespace, + revision, prefix)); + } else if ("leafref".equals(typeName)) { + final String path = parseLeafrefPath(typeBody); + final boolean absolute = path.startsWith("/"); + RevisionAwareXPath xpath = new RevisionAwareXPathImpl(path, + absolute); + type = new Leafref(xpath); + } else if ("binary".equals(typeName)) { + List bytes = Collections.emptyList(); + type = new BinaryType(bytes, lengthStatements, null); + } else if ("instance-identifier".equals(typeName)) { + boolean requireInstance = isRequireInstance(typeBody); + type = new InstanceIdentifier(null, requireInstance); + } + return type; + } + + private static boolean isRequireInstance(Type_body_stmtsContext ctx) { + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Require_instance_stmtContext) { + for (int j = 0; j < child.getChildCount(); j++) { + ParseTree reqArg = child.getChild(j); + if (reqArg instanceof Require_instance_argContext) { + return Boolean.valueOf(stringFromNode(reqArg)); + } + } + } + } + return false; + } + + private static String parseLeafrefPath(Type_body_stmtsContext ctx) { + for (int i = 0; i < ctx.getChildCount(); i++) { + ParseTree child = ctx.getChild(i); + if (child instanceof Leafref_specificationContext) { + for (int j = 0; j < child.getChildCount(); j++) { + ParseTree leafRefSpec = child.getChild(j); + if (leafRefSpec instanceof Path_stmtContext) { + return stringFromNode(leafRefSpec); + } + } + } + } + return null; + } + + /** + * Internal helper method for parsing Must_stmtContext. + * + * @param ctx + * Must_stmtContext + * @return an array of strings with following fields: [0] must text [1] + * description [2] reference + */ + public static String[] parseMust(YangParser.Must_stmtContext ctx) { + String[] params = new String[3]; + + StringBuilder mustText = new StringBuilder(); + String description = null; + String reference = null; + for (int i = 0; i < ctx.getChildCount(); ++i) { + ParseTree child = ctx.getChild(i); + if (child instanceof StringContext) { + final StringContext context = (StringContext) child; + for (int j = 0; j < context.getChildCount(); j++) { + String mustPart = context.getChild(j).getText(); + if (j == 0) { + mustText.append(mustPart.substring(0, + mustPart.length() - 1)); + continue; + } + if (j % 2 == 0) { + mustText.append(mustPart.substring(1)); + } + } + } else if (child instanceof Description_stmtContext) { + description = stringFromNode(child); + } else if (child instanceof Reference_stmtContext) { + reference = stringFromNode(child); + } + } + params[0] = mustText.toString(); + params[1] = description; + params[2] = reference; + + return params; + } + + /** + * Parse given tree and set constraints to given builder. + * + * @param ctx + * Context to search. + * @param constraintsBuilder + * ConstraintsBuilder to fill. + */ + public static void parseConstraints(ParseTree ctx, + ConstraintsBuilder constraintsBuilder) { + for (int i = 0; i < ctx.getChildCount(); ++i) { + final ParseTree childNode = ctx.getChild(i); + if (childNode instanceof Max_elements_stmtContext) { + Integer max = Integer.valueOf(stringFromNode(childNode)); + constraintsBuilder.setMinElements(max); + } else if (childNode instanceof Min_elements_stmtContext) { + Integer min = Integer.valueOf(stringFromNode(childNode)); + constraintsBuilder.setMinElements(min); + } else if (childNode instanceof Must_stmtContext) { + String[] mustParams = parseMust((Must_stmtContext) childNode); + constraintsBuilder.addMustDefinition(mustParams[0], + mustParams[1], mustParams[2]); + } else if (childNode instanceof Mandatory_stmtContext) { + for (int j = 0; j < childNode.getChildCount(); j++) { + ParseTree mandatoryTree = ctx.getChild(j); + if (mandatoryTree instanceof Mandatory_argContext) { + Boolean mandatory = Boolean + .valueOf(stringFromNode(mandatoryTree)); + constraintsBuilder.setMandatory(mandatory); + } + } + } else if (childNode instanceof When_stmtContext) { + constraintsBuilder.addWhenCondition(stringFromNode(childNode)); + } + } + } + + /** + * Parse given context and return yin value. + * + * @param ctx + * context to parse + * @return true if value is 'true', false otherwise + */ + public static boolean parseYinValue(Argument_stmtContext ctx) { + boolean yinValue = false; + outer: for (int j = 0; j < ctx.getChildCount(); j++) { + ParseTree yin = ctx.getChild(j); + if (yin instanceof Yin_element_stmtContext) { + for (int k = 0; k < yin.getChildCount(); k++) { + ParseTree yinArg = yin.getChild(k); + if (yinArg instanceof Yin_element_argContext) { + String yinString = stringFromNode(yinArg); + if ("true".equals(yinString)) { + yinValue = true; + break outer; + } + } + } + } + } + return yinValue; + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangParseException.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangParseException.java index bc1c9d6ac2..331869a0f7 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangParseException.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/main/java/org/opendaylight/controller/yang/model/parser/util/YangParseException.java @@ -15,4 +15,8 @@ public class YangParseException extends RuntimeException { super(errorMsg); } + public YangParseException(String errorMsg, Exception exception) { + super(errorMsg, exception); + } + } diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/ContainerSchemaNodeBuilderTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/ContainerSchemaNodeBuilderTest.java deleted file mode 100644 index 709d5e3750..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/ContainerSchemaNodeBuilderTest.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * 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.yang.model.parser.builder.impl; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.when; - -import java.net.URI; -import java.util.Date; -import java.util.HashSet; -import java.util.Set; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.yang.common.QName; -import org.opendaylight.controller.yang.model.api.AugmentationSchema; -import org.opendaylight.controller.yang.model.api.ContainerSchemaNode; -import org.opendaylight.controller.yang.model.api.GroupingDefinition; -import org.opendaylight.controller.yang.model.api.SchemaPath; -import org.opendaylight.controller.yang.model.api.Status; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.UsesNode; -import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder; - -public class ContainerSchemaNodeBuilderTest { - - private ContainerSchemaNodeBuilder tested; - - private final String NAME = "test-container"; - - private final URI namespace = URI.create("test:container.name"); - private final Date revision = new Date(); - private final String prefix = "x"; - - private SchemaPath schemaPath; - private final String description = "description of container"; - private final String reference = "reference"; - - private QName typedefQName; - private TypedefBuilder typeBuilder; - @Mock - private AugmentationSchema augment; - @Mock - private UsesNodeBuilder usesBuilder; - @Mock - private UsesNode uses; - @Mock - private GroupingBuilder groupingBuilder; - @Mock - private GroupingDefinition grouping; - - @Before - public void init() { - MockitoAnnotations.initMocks(this); - when(usesBuilder.build()).thenReturn(uses); - when(groupingBuilder.build()).thenReturn(grouping); - - schemaPath = TestUtils.createSchemaPath(true, namespace, "main", - "interface"); - typedefQName = new QName(namespace, "test-type"); - typeBuilder = new TypedefBuilder(typedefQName); - - QName qname = new QName(namespace, revision, prefix, NAME); - tested = new ContainerSchemaNodeBuilder(qname); - } - - @Test - public void test() { - tested.addTypedef(typeBuilder); - tested.setPath(schemaPath); - tested.setDescription(description); - tested.setReference(reference); - tested.setStatus(Status.OBSOLETE); - tested.setConfiguration(false); - tested.addUsesNode(usesBuilder); - tested.addAugmentation(augment); - tested.setPresenceContainer(true); - - ContainerSchemaNode result = tested.build(); - - Set> expectedTypedefs = result.getTypeDefinitions(); - assertEquals(1, expectedTypedefs.size()); - assertEquals(typedefQName, expectedTypedefs.iterator().next() - .getQName()); - - Set expectedAugments = new HashSet(); - expectedAugments.add(augment); - assertEquals(expectedAugments, result.getAvailableAugmentations()); - - assertEquals(schemaPath, result.getPath()); - assertEquals(description, result.getDescription()); - assertEquals(reference, result.getReference()); - assertEquals(Status.OBSOLETE, result.getStatus()); - assertFalse(result.isConfiguration()); - - Set expectedUses = new HashSet(); - expectedUses.add(uses); - assertEquals(expectedUses, result.getUses()); - - assertTrue(result.isPresenceContainer()); - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafListSchemaNodeBuilderTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafListSchemaNodeBuilderTest.java deleted file mode 100644 index 367669f8df..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafListSchemaNodeBuilderTest.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * 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.yang.model.parser.builder.impl; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.when; - -import java.net.URI; -import java.util.Date; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.yang.common.QName; -import org.opendaylight.controller.yang.model.api.GroupingDefinition; -import org.opendaylight.controller.yang.model.api.LeafListSchemaNode; -import org.opendaylight.controller.yang.model.api.SchemaPath; -import org.opendaylight.controller.yang.model.api.Status; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.UsesNode; -import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder; - -public class LeafListSchemaNodeBuilderTest { - - private LeafListSchemaNodeBuilder tested; - - private final String NAME = "test-leaf"; - - private final URI namespace = URI.create("test:leaf.name"); - private final Date revision = new Date(); - private final String prefix = "x"; - - private SchemaPath schemaPath; - private final String description = "description of container"; - private final String reference = "reference"; - - private QName typedefQName; - private TypeDefinition type; - - @Mock - private UsesNodeBuilder usesBuilder; - @Mock - private UsesNode uses; - @Mock - private GroupingBuilder groupingBuilder; - @Mock - private GroupingDefinition grouping; - - @Before - public void init() { - MockitoAnnotations.initMocks(this); - when(usesBuilder.build()).thenReturn(uses); - when(groupingBuilder.build()).thenReturn(grouping); - - schemaPath = TestUtils.createSchemaPath(true, namespace, "main", - "interface"); - typedefQName = new QName(namespace, "test-type"); - TypedefBuilder typeBuilder = new TypedefBuilder(typedefQName); - type = typeBuilder.build(); - - QName qname = new QName(namespace, revision, prefix, NAME); - tested = new LeafListSchemaNodeBuilder(qname); - } - - @Test - public void test() { - tested.setType(type); - tested.setPath(schemaPath); - tested.setDescription(description); - tested.setReference(reference); - tested.setStatus(Status.OBSOLETE); - tested.setConfiguration(false); - - LeafListSchemaNode result = tested.build(); - - assertEquals(type, result.getType()); - assertEquals(schemaPath, result.getPath()); - assertEquals(description, result.getDescription()); - assertEquals(reference, result.getReference()); - assertEquals(Status.OBSOLETE, result.getStatus()); - assertFalse(result.isConfiguration()); - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafSchemaNodeBuilderTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafSchemaNodeBuilderTest.java deleted file mode 100644 index 622c82d4fc..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/LeafSchemaNodeBuilderTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.yang.model.parser.builder.impl; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.when; - -import java.net.URI; -import java.util.Date; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.yang.common.QName; -import org.opendaylight.controller.yang.model.api.GroupingDefinition; -import org.opendaylight.controller.yang.model.api.LeafSchemaNode; -import org.opendaylight.controller.yang.model.api.SchemaPath; -import org.opendaylight.controller.yang.model.api.Status; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.UsesNode; -import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder; - -public class LeafSchemaNodeBuilderTest { - - private LeafSchemaNodeBuilder tested; - - private final String NAME = "test-leaf"; - - private final URI namespace = URI.create("test:leaf.name"); - private final Date revision = new Date(); - private final String prefix = "x"; - - private SchemaPath schemaPath; - private final String description = "description of container"; - private final String reference = "reference"; - - private QName typedefQName; - private TypeDefinition type; - @Mock - private UsesNodeBuilder usesBuilder; - @Mock - private UsesNode uses; - @Mock - private GroupingBuilder groupingBuilder; - @Mock - private GroupingDefinition grouping; - - @Before - public void init() { - MockitoAnnotations.initMocks(this); - when(usesBuilder.build()).thenReturn(uses); - when(groupingBuilder.build()).thenReturn(grouping); - - schemaPath = TestUtils.createSchemaPath(true, namespace, "main", - "interface"); - typedefQName = new QName(namespace, "test-type"); - TypedefBuilder typeBuilder = new TypedefBuilder(typedefQName); - type = typeBuilder.build(); - - QName qname = new QName(namespace, revision, prefix, NAME); - tested = new LeafSchemaNodeBuilder(qname); - } - - @Test - public void test() { - tested.setType(type); - tested.setPath(schemaPath); - tested.setDescription(description); - tested.setReference(reference); - tested.setStatus(Status.OBSOLETE); - tested.setConfiguration(false); - - LeafSchemaNode result = tested.build(); - - assertEquals(type, result.getType()); - assertEquals(schemaPath, result.getPath()); - assertEquals(description, result.getDescription()); - assertEquals(reference, result.getReference()); - assertEquals(Status.OBSOLETE, result.getStatus()); - assertFalse(result.isConfiguration()); - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/ListSchemaNodeBuilderTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/ListSchemaNodeBuilderTest.java deleted file mode 100644 index c5f336179b..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/builder/impl/ListSchemaNodeBuilderTest.java +++ /dev/null @@ -1,118 +0,0 @@ -/* - * 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.yang.model.parser.builder.impl; - -import static org.junit.Assert.*; -import static org.mockito.Mockito.when; - -import java.net.URI; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.opendaylight.controller.yang.common.QName; -import org.opendaylight.controller.yang.model.api.AugmentationSchema; -import org.opendaylight.controller.yang.model.api.GroupingDefinition; -import org.opendaylight.controller.yang.model.api.ListSchemaNode; -import org.opendaylight.controller.yang.model.api.SchemaPath; -import org.opendaylight.controller.yang.model.api.Status; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.UsesNode; -import org.opendaylight.controller.yang.model.parser.builder.api.GroupingBuilder; -import org.opendaylight.controller.yang.model.parser.builder.api.UsesNodeBuilder; - -public class ListSchemaNodeBuilderTest { - - private ListSchemaNodeBuilder tested; - - private static final String NAME = "test-list"; - - private final URI namespace = URI.create("test:list.name"); - private final Date revision = new Date(); - private final String prefix = "x"; - - private SchemaPath schemaPath; - private final String description = "description of list"; - private final String reference = "reference"; - - private QName typedefQName; - private TypedefBuilder typeBuilder; - @Mock - private AugmentationSchema augment; - @Mock - private UsesNodeBuilder usesBuilder; - @Mock - private UsesNode uses; - @Mock - private GroupingBuilder groupingBuilder; - @Mock - private GroupingDefinition grouping; - private List keyDefinition; - - @Before - public void init() { - MockitoAnnotations.initMocks(this); - when(usesBuilder.build()).thenReturn(uses); - when(groupingBuilder.build()).thenReturn(grouping); - - schemaPath = TestUtils.createSchemaPath(true, namespace, "main", NAME); - typedefQName = new QName(namespace, "test-type"); - typeBuilder = new TypedefBuilder(typedefQName); - - keyDefinition = new ArrayList(); - keyDefinition.add(new QName(namespace, "name")); - - QName qname = new QName(namespace, revision, prefix, NAME); - tested = new ListSchemaNodeBuilder(qname); - } - - @Test - public void test() { - tested.addTypedef(typeBuilder); - tested.setPath(schemaPath); - tested.setDescription(description); - tested.setReference(reference); - tested.setStatus(Status.OBSOLETE); - tested.setConfiguration(false); - tested.addUsesNode(usesBuilder); - tested.addAugmentation(augment); - tested.setUserOrdered(true); - tested.setKeyDefinition(keyDefinition); - - ListSchemaNode result = tested.build(); - - Set> expectedTypedefs = result.getTypeDefinitions(); - assertEquals(1, expectedTypedefs.size()); - assertEquals(typedefQName, expectedTypedefs.iterator().next() - .getQName()); - - Set expectedAugments = new HashSet(); - expectedAugments.add(augment); - assertEquals(expectedAugments, result.getAvailableAugmentations()); - - assertEquals(schemaPath, result.getPath()); - assertEquals(description, result.getDescription()); - assertEquals(reference, result.getReference()); - assertEquals(Status.OBSOLETE, result.getStatus()); - assertFalse(result.isConfiguration()); - - Set expectedUses = new HashSet(); - expectedUses.add(uses); - assertEquals(expectedUses, result.getUses()); - - assertTrue(result.isUserOrdered()); - assertEquals(keyDefinition, result.getKeyDefinition()); - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/TypesResolutionTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/TypesResolutionTest.java index cad548110a..de9142e592 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/TypesResolutionTest.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/TypesResolutionTest.java @@ -1,177 +1,249 @@ -/* - * 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.yang.model.parser.impl; - -import static org.junit.Assert.*; - -import java.io.File; -import java.util.List; -import java.util.Set; - -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.yang.model.api.IdentitySchemaNode; -import org.opendaylight.controller.yang.model.api.LeafSchemaNode; -import org.opendaylight.controller.yang.model.api.Module; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair; -import org.opendaylight.controller.yang.model.api.type.LengthConstraint; -import org.opendaylight.controller.yang.model.api.type.PatternConstraint; -import org.opendaylight.controller.yang.model.parser.api.YangModelParser; -import org.opendaylight.controller.yang.model.util.EnumerationType; -import org.opendaylight.controller.yang.model.util.InstanceIdentifier; -import org.opendaylight.controller.yang.model.util.StringType; -import org.opendaylight.controller.yang.model.util.UnionType; - -public class TypesResolutionTest { - - private YangModelParser parser; - private String[] testFiles; - private Set modules; - - @Before - public void init() { - parser = new YangModelParserImpl(); - File testDir = new File("src/test/resources/types"); - String[] fileList = testDir.list(); - testFiles = new String[fileList.length]; - int i = 0; - for(String fileName : fileList) { - File file = new File(testDir, fileName); - testFiles[i] = file.getAbsolutePath(); - i++; - } - modules = parser.parseYangModels(testFiles); - assertEquals(fileList.length, modules.size()); - } - - @Test - public void testIPVersion() { - Module tested = findModule(modules, "ietf-inet-types"); - Set> typedefs = tested.getTypeDefinitions(); - assertEquals(14, typedefs.size()); - - TypeDefinition type = findTypedef(typedefs, "ip-version"); - EnumerationType en = (EnumerationType)type.getBaseType(); - List values = en.getValues(); - assertEquals(3, values.size()); - - EnumPair value0 = values.get(0); - assertEquals("unknown", value0.getName()); - assertEquals(0, (int)value0.getValue()); - - EnumPair value1 = values.get(1); - assertEquals("ipv4", value1.getName()); - assertEquals(1, (int)value1.getValue()); - - EnumPair value2 = values.get(2); - assertEquals("ipv6", value2.getName()); - assertEquals(2, (int)value2.getValue()); - } - - @Test - public void testIpAddress() { - Module tested = findModule(modules, "ietf-inet-types"); - Set> typedefs = tested.getTypeDefinitions(); - TypeDefinition type = findTypedef(typedefs, "ip-address"); - UnionType baseType = (UnionType)type.getBaseType(); - List> unionTypes = baseType.getTypes(); - - StringType ipv4 = (StringType)unionTypes.get(0); - String expectedPattern = - "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}" - + "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" - + "(%[\\p{N}\\p{L}]+)?"; - assertEquals(expectedPattern, ipv4.getPatterns().get(0).getRegularExpression()); - - StringType ipv6 = (StringType)unionTypes.get(1); - List ipv6Patterns = ipv6.getPatterns(); - expectedPattern = "((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}" - + "((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|" - + "(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}" - + "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))" - + "(%[\\p{N}\\p{L}]+)?"; - assertEquals(expectedPattern, ipv6Patterns.get(0).getRegularExpression()); - - expectedPattern = "(([^:]+:){6}(([^:]+:[^:]+)|(.*\\..*)))|" - + "((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)" - + "(%.+)?"; - assertEquals(expectedPattern, ipv6Patterns.get(1).getRegularExpression()); - } - - @Test - public void testDomainName() { - Module tested = findModule(modules, "ietf-inet-types"); - Set> typedefs = tested.getTypeDefinitions(); - TypeDefinition type = findTypedef(typedefs, "domain-name"); - StringType baseType = (StringType)type.getBaseType(); - List patterns = baseType.getPatterns(); - assertEquals(1, patterns.size()); - String expectedPattern = "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*" - + "([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)" - + "|\\."; - assertEquals(expectedPattern, patterns.get(0).getRegularExpression()); - - List lengths = baseType.getLengthStatements(); - assertEquals(1, lengths.size()); - LengthConstraint length = baseType.getLengthStatements().get(0); - assertEquals(1L, length.getMin().longValue()); - assertEquals(253L, length.getMax().longValue()); - } - - @Test - public void testInstanceIdentifier1() { - Module tested = findModule(modules, "custom-types-test"); - LeafSchemaNode leaf = (LeafSchemaNode)tested.getDataChildByName("inst-id-leaf1"); - InstanceIdentifier leafType = (InstanceIdentifier)leaf.getType(); - assertFalse(leafType.requireInstance()); - } - - @Test - public void testInstanceIdentifier2() { - Module tested = findModule(modules, "custom-types-test"); - LeafSchemaNode leaf = (LeafSchemaNode)tested.getDataChildByName("inst-id-leaf2"); - InstanceIdentifier leafType = (InstanceIdentifier)leaf.getType(); - assertTrue(leafType.requireInstance()); - } - - @Test - public void testIdentity() { - Module tested = findModule(modules, "custom-types-test"); - Set identities = tested.getIdentities(); - IdentitySchemaNode testedIdentity = null; - for(IdentitySchemaNode id : identities) { - if(id.getQName().getLocalName().equals("crypto-alg")) { - testedIdentity = id; - IdentitySchemaNode baseIdentity = id.getBaseIdentity(); - assertEquals("crypto-base", baseIdentity.getQName().getLocalName()); - assertNull(baseIdentity.getBaseIdentity()); - } - } - assertNotNull(testedIdentity); - } - - private Module findModule(Set modules, String name) { - for(Module module : modules) { - if(module.getName().equals(name)) { - return module; - } - } - return null; - } - - private TypeDefinition findTypedef(Set> typedefs, String name) { - for(TypeDefinition td : typedefs) { - if(td.getQName().getLocalName().equals(name)) { - return td; - } - } - return 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.yang.model.parser.impl; + +import static org.junit.Assert.*; + +import java.io.File; +import java.util.List; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.yang.model.api.IdentitySchemaNode; +import org.opendaylight.controller.yang.model.api.LeafSchemaNode; +import org.opendaylight.controller.yang.model.api.Module; +import org.opendaylight.controller.yang.model.api.TypeDefinition; +import org.opendaylight.controller.yang.model.api.type.BitsTypeDefinition.Bit; +import org.opendaylight.controller.yang.model.api.type.EnumTypeDefinition.EnumPair; +import org.opendaylight.controller.yang.model.api.type.LengthConstraint; +import org.opendaylight.controller.yang.model.api.type.PatternConstraint; +import org.opendaylight.controller.yang.model.parser.api.YangModelParser; +import org.opendaylight.controller.yang.model.util.BitsType; +import org.opendaylight.controller.yang.model.util.EnumerationType; +import org.opendaylight.controller.yang.model.util.ExtendedType; +import org.opendaylight.controller.yang.model.util.InstanceIdentifier; +import org.opendaylight.controller.yang.model.util.StringType; +import org.opendaylight.controller.yang.model.util.UnionType; + +public class TypesResolutionTest { + + private Set testedModules; + + @Before + public void init() { + YangModelParser parser = new YangModelParserImpl(); + File testDir = new File("src/test/resources/types"); + String[] fileList = testDir.list(); + String[] testFiles = new String[fileList.length]; + for (int i = 0; i < fileList.length; i++) { + String fileName = fileList[i]; + File file = new File(testDir, fileName); + testFiles[i] = file.getAbsolutePath(); + } + testedModules = parser.parseYangModels(testFiles); + assertEquals(fileList.length, testedModules.size()); + } + + @Test + public void testIPVersion() { + Module tested = findModule(testedModules, "ietf-inet-types"); + Set> typedefs = tested.getTypeDefinitions(); + assertEquals(14, typedefs.size()); + + TypeDefinition type = findTypedef(typedefs, "ip-version"); + assertTrue(type.getDescription().contains( + "This value represents the version of the IP protocol.")); + assertTrue(type.getReference().contains( + "RFC 2460: Internet Protocol, Version 6 (IPv6) Specification")); + + EnumerationType enumType = (EnumerationType) type.getBaseType(); + List values = enumType.getValues(); + assertEquals(3, values.size()); + + EnumPair value0 = values.get(0); + assertEquals("unknown", value0.getName()); + assertEquals(0, (int) value0.getValue()); + assertEquals( + "An unknown or unspecified version of the Internet protocol.", + value0.getDescription()); + + EnumPair value1 = values.get(1); + assertEquals("ipv4", value1.getName()); + assertEquals(1, (int) value1.getValue()); + assertEquals("The IPv4 protocol as defined in RFC 791.", + value1.getDescription()); + + EnumPair value2 = values.get(2); + assertEquals("ipv6", value2.getName()); + assertEquals(2, (int) value2.getValue()); + assertEquals("The IPv6 protocol as defined in RFC 2460.", + value2.getDescription()); + } + + @Test + public void testIpAddress() { + Module tested = findModule(testedModules, "ietf-inet-types"); + Set> typedefs = tested.getTypeDefinitions(); + TypeDefinition type = findTypedef(typedefs, "ip-address"); + UnionType baseType = (UnionType) type.getBaseType(); + List> unionTypes = baseType.getTypes(); + + ExtendedType ipv4 = (ExtendedType)unionTypes.get(0); + StringType ipv4Base = (StringType) ipv4.getBaseType(); + String expectedPattern = "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}" + + "([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])" + + "(%[\\p{N}\\p{L}]+)?"; + assertEquals(expectedPattern, ipv4Base.getPatterns().get(0) + .getRegularExpression()); + + ExtendedType ipv6 = (ExtendedType)unionTypes.get(1); + StringType ipv6Base = (StringType) ipv6.getBaseType(); + List ipv6Patterns = ipv6Base.getPatterns(); + expectedPattern = "((:|[0-9a-fA-F]{0,4}):)([0-9a-fA-F]{0,4}:){0,5}" + + "((([0-9a-fA-F]{0,4}:)?(:|[0-9a-fA-F]{0,4}))|" + + "(((25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])\\.){3}" + + "(25[0-5]|2[0-4][0-9]|[01]?[0-9]?[0-9])))" + + "(%[\\p{N}\\p{L}]+)?"; + assertEquals(expectedPattern, ipv6Patterns.get(0) + .getRegularExpression()); + + expectedPattern = "(([^:]+:){6}(([^:]+:[^:]+)|(.*\\..*)))|" + + "((([^:]+:)*[^:]+)?::(([^:]+:)*[^:]+)?)" + "(%.+)?"; + assertEquals(expectedPattern, ipv6Patterns.get(1) + .getRegularExpression()); + } + + @Test + public void testDomainName() { + Module tested = findModule(testedModules, "ietf-inet-types"); + Set> typedefs = tested.getTypeDefinitions(); + TypeDefinition type = findTypedef(typedefs, "domain-name"); + StringType baseType = (StringType) type.getBaseType(); + List patterns = baseType.getPatterns(); + assertEquals(1, patterns.size()); + String expectedPattern = "((([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.)*" + + "([a-zA-Z0-9_]([a-zA-Z0-9\\-_]){0,61})?[a-zA-Z0-9]\\.?)" + + "|\\."; + assertEquals(expectedPattern, patterns.get(0).getRegularExpression()); + + List lengths = baseType.getLengthStatements(); + assertEquals(1, lengths.size()); + LengthConstraint length = baseType.getLengthStatements().get(0); + assertEquals(1L, length.getMin()); + assertEquals(253L, length.getMax()); + } + + @Test + public void testInstanceIdentifier1() { + Module tested = findModule(testedModules, "custom-types-test"); + LeafSchemaNode leaf = (LeafSchemaNode) tested + .getDataChildByName("inst-id-leaf1"); + InstanceIdentifier leafType = (InstanceIdentifier) leaf.getType(); + assertFalse(leafType.requireInstance()); + } + + @Test + public void testInstanceIdentifier2() { + Module tested = findModule(testedModules, "custom-types-test"); + LeafSchemaNode leaf = (LeafSchemaNode) tested + .getDataChildByName("inst-id-leaf2"); + InstanceIdentifier leafType = (InstanceIdentifier) leaf.getType(); + assertTrue(leafType.requireInstance()); + } + + @Test + public void testIdentity() { + Module tested = findModule(testedModules, "custom-types-test"); + Set identities = tested.getIdentities(); + IdentitySchemaNode testedIdentity = null; + for (IdentitySchemaNode id : identities) { + if (id.getQName().getLocalName().equals("crypto-alg")) { + testedIdentity = id; + IdentitySchemaNode baseIdentity = id.getBaseIdentity(); + assertEquals("crypto-base", baseIdentity.getQName() + .getLocalName()); + assertNull(baseIdentity.getBaseIdentity()); + } + } + assertNotNull(testedIdentity); + } + + @Test + public void testBitsType1() { + Module tested = findModule(testedModules, "custom-types-test"); + LeafSchemaNode leaf = (LeafSchemaNode) tested + .getDataChildByName("mybits"); + BitsType leafType = (BitsType) leaf.getType(); + List bits = leafType.getBits(); + assertEquals(3, bits.size()); + + Bit bit1 = bits.get(0); + assertEquals("disable-nagle", bit1.getName()); + assertEquals(0L, (long) bit1.getPosition()); + + Bit bit2 = bits.get(1); + assertEquals("auto-sense-speed", bit2.getName()); + assertEquals(1L, (long) bit2.getPosition()); + + Bit bit3 = bits.get(2); + assertEquals("10-Mb-only", bit3.getName()); + assertEquals(2L, (long) bit3.getPosition()); + } + + @Test + public void testBitsType2() { + Module tested = findModule(testedModules, "custom-types-test"); + Set> typedefs = tested.getTypeDefinitions(); + TypeDefinition testedType = findTypedef(typedefs, + "access-operations-type"); + + BitsType bitsType = (BitsType) testedType.getBaseType(); + List bits = bitsType.getBits(); + assertEquals(5, bits.size()); + + Bit bit0 = bits.get(0); + assertEquals(0L, (long) bit0.getPosition()); + + Bit bit1 = bits.get(1); + assertEquals(500L, (long) bit1.getPosition()); + + Bit bit2 = bits.get(2); + assertEquals(501L, (long) bit2.getPosition()); + + Bit bit3 = bits.get(3); + assertEquals(365L, (long) bit3.getPosition()); + + Bit bit4 = bits.get(4); + assertEquals(502L, (long) bit4.getPosition()); + } + + private Module findModule(Set modules, String name) { + Module result = null; + for (Module module : modules) { + if (module.getName().equals(name)) { + result = module; + break; + } + } + return result; + } + + private TypeDefinition findTypedef(Set> typedefs, + String name) { + TypeDefinition result = null; + for (TypeDefinition td : typedefs) { + if (td.getQName().getLocalName().equals(name)) { + result = td; + break; + } + } + return result; + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerTest.java deleted file mode 100644 index 1f0cb03012..0000000000 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserListenerTest.java +++ /dev/null @@ -1,271 +0,0 @@ -/* - * 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.yang.model.parser.impl; - -import static org.junit.Assert.*; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URI; -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Set; - -import org.antlr.v4.runtime.ANTLRInputStream; -import org.antlr.v4.runtime.CommonTokenStream; -import org.antlr.v4.runtime.tree.ParseTree; -import org.antlr.v4.runtime.tree.ParseTreeWalker; -import org.junit.Ignore; -import org.junit.Test; -import org.opendaylight.controller.antlrv4.code.gen.YangLexer; -import org.opendaylight.controller.antlrv4.code.gen.YangParser; -import org.opendaylight.controller.yang.common.QName; -import org.opendaylight.controller.yang.model.api.ContainerSchemaNode; -import org.opendaylight.controller.yang.model.api.DataNodeContainer; -import org.opendaylight.controller.yang.model.api.DataSchemaNode; -import org.opendaylight.controller.yang.model.api.LeafSchemaNode; -import org.opendaylight.controller.yang.model.api.ListSchemaNode; -import org.opendaylight.controller.yang.model.api.Module; -import org.opendaylight.controller.yang.model.api.ModuleImport; -import org.opendaylight.controller.yang.model.api.SchemaNode; -import org.opendaylight.controller.yang.model.api.SchemaPath; -import org.opendaylight.controller.yang.model.api.Status; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.parser.builder.impl.ModuleBuilder; -import org.opendaylight.controller.yang.model.util.Leafref; -import org.opendaylight.controller.yang.model.util.UnknownType; - -public class YangModelParserListenerTest { - - @Test - public void testParseImport() throws Exception { - Module module = getModule("/abstract-topology.yang"); - - Set imports = module.getImports(); - assertEquals(1, imports.size()); - ModuleImport moduleImport = imports.iterator().next(); - - assertEquals("inet", moduleImport.getPrefix()); - - DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd"); - Date expectedDate = simpleDateFormat.parse("2010-09-24"); - assertEquals(expectedDate, moduleImport.getRevision()); - } - - @Test - public void testParseHeaders() throws Exception { - Module module = getModule("/abstract-topology.yang"); - - URI namespace = module.getNamespace(); - URI expectedNS = URI.create(""); - assertEquals(expectedNS, namespace); - - DateFormat simpleDateFormat = new SimpleDateFormat("yyyy-mm-dd"); - Date expectedDate = simpleDateFormat.parse("2013-02-08"); - assertEquals(expectedDate, module.getRevision()); - - String prefix = module.getPrefix(); - String expectedPrefix = "tp"; - assertEquals(expectedPrefix, prefix); - - String expectedDescription = "This module contains the definitions of elements that creates network"; - assertTrue(module.getDescription().contains(expectedDescription)); - - String expectedReference = "~~~ WILL BE DEFINED LATER"; - assertEquals(expectedReference, module.getReference()); - - assertEquals("1", module.getYangVersion()); - } - - @Test - public void testParseLeafref() throws Exception { - Module module = getModule("/abstract-topology.yang"); - - Set> typedefs = module.getTypeDefinitions(); - assertEquals(2, typedefs.size()); - for(TypeDefinition td : typedefs) { - Leafref baseType = (Leafref)td.getBaseType(); - if(td.getQName().getLocalName().equals("node-id-ref")) { - assertEquals("/tp:topology/tp:network-nodes/tp:network-node/tp:node-id", baseType.getPathStatement().toString()); - } else { - assertEquals("/tp:topology/tp:network-links/tp:network-link/tp:link-id", baseType.getPathStatement().toString()); - } - } - } - - @Ignore - @Test - public void testParseModule() throws IOException { - //TODO: fix test - Module module = getModule("/test-model.yang"); - - URI namespace = module.getNamespace(); - Date revision = module.getRevision(); - String prefix = module.getPrefix(); - - String expectedDescription = "module description"; - assertEquals(expectedDescription, module.getDescription()); - - String expectedReference = "module reference"; - assertEquals(expectedReference, module.getReference()); - - Set> typedefs = module.getTypeDefinitions(); - assertEquals(10, typedefs.size()); - - Set childNodes = module.getChildNodes(); - assertEquals(1, childNodes.size()); - - final String containerName = "network"; - final QName containerQName = new QName(namespace, revision, prefix, containerName); - ContainerSchemaNode tested = (ContainerSchemaNode) module.getChildNodes().iterator().next(); - DataSchemaNode container1 = module.getDataChildByName(containerName); - DataSchemaNode container2 = module.getDataChildByName(containerQName); - - assertEquals(tested, container1); - assertEquals(container1, container2); - } - - @Ignore - @Test - public void testParseContainer() throws IOException { - //TODO: fix test - Module module = getModule("/test-model.yang"); - - URI namespace = module.getNamespace(); - Date revision = module.getRevision(); - String prefix = module.getPrefix(); - final QName containerQName = new QName(namespace, revision, prefix, "network"); - - ContainerSchemaNode tested = (ContainerSchemaNode)module.getDataChildByName(containerQName); - - Set containerChildNodes = tested.getChildNodes(); - assertEquals(3, containerChildNodes.size()); - - String expectedDescription = "network-description"; - String expectedReference = "network-reference"; - Status expectedStatus = Status.OBSOLETE; - testDesc_Ref_Status(tested, expectedDescription, expectedReference, expectedStatus); - - List path = new ArrayList(); - path.add(new QName(namespace, revision, prefix, "test-model")); - path.add(containerQName); - SchemaPath expectedSchemaPath = new SchemaPath(path, true); - assertEquals(expectedSchemaPath, tested.getPath()); - - assertTrue(tested.isConfiguration()); - assertTrue(tested.isPresenceContainer()); - } - - @Ignore - @Test - public void testParseList() throws IOException { - //TODO: fix test - Module module = getModule("/test-model.yang"); - - URI namespace = module.getNamespace(); - Date revision = module.getRevision(); - String prefix = module.getPrefix(); - final QName listQName = new QName(namespace, revision, prefix, "topology"); - - DataNodeContainer networkContainer = (DataNodeContainer)module.getDataChildByName("network"); - DataNodeContainer topologiesContainer = (DataNodeContainer)networkContainer.getDataChildByName("topologies"); - ListSchemaNode tested = (ListSchemaNode)topologiesContainer.getDataChildByName(listQName); - assertEquals(listQName, tested.getQName()); - - String expectedDescription = "Test description of list 'topology'."; - String expectedReference = null; - Status expectedStatus = Status.CURRENT; - testDesc_Ref_Status(tested, expectedDescription, expectedReference, expectedStatus); - - List path = new ArrayList(); - path.add(new QName(namespace, revision, prefix, "test-model")); - path.add(new QName(namespace, revision, prefix, "network")); - path.add(new QName(namespace, revision, prefix, "topologies")); - path.add(listQName); - SchemaPath expectedSchemaPath = new SchemaPath(path, true); - assertEquals(expectedSchemaPath, tested.getPath()); - - List expectedKey = new ArrayList(); - expectedKey.add(new QName(namespace, revision, prefix, "topology-id")); - assertEquals(expectedKey, tested.getKeyDefinition()); - - assertEquals(Collections.EMPTY_SET, tested.getTypeDefinitions()); - assertEquals(Collections.EMPTY_SET, tested.getUses()); - assertEquals(Collections.EMPTY_SET, tested.getGroupings()); - - assertTrue(tested.getDataChildByName("topology-id") instanceof LeafSchemaNode); - } - - @Ignore - @Test - public void testParseLeaf() throws IOException { - //TODO: fix test - Module module = getModule("/test-model.yang"); - - URI namespace = module.getNamespace(); - Date revision = module.getRevision(); - String prefix = module.getPrefix(); - final QName leafQName = new QName(namespace, revision, prefix, "topology-id"); - - DataNodeContainer networkContainer = (DataNodeContainer)module.getDataChildByName("network"); - DataNodeContainer topologiesContainer = (DataNodeContainer)networkContainer.getDataChildByName("topologies"); - DataNodeContainer topologyList = (DataNodeContainer)topologiesContainer.getDataChildByName("topology"); - LeafSchemaNode tested = (LeafSchemaNode)topologyList.getDataChildByName(leafQName); - assertEquals(leafQName, tested.getQName()); - - String expectedDescription = "Test description of leaf 'topology-id'"; - String expectedReference = null; - Status expectedStatus = Status.CURRENT; - testDesc_Ref_Status(tested, expectedDescription, expectedReference, expectedStatus); - - List path = new ArrayList(); - path.add(new QName(namespace, revision, prefix, "test-model")); - path.add(new QName(namespace, revision, prefix, "network")); - path.add(new QName(namespace, revision, prefix, "topologies")); - path.add(new QName(namespace, revision, prefix, "topology")); - path.add(leafQName); - SchemaPath expectedSchemaPath = new SchemaPath(path, true); - assertEquals(expectedSchemaPath, tested.getPath()); - - UnknownType.Builder typeBuilder = new UnknownType.Builder(new QName(namespace, revision, prefix, "topology-id"), null, null); - TypeDefinition expectedType = typeBuilder.build(); - assertEquals(expectedType, tested.getType()); - } - - - private void testDesc_Ref_Status(SchemaNode tested, String expectedDescription, String expectedReference, Status expectedStatus) { - assertEquals(expectedDescription, tested.getDescription()); - assertEquals(expectedReference, tested.getReference()); - assertEquals(expectedStatus, tested.getStatus()); - } - - private Module getModule(String testFile) throws IOException { - ModuleBuilder builder = getBuilder(testFile); - return builder.build(); - } - - private ModuleBuilder getBuilder(String fileName) throws IOException { - final InputStream inStream = getClass().getResourceAsStream(fileName); - ANTLRInputStream input = new ANTLRInputStream(inStream); - final YangLexer lexer = new YangLexer(input); - final CommonTokenStream tokens = new CommonTokenStream(lexer); - final YangParser parser = new YangParser(tokens); - - final ParseTree tree = parser.yang(); - final ParseTreeWalker walker = new ParseTreeWalker(); - - final YangModelParserListenerImpl modelParser = new YangModelParserListenerImpl(); - walker.walk(modelParser, tree); - return modelParser.getModuleBuilder(); - } - -} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserTest.java b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserTest.java index a42a4fa749..650eaeab82 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserTest.java +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/java/org/opendaylight/controller/yang/model/parser/impl/YangModelParserTest.java @@ -1,235 +1,293 @@ -/* - * 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.yang.model.parser.impl; - -import static org.junit.Assert.*; - -import java.util.HashSet; -import java.util.List; -import java.util.Set; - -import org.junit.Before; -import org.junit.Test; -import org.opendaylight.controller.yang.model.api.AugmentationSchema; -import org.opendaylight.controller.yang.model.api.ContainerSchemaNode; -import org.opendaylight.controller.yang.model.api.LeafSchemaNode; -import org.opendaylight.controller.yang.model.api.ListSchemaNode; -import org.opendaylight.controller.yang.model.api.Module; -import org.opendaylight.controller.yang.model.api.TypeDefinition; -import org.opendaylight.controller.yang.model.api.type.IntegerTypeDefinition; -import org.opendaylight.controller.yang.model.api.type.PatternConstraint; -import org.opendaylight.controller.yang.model.api.type.RangeConstraint; -import org.opendaylight.controller.yang.model.parser.api.YangModelParser; -import org.opendaylight.controller.yang.model.util.Decimal64; -import org.opendaylight.controller.yang.model.util.Int32; -import org.opendaylight.controller.yang.model.util.StringType; - -public class YangModelParserTest { - - private final String testFile1 = "src/test/resources/model/testfile1.yang"; - private final String testFile2 = "src/test/resources/model/testfile2.yang"; - private YangModelParser tested; - - @Before - public void init() { - tested = new YangModelParserImpl(); - } - - @Test - public void testAugment() { - Set modules = tested.parseYangModels(testFile1, testFile2); - assertEquals(2, modules.size()); - - Module m2 = null; - for(Module m : modules) { - if(m.getName().equals("types2")) { - m2 = m; - } - } - assertNotNull(m2); - - AugmentationSchema augment = m2.getAugmentations().iterator().next(); - assertNotNull(augment); - } - - @Test - public void testAugmentTarget() { - Set modules = tested.parseYangModels(testFile1, testFile2); - assertEquals(2, modules.size()); - - Module m1 = null; - for(Module m : modules) { - if(m.getName().equals("types1")) { - m1 = m; - } - } - assertNotNull(m1); - - ContainerSchemaNode container = (ContainerSchemaNode)m1.getDataChildByName("interfaces"); - assertNotNull(container); - - ListSchemaNode list = (ListSchemaNode)container.getDataChildByName("ifEntry"); - assertNotNull(list); - assertEquals(1, list.getAvailableAugmentations().size()); - - LeafSchemaNode leaf = (LeafSchemaNode)list.getDataChildByName("ds0ChannelNumber"); - assertNotNull(leaf); - } - - @Test - public void testTypedefRangesResolving() { - Set modules = tested.parseYangModels(testFile1, testFile2); - assertEquals(2, modules.size()); - - Module m1 = null; - for(Module m : modules) { - if(m.getName().equals("types1")) { - m1 = m; - } - } - assertNotNull(m1); - - LeafSchemaNode testleaf = (LeafSchemaNode)m1.getDataChildByName("testleaf"); - TypeDefinition baseType = testleaf.getType().getBaseType(); - assertTrue(testleaf.getType().getBaseType() instanceof Int32); - Int32 baseTypeCast = (Int32)baseType; - List ranges = baseTypeCast.getRangeStatements(); - assertEquals(2, ranges.size()); - RangeConstraint range = ranges.get(0); - assertEquals(2L, range.getMin()); - assertEquals(20L, range.getMax()); - } - - @Test - public void testTypedefPatternsResolving() { - Set modules = tested.parseYangModels(testFile1, testFile2); - assertEquals(2, modules.size()); - - Module m1 = null; - for(Module m : modules) { - if(m.getName().equals("types1")) { - m1 = m; - } - } - assertNotNull(m1); - - LeafSchemaNode testleaf = (LeafSchemaNode)m1.getDataChildByName("test-string-leaf"); - TypeDefinition baseType = testleaf.getType().getBaseType(); - assertTrue(testleaf.getType().getBaseType() instanceof StringType); - StringType baseTypeCast = (StringType)baseType; - - Set expectedRegularExpressions = new HashSet(); - expectedRegularExpressions.add("[a-k]*"); - expectedRegularExpressions.add("[b-u]*"); - expectedRegularExpressions.add("[e-z]*"); - - Set actualRegularExpressions = new HashSet(); - List patterns = baseTypeCast.getPatterns(); - for(PatternConstraint pc : patterns) { - actualRegularExpressions.add(pc.getRegularExpression()); - } - - assertEquals(expectedRegularExpressions, actualRegularExpressions); - } - - @Test - public void testTypedefLengthsResolving() { - Set modules = tested.parseYangModels(testFile1, testFile2); - assertEquals(2, modules.size()); - - Module m1 = null; - for(Module m : modules) { - if(m.getName().equals("types1")) { - m1 = m; - } - } - assertNotNull(m1); - - LeafSchemaNode testleaf = (LeafSchemaNode)m1.getDataChildByName("test-int-leaf"); - TypeDefinition baseType = testleaf.getType().getBaseType(); - assertTrue(testleaf.getType().getBaseType() instanceof IntegerTypeDefinition); - Int32 baseTypeCast = (Int32)baseType; - - Long[][] expectedRanges = new Long[3][2]; - expectedRanges[0] = new Long[]{10L, 20L}; - expectedRanges[1] = new Long[]{12L, 18L}; - expectedRanges[2] = new Long[]{14L, 16L}; - - List actualRanges = baseTypeCast.getRangeStatements(); - assertEquals(3, actualRanges.size()); - for(int i = 0; i < actualRanges.size(); i++) { - assertEquals(expectedRanges[i][0], actualRanges.get(i).getMin()); - assertEquals(expectedRanges[i][1], actualRanges.get(i).getMax()); - } - } - - @Test - public void testTypeDef() { - Set modules = tested.parseYangModels(testFile1, testFile2); - assertEquals(2, modules.size()); - - Module m2 = null; - for(Module m : modules) { - if(m.getName().equals("types2")) { - m2 = m; - } - } - assertNotNull(m2); - - LeafSchemaNode testleaf = (LeafSchemaNode)m2.getDataChildByName("nested-type-leaf"); - TypeDefinition baseType = testleaf.getType().getBaseType(); - assertTrue(testleaf.getType().getBaseType() instanceof Int32); - Int32 baseTypeCast = (Int32)baseType; - List ranges = baseTypeCast.getRangeStatements(); - assertEquals(2, ranges.size()); - RangeConstraint range = ranges.get(0); - assertEquals(2L, range.getMin()); - assertEquals(20L, range.getMax()); - } - - @Test - public void testTypedefDecimal1() { - Set modules = tested.parseYangModels(testFile1, testFile2); - assertEquals(2, modules.size()); - - Module m1 = null; - for(Module m : modules) { - if(m.getName().equals("types1")) { - m1 = m; - } - } - assertNotNull(m1); - - LeafSchemaNode testleaf = (LeafSchemaNode)m1.getDataChildByName("test-decimal-leaf"); - TypeDefinition baseType = testleaf.getType().getBaseType(); - assertTrue(testleaf.getType().getBaseType() instanceof Decimal64); - Decimal64 baseTypeCast = (Decimal64)baseType; - assertEquals(4, (int)baseTypeCast.getFractionDigits()); - } - - @Test - public void testTypedefDecimal2() { - Set modules = tested.parseYangModels(testFile1, testFile2); - assertEquals(2, modules.size()); - - Module m1 = null; - for(Module m : modules) { - if(m.getName().equals("types1")) { - m1 = m; - } - } - assertNotNull(m1); - - LeafSchemaNode testleaf = (LeafSchemaNode)m1.getDataChildByName("test-decimal-leaf2"); - TypeDefinition baseType = testleaf.getType().getBaseType(); - assertTrue(testleaf.getType().getBaseType() instanceof Decimal64); - Decimal64 baseTypeCast = (Decimal64)baseType; - assertEquals(5, (int)baseTypeCast.getFractionDigits()); - } - -} +/* + * 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.yang.model.parser.impl; + +import static org.junit.Assert.*; + +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; +import org.opendaylight.controller.yang.common.QName; +import org.opendaylight.controller.yang.model.api.AugmentationSchema; +import org.opendaylight.controller.yang.model.api.ContainerSchemaNode; +import org.opendaylight.controller.yang.model.api.LeafSchemaNode; +import org.opendaylight.controller.yang.model.api.ListSchemaNode; +import org.opendaylight.controller.yang.model.api.Module; +import org.opendaylight.controller.yang.model.api.TypeDefinition; +import org.opendaylight.controller.yang.model.api.type.LengthConstraint; +import org.opendaylight.controller.yang.model.api.type.PatternConstraint; +import org.opendaylight.controller.yang.model.api.type.RangeConstraint; +import org.opendaylight.controller.yang.model.parser.api.YangModelParser; +import org.opendaylight.controller.yang.model.util.Decimal64; +import org.opendaylight.controller.yang.model.util.ExtendedType; +import org.opendaylight.controller.yang.model.util.Int16; +import org.opendaylight.controller.yang.model.util.Int32; +import org.opendaylight.controller.yang.model.util.StringType; +import org.opendaylight.controller.yang.model.util.UnionType; + +public class YangModelParserTest { + + private static final String TEST_FILE1 = "src/test/resources/model/testfile1.yang"; + private static final String TEST_FILE2 = "src/test/resources/model/testfile2.yang"; + private YangModelParser tested; + + @Before + public void init() { + tested = new YangModelParserImpl(); + } + + @Test + public void testAugment() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types2"); + assertNotNull(testModule); + + AugmentationSchema augment = testModule.getAugmentations().iterator().next(); + assertNotNull(augment); + } + + @Test + public void testAugmentTarget() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types1"); + assertNotNull(testModule); + + ContainerSchemaNode container = (ContainerSchemaNode)testModule.getDataChildByName("interfaces"); + assertNotNull(container); + + ListSchemaNode list = (ListSchemaNode)container.getDataChildByName("ifEntry"); + assertNotNull(list); + assertEquals(1, list.getAvailableAugmentations().size()); + + LeafSchemaNode leaf = (LeafSchemaNode)list.getDataChildByName("ds0ChannelNumber"); + assertNotNull(leaf); + } + + @Test + public void testTypedefRangesResolving() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types1"); + assertNotNull(testModule); + + LeafSchemaNode testleaf = (LeafSchemaNode)testModule.getDataChildByName("testleaf"); + ExtendedType leafType = (ExtendedType)testleaf.getType(); + assertEquals("my-type1", leafType.getQName().getLocalName()); + assertEquals("t2", leafType.getQName().getPrefix()); + ExtendedType baseType = (ExtendedType)leafType.getBaseType(); + assertEquals("my-base-int32-type", baseType.getQName().getLocalName()); + assertEquals("t2", baseType.getQName().getPrefix()); + + List ranges = leafType.getRanges(); + assertEquals(1, ranges.size()); + RangeConstraint range = ranges.get(0); + assertEquals(11L, range.getMin()); + assertEquals(20L, range.getMax()); + } + + @Test + public void testTypedefPatternsResolving() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types1"); + assertNotNull(testModule); + + LeafSchemaNode testleaf = (LeafSchemaNode)testModule.getDataChildByName("test-string-leaf"); + ExtendedType testleafType = (ExtendedType)testleaf.getType(); + QName testleafTypeQName = testleafType.getQName(); + assertEquals("my-string-type-ext", testleafTypeQName.getLocalName()); + assertEquals("t2", testleafTypeQName.getPrefix()); + + Set expectedRegex = new HashSet(); + expectedRegex.add("[a-k]*"); + expectedRegex.add("[b-u]*"); + expectedRegex.add("[e-z]*"); + + Set actualRegex = new HashSet(); + List patterns = testleafType.getPatterns(); + assertEquals(3, patterns.size()); + for (PatternConstraint pc : patterns) { + actualRegex.add(pc.getRegularExpression()); + } + assertEquals(expectedRegex, actualRegex); + + TypeDefinition baseType = testleafType.getBaseType(); + assertEquals("my-string-type2", baseType.getQName().getLocalName()); + + List lengths = testleafType.getLengths(); + assertEquals(1, lengths.size()); + + LengthConstraint length = lengths.get(0); + assertEquals(5L, length.getMin()); + assertEquals(10L, length.getMax()); + } + + @Test + public void testTypedefLengthsResolving() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types1"); + assertNotNull(testModule); + + LeafSchemaNode testleaf = (LeafSchemaNode)testModule.getDataChildByName("leaf-with-length"); + ExtendedType testleafType = (ExtendedType)testleaf.getType(); + assertEquals("my-string-type", testleafType.getQName().getLocalName()); + + List lengths = testleafType.getLengths(); + assertEquals(1, lengths.size()); + + LengthConstraint length = lengths.get(0); + assertEquals(7L, length.getMin()); + assertEquals(10L, length.getMax()); + } + + @Test + public void testTypeDef() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types2"); + assertNotNull(testModule); + + LeafSchemaNode testleaf = (LeafSchemaNode)testModule.getDataChildByName("nested-type-leaf"); + ExtendedType testleafType = (ExtendedType)testleaf.getType(); + assertEquals("my-type1", testleafType.getQName().getLocalName()); + + ExtendedType baseType = (ExtendedType)testleafType.getBaseType(); + assertEquals("my-base-int32-type", baseType.getQName().getLocalName()); + + Int32 int32base = (Int32)baseType.getBaseType(); + List ranges = int32base.getRangeStatements(); + assertEquals(1, ranges.size()); + RangeConstraint range = ranges.get(0); + assertEquals(2L, range.getMin()); + assertEquals(20L, range.getMax()); + } + + @Test + public void testTypedefDecimal1() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types1"); + assertNotNull(testModule); + + LeafSchemaNode testleaf = (LeafSchemaNode)testModule.getDataChildByName("test-decimal-leaf"); + ExtendedType type = (ExtendedType)testleaf.getType(); + + TypeDefinition baseType = type.getBaseType(); + assertTrue(baseType instanceof Decimal64); + Decimal64 baseTypeCast = (Decimal64)baseType; + assertEquals(6, (int)baseTypeCast.getFractionDigits()); + } + + @Test + public void testTypedefDecimal2() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types1"); + assertNotNull(testModule); + + LeafSchemaNode testleaf = (LeafSchemaNode)testModule.getDataChildByName("test-decimal-leaf2"); + TypeDefinition baseType = testleaf.getType().getBaseType(); + assertTrue(testleaf.getType().getBaseType() instanceof Decimal64); + Decimal64 baseTypeCast = (Decimal64)baseType; + assertEquals(5, (int)baseTypeCast.getFractionDigits()); + } + + @Test + public void testTypedefUnion() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types1"); + assertNotNull(testModule); + + LeafSchemaNode testleaf = (LeafSchemaNode)testModule.getDataChildByName("union-leaf"); + ExtendedType testleafType = (ExtendedType)testleaf.getType(); + assertEquals("my-union-ext", testleafType.getQName().getLocalName()); + + ExtendedType baseType = (ExtendedType)testleafType.getBaseType(); + assertEquals("my-union", baseType.getQName().getLocalName()); + + UnionType unionBase = (UnionType) baseType.getBaseType(); + + List> unionTypes = unionBase.getTypes(); + Int16 unionType1 = (Int16)unionTypes.get(0); + List ranges = unionType1.getRangeStatements(); + assertEquals(1, ranges.size()); + RangeConstraint range = ranges.get(0); + assertEquals(1L, range.getMin()); + assertEquals(100L, range.getMax()); + + assertTrue(unionTypes.get(0) instanceof Int16); + assertTrue(unionTypes.get(1) instanceof Int32); + } + + @Test + public void testNestedUnionResolving() { + Set modules = tested.parseYangModels(TEST_FILE1, TEST_FILE2); + assertEquals(2, modules.size()); + + Module testModule = findModule(modules, "types1"); + assertNotNull(testModule); + + LeafSchemaNode testleaf = (LeafSchemaNode)testModule.getDataChildByName("nested-union-leaf"); + + ExtendedType nestedUnion1 = (ExtendedType)testleaf.getType(); + assertEquals("nested-union1", nestedUnion1.getQName().getLocalName()); + + ExtendedType nestedUnion2 = (ExtendedType)nestedUnion1.getBaseType(); + assertEquals("nested-union2", nestedUnion2.getQName().getLocalName()); + + UnionType unionType1 = (UnionType)nestedUnion2.getBaseType(); + List> unionTypes = unionType1.getTypes(); + assertEquals(2, unionTypes.size()); + assertTrue(unionTypes.get(0) instanceof StringType); + assertTrue(unionTypes.get(1) instanceof ExtendedType); + + ExtendedType extendedUnion = (ExtendedType)unionTypes.get(1); + ExtendedType extendedUnionBase = (ExtendedType)extendedUnion.getBaseType(); + assertEquals("my-union", extendedUnionBase.getQName().getLocalName()); + + UnionType extendedTargetUnion = (UnionType)extendedUnionBase.getBaseType(); + List> extendedTargetTypes = extendedTargetUnion.getTypes(); + assertTrue(extendedTargetTypes.get(0) instanceof Int16); + assertTrue(extendedTargetTypes.get(1) instanceof Int32); + + Int16 int16 = (Int16) extendedTargetTypes.get(0); + List ranges = int16.getRangeStatements(); + assertEquals(1, ranges.size()); + RangeConstraint range = ranges.get(0); + assertEquals(1L, range.getMin()); + assertEquals(100L, range.getMax()); + } + + private Module findModule(Set modules, String moduleName) { + Module result = null; + for(Module module : modules) { + if(module.getName().equals(moduleName)) { + result = module; + break; + } + } + return result; + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile1.yang b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile1.yang index 9e779c2ce5..f38e3488cf 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile1.yang +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile1.yang @@ -1,67 +1,81 @@ -module types1 { - yang-version 1; - namespace "urn:simple.container.demo"; - prefix "t1"; - - import types2 { - prefix "data"; - revision-date 2013-02-27; - } - - organization "Cisco"; - contact "WILL-BE-DEFINED-LATER"; - - revision "2013-02-27" { - reference " WILL BE DEFINED LATER"; - } - - container interfaces { - list ifEntry { - key "ifIndex"; - - leaf ifIndex { - type uint32; - units minutes; - } - - leaf ifMtu { - type int32; - } - } - } - - leaf testleaf { - type data:my-type1 { - range "min..max"; - } - } - - leaf test-string-leaf { - type data:my-string-type-ext; - } - - leaf leaf-with-length { - type data:my-string-type { - length "7..max"; - } - } - - leaf test-int-leaf { - type data:my-int-type-ext; - } - - leaf test-decimal-leaf { - type data:my-decimal-type { - fraction-digits 4; - } - } - - leaf test-decimal-leaf2 { - type data:my-decimal-type-ext; - } - - container ext { - data:c-define "MY_INTERFACES"; - } - -} +module types1 { + yang-version 1; + namespace "urn:simple.container.demo"; + prefix "t1"; + + import types2 { + prefix "data"; + revision-date 2013-02-27; + } + + organization "opendaylight"; + contact "WILL-BE-DEFINED-LATER"; + + revision "2013-02-27" { + reference " WILL BE DEFINED LATER"; + } + + container interfaces { + list ifEntry { + key "ifIndex"; + + leaf ifIndex { + type uint32; + units minutes; + } + + leaf ifMtu { + type int32; + } + } + } + + leaf testleaf { + type data:my-type1 { + range "min..max"; + } + } + + leaf test-string-leaf { + type data:my-string-type-ext; + } + + leaf leaf-with-length { + type data:my-string-type { + length "7..max"; + } + } + + leaf test-int-leaf { + type data:my-int-type-ext; + } + + leaf test-decimal-leaf { + type data:my-decimal-type { + fraction-digits 4; + } + } + + leaf test-decimal-leaf2 { + type data:my-decimal-type-ext; + } + + container ext { + data:c-define "MY_INTERFACES"; + } + + leaf union-leaf { + type data:my-union-ext; + } + + deviation /data:system/data:user { + deviate add { + default "admin"; // new users are 'admin' by default + } + } + + leaf nested-union-leaf { + type data:nested-union1; + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile2.yang b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile2.yang index ea12a507eb..15685f75a1 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile2.yang +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/model/testfile2.yang @@ -1,130 +1,149 @@ -module types2 { - yang-version 1; - namespace "urn:simple.types.data.demo"; - prefix "t2"; - - import types1 { - prefix "if"; - revision-date 2013-02-27; - } - - organization "Cisco"; - contact "WILL-BE-DEFINED-LATER"; - description "This is types-data test description"; - - revision "2013-02-27" { - reference " WILL BE DEFINED LATER"; - } - - typedef ranges1 { - type int32 { - range "10..20"; - } - } - - typedef ranges2 { - type ranges1 { - range "12..max"; - } - } - - typedef my-base-int32-type { - type int32 { - range "2..20"; - } - } - - typedef my-type1 { - type my-base-int32-type { - range "11..max"; - } - } - - typedef my-string-type { - type my-custom-string { - pattern "[a-k]*"; - length "5..10"; - } - } - - typedef my-custom-string { - type string { - pattern "[a-k]*"; - length "5..11"; - } - } - - typedef my-string-type2 { - type my-string-type { - pattern "[b-u]*"; - } - } - - typedef my-string-type-ext { - type my-string-type2 { - pattern "[e-z]*"; - } - } - - typedef my-int-type { - type int32 { - range "10..20"; - } - } - - typedef my-int-type2 { - type my-int-type { - range "12..18"; - } - } - - typedef my-int-type-ext { - type my-int-type2 { - range "14..16"; - } - } - - typedef my-decimal-type { - type decimal64 { - fraction-digits 6; - } - } - - typedef my-decimal-type-ext { - type decimal64 { - fraction-digits 5; - } - } - - augment "/if:interfaces/if:ifEntry" { - when "if:ifType='ds0'"; - leaf ds0ChannelNumber { - type string; - } - } - - leaf if-name { - type leafref { - path "/interface/name"; - } - } - - leaf name { - type string; - } - - leaf nested-type-leaf { - type my-type1; - } - - extension c-define { - description - "Takes as argument a name string. - Makes the code generator use the given name in the - #define."; - argument "name" { - yin-element "true"; - } - } - -} +module types2 { + yang-version 1; + namespace "urn:simple.types.data.demo"; + prefix "t2"; + + import types1 { + prefix "if"; + revision-date 2013-02-27; + } + + organization "opendaylight"; + contact "WILL-BE-DEFINED-LATER"; + description "This is types-data test description"; + + revision "2013-02-27" { + reference " WILL BE DEFINED LATER"; + } + + typedef my-base-int32-type { + type int32 { + range "2..20"; + } + } + + typedef my-type1 { + type my-base-int32-type { + range "11..max"; + } + units "mile"; + default "11"; + } + + typedef my-custom-string { + type string { + pattern "[a-k]*"; + length "5..11"; + } + } + + typedef my-string-type { + type my-custom-string { + length "5..10"; + } + } + + typedef my-string-type2 { + type my-string-type { + pattern "[b-u]*"; + } + } + + typedef my-string-type-ext { + type my-string-type2 { + pattern "[e-z]*"; + } + } + + typedef my-int-type { + type int32 { + range "10..20"; + } + } + + typedef my-int-type2 { + type my-int-type { + range "12..18"; + } + } + + typedef my-int-type-ext { + type my-int-type2 { + range "14..16"; + } + } + + typedef my-decimal-type { + type decimal64 { + fraction-digits 6; + } + } + + typedef my-decimal-type-ext { + type decimal64 { + fraction-digits 5; + } + } + + typedef my-union { + type union { + type int16 { + range "1..100"; + } + type int32; + } + } + + typedef my-union-ext { + type my-union; + } + + typedef nested-union1 { + type nested-union2; + } + + typedef nested-union2 { + type union { + type my-union-ext; + type string; + } + } + + augment "/if:interfaces/if:ifEntry" { + when "if:ifType='ds0'"; + leaf ds0ChannelNumber { + type string; + } + } + + leaf if-name { + type leafref { + path "/interface/name"; + } + } + + leaf name { + type string; + } + + leaf nested-type-leaf { + type my-type1; + } + + extension c-define { + description + "Takes as argument a name string. + Makes the code generator use the given name in the + #define."; + argument "name" { + yin-element "true"; + } + } + + container system { + leaf user { + type string; + } + } + +} diff --git a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/types/custom-types-test@2012-4-4.yang b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/types/custom-types-test@2012-4-4.yang index 4231699b50..d52068a4ad 100644 --- a/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/types/custom-types-test@2012-4-4.yang +++ b/opendaylight/sal/yang-prototype/code-generator/yang-model-parser-impl/src/test/resources/types/custom-types-test@2012-4-4.yang @@ -4,8 +4,32 @@ module custom-types-test { namespace "urn:simple.container.demo"; prefix "iit"; - organization "Cisco"; + organization "opendaylight"; contact "WILL-BE-DEFINED-LATER"; + + + typedef access-operations-type { + type bits { + bit create { + description "Any protocol operation that creates a new data node."; + } + bit read { + description "Any protocol operation or notification that returns the value of a data node."; + position 500; + } + bit update { + description "Any protocol operation that alters an existing data node."; + } + bit delete { + description "Any protocol operation that removes a data node."; + position 365; + } + bit exec { + description "Execution access to the specified protocol operation."; + } + } + description "NETCONF Access Operation."; + } leaf inst-id-leaf1 { type instance-identifier { @@ -25,5 +49,20 @@ module custom-types-test { base "crypto-base"; description "crypto-alg description"; } + + leaf mybits { + type bits { + bit disable-nagle { + position 0; + } + bit auto-sense-speed { + position 1; + } + bit 10-Mb-only { + position 2; + } + } + default "auto-sense-speed"; + } } diff --git a/opendaylight/sal/yang-prototype/yang/yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/TypeDefinition.java b/opendaylight/sal/yang-prototype/yang/yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/TypeDefinition.java index 0f098422eb..71b5d193df 100644 --- a/opendaylight/sal/yang-prototype/yang/yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/TypeDefinition.java +++ b/opendaylight/sal/yang-prototype/yang/yang-model-api/src/main/java/org/opendaylight/controller/yang/model/api/TypeDefinition.java @@ -8,7 +8,7 @@ package org.opendaylight.controller.yang.model.api; -public interface TypeDefinition> extends SchemaNode { +public interface TypeDefinition> extends SchemaNode { T getBaseType(); diff --git a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/ExtendedType.java b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/ExtendedType.java index c82df2e079..03f06387f1 100644 --- a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/ExtendedType.java +++ b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/ExtendedType.java @@ -15,6 +15,9 @@ import org.opendaylight.controller.yang.model.api.SchemaPath; import org.opendaylight.controller.yang.model.api.Status; import org.opendaylight.controller.yang.model.api.TypeDefinition; import org.opendaylight.controller.yang.model.api.UnknownSchemaNode; +import org.opendaylight.controller.yang.model.api.type.LengthConstraint; +import org.opendaylight.controller.yang.model.api.type.PatternConstraint; +import org.opendaylight.controller.yang.model.api.type.RangeConstraint; public class ExtendedType implements TypeDefinition { @@ -25,6 +28,12 @@ public class ExtendedType implements TypeDefinition { private final String reference; private final List unknownSchemaNodes; + private List ranges = Collections.emptyList(); + private List lengths = Collections.emptyList(); + private List patterns = Collections.emptyList(); + private Integer fractionDigits = null; + + private Status status; private String units; private Object defaultValue; @@ -42,6 +51,11 @@ public class ExtendedType implements TypeDefinition { private String units = ""; private Object defaultValue = null; + private List ranges = Collections.emptyList(); + private List lengths = Collections.emptyList(); + private List patterns = Collections.emptyList(); + private Integer fractionDigits = null; + public Builder(final QName typeName, TypeDefinition baseType, final String description, final String reference) { this.typeName = typeName; @@ -71,6 +85,32 @@ public class ExtendedType implements TypeDefinition { return this; } + public Builder ranges(final List ranges) { + if(ranges != null) { + this.ranges = ranges; + } + return this; + } + + public Builder lengths(final List lengths) { + if(lengths != null) { + this.lengths = lengths; + } + return this; + } + + public Builder patterns(final List patterns) { + if(patterns != null) { + this.patterns = patterns; + } + return this; + } + + public Builder fractionDigits(final Integer fractionDigits) { + this.fractionDigits = fractionDigits; + return this; + } + public ExtendedType build() { return new ExtendedType(this); } @@ -86,6 +126,11 @@ public class ExtendedType implements TypeDefinition { this.status = builder.status; this.units = builder.units; this.defaultValue = builder.defaultValue; + + this.ranges = builder.ranges; + this.lengths = builder.lengths; + this.patterns = builder.patterns; + this.fractionDigits = builder.fractionDigits; } @Override @@ -253,4 +298,20 @@ public class ExtendedType implements TypeDefinition { builder2.append("]"); return builder2.toString(); } + + public List getRanges() { + return ranges; + } + + public List getLengths() { + return lengths; + } + + public List getPatterns() { + return patterns; + } + + public Integer getFractionDigits() { + return fractionDigits; + } } diff --git a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Leafref.java b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Leafref.java index 3218116290..9253895e3f 100644 --- a/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Leafref.java +++ b/opendaylight/sal/yang-prototype/yang/yang-model-util/src/main/java/org/opendaylight/controller/yang/model/util/Leafref.java @@ -22,7 +22,7 @@ import org.opendaylight.controller.yang.model.api.type.LeafrefTypeDefinition; /** * The default implementation of Instance Leafref Type Definition * interface. - * + * * @see LeafrefTypeDefinition */ public class Leafref implements LeafrefTypeDefinition { @@ -35,12 +35,12 @@ public class Leafref implements LeafrefTypeDefinition { private final String units = ""; private final LeafrefTypeDefinition baseType; - private Leafref(final RevisionAwareXPath xpath) { + public Leafref(final RevisionAwareXPath xpath) { this.xpath = xpath; this.path = BaseTypes.schemaPath(name); this.baseType = this; } - + public Leafref(final List actualPath, final URI namespace, final Date revision, final RevisionAwareXPath xpath) { super(); @@ -48,7 +48,7 @@ public class Leafref implements LeafrefTypeDefinition { this.xpath = xpath; baseType = new Leafref(xpath); } - + public Leafref(final List actualPath, final URI namespace, final Date revision, final LeafrefTypeDefinition baseType, final RevisionAwareXPath xpath) { @@ -60,7 +60,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see * org.opendaylight.controller.yang.model.api.TypeDefinition#getBaseType() */ @@ -71,7 +71,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see org.opendaylight.controller.yang.model.api.TypeDefinition#getUnits() */ @Override @@ -81,7 +81,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see * org.opendaylight.controller.yang.model.api.TypeDefinition#getDefaultValue * () @@ -93,7 +93,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see org.opendaylight.controller.yang.model.api.SchemaNode#getQName() */ @Override @@ -103,7 +103,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see org.opendaylight.controller.yang.model.api.SchemaNode#getPath() */ @Override @@ -113,7 +113,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see * org.opendaylight.controller.yang.model.api.SchemaNode#getDescription() */ @@ -124,7 +124,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see org.opendaylight.controller.yang.model.api.SchemaNode#getReference() */ @Override @@ -134,7 +134,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see org.opendaylight.controller.yang.model.api.SchemaNode#getStatus() */ @Override @@ -144,7 +144,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see * org.opendaylight.controller.yang.model.api.SchemaNode#getExtensionSchemaNodes * () @@ -156,7 +156,7 @@ public class Leafref implements LeafrefTypeDefinition { /* * (non-Javadoc) - * + * * @see * org.opendaylight.controller.yang.model.api.type.LeafrefTypeDefinition * #getPathStatement() diff --git a/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/AuthorizationConfig.java b/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/AuthorizationConfig.java index 3eafe2b75b..2474eec6d9 100644 --- a/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/AuthorizationConfig.java +++ b/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/AuthorizationConfig.java @@ -8,36 +8,36 @@ package org.opendaylight.controller.usermanager.internal; +import org.opendaylight.controller.sal.utils.Status; /** * Configuration Java Object which represents a Local configured Authorization * for a remote authenticated user for User Manager. */ public class AuthorizationConfig extends UserConfig { - private static final long serialVersionUID = 1L; - - public AuthorizationConfig() { - super(); - } - - // Constructor may be needed for autocontainer logic - public AuthorizationConfig(String user, String role) { - super(); - this.user = user; - this.role = role; - } - - @Override - public boolean isValid() { - return (user != null && !user.isEmpty() && role != null && !role - .isEmpty()); - } - - public String getRolesData() { - return (role.replace(",", " ")); - } - - public String toString() { - return "AuthorizationConfig=[user: " + user + ", role: " + role + "]"; - } + private static final long serialVersionUID = 1L; + + public AuthorizationConfig() { + super(); + } + + // Constructor may be needed for autocontainer logic + public AuthorizationConfig(String user, String role) { + super(); + this.user = user; + this.role = role; + } + + @Override + public Status validate() { + return (!isRoleValid().isSuccess() ? isRoleValid() : isUsernameValid()); + } + + public String getRolesData() { + return (role.replace(",", " ")); + } + + public String toString() { + return "AuthorizationConfig=[user: " + user + ", role: " + role + "]"; + } } diff --git a/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/UserConfig.java b/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/UserConfig.java index 884ab8708c..cedae6c918 100644 --- a/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/UserConfig.java +++ b/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/UserConfig.java @@ -9,47 +9,56 @@ package org.opendaylight.controller.usermanager.internal; import java.io.Serializable; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.apache.commons.lang3.builder.EqualsBuilder; import org.apache.commons.lang3.builder.HashCodeBuilder; import org.opendaylight.controller.sal.authorization.AuthResultEnum; +import org.opendaylight.controller.sal.utils.Status; +import org.opendaylight.controller.sal.utils.StatusCode; import org.opendaylight.controller.usermanager.AuthResponse; /** - * Configuration Java Object which represents a Local AAA user - * configuration information for User Manager. + * Configuration Java Object which represents a Local AAA user configuration + * information for User Manager. */ public class UserConfig implements Serializable { - private static final long serialVersionUID = 1L; + private static final long serialVersionUID = 1L; - /* - * Clear text password as we are moving to some MD5 digest - * for when saving configurations - */ - protected String user; - protected String role; - private String password; + /* + * Clear text password as we are moving to some MD5 digest for when saving + * configurations + */ + protected String user; + protected String role; + private String password; + private static final int USERNAME_MAXLENGTH = 32; + private static final int PASSWORD_MINLENGTH = 5; + private static final int PASSWORD_MAXLENGTH = 256; + private static final Pattern INVALID_USERNAME_CHARACTERS = Pattern + .compile("([/\\s\\.\\?#%;\\\\]+)"); - public UserConfig() { - } + public UserConfig() { + } - public UserConfig(String user, String password, String role) { - this.user = user; - this.password = password; - this.role = role; - } + public UserConfig(String user, String password, String role) { + this.user = user; + this.password = password; + this.role = role; + } - public String getUser() { - return user; - } + public String getUser() { + return user; + } - public String getPassword() { - return password; - } + public String getPassword() { + return password; + } - public String getRole() { - return role; - } + public String getRole() { + return role; + } @Override public int hashCode() { @@ -60,41 +69,86 @@ public class UserConfig implements Serializable { public boolean equals(Object obj) { return EqualsBuilder.reflectionEquals(this, obj); } - + @Override public String toString() { - return "UserConfig[user="+ user + ", password=" + password + "]"; + return "UserConfig[user=" + user + ", password=" + password + "]"; + } + + public Status validate() { + Status validCheck = new Status(StatusCode.SUCCESS, null); + validCheck = isRoleValid(); + + if (validCheck.isSuccess()) + validCheck = isUsernameValid(); + if (validCheck.isSuccess()) + validCheck = isPasswordValid(); + + return validCheck; + } + + protected Status isUsernameValid() { + if (user == null || user.isEmpty()) { + return new Status(StatusCode.BADREQUEST, "Username cannot be empty"); + } + + Matcher mUser = UserConfig.INVALID_USERNAME_CHARACTERS.matcher(user); + if (user.length() > UserConfig.USERNAME_MAXLENGTH + || mUser.find() == true) { + return new Status(StatusCode.BADREQUEST, + "Username can have 1-32 non-whitespace " + + "alphanumeric characters and any special " + + "characters except ./#%;?\\"); + } + + return new Status(StatusCode.SUCCESS, null); + } + + private Status isPasswordValid() { + if (password == null || password.isEmpty()) { + return new Status(StatusCode.BADREQUEST, "Password cannot be empty"); + } + + if (password.length() < UserConfig.PASSWORD_MINLENGTH + || password.length() > UserConfig.PASSWORD_MAXLENGTH) { + return new Status(StatusCode.BADREQUEST, + "Password should have 5-256 characters"); + } + return new Status(StatusCode.SUCCESS, null); } - public boolean isValid() { - return (user != null && !user.isEmpty() && role != null - && !role.isEmpty() && password != null && !password.isEmpty()); - } - - public boolean update(String currentPassword, String newPassword, - String newRole) { - // To make any changes to a user configured profile, current password - // must always be provided - if (!this.password.equals(currentPassword)) { - return false; - } - if (newPassword != null) { - this.password = newPassword; - } - if (newRole != null) { - this.role = newRole; - } - return true; - } - - public AuthResponse authenticate(String clearTextPass) { - AuthResponse locResponse = new AuthResponse(); - if (password.equals(clearTextPass)) { - locResponse.setStatus(AuthResultEnum.AUTH_ACCEPT_LOC); - locResponse.addData(role.replace(",", " ")); - } else { - locResponse.setStatus(AuthResultEnum.AUTH_REJECT_LOC); - } - return locResponse; - } + protected Status isRoleValid() { + if (role == null || role.isEmpty()) { + return new Status(StatusCode.BADREQUEST, + "Role name cannot be empty"); + } + return new Status(StatusCode.SUCCESS, null); + } + + public boolean update(String currentPassword, String newPassword, + String newRole) { + // To make any changes to a user configured profile, current password + // must always be provided + if (!this.password.equals(currentPassword)) { + return false; + } + if (newPassword != null) { + this.password = newPassword; + } + if (newRole != null) { + this.role = newRole; + } + return true; + } + + public AuthResponse authenticate(String clearTextPass) { + AuthResponse locResponse = new AuthResponse(); + if (password.equals(clearTextPass)) { + locResponse.setStatus(AuthResultEnum.AUTH_ACCEPT_LOC); + locResponse.addData(role.replace(",", " ")); + } else { + locResponse.setStatus(AuthResultEnum.AUTH_REJECT_LOC); + } + return locResponse; + } } diff --git a/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/UserManagerImpl.java b/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/UserManagerImpl.java index 3e57ed846c..1b9c749163 100644 --- a/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/UserManagerImpl.java +++ b/opendaylight/usermanager/src/main/java/org/opendaylight/controller/usermanager/internal/UserManagerImpl.java @@ -82,7 +82,13 @@ public class UserManagerImpl implements IUserManager, IObjectReader, private static final String authFileName = ROOT + "authorization.conf"; private ConcurrentMap localUserConfigList; private ConcurrentMap remoteServerConfigList; - private ConcurrentMap authorizationConfList; // local authorization info for remotely authenticated users + private ConcurrentMap authorizationConfList; // local + // authorization + // info + // for + // remotely + // authenticated + // users private ConcurrentMap activeUsers; private ConcurrentMap authProviders; private ConcurrentMap localUserListSaveConfigEvent, @@ -94,8 +100,7 @@ public class UserManagerImpl implements IUserManager, IObjectReader, private ISessionManager sessionMgr = new SessionManager(); public boolean addAAAProvider(IAAAProvider provider) { - if (provider == null - || provider.getName() == null + if (provider == null || provider.getName() == null || provider.getName().trim().isEmpty()) { return false; } @@ -124,8 +129,7 @@ public class UserManagerImpl implements IUserManager, IObjectReader, this.applicationAuthorizationClients = Collections .synchronizedSet(new HashSet()); if (clusterGlobalService == null) { - logger - .error("un-initialized clusterGlobalService, can't create cache"); + logger.error("un-initialized clusterGlobalService, can't create cache"); return; } @@ -134,36 +138,35 @@ public class UserManagerImpl implements IUserManager, IObjectReader, EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); clusterGlobalService.createCache( - "usermanager.remoteServerConfigList", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + "usermanager.remoteServerConfigList", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); clusterGlobalService.createCache( - "usermanager.authorizationConfList", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + "usermanager.authorizationConfList", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); - clusterGlobalService.createCache("usermanager.activeUsers", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + clusterGlobalService.createCache("usermanager.activeUsers", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); clusterGlobalService.createCache( - "usermanager.localUserSaveConfigEvent", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + "usermanager.localUserSaveConfigEvent", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); clusterGlobalService.createCache( - "usermanager.remoteServerSaveConfigEvent", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + "usermanager.remoteServerSaveConfigEvent", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); clusterGlobalService.createCache( - "usermanager.authorizationSaveConfigEvent", EnumSet - .of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); + "usermanager.authorizationSaveConfigEvent", + EnumSet.of(IClusterServices.cacheMode.NON_TRANSACTIONAL)); } catch (CacheConfigException cce) { logger.error("\nCache configuration invalid - check cache mode"); } catch (CacheExistException ce) { - logger - .error("\nCache already exits - destroy and recreate if needed"); + logger.error("\nCache already exits - destroy and recreate if needed"); } } - @SuppressWarnings( { "unchecked", "deprecation" }) + @SuppressWarnings({ "unchecked", "deprecation" }) private void retrieveCaches() { if (clusterGlobalService == null) { logger.error("un-initialized clusterService, can't retrieve cache"); @@ -203,25 +206,23 @@ public class UserManagerImpl implements IUserManager, IObjectReader, remoteServerSaveConfigEvent = (ConcurrentMap) clusterGlobalService .getCache("usermanager.remoteServerSaveConfigEvent"); if (remoteServerSaveConfigEvent == null) { - logger - .error("\nFailed to get cache for remoteServerSaveConfigEvent"); + logger.error("\nFailed to get cache for remoteServerSaveConfigEvent"); } authorizationSaveConfigEvent = (ConcurrentMap) clusterGlobalService .getCache("usermanager.authorizationSaveConfigEvent"); if (authorizationSaveConfigEvent == null) { - logger - .error("\nFailed to get cache for authorizationSaveConfigEvent"); + logger.error("\nFailed to get cache for authorizationSaveConfigEvent"); } } private void loadConfigurations() { - // To encode and decode user and server configuration objects - loadSecurityKeys(); - + // To encode and decode user and server configuration objects + loadSecurityKeys(); + /* - * Do not load local startup file if we already got the - * configurations synced from another cluster node + * Do not load local startup file if we already got the configurations + * synced from another cluster node */ if (localUserConfigList.isEmpty()) { loadUserConfig(); @@ -235,17 +236,15 @@ public class UserManagerImpl implements IUserManager, IObjectReader, } private void loadSecurityKeys() { - - } - private void checkDefaultNetworkAdmin() { - // If startup config is not there, it's old or it was deleted, - // need to add Default Admin + } + + private void checkDefaultNetworkAdmin() { + // If startup config is not there, it's old or it was deleted, + // need to add Default Admin if (!localUserConfigList.containsKey(defaultAdmin)) { - localUserConfigList.put(defaultAdmin, - new UserConfig(defaultAdmin, - defaultAdminPassword, - defaultAdminRole)); + localUserConfigList.put(defaultAdmin, new UserConfig(defaultAdmin, + defaultAdminPassword, defaultAdminRole)); } } @@ -269,10 +268,9 @@ public class UserManagerImpl implements IUserManager, IObjectReader, rcResponse = aaaClient.authService(userName, password, aaaServer.getAddress(), aaaServer.getSecret()); if (rcResponse.getStatus() == AuthResultEnum.AUTH_ACCEPT) { - logger - .info( - "Remote Authentication Succeeded for User: \"{}\", by Server: {}", - userName, aaaServer.getAddress()); + logger.info( + "Remote Authentication Succeeded for User: \"{}\", by Server: {}", + userName, aaaServer.getAddress()); remotelyAuthenticated = true; break; } else if (rcResponse.getStatus() == AuthResultEnum.AUTH_REJECT) { @@ -299,9 +297,10 @@ public class UserManagerImpl implements IUserManager, IObjectReader, } rcResponse = localUser.authenticate(password); if (rcResponse.getStatus() != AuthResultEnum.AUTH_ACCEPT_LOC) { - logger.info("Local Authentication Failed for User: \"{}\", Reason: {}", - userName, rcResponse.getStatus().toString()); - + logger.info( + "Local Authentication Failed for User: \"{}\", Reason: {}", + userName, rcResponse.getStatus().toString()); + return (rcResponse.getStatus()); } logger.info("Local Authentication Succeeded for User: \"{}\"", @@ -314,8 +313,8 @@ public class UserManagerImpl implements IUserManager, IObjectReader, result = new AuthenticatedUser(userName); /* - * Extract attributes from response - * All the information we are interested in is in the first Cisco VSA (vendor specific attribute). + * Extract attributes from response All the information we are + * interested in is in the first Cisco VSA (vendor specific attribute). * Just process the first VSA and return */ String attributes = (rcResponse.getData() != null && !rcResponse @@ -327,15 +326,14 @@ public class UserManagerImpl implements IUserManager, IObjectReader, authorizationInfoIsPresent = checkAuthorizationInfo(attributes); /* - * The AAA server was only used to perform the authentication - * Look for locally stored authorization info for this user - * If found, add the data to the rcResponse + * The AAA server was only used to perform the authentication Look for + * locally stored authorization info for this user If found, add the + * data to the rcResponse */ if (remotelyAuthenticated && !authorizationInfoIsPresent) { - logger - .info( - "No Remote Authorization Info provided by Server for User: \"{}\"", - userName); + logger.info( + "No Remote Authorization Info provided by Server for User: \"{}\"", + userName); logger.info( "Looking for Local Authorization Info for User: \"{}\"", userName); @@ -351,11 +349,11 @@ public class UserManagerImpl implements IUserManager, IObjectReader, } /* - * Common response parsing for local & remote authenticated user - * Looking for authorized resources, detecting attributes' validity + * Common response parsing for local & remote authenticated user Looking + * for authorized resources, detecting attributes' validity */ if (authorizationInfoIsPresent) { - // Identifying the administrative role + // Identifying the administrative role adminRoles = attributes.split(" "); result.setRoleList(adminRoles); authorized = true; @@ -378,7 +376,8 @@ public class UserManagerImpl implements IUserManager, IObjectReader, return rcResponse.getStatus(); } - // Check in the attributes string whether or not authorization information is present + // Check in the attributes string whether or not authorization information + // is present private boolean checkAuthorizationInfo(String attributes) { return (attributes != null && !attributes.isEmpty()); } @@ -389,7 +388,8 @@ public class UserManagerImpl implements IUserManager, IObjectReader, private void removeUserFromActiveList(String user) { if (!activeUsers.containsKey(user)) { - // as cookie persists in cache, we can get logout for unexisting active users + // as cookie persists in cache, we can get logout for unexisting + // active users return; } activeUsers.remove(user); @@ -435,7 +435,8 @@ public class UserManagerImpl implements IUserManager, IObjectReader, @Override public Object readObject(ObjectInputStream ois) throws FileNotFoundException, IOException, ClassNotFoundException { - // Perform the class deserialization locally, from inside the package where the class is defined + // Perform the class deserialization locally, from inside the package + // where the class is defined return ois.readObject(); } @@ -488,29 +489,28 @@ public class UserManagerImpl implements IUserManager, IObjectReader, * Interaction with GUI START */ public Status addRemoveLocalUser(UserConfig AAAconf, boolean delete) { - // Validation check - if (!AAAconf.isValid()) { - String msg = "Invalid Local User configuration"; - logger.warn(msg); - return new Status(StatusCode.BADREQUEST, msg); + // UserConfig Validation check + Status validCheck = AAAconf.validate(); + if (!validCheck.isSuccess()) { + return validCheck; } // Update Config database if (delete) { - if (AAAconf.getUser().equals(UserManagerImpl.defaultAdmin)) { - String msg = "Invalid Request: Default Network Admin User " + - "cannot be deleted"; - logger.debug(msg); - return new Status(StatusCode.NOTALLOWED, msg); - } + if (AAAconf.getUser().equals(UserManagerImpl.defaultAdmin)) { + String msg = "Invalid Request: Default Network Admin User " + + "cannot be deleted"; + logger.debug(msg); + return new Status(StatusCode.NOTALLOWED, msg); + } localUserConfigList.remove(AAAconf.getUser()); } else { - if (AAAconf.getUser().equals(UserManagerImpl.defaultAdmin)) { - String msg = "Invalid Request: Default Network Admin User " + - "cannot be added"; - logger.debug(msg); - return new Status(StatusCode.NOTALLOWED, msg); - } + if (AAAconf.getUser().equals(UserManagerImpl.defaultAdmin)) { + String msg = "Invalid Request: Default Network Admin User " + + "cannot be added"; + logger.debug(msg); + return new Status(StatusCode.NOTALLOWED, msg); + } localUserConfigList.put(AAAconf.getUser(), AAAconf); } @@ -520,7 +520,7 @@ public class UserManagerImpl implements IUserManager, IObjectReader, private Status addRemoveAAAServer(ServerConfig AAAconf, boolean delete) { // Validation check if (!AAAconf.isValid()) { - String msg = "Invalid Server configuration"; + String msg = "Invalid Server configuration"; logger.warn(msg); return new Status(StatusCode.BADREQUEST, msg); } @@ -535,10 +535,11 @@ public class UserManagerImpl implements IUserManager, IObjectReader, return new Status(StatusCode.SUCCESS, null); } - private Status addRemoveAuthInfo(AuthorizationConfig AAAconf, - boolean delete) { - if (!AAAconf.isValid()) { - String msg = "Invalid Authorization configuration"; + private Status addRemoveAuthInfo(AuthorizationConfig AAAconf, boolean delete) { + Status configCheck = AAAconf.validate(); + if (!configCheck.isSuccess()) { + String msg = "Invalid Authorization configuration: " + + configCheck.getDescription(); logger.warn(msg); return new Status(StatusCode.BADREQUEST, msg); } @@ -565,14 +566,15 @@ public class UserManagerImpl implements IUserManager, IObjectReader, @Override public Status removeLocalUser(String userName) { - if (userName == null || userName.trim().isEmpty()) { - return new Status(StatusCode.BADREQUEST, "Invalid user name"); - } - if (!localUserConfigList.containsKey(userName)) { - return new Status(StatusCode.NOTFOUND, "User does not exist"); - } + if (userName == null || userName.trim().isEmpty()) { + return new Status(StatusCode.BADREQUEST, "Invalid user name"); + } + if (!localUserConfigList.containsKey(userName)) { + return new Status(StatusCode.NOTFOUND, "User does not exist"); + } return addRemoveLocalUser(localUserConfigList.get(userName), true); } + @Override public Status addAAAServer(ServerConfig AAAconf) { return addRemoveAAAServer(AAAconf, false); @@ -605,8 +607,8 @@ public class UserManagerImpl implements IUserManager, IObjectReader, @Override public List getAuthorizationList() { - return new ArrayList(authorizationConfList - .values()); + return new ArrayList( + authorizationConfList.values()); } @Override @@ -617,12 +619,14 @@ public class UserManagerImpl implements IUserManager, IObjectReader, // update configuration entry targetConfigEntry = localUserConfigList.get(user); if (targetConfigEntry == null) { - return new Status(StatusCode.NOTFOUND, "User not found"); + return new Status(StatusCode.NOTFOUND, "User not found"); } if (false == targetConfigEntry.update(curPassword, newPassword, null)) { - return new Status(StatusCode.BADREQUEST, "Current password is incorrect"); + return new Status(StatusCode.BADREQUEST, + "Current password is incorrect"); } - localUserConfigList.put(user, targetConfigEntry); // trigger cluster update + localUserConfigList.put(user, targetConfigEntry); // trigger cluster + // update logger.info("Password changed for User \"{}\"", user); @@ -631,7 +635,8 @@ public class UserManagerImpl implements IUserManager, IObjectReader, @Override public void userLogout(String userName) { - // TODO: if user was authenticated through AAA server, send Acct-Status-Type=stop message to server with logout as reason + // TODO: if user was authenticated through AAA server, send + // Acct-Status-Type=stop message to server with logout as reason removeUserFromActiveList(userName); logger.info("User \"{}\" logged out", userName); } @@ -641,7 +646,8 @@ public class UserManagerImpl implements IUserManager, IObjectReader, */ @Override public void userTimedOut(String userName) { - // TODO: if user was authenticated through AAA server, send Acct-Status-Type=stop message to server with timeout as reason + // TODO: if user was authenticated through AAA server, send + // Acct-Status-Type=stop message to server with timeout as reason removeUserFromActiveList(userName); logger.info("User \"{}\" timed out", userName); } @@ -726,34 +732,34 @@ public class UserManagerImpl implements IUserManager, IObjectReader, ci.println(conf.getUser() + " " + conf.getRole()); } } - - public void _addAAAServer (CommandInterpreter ci) { + + public void _addAAAServer(CommandInterpreter ci) { String server = ci.nextArgument(); String secret = ci.nextArgument(); String protocol = ci.nextArgument(); - + if (server == null || secret == null || protocol == null) { - ci.println("Usage : addAAAServer "); - return; + ci.println("Usage : addAAAServer "); + return; } ServerConfig s = new ServerConfig(server, secret, protocol); addAAAServer(s); } - - public void _removeAAAServer (CommandInterpreter ci) { + + public void _removeAAAServer(CommandInterpreter ci) { String server = ci.nextArgument(); String secret = ci.nextArgument(); String protocol = ci.nextArgument(); - + if (server == null || secret == null || protocol == null) { - ci.println("Usage : addAAAServer "); - return; + ci.println("Usage : addAAAServer "); + return; } ServerConfig s = new ServerConfig(server, secret, protocol); removeAAAServer(s); } - public void _printAAAServers (CommandInterpreter ci) { + public void _printAAAServers(CommandInterpreter ci) { for (ServerConfig aaaServer : remoteServerConfigList.values()) { String protocol = aaaServer.getProtocol(); ci.println(aaaServer.getAddress() + "-" + aaaServer.getProtocol()); @@ -799,25 +805,24 @@ public class UserManagerImpl implements IUserManager, IObjectReader, /** * Function called by the dependency manager when all the required * dependencies are satisfied - * + * */ 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. - * + * 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 - * + * 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() { authProviders = new ConcurrentHashMap(); @@ -837,10 +842,10 @@ public class UserManagerImpl implements IUserManager, IObjectReader, } /** - * Function called by the dependency manager before the services - * exported by the component are unregistered, this will be - * followed by a "destroy ()" calls - * + * 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() { } @@ -858,19 +863,19 @@ public class UserManagerImpl implements IUserManager, IObjectReader, @Override public UserLevel getUserLevel(String username) { // Returns the controller well-know user level for the passed user - String roleName = null; + String roleName = null; - // First check in active users then in local configured users + // First check in active users then in local configured users if (activeUsers.containsKey(username)) { - roleName = activeUsers.get(username).getUserRoles().get(0); + roleName = activeUsers.get(username).getUserRoles().get(0); } else if (localUserConfigList.containsKey(username)) { - roleName = localUserConfigList.get(username).getRole(); + roleName = localUserConfigList.get(username).getRole(); } - + if (roleName == null) { - return UserLevel.NOUSER; + return UserLevel.NOUSER; } - + // For now only one role per user is allowed if (roleName.equals(UserLevel.SYSTEMADMIN.toString())) { return UserLevel.SYSTEMADMIN; @@ -915,7 +920,7 @@ public class UserManagerImpl implements IUserManager, IObjectReader, } return new Status(StatusCode.INTERNALERROR, - "Failed to save user configurations"); + "Failed to save user configurations"); } @Override @@ -931,8 +936,8 @@ public class UserManagerImpl implements IUserManager, IObjectReader, return new User(username, localUserConfigList.get(username) .getPassword(), enabled, accountNonExpired, - credentialsNonExpired, accountNonLocked, user - .getGrantedAuthorities(getUserLevel(username))); + credentialsNonExpired, accountNonLocked, + user.getGrantedAuthorities(getUserLevel(username))); } else throw new UsernameNotFoundException("User not found " + username); } @@ -964,8 +969,9 @@ public class UserManagerImpl implements IUserManager, IObjectReader, "Username or credentials did not match"); } - AuthResultEnum result = authenticate((String) authentication - .getPrincipal(), (String) authentication.getCredentials()); + AuthResultEnum result = authenticate( + (String) authentication.getPrincipal(), + (String) authentication.getCredentials()); if (result.equals(AuthResultEnum.AUTHOR_PASS) || result.equals(AuthResultEnum.AUTH_ACCEPT_LOC) || result.equals(AuthResultEnum.AUTH_ACCEPT)) { @@ -979,10 +985,10 @@ public class UserManagerImpl implements IUserManager, IObjectReader, } authentication = new UsernamePasswordAuthenticationToken( - authentication.getPrincipal(), authentication - .getCredentials(), user - .getGrantedAuthorities(getUserLevel(authentication - .getName()))); + authentication.getPrincipal(), + authentication.getCredentials(), + user.getGrantedAuthorities(getUserLevel(authentication + .getName()))); return authentication; } else @@ -991,34 +997,46 @@ public class UserManagerImpl implements IUserManager, IObjectReader, } - //following are setters for use in unit testing + // following are setters for use in unit testing void setLocalUserConfigList(ConcurrentMap ucl) { - if (ucl != null) { this.localUserConfigList = ucl; } + if (ucl != null) { + this.localUserConfigList = ucl; + } } - void setRemoteServerConfigList (ConcurrentMap scl) { - if (scl != null) { this.remoteServerConfigList = scl; } + + void setRemoteServerConfigList(ConcurrentMap scl) { + if (scl != null) { + this.remoteServerConfigList = scl; + } } - void setAuthorizationConfList (ConcurrentMap acl) { - if (acl != null) { this.authorizationConfList = acl; } + + void setAuthorizationConfList(ConcurrentMap acl) { + if (acl != null) { + this.authorizationConfList = acl; + } } - void setActiveUsers (ConcurrentMap au) { - if (au != null) { this.activeUsers = au; } + + void setActiveUsers(ConcurrentMap au) { + if (au != null) { + this.activeUsers = au; + } } - void setAuthProviders(ConcurrentMap ap ) { - if (ap != null){ + + void setAuthProviders(ConcurrentMap ap) { + if (ap != null) { this.authProviders = ap; } } - + @Override public ISessionManager getSessionManager() { return this.sessionMgr; } - + public void setSessionMgr(ISessionManager sessionMgr) { this.sessionMgr = sessionMgr; } - + public String getPassword(String username) { return localUserConfigList.get(username).getPassword(); } diff --git a/opendaylight/usermanager/src/test/java/org/opendaylight/controller/usermanager/internal/AuthorizationUserConfigTest.java b/opendaylight/usermanager/src/test/java/org/opendaylight/controller/usermanager/internal/AuthorizationUserConfigTest.java index 12c7690f86..d274da5248 100644 --- a/opendaylight/usermanager/src/test/java/org/opendaylight/controller/usermanager/internal/AuthorizationUserConfigTest.java +++ b/opendaylight/usermanager/src/test/java/org/opendaylight/controller/usermanager/internal/AuthorizationUserConfigTest.java @@ -21,82 +21,81 @@ import org.opendaylight.controller.usermanager.AuthResponse; */ public class AuthorizationUserConfigTest { - @Test - public void AuthorizationConfigTest() { - AuthorizationConfig authConfig; - - // test isValid - authConfig = new AuthorizationConfig(null, - UserLevel.SYSTEMADMIN.toString()); - assertFalse(authConfig.isValid()); - authConfig = new AuthorizationConfig("admin", ""); - assertFalse(authConfig.isValid()); - authConfig = new AuthorizationConfig("admin", - UserLevel.SYSTEMADMIN.toString()); - assertTrue(authConfig.isValid()); - } - - @Test - public void UserConfigTest() { - UserConfig userConfig; - - userConfig = new UserConfig(null, "cisco", - UserLevel.NETWORKOPERATOR.toString()); - assertFalse(userConfig.isValid()); - - userConfig = new UserConfig("uname", "", "cisco"); - assertFalse(userConfig.isValid()); - - userConfig = new UserConfig("uname", "ciscocisco", - UserLevel.NETWORKOPERATOR.toString()); - assertTrue(userConfig.isValid()); - - /* currentPassword mismatch */ - assertFalse(userConfig.update("Cisco", "cisco123", - UserLevel.NETWORKOPERATOR.toString())); - - assertTrue(userConfig.update("ciscocisco", null, - UserLevel.NETWORKOPERATOR.toString())); - /* New Password = null, No change in password */ - assertTrue(userConfig.getPassword().equals("ciscocisco")); - - /* Password changed successfully, no change in user role */ - assertTrue(userConfig.update("ciscocisco", "cisco123", - UserLevel.NETWORKOPERATOR.toString())); - assertTrue(userConfig.getPassword().equals("cisco123")); - assertTrue(userConfig.getRole().equals( - UserLevel.NETWORKOPERATOR.toString())); - - /* Password not changed, role changed successfully */ - assertTrue(userConfig.update("cisco123", "cisco123", - UserLevel.SYSTEMADMIN.toString())); - assertTrue(userConfig.getPassword().equals("cisco123")); - assertTrue(userConfig.getRole() - .equals(UserLevel.SYSTEMADMIN.toString())); - - /* Password and role changed successfully */ - assertTrue(userConfig.update("cisco123", "ciscocisco", - UserLevel.SYSTEMADMIN.toString())); - assertTrue(userConfig.getPassword().equals("ciscocisco")); - assertTrue(userConfig.getRole() - .equals(UserLevel.SYSTEMADMIN.toString())); - - String username = userConfig.getUser(); - assertTrue(username.equals("uname")); - - // test authenticate - AuthResponse authresp = userConfig.authenticate("ciscocisco"); - assertTrue(authresp.getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC)); - authresp = userConfig.authenticate("wrongPassword"); - assertTrue(authresp.getStatus().equals(AuthResultEnum.AUTH_REJECT_LOC)); - - // test equals() - userConfig = new UserConfig("uname", "ciscocisco", - UserLevel.NETWORKOPERATOR.toString()); - assertEquals(userConfig, userConfig); - UserConfig userConfig2 = new UserConfig("uname", - "ciscocisco", - UserLevel.NETWORKOPERATOR.toString()); - assertEquals(userConfig, userConfig2); - } + @Test + public void AuthorizationConfigTest() { + AuthorizationConfig authConfig; + + // test isValid + authConfig = new AuthorizationConfig(null, + UserLevel.SYSTEMADMIN.toString()); + assertFalse(authConfig.validate().isSuccess()); + authConfig = new AuthorizationConfig("admin", ""); + assertFalse(authConfig.validate().isSuccess()); + authConfig = new AuthorizationConfig("admin", + UserLevel.SYSTEMADMIN.toString()); + assertTrue(authConfig.validate().isSuccess()); + } + + @Test + public void UserConfigTest() { + UserConfig userConfig; + + userConfig = new UserConfig(null, "cisco", + UserLevel.NETWORKOPERATOR.toString()); + assertFalse(userConfig.validate().isSuccess()); + + userConfig = new UserConfig("uname", "", "cisco"); + assertFalse(userConfig.validate().isSuccess()); + + userConfig = new UserConfig("uname", "ciscocisco", + UserLevel.NETWORKOPERATOR.toString()); + assertTrue(userConfig.validate().isSuccess()); + + /* currentPassword mismatch */ + assertFalse(userConfig.update("Cisco", "cisco123", + UserLevel.NETWORKOPERATOR.toString())); + + assertTrue(userConfig.update("ciscocisco", null, + UserLevel.NETWORKOPERATOR.toString())); + /* New Password = null, No change in password */ + assertTrue(userConfig.getPassword().equals("ciscocisco")); + + /* Password changed successfully, no change in user role */ + assertTrue(userConfig.update("ciscocisco", "cisco123", + UserLevel.NETWORKOPERATOR.toString())); + assertTrue(userConfig.getPassword().equals("cisco123")); + assertTrue(userConfig.getRole().equals( + UserLevel.NETWORKOPERATOR.toString())); + + /* Password not changed, role changed successfully */ + assertTrue(userConfig.update("cisco123", "cisco123", + UserLevel.SYSTEMADMIN.toString())); + assertTrue(userConfig.getPassword().equals("cisco123")); + assertTrue(userConfig.getRole() + .equals(UserLevel.SYSTEMADMIN.toString())); + + /* Password and role changed successfully */ + assertTrue(userConfig.update("cisco123", "ciscocisco", + UserLevel.SYSTEMADMIN.toString())); + assertTrue(userConfig.getPassword().equals("ciscocisco")); + assertTrue(userConfig.getRole() + .equals(UserLevel.SYSTEMADMIN.toString())); + + String username = userConfig.getUser(); + assertTrue(username.equals("uname")); + + // test authenticate + AuthResponse authresp = userConfig.authenticate("ciscocisco"); + assertTrue(authresp.getStatus().equals(AuthResultEnum.AUTH_ACCEPT_LOC)); + authresp = userConfig.authenticate("wrongPassword"); + assertTrue(authresp.getStatus().equals(AuthResultEnum.AUTH_REJECT_LOC)); + + // test equals() + userConfig = new UserConfig("uname", "ciscocisco", + UserLevel.NETWORKOPERATOR.toString()); + assertEquals(userConfig, userConfig); + UserConfig userConfig2 = new UserConfig("uname", "ciscocisco", + UserLevel.NETWORKOPERATOR.toString()); + assertEquals(userConfig, userConfig2); + } } diff --git a/opendaylight/web/devices/src/main/resources/js/page.js b/opendaylight/web/devices/src/main/resources/js/page.js index d21f8d83a7..7a2b579326 100644 --- a/opendaylight/web/devices/src/main/resources/js/page.js +++ b/opendaylight/web/devices/src/main/resources/js/page.js @@ -62,7 +62,7 @@ one.f.switchmanager = { return $table; }, validateName: function(name) { - return name.match(/^[a-zA-Z0-9][a-zA-Z0-9_\-\.]{1,31}$/g) == null ? false : true; + return (name.length < 256); } }; @@ -177,7 +177,7 @@ one.f.switchmanager.nodesLearnt = { var result = {}; result['nodeName'] = $('#' + one.f.switchmanager.nodesLearnt.id.modal.form.nodeName, $modal).val(); if(!one.f.switchmanager.validateName(result['nodeName'])) { - alert("Node name can contain alphabets numbers and characters _ - . upto 32 characters in length"); + alert("Node name can contain upto 255 characters"); return; } result['nodeId'] = $('#' + one.f.switchmanager.nodesLearnt.id.modal.form.nodeId, $modal).val(); @@ -386,7 +386,7 @@ one.f.switchmanager.subnetGatewayConfig = { var result = {}; result['gatewayName'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.name, $modal).val(); if(!one.f.switchmanager.validateName(result['gatewayName'])) { - alert("Gateway name can contain alphabets numbers and characters _ - . upto 32 characters in length"); + alert("Gateway name can contain upto 255 characters"); return; } result['gatewayIPAddress'] = $('#' + one.f.switchmanager.subnetGatewayConfig.id.modal.form.gatewayIPAddress, $modal).val();