X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.scl.osgi%2Fsrc%2Forg%2Fsimantics%2Fscl%2Fosgi%2Finternal%2FBundleModuleSource.java;h=a805e6026607c2f31e708651ba67fa982d5d5d90;hp=a4dce2101eff9d427f23cbf08e2b9d23a0aabe05;hb=5704e9deb877257b2c0c542e185fda124cf3ce37;hpb=593a8f75d9dbc363234002dc500c346afbeba040 diff --git a/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/internal/BundleModuleSource.java b/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/internal/BundleModuleSource.java index a4dce2101..a805e6026 100644 --- a/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/internal/BundleModuleSource.java +++ b/bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/internal/BundleModuleSource.java @@ -1,154 +1,198 @@ -package org.simantics.scl.osgi.internal; - -import java.io.IOException; -import java.io.InputStream; -import java.net.URISyntaxException; -import java.net.URL; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.util.ArrayList; -import java.util.Arrays; - -import org.eclipse.core.runtime.FileLocator; -import org.osgi.framework.Bundle; -import org.osgi.framework.wiring.BundleWiring; -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; - -public class BundleModuleSource extends EncodedTextualModuleSource { - - 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 ArrayList listeners; - - public BundleModuleSource(String moduleName, Bundle bundle, URL url) { - super(moduleName); - this.bundle = bundle; - this.url = url; - } - - @Override - protected 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) { - e.printStackTrace(); - return new byte[0]; - } finally { - stream.close(); - } - } catch(IOException e) { - e.printStackTrace(); - 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 ArrayList(2); - listeners.add(listener); - } - 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) - return wiring.getClassLoader(); - else - return getClass().getClassLoader(); - } - } - - public void checkUpdates() { - if(digest != null && listeners != null) { - byte[] newDigest = computeDigest(); - if(!Arrays.equals(digest, newDigest)) { - digest = newDigest; - ArrayList oldListeners = listeners; - listeners = null; - for(UpdateListener listener : oldListeners) - listener.notifyAboutUpdate(); - } - } - } - - private Path getPath() throws IOException { - try { - return Paths.get(FileLocator.toFileURL(url).toURI()); - } catch (URISyntaxException e) { - throw new IOException(e); - } - } - - @Override - public boolean isUpdateable() { - try { - return Files.exists(getPath()); - } catch (IOException e) { - return false; - } - } - - @Override - public void update(String newSourceText) { - try { - Path path = getPath(); - Files.write(path, newSourceText.getBytes(Charset.forName("UTF-8"))); - } catch(IOException e) { - e.printStackTrace(); - } - checkUpdates(); - } - - public void clear() { - if (listeners != null) { - listeners.clear(); - listeners = null; - } - } - -} +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 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(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 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); + } +}