CDS: Add stress test RPC to the cars model
[controller.git] / opendaylight / netconf / netconf-cli / src / main / java / org / opendaylight / controller / netconf / cli / commands / CommandDispatcher.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.controller.netconf.cli.commands;
9
10 import com.google.common.base.Function;
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import com.google.common.collect.Collections2;
14 import com.google.common.collect.Lists;
15 import com.google.common.collect.Maps;
16 import java.io.InputStream;
17 import java.util.Collection;
18 import java.util.Collections;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22 import org.opendaylight.controller.md.sal.dom.api.DOMRpcService;
23 import org.opendaylight.controller.netconf.cli.NetconfDeviceConnectionHandler;
24 import org.opendaylight.controller.netconf.cli.NetconfDeviceConnectionManager;
25 import org.opendaylight.controller.netconf.cli.commands.local.Close;
26 import org.opendaylight.controller.netconf.cli.commands.local.Connect;
27 import org.opendaylight.controller.netconf.cli.commands.local.Disconnect;
28 import org.opendaylight.controller.netconf.cli.commands.local.Help;
29 import org.opendaylight.controller.netconf.cli.commands.remote.RemoteCommand;
30 import org.opendaylight.controller.netconf.cli.io.IOUtil;
31 import org.opendaylight.yangtools.yang.common.QName;
32 import org.opendaylight.yangtools.yang.model.api.Module;
33 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
34 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
35 import org.opendaylight.yangtools.yang.parser.impl.YangParserImpl;
36
37 /**
38  * The registry of available commands local + remote. Created from schema contexts.
39  */
40 public class CommandDispatcher {
41
42     // TODO extract interface
43
44     private final Map<QName, Command> localCommands = Maps.newHashMap();
45     private final Map<String, QName> nameToQNameLocal = Maps.newHashMap();
46
47     private final Map<QName, Command> remoteCommands = Maps.newHashMap();
48     private final Map<String, QName> nameToQNameRemote = Maps.newHashMap();
49
50     public synchronized Map<QName, Command> getCommands() {
51         return Collections.unmodifiableMap(mergeCommands());
52     }
53
54     private Map<QName, Command> mergeCommands() {
55         // TODO cache this merged map
56         return mergeMaps(remoteCommands, localCommands);
57     }
58
59     private Map<String, QName> mergeCommandIds() {
60         // TODO cache this merged map
61         return mergeMaps(nameToQNameRemote, nameToQNameLocal);
62     }
63
64     private <K, V> Map<K, V> mergeMaps(final Map<K, V> remoteMap, final Map<K, V> localMap) {
65         final Map<K, V> mergedCommands = Maps.newHashMap();
66         mergedCommands.putAll(remoteMap);
67         mergedCommands.putAll(localMap);
68         return mergedCommands;
69     }
70
71     public synchronized Set<String> getCommandIds() {
72         return mergeCommandIds().keySet();
73     }
74
75     public synchronized Set<String> getRemoteCommandIds() {
76         return nameToQNameRemote.keySet();
77     }
78
79     public synchronized Optional<Command> getCommand(final String nameWithModule) {
80         final QName commandQName = mergeCommandIds().get(nameWithModule);
81         final Map<QName, Command> qNameCommandMap = mergeCommands();
82         if(commandQName == null || qNameCommandMap.containsKey(commandQName) == false) {
83             return Optional.absent();
84         }
85
86         return Optional.of(qNameCommandMap.get(commandQName));
87     }
88
89     public synchronized Optional<Command> getCommand(final QName qName) {
90         return Optional.fromNullable(mergeCommands().get(qName));
91     }
92
93     private static Optional<Command> getCommand(final Map<String, QName> commandNameMap, final Map<QName, Command> commands, final String nameWithModule) {
94         final QName qName = commandNameMap.get(nameWithModule);
95         if(qName == null)
96             return Optional.absent();
97
98         final Command command = commands.get(qName);
99         if(command == null) {
100             return Optional.absent();
101         }
102
103         return Optional.of(command);
104     }
105
106     public static final Collection<String> BASE_NETCONF_SCHEMA_PATHS = Lists.newArrayList("/schema/remote/ietf-netconf.yang",
107             "/schema/common/netconf-cli-ext.yang", "/schema/common/ietf-inet-types.yang");
108
109     public synchronized void addRemoteCommands(final DOMRpcService rpcService, final SchemaContext remoteSchema) {
110         this.addRemoteCommands(rpcService, remoteSchema, parseSchema(BASE_NETCONF_SCHEMA_PATHS));
111     }
112
113     public synchronized void addRemoteCommands(final DOMRpcService rpcService, final SchemaContext remoteSchema, final SchemaContext baseNetconfSchema) {
114         for (final SchemaContext context : Lists.newArrayList(remoteSchema, baseNetconfSchema)) {
115             for (final Module module : context.getModules()) {
116                 for (final RpcDefinition rpcDefinition : module.getRpcs()) {
117                     final Command command = RemoteCommand.fromRpc(rpcDefinition, rpcService);
118                     remoteCommands.put(rpcDefinition.getQName(), command);
119                     nameToQNameRemote.put(getCommandName(rpcDefinition, module), rpcDefinition.getQName());
120                 }
121             }
122         }
123     }
124
125     public synchronized void removeRemoteCommands() {
126         remoteCommands.clear();
127         nameToQNameRemote.clear();
128     }
129
130     public static final Collection<String> LOCAL_SCHEMA_PATHS = Lists.newArrayList("/schema/local/netconf-cli.yang", "/schema/common/netconf-cli-ext.yang",
131             "/schema/common/ietf-inet-types.yang");
132
133     public synchronized void addLocalCommands(final NetconfDeviceConnectionManager connectionManager, final SchemaContext localSchema, final Integer connectionTimeout) {
134         for (final Module module : localSchema.getModules()) {
135             for (final RpcDefinition rpcDefinition : module.getRpcs()) {
136
137                 // FIXME make local commands extensible
138                 // e.g. by yang extension defining java class to be instantiated
139                 // problem is with command specific resources
140                 // e.g. Help would need command registry
141                 final Command localCommand;
142                 if (rpcDefinition.getQName().equals(CommandConstants.HELP_QNAME)) {
143                     localCommand = Help.create(rpcDefinition, this);
144                 } else if (rpcDefinition.getQName().equals(CommandConstants.CLOSE_QNAME)) {
145                     localCommand = Close.create(rpcDefinition);
146                 } else if (rpcDefinition.getQName().equals(CommandConstants.CONNECT_QNAME)) {
147                     localCommand = Connect.create(rpcDefinition, connectionManager, connectionTimeout);
148                 } else if (rpcDefinition.getQName().equals(CommandConstants.DISCONNECT_QNAME)) {
149                     localCommand = Disconnect.create(rpcDefinition, connectionManager);
150                 } else {
151                     throw new IllegalStateException("No command implementation available for local command: " + rpcDefinition.getQName());
152                 }
153
154                 localCommands.put(localCommand.getCommandId(), localCommand);
155                 nameToQNameLocal.put(getCommandName(rpcDefinition, module), localCommand.getCommandId());
156             }
157         }
158     }
159
160     private static String getCommandName(final RpcDefinition rpcDefinition, final Module module) {
161         return IOUtil.qNameToKeyString(rpcDefinition.getQName(), module.getName());
162     }
163
164     public static SchemaContext parseSchema(final Collection<String> yangPath) {
165         final YangParserImpl yangParserImpl = new YangParserImpl();
166         // TODO change deprecated method
167         final Set<Module> modules = yangParserImpl.parseYangModelsFromStreams(loadYangs(yangPath));
168         return yangParserImpl.resolveSchemaContext(modules);
169     }
170
171     private static List<InputStream> loadYangs(final Collection<String> yangPaths) {
172
173         return Lists.newArrayList(Collections2.transform(Lists.newArrayList(yangPaths),
174                 new Function<String, InputStream>() {
175                     @Override
176                     public InputStream apply(final String input) {
177                         final InputStream resourceAsStream = NetconfDeviceConnectionHandler.class.getResourceAsStream(input);
178                         Preconditions.checkNotNull(resourceAsStream, "File %s was null", input);
179                         return resourceAsStream;
180                     }
181                 }));
182     }
183 }