]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/internal/BundleModuleSource.java
SCL-compiler should activate installed bundles
[simantics/platform.git] / bundles / org.simantics.scl.osgi / src / org / simantics / scl / osgi / internal / BundleModuleSource.java
index 66431fe50628ac47e7dd8bfcdf6681da31d688cb..a805e6026607c2f31e708651ba67fa982d5d5d90 100644 (file)
-package org.simantics.scl.osgi.internal;\r
-\r
-import java.io.File;\r
-import java.io.IOException;\r
-import java.io.InputStream;\r
-import java.net.URISyntaxException;\r
-import java.net.URL;\r
-import java.nio.charset.Charset;\r
-import java.nio.file.Files;\r
-import java.nio.file.Path;\r
-import java.nio.file.Paths;\r
-import java.security.MessageDigest;\r
-import java.security.NoSuchAlgorithmException;\r
-import java.util.ArrayList;\r
-import java.util.Arrays;\r
-\r
-import org.eclipse.core.runtime.FileLocator;\r
-import org.osgi.framework.Bundle;\r
-import org.osgi.framework.wiring.BundleWiring;\r
-import org.simantics.scl.compiler.module.ImportDeclaration;\r
-import org.simantics.scl.compiler.module.repository.UpdateListener;\r
-import org.simantics.scl.compiler.source.EncodedTextualModuleSource;\r
-import org.simantics.scl.compiler.types.Type;\r
-\r
-public class BundleModuleSource extends EncodedTextualModuleSource {\r
-\r
-    public static final ImportDeclaration[] DEFAULT_IMPORTS = new ImportDeclaration[] {\r
-        new ImportDeclaration("Builtin", ""),\r
-        new ImportDeclaration("StandardLibrary", "")\r
-    };\r
-    \r
-    public static final ImportDeclaration[] DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY = new ImportDeclaration[] {\r
-        new ImportDeclaration("Builtin", ""),\r
-    };\r
-    \r
-    public final Bundle bundle;\r
-    public final URL url;\r
-    \r
-    private byte[] digest;\r
-    private ArrayList<UpdateListener> listeners;\r
-    \r
-    public BundleModuleSource(String moduleName, Bundle bundle, URL url) {\r
-        super(moduleName);\r
-        this.bundle = bundle;\r
-        this.url = url;\r
-    }\r
-\r
-    @Override\r
-    protected ImportDeclaration[] getBuiltinImports(UpdateListener listener) {\r
-        if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))\r
-            return DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY;\r
-        else\r
-            return DEFAULT_IMPORTS;\r
-    }\r
-    \r
-    private byte[] computeDigest() {\r
-        try {\r
-            InputStream stream = url.openStream();\r
-            try {\r
-                MessageDigest digest = MessageDigest.getInstance("SHA1");\r
-                byte[] buffer = new byte[1024];\r
-                while(true) {\r
-                    int count = stream.read(buffer);\r
-                    if(count <= 0)\r
-                        break;\r
-                    digest.update(buffer, 0, count);\r
-                }\r
-                return digest.digest();\r
-            } catch (NoSuchAlgorithmException e) {\r
-                e.printStackTrace();\r
-                return new byte[0];\r
-            } finally {\r
-                stream.close();\r
-            }\r
-        } catch(IOException e) {\r
-            e.printStackTrace();\r
-            return new byte[0];\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    protected InputStream getSourceStream(UpdateListener listener)\r
-            throws IOException {\r
-        if(digest == null)\r
-            digest = computeDigest();\r
-        if(listener != null) {\r
-            if(listeners == null)\r
-                listeners = new ArrayList<UpdateListener>(2);\r
-            listeners.add(listener);\r
-        }\r
-        return url.openStream();\r
-    }\r
-    \r
-    @Override\r
-    public ClassLoader getClassLoader() {\r
-        if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))\r
-            return Type.class.getClassLoader();\r
-        else {\r
-            BundleWiring wiring = bundle.adapt(BundleWiring.class);\r
-            if(wiring != null)\r
-                return wiring.getClassLoader();\r
-            else\r
-                return getClass().getClassLoader();\r
-        }\r
-    }\r
-\r
-    public void checkUpdates() {\r
-        System.out.println(url + " checkUpdates");\r
-        if(digest != null && listeners != null) {\r
-            byte[] newDigest = computeDigest();\r
-            if(!Arrays.equals(digest, newDigest)) {\r
-                digest = newDigest;\r
-                ArrayList<UpdateListener> oldListeners = listeners;\r
-                listeners = null;\r
-                for(UpdateListener listener : oldListeners)\r
-                    listener.notifyAboutUpdate();\r
-            }\r
-        }\r
-    }\r
-    \r
-    private Path getPath() throws IOException {\r
-        try {\r
-            return Paths.get(FileLocator.toFileURL(url).toURI());\r
-        } catch (URISyntaxException e) {\r
-            throw new IOException(e);\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    public boolean isUpdateable() {\r
-        try {\r
-            return Files.exists(getPath());\r
-        } catch (IOException e) {\r
-            return false;\r
-        }\r
-    }\r
-    \r
-    @Override\r
-    public void update(String newSourceText) {\r
-        System.out.println(url + " update");\r
-        try {\r
-            Path path = getPath();\r
-            Files.write(path, newSourceText.getBytes(Charset.forName("UTF-8")));\r
-        } catch(IOException e) {\r
-            e.printStackTrace();\r
-        }\r
-        checkUpdates();\r
-    }\r
-\r
-    public void clear() {\r
-        if (listeners != null) {\r
-            listeners.clear();\r
-            listeners = null;\r
-        }\r
-    }\r
-\r
-}\r
+package org.simantics.scl.osgi.internal;
+
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import org.eclipse.core.runtime.FileLocator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.wiring.BundleWiring;
+import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidatorFactory;
+import org.simantics.scl.compiler.module.ImportDeclaration;
+import org.simantics.scl.compiler.module.repository.UpdateListener;
+import org.simantics.scl.compiler.source.EncodedTextualModuleSource;
+import org.simantics.scl.compiler.types.Type;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import gnu.trove.set.hash.THashSet;
+
+public class BundleModuleSource extends EncodedTextualModuleSource implements UpdateListener.Observable {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(BundleModuleSource.class);
+
+    public static final ImportDeclaration[] DEFAULT_IMPORTS = new ImportDeclaration[] {
+        new ImportDeclaration("Builtin", ""),
+        new ImportDeclaration("StandardLibrary", "")
+    };
+    
+    public static final ImportDeclaration[] DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY = new ImportDeclaration[] {
+        new ImportDeclaration("Builtin", ""),
+    };
+    
+    public final Bundle bundle;
+    public final URL url;
+    
+    private byte[] digest;
+    private THashSet<UpdateListener> listeners;
+    
+    public BundleModuleSource(String moduleName, Bundle bundle, URL url) {
+        super(moduleName);
+        this.bundle = bundle;
+        this.url = url;
+    }
+    
+    @Override
+    public void removeListener(UpdateListener listener) {
+        if(listeners != null)
+            synchronized(listeners) {
+                listeners.remove(listener);
+            }
+    }
+
+    @Override
+    public ImportDeclaration[] getBuiltinImports(UpdateListener listener) {
+        if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))
+            return DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY;
+        else
+            return DEFAULT_IMPORTS;
+    }
+    
+    private byte[] computeDigest() {
+        try {
+            InputStream stream = url.openStream();
+            try {
+                MessageDigest digest = MessageDigest.getInstance("SHA1");
+                byte[] buffer = new byte[1024];
+                while(true) {
+                    int count = stream.read(buffer);
+                    if(count <= 0)
+                        break;
+                    digest.update(buffer, 0, count);
+                }
+                return digest.digest();
+            } catch (NoSuchAlgorithmException e) {
+                LOGGER.error("No SHA1 algorithm found", e);
+                return new byte[0];
+            } finally {
+                stream.close();
+            }
+        } catch(IOException e) {
+            LOGGER.error("Could not compute digest for {}", getModuleName(), e);
+            return new byte[0];
+        }
+    }
+    
+    @Override
+    protected InputStream getSourceStream(UpdateListener listener)
+            throws IOException {
+        if(digest == null)
+            digest = computeDigest();
+        if(listener != null) {
+            if(listeners == null)
+                listeners = new THashSet<UpdateListener>(4);
+            listeners.add(listener);
+            listener.addObservable(this);
+        }
+        return url.openStream();
+    }
+
+    @Override
+    public ClassLoader getClassLoader() {
+        if (bundle.getSymbolicName().equals("org.simantics.scl.runtime"))
+            return Type.class.getClassLoader();
+        else {
+            BundleWiring wiring = bundle.adapt(BundleWiring.class);
+            if (wiring == null && bundle.getState() == Bundle.INSTALLED) {
+                try {
+                    bundle.start();
+                } catch (BundleException e) {
+                    LOGGER.error("Could not start bundle {}", bundle.getSymbolicName(), e);
+                }
+                wiring = bundle.adapt(BundleWiring.class);
+            }
+            if (wiring != null) {
+                return wiring.getClassLoader();
+            } else {
+                LOGGER.error("Couldn't find class loader for bundle {} with state {}", bundle.getSymbolicName(), BundleUtils.resolveBundleState(bundle));
+                return getClass().getClassLoader();
+            }
+        }
+    }
+
+    public void checkUpdates() {
+        if(digest != null && listeners != null) {
+            byte[] newDigest = computeDigest();
+            if(!Arrays.equals(digest, newDigest)) {
+                digest = newDigest;
+                THashSet<UpdateListener> oldListeners = listeners;
+                listeners = null;
+                for(UpdateListener listener : oldListeners)
+                    listener.notifyAboutUpdate();
+            }
+        }
+    }
+
+    /*
+     * This code is a copy from org.simantics.utils.ui.BundleUtils
+     */
+    public static File resolveWritableBundleFile(URL url) throws IOException {
+        // This returns file, jar, http etc. - essentially resolves the bundle protocol
+        URL resolved = FileLocator.resolve(url);
+        if (resolved.getProtocol().equals("file")) {
+            return new File(resolved.getPath());
+        }
+        return null;
+    }
+
+    private Path getPath() throws IOException {
+        File file = resolveWritableBundleFile(url);
+        return file != null ? file.toPath() : null;
+    }
+
+    @Override
+    public boolean isUpdateable() {
+        try {
+            Path path = getPath();
+            if(path == null)
+                return false;
+            return Files.exists(path);
+        } catch (IOException e) {
+            LOGGER.debug("Could not check if {} is updateable", this, e);
+            return false;
+        }
+    }
+
+    @Override
+    public void update(String newSourceText) {
+        try {
+            Path path = getPath();
+            if(path == null)
+                return;
+            Files.write(path, newSourceText.getBytes(Charset.forName("UTF-8")));
+        } catch(IOException e) {
+            LOGGER.error("Could not update module {} in url {} with text {}", getModuleName(), url, newSourceText);
+        }
+        checkUpdates();
+    }
+
+    public void clear() {
+        if (listeners != null) {
+            listeners.clear();
+            listeners = null;
+        }
+    }
+
+    public JavaReferenceValidatorFactory getJavaReferenceValidatorFactory() {
+        return new OsgiJavaReferenceValidatorFactory(bundle);
+    }
+}