]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Merge "(refs #7541) Added support for module deprecation"
authorHannu Niemistö <hannu.niemisto@semantum.fi>
Wed, 11 Oct 2017 06:14:54 +0000 (09:14 +0300)
committerGerrit Code Review <gerrit2@www.simantics.org>
Wed, 11 Oct 2017 06:14:54 +0000 (09:14 +0300)
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/constants/generic/CallJava.java
bundles/org.simantics.scl.db/scl/Simantics/DB.scl
bundles/org.simantics.scl.db/src/org/simantics/scl/db/SCLFunctions.java
bundles/org.simantics.utils/src/org/simantics/utils/FileUtils.java
bundles/org.simantics/src/org/simantics/SimanticsPlatform.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/ModuleRegressionTests.java
tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DeconstructEnum.scl [new file with mode: 0644]

index 1dd4477151e0a255dd21c0f7884dbb47d6a5c686..0e3ad1f52c5daa3aad92cdb733374fb2b9c8373a 100644 (file)
@@ -1,9 +1,13 @@
 package org.simantics.scl.compiler.constants.generic;
 
 import org.cojen.classfile.TypeDesc;
+import org.objectweb.asm.Label;
 import org.simantics.scl.compiler.constants.FunctionValue;
+import org.simantics.scl.compiler.internal.codegen.continuations.Cont;
+import org.simantics.scl.compiler.internal.codegen.references.IVal;
 import org.simantics.scl.compiler.internal.codegen.references.Val;
 import org.simantics.scl.compiler.internal.codegen.types.JavaReferenceValidator;
+import org.simantics.scl.compiler.internal.codegen.utils.Constants;
 import org.simantics.scl.compiler.internal.codegen.utils.MethodBuilder;
 import org.simantics.scl.compiler.types.TVar;
 import org.simantics.scl.compiler.types.Type;
@@ -92,4 +96,16 @@ public class CallJava extends FunctionValue {
         for(StackItem item : stackItems)
             item.prepare(mb);
     }
+    
+    @Override
+    public void deconstruct(MethodBuilder mb, IVal parameter, Cont success,
+            Label failure) {
+        if(parameterTypes.length != 0)
+            super.deconstruct(mb, parameter, success, failure);
+        push(mb);
+        mb.push(parameter, getType());
+        mb.invokeVirtual(TypeDesc.OBJECT, "equals", TypeDesc.BOOLEAN, Constants.OBJECTS[1]);
+        mb.ifZeroComparisonBranch(failure, "==");
+        mb.jump(success);
+    }
 }
index cd0242be78426791570a52f794b1065486e5ffef..ec9cc2671e3294f5f5335bf1c252f6653d0ffebc 100644 (file)
@@ -344,6 +344,8 @@ importJava "org.simantics.scl.db.SCLFunctions" where
     subquery :: (<ReadGraph,Proc> a) -> <ReadGraph,Proc> a
     "Makes a new read request with given procedure for calculating the result. The request is always cached."
     subqueryC :: (<ReadGraph,Proc> a) -> <ReadGraph,Proc> a
+    "Makes a new read asynchronous request with function to handle the request result. The last `isDisposed` function parameter is used to determine if the listener is still alive or not."
+    subqueryL :: (<ReadGraph,Proc> a) -> (a -> <ReadGraph, e> ()) -> (Throwable -> <ReadGraph, e> ()) -> (<e> Boolean) -> <ReadGraph, Proc, e> ()
     "Tries to convert the given Dynamic value to a value with the inferred type"
     possibleFromDynamic :: Typeable a => String -> Dynamic -> Maybe a
 
index 00df313ad4e34eaed68253b4ccc93640f52d1c79..da88b72c063ab2bb2862156f1f39afe5058839c9 100644 (file)
@@ -8,6 +8,7 @@ import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
 import org.simantics.db.VirtualGraph;
 import org.simantics.db.WriteGraph;
+import org.simantics.db.common.procedure.adapter.SyncListenerAdapter;
 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
 import org.simantics.db.common.request.BinaryRead;
 import org.simantics.db.common.request.DelayedWriteRequest;
@@ -33,6 +34,7 @@ import org.simantics.scl.osgi.SCLOsgi;
 import org.simantics.scl.runtime.SCLContext;
 import org.simantics.scl.runtime.function.Function;
 import org.simantics.scl.runtime.function.Function1;
+import org.simantics.scl.runtime.tuple.Tuple;
 import org.simantics.scl.runtime.tuple.Tuple0;
 import org.simantics.utils.DataContainer;
 
@@ -319,6 +321,26 @@ public class SCLFunctions {
     public static Object subqueryC(ReadGraph graph, Function q) throws DatabaseException {
         return graph.syncRequest(new Subquery(q), TransientCacheAsyncListener.<Object>instance());
     }
+    
+    public static void subqueryL(ReadGraph graph, Function query, Function executeCallback, Function1<Throwable, Tuple> exceptionCallback, Function1<Tuple0, Boolean> isDisposedCallback) throws DatabaseException {
+        graph.asyncRequest(new Subquery(query), new SyncListenerAdapter<Object>() {
+            
+            @Override
+            public void execute(ReadGraph graph, Object result) {
+                executeCallback.apply(result);
+            }
+            
+            @Override
+            public void exception(ReadGraph graph, Throwable t) {
+                exceptionCallback.apply(t);
+            }
+            
+            @Override
+            public boolean isDisposed() {
+                return isDisposedCallback.apply(Tuple0.INSTANCE);
+            }
+        });
+    }
 
     public static Object possibleFromDynamic(Type expectedType, String moduleName, Object value) {
        
index 4e68f29c4ac95246da7d81d2b9e14c7b323dafbc..798fd02b8742c302958c495759fc2ef7950c5b0c 100644 (file)
@@ -840,8 +840,8 @@ public class FileUtils {
      * @throws IOException
      */
     public static void extractZip(File zipFile, File dst) throws IOException {
-        if (LOGGER.isDebugEnabled())
-               LOGGER.debug("Extracting zip "+zipFile);
+        if (LOGGER.isTraceEnabled())
+            LOGGER.trace("Extracting zip "+zipFile);
         try (FileInputStream fis = new FileInputStream(zipFile)) {
             extractZip(fis, dst);
         }
@@ -863,8 +863,8 @@ public class FileUtils {
         while (entry != null) {
             // for each entry to be extracted
             String name = entry.getName();
-            if (LOGGER.isDebugEnabled())
-                LOGGER.debug("Extracting "+name);
+            if (LOGGER.isTraceEnabled())
+                LOGGER.trace("Extracting "+name);
             File file = new File(dst, name);
 
             if (entry.isDirectory())
index faee6944da3a356496cdbbc0f40ff710175e917f..961dfc71899d8a872d8941dda396f95a8ab2f0ca 100644 (file)
@@ -21,6 +21,10 @@ import java.io.File;
 import java.io.IOException;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.Instant;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
@@ -31,6 +35,8 @@ import java.util.Properties;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.UUID;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
 
 import org.eclipse.core.runtime.ILog;
 import org.eclipse.core.runtime.IProduct;
@@ -43,6 +49,8 @@ import org.eclipse.core.runtime.SubMonitor;
 import org.eclipse.osgi.service.resolver.BundleDescription;
 import org.ini4j.Ini;
 import org.ini4j.InvalidFileFormatException;
+import org.simantics.SimanticsPlatform.OntologyRecoveryPolicy;
+import org.simantics.SimanticsPlatform.RecoveryPolicy;
 import org.simantics.databoard.Bindings;
 import org.simantics.databoard.Databoard;
 import org.simantics.datatypes.literal.Font;
@@ -705,6 +713,75 @@ public class SimanticsPlatform implements LifecycleListener {
         resetDatabase(monitor);
     }
 
+    public boolean handleBaselineDatabase() throws PlatformException {
+        Path workspaceLocation = Platform.getLocation().toFile().toPath();
+        Path baselineIndicatorFile = workspaceLocation.resolve(".baselined");
+        if (Files.isRegularFile(baselineIndicatorFile)) {
+            // This means that the workspace has already been initialized from
+            // a database baseline and further initialization is not necessary.
+            return true;
+        }
+
+        String dbBaselineArchive = System.getProperty("org.simantics.db.baseline", null);
+        if (dbBaselineArchive == null)
+            return false;
+
+        Path baseline = Paths.get(dbBaselineArchive);
+        if (!Files.isRegularFile(baseline))
+            throw new PlatformException("Specified database baseline archive " + baseline + " does not exist. Cannot initialize workspace database.");
+
+        validateBaselineFile(baseline);
+        validateWorkspaceForBaselineInitialization(workspaceLocation);
+
+        try {
+            Files.createDirectories(workspaceLocation);
+            FileUtils.extractZip(baseline.toFile(), workspaceLocation.toFile());
+            Files.write(baselineIndicatorFile, baselineIndicatorContents(baselineIndicatorFile));
+            return true;
+        } catch (IOException e) {
+            throw new PlatformException(e);
+        }
+    }
+
+    private static final DateTimeFormatter TIMESTAMP_FORMAT = DateTimeFormatter.ofPattern("d. MMM yyyy HH:mm:ss");
+
+    private static byte[] baselineIndicatorContents(Path path) throws IOException {
+        return String.format("%s%n%s%n",
+                path.toString(),
+                Instant.now().atZone(ZoneId.systemDefault()).format(TIMESTAMP_FORMAT))
+                .getBytes("UTF-8");
+    }
+
+    private void validateWorkspaceForBaselineInitialization(Path workspaceLocation) throws PlatformException {
+        try {
+            Path db = workspaceLocation.resolve("db");
+            if (Files.exists(db))
+                throw new PlatformException("Database location " + db + " already exists. Cannot re-initialize workspace from baseline.");
+            Path index = workspaceLocation.resolve(".metadata/.plugins/org.simantics.db.indexing");
+            if (!Files.exists(index) || !isEmptyDirectory(index))
+                throw new PlatformException("Index location " + index + " already exists. Cannot re-initialize workspace from baseline.");
+        } catch (IOException e) {
+            throw new PlatformException("Failed to validate workspace for baseline initialization", e);
+        }
+    }
+
+    private static boolean isEmptyDirectory(Path dir) throws IOException {
+        return Files.walk(dir).count() == 1;
+    }
+
+    private void validateBaselineFile(Path baseline) throws PlatformException {
+        try (ZipFile zip = new ZipFile(baseline.toFile())) {
+            ZipEntry db = zip.getEntry("db");
+            if (db == null)
+               throw new PlatformException("Baseline archive does not contain database directory 'db'");
+            ZipEntry index = zip.getEntry(".metadata/.plugins/org.simantics.db.indexing");
+            if (index == null)
+                throw new PlatformException("Baseline archive does not contain database index directory '.metadata/.plugins/org.simantics.db.indexing'");
+        } catch (IOException e) {
+            throw new PlatformException("Failed to validate baseline archive " + baseline, e);
+        }
+    }
+
     /**
      * Start-up the platform. The procedure consists of 8 steps. Once everything
      * is up and running, all fields are set property.
@@ -757,6 +834,9 @@ public class SimanticsPlatform implements LifecycleListener {
         // 0.2 Clear VariableRepository.repository static map which holds references to SessionImplDb
         VariableRepository.clear();
         
+        // 0.3 Handle baseline database before opening db
+        boolean usingBaseline = handleBaselineDatabase();
+        
         // 1. Assert there is a database at <workspace>/db
         session = setupDatabase(databaseDriverId, progressMonitor, workspacePolicy, userAgent);
         TimeLogger.log("Database setup complete");
@@ -772,8 +852,10 @@ public class SimanticsPlatform implements LifecycleListener {
         }
         
         // 2. Assert all graphs, and correct versions, are installed to the database
-        synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize);
-        TimeLogger.log("Synchronized ontologies");
+        if(!usingBaseline) {
+            synchronizeOntologies(progressMonitor, ontologyPolicy, requireSynchronize);
+            TimeLogger.log("Synchronized ontologies");
+        }
 
         // 4. Assert simantics.cfg exists
         boolean installProject = assertConfiguration(progressMonitor,workspacePolicy);
@@ -862,8 +944,11 @@ public class SimanticsPlatform implements LifecycleListener {
         try {
             // Construct and initialize SessionContext from Session.
             SessionContext sessionContext = SessionContext.create(session, init);
-            if (init)
+            TimeLogger.log("Session context created");
+            if (init) {
                 sessionContext.registerServices();
+                TimeLogger.log("Session services registered");
+            }
             return sessionContext;
         } catch (DatabaseException e) {
             throw new PlatformException(e);
index f67b7c8b59fee99cb705a504ad3dcdd57cc44c93..2321a93f6e57bc87d8d79d0ad4e696f1b72f7670 100644 (file)
@@ -46,6 +46,7 @@ public class ModuleRegressionTests extends TestBase {
     @Test public void ConjunctionMacro() { test(); }
     @Test public void Constant() { test(); }
     @Test public void ConstructorNameClash() { test(); }
+    @Test public void DeconstructEnum() { test(); }
     @Test public void DefaultMethods1() { test(); }
     @Test public void Deriving3() { test(); }
     @Test public void Deriving4() { test(); }
diff --git a/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DeconstructEnum.scl b/tests/org.simantics.scl.compiler.tests/src/org/simantics/scl/compiler/tests/scl/DeconstructEnum.scl
new file mode 100644 (file)
index 0000000..86cd33a
--- /dev/null
@@ -0,0 +1,14 @@
+import "Prelude"
+
+importJava "java.nio.file.StandardOpenOption" where
+    data OpenOption
+
+    READ :: OpenOption
+    WRITE :: OpenOption
+    
+idOf READ = 3
+idOf WRITE = 19
+
+main = idOf READ + idOf WRITE + idOf READ
+--
+25
\ No newline at end of file