]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/internal/BundleModuleSource.java
Merge branch 'feature/funcwrite'
[simantics/platform.git] / bundles / org.simantics.scl.osgi / src / org / simantics / scl / osgi / internal / BundleModuleSource.java
1 package org.simantics.scl.osgi.internal;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.net.URISyntaxException;
6 import java.net.URL;
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;
14
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
24 import gnu.trove.set.hash.THashSet;
25
26 public class BundleModuleSource extends EncodedTextualModuleSource implements UpdateListener.Observable {
27
28     public static final ImportDeclaration[] DEFAULT_IMPORTS = new ImportDeclaration[] {
29         new ImportDeclaration("Builtin", ""),
30         new ImportDeclaration("StandardLibrary", "")
31     };
32     
33     public static final ImportDeclaration[] DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY = new ImportDeclaration[] {
34         new ImportDeclaration("Builtin", ""),
35     };
36     
37     public final Bundle bundle;
38     public final URL url;
39     
40     private byte[] digest;
41     private THashSet<UpdateListener> listeners;
42     
43     public BundleModuleSource(String moduleName, Bundle bundle, URL url) {
44         super(moduleName);
45         this.bundle = bundle;
46         this.url = url;
47     }
48     
49     @Override
50     public void removeListener(UpdateListener listener) {
51         if(listeners != null)
52             synchronized(listeners) {
53                 listeners.remove(listener);
54             }
55     }
56
57     @Override
58     protected ImportDeclaration[] getBuiltinImports(UpdateListener listener) {
59         if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))
60             return DEFAULT_IMPORTS_FOR_STANDARD_LIBRARY;
61         else
62             return DEFAULT_IMPORTS;
63     }
64     
65     private byte[] computeDigest() {
66         try {
67             InputStream stream = url.openStream();
68             try {
69                 MessageDigest digest = MessageDigest.getInstance("SHA1");
70                 byte[] buffer = new byte[1024];
71                 while(true) {
72                     int count = stream.read(buffer);
73                     if(count <= 0)
74                         break;
75                     digest.update(buffer, 0, count);
76                 }
77                 return digest.digest();
78             } catch (NoSuchAlgorithmException e) {
79                 e.printStackTrace();
80                 return new byte[0];
81             } finally {
82                 stream.close();
83             }
84         } catch(IOException e) {
85             e.printStackTrace();
86             return new byte[0];
87         }
88     }
89     
90     @Override
91     protected InputStream getSourceStream(UpdateListener listener)
92             throws IOException {
93         if(digest == null)
94             digest = computeDigest();
95         if(listener != null) {
96             if(listeners == null)
97                 listeners = new THashSet<UpdateListener>(4);
98             listeners.add(listener);
99             listener.addObservable(this);
100         }
101         return url.openStream();
102     }
103     
104     @Override
105     public ClassLoader getClassLoader() {
106         if(bundle.getSymbolicName().equals("org.simantics.scl.runtime"))
107             return Type.class.getClassLoader();
108         else {
109             BundleWiring wiring = bundle.adapt(BundleWiring.class);
110             if(wiring != null)
111                 return wiring.getClassLoader();
112             else
113                 return getClass().getClassLoader();
114         }
115     }
116
117     public void checkUpdates() {
118         if(digest != null && listeners != null) {
119             byte[] newDigest = computeDigest();
120             if(!Arrays.equals(digest, newDigest)) {
121                 digest = newDigest;
122                 THashSet<UpdateListener> oldListeners = listeners;
123                 listeners = null;
124                 for(UpdateListener listener : oldListeners)
125                     listener.notifyAboutUpdate();
126             }
127         }
128     }
129     
130     private Path getPath() throws IOException {
131         try {
132             return Paths.get(FileLocator.toFileURL(url).toURI());
133         } catch (URISyntaxException e) {
134             throw new IOException(e);
135         }
136     }
137     
138     @Override
139     public boolean isUpdateable() {
140         try {
141             return Files.exists(getPath());
142         } catch (IOException e) {
143             return false;
144         }
145     }
146     
147     @Override
148     public void update(String newSourceText) {
149         try {
150             Path path = getPath();
151             Files.write(path, newSourceText.getBytes(Charset.forName("UTF-8")));
152         } catch(IOException e) {
153             e.printStackTrace();
154         }
155         checkUpdates();
156     }
157
158     public void clear() {
159         if (listeners != null) {
160             listeners.clear();
161             listeners = null;
162         }
163     }
164
165     public JavaReferenceValidatorFactory getJavaReferenceValidatorFactory() {
166         return new OsgiJavaReferenceValidatorFactory(bundle);
167     }
168 }