Bug 931, Bug 910 - Enhance Restconf Swagger Documentation
[controller.git] / opendaylight / md-sal / sal-rest-docgen / src / main / java / org / opendaylight / controller / sal / rest / doc / mountpoints / MountPointSwagger.java
diff --git a/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/mountpoints/MountPointSwagger.java b/opendaylight/md-sal/sal-rest-docgen/src/main/java/org/opendaylight/controller/sal/rest/doc/mountpoints/MountPointSwagger.java
new file mode 100644 (file)
index 0000000..b996bf1
--- /dev/null
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2014 Brocade Communications Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+package org.opendaylight.controller.sal.rest.doc.mountpoints;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.TreeMap;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.concurrent.atomic.AtomicReference;
+
+import javax.ws.rs.core.UriInfo;
+
+import org.opendaylight.controller.sal.core.api.model.SchemaService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionInstance;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService;
+import org.opendaylight.controller.sal.core.api.mount.MountProvisionService.MountProvisionListener;
+import org.opendaylight.controller.sal.rest.doc.impl.BaseYangSwaggerGenerator;
+import org.opendaylight.controller.sal.rest.doc.swagger.Api;
+import org.opendaylight.controller.sal.rest.doc.swagger.ApiDeclaration;
+import org.opendaylight.controller.sal.rest.doc.swagger.Operation;
+import org.opendaylight.controller.sal.rest.doc.swagger.Resource;
+import org.opendaylight.controller.sal.rest.doc.swagger.ResourceList;
+import org.opendaylight.yangtools.yang.common.QName;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.NodeIdentifierWithPredicates;
+import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier.PathArgument;
+import org.opendaylight.yangtools.yang.model.api.Module;
+import org.opendaylight.yangtools.yang.model.api.SchemaContext;
+
+public class MountPointSwagger extends BaseYangSwaggerGenerator implements MountProvisionListener {
+
+    private static final String DATASTORES_REVISION = "-";
+    private static final String DATASTORES_LABEL = "Datastores";
+
+    private MountProvisionService mountService;
+    private final Map<InstanceIdentifier, Long> instanceIdToLongId = new TreeMap<>(
+            new Comparator<InstanceIdentifier>() {
+                @Override
+                public int compare(InstanceIdentifier o1, InstanceIdentifier o2) {
+                    return o1.toString().compareToIgnoreCase(o2.toString());
+                }
+            });
+    private final Map<Long, InstanceIdentifier> longIdToInstanceId = new HashMap<>();
+    private final Object lock = new Object();
+
+    private final AtomicLong idKey = new AtomicLong(0);
+
+    private static AtomicReference<MountPointSwagger> selfRef = new AtomicReference<>();
+    private SchemaService globalSchema;
+
+    public Map<String, Long> getInstanceIdentifiers() {
+        Map<String, Long> urlToId = new HashMap<>();
+        synchronized (lock) {
+            SchemaContext context = globalSchema.getGlobalContext();
+            for (Entry<InstanceIdentifier, Long> entry : instanceIdToLongId.entrySet()) {
+                String modName = findModuleName(entry.getKey(), context);
+                urlToId.put(generateUrlPrefixFromInstanceID(entry.getKey(), modName),
+                        entry.getValue());
+            }
+        }
+        return urlToId;
+    }
+
+    public void setGlobalSchema(SchemaService globalSchema) {
+        this.globalSchema = globalSchema;
+    }
+
+    private String findModuleName(InstanceIdentifier id, SchemaContext context) {
+        PathArgument rootQName = id.getPath().get(0);
+        for (Module mod : context.getModules()) {
+            if (mod.getDataChildByName(rootQName.getNodeType()) != null) {
+                return mod.getName();
+            }
+        }
+        return null;
+    }
+
+    private String generateUrlPrefixFromInstanceID(InstanceIdentifier key, String moduleName) {
+        List<PathArgument> path = key.getPath();
+        StringBuilder builder = new StringBuilder();
+        if (moduleName != null) {
+            builder.append(moduleName);
+            builder.append(":");
+        }
+        boolean first = true;
+        for (PathArgument arg : path) {
+
+            String name = arg.getNodeType().getLocalName();
+            if (first) {
+                first = false;
+            } else {
+                builder.append("/");
+            }
+            builder.append(name);
+            if (arg instanceof InstanceIdentifier.NodeIdentifierWithPredicates) {
+                NodeIdentifierWithPredicates nodeId = (NodeIdentifierWithPredicates) arg;
+                for (Entry<QName, Object> entry : nodeId.getKeyValues().entrySet()) {
+                    builder.append("/").append(entry.getValue());
+                }
+            }
+        }
+
+        return builder.append("/").toString();
+    }
+
+    private String getYangMountUrl(InstanceIdentifier key) {
+        String modName = findModuleName(key, globalSchema.getGlobalContext());
+        return generateUrlPrefixFromInstanceID(key, modName) + "yang-ext:mount/";
+    }
+
+    public ResourceList getResourceList(UriInfo uriInfo, Long id) {
+        InstanceIdentifier iid = getInstanceId(id);
+        if (iid == null) {
+            return null; // indicating not found.
+        }
+        SchemaContext context = getSchemaContext(iid);
+        String urlPrefix = getYangMountUrl(iid);
+        if (context == null) {
+            return createResourceList();
+        }
+        List<Resource> resources = new LinkedList<>();
+        Resource dataStores = new Resource();
+        dataStores.setDescription("Provides methods for accessing the data stores.");
+        dataStores.setPath(generatePath(uriInfo, DATASTORES_LABEL, DATASTORES_REVISION));
+        resources.add(dataStores);
+        ResourceList list = super.getResourceListing(uriInfo, context, urlPrefix);
+        resources.addAll(list.getApis());
+        list.setApis(resources);
+        return list;
+    }
+
+    private InstanceIdentifier getInstanceId(Long id) {
+        InstanceIdentifier instanceId;
+        synchronized (lock) {
+            instanceId = longIdToInstanceId.get(id);
+        }
+        return instanceId;
+    }
+
+    private SchemaContext getSchemaContext(InstanceIdentifier id) {
+
+        if (id == null) {
+            return null;
+        }
+
+        MountProvisionInstance mountPoint = mountService.getMountPoint(id);
+        if (mountPoint == null) {
+            return null;
+        }
+
+        SchemaContext context = mountPoint.getSchemaContext();
+        if (context == null) {
+            return null;
+        }
+        return context;
+    }
+
+    public ApiDeclaration getMountPointApi(UriInfo uriInfo, Long id, String module, String revision) {
+        InstanceIdentifier iid = getInstanceId(id);
+        SchemaContext context = getSchemaContext(iid);
+        String urlPrefix = getYangMountUrl(iid);
+        if (context == null) {
+            return null;
+        }
+
+        if (DATASTORES_LABEL.equals(module) && DATASTORES_REVISION.equals(revision)) {
+            return generateDataStoreApiDoc(uriInfo, urlPrefix);
+        }
+        return super.getApiDeclaration(module, revision, uriInfo, context, urlPrefix);
+    }
+
+    private ApiDeclaration generateDataStoreApiDoc(UriInfo uriInfo, String context) {
+
+        ApiDeclaration declaration = super.createApiDeclaration(createBasePathFromUriInfo(uriInfo));
+        List<Api> apis = new LinkedList<>();
+        apis.add(createGetApi("config",
+                "Queries the config (startup) datastore on the mounted hosted.", context));
+        apis.add(createGetApi("operational",
+                "Queries the operational (running) datastore on the mounted hosted.", context));
+        apis.add(createGetApi("operations",
+                "Queries the available operations (RPC calls) on the mounted hosted.", context));
+        declaration.setApis(apis);
+        return declaration;
+
+    }
+
+    private Api createGetApi(String datastore, String note, String context) {
+        Operation getConfig = new Operation();
+        getConfig.setMethod("GET");
+        getConfig.setNickname("GET " + datastore);
+        getConfig.setNotes(note);
+
+        Api api = new Api();
+        api.setPath(getDataStorePath("/" + datastore + "/", context));
+        api.setOperations(Collections.singletonList(getConfig));
+
+        return api;
+    }
+
+    public void setMountService(MountProvisionService mountService) {
+        this.mountService = mountService;
+    }
+
+    @Override
+    public void onMountPointCreated(InstanceIdentifier path) {
+        synchronized (lock) {
+            Long idLong = idKey.incrementAndGet();
+            instanceIdToLongId.put(path, idLong);
+            longIdToInstanceId.put(idLong, path);
+        }
+    }
+
+    @Override
+    public void onMountPointRemoved(InstanceIdentifier path) {
+        synchronized (lock) {
+            Long id = instanceIdToLongId.remove(path);
+            longIdToInstanceId.remove(id);
+        }
+    }
+
+    public static MountPointSwagger getInstance() {
+        MountPointSwagger swagger = selfRef.get();
+        if (swagger == null) {
+            selfRef.compareAndSet(null, new MountPointSwagger());
+            swagger = selfRef.get();
+        }
+        return swagger;
+    }
+
+}