Merge "Re-added config.version to config-module-archetype."
[controller.git] / opendaylight / md-sal / sal-rest-docgen / src / main / java / org / opendaylight / controller / sal / rest / doc / mountpoints / MountPointSwagger.java
1 /*
2  * Copyright (c) 2014 Brocade Communications 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.sal.rest.doc.mountpoints;
9
10 import java.util.Collections;
11 import java.util.Comparator;
12 import java.util.HashMap;
13 import java.util.LinkedList;
14 import java.util.List;
15 import java.util.Map;
16 import java.util.Map.Entry;
17 import java.util.TreeMap;
18 import java.util.concurrent.atomic.AtomicLong;
19 import java.util.concurrent.atomic.AtomicReference;
20
21 import javax.ws.rs.core.UriInfo;
22
23 import org.opendaylight.controller.sal.core.api.model.SchemaService;
24 import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
25 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
26 import org.opendaylight.controller.sal.core.api.mount.MountProvisionService.MountProvisionListener;
27 import org.opendaylight.controller.sal.rest.doc.impl.BaseYangSwaggerGenerator;
28 import org.opendaylight.controller.sal.rest.doc.swagger.Api;
29 import org.opendaylight.controller.sal.rest.doc.swagger.ApiDeclaration;
30 import org.opendaylight.controller.sal.rest.doc.swagger.Operation;
31 import org.opendaylight.controller.sal.rest.doc.swagger.Resource;
32 import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList;
33 import org.opendaylight.yangtools.yang.common.QName;
34 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
35 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
36 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
37 import org.opendaylight.yangtools.yang.model.api.Module;
38 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
39
40 public class MountPointSwagger extends BaseYangSwaggerGenerator implements MountProvisionListener {
41
42     private static final String DATASTORES_REVISION = "-";
43     private static final String DATASTORES_LABEL = "Datastores";
44
45     private MountProvisionService mountService;
46     private final Map<InstanceIdentifier, Long> instanceIdToLongId = new TreeMap<>(
47             new Comparator<InstanceIdentifier>() {
48                 @Override
49                 public int compare(final InstanceIdentifier o1, final InstanceIdentifier o2) {
50                     return o1.toString().compareToIgnoreCase(o2.toString());
51                 }
52             });
53     private final Map<Long, InstanceIdentifier> longIdToInstanceId = new HashMap<>();
54     private final Object lock = new Object();
55
56     private final AtomicLong idKey = new AtomicLong(0);
57
58     private static AtomicReference<MountPointSwagger> selfRef = new AtomicReference<>();
59     private SchemaService globalSchema;
60
61     public Map<String, Long> getInstanceIdentifiers() {
62         Map<String, Long> urlToId = new HashMap<>();
63         synchronized (lock) {
64             SchemaContext context = globalSchema.getGlobalContext();
65             for (Entry<InstanceIdentifier, Long> entry : instanceIdToLongId.entrySet()) {
66                 String modName = findModuleName(entry.getKey(), context);
67                 urlToId.put(generateUrlPrefixFromInstanceID(entry.getKey(), modName),
68                         entry.getValue());
69             }
70         }
71         return urlToId;
72     }
73
74     public void setGlobalSchema(final SchemaService globalSchema) {
75         this.globalSchema = globalSchema;
76     }
77
78     private String findModuleName(final InstanceIdentifier id, final SchemaContext context) {
79         PathArgument rootQName = id.getPathArguments().iterator().next();
80         for (Module mod : context.getModules()) {
81             if (mod.getDataChildByName(rootQName.getNodeType()) != null) {
82                 return mod.getName();
83             }
84         }
85         return null;
86     }
87
88     private String generateUrlPrefixFromInstanceID(final InstanceIdentifier key, final String moduleName) {
89         StringBuilder builder = new StringBuilder();
90         if (moduleName != null) {
91             builder.append(moduleName);
92             builder.append(':');
93         }
94         boolean first = true;
95         for (PathArgument arg : key.getPathArguments()) {
96
97             String name = arg.getNodeType().getLocalName();
98             if (first) {
99                 first = false;
100             } else {
101                 builder.append('/');
102             }
103             builder.append(name);
104             if (arg instanceof InstanceIdentifier.NodeIdentifierWithPredicates) {
105                 NodeIdentifierWithPredicates nodeId = (NodeIdentifierWithPredicates) arg;
106                 for (Entry<QName, Object> entry : nodeId.getKeyValues().entrySet()) {
107                     builder.append('/').append(entry.getValue());
108                 }
109             }
110         }
111
112         return builder.append('/').toString();
113     }
114
115     private String getYangMountUrl(final InstanceIdentifier key) {
116         String modName = findModuleName(key, globalSchema.getGlobalContext());
117         return generateUrlPrefixFromInstanceID(key, modName) + "yang-ext:mount/";
118     }
119
120     public ResourceList getResourceList(final UriInfo uriInfo, final Long id) {
121         InstanceIdentifier iid = getInstanceId(id);
122         if (iid == null) {
123             return null; // indicating not found.
124         }
125         SchemaContext context = getSchemaContext(iid);
126         String urlPrefix = getYangMountUrl(iid);
127         if (context == null) {
128             return createResourceList();
129         }
130         List<Resource> resources = new LinkedList<>();
131         Resource dataStores = new Resource();
132         dataStores.setDescription("Provides methods for accessing the data stores.");
133         dataStores.setPath(generatePath(uriInfo, DATASTORES_LABEL, DATASTORES_REVISION));
134         resources.add(dataStores);
135         ResourceList list = super.getResourceListing(uriInfo, context, urlPrefix);
136         resources.addAll(list.getApis());
137         list.setApis(resources);
138         return list;
139     }
140
141     private InstanceIdentifier getInstanceId(final Long id) {
142         InstanceIdentifier instanceId;
143         synchronized (lock) {
144             instanceId = longIdToInstanceId.get(id);
145         }
146         return instanceId;
147     }
148
149     private SchemaContext getSchemaContext(final InstanceIdentifier id) {
150
151         if (id == null) {
152             return null;
153         }
154
155         MountProvisionInstance mountPoint = mountService.getMountPoint(id);
156         if (mountPoint == null) {
157             return null;
158         }
159
160         SchemaContext context = mountPoint.getSchemaContext();
161         if (context == null) {
162             return null;
163         }
164         return context;
165     }
166
167     public ApiDeclaration getMountPointApi(final UriInfo uriInfo, final Long id, final String module, final String revision) {
168         InstanceIdentifier iid = getInstanceId(id);
169         SchemaContext context = getSchemaContext(iid);
170         String urlPrefix = getYangMountUrl(iid);
171         if (context == null) {
172             return null;
173         }
174
175         if (DATASTORES_LABEL.equals(module) && DATASTORES_REVISION.equals(revision)) {
176             return generateDataStoreApiDoc(uriInfo, urlPrefix);
177         }
178         return super.getApiDeclaration(module, revision, uriInfo, context, urlPrefix);
179     }
180
181     private ApiDeclaration generateDataStoreApiDoc(final UriInfo uriInfo, final String context) {
182
183         ApiDeclaration declaration = super.createApiDeclaration(createBasePathFromUriInfo(uriInfo));
184         List<Api> apis = new LinkedList<>();
185         apis.add(createGetApi("config",
186                 "Queries the config (startup) datastore on the mounted hosted.", context));
187         apis.add(createGetApi("operational",
188                 "Queries the operational (running) datastore on the mounted hosted.", context));
189         apis.add(createGetApi("operations",
190                 "Queries the available operations (RPC calls) on the mounted hosted.", context));
191         declaration.setApis(apis);
192         return declaration;
193
194     }
195
196     private Api createGetApi(final String datastore, final String note, final String context) {
197         Operation getConfig = new Operation();
198         getConfig.setMethod("GET");
199         getConfig.setNickname("GET " + datastore);
200         getConfig.setNotes(note);
201
202         Api api = new Api();
203         api.setPath(getDataStorePath("/" + datastore + "/", context));
204         api.setOperations(Collections.singletonList(getConfig));
205
206         return api;
207     }
208
209     public void setMountService(final MountProvisionService mountService) {
210         this.mountService = mountService;
211     }
212
213     @Override
214     public void onMountPointCreated(final InstanceIdentifier path) {
215         synchronized (lock) {
216             Long idLong = idKey.incrementAndGet();
217             instanceIdToLongId.put(path, idLong);
218             longIdToInstanceId.put(idLong, path);
219         }
220     }
221
222     @Override
223     public void onMountPointRemoved(final InstanceIdentifier path) {
224         synchronized (lock) {
225             Long id = instanceIdToLongId.remove(path);
226             longIdToInstanceId.remove(id);
227         }
228     }
229
230     public static MountPointSwagger getInstance() {
231         MountPointSwagger swagger = selfRef.get();
232         if (swagger == null) {
233             selfRef.compareAndSet(null, new MountPointSwagger());
234             swagger = selfRef.get();
235         }
236         return swagger;
237     }
238
239 }