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