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