1 package org.simantics.scl.osgi.internal;
4 import java.io.IOException;
5 import java.io.InputStream;
7 import java.nio.charset.Charset;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.security.MessageDigest;
11 import java.security.NoSuchAlgorithmException;
12 import java.util.Arrays;
14 import org.eclipse.core.runtime.FileLocator;
15 import org.osgi.framework.Bundle;
16 import org.osgi.framework.wiring.BundleWiring;
17 import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidatorFactory;
18 import org.simantics.scl.compiler.module.ImportDeclaration;
19 import org.simantics.scl.compiler.module.repository.UpdateListener;
20 import org.simantics.scl.compiler.source.EncodedTextualModuleSource;
21 import org.simantics.scl.compiler.types.Type;
23 import gnu.trove.set.hash.THashSet;
25 public class BundleModuleSource extends EncodedTextualModuleSource implements UpdateListener.Observable {
27 public static final ImportDeclaration[] DEFAULT_IMPORTS = new ImportDeclaration[] {
28 new ImportDeclaration("Builtin", ""),
29 new ImportDeclaration("StandardLibrary", "")
32 public static final ImportDeclaration[] DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY = new ImportDeclaration[] {
33 new ImportDeclaration("Builtin", ""),
36 public final Bundle bundle;
39 private byte[] digest;
40 private THashSet<UpdateListener> listeners;
42 public BundleModuleSource(String moduleName, Bundle bundle, URL url) {
49 public void removeListener(UpdateListener listener) {
51 synchronized(listeners) {
52 listeners.remove(listener);
57 protected ImportDeclaration[] getBuiltinImports(UpdateListener listener) {
58 if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))
59 return DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY;
61 return DEFAULT_IMPORTS;
64 private byte[] computeDigest() {
66 InputStream stream = url.openStream();
68 MessageDigest digest = MessageDigest.getInstance("SHA1");
69 byte[] buffer = new byte[1024];
71 int count = stream.read(buffer);
74 digest.update(buffer, 0, count);
76 return digest.digest();
77 } catch (NoSuchAlgorithmException e) {
83 } catch(IOException e) {
90 protected InputStream getSourceStream(UpdateListener listener)
93 digest = computeDigest();
94 if(listener != null) {
96 listeners = new THashSet<UpdateListener>(4);
97 listeners.add(listener);
98 listener.addObservable(this);
100 return url.openStream();
104 public ClassLoader getClassLoader() {
105 if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))
106 return Type.class.getClassLoader();
108 BundleWiring wiring = bundle.adapt(BundleWiring.class);
110 return wiring.getClassLoader();
112 return getClass().getClassLoader();
116 public void checkUpdates() {
117 if(digest != null && listeners != null) {
118 byte[] newDigest = computeDigest();
119 if(!Arrays.equals(digest, newDigest)) {
121 THashSet<UpdateListener> oldListeners = listeners;
123 for(UpdateListener listener : oldListeners)
124 listener.notifyAboutUpdate();
130 * This code is a copy from org.simantics.utils.ui.BundleUtils
132 public static File resolveWritableBundleFile(URL url) throws IOException {
133 // This returns file, jar, http etc. - essentially resolves the bundle protocol
134 URL resolved = FileLocator.resolve(url);
135 if (resolved.getProtocol().equals("file")) {
136 return new File(resolved.getPath());
141 private Path getPath() throws IOException {
142 File file = resolveWritableBundleFile(url);
143 return file != null ? file.toPath() : null;
147 public boolean isUpdateable() {
149 return Files.exists(getPath());
150 } catch (IOException e) {
156 public void update(String newSourceText) {
158 Path path = getPath();
159 Files.write(path, newSourceText.getBytes(Charset.forName("UTF-8")));
160 } catch(IOException e) {
166 public void clear() {
167 if (listeners != null) {
173 public JavaReferenceValidatorFactory getJavaReferenceValidatorFactory() {
174 return new OsgiJavaReferenceValidatorFactory(bundle);