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