--- /dev/null
+package org.simantics.scl.osgi.internal;\r
+\r
+import java.io.File;\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
+ System.out.println(url + " 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
+ System.out.println(url + " update");\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