1 package org.simantics.scl.osgi.internal;
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.URISyntaxException;
7 import java.nio.charset.Charset;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.Paths;
11 import java.security.MessageDigest;
12 import java.security.NoSuchAlgorithmException;
13 import java.util.Arrays;
15 import org.eclipse.core.runtime.FileLocator;
16 import org.osgi.framework.Bundle;
17 import org.osgi.framework.wiring.BundleWiring;
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();
129 private Path getPath() throws IOException {
131 return Paths.get(FileLocator.toFileURL(url).toURI());
132 } catch (URISyntaxException e) {
133 throw new IOException(e);
138 public boolean isUpdateable() {
140 return Files.exists(getPath());
141 } catch (IOException e) {
147 public void update(String newSourceText) {
149 Path path = getPath();
150 Files.write(path, newSourceText.getBytes(Charset.forName("UTF-8")));
151 } catch(IOException e) {
157 public void clear() {
158 if (listeners != null) {