Adding a small hack to allow resolving model specific resources against the class-loader of the model.

Change-Id: I78dd29cd626495005cec094a8a6f1a952e3e68df
diff --git a/apps/yang-gui/BUCK b/apps/yang-gui/BUCK
index a3470f8..319dbf6 100644
--- a/apps/yang-gui/BUCK
+++ b/apps/yang-gui/BUCK
@@ -1,6 +1,7 @@
 COMPILE_DEPS = [
     '//lib:CORE_DEPS',
     '//lib:onos-yang-runtime',
+    '//apps/yang:onos-apps-yang',
 ]
 
 osgi_jar_with_tests (
diff --git a/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java b/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java
index 9b90d5e..26909ad 100644
--- a/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java
+++ b/apps/yang-gui/src/main/java/org/onosproject/yang/gui/YangModelMessageHandler.java
@@ -25,6 +25,9 @@
 import org.onosproject.ui.UiMessageHandler;
 import org.onosproject.ui.table.TableModel;
 import org.onosproject.ui.table.TableRequestHandler;
+import org.onosproject.yang.YangClassLoaderRegistry;
+import org.onosproject.yang.model.DefaultYangModuleId;
+import org.onosproject.yang.model.ModelException;
 import org.onosproject.yang.model.YangModel;
 import org.onosproject.yang.model.YangModule;
 import org.onosproject.yang.model.YangModuleId;
@@ -65,6 +68,7 @@
     private final Logger log = LoggerFactory.getLogger(getClass());
 
     private YangModelRegistry modelRegistry;
+    private YangClassLoaderRegistry classLoaderRegistry;
 
 
     // ===============-=-=-=-=-=-==================-=-=-=-=-=-=-===========
@@ -73,6 +77,7 @@
     public void init(UiConnection connection, ServiceDirectory directory) {
         super.init(connection, directory);
         modelRegistry = directory.get(YangModelRegistry.class);
+        classLoaderRegistry = directory.get(YangClassLoaderRegistry.class);
     }
 
     @Override
@@ -132,20 +137,20 @@
 
         @Override
         public void process(ObjectNode payload) {
-            String name = string(payload, ID);
             String modelId = string(payload, MODEL_ID);
-            YangModule module = getModule(modelId, name);
+            String moduleName = string(payload, ID);
+            String revision = string(payload, REVISION);
+            YangModule module = getModule(modelId, new DefaultYangModuleId(moduleName, revision));
 
             ObjectNode data = objectNode();
-            data.put(ID, name);
-            if (module != null) {
-                data.put(REVISION, module.getYangModuleId().revision());
-                data.put(MODEL_ID, modelId);
+            data.put(MODEL_ID, modelId);
+            data.put(ID, moduleName);
+            data.put(REVISION, revision);
 
+            if (module != null) {
                 ArrayNode source = arrayNode();
                 data.set(SOURCE, source);
-
-                addSource(source, module.getYangSource());
+                addSource(source, getSource(modelId, module));
             }
 
             ObjectNode rootNode = objectNode();
@@ -153,6 +158,23 @@
             sendMessage(DETAILS_RESP, rootNode);
         }
 
+        // FIXME: Hack to properly resolve the YANG source resource
+        private InputStream getSource(String modelId, YangModule module) {
+            try {
+                module.getYangSource(); // trigger exception
+            } catch (ModelException e) {
+                // Strip the YANG source file base-name and then use it to access
+                // the corresponding resource in the correct run-time context.
+                String msg = e.getMessage();
+                int i = msg.lastIndexOf('/');
+                String baseName = i > 0 ? msg.substring(i) : msg;
+                ClassLoader loader = classLoaderRegistry.getClassLoader(modelId);
+                return loader == null ? null :
+                        loader.getResourceAsStream("/yang/resources" + baseName);
+            }
+            return null;
+        }
+
         private void addSource(ArrayNode source, InputStream yangSource) {
             try (InputStreamReader isr = new InputStreamReader(yangSource);
                  BufferedReader br = new BufferedReader(isr)) {
@@ -160,27 +182,15 @@
                 while ((line = br.readLine()) != null) {
                     source.add(line);
                 }
-
             } catch (IOException e) {
                 log.warn("Unable to read YANG source", e);
             }
         }
     }
 
-
-    private YangModule getModule(String modelId, String name) {
-        int nid = Integer.parseInt(modelId.substring(2));
-        log.info("Got {}; {}", modelId, nid);
-        YangModel model = modelRegistry.getModels().stream()
-                .filter(m -> m.getYangModelId().equals(modelId))
-                .findFirst().orElse(null);
-        if (model != null) {
-            log.info("Got model");
-            return model.getYangModules().stream()
-                    .filter(m -> m.getYangModuleId().moduleName().contentEquals(name))
-                    .findFirst().orElse(null);
-        }
-        return null;
+    private YangModule getModule(String modelId, DefaultYangModuleId moduleId) {
+        YangModel model = modelRegistry.getModel(modelId);
+        return model != null ? model.getYangModule(moduleId) : null;
     }
 
 }
diff --git a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js
index 6dfb890..953fa21 100644
--- a/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js
+++ b/apps/yang-gui/src/main/resources/app/view/yangModel/yangModel.js
@@ -159,7 +159,11 @@
             // row selection callback
             function selCb($event, row) {
                 if ($scope.selId) {
-                    wss.sendEvent(detailsReq, { modelId: row.modelId, id: row.id  });
+                    wss.sendEvent(detailsReq, {
+                        modelId: row.modelId,
+                        id: row.id,
+                        revision: row.revision
+                    });
                 } else {
                     $scope.hidePanel();
                 }
diff --git a/apps/yang/src/main/java/org/onosproject/yang/AbstractYangModelRegistrator.java b/apps/yang/src/main/java/org/onosproject/yang/AbstractYangModelRegistrator.java
index 094c1c2..d2ec54f 100644
--- a/apps/yang/src/main/java/org/onosproject/yang/AbstractYangModelRegistrator.java
+++ b/apps/yang/src/main/java/org/onosproject/yang/AbstractYangModelRegistrator.java
@@ -43,12 +43,17 @@
 
     private final Logger log = LoggerFactory.getLogger(getClass());
     private final Class<?> loaderClass;
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected YangModelRegistry modelRegistry;
+
     private Map<YangModuleId, AppModuleInfo> appInfo;
     protected YangModel model;
     private ModelRegistrationParam registrationParam;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected YangModelRegistry modelRegistry;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected YangClassLoaderRegistry sourceResolver;
+
     /**
      * Creates a model registrator primed with the class-loader of the specified
      * class.
@@ -80,6 +85,7 @@
         ModelRegistrationParam.Builder b =
                 DefaultModelRegistrationParam.builder().setYangModel(model);
         registrationParam = getAppInfo(b).setYangModel(model).build();
+        sourceResolver.registerClassLoader(model.getYangModelId(), loaderClass.getClassLoader());
         modelRegistry.registerModel(registrationParam);
         log.info("Started");
     }
@@ -96,6 +102,7 @@
     @Deactivate
     protected void deactivate() {
         modelRegistry.unregisterModel(registrationParam);
+        sourceResolver.unregisterClassLoader(model.getYangModelId());
         log.info("Stopped");
     }
 }
diff --git a/apps/yang/src/main/java/org/onosproject/yang/YangClassLoaderRegistry.java b/apps/yang/src/main/java/org/onosproject/yang/YangClassLoaderRegistry.java
new file mode 100644
index 0000000..7198346
--- /dev/null
+++ b/apps/yang/src/main/java/org/onosproject/yang/YangClassLoaderRegistry.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2017-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yang;
+
+import com.google.common.annotations.Beta;
+
+/**
+ * Auxiliary mechanism for resolving model IDs into class-loaders from where
+ * the model was registered.
+ */
+@Beta
+public interface YangClassLoaderRegistry {
+
+    /**
+     * Get the class loader registered for the given model id.
+     *
+     * @param modelId model identifier
+     * @return class loader registered for the model
+     */
+    ClassLoader getClassLoader(String modelId);
+
+    /**
+     * Register the class loader for the specified model.
+     *
+     * @param modelId     model identifier
+     * @param classLoader class loader
+     */
+    void registerClassLoader(String modelId, ClassLoader classLoader);
+
+    /**
+     * Register the class loader for the specified model.
+     *
+     * @param modelId model identifier
+     */
+    void unregisterClassLoader(String modelId);
+}
diff --git a/apps/yang/src/main/java/org/onosproject/yang/YangRuntimeManager.java b/apps/yang/src/main/java/org/onosproject/yang/YangRuntimeManager.java
index 063051b..c792dd8 100644
--- a/apps/yang/src/main/java/org/onosproject/yang/YangRuntimeManager.java
+++ b/apps/yang/src/main/java/org/onosproject/yang/YangRuntimeManager.java
@@ -53,7 +53,9 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 
@@ -65,7 +67,7 @@
 @Component(immediate = true)
 public class YangRuntimeManager implements YangModelRegistry,
         YangSerializerRegistry, YangRuntimeService, ModelConverter,
-        SchemaContextProvider {
+        SchemaContextProvider, YangClassLoaderRegistry {
 
     private static final String APP_ID = "org.onosproject.yang";
     private final Logger log = LoggerFactory.getLogger(getClass());
@@ -79,6 +81,8 @@
     private DefaultModelConverter modelConverter;
     private DefaultSchemaContextProvider schemaContextProvider;
 
+    private Map<String, ClassLoader> classLoaders;
+
     @Activate
     public void activate() {
         coreService.registerApplication(APP_ID);
@@ -89,6 +93,7 @@
         serializerRegistry.registerSerializer(new JsonSerializer());
         serializerRegistry.registerSerializer(new XmlSerializer());
         modelConverter = new DefaultModelConverter(modelRegistry);
+        classLoaders = new ConcurrentHashMap<>();
         log.info("Started");
     }
 
@@ -174,4 +179,19 @@
     public RpcContext getRpcContext(ResourceId resourceId) {
         return schemaContextProvider.getRpcContext(resourceId);
     }
+
+    @Override
+    public ClassLoader getClassLoader(String modelId) {
+        return classLoaders.get(modelId);
+    }
+
+    @Override
+    public void registerClassLoader(String modelId, ClassLoader classLoader) {
+        classLoaders.put(modelId, classLoader);
+    }
+
+    @Override
+    public void unregisterClassLoader(String modelId) {
+        classLoaders.remove(modelId);
+    }
 }