1 package org.simantics.scl.osgi.internal;
5 import java.io.IOException;
6 import java.io.InputStream;
8 import java.nio.charset.Charset;
9 import java.nio.file.Files;
10 import java.nio.file.Path;
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.internal.codegen.types.JavaReferenceValidatorFactory;
19 import org.simantics.scl.compiler.module.ImportDeclaration;
20 import org.simantics.scl.compiler.module.repository.UpdateListener;
21 import org.simantics.scl.compiler.source.EncodedTextualModuleSource;
22 import org.simantics.scl.compiler.types.Type;
23 import org.slf4j.Logger;
24 import org.slf4j.LoggerFactory;
26 import gnu.trove.set.hash.THashSet;
28 public class BundleModuleSource extends EncodedTextualModuleSource implements UpdateListener.Observable {
30 private static final Logger LOGGER = LoggerFactory.getLogger(BundleModuleSource.class);
32 public static final ImportDeclaration[] DEFAULT_IMPORTS = new ImportDeclaration[] {
33 new ImportDeclaration("Builtin", ""),
34 new ImportDeclaration("StandardLibrary", "")
37 public static final ImportDeclaration[] DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY = new ImportDeclaration[] {
38 new ImportDeclaration("Builtin", ""),
41 public final Bundle bundle;
44 private byte[] digest;
45 private THashSet<UpdateListener> listeners;
47 public BundleModuleSource(String moduleName, Bundle bundle, URL url) {
54 public void removeListener(UpdateListener listener) {
56 synchronized(listeners) {
57 listeners.remove(listener);
62 public ImportDeclaration[] getBuiltinImports(UpdateListener listener) {
63 if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))
64 return DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY;
66 return DEFAULT_IMPORTS;
69 private byte[] computeDigest() {
71 InputStream stream = url.openStream();
73 MessageDigest digest = MessageDigest.getInstance("SHA1");
74 byte[] buffer = new byte[1024];
76 int count = stream.read(buffer);
79 digest.update(buffer, 0, count);
81 return digest.digest();
82 } catch (NoSuchAlgorithmException e) {
83 LOGGER.error("No SHA1 algorithm available", e);
88 } catch(IOException e) {
89 LOGGER.error("Could not compute digest for {}", this);
95 protected InputStream getSourceStream(UpdateListener listener)
98 digest = computeDigest();
99 if(listener != null) {
100 if(listeners == null)
101 listeners = new THashSet<UpdateListener>(4);
102 listeners.add(listener);
103 listener.addObservable(this);
105 return url.openStream();
109 public ClassLoader getClassLoader() {
110 if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))
111 return Type.class.getClassLoader();
113 BundleWiring wiring = bundle.adapt(BundleWiring.class);
115 return wiring.getClassLoader();
117 return getClass().getClassLoader();
121 public void checkUpdates() {
122 if(digest != null && listeners != null) {
123 byte[] newDigest = computeDigest();
124 if(!Arrays.equals(digest, newDigest)) {
126 THashSet<UpdateListener> oldListeners = listeners;
128 for(UpdateListener listener : oldListeners)
129 listener.notifyAboutUpdate();
135 * This code is a copy from org.simantics.utils.ui.BundleUtils
137 public static File resolveWritableBundleFile(URL url) throws IOException {
138 // This returns file, jar, http etc. - essentially resolves the bundle protocol
139 URL resolved = FileLocator.resolve(url);
140 if (resolved.getProtocol().equals("file")) {
141 return new File(resolved.getPath());
146 private Path getPath() throws IOException {
147 File file = resolveWritableBundleFile(url);
148 return file != null ? file.toPath() : null;
152 public boolean isUpdateable() {
154 Path path = getPath();
157 return Files.exists(path);
158 } catch (IOException e) {
159 LOGGER.debug("Could not check if {} is updateable", this, e);
165 public void update(String newSourceText) {
167 Path path = getPath();
170 Files.write(path, newSourceText.getBytes(Charset.forName("UTF-8")));
171 } catch(IOException e) {
172 LOGGER.error("Could not update {} with {}", this, newSourceText, e);
177 public void clear() {
178 if (listeners != null) {
184 public JavaReferenceValidatorFactory getJavaReferenceValidatorFactory() {
185 return new OsgiJavaReferenceValidatorFactory(bundle);