-package org.simantics.scl.osgi.internal;\r
-\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
- 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
- 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.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 gnu.trove.set.hash.THashSet;
+
+public class BundleModuleSource extends EncodedTextualModuleSource implements UpdateListener.Observable {
+
+ 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
+ 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 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)
+ 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;
+ 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 {
+ 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;
+ }
+ }
+
+ public JavaReferenceValidatorFactory getJavaReferenceValidatorFactory() {
+ return new OsgiJavaReferenceValidatorFactory(bundle);
+ }
+}