2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
9 package org.opendaylight.controller.netconf.confignetconfconnector.operations.runtimerpc;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.Maps;
14 import org.opendaylight.controller.config.util.ConfigRegistryClient;
15 import org.opendaylight.controller.config.yang.store.api.YangStoreSnapshot;
16 import org.opendaylight.controller.config.yangjmxgenerator.ModuleMXBeanEntry;
17 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry;
18 import org.opendaylight.controller.config.yangjmxgenerator.RuntimeBeanEntry.Rpc;
19 import org.opendaylight.controller.config.yangjmxgenerator.attribute.SimpleTypeResolver;
20 import org.opendaylight.controller.netconf.api.NetconfDocumentedException;
21 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.fromxml.AttributeConfigElement;
22 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.attributes.mapping.SimpleAttributeMappingStrategy;
23 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.InstanceRuntimeRpc;
24 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.ModuleRpcs;
25 import org.opendaylight.controller.netconf.confignetconfconnector.mapping.rpc.Rpcs;
26 import org.opendaylight.controller.netconf.confignetconfconnector.operations.AbstractConfigNetconfOperation;
27 import org.opendaylight.controller.netconf.confignetconfconnector.operations.Commit;
28 import org.opendaylight.controller.netconf.mapping.api.HandlingPriority;
29 import org.opendaylight.controller.netconf.util.xml.XmlElement;
30 import org.opendaylight.controller.netconf.util.xml.XmlUtil;
31 import org.slf4j.Logger;
32 import org.slf4j.LoggerFactory;
33 import org.w3c.dom.Document;
34 import org.w3c.dom.Element;
36 import javax.management.ObjectName;
37 import javax.management.openmbean.SimpleType;
40 public class RuntimeRpc extends AbstractConfigNetconfOperation {
42 private static final Logger logger = LoggerFactory.getLogger(Commit.class);
43 public static final String CONTEXT_INSTANCE = "context-instance";
45 private final YangStoreSnapshot yangStoreSnapshot;
47 public RuntimeRpc(final YangStoreSnapshot yangStoreSnapshot, ConfigRegistryClient configRegistryClient,
48 String netconfSessionIdForReporting) {
49 super(configRegistryClient, netconfSessionIdForReporting);
50 this.yangStoreSnapshot = yangStoreSnapshot;
53 private String getStringRepresentation(final Object result) {
54 final SimpleType<?> simpleType = SimpleTypeResolver.getSimpleType(result.getClass().getName());
55 final Optional<String> mappedAttributeOpt = new SimpleAttributeMappingStrategy(simpleType).mapAttribute(result);
56 return mappedAttributeOpt.isPresent() ? mappedAttributeOpt.get() : "";
59 private Object executeOperation(final ConfigRegistryClient configRegistryClient, final ObjectName on,
60 final String name, final Map<String, AttributeConfigElement> attributes) {
61 final Object[] params = new Object[attributes.size()];
62 final String[] signature = new String[attributes.size()];
65 for (final String attrName : attributes.keySet()) {
66 final AttributeConfigElement attribute = attributes.get(attrName);
67 final Optional<?> resolvedValueOpt = attribute.getResolvedValue();
69 params[i] = resolvedValueOpt.isPresent() ? resolvedValueOpt.get() : attribute.getResolvedDefaultValue();
70 signature[i] = resolvedValueOpt.isPresent() ? resolvedValueOpt.get().getClass().getName() : attribute
71 .getResolvedDefaultValue().getClass().getName();
75 return configRegistryClient.invokeMethod(on, name, params, signature);
78 public NetconfOperationExecution fromXml(final XmlElement xml) throws NetconfDocumentedException {
79 final String namespace = xml.getNamespace();
80 final XmlElement contextInstanceElement = xml.getOnlyChildElement(CONTEXT_INSTANCE);
81 final String operationName = xml.getName();
83 final RuntimeRpcElementResolved id = RuntimeRpcElementResolved.fromXpath(
84 contextInstanceElement.getTextContent(), operationName, namespace);
86 final Rpcs rpcs = mapRpcs(yangStoreSnapshot.getModuleMXBeanEntryMap());
88 final ModuleRpcs rpcMapping = rpcs.getRpcMapping(id);
89 final InstanceRuntimeRpc instanceRuntimeRpc = rpcMapping.getRpc(id.getRuntimeBeanName(), operationName);
91 // TODO move to Rpcs after xpath attribute is redesigned
93 final ObjectName on = id.getObjectName(rpcMapping);
94 Map<String, AttributeConfigElement> attributes = instanceRuntimeRpc.fromXml(xml);
95 attributes = sortAttributes(attributes, xml);
97 return new NetconfOperationExecution(on, instanceRuntimeRpc.getName(), attributes,
98 instanceRuntimeRpc.getReturnType(), namespace);
102 public HandlingPriority canHandle(Document message) {
103 XmlElement requestElement = getRequestElementWithCheck(message);
105 XmlElement operationElement = requestElement.getOnlyChildElement();
106 final String netconfOperationName = operationElement.getName();
107 final String netconfOperationNamespace = operationElement.getNamespace();
109 final Optional<XmlElement> contextInstanceElement = operationElement
110 .getOnlyChildElementOptionally(CONTEXT_INSTANCE);
112 if (contextInstanceElement.isPresent() == false)
113 return HandlingPriority.CANNOT_HANDLE;
115 final RuntimeRpcElementResolved id = RuntimeRpcElementResolved.fromXpath(contextInstanceElement.get()
116 .getTextContent(), netconfOperationName, netconfOperationNamespace);
118 // TODO reuse rpcs instance in fromXml method
119 final Rpcs rpcs = mapRpcs(yangStoreSnapshot.getModuleMXBeanEntryMap());
123 final ModuleRpcs rpcMapping = rpcs.getRpcMapping(id);
124 final InstanceRuntimeRpc instanceRuntimeRpc = rpcMapping.getRpc(id.getRuntimeBeanName(),
125 netconfOperationName);
126 Preconditions.checkState(instanceRuntimeRpc != null, "No rpc found for %s:%s", netconfOperationNamespace,
127 netconfOperationName);
129 } catch (IllegalStateException e) {
130 logger.debug("Cannot handle runtime operation {}:{}", netconfOperationNamespace, netconfOperationName, e);
131 return HandlingPriority.CANNOT_HANDLE;
134 return HandlingPriority.HANDLE_WITH_DEFAULT_PRIORITY;
138 protected HandlingPriority canHandle(String netconfOperationName, String namespace) {
139 throw new UnsupportedOperationException(
140 "This should not be used since it is not possible to provide check with these attributes");
144 protected String getOperationName() {
145 throw new UnsupportedOperationException("Runtime rpc does not have a stable name");
149 protected Element handle(Document document, XmlElement xml) throws NetconfDocumentedException {
151 // TODO exception handling
152 // TODO check for namespaces and unknown elements
154 final NetconfOperationExecution execution = fromXml(xml);
156 logger.debug("Invoking operation {} on {} with arguments {}", execution.operationName, execution.on,
157 execution.attributes);
158 final Object result = executeOperation(configRegistryClient, execution.on, execution.operationName,
159 execution.attributes);
161 logger.info("Operation {} called successfully on {} with arguments {} with result {}", execution.operationName,
162 execution.on, execution.attributes, result);
164 if (execution.returnType.equals("void")) {
165 return document.createElement("ok");
167 final Element output = XmlUtil.createTextElement(document, "result", getStringRepresentation(result));
168 XmlUtil.addNamespaceAttr(output, execution.namespace);
173 private static class NetconfOperationExecution {
175 private final ObjectName on;
176 private final String operationName;
177 private final Map<String, AttributeConfigElement> attributes;
178 private final String returnType;
179 private final String namespace;
181 public NetconfOperationExecution(final ObjectName on, final String name,
182 final Map<String, AttributeConfigElement> attributes, final String returnType, final String namespace) {
184 this.operationName = name;
185 this.attributes = attributes;
186 this.returnType = returnType;
187 this.namespace = namespace;
192 private static Map<String, AttributeConfigElement> sortAttributes(
193 final Map<String, AttributeConfigElement> attributes, final XmlElement xml) {
194 final Map<String, AttributeConfigElement> sorted = Maps.newLinkedHashMap();
196 for (XmlElement xmlElement : xml.getChildElements()) {
197 final String name = xmlElement.getName();
198 if (CONTEXT_INSTANCE.equals(name) == false) { // skip context
199 // instance child node
203 final AttributeConfigElement value = attributes.get(name);
205 throw new IllegalArgumentException("Cannot find yang mapping for node " + xmlElement);
207 sorted.put(name, value);
214 private static Rpcs mapRpcs(final Map<String, Map<String, ModuleMXBeanEntry>> mBeanEntries) {
216 final Map<String, Map<String, ModuleRpcs>> map = Maps.newHashMap();
218 for (final String namespace : mBeanEntries.keySet()) {
220 Map<String, ModuleRpcs> namespaceToModules = map.get(namespace);
221 if (namespaceToModules == null) {
222 namespaceToModules = Maps.newHashMap();
223 map.put(namespace, namespaceToModules);
226 for (final String moduleName : mBeanEntries.get(namespace).keySet()) {
228 ModuleRpcs rpcMapping = namespaceToModules.get(moduleName);
229 if (rpcMapping == null) {
230 rpcMapping = new ModuleRpcs();
231 namespaceToModules.put(moduleName, rpcMapping);
234 final ModuleMXBeanEntry entry = mBeanEntries.get(namespace).get(moduleName);
236 for (final RuntimeBeanEntry runtimeEntry : entry.getRuntimeBeans()) {
237 rpcMapping.addNameMapping(runtimeEntry);
238 for (final Rpc rpc : runtimeEntry.getRpcs()) {
239 rpcMapping.addRpc(runtimeEntry, rpc);
245 return new Rpcs(map);