]> gerrit.simantics Code Review - simantics/platform.git/commitdiff
Merge remote-tracking branch 'origin/master' into private/antti2 private/antti2
authorAntti Villberg <antti.villberg@semantum.fi>
Sat, 11 Jan 2020 10:54:22 +0000 (12:54 +0200)
committerAntti Villberg <antti.villberg@semantum.fi>
Sat, 11 Jan 2020 10:54:22 +0000 (12:54 +0200)
Conflicts:
bundles/org.simantics.acorn/src/org/simantics/acorn/OperationQueue.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardVariableBuilder.java

Change-Id: I5a4cbd88743669fa4b1104ec466c0efa3aa0aa3d

41 files changed:
bundles/org.simantics.acorn/src/org/simantics/acorn/OperationQueue.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/BlockingAsyncProcedure.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/AsyncBarrierImpl.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/BarrierTracing.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/graph/ReadGraphImpl.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/AsyncReadEntry.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/IPending.java [new file with mode: 0644]
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/PendingTaskSupport.java [new file with mode: 0644]
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCache.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryCacheBase.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryListening.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryProcessor.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/QueryThread.java
bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/ReadEntry.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/request/PropertyInfo.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/scl/AbstractExpressionCompilationRequest.java
bundles/org.simantics.db.layer0/src/org/simantics/db/layer0/variable/StandardGraphPropertyVariable.java
bundles/org.simantics.db.procore/src/fi/vtt/simantics/procore/internal/SessionImplSocket.java
bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/ConnectionRequest2.java [new file with mode: 0644]
bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/GraphToDiagramSynchronizer.java
bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/NodeRequest2.java [new file with mode: 0644]
bundles/org.simantics.diagram/src/org/simantics/diagram/symbollibrary/ui/SymbolLibraryComposite.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/DocumentRequest.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodeRequest.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/NodesRequest2.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLHandlerValueRequest.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLValueRequest.java
bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLValueRequestBase.java [new file with mode: 0644]
bundles/org.simantics.issues.common/src/org/simantics/issues/common/ChildMaxIssueSeverity.java
bundles/org.simantics.issues.common/src/org/simantics/issues/common/MaxIssueSeverityRecursive.java
bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/diagram/monitor/MonitorClassFactory2.java
bundles/org.simantics.project/src/org/simantics/project/management/PlatformUtil.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/ConcreteModule.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/module/repository/ModuleRepository.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/ExpressionClassLoader.java
bundles/org.simantics.scl.compiler/src/org/simantics/scl/compiler/runtime/RuntimeModule.java
bundles/org.simantics.scl.osgi/src/org/simantics/scl/osgi/SCLOsgi.java
bundles/org.simantics.structural2/src/org/simantics/structural2/scl/procedural/CompileProceduralComponentTypeRequest.java
bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogVisualizer.java
bundles/org.simantics.utils.thread/src/org/simantics/utils/threads/logger/ThreadLogger.java

index a85aa882930446b6214e4bd5116b8e3358233930..d48f9ba6da792f6c292f1ac4ac14cf01aaadbd95 100644 (file)
@@ -173,5 +173,4 @@ class OperationQueue {
                return System.nanoTime() - start;
 
        }
-
 }
index 2d3e2804c6ebf4d630984892195c6fe2e2e4b0fa..c491fb377464e366f5b34e8e8eac2e0e205840c5 100644 (file)
 package org.simantics.db.impl;
 
 import org.simantics.db.AsyncReadGraph;
-import org.simantics.db.common.utils.Logger;
 import org.simantics.db.exception.DatabaseException;
-import org.simantics.db.impl.graph.AsyncBarrierImpl;
+import org.simantics.db.impl.graph.BarrierTracing;
 import org.simantics.db.impl.graph.ReadGraphImpl;
+import org.simantics.db.impl.query.AsyncReadEntry;
+import org.simantics.db.impl.query.PendingTaskSupport;
 import org.simantics.db.procedure.AsyncProcedure;
 
 public class BlockingAsyncProcedure<Result> implements AsyncProcedure<Result> {
 
     private static final Object NO_RESULT = new Object();
 
-    private final Object key;
-    private final AsyncBarrierImpl barrier;
-    private final ReadGraphImpl procedureGraph;
-    private final AsyncProcedure<Result> procedure;
+    public final Object key;
+    public final ReadGraphImpl queryGraph;
+    public final ReadGraphImpl callerGraph;
+    public final AsyncProcedure<Result> procedure;
+    public PendingTaskSupport pendingTaskSupport;
+    public Object result = NO_RESULT;
+    public Throwable exception = null;
 
-    private Object result = NO_RESULT;
-    private Throwable exception = null;
+    private ReadGraphImpl queryGraph() {
+        return queryGraph;
+    }
+    
+    public BlockingAsyncProcedure(ReadGraphImpl callerGraph, AsyncReadEntry<Result> entry, AsyncProcedure<Result> procedure, Object key, boolean needsToBlock) {
+
+        // A new graph for evaluating the query with correct parent and asyncBarrier
+        queryGraph = callerGraph.withParent(entry, () -> {
+
+            dispatchProcedure(queryGraph(), callerGraph, entry, procedure, needsToBlock);
+            
+        });
+        
+        queryGraph.asyncBarrier.inc();
 
-    public BlockingAsyncProcedure(AsyncBarrierImpl barrier, ReadGraphImpl procedureGraph, AsyncProcedure<Result> procedure, Object key) {
         this.procedure = procedure;
         this.key = key;
-        this.barrier = barrier;
-        this.barrier.inc();
-        this.procedureGraph = procedureGraph;
+        this.queryGraph.asyncBarrier.inc();
+        this.callerGraph = callerGraph;
+        if (BarrierTracing.BOOKKEEPING) {
+            BarrierTracing.registerBAP(this);
+        }
     }
 
     @Override
     public void execute(AsyncReadGraph graph_, Result result) {
+        
         this.result = result;
-        try {
-            if(procedure != null) procedure.execute(procedureGraph, result);
-        } catch (Throwable throwable) {
-            Logger.defaultLogError("AsyncProcedure.execute threw for " + procedure, throwable);
-        } finally {
-            barrier.dec();
-        }
+        queryGraph.asyncBarrier.dec();
+        
     }
 
     @Override
     public void exception(AsyncReadGraph graph_, Throwable t) {
+
         this.exception = t;
-        try {
-            if(procedure != null) procedure.exception(procedureGraph, t);
-        } catch (Throwable throwable) {
-            Logger.defaultLogError("AsyncProcedure.exception threw for " + procedure, throwable);
-        } finally {
-            barrier.dec();
-        }
+        queryGraph.asyncBarrier.dec();
+        
     }
-
+    
     public void waitBarrier() {
-        barrier.waitBarrier(key, procedureGraph);
+        queryGraph.asyncBarrier.waitBarrier(key, queryGraph);
+    }
+    
+    public void dec() {
+
+        queryGraph.asyncBarrier.dec();
+        
     }
 
     @SuppressWarnings("unchecked")
     public Result get() throws DatabaseException {
 
-        barrier.waitBarrier(key, procedureGraph);
+        queryGraph.asyncBarrier.waitBarrier(key, queryGraph);
 
         if(exception != null) {
             if(exception instanceof DatabaseException) throw (DatabaseException)exception;
@@ -80,10 +95,6 @@ public class BlockingAsyncProcedure<Result> implements AsyncProcedure<Result> {
 
     }
 
-    public boolean isDone() {
-        return barrier.get() == 0;
-    }
-
     @SuppressWarnings("unchecked")
     public Result getResult() {
         return (Result)result;
@@ -97,5 +108,41 @@ public class BlockingAsyncProcedure<Result> implements AsyncProcedure<Result> {
     public String toString() {
         return "." + procedure; 
     }
+    
+    private void dispatchProcedure(ReadGraphImpl queryGraph, ReadGraphImpl parentGraph, AsyncReadEntry<Result> entry, AsyncProcedure<Result> procedure_, boolean needsToBlock) {
+        
+        AsyncProcedure<Result> procedure = entry != null ? entry : procedure_;
+
+        ReadGraphImpl executeGraph = parentGraph.withParent(parentGraph.parent);
+        executeGraph.asyncBarrier.inc();
+        try {
+            if(procedure != null) {
+                procedure.execute(executeGraph, get());
+            }
+        } catch (DatabaseException e) {
+            if(procedure != null) procedure.exception(executeGraph, e);
+            exception = e;
+        } catch (Throwable t) {
+            DatabaseException dbe = new DatabaseException(t);
+            if(procedure != null) procedure.exception(executeGraph, dbe);
+            exception = dbe;
+        } finally {
+
+            if (entry != null) {
+                assert(entry.isReady());
+                // This does not throw
+                entry.performFromCache(executeGraph, procedure_);
+            }
+
+            executeGraph.asyncBarrier.dec();
+            if(needsToBlock)
+                executeGraph.asyncBarrier.waitBarrier(procedure, executeGraph);
+        }
+
+        if (BarrierTracing.BOOKKEEPING) {
+            BarrierTracing.unregisterBAP(this);
+        }
+
+    }
 
 }
index b94ec6f6857cb0e0ca913ef920a5231c9ecc3577..060fc22aefb866d15a17bb0f70e7cd4692846d90 100644 (file)
@@ -18,20 +18,24 @@ import org.simantics.db.common.utils.Logger;
 import org.simantics.db.exception.RuntimeDatabaseException;
 import org.simantics.db.impl.query.CacheEntry;
 import org.simantics.db.impl.query.QueryProcessor.AsyncBarrier;
+import org.simantics.db.impl.query.QueryProcessor.SessionTask;
 
 final public class AsyncBarrierImpl extends AtomicInteger implements AsyncBarrier {
 
        private static final long serialVersionUID = 4724463372850048672L;
 
-       static final int WAIT_TIME = 600;
+       static final int WAIT_TIME = 60000;
 
        public static final boolean PRINT = false;
 
        final public AsyncBarrierImpl caller;
+       
+       final public Runnable callback;
 
-       public AsyncBarrierImpl(AsyncBarrierImpl caller, CacheEntry<?> entry) {
+       public AsyncBarrierImpl(AsyncBarrierImpl caller, CacheEntry<?> entry, Runnable callback) {
                super(0);
                this.caller = caller;
+               this.callback = callback;
         if (BarrierTracing.BOOKKEEPING) {
             BarrierTracing.trace(this, entry);
         }
@@ -92,6 +96,10 @@ final public class AsyncBarrierImpl extends AtomicInteger implements AsyncBarrie
                                                new Exception());
                        }
                        assert (count >= 0);
+                       
+                       if(callback != null)
+                           callback.run();
+                       
                }
 
        }
@@ -142,7 +150,7 @@ final public class AsyncBarrierImpl extends AtomicInteger implements AsyncBarrie
                                                e.printStackTrace();
                                        }
                                }
-                               if(waitCount > WAIT_TIME*1000) {
+                               if(waitCount > WAIT_TIME) {
 
                                        System.err.println("AsyncBarrierImpl.waitBarrier("
                                                        + request
@@ -153,6 +161,11 @@ final public class AsyncBarrierImpl extends AtomicInteger implements AsyncBarrie
                                                synchronized (BarrierTracing.reverseLookup) {
                                                        printReverse(this, 0);
                                                }
+                                               BarrierTracing.printBAPS();
+                                       }
+                                       
+                                       for(SessionTask t : impl.processor.freeScheduling) {
+                                           System.err.println("Pending task:" + t);
                                        }
 
 //                                     if(Development.DEVELOPMENT) {
index 3ff77f6bc108c18b59535a3c02f3f1b51f78fac0..3168b27c43e3448a18f368d55fff5c59c0f146e4 100644 (file)
@@ -5,13 +5,14 @@ import java.util.Collection;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.simantics.db.impl.BlockingAsyncProcedure;
 import org.simantics.db.impl.query.CacheEntry;
 import org.simantics.db.impl.query.QueryProcessor.SessionTask;
 
 public class BarrierTracing {
 
     public static final boolean BOOKKEEPING = false;
-    static final boolean RESTART_GUARD = BOOKKEEPING && false;
+    static final boolean RESTART_GUARD = BOOKKEEPING && true;
 
     public static Map<SessionTask,Exception> tasks = new HashMap<>();
     public static final HashMap<AsyncBarrierImpl, Collection<AsyncBarrierImpl>> reverseLookup = new HashMap<>();
@@ -19,7 +20,31 @@ public class BarrierTracing {
     public static final HashMap<AsyncBarrierImpl, CacheEntry<?>> entryMap = new HashMap<>();
     public static final HashMap<AsyncBarrierImpl, Throwable> restartMap = new HashMap<>();
     public static final HashMap<AsyncBarrierImpl, Throwable> startMap = new HashMap<>();
+    public static final HashMap<BlockingAsyncProcedure, Throwable> baps = new HashMap<>();
 
+    synchronized public static void registerBAP(BlockingAsyncProcedure bap) {
+        baps.put(bap, new Exception());
+    }
+    
+    synchronized public static void unregisterBAP(BlockingAsyncProcedure bap) {
+        baps.remove(bap);
+    }
+
+    synchronized public static void printBAPS() {
+        for(BlockingAsyncProcedure bap : baps.keySet()) {
+            Throwable e = baps.get(bap);
+            System.err.println("BlockingAsyncProcedure");
+            System.err.println("-key: " + bap.key);
+            System.err.println("-queryGraph: " + bap.queryGraph);
+            System.err.println("-callerGraph: " + bap.callerGraph);
+            System.err.println("-procedure: " + bap.procedure);
+            System.err.println("-pendingTaskSupport: " + bap.pendingTaskSupport);
+            System.err.println("-result: " + bap.result);
+            System.err.println("-exception: " + bap.exception);
+            e.printStackTrace();
+        }
+    }
+    
     public static void trace(AsyncBarrierImpl barrier, CacheEntry<?> entry) {
 
         if (RESTART_GUARD) {
index a693b29228e026c1e1f6a5c7f3652c8d4320eb4c..dcb48a0f04faf76b3eb195b6fe02a2d058bce5d3 100644 (file)
@@ -1926,9 +1926,9 @@ public class ReadGraphImpl implements AsyncReadGraph {
        public <T> T syncRequest(final Read<T> request) throws DatabaseException {
                assert (request != null);
 
-               ITask task = ThreadLogger.task(request);
+               //ITask task = ThreadLogger.task(request);
                T result = (T)QueryCache.runnerReadEntry(this, request, parent, null, null, true);
-               task.finish();
+               //task.finish();
                return result;
                
        }
@@ -1950,10 +1950,8 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                assert (request != null);
 
-               ITask task = ThreadLogger.task(request);
                ListenerBase listener = procedure != null ? getListenerBase(procedure) : null;
-               T result = QueryCache.resultReadEntry(this, request, parent, listener, procedure);
-               task.finish();
+               T result = (T)QueryCache.runnerReadEntry(this, request, parent, listener, procedure, true);
                return result;
 
        }
@@ -2038,10 +2036,10 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                assert (request != null);
 
-               ITask task = ThreadLogger.task(request);
+               //ITask task = ThreadLogger.task(request);
                ListenerBase listener = getListenerBase(procedure);
                T result = (T)QueryCache.runnerAsyncReadEntry(this, request, parent, listener, procedure, true); 
-               task.finish();
+               //task.finish();
                return result;
 
        }
@@ -5160,7 +5158,11 @@ public class ReadGraphImpl implements AsyncReadGraph {
 
                assert (request != null);
                assert (procedure != null);
-       
+               
+               AsyncBarrierImpl barrier = asyncBarrier;
+               if(barrier != null)
+                   barrier.inc();
+               
                processor.scheduleNow(new SessionTask(this) {
 
                        @Override
@@ -5170,6 +5172,9 @@ public class ReadGraphImpl implements AsyncReadGraph {
                                        QueryCache.runnerReadEntry(ReadGraphImpl.this, request, parent, listener, procedure, false);
                                } catch (DatabaseException e) {
                                        Logger.defaultLogError(e);
+                               } finally {
+                               if(barrier != null)
+                                   barrier.dec();
                                }
                        }
                        
@@ -5241,29 +5246,43 @@ public class ReadGraphImpl implements AsyncReadGraph {
                assert (request != null);
                assert (procedure != null);
 
-               ITask task = ThreadLogger.task(request);
+               //ITask task = ThreadLogger.task(request);
+               
+        AsyncBarrierImpl barrier = asyncBarrier;
+        if(barrier != null)
+            barrier.inc();
 
                processor.scheduleNow(new SessionTask(this) {
 
                        @Override
                        public void run0(int thread) {
-                               try {
+
+                           if(barrier != null)
+                           barrier.inc();
+
+                           try {
                                        final ListenerBase listener = getListenerBase(procedure);
                                        QueryCache.runnerAsyncReadEntry(ReadGraphImpl.this, request, parent, listener, new AsyncProcedure<T>() {
 
                                                @Override
                                                public void execute(AsyncReadGraph graph, T result) {
-                                                       task.finish();
+                                                       //task.finish();
                                                        procedure.execute(graph, result);
+                                               if(barrier != null)
+                                                   barrier.dec();
                                                }
 
                                                @Override
                                                public void exception(AsyncReadGraph graph, Throwable throwable) {
-                                                       task.finish();
+                                                       //task.finish();
                                                        procedure.exception(graph, throwable);
+                            if(barrier != null)
+                                barrier.dec();
                                                }
                                                
                                        }, false);
+                               if(barrier != null)
+                                   barrier.dec();
                                } catch (DatabaseException e) {
                                        Logger.defaultLogError(e);
                                }
@@ -5651,27 +5670,47 @@ public class ReadGraphImpl implements AsyncReadGraph {
                this.parentGraph = parentGraph;
                this.parent = parent;
                this.processor = support;
-               this.asyncBarrier = new AsyncBarrierImpl(parentGraph != null ? parentGraph.asyncBarrier : null, parent);
+               this.asyncBarrier = new AsyncBarrierImpl(parentGraph != null ? parentGraph.asyncBarrier : null, parent, null);
        }
 
+    ReadGraphImpl(ReadGraphImpl parentGraph, CacheEntry parent, QueryProcessor support, AsyncBarrierImpl asyncBarrier) {
+        this.parentGraph = parentGraph;
+        this.parent = parent;
+        this.processor = support;
+        this.asyncBarrier = asyncBarrier;
+    }
+
        ReadGraphImpl(ReadGraphImpl graph, CacheEntry parent) {
                this(graph, parent, graph.processor);
        }
 
+    ReadGraphImpl(ReadGraphImpl parentGraph, CacheEntry parent, Runnable callback) {
+        this(parentGraph, parent, parentGraph.processor, new AsyncBarrierImpl(parentGraph != null ? parentGraph.asyncBarrier : null, parent, callback));
+    }
+
        ReadGraphImpl(ReadGraphImpl graph) {
                this(graph, graph.parent);
        }
 
-       public ReadGraphImpl withParent(CacheEntry parent) {
-               return new ReadGraphImpl(this, parent);
+       public ReadGraphImpl withParent(CacheEntry parent, Runnable callback) {
+               return new ReadGraphImpl(this, parent, callback);
        }
 
+    public ReadGraphImpl withParent(CacheEntry parent) {
+        return withParent(parent, null);
+    }
+
+       public ReadGraphImpl syncWithParent(CacheEntry parent) {
+        return new ReadGraphImpl(this, parent, processor, null);
+    }
+
        public ReadGraphImpl forRecompute(CacheEntry parent) {
                return new ReadGraphImpl(null, parent, processor);
        }
 
        public static ReadGraphImpl create(QueryProcessor support) {
-               return new ReadGraphImpl(null, null, support);
+           ReadGraphImpl result = new ReadGraphImpl(null, null, support);
+           return result;
        }
 
        public ReadGraphImpl newRestart(ReadGraphImpl impl) {
@@ -6357,6 +6396,12 @@ public class ReadGraphImpl implements AsyncReadGraph {
         else return 1 + getLevelStatic(impl.parentGraph);
     }
     
+    public boolean isParent(ReadGraphImpl impl) {
+        if(impl == null) return false;
+        if(this == impl) return true;
+        return isParent(impl.parentGraph);
+    }
+    
     public ReadGraphImpl getTopLevelGraph() {
         return getTopLevelGraphStatic(this);
     }
index e13ecab72cd0819f71c3c337af62ad242db709c2..0dd5730a5f3a1f5c6c232063741bf4343303feb4 100644 (file)
  *******************************************************************************/
 package org.simantics.db.impl.query;
 
+import java.util.Collection;
+
 import org.simantics.databoard.Bindings;
 import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.DevelopmentKeys;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.impl.BlockingAsyncProcedure;
-import org.simantics.db.impl.graph.AsyncBarrierImpl;
-import org.simantics.db.impl.graph.BarrierTracing;
 import org.simantics.db.impl.graph.ReadGraphImpl;
 import org.simantics.db.impl.query.QueryProcessor.SessionTask;
 import org.simantics.db.procedure.AsyncProcedure;
@@ -26,11 +26,12 @@ import org.simantics.utils.Development;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> implements AsyncProcedure<T> {
+final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> implements AsyncProcedure<T>, IPending {
 
     private static final Logger LOGGER = LoggerFactory.getLogger(AsyncReadEntry.class);
 
     protected AsyncRead<T> id;
+    protected PendingTaskSupport pendingTaskSupport;
 
     AsyncReadEntry(AsyncRead<T> request) {
         this.id = request;
@@ -77,7 +78,7 @@ final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> i
 
                 try {
 
-                    BlockingAsyncProcedure<T> proc = new BlockingAsyncProcedure<>(graph.asyncBarrier, graph, new AsyncProcedure<T>() {
+                    BlockingAsyncProcedure<T> proc = new BlockingAsyncProcedure(graph, AsyncReadEntry.this, new AsyncProcedure<T>() {
 
                         @Override
                         public void execute(AsyncReadGraph graph, T result) {
@@ -90,10 +91,11 @@ final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> i
                             except(t);
                         }
 
-                    }, id);
-
-                    id.perform(graph, proc);
+                    }, id, true);
 
+                    id.perform(proc.queryGraph, proc);
+                    
+                    proc.dec();
                     proc.get();
 
                 } catch (Throwable t) {
@@ -152,103 +154,24 @@ final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> i
 
     }
 
-    public static <T> T computeForEach(ReadGraphImpl graph, AsyncRead<T> request, AsyncReadEntry<T> entry,
+    public static <T> T computeForEach(ReadGraphImpl callerGraph, AsyncRead<T> request, AsyncReadEntry<T> entry,
             AsyncProcedure<T> procedure_, boolean needsToBlock) throws DatabaseException {
 
-        AsyncProcedure<T> procedure = entry != null ? entry : procedure_;
-
-        ReadGraphImpl queryGraph = graph.withParent(entry);
-        queryGraph.asyncBarrier.inc();
-        
-        BlockingAsyncProcedure<T> proc = new BlockingAsyncProcedure<>(queryGraph.asyncBarrier, graph, null, request);
-        
-        class AsyncTask extends SessionTask {
-
-            int counter = 0;
-            T result;
-            DatabaseException exception;
-            
-            public AsyncTask(ReadGraphImpl graph) {
-                this(graph, 1);
-            }
-
-            public AsyncTask(ReadGraphImpl graph, int pos) {
-                super(graph);
-                this.position = pos;
-                if(this.position < 1024)
-                    this.position *= 2;
-            }
-
-            @Override
-            public void run0(int thread) {
-                if(needsToBlock) proc.waitBarrier();
-                if(proc.isDone()) {
-                    ReadGraphImpl executeGraph = graph.withParent(graph.parent);
-                    executeGraph.asyncBarrier.inc();
-                    try {
-                        result = (T)proc.get();
-                        if(procedure != null) {
-                            procedure.execute(executeGraph, result);
-                        }
-                    } catch (DatabaseException e) {
-                        if(procedure != null) procedure.exception(executeGraph, e);
-                        exception = e;
-                    } catch (Throwable t) {
-                        DatabaseException dbe = new DatabaseException(t);
-                        if(procedure != null) procedure.exception(executeGraph, dbe);
-                        exception = dbe;
-                    } finally {
-                        if (entry != null) {
-                            // This does not throw
-                            entry.performFromCache(executeGraph, procedure_);
-                        }
-                        executeGraph.asyncBarrier.dec();
-                        executeGraph.asyncBarrier.waitBarrier(procedure, executeGraph);
-                    }
-                } else {
-                    if(counter++ > 10000) {
-                        if(BarrierTracing.BOOKKEEPING) {
-                            AsyncBarrierImpl.printReverse(queryGraph.asyncBarrier, 2);
-                            AsyncBarrierImpl caller = queryGraph.asyncBarrier.caller;
-                            while(caller != null) {
-                                System.err.println("called by " + AsyncBarrierImpl.report(caller));
-                                caller = caller.caller;
-                            }
-                            for(AsyncBarrierImpl ab : BarrierTracing.debuggerMap.keySet()) {
-                                AsyncBarrierImpl.printReverse(ab, 2);
-                            }
-                        }
-                        throw new IllegalStateException("Eternal loop in queries.");
-                    }
-                    graph.processor.scheduleLater(new AsyncTask(graph, position));
-                }
-            }
-            
-            @Override
-            public boolean maybeReady() {
-               return proc.isDone();
-            }
-            
-        }
+        BlockingAsyncProcedure<T> proc = new BlockingAsyncProcedure(callerGraph, entry, procedure_, request, needsToBlock);
 
         try {
-            request.perform(queryGraph, proc);
+            request.perform(proc.queryGraph, proc);
         } finally {
-            queryGraph.asyncBarrier.dec();
+            proc.queryGraph.asyncBarrier.dec();
         }
 
-        AsyncTask task = new AsyncTask(graph);
-
-        if(needsToBlock) task.run(0);
-        else if (proc.isDone()) task.run(0);
-        else  {
-            graph.processor.scheduleLater(task);
+        if(needsToBlock) {
+            proc.waitBarrier();
+            return proc.get();
+        } else {
             return null;
         }
 
-        if(task.exception != null) throw task.exception;
-        else return task.result;
-
     }
 
     @Override
@@ -263,13 +186,41 @@ final public class AsyncReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> i
 
     @Override
     public void execute(AsyncReadGraph graph, T result) {
-        setResult(result);
-        setReady();
+        Collection<SessionTask> tasks = null;
+        synchronized(this) {
+            setResult(result);
+            setReady();
+            if(pendingTaskSupport != null)
+                tasks = pendingTaskSupport.executePending();
+        }
+        if(tasks != null)
+            for(SessionTask task : tasks)
+                ((ReadGraphImpl)graph).processor.scheduleNow(task);
     }
 
     @Override
-    public void exception(AsyncReadGraph graph, Throwable throwable) {
-        except(throwable);
+    public synchronized void exception(AsyncReadGraph graph, Throwable throwable) {
+        Collection<SessionTask> tasks = null;
+        synchronized(this) {
+            except(throwable);
+            if(pendingTaskSupport != null)
+                tasks = pendingTaskSupport.executePending();
+        }
+        if(tasks != null)
+            for(SessionTask task : tasks)
+                ((ReadGraphImpl)graph).processor.scheduleNow(task);
+    }
+
+    public void executeWhenResultIsAvailable(QueryProcessor processor, SessionTask task) {
+        boolean ready = false;
+        synchronized(this) {
+            if(pendingTaskSupport == null)
+                pendingTaskSupport = new PendingTaskSupport(this);
+            ready = pendingTaskSupport.executeWhenResultIsAvailable(task);
+        }
+        if(ready) {
+            processor.scheduleNow(task);
+        }
     }
 
 }
diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/IPending.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/IPending.java
new file mode 100644 (file)
index 0000000..c738135
--- /dev/null
@@ -0,0 +1,7 @@
+package org.simantics.db.impl.query;
+
+public interface IPending {
+    
+    boolean isPending();
+
+}
diff --git a/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/PendingTaskSupport.java b/bundles/org.simantics.db.impl/src/org/simantics/db/impl/query/PendingTaskSupport.java
new file mode 100644 (file)
index 0000000..f63bad5
--- /dev/null
@@ -0,0 +1,45 @@
+package org.simantics.db.impl.query;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.simantics.db.impl.query.QueryProcessor.SessionTask;
+
+/*
+ * Support class for queuing pending tasks to be executed when result gets ready
+ */
+public class PendingTaskSupport {
+
+    private ArrayList<SessionTask> pendingTasks;
+    private IPending pending;
+    
+    public PendingTaskSupport(IPending pending) {
+        this.pending = pending;
+    }
+    
+    /*
+     * We assume here that the associated IPending performs this atomically
+     * The caller is responsible for execution of the returned task after the critical section
+     */
+    public boolean executeWhenResultIsAvailable(SessionTask task) {
+        if(pending.isPending()) {
+            if(pendingTasks == null)
+                pendingTasks = new ArrayList<SessionTask>();
+            pendingTasks.add(task);
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /*
+     * We assume here that the associated IPending performs this atomically after changing the pending result
+     * The caller is responsible for execution of the returned task after the critical section
+     */
+    public Collection<SessionTask> executePending() {
+        ArrayList<SessionTask> ret = pendingTasks;
+        pendingTasks = null;
+        return ret;
+    }
+
+}
index cc0ca919b584942a4d49a1a4c61b97b741e631f2..35ebdbc65ba4ce82e5e7e7dced301310c30f8b17 100644 (file)
@@ -625,7 +625,7 @@ public class QueryCache extends QueryCacheBase {
         }
     }
     
-    ReadEntry getOrCreateReadEntry(ReadGraphImpl graph, Read<?> r, boolean needsToBlock) throws DatabaseException {
+    private final ReadEntry getOrCreateReadEntry(ReadGraphImpl graph, Read<?> r, boolean needsToBlock) throws DatabaseException {
         ReadEntry existing = null;
         synchronized(readEntryMap) {
             existing = (ReadEntry)readEntryMap.get(r);
@@ -670,11 +670,13 @@ public class QueryCache extends QueryCacheBase {
         }
         ReadEntry entry = (ReadEntry)cache.getOrCreateReadEntry(graph, r, needsToBlock);
         if(entry == null) {
-          graph.processor.scheduleNow(new SessionTask(graph) {
+          graph.asyncBarrier.inc();  
+          graph.processor.scheduleNow(new SessionTask() {
             @Override
             public void run0(int thread) {
               try {
                 runnerReadEntry(graph, r, parent, listener, procedure, needsToBlock);
+                graph.asyncBarrier.dec();  
               } catch (DatabaseException e) {
                 Logger.defaultLogError(e);
               }
@@ -704,7 +706,7 @@ public class QueryCache extends QueryCacheBase {
         }
     }
     
-    AsyncReadEntry getOrCreateAsyncReadEntry(ReadGraphImpl graph, AsyncRead<?> r, boolean needsToBlock) throws DatabaseException {
+    AsyncReadEntry getOrCreateAsyncReadEntry(ReadGraphImpl graph, AsyncRead<?> r, CacheEntry parent, ListenerBase listener, final AsyncProcedure procedure, boolean needsToBlock) throws DatabaseException {
         AsyncReadEntry existing = null;
         synchronized(asyncReadEntryMap) {
             existing = (AsyncReadEntry)asyncReadEntryMap.get(r);
@@ -721,11 +723,21 @@ public class QueryCache extends QueryCacheBase {
             }
         }
         if(existing.isPending()) {
-          if(needsToBlock)
-            waitPending(graph, existing);
-          else {
-            return null;
-          }
+            if(needsToBlock)
+                waitPending(graph, existing);
+            else {
+                existing.executeWhenResultIsAvailable(graph.processor, new SessionTask(graph) {
+                    @Override
+                    public void run0(int thread) {
+                        try {
+                            runnerAsyncReadEntry(graph, r, parent, listener, procedure, needsToBlock);
+                        } catch (DatabaseException e) {
+                            Logger.defaultLogError(e);
+                        }
+                    }
+                });
+                return null;
+            }
         }
         return existing;
     }
@@ -747,19 +759,10 @@ public class QueryCache extends QueryCacheBase {
             }
             return AsyncReadEntry.computeForEach(graph, r, null, procedure, needsToBlock);
         }
-        AsyncReadEntry entry = (AsyncReadEntry)cache.getOrCreateAsyncReadEntry(graph, r, needsToBlock);
+        AsyncReadEntry entry = (AsyncReadEntry)cache.getOrCreateAsyncReadEntry(graph, r, parent, listener, procedure, needsToBlock);
         if(entry == null) {
-          graph.processor.scheduleNow(new SessionTask(graph) {
-            @Override
-            public void run0(int thread) {
-              try {
-                runnerAsyncReadEntry(graph, r, parent, listener, procedure, needsToBlock);
-              } catch (DatabaseException e) {
-                Logger.defaultLogError(e);
-              }
-            }
-          });
-          return null;
+            // Entry was pending and this request has been queued  
+            return null;
         }
         AsyncProcedure procedure_ = procedure != null ? procedure : emptyProcedureAsyncReadEntry;
         if(entry.isReady()) {
index 54efda83976d8255f549ec0cd1cf41df8fc07e6c..deeb65fddb92a3c161e6315d6ce75ef1d00282aa 100644 (file)
@@ -421,7 +421,7 @@ public class QueryCacheBase {
                int counter = 0;
                while(entry.isPending()) {
                        try {
-                           boolean performed = graph.performPending();
+                           boolean performed = false;//graph.performPending();
                            if(!performed) {
                                        Thread.sleep(1);
                                        counter++;
@@ -905,10 +905,6 @@ public class QueryCacheBase {
                return wrap.get();
        }
 
-       public static <T> T resultReadEntry(ReadGraphImpl graph, Read r, CacheEntry parent, ListenerBase listener, AsyncProcedure<T> procedure) throws DatabaseException {
-               return (T)QueryCache.runnerReadEntry(graph, r, parent, listener, procedure, true);
-       }
-
        public static <T> T resultAsyncReadEntry(ReadGraphImpl graph, AsyncRead r, CacheEntry parent, ListenerBase listener, AsyncProcedure<T> procedure) throws DatabaseException {
                return (T)QueryCache.runnerAsyncReadEntry(graph, r, parent, listener, procedure, true);
        }
index 9daab950e3964a8681a12fabc5ef0b2cfaf74ceb..db9d0310f257a33fbfd53334a930fb31bdef7630 100644 (file)
@@ -14,9 +14,10 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.concurrent.ArrayBlockingQueue;
-import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Semaphore;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
 
 import org.simantics.databoard.Bindings;
 import org.simantics.db.DevelopmentKeys;
@@ -37,372 +38,483 @@ public class QueryListening {
 
     private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(QueryListening.class);
 
-       final private QueryProcessor                            processor;
-       private THashSet<ListenerEntry>                         scheduledListeners    = new THashSet<ListenerEntry>();
-       private boolean                                         firingListeners       = false;
-       final THashMap<CacheEntry, ArrayList<ListenerEntry>>    listeners = new THashMap<CacheEntry, ArrayList<ListenerEntry>>(10, 0.75f);
-       private BlockingQueue<Runnable>                         tasks = new ArrayBlockingQueue<Runnable>(2048);
-       private Map<ListenerBase,ListenerEntry>                 addedEntries = new HashMap<>();
-       
-       QueryListening(QueryProcessor processor) {
-               this.processor = processor;
-               new DependencyManagementThread(processor, tasks).start();
-       }
-       
-       public void sync() {
-               Semaphore s = new Semaphore(0);
-               try {
-                       tasks.put(() -> {
-                               s.release();
-                       });
-                       s.acquire();
-               } catch (Throwable t) {
-                       LOGGER.error("Error while waiting for query dependency management", t);
-               }
-       }
-       
-       static class DependencyManagementThread extends Thread {
-               
-               final private QueryProcessor processor;
-               final BlockingQueue<Runnable> tasks;
-               
-               DependencyManagementThread(QueryProcessor processor, BlockingQueue<Runnable> tasks) {
-                       setName("Query Dependency Manager");
-                       this.processor = processor;
-                       this.tasks = tasks;
-               }
-               
-               @Override
-               public void run() {
-                       while(processor.isAlive()) {
-                               try {
-                                       Runnable r = tasks.take();
-                                       r.run();
-                               } catch (Throwable t) {
-                                       // Spurious problems?
-                                       LOGGER.error("Error while waiting for query dependency management tasks", t);
-                               }
-                       }
-               }
-               
-       }
-       
-       public boolean hasScheduledUpdates() {
-               return !scheduledListeners.isEmpty();
-       }
-
-       void registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) {
-               
-               try {
-                       tasks.put(() -> {
-
-                               if (parent != null && !inferred) {
-                                       try {
-                                               if(!child.isImmutable(graph))
-                                                       child.addParent(parent);
-                                       } catch (DatabaseException e) {
-                                               LOGGER.error("Error while registering query dependencies", e);
-                                       }
-                                       if (Development.DEVELOPMENT) {
-                                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_DEPENDENCIES, Bindings.BOOLEAN)) {
-                                                       System.out.println(child + " -> " + parent);
-                                               }
-                                       }
-                               }
-
-                               if (listener != null)
-                                       registerListener(child, listener, procedure);
-
-                       });
-               } catch (InterruptedException e) {
-                       LOGGER.error("Error while registering dependencies", e);
-               }
-               
-       }
-
-       void registerFirstKnown(ListenerBase base, Object result) {
-               
-               tasks.offer(() -> {
-
-                       ListenerEntry entry = addedEntries.get(base);
-                       if(entry != null) entry.setLastKnown(result);
-                       
-               });
-               
-       }
-
-       public ListenerEntry registerListener(final CacheEntry entry, final ListenerBase base, final Object procedure) {
-
-               assert (entry != null);
-
-               if (base.isDisposed())
-                       return null;
-
-               return addListener(entry, base, procedure);
-
-       }
-
-       /*
-        * Registers a listener and returns an entry iff the entry was added
-        */
-       private ListenerEntry addListener(CacheEntry entry, ListenerBase base, Object procedure) {
-
-               assert (entry != null);
-               assert (procedure != null);
-
-               ArrayList<ListenerEntry> list = listeners.get(entry);
-               if (list == null) {
-                       list = new ArrayList<>(1);
-                       listeners.put(entry, list);
-               }
-
-               ListenerEntry result = new ListenerEntry(entry, base, procedure);
-               // Equals is here based on base
-               int currentIndex = list.indexOf(result);
-               // There was already a listener
-               if(currentIndex > -1) {
-                       ListenerEntry current = list.get(currentIndex);
-                       if(!current.base.isDisposed()) return null;
-                       list.set(currentIndex, result);
-               } else {
-                       list.add(result);
-               }
-
-               if (Development.DEVELOPMENT) {
-                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                               new Exception().printStackTrace();
-                               System.err.println("addListener -> " + list.size() + " " + entry + " " + base + " " + procedure);
-                       }
-               }
-               
-               addedEntries.put(base, result);
-               
-               return result;
-
-       }
-
-       void scheduleListener(ListenerEntry entry) {
-               assert (entry != null);
-               if (Development.DEVELOPMENT) {
-                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                               System.err.println("Scheduled " + entry.procedure);
-                       }
-               }
-               scheduledListeners.add(entry);
-       }
-
-       private void removeListener(ListenerEntry entry) {
-               assert (entry != null);
-               ArrayList<ListenerEntry> list = listeners.get(entry.entry);
-               if(list == null) return;
-               boolean success = list.remove(entry);
-               assert (success);
-               if (list.isEmpty())
-                       listeners.remove(entry.entry);
-       }
-
-       boolean hasListener(CacheEntry entry) {
-               if(listeners.get(entry) != null) return true;
-               return false;
-       }
-
-       boolean hasListenerAfterDisposing(CacheEntry entry) {
-               if(listeners.get(entry) != null) {
-                       ArrayList<ListenerEntry> entries = listeners.get(entry);
-                       ArrayList<ListenerEntry> list = null;
-                       for (ListenerEntry e : entries) {
-                               if (e.base.isDisposed()) {
-                                       if(list == null) list = new ArrayList<ListenerEntry>();
-                                       list.add(e);
-                               }
-                       }
-                       if(list != null) {
-                               for (ListenerEntry e : list) {
-                                       entries.remove(e);
-                               }
-                       }
-                       if (entries.isEmpty()) {
-                               listeners.remove(entry);
-                               return false;
-                       }
-                       return true;
-               }
-               return false;
-       }
-
-       List<ListenerEntry> getListenerEntries(CacheEntry entry) {
-               hasListenerAfterDisposing(entry);
-               if(listeners.get(entry) != null)
-                       return listeners.get(entry);
-               else 
-                       return Collections.emptyList();
-       }
-
-       void processListenerReport(CacheEntry<?> entry, Map<CacheEntry, Set<ListenerBase>> workarea) {
-
-               if(!workarea.containsKey(entry)) {
-
-                       HashSet<ListenerBase> ls = new HashSet<ListenerBase>();
-                       for(ListenerEntry e : getListenerEntries(entry))
-                               ls.add(e.base);
-
-                       workarea.put(entry, ls);
-
-                       for(CacheEntry parent : entry.getParents(processor)) {
-                               processListenerReport(parent, workarea);
-                               ls.addAll(workarea.get(parent));
-                       }
-
-               }
-
-       }
-
-       public synchronized ListenerReport getListenerReport() throws IOException {
-
-               class ListenerReportImpl implements ListenerReport {
-
-                       Map<CacheEntry, Set<ListenerBase>> workarea = new HashMap<CacheEntry, Set<ListenerBase>>();
-
-                       @Override
-                       public void print(PrintStream b) {
-                               Map<ListenerBase, Integer> hist = new HashMap<ListenerBase, Integer>();
-                               for(Map.Entry<CacheEntry, Set<ListenerBase>> e : workarea.entrySet()) {
-                                       for(ListenerBase l : e.getValue()) {
-                                               Integer i = hist.get(l);
-                                               hist.put(l, i != null ? i-1 : -1);
-                                       }
-                               }
-
-                               for(Pair<ListenerBase, Integer> p : CollectionUtils.valueSortedEntries(hist)) {
-                                       b.print("" + -p.second + " " + p.first + "\n");
-                               }
-
-                               b.flush();
-                       }
-
-               }
-
-               ListenerReportImpl result = new ListenerReportImpl();
-
-               Collection<CacheEntryBase> all = processor.allCaches(new CacheCollectionResult()).toCollection();
-               for(CacheEntryBase entry : all) {
-                       hasListenerAfterDisposing(entry);
-               }
-               for(CacheEntryBase entry : all) {
-                       processListenerReport(entry, result.workarea);
-               }
-
-               return result;
-
-       }
-
-       public synchronized String reportListeners(File file) throws IOException {
-
-               if (!processor.isAlive())
-                       return "Disposed!";
-
-               PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
-               ListenerReport report = getListenerReport();
-               report.print(b);
-
-               return "Done reporting listeners.";
-
-       }
-
-       public void fireListeners(WriteGraphImpl graph) {
-
-               assert (!processor.updating);
-               assert (!processor.cache.collecting);
-               assert (!firingListeners);
-
-               firingListeners = true;
-
-               try {
-
-                       // Performing may cause further events to be scheduled.
-                       while (!scheduledListeners.isEmpty()) {
-
-                               // Clone current events to make new entries possible during
-                               // firing.
-                               THashSet<ListenerEntry> entries = scheduledListeners;
-                               scheduledListeners = new THashSet<ListenerEntry>();
+    final private QueryProcessor                            processor;
+    private THashSet<ListenerEntry>                         scheduledListeners    = new THashSet<ListenerEntry>();
+    private boolean                                         firingListeners       = false;
+    final THashMap<CacheEntry, ArrayList<ListenerEntry>>    listeners = new THashMap<CacheEntry, ArrayList<ListenerEntry>>(10, 0.75f);
+    private EventBusImpl                                    eventBus;
+    private Consumer<Runnable>                              consumer;
+    private Map<ListenerBase,ListenerEntry>                 addedEntries = new HashMap<>();
+
+    static class TL extends ThreadLocal<ArrayList<Runnable>> {
+
+        Map<Thread,ArrayList<Runnable>> allQueues = new HashMap<>();
+        ArrayList<ArrayList<Runnable>> dispatchedQueues = new ArrayList<>();
+
+        @Override
+        protected synchronized ArrayList<Runnable> initialValue() {
+            ArrayList<Runnable> result = new ArrayList<>();
+            allQueues.put(Thread.currentThread(), result);
+            return result;
+        }
+
+        synchronized void sendToExecution() {
+            ArrayList<Runnable> rs = allQueues.remove(Thread.currentThread());
+            dispatchedQueues.add(rs);
+            notify();
+        }
+
+        synchronized ArrayList<ArrayList<Runnable>> getDispatchedQueues() {
+            ArrayList<ArrayList<Runnable>> result = dispatchedQueues;
+            dispatchedQueues = new ArrayList<>();
+            return result;
+        }
+
+    }
+
+    static class EventBusImpl {
+
+        private static final int BUFFER_SIZE = 100;
+
+        TL queues = new TL();
+        Semaphore flush = null;
+
+        public boolean isTerminated() {
+            return false;
+        }
+
+        public Consumer<Runnable> newConsumer() {
+            return new Consumer<Runnable>() {
+
+                @Override
+                public void accept(Runnable arg0) {
+                    ArrayList<Runnable> l = queues.get();
+                    l.add(arg0);
+                    if(l.size() == BUFFER_SIZE) {
+                        queues.remove();
+                        queues.sendToExecution();
+                    }
+                }
+            };
+        }
+
+        public void shutdown() {
+        }
+
+        public void start(ThreadFactory arg1) {
+            arg1.newThread(new Runnable() {
+
+                @Override
+                public void run() {
+                    synchronized(queues) {
+                        while(!isTerminated()) {
+                            try {
+                                ArrayList<ArrayList<Runnable>> qs = queues.getDispatchedQueues();
+                                for(ArrayList<Runnable> queue : qs) {
+                                    for(Runnable r : queue)
+                                        r.run();
+                                }
+                                if(flush != null) {
+                                    for(ArrayList<Runnable> queue : queues.allQueues.values()) {
+                                        for(Runnable r : queue) {
+                                            r.run();   
+                                        }
+                                        queue.clear();
+                                    }
+                                    Semaphore s = flush;
+                                    flush = null;
+                                    s.release();
+                                }
+                                queues.wait(1000);
+                            } catch (InterruptedException e) {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+
+            }).start();
+        }
+
+        void flush() {
+            synchronized(queues) {
+                flush = new Semaphore(0);
+                queues.notify();
+            }
+            try {
+                flush.acquire();
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+
+    }
+
+    QueryListening(QueryProcessor processor) {
+        this.processor = processor;
+        eventBus = new EventBusImpl();
+        consumer = eventBus.newConsumer();
+        eventBus.start(new ThreadFactory()
+        {
+            @Override
+            public Thread newThread(Runnable r) {
+                System.err.println("new Thread " + r);
+                return new Thread(r, "QueryDependencyManager");
+            }
+        });
+    }
+
+    public void sync() {
+        try {
+            eventBus.flush();
+        } catch (Throwable t) {
+            LOGGER.error("Error while waiting for query dependency management", t);
+        }
+    }
+
+    public boolean hasScheduledUpdates() {
+        return !scheduledListeners.isEmpty();
+    }
+
+    static class RegisterParentRunnable implements Runnable {
+        
+        final CacheEntry parent;
+        final CacheEntry child;
+        
+        public RegisterParentRunnable(CacheEntry parent, CacheEntry child) {
+            this.parent = parent;
+            this.child = child;
+        }
+
+        @Override
+        public void run() {
+            child.addParent(parent);
+            if (Development.DEVELOPMENT) {
+                if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_DEPENDENCIES, Bindings.BOOLEAN)) {
+                    System.out.println(child + " -> " + parent);
+                }
+            }
+        }
+        
+    }
+    
+    static class RegisterListenerRunnable implements Runnable {
+
+        final QueryListening queryListening;
+        final ListenerBase base;
+        final Object procedure;
+        final CacheEntry parent;
+        final CacheEntry entry;
+
+        public RegisterListenerRunnable(QueryListening queryListening, ListenerBase base, Object procedure, CacheEntry parent, CacheEntry entry) {
+            this.queryListening = queryListening;
+            this.base = base;; 
+            this.procedure = procedure;
+            this.parent = parent;
+            this.entry = entry;
+        }
+
+        @Override
+        public void run() {
+            queryListening.addListener(entry, base, procedure);
+        }
+        
+    }
+
+    void registerDependencies(ReadGraphImpl graph, CacheEntry child, CacheEntry parent, ListenerBase listener, Object procedure, boolean inferred) {
+
+        if(inferred) {
+            assert(listener == null);
+            return;
+        }
+
+        if(parent != null) {
+            try {
+                if(!child.isImmutable(graph))
+                    consumer.accept(new RegisterParentRunnable(parent, child));
+            } catch (DatabaseException e) {
+                LOGGER.error("Error while registering query dependencies", e);
+            }
+        }
+
+        if(listener != null)
+            if(!listener.isDisposed())
+                consumer.accept(new RegisterListenerRunnable(this, listener, procedure, parent, child));
+
+    }
+
+    void registerFirstKnown(ListenerBase base, Object result) {
+        
+        if(base == null) return;
+
+        consumer.accept(() -> {
+            ListenerEntry entry = addedEntries.get(base);
+            if(entry != null) entry.setLastKnown(result);
+        });
+
+    }
+
+    /*
+     * Registers a listener and returns an entry iff the entry was added
+     */
+    private ListenerEntry addListener(CacheEntry entry, ListenerBase base, Object procedure) {
+
+        assert (entry != null);
+        assert (procedure != null);
+
+        ArrayList<ListenerEntry> list = listeners.get(entry);
+        if (list == null) {
+            list = new ArrayList<>(1);
+            listeners.put(entry, list);
+        }
+
+        ListenerEntry result = new ListenerEntry(entry, base, procedure);
+        // Equals is here based on base
+        int currentIndex = list.indexOf(result);
+        // There was already a listener
+        if(currentIndex > -1) {
+            ListenerEntry current = list.get(currentIndex);
+            if(!current.base.isDisposed()) return null;
+            list.set(currentIndex, result);
+        } else {
+            list.add(result);
+        }
+
+        if (Development.DEVELOPMENT) {
+            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                new Exception().printStackTrace();
+                System.err.println("addListener -> " + list.size() + " " + entry + " " + base + " " + procedure);
+            }
+        }
+
+        addedEntries.put(base, result);
+
+        return result;
+
+    }
+
+    void scheduleListener(ListenerEntry entry) {
+        assert (entry != null);
+        if (Development.DEVELOPMENT) {
+            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                System.err.println("Scheduled " + entry.procedure);
+            }
+        }
+        scheduledListeners.add(entry);
+    }
+
+    private void removeListener(ListenerEntry entry) {
+        assert (entry != null);
+        ArrayList<ListenerEntry> list = listeners.get(entry.entry);
+        if(list == null) return;
+        boolean success = list.remove(entry);
+        assert (success);
+        if (list.isEmpty())
+            listeners.remove(entry.entry);
+    }
+
+    boolean hasListener(CacheEntry entry) {
+        if(listeners.get(entry) != null) return true;
+        return false;
+    }
+
+    boolean hasListenerAfterDisposing(CacheEntry entry) {
+        if(listeners.get(entry) != null) {
+            ArrayList<ListenerEntry> entries = listeners.get(entry);
+            ArrayList<ListenerEntry> list = null;
+            for (ListenerEntry e : entries) {
+                if (e.base.isDisposed()) {
+                    if(list == null) list = new ArrayList<ListenerEntry>();
+                    list.add(e);
+                }
+            }
+            if(list != null) {
+                for (ListenerEntry e : list) {
+                    entries.remove(e);
+                }
+            }
+            if (entries.isEmpty()) {
+                listeners.remove(entry);
+                return false;
+            }
+            return true;
+        }
+        return false;
+    }
+
+    List<ListenerEntry> getListenerEntries(CacheEntry entry) {
+        hasListenerAfterDisposing(entry);
+        if(listeners.get(entry) != null)
+            return listeners.get(entry);
+        else 
+            return Collections.emptyList();
+    }
+
+    void processListenerReport(CacheEntry<?> entry, Map<CacheEntry, Set<ListenerBase>> workarea) {
+
+        if(!workarea.containsKey(entry)) {
+
+            HashSet<ListenerBase> ls = new HashSet<ListenerBase>();
+            for(ListenerEntry e : getListenerEntries(entry))
+                ls.add(e.base);
+
+            workarea.put(entry, ls);
+
+            for(CacheEntry parent : entry.getParents(processor)) {
+                processListenerReport(parent, workarea);
+                ls.addAll(workarea.get(parent));
+            }
+
+        }
+
+    }
+
+    public synchronized ListenerReport getListenerReport() throws IOException {
+
+        class ListenerReportImpl implements ListenerReport {
+
+            Map<CacheEntry, Set<ListenerBase>> workarea = new HashMap<CacheEntry, Set<ListenerBase>>();
+
+            @Override
+            public void print(PrintStream b) {
+                Map<ListenerBase, Integer> hist = new HashMap<ListenerBase, Integer>();
+                for(Map.Entry<CacheEntry, Set<ListenerBase>> e : workarea.entrySet()) {
+                    for(ListenerBase l : e.getValue()) {
+                        Integer i = hist.get(l);
+                        hist.put(l, i != null ? i-1 : -1);
+                    }
+                }
+
+                for(Pair<ListenerBase, Integer> p : CollectionUtils.valueSortedEntries(hist)) {
+                    b.print("" + -p.second + " " + p.first + "\n");
+                }
+
+                b.flush();
+            }
+
+        }
+
+        ListenerReportImpl result = new ListenerReportImpl();
+
+        Collection<CacheEntryBase> all = processor.allCaches(new CacheCollectionResult()).toCollection();
+        for(CacheEntryBase entry : all) {
+            hasListenerAfterDisposing(entry);
+        }
+        for(CacheEntryBase entry : all) {
+            processListenerReport(entry, result.workarea);
+        }
+
+        return result;
+
+    }
+
+    public synchronized String reportListeners(File file) throws IOException {
+
+        if (!processor.isAlive())
+            return "Disposed!";
+
+        PrintStream b = new PrintStream(new BufferedOutputStream(new FileOutputStream(file)));
+        ListenerReport report = getListenerReport();
+        report.print(b);
+
+        return "Done reporting listeners.";
+
+    }
+
+    public void fireListeners(WriteGraphImpl graph) {
+
+        assert (!processor.updating);
+        assert (!processor.cache.collecting);
+        assert (!firingListeners);
+
+        firingListeners = true;
+
+        try {
 
-                               ArrayList<ListenerEntry> schedule = new ArrayList<ListenerEntry>();
+            // Performing may cause further events to be scheduled.
+            while (!scheduledListeners.isEmpty()) {
 
-                               for (ListenerEntry listenerEntry : entries) {
+                // Clone current events to make new entries possible during
+                // firing.
+                THashSet<ListenerEntry> entries = scheduledListeners;
+                scheduledListeners = new THashSet<ListenerEntry>();
 
-                                       if (pruneListener(listenerEntry)) {
-                                               if (Development.DEVELOPMENT) {
-                                                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                                                               new Exception().printStackTrace();
-                                                               System.err.println("Pruned " + listenerEntry.procedure);
-                                                       }
-                                               }
-                                               continue;
-                                       }
+                ArrayList<ListenerEntry> schedule = new ArrayList<ListenerEntry>();
 
-                                       final CacheEntry entry = listenerEntry.entry;
-                                       assert (entry != null);
+                for (ListenerEntry listenerEntry : entries) {
 
-                                       Object newValue = processor.compareTo(graph, entry, listenerEntry.getLastKnown());
+                    if (pruneListener(listenerEntry)) {
+                        if (Development.DEVELOPMENT) {
+                            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                                new Exception().printStackTrace();
+                                System.err.println("Pruned " + listenerEntry.procedure);
+                            }
+                        }
+                        continue;
+                    }
+
+                    final CacheEntry entry = listenerEntry.entry;
+                    assert (entry != null);
+
+                    Object newValue = processor.compareTo(graph, entry, listenerEntry.getLastKnown());
+
+                    if (newValue != ListenerEntry.NOT_CHANGED) {
+                        if (Development.DEVELOPMENT) {
+                            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                                new Exception().printStackTrace();
+                                System.err.println("Add to schedule " + listenerEntry.procedure + " with " + newValue);
+                            }
+                        }
+                        schedule.add(listenerEntry);
+                        listenerEntry.setLastKnown(entry.getResult());
+                    }
+
+                }
+
+                for(ListenerEntry listenerEntry : schedule) {
+                    final CacheEntry entry = listenerEntry.entry;
+                    if (Development.DEVELOPMENT) {
+                        if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                            System.err.println("Firing " + listenerEntry.procedure);
+                        }
+                    }
+                    try {
+                        if (Development.DEVELOPMENT) {
+                            if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
+                                System.err.println("Firing " + listenerEntry.procedure + " for " + listenerEntry.entry);
+                            }
+                        }
+                        entry.performFromCache(graph, listenerEntry.procedure);
+                    } catch (Throwable t) {
+                        t.printStackTrace();
+                    }
+                }
+
+            }
+
+        } finally {
+            firingListeners = false;
+        }
+
+    }
+
+    void updateParents(int indent, CacheEntry entry, LinkedList<UpdateEntry> todo) {
+
+        Iterable<CacheEntry> oldParents = entry.getParents(processor);
+        for (CacheEntry parent : oldParents) {
+            if(!parent.isDiscarded())
+                todo.push(new UpdateEntry(entry, parent, indent + 2));
+        }
+
+    }
+
+    private boolean pruneListener(ListenerEntry entry) {
+        if (entry.base.isDisposed()) {
+            removeListener(entry);
+            return true;
+        } else {
+            return false;
+        }
+    }
 
-                                       if (newValue != ListenerEntry.NOT_CHANGED) {
-                                               if (Development.DEVELOPMENT) {
-                                                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                                                               new Exception().printStackTrace();
-                                                               System.err.println("Add to schedule " + listenerEntry.procedure + " with " + newValue);
-                                                       }
-                                               }
-                                               schedule.add(listenerEntry);
-                                               listenerEntry.setLastKnown(entry.getResult());
-                                       }
-
-                               }
-
-                               for(ListenerEntry listenerEntry : schedule) {
-                                       final CacheEntry entry = listenerEntry.entry;
-                                       if (Development.DEVELOPMENT) {
-                                               if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                                                       System.err.println("Firing " + listenerEntry.procedure);
-                                               }
-                                       }
-                                       try {
-                                               if (Development.DEVELOPMENT) {
-                                                       if(Development.<Boolean>getProperty(DevelopmentKeys.QUERYPROCESSOR_LISTENERS, Bindings.BOOLEAN)) {
-                                                               System.err.println("Firing " + listenerEntry.procedure + " for " + listenerEntry.entry);
-                                                       }
-                                               }
-                                               entry.performFromCache(graph, listenerEntry.procedure);
-                                       } catch (Throwable t) {
-                                               t.printStackTrace();
-                                       }
-                               }
-
-                       }
-
-               } finally {
-                       firingListeners = false;
-               }
-
-       }
-       
-       void updateParents(int indent, CacheEntry entry, LinkedList<UpdateEntry> todo) {
-
-               Iterable<CacheEntry> oldParents = entry.getParents(processor);
-               for (CacheEntry parent : oldParents) {
-                       if(!parent.isDiscarded())
-                               todo.push(new UpdateEntry(entry, parent, indent + 2));
-               }
-
-       }
-
-       private boolean pruneListener(ListenerEntry entry) {
-               if (entry.base.isDisposed()) {
-                       removeListener(entry);
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-       
 }
index ee4b11175e4d2767cee0058d3938d8cd47125997..50a9a827a6b6d3ef707d87707e778b091ef62633 100644 (file)
@@ -143,6 +143,8 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap
        QueryThread[]                                   executors;
        
        public LinkedList<SessionTask>                           freeScheduling = new LinkedList<SessionTask>();
+    
+    public LinkedList<SessionTask>                           topLevelTasks = new LinkedList<SessionTask>();
 
        enum ThreadState {
 
@@ -159,13 +161,12 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap
        public void close() {
        }
 
-    public SessionTask getSubTask(ReadGraphImpl impl) {
+    public SessionTask getSubTask(ReadGraphImpl parent) {
         synchronized(querySupportLock) {
             int index = 0;
             while(index < freeScheduling.size()) {
                 SessionTask task = freeScheduling.get(index);
-                if(task.hasCommonParent(task.graph, impl) && task.maybeReady()) {
-                    queueLength.decrementAndGet();
+                if(task.isSubtask(parent) && task.maybeReady()) {
                     return freeScheduling.remove(index);
                 }
                 index++;
@@ -178,82 +179,46 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap
      * We are running errands while waiting for requests to complete.
      * We can only run work that is part of the current root request to avoid any deadlocks
      */
-    public boolean performPending(ReadGraphImpl graph) {
-        SessionTask task = getSubTask(graph);
+    public boolean performPending(ReadGraphImpl under) {
+        SessionTask task = getSubTask(under);
                if(task != null) {
-                       task.run(QueryProcessor.thread.get());
+                       task.run(thread.get());
                        return true;
                }
                return false;
        }
-
+    
     final public void scheduleNow(SessionTask request) {
-        schedule(request, false);
+        SessionTask toExecute = scheduleOrReturnForExecution(request);
+        if(toExecute != null)
+            toExecute.run(thread.get());
     }
 
-    final public void scheduleLater(SessionTask request) {
-        schedule(request, true);
-    }
+    final public SessionTask scheduleOrReturnForExecution(SessionTask request) {
 
-    AtomicInteger queueLength = new AtomicInteger(0);
-    
-    final public void schedule(SessionTask request, boolean late) {
-        
-        int queueLengthEstimate = queueLength.get();
-        if(!late && queueLengthEstimate > 80) {
-            request.run(thread.get());
-            return;
-        }
-        
-               assert(request != null);
-               
-               synchronized(querySupportLock) {
+        assert(request != null);
 
-                   if(BarrierTracing.BOOKKEEPING) {
-                       Exception current = new Exception();
-                       Exception previous = BarrierTracing.tasks.put(request, current);
-                       if(previous != null) {
-                           previous.printStackTrace();
-                           current.printStackTrace();
-                       }
-                   }
+        synchronized(querySupportLock) {
 
-                   if(late) {
-                       int pos = request.position - 1;
-                       if(pos < freeScheduling.size()) { 
-                           freeScheduling.add(pos, request);
-                           queueLength.incrementAndGet();
-                           requests.release();
-                       } else {
-                           freeScheduling.addLast(request);
-                    queueLength.incrementAndGet();
-                    requests.release();
-                       }
-                   }
-                   else {
-                       if(request.getLevel() < 4) {
-                           if(freeScheduling.size() < 100) {
-                               freeScheduling.addFirst(request);
-                           queueLength.incrementAndGet();
-                           requests.release();
-                           } else {
-                               request.run(thread.get());
-                           }
-                       } else {
-                           if(freeScheduling.size() < 20) {
-                               freeScheduling.addFirst(request);
-                           queueLength.incrementAndGet();
-                           requests.release();
-                           } else {
-                               request.run(thread.get());
-                           }
-                       }
-                   }
+            LinkedList<SessionTask> queue = request.rootGraph != null ? freeScheduling : topLevelTasks;
+            
+            if(BarrierTracing.BOOKKEEPING) {
+                Exception current = new Exception();
+                Exception previous = BarrierTracing.tasks.put(request, current);
+                if(previous != null) {
+                    previous.printStackTrace();
+                    current.printStackTrace();
+                }
+            }
 
+            queue.addFirst(request);
+            requests.release();
 
-               }
+        }
 
-       }
+        return null;
+
+    }
 
 
        final int THREADS;
@@ -263,20 +228,22 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap
 
        public static abstract class SessionTask {
 
-               public final ReadGraphImpl graph;
+           final protected ReadGraphImpl rootGraph;
                private int counter = 0;
                protected int position = 1;
                private Exception trace;
 
-               public SessionTask(ReadGraphImpl graph) {
-                       this.graph = graph;
-                       if(graph != null) graph.asyncBarrier.inc();
+               public SessionTask() {
+                   this(null);
                }
-
-        public static boolean hasCommonParent(ReadGraphImpl r1, ReadGraphImpl r2) {
-            if(r1 == null || r2 == null) return false;
-            return r1.getTopLevelGraph() == r2.getTopLevelGraph();
-        } 
+               
+        public SessionTask(ReadGraphImpl rootGraph) {
+            this.rootGraph = rootGraph;
+        }
+        
+        public boolean isSubtask(ReadGraphImpl graph) {
+            return graph.isParent(rootGraph);
+        }
 
         public abstract void run0(int thread);
 
@@ -292,7 +259,7 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap
                        trace = new Exception();
                    }
                    run0(thread);
-                   if(graph != null) graph.asyncBarrier.dec();
+                   //if(graph != null && graph.asyncBarrier != null) graph.asyncBarrier.dec();
                }
                
                public boolean maybeReady() {
@@ -301,16 +268,16 @@ final public class QueryProcessor extends AbstractDisposable implements ReadGrap
 
                @Override
                public String toString() {
-                       if(graph == null)
+                       if(rootGraph == null)
                                return "SessionTask[no graph]";
                        else
-                               return "SessionTask[" + graph.parent + "]";
+                               return "SessionTask[" + rootGraph.parent + "]";
                }
                
-               public int getLevel() {
-                   if(graph == null) return 0;
-                   else return graph.getLevel();
-               }
+//             public int getLevel() {
+//                 if(graph == null) return 0;
+//                 else return graph.getLevel();
+//             }
 
        }
 
index 5510944dc319265e7e033e38a5462e62b280ee16..cfa088a2dbfd7a966e0af3db7f4d9a5aa5d1ad4c 100644 (file)
@@ -98,11 +98,16 @@ class QueryThread extends Thread implements SessionThread {
        }
 
        private boolean pumpTask() {
-               if(!processor.freeScheduling.isEmpty()) {
-                       tasks.add(processor.freeScheduling.removeFirst());
-                       processor.queueLength.decrementAndGet();
-                       return true;
-               }
+           // First finish existing executions
+        if(!processor.freeScheduling.isEmpty()) {
+            tasks.add(processor.freeScheduling.removeFirst());
+            return true;
+        }
+        // Check for new tasks
+        if(!processor.topLevelTasks.isEmpty()) {
+            tasks.add(processor.topLevelTasks.removeFirst());
+            return true;
+        }
                return false;
        }
        
@@ -226,8 +231,6 @@ class QueryThread extends Thread implements SessionThread {
        @Override
        public void run() {
 
-               processor.thread.set(index);
-               
                QuerySupport support = this.querySupport;
 
                try {
@@ -242,23 +245,10 @@ class QueryThread extends Thread implements SessionThread {
                                while(!tasks.isEmpty()) {
 
                                        SessionTask task = tasks.remove(tasks.size()-1);
-//                                     System.err.println("QT " + index + " runs " + task);
-                                       task.run(index);
+                                       task.run(0);
 
                                }
 
-//                             for(int performer=0;performer<THREADS;performer++) {
-//                                     if(!delayQueues[index * THREADS + performer].isEmpty()) {
-//                                             synchronized(executors[performer]) {
-//                                                     threadLocks[performer].lock();
-//                                                     queues[performer].addAll(delayQueues[index * THREADS + performer]);
-//                                                     delayQueues[index * THREADS + performer].clear();
-//                                                     executors[performer].notify();
-//                                                     threadLocks[performer].unlock();
-//                                             }
-//                                     }
-//                             }
-
                        }
 
                } catch (Throwable t) {
index 72f132288bf79990c5bf56ce591463993ccd8acd..9edcbb997b97554946ea510728fe9395259d5741 100644 (file)
@@ -139,7 +139,8 @@ public final class ReadEntry<T> extends CacheEntryBase<AsyncProcedure<T>> implem
             } finally {
  
                 executeGraph.asyncBarrier.dec();
-                executeGraph.asyncBarrier.waitBarrier(procedure, executeGraph);
+                if(needsToBlock)
+                    executeGraph.asyncBarrier.waitBarrier(procedure, executeGraph);
 
             }
                 
index 6ecfb8eadf126834b958fefe5f2b850ea05d3ee3..286ce09aaea0ad4c18b4ddb4fb52c2e304883197 100644 (file)
@@ -30,6 +30,7 @@ import org.simantics.utils.datastructures.Pair;
 public class PropertyInfo {
     public final Resource predicate;
     public final String name;
+    public final boolean isImmutable;
     public final boolean isHasProperty;
     public final boolean isFunctional;
     public final Set<String> classifications;
@@ -42,9 +43,10 @@ public class PropertyInfo {
     public final Map<String,Pair<Resource, ChildReference>> subliteralPredicates;
     public final ValueAccessor valueAccessor;
     public final boolean hasEnumerationRange;
-    public PropertyInfo(Resource predicate, String name, boolean isFunctional, boolean isHasProperty, Set<String> classifications, VariableBuilder builder, Resource literalRange, Datatype requiredDatatype, String definedUnit, String requiredValueType, Binding defaultBinding, Map<String,Pair<Resource, ChildReference>> subliteralPredicates, ValueAccessor valueAccessor, boolean hasEnumerationRange) {
+    public PropertyInfo(Resource predicate, String name, boolean isImmutable, boolean isFunctional, boolean isHasProperty, Set<String> classifications, VariableBuilder builder, Resource literalRange, Datatype requiredDatatype, String definedUnit, String requiredValueType, Binding defaultBinding, Map<String,Pair<Resource, ChildReference>> subliteralPredicates, ValueAccessor valueAccessor, boolean hasEnumerationRange) {
         this.predicate = predicate;
         this.name = name;
+        this.isImmutable = isImmutable;
         this.isFunctional = isFunctional;
         this.isHasProperty = isHasProperty;
         this.classifications = classifications;
@@ -59,7 +61,6 @@ public class PropertyInfo {
         this.hasEnumerationRange = hasEnumerationRange;
     }
     public static PropertyInfo make(ReadGraph graph, Resource predicate, String name, boolean isFunctional, boolean isHasProperty, Set<String> classifications, VariableBuilder builder, Resource literalRange, Datatype requiredDatatype, String definedUnit, String requiredValueType, Map<String,Pair<Resource, ChildReference>> subliteralPredicates, ValueAccessor valueAccessor, boolean hasEnumerationRange) throws DatabaseException {
-
         Layer0 L0 = Layer0.getInstance(graph);
         if(literalRange != null) {
             Collection<Resource> dts = graph.getAssertedObjects(literalRange, L0.HasDataType);
@@ -68,11 +69,8 @@ public class PropertyInfo {
                 if(requiredDatatype == null) requiredDatatype = dt;
             }
         }
-        
         Binding defaultBinding = requiredDatatype != null ? Bindings.getBinding(requiredDatatype) : null;
-        
-        return new PropertyInfo(predicate, name, isFunctional, isHasProperty, classifications, builder, literalRange, requiredDatatype, definedUnit, requiredValueType, defaultBinding, subliteralPredicates, valueAccessor, hasEnumerationRange);
-
+        return new PropertyInfo(predicate, name, graph.isImmutable(predicate), isFunctional, isHasProperty, classifications, builder, literalRange, requiredDatatype, definedUnit, requiredValueType, defaultBinding, subliteralPredicates, valueAccessor, hasEnumerationRange);
     }
     public boolean hasClassification(String classification) {
         return classifications.contains(classification);
@@ -107,20 +105,22 @@ public class PropertyInfo {
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((builder == null) ? 0 : builder.hashCode());
-        result = prime * result + ((classifications == null) ? 0 : classifications.hashCode());
-        result = prime * result + ((defaultBinding == null) ? 0 : defaultBinding.hashCode());
-        result = prime * result + ((definedUnit == null) ? 0 : definedUnit.hashCode());
-        result = prime * result + (hasEnumerationRange ? 1231 : 1237);
-        result = prime * result + (isFunctional ? 1231 : 1237);
-        result = prime * result + (isHasProperty ? 1231 : 1237);
-        result = prime * result + ((literalRange == null) ? 0 : literalRange.hashCode());
-        result = prime * result + ((name == null) ? 0 : name.hashCode());
         result = prime * result + ((predicate == null) ? 0 : predicate.hashCode());
-        result = prime * result + ((requiredDatatype == null) ? 0 : requiredDatatype.hashCode());
-        result = prime * result + ((requiredValueType == null) ? 0 : requiredValueType.hashCode());
-        result = prime * result + ((subliteralPredicates == null) ? 0 : subliteralPredicates.hashCode());
-        result = prime * result + ((valueAccessor == null) ? 0 : valueAccessor.hashCode());
+        if(!isImmutable) { 
+            result = prime * result + ((builder == null) ? 0 : builder.hashCode());
+            result = prime * result + ((classifications == null) ? 0 : classifications.hashCode());
+            result = prime * result + ((defaultBinding == null) ? 0 : defaultBinding.hashCode());
+            result = prime * result + ((definedUnit == null) ? 0 : definedUnit.hashCode());
+            result = prime * result + (hasEnumerationRange ? 1231 : 1237);
+            result = prime * result + (isFunctional ? 1231 : 1237);
+            result = prime * result + (isHasProperty ? 1231 : 1237);
+            result = prime * result + ((literalRange == null) ? 0 : literalRange.hashCode());
+            result = prime * result + ((name == null) ? 0 : name.hashCode());
+            result = prime * result + ((requiredDatatype == null) ? 0 : requiredDatatype.hashCode());
+            result = prime * result + ((requiredValueType == null) ? 0 : requiredValueType.hashCode());
+            result = prime * result + ((subliteralPredicates == null) ? 0 : subliteralPredicates.hashCode());
+            result = prime * result + ((valueAccessor == null) ? 0 : valueAccessor.hashCode());
+        }
         return result;
     }
     @Override
@@ -132,6 +132,13 @@ public class PropertyInfo {
         if (getClass() != obj.getClass())
             return false;
         PropertyInfo other = (PropertyInfo) obj;
+        if (predicate == null) {
+            if (other.predicate != null)
+                return false;
+        } else if (!predicate.equals(other.predicate))
+            return false;
+        if(isImmutable)
+            return true;
         if (builder == null) {
             if (other.builder != null)
                 return false;
@@ -168,11 +175,6 @@ public class PropertyInfo {
                 return false;
         } else if (!name.equals(other.name))
             return false;
-        if (predicate == null) {
-            if (other.predicate != null)
-                return false;
-        } else if (!predicate.equals(other.predicate))
-            return false;
         if (requiredDatatype == null) {
             if (other.requiredDatatype != null)
                 return false;
index 8d364c737bdc5dc3070b59ccbb412a3ad73ff5ca..1bcd918771f3db8520507e6893b2de2376d61164 100644 (file)
@@ -104,7 +104,7 @@ implements Read<Function1<EvaluationContext,Object>> {
         return DEFAULT_EXPECTED_EFFECT;
     }
     
-    private ExpressionEvaluator prepareEvaluator(final ReadGraph graph, final CompilationContext context, Type expectedType) throws DatabaseException {
+    protected ExpressionEvaluator prepareEvaluator(final ReadGraph graph, final CompilationContext context, Type expectedType) throws DatabaseException {
         final Variable contextVariable = new Variable("context", getContextVariableType());
         LocalEnvironment localEnvironment = new AbstractLocalEnvironment() {
             THashMap<String,Pair<Variable,Expression>> precalculatedVariables = new THashMap<String,Pair<Variable,Expression>>(); 
@@ -156,7 +156,7 @@ implements Read<Function1<EvaluationContext,Object>> {
     }
     
     @SuppressWarnings("unchecked")
-    private Function1<EvaluationContext, Object> eval(ExpressionEvaluator evaluator, ReadGraph graph) throws DatabaseException {
+    protected Function1<EvaluationContext, Object> eval(ExpressionEvaluator evaluator, ReadGraph graph) throws DatabaseException {
         Object oldGraph = SCLContext.getCurrent().put("graph", graph);
         try {
             return (Function1<EvaluationContext,Object>)evaluator.eval();
index 7927614cd37f9779292ee4ace98e5fd4ba7f00f0..0589f36d2007ac8c1366007b6869e643649c6efa 100644 (file)
@@ -37,7 +37,7 @@ import org.slf4j.LoggerFactory;
 public class StandardGraphPropertyVariable extends AbstractPropertyVariable {
     private static final Logger LOGGER = LoggerFactory.getLogger(StandardGraphPropertyVariable.class);
     
-       protected static final PropertyInfo NO_PROPERTY = new PropertyInfo(null, null,
+       protected static final PropertyInfo NO_PROPERTY = new PropertyInfo(null, null, true,
                        false, false, Collections.<String> emptySet(), null, null, null, null, null, null,
                        Collections.<String, Pair<Resource, ChildReference>> emptyMap(),
                        null, false);
index 8220ba74385221cfc2064d6ff368c023c72f42b0..1eb81524031b7431a90be4c9227df5618c2a0793 100644 (file)
@@ -1639,7 +1639,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
 
                     } else {
 
-                       BlockingAsyncProcedure<T> wrap = new BlockingAsyncProcedure<T>(newGraph.asyncBarrier, newGraph, procedure, request) {
+                       BlockingAsyncProcedure<T> wrap = new BlockingAsyncProcedure<T>(newGraph, null, procedure, request, true) {
                                
                                public void execute(AsyncReadGraph graph_, T result) {
                                        task.finish();
@@ -1656,6 +1656,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
                        try {
 
                             request.perform(newGraph, wrap);
+                            wrap.dec();
                             wrap.get();
 
                         } catch (DatabaseException e) {
@@ -3523,7 +3524,7 @@ public abstract class SessionImplSocket implements Session, WriteRequestSchedule
 
     public int getAmountOfQueryThreads() {
         // This must be a power of two
-        return 1;
+        return 32;
 //        return Integer.highestOneBit(Runtime.getRuntime().availableProcessors());
     }
 
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/ConnectionRequest2.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/ConnectionRequest2.java
new file mode 100644 (file)
index 0000000..36a01b5
--- /dev/null
@@ -0,0 +1,101 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.adapter;
+
+import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.primitiverequest.Adapter;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.procedure.AsyncProcedure;
+import org.simantics.diagram.synchronization.ErrorHandler;
+import org.simantics.g2d.canvas.ICanvasContext;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.element.ElementClass;
+import org.simantics.g2d.element.IElement;
+import org.simantics.scl.runtime.tuple.Tuple3;
+
+/**
+ * @author Antti Villberg
+ */
+public class ConnectionRequest2 extends BaseRequest2<Resource, Tuple3> {
+
+    final IDiagram diagram;
+    final ErrorHandler errorHandler;
+
+    public ConnectionRequest2(ICanvasContext canvas, IDiagram diagram, Resource resource, ErrorHandler errorHandler) {
+        super(canvas, resource);
+        this.diagram = diagram;
+        this.errorHandler = errorHandler;
+    }
+
+    @Override
+    public void perform(AsyncReadGraph graph, final AsyncProcedure<Tuple3> procedure) {
+
+        graph.forHasStatement(data, new AsyncProcedure<Boolean>() {
+
+            @Override
+            public void exception(AsyncReadGraph graph, Throwable throwable) {
+                procedure.exception(graph, throwable);
+            }
+
+            @Override
+            public void execute(AsyncReadGraph graph, Boolean result) {
+
+                if (!result) {
+                    procedure.execute(graph, null);
+                    return;
+                }
+
+                graph.asyncRequest(new Adapter<ElementFactory>(data, ElementFactory.class), new TransientCacheAsyncListener<ElementFactory>() {
+
+                    @Override
+                    public void exception(AsyncReadGraph graph, Throwable throwable) {
+                        errorHandler.error("Unexpected ElementFactory adaption failure", throwable);
+                        procedure.execute(graph, null);
+                    }
+
+                    @Override
+                    public void execute(AsyncReadGraph graph, final ElementFactory factory) {
+
+                        graph.asyncRequest(new GetElementClassRequest(factory, data, canvas, diagram), new TransientCacheAsyncListener<ElementClass>() {
+
+                            @Override
+                            public void exception(AsyncReadGraph graph, Throwable throwable) {
+                                errorHandler.error("Unexpected ElementClass creation failure", throwable);
+                                procedure.execute(graph, null);
+                            }
+
+                            @Override
+                            public void execute(AsyncReadGraph graph, final ElementClass ec) {
+
+                                graph.asyncRequest(new SpawnRequest(canvas, ec, data), new TransientCacheAsyncListener<IElement>() {
+
+                                    @Override
+                                    public void exception(AsyncReadGraph graph, Throwable throwable) {
+                                        errorHandler.error("Unexpected SpawnRequest failure", throwable);
+                                        procedure.execute(graph, null);
+                                    }
+
+                                    @Override
+                                    public void execute(AsyncReadGraph graph, IElement element) {
+                                        procedure.execute(graph, new Tuple3(element, ec, factory));
+                                    }
+                                });
+                            }
+                        });
+                    }
+                });
+            }
+        });
+    }
+
+}
index 226f47daa76b62ea90f572d561aa75e6bc830295..37471eb3a1186fa8dc1c993e7d0f267f178a5f91 100644 (file)
@@ -138,6 +138,7 @@ import org.simantics.scenegraph.INode;
 import org.simantics.scenegraph.profile.DataNodeConstants;
 import org.simantics.scenegraph.profile.DataNodeMap;
 import org.simantics.scenegraph.profile.common.ProfileObserver;
+import org.simantics.scl.runtime.tuple.Tuple3;
 import org.simantics.structural2.modelingRules.IModelingRules;
 import org.simantics.utils.datastructures.ArrayMap;
 import org.simantics.utils.datastructures.MapSet;
@@ -1649,6 +1650,90 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
             this.removedRouteGraphConnections.clear();
         }
 
+        class LoadNodeListener extends DisposableListener<IElement> {
+
+            final Resource element;
+            public IElement lastLoaded;
+
+            public LoadNodeListener(ListenerSupport support, Resource element) {
+                super(support);
+                this.element = element;
+            }
+
+            @Override
+            public String toString() {
+                return "Node load listener for " + element;
+            }
+
+            public void applyFirst(IElement loaded) {
+
+                Object data = loaded.getHint(ElementHints.KEY_OBJECT);
+
+                if (addedElementMap.containsKey(data)) {
+                    // This element was just loaded, in
+                    // which case its hints need to
+                    // uploaded to the real mapped
+                    // element immediately.
+                    IElement mappedElement = getMappedElement(data);
+                    if (DebugPolicy.DEBUG_NODE_LISTENER)
+                        System.out.println("LOADED ADDED ELEMENT, currently mapped element: " + mappedElement);
+                    if (mappedElement != null && (mappedElement instanceof Element)) {
+                        if (DebugPolicy.DEBUG_NODE_LISTENER) {
+                            System.out.println("  mapped hints: " + mappedElement.getHints());
+                            System.out.println("  loaded hints: " + loaded.getHints());
+                        }
+                        updateMappedElement((Element) mappedElement, loaded);
+                    }
+                }
+
+            }
+
+            @Override
+            public void execute(IElement loaded) {
+
+                // Invoked when the element has been loaded.
+                if (DebugPolicy.DEBUG_NODE_LISTENER)
+                    System.out.println("NODE LoadListener for " + loaded);
+
+                if (loaded == null) {
+                    disposeListener();
+                    return;
+                }
+
+
+                boolean first = lastLoaded == null;
+
+                lastLoaded = loaded;
+
+                /*
+                 * The first invocation is postponed
+                 */
+                if(first) {
+                    applyFirst(loaded);
+                    return;
+                }
+
+                Object data = loaded.getHint(ElementHints.KEY_OBJECT);
+
+                // Logic for disposing listener
+                if (!previousContent.nodeSet.contains(data)) {
+                    if (DebugPolicy.DEBUG_NODE_LISTENER)
+                        System.out.println("NODE LoadListener, node not in current content: " + data + ". Disposing.");
+                    disposeListener();
+                    return;
+                }
+
+                // This element was already loaded.
+                // Just schedule an update some time
+                // in the future.
+                if (DebugPolicy.DEBUG_NODE_LISTENER)
+                    System.out.println("PREVIOUSLY LOADED NODE UPDATED, scheduling update into the future");
+                offerGraphUpdate( nodeUpdater(element, loaded) );
+
+            }
+
+        }
+
         void processNodes(AsyncReadGraph graph) throws DatabaseException {
 
             for (Map.Entry<Resource, Change> entry : changes.elements.entrySet()) {
@@ -1745,6 +1830,13 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                                     @Override
                                     public void execute(AsyncReadGraph graph, final IElement e) {
 
+                                        mapElement(element, e);
+                                        synchronized (GraphToDiagramUpdater.this) {
+                                            addedElements.add(e);
+                                            addedElementMap.put(element, e);
+                                            addedConnectionMap.put(element, e);
+                                        }
+
                                         // Read connection type
                                         graph.forSingleType(element, br.DIA.Connection, new Procedure<Resource>() {
                                             @Override
@@ -1778,87 +1870,33 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                                 });
                             } else if (content.nodeSet.contains(element)) {
 
-                                Listener<IElement> loadListener = new DisposableListener<IElement>(canvasListenerSupport) {
-
-                                    boolean firstTime = true;
+                                graph.asyncRequest(new ReadRequest() {
 
                                     @Override
-                                    public String toString() {
-                                        return "Node load listener for " + element;
-                                    }
-                                    @Override
-                                    public void execute(IElement loaded) {
-                                        // Invoked when the element has been loaded.
-                                        if (DebugPolicy.DEBUG_NODE_LISTENER)
-                                            System.out.println("NODE LoadListener for " + loaded);
-
-                                        if (loaded == null) {
-                                            disposeListener();
-                                            return;
-                                        }
-
-                                        if (firstTime) {
-
-                                            // This is invoked before the element is actually loaded.
-                                            //System.out.println("NodeRequestProcedure " + e);
-                                            if (DebugPolicy.DEBUG_NODE_LOAD)
-                                                System.out.println("MAPPING ADDED NODE: " + element + " -> " + loaded);
-                                            mapElement(element, loaded);
-                                            synchronized (GraphToDiagramUpdater.this) {
-                                                addedElements.add(loaded);
-                                                addedElementMap.put(element, loaded);
-                                            }
-
-                                            firstTime = false;
-
-                                        }
-
-                                        Object data = loaded.getHint(ElementHints.KEY_OBJECT);
+                                    public void run(ReadGraph graph) throws DatabaseException {
 
-                                        // Logic for disposing listener
-                                        if (!previousContent.nodeSet.contains(data)) {
-                                            if (DebugPolicy.DEBUG_NODE_LISTENER)
-                                                System.out.println("NODE LoadListener, node not in current content: " + data + ". Disposing.");
-                                            disposeListener();
+                                        LoadNodeListener loadListener = new LoadNodeListener(canvasListenerSupport, element);
+                                        Tuple3 t = graph.syncRequest(new NodeRequest2(canvas, diagram, element));
+                                        IElement e = (IElement)t.c0;
+                                        ElementClass ec = (ElementClass)t.c1;
+                                        org.simantics.diagram.adapter.ElementFactory ef = (org.simantics.diagram.adapter.ElementFactory)t.c2;
+                                        if (e == null)
                                             return;
+                                        
+                                        // This is invoked before the element is actually loaded.
+                                        //System.out.println("NodeRequestProcedure " + e);
+                                        if (DebugPolicy.DEBUG_NODE_LOAD)
+                                            System.out.println("MAPPING ADDED NODE: " + element + " -> " + e);
+                                        mapElement(element, e);
+                                        synchronized (GraphToDiagramUpdater.this) {
+                                            addedElements.add(e);
+                                            addedElementMap.put(element, e);
                                         }
 
-                                        if (addedElementMap.containsKey(data)) {
-                                            // This element was just loaded, in
-                                            // which case its hints need to
-                                            // uploaded to the real mapped
-                                            // element immediately.
-                                            IElement mappedElement = getMappedElement(data);
-                                            if (DebugPolicy.DEBUG_NODE_LISTENER)
-                                                System.out.println("LOADED ADDED ELEMENT, currently mapped element: " + mappedElement);
-                                            if (mappedElement != null && (mappedElement instanceof Element)) {
-                                                if (DebugPolicy.DEBUG_NODE_LISTENER) {
-                                                    System.out.println("  mapped hints: " + mappedElement.getHints());
-                                                    System.out.println("  loaded hints: " + loaded.getHints());
-                                                }
-                                                updateMappedElement((Element) mappedElement, loaded);
-                                            }
-                                        } else {
-                                            // This element was already loaded.
-                                            // Just schedule an update some time
-                                            // in the future.
-                                            if (DebugPolicy.DEBUG_NODE_LISTENER)
-                                                System.out.println("PREVIOUSLY LOADED NODE UPDATED, scheduling update into the future");
-                                            offerGraphUpdate( nodeUpdater(element, loaded) );
-                                        }
-                                    }
-                                };
-
-                                //System.out.println("NODE REQUEST: " + element);
-                                graph.asyncRequest(new NodeRequest(canvas, diagram, element, loadListener), new AsyncProcedure<IElement>() {
-                                    @Override
-                                    public void execute(AsyncReadGraph graph, IElement e) {
-                                    }
-
-                                    @Override
-                                    public void exception(AsyncReadGraph graph, Throwable throwable) {
-                                        error(throwable);
+                                        graph.syncRequest(new LoadRequest(canvas, diagram, ef, ec, element), loadListener);
+                                        
                                     }
+                                    
                                 });
 
                             } else {
@@ -1980,8 +2018,121 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                 }
             }
         }
+        
+        class LoadRouteGraphConnectionListener extends DisposableListener<IElement> {
+            
+            final Resource connection;
+            public IElement lastLoaded;
+
+            public LoadRouteGraphConnectionListener(ListenerSupport support, Resource connection) {
+                super(support);
+                this.connection = connection;
+            }
+
+            @Override
+            public String toString() {
+                return "processRouteGraphConnections " + connection;
+            }
+            
+            public void applyFirst(IElement loaded) {
+                
+                Object data = loaded.getHint(ElementHints.KEY_OBJECT);
+                if (addedElementMap.containsKey(data)) {
+                    // This element was just loaded, in
+                    // which case its hints need to
+                    // uploaded to the real mapped
+                    // element immediately.
+                    IElement mappedElement = getMappedElement(data);
+                    if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
+                        System.out.println("LOADED ADDED ROUTE GRAPH CONNECTION, currently mapped connection: " + mappedElement);
+                    if (mappedElement instanceof Element) {
+                        if (DebugPolicy.DEBUG_CONNECTION_LISTENER) {
+                            System.out.println("  mapped hints: " + mappedElement.getHints());
+                            System.out.println("  loaded hints: " + loaded.getHints());
+                        }
+                        updateMappedElement((Element) mappedElement, loaded);
+                    }
+                }
+                
+            }
+            
+            @Override
+            public void execute(IElement loaded) {
+                
+                // Invoked when the element has been loaded.
+                if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
+                    System.out.println("ROUTE GRAPH CONNECTION LoadListener for " + loaded);
+
+                if (loaded == null) {
+                    disposeListener();
+                    return;
+                }
+
+                boolean first = lastLoaded == null;
+
+                lastLoaded = loaded;
+                
+                /*
+                 * The first invocation is postponed
+                 */
+                if(first) {
+                    applyFirst(loaded);
+                    return;
+                }
+
+                Object data = loaded.getHint(ElementHints.KEY_OBJECT);
+
+                // Logic for disposing listener
+                if (!previousContent.routeGraphConnectionSet.contains(data)) {
+                    if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
+                        System.out.println("ROUTE GRAPH CONNECTION LoadListener, connection not in current content: " + data + ". Disposing.");
+                    disposeListener();
+                    return;
+                }
+
+                if (addedElementMap.containsKey(data)) {
+                    // This element was just loaded, in
+                    // which case its hints need to
+                    // uploaded to the real mapped
+                    // element immediately.
+                    IElement mappedElement = getMappedElement(data);
+                    if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
+                        System.out.println("LOADED ADDED ROUTE GRAPH CONNECTION, currently mapped connection: " + mappedElement);
+                    if (mappedElement instanceof Element) {
+                        if (DebugPolicy.DEBUG_CONNECTION_LISTENER) {
+                            System.out.println("  mapped hints: " + mappedElement.getHints());
+                            System.out.println("  loaded hints: " + loaded.getHints());
+                        }
+                        updateMappedElement((Element) mappedElement, loaded);
+                    }
+                } else {
+                    // This element was already loaded.
+                    // Just schedule an update some time
+                    // in the future.
+                    if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
+                        System.out.println("PREVIOUSLY LOADED ROUTE GRAPH CONNECTION UPDATED, scheduling update into the future: " + connection);
+
+                    Set<Object> dirtyNodes = new THashSet<Object>(4);
+                    IElement mappedElement = getMappedElement(connection);
+                    ConnectionEntity ce = mappedElement.getHint(ElementHints.KEY_CONNECTION_ENTITY);
+                    if (ce != null) {
+                        for (Connection conn : ce.getTerminalConnections(null)) {
+                            Object o = conn.node.getHint(ElementHints.KEY_OBJECT);
+                            if (o != null) {
+                                dirtyNodes.add(o);
+                                if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
+                                    System.out.println("Marked connectivity dirty for node: " + conn.node);
+                            }
+                        }
+                    }
+
+                    offerGraphUpdate( routeGraphConnectionUpdater(connection, loaded, dirtyNodes) );
+                }
+            }
+        };
 
-        void processRouteGraphConnections(ReadGraph graph) throws DatabaseException {
+
+        void processRouteGraphConnections(AsyncReadGraph graph) throws DatabaseException {
             for (Map.Entry<Resource, Change> entry : changes.routeGraphConnections.entrySet()) {
                 final Resource connection = entry.getKey();
 
@@ -1992,97 +2143,39 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                         if (mappedElement != null)
                             continue;
 
-                        Listener<IElement> loadListener = new DisposableListener<IElement>(canvasListenerSupport) {
-
-                            boolean firstTime = true;
+                        
+                        graph.asyncRequest(new ReadRequest() {
 
                             @Override
-                            public String toString() {
-                                return "processRouteGraphConnections " + connection;
-                            }
-                            @Override
-                            public void execute(IElement loaded) {
-                                // Invoked when the element has been loaded.
-                                if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
-                                    System.out.println("ROUTE GRAPH CONNECTION LoadListener for " + loaded);
+                            public void run(ReadGraph graph) throws DatabaseException {
 
-                                if (loaded == null) {
-                                    disposeListener();
-                                    return;
-                                }
-
-                                if(firstTime) {
-                                    if (DebugPolicy.DEBUG_NODE_LOAD)
-                                        System.out.println("MAPPING ADDED ROUTE GRAPH CONNECTION: " + connection + " -> " + loaded);
-                                    mapElement(connection, loaded);
-                                    synchronized (GraphToDiagramUpdater.this) {
-                                        addedElements.add(loaded);
-                                        addedElementMap.put(connection, loaded);
-                                        addedRouteGraphConnectionMap.put(connection, loaded);
-                                    }
-                                    firstTime = false;
-                                }
+                                LoadRouteGraphConnectionListener loadListener = new LoadRouteGraphConnectionListener(canvasListenerSupport, connection);
 
-                                Object data = loaded.getHint(ElementHints.KEY_OBJECT);
+                                Tuple3 t = graph.syncRequest(new ConnectionRequest2(canvas, diagram, connection, errorHandler));
+                                IElement e = (IElement)t.c0;
+                                ElementClass ec = (ElementClass)t.c1;
+                                org.simantics.diagram.adapter.ElementFactory ef = (org.simantics.diagram.adapter.ElementFactory)t.c2;
 
-                                // Logic for disposing listener
-                                if (!previousContent.routeGraphConnectionSet.contains(data)) {
-                                    if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
-                                        System.out.println("ROUTE GRAPH CONNECTION LoadListener, connection not in current content: " + data + ". Disposing.");
-                                    disposeListener();
+                                if (e == null)
                                     return;
+
+                                //System.out.println("ConnectionRequestProcedure " + e);
+                                if (DebugPolicy.DEBUG_NODE_LOAD)
+                                    System.out.println("MAPPING ADDED ROUTE GRAPH CONNECTION: " + connection + " -> " + e);
+                                mapElement(connection, e);
+                                synchronized (GraphToDiagramUpdater.this) {
+                                    addedElements.add(e);
+                                    addedElementMap.put(connection, e);
+                                    addedRouteGraphConnectionMap.put(connection, e);
                                 }
 
-                                if (addedElementMap.containsKey(data)) {
-                                    // This element was just loaded, in
-                                    // which case its hints need to
-                                    // uploaded to the real mapped
-                                    // element immediately.
-                                    IElement mappedElement = getMappedElement(data);
-                                    if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
-                                        System.out.println("LOADED ADDED ROUTE GRAPH CONNECTION, currently mapped connection: " + mappedElement);
-                                    if (mappedElement instanceof Element) {
-                                        if (DebugPolicy.DEBUG_CONNECTION_LISTENER) {
-                                            System.out.println("  mapped hints: " + mappedElement.getHints());
-                                            System.out.println("  loaded hints: " + loaded.getHints());
-                                        }
-                                        updateMappedElement((Element) mappedElement, loaded);
-                                    }
-                                } else {
-                                    // This element was already loaded.
-                                    // Just schedule an update some time
-                                    // in the future.
-                                    if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
-                                        System.out.println("PREVIOUSLY LOADED ROUTE GRAPH CONNECTION UPDATED, scheduling update into the future: " + connection);
-
-                                    Set<Object> dirtyNodes = new THashSet<Object>(4);
-                                    IElement mappedElement = getMappedElement(connection);
-                                    ConnectionEntity ce = mappedElement.getHint(ElementHints.KEY_CONNECTION_ENTITY);
-                                    if (ce != null) {
-                                        for (Connection conn : ce.getTerminalConnections(null)) {
-                                            Object o = conn.node.getHint(ElementHints.KEY_OBJECT);
-                                            if (o != null) {
-                                                dirtyNodes.add(o);
-                                                if (DebugPolicy.DEBUG_CONNECTION_LISTENER)
-                                                    System.out.println("Marked connectivity dirty for node: " + conn.node);
-                                            }
-                                        }
-                                    }
+                                graph.syncRequest(new LoadRequest(canvas, diagram, ef, ec, connection), loadListener);
 
-                                    offerGraphUpdate( routeGraphConnectionUpdater(connection, loaded, dirtyNodes) );
-                                }
                             }
-                        };
 
-                        graph.syncRequest(new ConnectionRequest(canvas, diagram, connection, errorHandler, loadListener), new Procedure<IElement>() {
-                            @Override
-                            public void execute(final IElement e) {
-                            }
-                            @Override
-                            public void exception(Throwable throwable) {
-                                error(throwable);
-                            }
                         });
+
+
                         break;
                     }
                     case REMOVED: {
@@ -2127,8 +2220,6 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
 
                             Listener<IElement> loadListener = new DisposableListener<IElement>(canvasListenerSupport) {
 
-                                boolean firstTime = true;
-
                                 @Override
                                 public String toString() {
                                     return "processBranchPoints for " + element;
@@ -2144,21 +2235,6 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                                         return;
                                     }
 
-                                    if (firstTime) {
-
-                                        mapElement(element, loaded);
-                                        synchronized (GraphToDiagramUpdater.this) {
-                                            addedBranchPoints.add(loaded);
-                                            addedElementMap.put(element, loaded);
-                                            ConnectionEntityImpl ce = getConnectionEntity(element);
-                                            loaded.setHint(ElementHints.KEY_CONNECTION_ENTITY, ce);
-                                            loaded.setHint(ElementHints.KEY_PARENT_ELEMENT, ce.getConnectionElement());
-                                        }
-
-                                        firstTime = false;
-
-                                    }
-
                                     Object data = loaded.getHint(ElementHints.KEY_OBJECT);
                                     if (addedElementMap.containsKey(data)) {
                                         // This element was just loaded, in
@@ -2360,6 +2436,7 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
                         return "processBranchPoints";
                     }
                 });
+
             }
             //System.out.println("---- PROCESS BRANCH POINTS END");
 
@@ -2394,9 +2471,9 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
 
             task = Timing.BEGIN("processRouteGraphConnections");
             if (!changes.routeGraphConnections.isEmpty()) {
-                graph.syncRequest(new ReadRequest() {
+                graph.syncRequest(new AsyncReadRequest() {
                     @Override
-                    public void run(ReadGraph graph) throws DatabaseException {
+                    public void run(AsyncReadGraph graph) throws DatabaseException {
                         processRouteGraphConnections(graph);
                     }
                     @Override
@@ -2724,8 +2801,11 @@ public class GraphToDiagramSynchronizer extends AbstractDisposable implements ID
 
                 diagramUpdateLock.lock();
                 try {
-                    if (DebugPolicy.DEBUG_DIAGRAM_UPDATE)
+                    if (DebugPolicy.DEBUG_DIAGRAM_UPDATE) {
                         System.out.println("In diagramGraphUpdater:");
+                        System.out.println("-content = " + content);
+                        System.out.println("-previousContent = " + previousContent);
+                    }
 
                     // Find out what has changed since the last query.
                     Object task = Timing.BEGIN("diagramContentDifference");
diff --git a/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/NodeRequest2.java b/bundles/org.simantics.diagram/src/org/simantics/diagram/adapter/NodeRequest2.java
new file mode 100644 (file)
index 0000000..61e8668
--- /dev/null
@@ -0,0 +1,129 @@
+/*******************************************************************************
+ * Copyright (c) 2007, 2010 Association for Decentralized Information Management
+ * in Industry THTH ry.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ *     VTT Technical Research Centre of Finland - initial API and implementation
+ *******************************************************************************/
+package org.simantics.diagram.adapter;
+
+import java.util.List;
+
+import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.primitiverequest.Adapter;
+import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.procedure.AsyncProcedure;
+import org.simantics.db.procedure.Listener;
+import org.simantics.diagram.synchronization.ErrorHandler;
+import org.simantics.g2d.canvas.ICanvasContext;
+import org.simantics.g2d.diagram.IDiagram;
+import org.simantics.g2d.diagram.handler.SubstituteElementClass;
+import org.simantics.g2d.element.ElementClass;
+import org.simantics.g2d.element.IElement;
+import org.simantics.scl.runtime.tuple.Tuple3;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * @author Antti Villberg
+ */
+public class NodeRequest2 extends BaseRequest2<Resource, Tuple3> {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(NodeRequest2.class);
+
+    final IDiagram diagram;
+
+    public NodeRequest2(ICanvasContext canvas, IDiagram diagram, Resource resource) {
+        super(canvas, resource);
+        this.diagram = diagram;
+    }
+
+    @Override
+    public void perform(AsyncReadGraph graph, final AsyncProcedure<Tuple3> procedure) {
+        // Keep this code from crashing the whole DB client by unexpected
+        // throwing of NPE's somewhere in the following code that leads to
+        // procedure not getting called properly.
+        if (diagram == null) {
+            procedure.exception(graph, new NullPointerException("null diagram specified for resource " + data));
+            return;
+        }
+
+        final ErrorHandler eh = ElementFactoryUtil.getErrorHandler(diagram);
+
+        graph.forHasStatement(data, new AsyncProcedure<Boolean>() {
+
+            @Override
+            public void exception(AsyncReadGraph graph, Throwable throwable) {
+                eh.error("NodeRequest.forHasStatement failed", throwable);
+                procedure.execute(graph, null);
+            }
+
+            @Override
+            public void execute(AsyncReadGraph graph, Boolean result) {
+
+                if(!result) {
+                    procedure.execute(graph, null);
+                    return;
+                }
+
+                graph.asyncRequest(new Adapter<ElementFactory>(data, ElementFactory.class), new TransientCacheAsyncListener<ElementFactory>() {
+
+                    @Override
+                    public void exception(AsyncReadGraph graph, Throwable throwable) {
+                        eh.error("NodeRequest.asyncRequest(Adapter<ElementFactory>) failed", throwable);
+                        procedure.execute(graph, null);
+                    }
+
+                    @Override
+                    public void execute(AsyncReadGraph graph, final ElementFactory factory) {
+
+                        graph.asyncRequest(new GetElementClassRequest(factory, data, canvas, diagram), new TransientCacheAsyncListener<ElementClass>() {
+
+                            @Override
+                            public void exception(AsyncReadGraph graph, Throwable throwable) {
+                                LOGGER.error("Unexpected error in GetElementClassRequest", throwable);
+                                procedure.execute(graph, null);
+                            }
+
+                            @Override
+                            public void execute(AsyncReadGraph graph, ElementClass mutableClazz) {
+                                List<SubstituteElementClass> substitutes = diagram.getDiagramClass().getItemsByClass(SubstituteElementClass.class);
+                                for (SubstituteElementClass subs : substitutes) {
+                                    mutableClazz = subs.substitute(diagram, mutableClazz);
+                                }
+                                final ElementClass clazz = mutableClazz;
+                                graph.asyncRequest(new SpawnRequest(canvas, clazz, data), new TransientCacheAsyncListener<IElement>() {
+
+                                    @Override
+                                    public void exception(AsyncReadGraph graph, Throwable throwable) {
+                                        LOGGER.error("Unexpected error in SpawnRequest", throwable);
+                                        procedure.execute(graph, null);
+                                    }
+
+                                    @Override
+                                    public void execute(AsyncReadGraph graph, IElement element) {
+                                        procedure.execute(graph, new Tuple3(element, clazz, factory));
+                                    }
+
+                                });
+
+                            }
+
+                        });
+
+                    }
+
+                });
+
+            }
+
+        });
+
+    }
+
+}
index af58be479ec1c7bf7ac4687d11ed478e26995155..b039b6293c8b7d7b6406a5d4a30fde6d3c30ff62 100644 (file)
@@ -1120,8 +1120,8 @@ public class SymbolLibraryComposite extends Composite {
             for(int i=0;i<res.length;i++) {
                if(pos > 0) json.append(",");
                Object r = res[i];
-               if(r instanceof IdentifiedObject) {
-                       Object id = ((IdentifiedObject) r).getId();
+               if(r instanceof IIdentifiedObject) {
+                       Object id = ((IIdentifiedObject) r).getId();
                        if(id instanceof IAdaptable) {
                                Object resource = ((IAdaptable) id).getAdapter(Resource.class);
                                if(resource != null) {
index 9a53060bef2c0b246a21e465da1f0e53756d2f17..f057b98b67732aeb22c36b636cb9e99ede1d48c5 100644 (file)
@@ -7,16 +7,19 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
+import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.common.procedure.adapter.TransientCacheAsyncListener;
+import org.simantics.db.common.request.AsyncReadRequest;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.request.VariableRead;
 import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.document.server.JSONObject;
 
 public class DocumentRequest extends VariableRead<List<JSONObject>> {
        
-       public static boolean PROFILE = false;
+       public static boolean PROFILE = true;
        // Thresholds in microseconds
        public static int PROFILE_THRESHOLD_NODEREQUEST = 2000;
        public static int PROFILE_THRESHOLD_VALUEREQUEST = 500;
@@ -35,20 +38,43 @@ public class DocumentRequest extends VariableRead<List<JSONObject>> {
         if(nodes.isEmpty()) {
             return Collections.emptyList();
         }
-        
-        
-        /*TreeMap<String, Variable> nodeMap = new TreeMap<String, Variable>();
-        
-        for (Variable node : nodes) {
-               nodeMap.put(node.getURI(graph), node);
+
+        if(PROFILE) {
+            long dura = System.nanoTime()-s;
+            System.err.println("DocumentRequest1 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
         }
-        System.out.println("*************************************************************************");
-        for (Variable node : nodeMap.values()) {
-               System.out.println("               " + node.getURI(graph));
-        }*/
-        
-        for(Variable node : nodes) {
-            rs.add(graph.syncRequest(new NodeRequest(node), TransientCacheAsyncListener.<JSONObject>instance()));
+
+        graph.syncRequest(new AsyncReadRequest() {
+
+            @Override
+            public void run(AsyncReadGraph graph) throws DatabaseException {
+
+                for(Variable node : nodes) {
+                    graph.asyncRequest(new NodeRequest(node), new AsyncProcedure<JSONObject> () {
+
+                        @Override
+                        public void execute(AsyncReadGraph graph, JSONObject result) {
+                            synchronized (rs) {
+                                rs.add(result);
+                            }
+                        }
+
+                        @Override
+                        public void exception(AsyncReadGraph graph, Throwable throwable) {
+                        }
+
+                    });
+                    
+                }
+                
+            }
+            
+        });
+
+
+        if(PROFILE) {
+            long dura = System.nanoTime()-s;
+            System.err.println("DocumentRequest2 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
         }
 
                ArrayList<JSONObject> result = new ArrayList<JSONObject>(rs);
@@ -63,7 +89,7 @@ public class DocumentRequest extends VariableRead<List<JSONObject>> {
         
         if(PROFILE) {
                long dura = System.nanoTime()-s;
-               System.err.println("DocumentRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
+               System.err.println("DocumentRequest3 " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
         }
 
                return result;
index 8d96c4798cb59e0947bda57879f9019915afae39..82b190544ef43e7da9bd8ebb12dd0f79f6128d38 100644 (file)
@@ -5,6 +5,8 @@ import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.request.VariableRead;
 import org.simantics.db.layer0.variable.Variable;
 import org.simantics.document.server.DocumentServerUtils.AttributesRequest;
+import org.simantics.utils.threads.logger.ITask;
+import org.simantics.utils.threads.logger.ThreadLogger;
 import org.simantics.document.server.JSONObject;
 
 public class NodeRequest extends VariableRead<JSONObject> {
@@ -18,17 +20,13 @@ public class NodeRequest extends VariableRead<JSONObject> {
 
     @Override
     public JSONObject perform(ReadGraph graph) throws DatabaseException {
-        long s = DocumentRequest.PROFILE ? System.nanoTime() : 0L;
 
-        JSONObject staticContent = graph.syncRequest(new AttributesRequest(variable));
+        ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null;
 
-        if (DocumentRequest.PROFILE) {
-            long dura = System.nanoTime()-s;
-            if (dura > DocumentRequest.PROFILE_THRESHOLD_NODEREQUEST * 1e3) {
-                System.err.println("NodeRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
-            }
-        }
+        JSONObject staticContent = graph.syncRequest(new AttributesRequest(variable));
 
+        if(DocumentRequest.PROFILE) task.finish();
+        
         return staticContent;
     }
 
index f3f1177fc4d1f613950bc7b4f7d56e2ec010105f..99526368e8cc3e21e1b92451f4dd915db45d40ba 100644 (file)
@@ -1,47 +1,72 @@
 package org.simantics.document.server.request;
 
-import gnu.trove.set.hash.THashSet;
-
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 
+import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.ReadGraph;
+import org.simantics.db.common.request.AsyncReadRequest;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.request.VariableChildren;
 import org.simantics.db.layer0.request.VariableRead;
 import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.structural.stubs.StructuralResource2;
+import org.simantics.utils.threads.logger.ITask;
+import org.simantics.utils.threads.logger.ThreadLogger;
+
+import gnu.trove.set.hash.THashSet;
 
 public class NodesRequest extends VariableRead<Set<Variable>> {
 
     public NodesRequest(Variable var) {
         super(var);
-       }
-
-       @Override
-       public Set<Variable> perform(ReadGraph graph) throws DatabaseException {
-
-               long s = System.nanoTime();
-               
-               StructuralResource2.getInstance(graph);
-               if(variable == null)
-                       return Collections.emptySet();
-               
-               Set<Variable> nodes = new THashSet<Variable>();
-               Collection<Variable> children = graph.syncRequest(new VariableChildren(variable));
-               for(Variable child : children) {
-                       Set<Variable> childNodes = graph.syncRequest(new NodesRequest2(child));
-                       nodes.addAll(childNodes);
-               }
-               
-        if(DocumentRequest.PROFILE) {
-               long dura = System.nanoTime()-s;
-               System.err.println("NodesRequest " + System.identityHashCode(this) + " in " + 1e-6*dura + "ms. " + variable.getURI(graph));
-        }
-               
-               return nodes;
-
-       }
+    }
+
+    @Override
+    public Set<Variable> perform(ReadGraph graph) throws DatabaseException {
+
+        ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null;
+
+        StructuralResource2.getInstance(graph);
+        if(variable == null)
+            return Collections.emptySet();
+
+        Set<Variable> nodes = new THashSet<Variable>();
+
+        Collection<Variable> children = graph.syncRequest(new VariableChildren(variable));
+
+        graph.syncRequest(new AsyncReadRequest() {
+
+            @Override
+            public void run(AsyncReadGraph graph) throws DatabaseException {
+
+                for(Variable child : children) {
+                    graph.asyncRequest(new NodesRequest2(child), new AsyncProcedure<Set<Variable>>() {
+
+                        @Override
+                        public void execute(AsyncReadGraph graph, Set<Variable> result) {
+                            synchronized(nodes) {
+                                nodes.addAll(result);
+                            }
+                        }
+
+                        @Override
+                        public void exception(AsyncReadGraph graph, Throwable throwable) {
+                        }
+                        
+                    });
+                }
+
+            }
+
+        });
+
+        if(DocumentRequest.PROFILE) task.finish();
+
+        return nodes;
+
+    }
 
 }
\ No newline at end of file
index 0f57a01c03f2cfc87ff34c9f3a1339fa9dbe9d52..6251fb6ec8d283ace11c7cd5592e40907efded21 100644 (file)
@@ -2,48 +2,91 @@ package org.simantics.document.server.request;
 
 import gnu.trove.set.hash.THashSet;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
 
 import org.simantics.databoard.Bindings;
+import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
+import org.simantics.db.common.request.AsyncReadRequest;
 import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.request.VariableChildren;
 import org.simantics.db.layer0.request.VariableRead;
 import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.document.base.ontology.DocumentationResource;
+import org.simantics.utils.threads.logger.ITask;
+import org.simantics.utils.threads.logger.ThreadLogger;
 
 public class NodesRequest2 extends VariableRead<Set<Variable>> {
 
     public NodesRequest2(Variable var) {
         super(var);
-       }
-
-       @Override
-       public Set<Variable> perform(ReadGraph graph) throws DatabaseException {
-           
-               DocumentationResource DOC = DocumentationResource.getInstance(graph);
-
-               Resource type = variable.getPossibleType(graph);
-               if(type == null) return Collections.emptySet();
-               
-               if(!graph.isInheritedFrom(type, DOC.Components_Component)) return Collections.emptySet();
-
-               Boolean pathExists = variable.getPossiblePropertyValue(graph, DOC.Properties_pathExists, Bindings.BOOLEAN);
-               if(pathExists != null && !pathExists) return Collections.emptySet();
-
-               if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) {
-                       return Collections.singleton(variable);
-               } else {
-                       Set<Variable> result = new THashSet<Variable>();
-                       for(Variable child : variable.getChildren(graph)) {
-                               Set<Variable> nodes = graph.syncRequest(new NodesRequest2(child));
-                               result.addAll(nodes);
-                       }
-               
-                       return result;
-               }
-
-       }
+    }
+
+    @Override
+    public Set<Variable> perform(ReadGraph graph) throws DatabaseException {
+
+        ITask task = DocumentRequest.PROFILE ? ThreadLogger.task(this) : null;
+
+        DocumentationResource DOC = DocumentationResource.getInstance(graph);
+
+        Resource type = variable.getPossibleType(graph);
+        if(type == null) {
+            if(DocumentRequest.PROFILE) task.finish();
+            return Collections.emptySet();
+        }
+
+        if(!graph.isInheritedFrom(type, DOC.Components_Component)) {
+            if(DocumentRequest.PROFILE) task.finish();
+            return Collections.emptySet();
+        }
+
+        Boolean pathExists = variable.getPossiblePropertyValue(graph, DOC.Properties_pathExists, Bindings.BOOLEAN);
+        if(pathExists != null && !pathExists) {
+            if(DocumentRequest.PROFILE) task.finish();
+            return Collections.emptySet();
+        }
+
+        if(graph.isInheritedFrom(type, DOC.Components_PrimitiveComponent)) {
+            if(DocumentRequest.PROFILE) task.finish();
+            return Collections.singleton(variable);
+        } else {
+            Set<Variable> result = new THashSet<Variable>();
+            Collection<Variable> children = graph.syncRequest(new VariableChildren(variable));
+            graph.syncRequest(new AsyncReadRequest() {
+
+                @Override
+                public void run(AsyncReadGraph graph) throws DatabaseException {
+
+                    for(Variable child : children) {
+                        graph.asyncRequest(new NodesRequest2(child), new AsyncProcedure<Set<Variable>>() {
+
+                            @Override
+                            public void execute(AsyncReadGraph graph, Set<Variable> vars) {
+                                synchronized(result) {
+                                    result.addAll(vars);
+                                }
+                            }
+
+                            @Override
+                            public void exception(AsyncReadGraph graph, Throwable throwable) {
+                            }
+                            
+                        });
+                    }
+
+                }
+
+            });
+            
+            if(DocumentRequest.PROFILE) task.finish();
+            return result;
+            
+        }
+
+    }
 
 }
\ No newline at end of file
index 8ca55eaa5ab67affe0460dcd7ff0c2ff4a81d277..e117dd004070f8ec983f2e5478504d7d494129c5 100644 (file)
@@ -1,5 +1,6 @@
 package org.simantics.document.server.request;
 
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
@@ -9,15 +10,11 @@ import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
 import org.simantics.db.common.procedure.adapter.TransientCacheListener;
 import org.simantics.db.common.request.IndexRoot;
-import org.simantics.db.common.request.PossibleTypedParent;
 import org.simantics.db.common.request.UnaryRead;
 import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.layer0.scl.AbstractExpressionCompilationContext;
-import org.simantics.db.layer0.scl.AbstractExpressionCompilationRequest;
 import org.simantics.db.layer0.util.RuntimeEnvironmentRequest2;
 import org.simantics.db.layer0.variable.Variable;
-import org.simantics.document.base.ontology.DocumentationResource;
-import org.simantics.document.server.request.ServerSCLHandlerValueRequest.CompilationContext;
 import org.simantics.layer0.Layer0;
 import org.simantics.scl.compiler.elaboration.expressions.EApply;
 import org.simantics.scl.compiler.elaboration.expressions.EConstant;
@@ -30,147 +27,156 @@ import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
 import org.simantics.scl.compiler.types.TCon;
 import org.simantics.scl.compiler.types.Type;
 import org.simantics.scl.compiler.types.Types;
+import org.simantics.scl.compiler.types.exceptions.MatchException;
 import org.simantics.scl.compiler.types.kinds.Kinds;
+import org.simantics.scl.compiler.types.util.MultiFunction;
 import org.simantics.scl.runtime.SCLContext;
 import org.simantics.scl.runtime.function.Function1;
+import org.simantics.scl.runtime.function.FunctionImpl1;
 import org.simantics.structural2.scl.ComponentTypeProperty;
 import org.simantics.structural2.scl.FindPossibleComponentTypeRequest;
 import org.simantics.structural2.scl.ReadComponentTypeInterfaceRequest;
 import org.simantics.utils.datastructures.Pair;
 
-public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationRequest<CompilationContext, Object> {
-
-       private final Pair<Resource,Resource> componentTypeAndRoot;
-       private final Resource literal;
-       protected String possibleExpectedValueType;
-
-       public static class CompilationContext extends AbstractExpressionCompilationContext {
-               public final Map<String, ComponentTypeProperty> propertyMap;
-
-               public CompilationContext(RuntimeEnvironment runtimeEnvironment,
-                               Map<String, ComponentTypeProperty> propertyMap) {
-                       super(runtimeEnvironment);
-                       this.propertyMap = propertyMap;
-               }
-       }
-
-       private ServerSCLHandlerValueRequest(Pair<Resource,Resource> componentTypeAndRoot, Resource literal, String possibleExpectedValueType) {
-               assert(literal != null);
-               this.literal = literal;
-               this.componentTypeAndRoot = componentTypeAndRoot;
-               this.possibleExpectedValueType = possibleExpectedValueType;
-       }
-
-       public ServerSCLHandlerValueRequest(ReadGraph graph, Variable context) throws DatabaseException {
-               this(getComponentTypeAndRoot(graph, context), context.getRepresents(graph), resolveExpectedValueType(graph, context.getPredicateResource(graph)));
-       }
-
-       public ServerSCLHandlerValueRequest(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException {
-               this(getComponentTypeAndRoot(graph, s, o), o, resolveExpectedValueType(graph, p));
-       }
-
-       private static Pair<Resource,Resource> getComponentTypeAndRoot(ReadGraph graph, Variable property)  throws DatabaseException {
-               Variable parent = property.getParent(graph);
-               Resource represents = parent.getRepresents(graph);
-               if(represents != null) {
-                       Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(represents));
-                       if(type != null) {
-                               Resource root = graph.syncRequest(new IndexRoot(type));
-                               return Pair.make(type, root);
-                       }
-               }
-               parent = parent.getParent(graph);
-               Resource root = graph.syncRequest(new IndexRoot(property.getRepresents(graph)));
-               return Pair.make(parent.getType(graph), root);
-       }
-
-       private static Pair<Resource,Resource> getComponentTypeAndRoot(ReadGraph graph, Resource component, Resource literal)  throws DatabaseException {
-               if(component != null) {
-                       Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(component));
-                       if(type != null) {
-                               Resource root = graph.syncRequest(new IndexRoot(type));
-                               return Pair.make(type, root);
-                       } else {
-                               Resource doc = graph.syncRequest(new PossibleTypedParent(component, DocumentationResource.getInstance(graph).Document));
-                               Resource componentType = graph.getSingleType(doc); 
-                               Resource root = graph.syncRequest(new IndexRoot(doc));
-                               return Pair.make(componentType, root);
-                       }
-                       // TODO: For Antti to consider and fix later
-                       // Introduced to handle procedural user components where component == null
-               } else if (literal != null) {
-                   Resource root = graph.syncRequest(new IndexRoot(literal));
-                   return Pair.make(null, root);
-               } else {
-                   throw new DatabaseException("Couldn't resolve component type and root for component == null && literal == null");
-               }
-               //throw new IllegalStateException();
-       }
+public class ServerSCLHandlerValueRequest extends ServerSCLValueRequestBase<org.simantics.document.server.request.ServerSCLHandlerValueRequest.CompilationContext> {
+
+    private final Pair<Resource,Resource> componentTypeAndRoot;
+    private final Resource literal;
+    protected String possibleExpectedValueType;
+
+    public static class CompilationContext extends AbstractExpressionCompilationContext {
+        public final Map<String, ComponentTypeProperty> propertyMap;
+
+        public CompilationContext(RuntimeEnvironment runtimeEnvironment,
+                Map<String, ComponentTypeProperty> propertyMap) {
+            super(runtimeEnvironment);
+            this.propertyMap = propertyMap;
+        }
+    }
+
+    private ServerSCLHandlerValueRequest(Pair<Resource,Resource> componentTypeAndRoot, Resource literal, String possibleExpectedValueType) {
+        assert(literal != null);
+        this.literal = literal;
+        this.componentTypeAndRoot = componentTypeAndRoot;
+        this.possibleExpectedValueType = possibleExpectedValueType;
+    }
+
+    public ServerSCLHandlerValueRequest(ReadGraph graph, Variable context) throws DatabaseException {
+        this(getComponentTypeAndRoot(graph, context), context.getRepresents(graph), resolveExpectedValueType(graph, context.getPredicateResource(graph)));
+    }
+
+    public ServerSCLHandlerValueRequest(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException {
+        this(getComponentTypeAndRoot(graph, s, o), o, resolveExpectedValueType(graph, p));
+    }
+
+    private static Pair<Resource,Resource> getComponentTypeAndRoot(ReadGraph graph, Variable property)  throws DatabaseException {
+        Variable parent = property.getParent(graph);
+        Resource represents = parent.getRepresents(graph);
+        if(represents != null) {
+            Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(represents));
+            if(type != null) {
+                Resource root = graph.syncRequest(new IndexRoot(type));
+                return Pair.make(type, root);
+            }
+        }
+        parent = parent.getParent(graph);
+        Resource root = graph.syncRequest(new IndexRoot(property.getRepresents(graph)));
+        return Pair.make(parent.getType(graph), root);
+    }
+
 
     public static List<TCon> getEffects(ReadGraph graph, Variable context) throws DatabaseException {
+        HandlerFn fn = (HandlerFn)compile(graph, context);
+        return fn.effects;
+    }
+
+    public static Object compileAndEvaluate(ReadGraph graph, Variable context) throws DatabaseException {
+        SCLContext sclContext = SCLContext.getCurrent();
+        Object oldGraph = sclContext.get("graph");
         try {
-               ServerSCLHandlerValueRequest req = new ServerSCLHandlerValueRequest(graph, context);
-               return req.getExpressionEffects(graph);
+            Function1<Object,Object> exp = graph.syncRequest(new ServerSCLHandlerValueRequest(graph, context),
+                    TransientCacheListener.instance());
+            sclContext.put("graph", graph);
+            return exp.apply(context);
         } catch (DatabaseException e) {
             throw (DatabaseException)e;
         } catch (Throwable t) {
             throw new DatabaseException(t);
+        } finally {
+            sclContext.put("graph", oldGraph);
         }
     }
 
-       public static Object compileAndEvaluate(ReadGraph graph, Variable context) throws DatabaseException {
-               SCLContext sclContext = SCLContext.getCurrent();
-        Object oldGraph = sclContext.get("graph");
-               try {
-                       Function1<Object,Object> exp = graph.syncRequest(new ServerSCLHandlerValueRequest(graph, context),
-                                       TransientCacheListener.instance());
-                       sclContext.put("graph", graph);
-                       return exp.apply(context);
-               } catch (DatabaseException e) {
-                       throw (DatabaseException)e;
-               } catch (Throwable t) {
-                       throw new DatabaseException(t);
-               } finally {
-            sclContext.put("graph", oldGraph);
-               }
-       }
-
-       public static Function1<Object, Object> compile(ReadGraph graph, Variable context) throws DatabaseException {
-               return graph.syncRequest(new ServerSCLHandlerValueRequest(graph, context), TransientCacheListener.instance());
-       }
-
-       public static Function1<Object, Object> compile(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException {
-               return graph.syncRequest(new ServerSCLHandlerValueRequest(graph, s, o, p), TransientCacheListener.<Function1<Object,Object>>instance());
-       }
-
-       @Override
-       protected String getExpressionText(ReadGraph graph)
-                       throws DatabaseException {
-               Layer0 L0 = Layer0.getInstance(graph);
-               String exp = graph.getRelatedValue(literal, L0.SCLValue_expression, Bindings.STRING);
-               return "\\context -> " + exp;
-       }
-
-       protected RuntimeEnvironmentRequest2 getRuntimeEnvironmentRequest(Resource componentType, Resource indexRoot) {
-               return new RuntimeEnvironmentRequest2(componentType, indexRoot) {
-                       @Override
-                       protected void fillEnvironmentSpecification(
-                                       EnvironmentSpecification environmentSpecification) {
-                       }
-               };
-       }
-
-       @Override
-       protected CompilationContext getCompilationContext(ReadGraph graph) throws DatabaseException {
-               return graph.syncRequest(new UnaryRead<Pair<Resource,Resource>,CompilationContext>(componentTypeAndRoot) {
-                       @Override
-                       public CompilationContext perform(ReadGraph graph) throws DatabaseException {
-                               RuntimeEnvironment runtimeEnvironment = graph.syncRequest(getRuntimeEnvironmentRequest(parameter.first, parameter.second));
+    public static Function1<Object, Object> compile(ReadGraph graph, Variable context) throws DatabaseException {
+        return graph.syncRequest(new ServerSCLHandlerValueRequest(graph, context), TransientCacheListener.instance());
+    }
+
+    public static Function1<Object, Object> compile(ReadGraph graph, Resource s, Resource o, Resource p) throws DatabaseException {
+        return graph.syncRequest(new ServerSCLHandlerValueRequest(graph, s, o, p), TransientCacheListener.instance());
+    }
+
+    public static class HandlerFn extends FunctionImpl1<Object,Object> {
+
+        Function1<Object,Object> handler;
+        ArrayList<TCon> effects;
+
+        HandlerFn(Function1<Object,Object> handler, Type type) {
+            try {
+                this.handler = handler;
+                this.effects = new ArrayList<TCon>();
+                MultiFunction mfun = Types.matchFunction(type, 1);
+                mfun.effect.collectConcreteEffects(this.effects);
+            } catch(MatchException e) {
+                // Should not happen!
+                throw new RuntimeException(e);
+            }
+        }
+
+        @Override
+        public Object apply(Object p0) {
+            return handler.apply(p0);
+        }
+
+    }
+
+    @Override
+    public Function1<Object, Object> perform(ReadGraph graph) throws DatabaseException {
+
+        CompilationContext context = getCompilationContext(graph);
+        Type expectedType = getExpectedType(graph, context);
+        Function1<Object,Object> handler = eval(prepareEvaluator(graph, context, expectedType), graph);
+        return new HandlerFn(handler, expectedType);
+
+    }
+
+    @Override
+    protected String getExpressionText(ReadGraph graph)
+            throws DatabaseException {
+        Layer0 L0 = Layer0.getInstance(graph);
+        String exp = graph.getRelatedValue(literal, L0.SCLValue_expression, Bindings.STRING);
+        return "\\context -> " + exp;
+    }
+
+    protected RuntimeEnvironmentRequest2 getRuntimeEnvironmentRequest(Resource componentType, Resource indexRoot) {
+        return new RuntimeEnvironmentRequest2(componentType, indexRoot) {
+            @Override
+            protected void fillEnvironmentSpecification(
+                    EnvironmentSpecification environmentSpecification) {
+            }
+        };
+    }
+
+    @Override
+    protected CompilationContext getCompilationContext(ReadGraph graph) throws DatabaseException {
+        return graph.syncRequest(new UnaryRead<Pair<Resource,Resource>,CompilationContext>(componentTypeAndRoot) {
+            @Override
+            public CompilationContext perform(ReadGraph graph) throws DatabaseException {
+                RuntimeEnvironment runtimeEnvironment = graph.syncRequest(getRuntimeEnvironmentRequest(parameter.first, parameter.second));
                 Map<String, ComponentTypeProperty> propertyMap;
                 if (parameter.first != null) {
                     propertyMap =
-                        graph.syncRequest(new ReadComponentTypeInterfaceRequest(parameter.first, runtimeEnvironment.getEnvironment()),
-                                TransientCacheListener.<Map<String, ComponentTypeProperty>>instance());
+                            graph.syncRequest(new ReadComponentTypeInterfaceRequest(parameter.first, runtimeEnvironment.getEnvironment()),
+                                    TransientCacheListener.<Map<String, ComponentTypeProperty>>instance());
                 } else {
                     // TODO: Antti to consider
                     // To handle procedural user components
@@ -179,47 +185,47 @@ public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationR
 //                             Map<String, ComponentTypeProperty> propertyMap =
 //                                             graph.syncRequest(new ReadComponentTypeInterfaceRequest(parameter.first, runtimeEnvironment.getEnvironment()),
 //                                                             TransientCacheListener.<Map<String, ComponentTypeProperty>>instance());
-                               return new CompilationContext(runtimeEnvironment, propertyMap);
-                       }
-               });
-       }
-
-       @Override
-       protected Type getContextVariableType() {
-               return VARIABLE; 
-       }
-
-       private static Expression accessInputVariable(Environment environment,
-                       org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable) {
-               SCLValue variableParentFunction = environment.getValue(VARIABLE_PARENT);
-               return new EApply(new EConstant(variableParentFunction),
-                               new EApply(new EConstant(variableParentFunction),
-                                               new EVariable(contextVariable)));
-       }
-
-       protected static Expression standardGetProperty(
-                       Environment environment,
-                       org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
-                       String name,
-                       Type type) {
-               return getPropertyFlexible(environment, accessInputVariable(environment, contextVariable), name, type);
-       }
-
-       @Override
-       protected Expression getVariableAccessExpression(
-                       ReadGraph graph,
-                       CompilationContext context,
-                       org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
-                       String name) throws DatabaseException {
-               ComponentTypeProperty property = context.propertyMap.get(name);
-               if(property != null)
-                       return standardGetProperty(
-                                       context.runtimeEnvironment.getEnvironment(),
-                                       contextVariable,
-                                       name,
-                                       property.type == null ? Types.metaVar(Kinds.STAR) : property.type);
-               else {
-                       
+                return new CompilationContext(runtimeEnvironment, propertyMap);
+            }
+        });
+    }
+
+    @Override
+    protected Type getContextVariableType() {
+        return VARIABLE; 
+    }
+
+    private static Expression accessInputVariable(Environment environment,
+            org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable) {
+        SCLValue variableParentFunction = environment.getValue(VARIABLE_PARENT);
+        return new EApply(new EConstant(variableParentFunction),
+                new EApply(new EConstant(variableParentFunction),
+                        new EVariable(contextVariable)));
+    }
+
+    protected static Expression standardGetProperty(
+            Environment environment,
+            org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
+            String name,
+            Type type) {
+        return getPropertyFlexible(environment, accessInputVariable(environment, contextVariable), name, type);
+    }
+
+    @Override
+    protected Expression getVariableAccessExpression(
+            ReadGraph graph,
+            CompilationContext context,
+            org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
+            String name) throws DatabaseException {
+        ComponentTypeProperty property = context.propertyMap.get(name);
+        if(property != null)
+            return standardGetProperty(
+                    context.runtimeEnvironment.getEnvironment(),
+                    contextVariable,
+                    name,
+                    property.type == null ? Types.metaVar(Kinds.STAR) : property.type);
+        else {
+
 //                     if(context.propertyMap.containsKey(name)) {
 //                             
 //                             org.simantics.scl.compiler.elaboration.expressions.Variable parametersVariable = new org.simantics.scl.compiler.elaboration.expressions.Variable("context", COMMAND_CONTEXT);
@@ -234,45 +240,45 @@ public class ServerSCLHandlerValueRequest extends AbstractExpressionCompilationR
 //                                     new ELiteral(new StringConstant(name)));
 //                             
 //                     }
-                       
-                       return getSpecialVariableAccessExpression(graph, context, contextVariable, name);
-                       
-               }
-       }
-
-       protected Expression getSpecialVariableAccessExpression(ReadGraph graph,
-                       CompilationContext context,
-                       org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
-                       String name) throws DatabaseException {
-               if(name.equals("input")) {
-                       Environment environment = context.runtimeEnvironment.getEnvironment();
-                       return accessInputVariable(environment, contextVariable);
-               } else if(name.equals("self"))
-                       return new EVariable(contextVariable);
-               else
-                       return null;
-       }
+
+            return getSpecialVariableAccessExpression(graph, context, contextVariable, name);
+
+        }
+    }
+
+    protected Expression getSpecialVariableAccessExpression(ReadGraph graph,
+            CompilationContext context,
+            org.simantics.scl.compiler.elaboration.expressions.Variable contextVariable,
+            String name) throws DatabaseException {
+        if(name.equals("input")) {
+            Environment environment = context.runtimeEnvironment.getEnvironment();
+            return accessInputVariable(environment, contextVariable);
+        } else if(name.equals("self"))
+            return new EVariable(contextVariable);
+        else
+            return null;
+    }
 
     @Override
     protected Type getExpectedType(ReadGraph graph, CompilationContext context) throws DatabaseException {
         return super.getExpectedType(graph, context);
     }
 
-       @Override
-       public int hashCode() {
-               return 31*(31*getClass().hashCode() + literal.hashCode()) + componentTypeAndRoot.hashCode();
-       }
-
-       @Override
-       public boolean equals(Object obj) {
-               if (this == obj)
-                       return true;
-               if (obj == null)
-                       return false;
-               if (getClass() != obj.getClass())
-                       return false;
-               ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest) obj;
-               return literal.equals(other.literal) && componentTypeAndRoot.equals(other.componentTypeAndRoot);
-       }
+    @Override
+    public int hashCode() {
+        return 31*(31*getClass().hashCode() + literal.hashCode()) + componentTypeAndRoot.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ServerSCLHandlerValueRequest other = (ServerSCLHandlerValueRequest) obj;
+        return literal.equals(other.literal) && componentTypeAndRoot.equals(other.componentTypeAndRoot);
+    }
 
 }
index adff8dab5b9ec87d1271e1ca02d1d3bea58e49a3..7f9473861708decb38097a0ee5530657956820a1 100644 (file)
@@ -45,7 +45,7 @@ import org.simantics.utils.datastructures.Pair;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-public class ServerSCLValueRequest extends AbstractExpressionCompilationRequest<CompilationContext, Object> {
+public class ServerSCLValueRequest extends ServerSCLValueRequestBase<org.simantics.document.server.request.ServerSCLValueRequest.CompilationContext> {
 
        private final Pair<Resource,Resource> componentTypeAndRoot;
        private final Resource literal;
@@ -91,39 +91,9 @@ public class ServerSCLValueRequest extends AbstractExpressionCompilationRequest<
                return Pair.make(parent.getType(graph), root);
        }
 
-       private static Pair<Resource,Resource> getComponentTypeAndRoot(ReadGraph graph, Resource component, Resource literal)  throws DatabaseException {
-               if(component != null) {
-                       Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(component));
-                       if(type != null) {
-                               Resource root = graph.syncRequest(new IndexRoot(type));
-                               //      System.err.println("getComponentTypeAndRoot3 " + graph.getPossibleURI(component) + " => " + graph.getPossibleURI(type) + " " + graph.getPossibleURI(root));
-                               return Pair.make(type, root);
-                       } else {
-                               Resource doc = graph.syncRequest(new PossibleTypedParent(component, DocumentationResource.getInstance(graph).Document));
-                               if(doc != null) {
-                                       Resource componentType = graph.getSingleType(doc);
-                                       Resource root = graph.syncRequest(new IndexRoot(doc));
-                                       return Pair.make(componentType, root);
-                               } else {
-                                       //System.err.println("component = " + component);
-                                       Resource root = graph.syncRequest(new IndexRoot(component));
-//                                     Resource componentType = graph.getSingleType(doc);
-                                       return Pair.make(null, root);
-                               }
-                       }
-        // TODO: For Antti to consider and fix later
-        // Introduced to handle procedural user components where component == null
-        } else if (literal != null) {
-            Resource root = graph.syncRequest(new IndexRoot(literal));
-            return Pair.make(null, root);
-        } else {
-            throw new DatabaseException("Couldn't resolve component type and root for component == null && literal == null");
-        }
-       }
-
        public static Object compileAndEvaluate(ReadGraph graph, Variable context) throws DatabaseException {
                SCLContext sclContext = SCLContext.getCurrent();
-        Object oldGraph = sclContext.get("graph");
+               Object oldGraph = sclContext.get("graph");
                try {
                        Function1<Object,Object> exp = compile(graph, context);
                        sclContext.put("graph", graph);
@@ -133,7 +103,7 @@ public class ServerSCLValueRequest extends AbstractExpressionCompilationRequest<
                } catch (Throwable t) {
                        throw new DatabaseException(t);
                } finally {
-            sclContext.put("graph", oldGraph);
+                       sclContext.put("graph", oldGraph);
                }
        }
 
diff --git a/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLValueRequestBase.java b/bundles/org.simantics.document.server/src/org/simantics/document/server/request/ServerSCLValueRequestBase.java
new file mode 100644 (file)
index 0000000..ab23e2a
--- /dev/null
@@ -0,0 +1,43 @@
+package org.simantics.document.server.request;
+
+import org.simantics.db.ReadGraph;
+import org.simantics.db.Resource;
+import org.simantics.db.common.request.IndexRoot;
+import org.simantics.db.common.request.PossibleTypedParent;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.layer0.scl.AbstractExpressionCompilationContext;
+import org.simantics.db.layer0.scl.AbstractExpressionCompilationRequest;
+import org.simantics.document.base.ontology.DocumentationResource;
+import org.simantics.structural2.scl.FindPossibleComponentTypeRequest;
+import org.simantics.utils.datastructures.Pair;
+
+abstract public class ServerSCLValueRequestBase<ASD extends AbstractExpressionCompilationContext> extends AbstractExpressionCompilationRequest<ASD, Object> {
+
+    static Pair<Resource,Resource> getComponentTypeAndRoot(ReadGraph graph, Resource component, Resource literal)  throws DatabaseException {
+        if(component != null) {
+            Resource type = graph.syncRequest(new FindPossibleComponentTypeRequest(component));
+            if(type != null) {
+                Resource root = graph.syncRequest(new IndexRoot(type));
+                return Pair.make(type, root);
+            } else {
+                Resource doc = graph.syncRequest(new PossibleTypedParent(component, DocumentationResource.getInstance(graph).Document));
+                if(doc != null) {
+                    Resource componentType = graph.getSingleType(doc);
+                    Resource root = graph.syncRequest(new IndexRoot(doc));
+                    return Pair.make(componentType, root);
+                } else {
+                    Resource root = graph.syncRequest(new IndexRoot(component));
+                    return Pair.make(null, root);
+                }
+            }
+            // TODO: For Antti to consider and fix later
+            // Introduced to handle procedural user components where component == null
+        } else if (literal != null) {
+            Resource root = graph.syncRequest(new IndexRoot(literal));
+            return Pair.make(null, root);
+        } else {
+            throw new DatabaseException("Couldn't resolve component type and root for component == null && literal == null");
+        }
+    }
+
+}
index 1103b5f262af788774072ef3d400ada1800fea51..80f22b7852e85f1ad968f10aec0ebc1666b51cc6 100644 (file)
  *******************************************************************************/
 package org.simantics.issues.common;
 
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 
 import org.simantics.db.AsyncReadGraph;
 import org.simantics.db.Resource;
 import org.simantics.db.common.request.TernaryAsyncRead;
-import org.simantics.db.procedure.AsyncMultiProcedure;
+import org.simantics.db.exception.DatabaseException;
 import org.simantics.db.procedure.AsyncProcedure;
 import org.simantics.issues.Severity;
 
 /**
  * @author Tuukka Lehtonen
  */
-public class ChildMaxIssueSeverity extends TernaryAsyncRead<Resource, Resource, Set<Resource>, Severity>{
+public class ChildMaxIssueSeverity extends TernaryAsyncRead<Resource, Resource, Set<Resource>, Severity> {
 
+    static class AsyncReadResult<T> {
+        private AtomicReference<T> resultRef;
+        private Throwable throwable;
+        private AtomicInteger counter = new AtomicInteger(1);
+        private AsyncProcedure<T> procedure;
+        AsyncReadResult(AsyncProcedure<T> procedure, AtomicReference<T> resultRef) {
+            this.procedure = procedure;
+            this.resultRef = resultRef;
+        }
+        void except(AsyncReadGraph graph, Throwable throwable) {
+            this.throwable = throwable;
+            dec(graph);
+        }
+        void set(AsyncReadGraph graph, T result) {
+            resultRef.set(result);
+            dec(graph);
+        }
+        void inc() {
+            counter.incrementAndGet();
+        }
+        void dec(AsyncReadGraph graph) {
+            if(counter.decrementAndGet() == 0) {
+                if(throwable != null)
+                    procedure.exception(graph, throwable);
+                else
+                    procedure.execute(graph, resultRef.get());
+            }
+        }
+        
+    }
+    
     public ChildMaxIssueSeverity(Resource resource, Resource childRelation, Set<Resource> typesToRecurse) {
         super(resource, childRelation, typesToRecurse);
     }
 
-//    @Override
-//    public Severity perform(ReadGraph graph) throws DatabaseException {
-//        Severity maxSeverity = null;
-//        //System.out.println("severityForChildren: " + NameUtils.getSafeName(graph, resource));
-//        for (Resource child : graph.getObjects(resource, resource2)) {
-//            Severity s = graph.syncRequest(new MaxIssueSeverityRecursive(child));
-//            maxSeverity = Severity.moreSevere(maxSeverity, s);
-//        }
-//        //System.out.println("severityForChildren: " + NameUtils.getSafeName(graph, resource) + " : " + maxSeverity);
-//        return maxSeverity;
-//    }
-
     @Override
     public void perform(AsyncReadGraph graph, final AsyncProcedure<Severity> procedure) {
-        //System.out.println(getClass().getSimpleName() + ": " + parameter);
         
-        graph.forTypes(parameter, new AsyncProcedure<Set<Resource>>() {
-            @Override
-            public void execute(AsyncReadGraph graph, Set<Resource> result) {
-                if (!Collections.disjoint(parameter3, result)) {
-                    checkChildren(graph, procedure);
-                } else {
-                    procedure.execute(graph, null);
-                }
-            }
-            @Override
-            public void exception(AsyncReadGraph graph, Throwable throwable) {
-                procedure.exception(graph, throwable);
+        try {
+            Set<Resource> types = graph.getTypes(parameter);
+            if (!Collections.disjoint(parameter3, types)) {
+                checkChildren(graph, procedure);
+            } else {
+                procedure.execute(graph, null);
             }
-        });
+        } catch (DatabaseException e) {
+            procedure.exception(graph, e);
+        }
+        
     }
 
     protected void checkChildren(AsyncReadGraph graph, final AsyncProcedure<Severity> procedure) {
-        graph.forEachObject(parameter, parameter2, new AsyncMultiProcedure<Resource>() {
-            AtomicReference<Severity> maxSeverity = new AtomicReference<Severity>();
-            @Override
-            public void execute(AsyncReadGraph graph, Resource child) {
+        
+        AsyncReadResult<Severity> maxSeverity = new AsyncReadResult<Severity>(procedure, new AtomicReference<Severity>());
+        
+        try {
+            Collection<Resource> children = graph.getObjects(parameter, parameter2);
+            for(Resource child : children) {
+                maxSeverity.inc();
                 graph.asyncRequest(new MaxIssueSeverityRecursive(child, parameter2, parameter3), new AsyncProcedure<Severity>() {
                     @Override
                     public void execute(AsyncReadGraph graph, Severity severity) {
                         if (severity != null) {
                             synchronized (maxSeverity) {
-                                maxSeverity.set(Severity.moreSevere(maxSeverity.get(), severity));
+                                maxSeverity.set(graph, Severity.moreSevere(maxSeverity.resultRef.get(), severity));
                             }
+                        } else {
+                            maxSeverity.dec(graph);
                         }
                     }
                     @Override
                     public void exception(AsyncReadGraph graph, Throwable throwable) {
-                        procedure.exception(graph, throwable);
+                        maxSeverity.except(graph, throwable);
                     }
                 });
             }
-            @Override
-            public void finished(AsyncReadGraph graph) {
-                procedure.execute(graph, maxSeverity.get());
-            }
-            @Override
-            public void exception(AsyncReadGraph graph, Throwable throwable) {
-                procedure.exception(graph, throwable);
-            }
-        });
+            maxSeverity.dec(graph);
+        } catch (DatabaseException e) {
+            maxSeverity.except(graph, e);
+            return;
+        }
+        
     }
 
 }
index 7646271e3d91443564d9d51fd47af401d2b9ca68..ed3d6c2b97f66c97d7e40a050c0699e9152b2f84 100644 (file)
  *******************************************************************************/
 package org.simantics.issues.common;
 
+import java.util.Collection;
 import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
 
-import org.simantics.db.AsyncReadGraph;
+import org.simantics.db.ReadGraph;
 import org.simantics.db.Resource;
-import org.simantics.db.common.request.TernaryAsyncRead;
-import org.simantics.db.procedure.AsyncMultiProcedure;
-import org.simantics.db.procedure.AsyncProcedure;
+import org.simantics.db.common.request.TernaryRead;
+import org.simantics.db.exception.DatabaseException;
 import org.simantics.issues.Severity;
 import org.simantics.issues.ontology.IssueResource;
 
 /**
  * @author Tuukka Lehtonen
  */
-public class MaxIssueSeverityRecursive extends TernaryAsyncRead<Resource, Resource, Set<Resource>, Severity> {
+public class MaxIssueSeverityRecursive extends TernaryRead<Resource, Resource, Set<Resource>, Severity> {
 
     public MaxIssueSeverityRecursive(Resource resource, Resource childRelation, Set<Resource> typesToRecurse) {
         super(resource, childRelation, typesToRecurse);
     }
     
     @Override
-    public void perform(AsyncReadGraph graph, final AsyncProcedure<Severity> procedure) {
+    public Severity perform(ReadGraph graph) throws DatabaseException {
 
         IssueResource ISSUE = graph.getService(IssueResource.class);
 
-        AtomicInteger issues = new AtomicInteger();
-        AtomicBoolean excepted = new AtomicBoolean(false);
-
-        graph.forEachObject(parameter, ISSUE.Issue_HasContext_Inverse, new AsyncMultiProcedure<Resource>() {
-            @Override
-            public void execute(AsyncReadGraph graph, Resource result) {
-                issues.incrementAndGet();
-            }
-            @Override
-            public void finished(AsyncReadGraph graph) {
-            
-            }
-            @Override
-            public void exception(AsyncReadGraph graph, Throwable throwable) {
-                if(excepted.compareAndSet(false, true))
-                    procedure.exception(graph, throwable);
-            }
-        });
-
-        graph.forEachObject(parameter, ISSUE.Issue_ContextList_Element_Inverse, new AsyncMultiProcedure<Resource>() {
-            @Override
-            public void execute(AsyncReadGraph graph, Resource result) {
-                issues.incrementAndGet();
-            }
-            @Override
-            public void finished(AsyncReadGraph graph) {
-            
-            }
-            @Override
-            public void exception(AsyncReadGraph graph, Throwable throwable) {
-                if(excepted.compareAndSet(false, true))
-                  procedure.exception(graph, throwable);
-            }
-        });
-        
-        if(excepted.get()) return;
-
-        if (issues.get() == 0) {
-            // This content does not have directly attached issues, try to look
-            // for some in the child components.
-            graph.asyncRequest(new ChildMaxIssueSeverity(parameter, parameter2, parameter3), procedure);
-        } else {
-            // Try local issues first
-            graph.asyncRequest(new MaxIssueSeveritySingle(parameter), new AsyncProcedure<Severity>() {
-                @Override
-                public void execute(AsyncReadGraph graph, Severity maxSeverity) {
-                    if (maxSeverity == null)
-                        // No severity for local issues, try children next.
-                        graph.asyncRequest(new ChildMaxIssueSeverity(parameter, parameter2, parameter3), procedure);
-                    else
-                        procedure.execute(graph, maxSeverity);
-                }
-                @Override
-                public void exception(AsyncReadGraph graph, Throwable throwable) {
-                    if(excepted.compareAndSet(false, true))
-                      procedure.exception(graph, throwable);
-                }
-            });
+        Collection<Resource> inv = graph.getObjects(parameter, ISSUE.Issue_HasContext_Inverse);
+        Collection<Resource> inv2 = graph.getObjects(parameter, ISSUE.Issue_ContextList_Element_Inverse);
+        if(inv.isEmpty() && inv2.isEmpty()) {
+            return graph.syncRequest(new ChildMaxIssueSeverity(parameter, parameter2, parameter3));
         }
+        
+        Severity max = graph.syncRequest(new MaxIssueSeveritySingle(parameter));
+        if(max != null)
+            return max;
+        else
+            return graph.syncRequest(new ChildMaxIssueSeverity(parameter, parameter2, parameter3));
+            
     }
 
 }
index c7a2b6385a276e20e1aecd90ea876e5af243ee41..75d3050b9cd91689c5d136ed82868bd20808fd5f 100644 (file)
@@ -209,7 +209,7 @@ public class MonitorClassFactory2 extends SyncElementFactory {
                 });
             }
 
-            IElement mappedElement = diagram.getDiagramClass().getSingleItem(DataElementMap.class).getElement(diagram, element);
+            IElement mappedElement = e;//diagram.getDiagramClass().getSingleItem(DataElementMap.class).getElement(diagram, element);
             MonitorListener monitorListener = new MonitorListener(element, canvas, diagram, substitutions);
             if (mappedElement != null) {
                 MonitorListener oldListener = mappedElement.getHint(KEY_VARIABLE_LISTENER);
index af59dbfc164bdd60a859011597bd334a7b406e49..a783acbad6e421fbc0f7e272f2a35e1ccafe7590 100644 (file)
@@ -478,8 +478,19 @@ public class PlatformUtil {
        }
 
        private static boolean isImmutable(Bundle bundle) {
-               String immutable = (String) bundle.getHeaders().get("Immutable");
-               return immutable != null ? "true".equals(immutable) : true;
+        String immutable = (String) bundle.getHeaders().get("Immutable");
+        if(immutable == null)
+            return true;
+        if("false".equals(immutable))
+            return false;
+        if("trueWhenDeployed".equals(immutable)) {
+            String installHint = System.getProperty("installOntologiesAsDeployed");
+            if("true".equals(installHint))
+                return true;
+            else
+                return false;
+        }
+        return true;
        }
 
        public static class TGInfo {
index 31ef0dc5a0cb9863874d042858aec59d451adadd..23704156cbbaa73bec8b83c99bbabfaf0f382e16 100644 (file)
@@ -357,4 +357,9 @@ public class ConcreteModule implements Module {
     public ModuleDebugInfo getModuleDebugInfo() {
         return moduleDebugInfo;
     }
+    
+    public Map<String, byte[]> getClasses() {
+        return classes;
+    }
+    
 }
index a6650e9a44faa5627b41b0cf260ee6ecf6baaadb..78dfa8f886b3de9ed68648b7dbced730392a108a 100644 (file)
@@ -3,7 +3,9 @@ package org.simantics.scl.compiler.module.repository;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
 import org.simantics.scl.compiler.common.exceptions.InternalCompilerError;
@@ -52,6 +54,7 @@ public class ModuleRepository {
     private final ModuleRepository parentRepository;
     private final ModuleSourceRepository sourceRepository;
     private ConcurrentHashMap<String, ModuleEntry> moduleCache = new ConcurrentHashMap<String, ModuleEntry>();
+    public Set<RuntimeEnvironment> runtimeEnvironments = new HashSet<RuntimeEnvironment>();
     
     private static final ThreadLocal<THashSet<String>> PENDING_MODULES = new ThreadLocal<THashSet<String>>();
     
@@ -395,7 +398,9 @@ public class ModuleRepository {
         THashMap<String, Module> moduleMap = mapEntriesToModules(entries);
         Environment environment = createEnvironment(moduleMap, imports);
         THashMap<String, RuntimeModule> runtimeModuleMap = mapEntriesToRuntimeModules(entries);
-        return new RuntimeEnvironmentImpl(environment, parentClassLoader, runtimeModuleMap);
+        RuntimeEnvironmentImpl result = new RuntimeEnvironmentImpl(environment, parentClassLoader, runtimeModuleMap);
+        runtimeEnvironments.add(result);
+        return result;
     }
     
     private static Environment createEnvironment(
@@ -530,6 +535,10 @@ public class ModuleRepository {
     public void setAdvisor(ModuleCompilationOptionsAdvisor advisor) {
         this.advisor = advisor;
     }
+    
+    public Set<RuntimeEnvironment> getRuntimeEnvironments() {
+        return runtimeEnvironments;
+    }
 
 }
  
\ No newline at end of file
index 45e3027207f86ab6be25dff2863a20d6c6bbd42a..dbfafe19bc325fdf41852a04663db13f1053189f 100644 (file)
@@ -11,7 +11,7 @@ public class ExpressionClassLoader extends ClassLoader implements MutableClassLo
     public static final boolean TRACE_CLASS_CREATION = false;
     
     String basePackageName;
-    THashMap<String, byte[]> localClasses = new THashMap<String, byte[]>(); 
+    public THashMap<String, byte[]> localClasses = new THashMap<String, byte[]>(); 
     THashMap<String, RuntimeModule> runtimeModuleMap;
     int transientPackageId = 0;
     THashMap<Constant,Object> valueCache = new THashMap<Constant,Object>(); 
@@ -57,7 +57,11 @@ public class ExpressionClassLoader extends ClassLoader implements MutableClassLo
         if(bytes == null)
             throw new ClassNotFoundException(name);
 
-        return defineClass(name, bytes, 0, bytes.length);
+        clazz = defineClass(name, bytes, 0, bytes.length);
+        resolveClass(clazz);
+        
+        return clazz;
+        
     }
     
     @Override
index 5ae73c41240700f44662e1b70f6851487752b290..9955c77aac46fb76e8549548c9e78d55a64ce423 100644 (file)
@@ -3,9 +3,15 @@ package org.simantics.scl.compiler.runtime;
 import java.io.OutputStreamWriter;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.commons.ClassRemapper;
+import org.objectweb.asm.commons.Remapper;
 import org.simantics.scl.compiler.constants.Constant;
 import org.simantics.scl.compiler.elaboration.modules.SCLValue;
 import org.simantics.scl.compiler.elaboration.rules.TransformationRule;
@@ -16,6 +22,7 @@ import org.simantics.scl.compiler.internal.codegen.utils.JavaNamingPolicy;
 import org.simantics.scl.compiler.internal.codegen.utils.TransientClassBuilder;
 import org.simantics.scl.compiler.internal.decompilation.DecompilerFactory;
 import org.simantics.scl.compiler.internal.decompilation.IDecompiler;
+import org.simantics.scl.compiler.module.ConcreteModule;
 import org.simantics.scl.compiler.module.Module;
 import org.simantics.scl.compiler.top.SCLCompilerConfiguration;
 import org.simantics.scl.compiler.top.ValueNotFound;
@@ -123,7 +130,10 @@ public class RuntimeModule {
         }
         
         private Class<?> getClass(String name) throws ClassNotFoundException {
-            //System.out.println("getClass " + name);
+            
+            Class<?> clazz = findLoadedClass(name);
+            if(clazz != null)
+                return clazz;
             
             // If the class is not generated from SCL, use parent class loader
             if(!name.startsWith(SCL_PACKAGE_PREFIX)) {
@@ -160,6 +170,22 @@ public class RuntimeModule {
             }
         }
         
+//        protected Class<?> loadClass(String name, boolean resolve)
+//                throws ClassNotFoundException
+//            {
+//                synchronized (getClassLoadingLock(name)) {
+//                    // First, check if the class has already been loaded
+//                    Class<?> c = findLoadedClass(name);
+//                    if (c == null) {
+//                        c = getClass(name);
+//                    }
+//                    if (resolve) {
+//                        resolveClass(c);
+//                    }
+//                    return c;
+//                }
+//            }
+        
         @Override
         public synchronized Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
             Class<?> clazz = getClass(name);
@@ -168,6 +194,11 @@ public class RuntimeModule {
             return clazz;
         }
         
+        @Override
+        public Class<?> loadClass(String name) throws ClassNotFoundException {
+            return super.loadClass(name);
+        }
+        
         public Module getModule(String moduleName) {
             //System.out.println("ModuleClassLoader.getModule(" + moduleName + ")");
             if(moduleName.equals(this.moduleName))
@@ -285,4 +316,106 @@ public class RuntimeModule {
         classLoader = null;
         classBuilder = null;
     }
+    
+    public class ClassNameRecordingRemapper extends Remapper {
+
+        private final Set<? super String> classNames;
+
+        public ClassNameRecordingRemapper(Set<? super String> classNames) {
+            this.classNames = classNames;
+        }
+        
+        @Override
+        public String map(String typeName) {
+            classNames.add(typeName);
+            return super.map(typeName);
+        }
+        
+        @Override
+        public String mapDesc(String desc) {
+            //classNames.add(desc);
+            return super.mapDesc(desc);
+        }
+        @Override
+        public String mapFieldName(String owner, String name, String desc) {
+            return super.mapFieldName(owner, name, desc);
+        }
+        @Override
+        public String mapInvokeDynamicMethodName(String name, String desc) {
+            // TODO Auto-generated method stub
+            return super.mapInvokeDynamicMethodName(name, desc);
+        }
+        @Override
+        public String mapMethodDesc(String desc) {
+            //classNames.add(desc);
+            return super.mapMethodDesc(desc);
+        }
+        @Override
+        public String mapMethodName(String owner, String name, String desc) {
+            // TODO Auto-generated method stub
+            return super.mapMethodName(owner, name, desc);
+        }
+        @Override
+        public String mapSignature(String signature, boolean typeSignature) {
+            //classNames.add(signature);
+            return super.mapSignature(signature, typeSignature);
+        }
+        @Override
+        public String mapType(String type) {
+            classNames.add(type);
+            return super.mapType(type);
+        }
+        @Override
+        public String[] mapTypes(String[] types) {
+            for(String type : types)
+                classNames.add(type);
+            // TODO Auto-generated method stub
+            return super.mapTypes(types);
+        }
+        @Override
+        public Object mapValue(Object value) {
+            //classNames.add(value.toString());
+            // TODO Auto-generated method stub
+            return super.mapValue(value);
+        }
+    }
+    
+    public Set<String> classReferences(String className) {
+        try {
+            HashSet<String> referencedClasses = new HashSet<>();
+            ClassNameRecordingRemapper m = new ClassNameRecordingRemapper(referencedClasses);
+            ClassReader cr = new ClassReader(module.getClass(className));
+            int ASM5 = 5 << 16 | 0 << 8 | 0;
+            //TraceClassVisitor tcv = new TraceClassVisitor(null, new PrintWriter(System.err));
+            ClassVisitor cv1 = new ClassVisitor(ASM5) {};
+            ClassVisitor cv = new ClassRemapper(cv1, m);
+            cr.accept(cv, ClassReader.SKIP_DEBUG);
+            return referencedClasses;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+    
+    public void loadClasses() {
+        if(module instanceof ConcreteModule) {
+            ConcreteModule cm = (ConcreteModule)module;
+            try {
+                for(String className : cm.getClasses().keySet()) {
+                    Set<String> refs = classReferences(className);
+                    for(String s : refs) {
+                        String internalName = s.replace('/', '.');
+                        try {
+                            classLoader.getClass(internalName);
+                        } catch (Throwable e) {
+                            e.printStackTrace();
+                        }
+                    }
+                }
+            } catch (Throwable e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
 }
\ No newline at end of file
index 2e717f945780574f71c3382c33cb3bf157fa55e2..35438747c9ee6f4e699d600085dfd84d5a89a79c 100644 (file)
@@ -4,10 +4,14 @@ import java.util.ArrayList;
 
 import org.simantics.scl.compiler.errors.DoesNotExist;
 import org.simantics.scl.compiler.errors.Failable;
+import org.simantics.scl.compiler.module.ConcreteModule;
 import org.simantics.scl.compiler.module.Module;
 import org.simantics.scl.compiler.module.options.ModuleCompilationOptions;
 import org.simantics.scl.compiler.module.options.ModuleCompilationOptionsAdvisor;
 import org.simantics.scl.compiler.module.repository.ModuleRepository;
+import org.simantics.scl.compiler.runtime.ExpressionClassLoader;
+import org.simantics.scl.compiler.runtime.RuntimeEnvironment;
+import org.simantics.scl.compiler.runtime.RuntimeModule;
 import org.simantics.scl.compiler.source.repository.ModuleSourceRepository;
 import org.simantics.scl.compiler.testing.repository.TestRepository;
 import org.simantics.scl.osgi.internal.Activator;
@@ -47,9 +51,9 @@ public class SCLOsgi {
                 System.out.print(moduleName);
                 System.out.print(" - ");
                 Failable<Module> module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName);
-                if(module.didSucceed())
+                if(module.didSucceed()) {
                     System.out.println("succeeded");
-                else if(module == DoesNotExist.INSTANCE)
+                else if(module == DoesNotExist.INSTANCE)
                     System.out.println("does not exist"); // should not happen
                 else {
                     System.out.println("error");
@@ -67,4 +71,37 @@ public class SCLOsgi {
         }
         return null;
     }
+    
+    public static String primeClassloading() {
+        ArrayList<String> modulesWithErrors = new ArrayList<String>(); 
+        SCLOsgi.SOURCE_REPOSITORY.forAllModules(new TObjectProcedure<String>() {
+            @Override
+            public boolean execute(String moduleName) {
+                Failable<Module> module = SCLOsgi.MODULE_REPOSITORY.getModule(moduleName);
+                if(module.didSucceed()) {
+                    Failable<RuntimeModule> frm = SCLOsgi.MODULE_REPOSITORY.getRuntimeModule(moduleName);
+                    RuntimeModule rm = frm.getResult();
+                    rm.loadClasses();
+                } else if(module == DoesNotExist.INSTANCE)
+                    System.out.println("does not exist"); // should not happen
+                else {
+                    System.out.println("error");
+                    modulesWithErrors.add(moduleName);
+                }
+                return true;
+            }
+        });
+        for(RuntimeEnvironment env : SCLOsgi.MODULE_REPOSITORY.getRuntimeEnvironments()) {
+            ExpressionClassLoader ecl = (ExpressionClassLoader)env.getMutableClassLoader();
+            for(String name : ecl.localClasses.keySet()) {
+                try {
+                    ecl.loadClass(name.replace("/", "."));
+                } catch (ClassNotFoundException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return null;
+    }
+    
 }
index 871dc1975c7a70295ced2b5cf800e51cf0496429..3a4801078664ae5539556436bbb1664f936cb828 100644 (file)
@@ -58,6 +58,10 @@ public class CompileProceduralComponentTypeRequest extends AbstractExpressionCom
         }
     }
 
+    public static Function1<Variable, Object> compile(ReadGraph graph, Resource componentType) throws DatabaseException {
+        return graph.syncRequest(new CompileProceduralComponentTypeRequest(componentType), TransientCacheListener.instance());
+    }
+    
     @Override
     protected String getExpressionText(ReadGraph graph)
             throws DatabaseException {
index 5a1bb23fbdb13b3ba9c517cd7cea3b9bbf662ba3..07d32a8e961dea7264687711b56588950ef93627 100644 (file)
@@ -27,7 +27,7 @@ import java.util.Map;
 public class ThreadLogVisualizer {
        
     // Do not show tasks shorter than 5ms
-    final public static long DISCARD_LIMIT = 2 * 1000 * 1000;
+    final public static long DISCARD_LIMIT = 50 * 1000 * 1000;
     // 1s columns
     final public static long COLUMN_WIDTH = 1000000000;
     
index 2f3425c58b5be1975c3014fb7a1aee03c41154fa..67cc929039057bab260ccb4f2826c207a66156c1 100644 (file)
@@ -23,7 +23,7 @@ public class ThreadLogger implements IThreadLogger {
 
     public static String LOG_FILE = "threads.log";
     
-    public static boolean LOG = false;
+    public static boolean LOG = true;
 
     static Object loggerCreationLock = new Object();
     static ThreadLogger logger = null;