]> gerrit.simantics Code Review - simantics/platform.git/blobdiff - bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorInput2.java
Fixed all line endings of the repository
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / workbench / ResourceEditorInput2.java
index a03ea7c45dd177d8e7b88f5f6fc8ab66a6a2344c..e1ec2f52106cbbcfc4a0ae1d52157e8bf309702b 100644 (file)
-/*******************************************************************************\r
- * Copyright (c) 2007, 2013 Association for Decentralized Information Management\r
- * in Industry THTH ry.\r
- * All rights reserved. This program and the accompanying materials\r
- * are made available under the terms of the Eclipse Public License v1.0\r
- * which accompanies this distribution, and is available at\r
- * http://www.eclipse.org/legal/epl-v10.html\r
- *\r
- * Contributors:\r
- *     VTT Technical Research Centre of Finland - initial API and implementation\r
- *     Semantum Oy - issue #4384\r
- *******************************************************************************/\r
-package org.simantics.ui.workbench;\r
-\r
-import java.lang.ref.Reference;\r
-\r
-import org.eclipse.core.runtime.IAdaptable;\r
-import org.eclipse.core.runtime.PlatformObject;\r
-import org.eclipse.jface.resource.ImageDescriptor;\r
-import org.eclipse.ui.IMemento;\r
-import org.eclipse.ui.IPersistableElement;\r
-import org.simantics.Simantics;\r
-import org.simantics.db.ReadGraph;\r
-import org.simantics.db.RequestProcessor;\r
-import org.simantics.db.Resource;\r
-import org.simantics.db.Session;\r
-import org.simantics.db.common.ResourceArray;\r
-import org.simantics.db.common.request.ReadRequest;\r
-import org.simantics.db.exception.AdaptionException;\r
-import org.simantics.db.exception.DatabaseException;\r
-import org.simantics.db.exception.ResourceNotFoundException;\r
-import org.simantics.db.layer0.exception.MissingVariableException;\r
-import org.simantics.db.layer0.variable.RVI;\r
-import org.simantics.db.layer0.variable.Variable;\r
-import org.simantics.db.layer0.variable.Variables;\r
-import org.simantics.db.request.Read;\r
-import org.simantics.db.service.LifecycleSupport;\r
-import org.simantics.ui.icons.ImageDescriptorProvider;\r
-import org.simantics.ui.workbench.editor.input.ResourceEditorInputMatchingStrategy;\r
-import org.simantics.utils.ObjectUtils;\r
-import org.simantics.utils.datastructures.cache.ProvisionException;\r
-import org.simantics.utils.ui.ErrorLogger;\r
-import org.simantics.utils.ui.workbench.StringMemento;\r
-\r
-/**\r
- * This is an input class for editors that have as their input the a tuple:\r
- * (Input Resource, Model URI, RVI).\r
- * \r
- * Editor extensions requiring these as input should always use\r
- * {@link ResourceEditorInputMatchingStrategy} as their matchingStrategy.\r
- * \r
- * @author Tuukka Lehtonen\r
- * @see ResourceEditorInput\r
- * @see ResourceEditorInputMatchingStrategy\r
- */\r
-public class ResourceEditorInput2 extends PlatformObject implements IResourceEditorInput2, IPersistableElement {\r
-\r
-    private final static boolean          DEBUG_EXISTS    = false;\r
-    private final static boolean          DEBUG_UPDATE    = false;\r
-\r
-    private static final String           NO_NAME         = ResourceEditorInput.NO_NAME;\r
-\r
-    private final String                  editorID;\r
-\r
-    /**\r
-     * A random access ID to {@link #resource}.\r
-     */\r
-    protected String                        modelId;\r
-\r
-    protected String                        rvi;\r
-\r
-    /**\r
-     * A random access ID to {@link #resource}.\r
-     */\r
-    private String                        resourceId;\r
-\r
-    private transient Reference<Resource> model;\r
-\r
-    private transient Reference<Resource> resource;\r
-\r
-    private transient boolean             exists;\r
-\r
-    private transient String              name;\r
-\r
-    private transient String              tooltip;\r
-\r
-    private transient ImageDescriptor     imageDesc;\r
-\r
-    /** Persistent memento for external data */\r
-    private final StringMemento           persistentStore = new StringMemento();\r
-\r
-    ResourceEditorInput2(String editorID, String resourceId, String modelId, String rvi) {\r
-       \r
-        if (editorID == null)\r
-            throw new IllegalArgumentException("null editor id");\r
-        if (resourceId == null)\r
-            throw new IllegalArgumentException("null resource id");\r
-\r
-        this.editorID = editorID;\r
-        this.resourceId = resourceId;\r
-        this.resource = null;\r
-        this.modelId = modelId;\r
-        this.model = null;\r
-        this.rvi = rvi;\r
-\r
-        setNonExistant();\r
-    }\r
-    \r
-    /**\r
-     * @param editorID\r
-     * @param resourceId\r
-     * @param modelURI\r
-     * @param rvi\r
-     */\r
-    public ResourceEditorInput2(String editorID, String resourceId, String modelId, RVI rvi) {\r
-        if (editorID == null)\r
-            throw new IllegalArgumentException("null editor id");\r
-        if (resourceId == null)\r
-            throw new IllegalArgumentException("null resource id");\r
-\r
-        this.editorID = editorID;\r
-        this.resourceId = resourceId;\r
-        this.resource = null;\r
-        this.modelId = modelId;\r
-        this.model = null;\r
-        this.rvi = rvi.toString();\r
-\r
-        setNonExistant();\r
-    }\r
-\r
-    @Deprecated\r
-    public ResourceEditorInput2(String editorID, Resource resource, Resource model, String rvi) {\r
-        if (editorID == null)\r
-            throw new IllegalArgumentException("null editor id");\r
-        if (resource == null)\r
-            throw new IllegalArgumentException("null resource");\r
-        if (model == null)\r
-            throw new IllegalArgumentException("null model");\r
-\r
-        this.editorID = editorID;\r
-        this.resourceId = ResourceInputs.getRandomAccessId(resource);\r
-        this.resource = ResourceInputs.makeReference(resource);\r
-        this.modelId = ResourceInputs.getRandomAccessId(model);\r
-        this.model = ResourceInputs.makeReference(model);\r
-        this.rvi = rvi;\r
-\r
-        setNonExistant();\r
-    }\r
-    \r
-    public ResourceEditorInput2(String editorID, Resource resource, Resource model, RVI rvi) {\r
-        if (editorID == null)\r
-            throw new IllegalArgumentException("null editor id");\r
-        if (resource == null)\r
-            throw new IllegalArgumentException("null resource");\r
-        if (model == null)\r
-            throw new IllegalArgumentException("null model");\r
-\r
-        this.editorID = editorID;\r
-        this.resourceId = ResourceInputs.getRandomAccessId(resource);\r
-        this.resource = ResourceInputs.makeReference(resource);\r
-        this.modelId = ResourceInputs.getRandomAccessId(model);\r
-        this.model = ResourceInputs.makeReference(model);\r
-        this.rvi = rvi != null ? rvi.toString() : null;\r
-\r
-        setNonExistant();\r
-    }\r
-    \r
-    @Override\r
-    public void init(IAdaptable adapter) throws DatabaseException {\r
-        Resource r = getResource();\r
-        if (r != null)\r
-            updateCaches(getSession(), true);\r
-    }\r
-\r
-    @Override\r
-    public void dispose() {\r
-        //System.out.println("dispose resource editor input: " + name);\r
-        // NOTE: this has to be done since Eclipse will cache these IEditorInput\r
-        // instances within EditorHistoryItem's that are stored in an EditorHistory\r
-        // instance. They are held by strong reference which means that the session\r
-        // cannot be collected if it is not nulled here.\r
-        resource = null;\r
-        model = null;\r
-    }\r
-\r
-    /**\r
-     * @return a graph instance if it exists and has not yet been disposed,\r
-     *         <code>null</code> otherwise\r
-     */\r
-    public Session getSession() {\r
-        Session s = Simantics.getSession();\r
-        if (s.getService(LifecycleSupport.class).isClosed())\r
-            throw new IllegalStateException("database session is closed");\r
-        return s;\r
-    }\r
-\r
-    @Override\r
-    public boolean exists() {\r
-        return exists;\r
-    }\r
-\r
-    @Override\r
-    public boolean exists(ReadGraph graph) throws DatabaseException {\r
-        try {\r
-            assertExists(graph);\r
-            return true;\r
-        } catch (MissingVariableException e) {\r
-        } catch (ResourceNotFoundException e) {\r
-        } catch (Nonexistant e) {\r
-        }\r
-        return false;\r
-    }\r
-\r
-    public Resource getResource0() throws DatabaseException {\r
-        Resource r = tryGetResource();\r
-        if (r != null)\r
-            return r;\r
-\r
-        Session s = ResourceInputs.peekSession();\r
-        if (s == null)\r
-            return null;\r
-\r
-        r = ResourceInputs.resolveResource( s, resourceId );\r
-        this.resource = ResourceInputs.makeReference( r );\r
-        return r;\r
-    }\r
-\r
-    public Resource getModel0() throws DatabaseException {\r
-        Resource r = tryGetModel();\r
-        if (r != null)\r
-            return r;\r
-\r
-        Session s = ResourceInputs.peekSession();\r
-        if (s == null)\r
-            return null;\r
-\r
-        r = ResourceInputs.resolveResource( s, modelId );\r
-        this.model = ResourceInputs.makeReference( r );\r
-        return r;\r
-    }\r
-    \r
-    @Override\r
-    public Resource getResource() {\r
-        try {\r
-            return getResource0();\r
-        } catch (DatabaseException e) {\r
-            ErrorLogger.defaultLogError(e);\r
-            return null;\r
-        }\r
-    }\r
-\r
-    @Override\r
-    @Deprecated\r
-    public ResourceArray getResourceArray() {\r
-        Resource r = getResource();\r
-        return r == null ? ResourceArray.EMPTY : new ResourceArray(r);\r
-    }\r
-    \r
-    public Resource getModel(ReadGraph graph) {\r
-        try {\r
-            return getModel0();\r
-        } catch (DatabaseException e) {\r
-            ErrorLogger.defaultLogError(e);\r
-            return null;\r
-        }\r
-    }\r
-    \r
-\r
-    @Override\r
-    public String getRVI() {\r
-        return rvi;\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.ui.IEditorInput#getImageDescriptor()\r
-     */\r
-    @Override\r
-    public ImageDescriptor getImageDescriptor() {\r
-        return imageDesc;\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.ui.IEditorInput#getName()\r
-     */\r
-    @Override\r
-    public String getName() {\r
-        return name;\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.ui.IEditorInput#getToolTipText()\r
-     */\r
-    @Override\r
-    public String getToolTipText() {\r
-        return tooltip;\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.ui.IEditorInput#getPersistable()\r
-     */\r
-    @Override\r
-    public IPersistableElement getPersistable() {\r
-        // Don't allow persistability when it's not possible.\r
-        if (!isPersistable())\r
-            return null;\r
-        return this;\r
-    }\r
-\r
-    protected boolean isPersistable() {\r
-        Session session = Simantics.peekSession();\r
-        if (session == null)\r
-            return false;\r
-        LifecycleSupport lc = session.peekService(LifecycleSupport.class);\r
-        if (lc == null)\r
-            return false;\r
-        if (lc.isClosed())\r
-            return false;\r
-        return true;\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.ui.IPersistableElement#getFactoryId()\r
-     */\r
-    @Override\r
-    public String getFactoryId() {\r
-        return ResourceEditorInputFactory2.getFactoryId();\r
-    }\r
-\r
-    /**\r
-     * Saves the state of the given resource editor input into the given memento.\r
-     *\r
-     * @param memento the storage area for element state\r
-     * @see org.eclipse.ui.IPersistable#saveState(org.eclipse.ui.IMemento)\r
-     */\r
-    @Override\r
-    public void saveState(IMemento memento) {\r
-        IMemento child = memento.createChild(ResourceEditorInputFactory2.TAG_RESOURCE_ID);\r
-        child.putTextData(resourceId);\r
-        memento.putString(ResourceEditorInputFactory2.TAG_EDITOR_ID, editorID);\r
-        memento.putString(ResourceEditorInputFactory2.TAG_MODEL_ID, modelId);\r
-        memento.putString(ResourceEditorInputFactory2.TAG_RVI, rvi);\r
-        memento.putString(ResourceEditorInputFactory2.TAG_EXTERNAL_MEMENTO_ID, persistentStore.toString());\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)\r
-     */\r
-    @SuppressWarnings("rawtypes")\r
-    @Override\r
-    public Object getAdapter(Class adapter) {\r
-        //System.out.println("[ResourceEditorInput] getAdapter: " + adapter.getName());\r
-        return null;\r
-    }\r
-\r
-    @Override\r
-    public int hashCode() {\r
-        final int prime = 31;\r
-        int result = 1;\r
-        result = prime * result + editorID.hashCode();\r
-        // modelURI and rvi may change => can't use either in hashcode.\r
-//        result = prime * result + ObjectUtils.hashCode(modelURI);\r
-//        result = prime * result + ObjectUtils.hashCode(rvi);\r
-        result = prime * result + ObjectUtils.hashCode(modelId);\r
-        result = prime * result + ObjectUtils.hashCode(resourceId);\r
-        return result;\r
-    }\r
-\r
-    @Override\r
-    public boolean equals(Object obj) {\r
-        if (this == obj)\r
-            return true;\r
-        if (obj == null)\r
-            return false;\r
-        if (getClass() != obj.getClass())\r
-            return false;\r
-        ResourceEditorInput2 other = (ResourceEditorInput2) obj;\r
-        if (!editorID.equals(other.editorID))\r
-            return false;\r
-        if (!ObjectUtils.objectEquals(modelId, other.modelId))\r
-            return false;\r
-        if (!ObjectUtils.objectEquals(rvi, other.rvi))\r
-            return false;\r
-        if (!ObjectUtils.objectEquals(resourceId, other.resourceId))\r
-            return false;\r
-        return true;\r
-    }\r
-\r
-    private void updateCaches(RequestProcessor processor, boolean sync) throws DatabaseException {\r
-        ReadRequest req = new ReadRequest() {\r
-            @Override\r
-            public void run(ReadGraph g) throws DatabaseException {\r
-                update(g);\r
-            }\r
-        };\r
-        if (sync) {\r
-            processor.syncRequest(req);\r
-        } else {\r
-            processor.asyncRequest(req);\r
-        }\r
-    }\r
-\r
-    static class Nonexistant extends DatabaseException {\r
-        private static final long serialVersionUID = -7964385375237203651L;\r
-\r
-        @Override\r
-        public synchronized Throwable fillInStackTrace() {\r
-            return this;\r
-        }\r
-    }\r
-\r
-    /* (non-Javadoc)\r
-     * @see org.simantics.ui.workbench.IResourceEditorInput#update(org.simantics.db.Graph)\r
-     */\r
-    @Override\r
-    public void update(ReadGraph g) throws DatabaseException {\r
-        Resource r = getResource();\r
-        if (r == null)\r
-            return;\r
-\r
-        if (DEBUG_UPDATE)\r
-            System.out.println("update(" + this + ")");\r
-\r
-        try {\r
-            assertExists(g);\r
-\r
-            name = g.syncRequest(new TitleRequest(editorID, this));\r
-            if (name == null)\r
-                name = NO_NAME;\r
-\r
-            tooltip = g.syncRequest(new ToolTipRequest(editorID, this));\r
-            if (tooltip == null)\r
-                tooltip = NO_NAME;\r
-\r
-            try {\r
-                ImageDescriptorProvider idp = g.adapt(r, ImageDescriptorProvider.class);\r
-                imageDesc = idp.get();\r
-            } catch (AdaptionException e) {\r
-                imageDesc = ImageDescriptor.getMissingImageDescriptor();\r
-            } catch (ProvisionException e) {\r
-                imageDesc = ImageDescriptor.getMissingImageDescriptor();\r
-                ErrorLogger.defaultLogError(e);\r
-            }\r
-\r
-            if (DEBUG_UPDATE)\r
-                System.out.println("update(" + this + ") finished");\r
-        } catch (DatabaseException e) {\r
-            if (DEBUG_UPDATE)\r
-                e.printStackTrace();\r
-            setNonExistant();\r
-        }\r
-    }\r
-\r
-    private void assertExists(ReadGraph g) throws DatabaseException {\r
-        if (DEBUG_EXISTS)\r
-            System.out.println("ResourceEditorInput2.assertExists(" + this + ") begins");\r
-\r
-        // 1. Check resource existence\r
-        Resource r = getResource();\r
-        if (r == null)\r
-            throw new Nonexistant();\r
-\r
-        exists = g.hasStatement(r);\r
-        if (!exists)\r
-            throw new Nonexistant();\r
-\r
-        // 2. Check model existence\r
-        Resource model = getModel(g);\r
-        if (model == null)\r
-            throw new Nonexistant();\r
-\r
-        exists = g.hasStatement(model);\r
-        if (!exists)\r
-            throw new Nonexistant();\r
-\r
-        // 3. Validate rvi\r
-        if (DEBUG_EXISTS)\r
-               System.out.println("validating rvi: '" + rvi + "'");\r
-\r
-        if(rvi != null && !rvi.isEmpty()) {\r
-               Variable context = Variables.getPossibleConfigurationContext(g, model);\r
-               if (context == null)\r
-                       throw new Nonexistant();\r
-               RVI rvi_ = RVI.fromResourceFormat(g, rvi);\r
-               Variable variable = rvi_.resolvePossible(g, context);\r
-               if (variable == null)\r
-                       throw new Nonexistant();\r
-        }\r
-\r
-        // Touch the diagram title calculation within this existence\r
-        // checking request.\r
-        g.syncRequest(new TitleRequest(editorID, this));\r
-\r
-        if (DEBUG_EXISTS)\r
-            System.out.println("ResourceEditorInput2.assertExists(" + this + ") finished");\r
-    }\r
-\r
-    private void setNonExistant() {\r
-        if (DEBUG_UPDATE)\r
-            System.out.println("setNonExistant(" + this + " @ " + System.identityHashCode(this) + ")");\r
-\r
-        exists = false;\r
-        tooltip = name = NO_NAME;\r
-        imageDesc = ImageDescriptor.getMissingImageDescriptor();\r
-    }\r
-\r
-    public IMemento getPersistentStore() {\r
-        return persistentStore;\r
-    }\r
-\r
-    @Override\r
-    public String toString() {\r
-        return getClass().getSimpleName() + " [name=" + getName() + ", resource=" + resource + ", model=" + model + ", rvi=" + rvi + "]";\r
-    }\r
-\r
-    /**\r
-     * @see org.simantics.ui.workbench.IResourceEditorInput2#getVariable()\r
-     */\r
-    public Variable getVariable() throws DatabaseException {\r
-        return getSession().syncRequest(new Read<Variable>() {\r
-            @Override\r
-            public Variable perform(ReadGraph graph) throws DatabaseException {\r
-                return getVariable(graph);\r
-            }\r
-        });\r
-    }\r
-\r
-    /**\r
-     * @see org.simantics.ui.workbench.IResourceEditorInput2#getVariable(org.simantics.db.ReadGraph)\r
-     */\r
-    public Variable getVariable(ReadGraph graph) throws DatabaseException {\r
-        Resource model = getModel(graph);\r
-        String rvi = getRVI();\r
-        // Model + RVI\r
-        if (rvi != null) {\r
-            Variable configuration = Variables.getConfigurationContext(graph, model);\r
-            RVI rrvi = RVI.fromResourceFormat(graph, rvi);\r
-            return rrvi.resolve(graph, configuration);\r
-        }\r
-        // Absolute URI\r
-        else {\r
-            return Variables.getVariable(graph, model);\r
-        }\r
-    }\r
-\r
-    private Resource tryGetResource() {\r
-        Reference<Resource> ref = resource;\r
-        return ref == null ? null : ref.get();\r
-    }\r
-\r
-    private Resource tryGetModel() {\r
-        Reference<Resource> ref = model;\r
-        return ref == null ? null : ref.get();\r
-    }\r
-\r
+/*******************************************************************************
+ * Copyright (c) 2007, 2013 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
+ *     Semantum Oy - issue #4384
+ *******************************************************************************/
+package org.simantics.ui.workbench;
+
+import java.lang.ref.Reference;
+
+import org.eclipse.core.runtime.IAdaptable;
+import org.eclipse.core.runtime.PlatformObject;
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.ui.IMemento;
+import org.eclipse.ui.IPersistableElement;
+import org.simantics.Simantics;
+import org.simantics.db.ReadGraph;
+import org.simantics.db.RequestProcessor;
+import org.simantics.db.Resource;
+import org.simantics.db.Session;
+import org.simantics.db.common.ResourceArray;
+import org.simantics.db.common.request.ReadRequest;
+import org.simantics.db.exception.AdaptionException;
+import org.simantics.db.exception.DatabaseException;
+import org.simantics.db.exception.ResourceNotFoundException;
+import org.simantics.db.layer0.exception.MissingVariableException;
+import org.simantics.db.layer0.variable.RVI;
+import org.simantics.db.layer0.variable.Variable;
+import org.simantics.db.layer0.variable.Variables;
+import org.simantics.db.request.Read;
+import org.simantics.db.service.LifecycleSupport;
+import org.simantics.ui.icons.ImageDescriptorProvider;
+import org.simantics.ui.workbench.editor.input.ResourceEditorInputMatchingStrategy;
+import org.simantics.utils.ObjectUtils;
+import org.simantics.utils.datastructures.cache.ProvisionException;
+import org.simantics.utils.ui.ErrorLogger;
+import org.simantics.utils.ui.workbench.StringMemento;
+
+/**
+ * This is an input class for editors that have as their input the a tuple:
+ * (Input Resource, Model URI, RVI).
+ * 
+ * Editor extensions requiring these as input should always use
+ * {@link ResourceEditorInputMatchingStrategy} as their matchingStrategy.
+ * 
+ * @author Tuukka Lehtonen
+ * @see ResourceEditorInput
+ * @see ResourceEditorInputMatchingStrategy
+ */
+public class ResourceEditorInput2 extends PlatformObject implements IResourceEditorInput2, IPersistableElement {
+
+    private final static boolean          DEBUG_EXISTS    = false;
+    private final static boolean          DEBUG_UPDATE    = false;
+
+    private static final String           NO_NAME         = ResourceEditorInput.NO_NAME;
+
+    private final String                  editorID;
+
+    /**
+     * A random access ID to {@link #resource}.
+     */
+    protected String                        modelId;
+
+    protected String                        rvi;
+
+    /**
+     * A random access ID to {@link #resource}.
+     */
+    private String                        resourceId;
+
+    private transient Reference<Resource> model;
+
+    private transient Reference<Resource> resource;
+
+    private transient boolean             exists;
+
+    private transient String              name;
+
+    private transient String              tooltip;
+
+    private transient ImageDescriptor     imageDesc;
+
+    /** Persistent memento for external data */
+    private final StringMemento           persistentStore = new StringMemento();
+
+    ResourceEditorInput2(String editorID, String resourceId, String modelId, String rvi) {
+       
+        if (editorID == null)
+            throw new IllegalArgumentException("null editor id");
+        if (resourceId == null)
+            throw new IllegalArgumentException("null resource id");
+
+        this.editorID = editorID;
+        this.resourceId = resourceId;
+        this.resource = null;
+        this.modelId = modelId;
+        this.model = null;
+        this.rvi = rvi;
+
+        setNonExistant();
+    }
+    
+    /**
+     * @param editorID
+     * @param resourceId
+     * @param modelURI
+     * @param rvi
+     */
+    public ResourceEditorInput2(String editorID, String resourceId, String modelId, RVI rvi) {
+        if (editorID == null)
+            throw new IllegalArgumentException("null editor id");
+        if (resourceId == null)
+            throw new IllegalArgumentException("null resource id");
+
+        this.editorID = editorID;
+        this.resourceId = resourceId;
+        this.resource = null;
+        this.modelId = modelId;
+        this.model = null;
+        this.rvi = rvi.toString();
+
+        setNonExistant();
+    }
+
+    @Deprecated
+    public ResourceEditorInput2(String editorID, Resource resource, Resource model, String rvi) {
+        if (editorID == null)
+            throw new IllegalArgumentException("null editor id");
+        if (resource == null)
+            throw new IllegalArgumentException("null resource");
+        if (model == null)
+            throw new IllegalArgumentException("null model");
+
+        this.editorID = editorID;
+        this.resourceId = ResourceInputs.getRandomAccessId(resource);
+        this.resource = ResourceInputs.makeReference(resource);
+        this.modelId = ResourceInputs.getRandomAccessId(model);
+        this.model = ResourceInputs.makeReference(model);
+        this.rvi = rvi;
+
+        setNonExistant();
+    }
+    
+    public ResourceEditorInput2(String editorID, Resource resource, Resource model, RVI rvi) {
+        if (editorID == null)
+            throw new IllegalArgumentException("null editor id");
+        if (resource == null)
+            throw new IllegalArgumentException("null resource");
+        if (model == null)
+            throw new IllegalArgumentException("null model");
+
+        this.editorID = editorID;
+        this.resourceId = ResourceInputs.getRandomAccessId(resource);
+        this.resource = ResourceInputs.makeReference(resource);
+        this.modelId = ResourceInputs.getRandomAccessId(model);
+        this.model = ResourceInputs.makeReference(model);
+        this.rvi = rvi != null ? rvi.toString() : null;
+
+        setNonExistant();
+    }
+    
+    @Override
+    public void init(IAdaptable adapter) throws DatabaseException {
+        Resource r = getResource();
+        if (r != null)
+            updateCaches(getSession(), true);
+    }
+
+    @Override
+    public void dispose() {
+        //System.out.println("dispose resource editor input: " + name);
+        // NOTE: this has to be done since Eclipse will cache these IEditorInput
+        // instances within EditorHistoryItem's that are stored in an EditorHistory
+        // instance. They are held by strong reference which means that the session
+        // cannot be collected if it is not nulled here.
+        resource = null;
+        model = null;
+    }
+
+    /**
+     * @return a graph instance if it exists and has not yet been disposed,
+     *         <code>null</code> otherwise
+     */
+    public Session getSession() {
+        Session s = Simantics.getSession();
+        if (s.getService(LifecycleSupport.class).isClosed())
+            throw new IllegalStateException("database session is closed");
+        return s;
+    }
+
+    @Override
+    public boolean exists() {
+        return exists;
+    }
+
+    @Override
+    public boolean exists(ReadGraph graph) throws DatabaseException {
+        try {
+            assertExists(graph);
+            return true;
+        } catch (MissingVariableException e) {
+        } catch (ResourceNotFoundException e) {
+        } catch (Nonexistant e) {
+        }
+        return false;
+    }
+
+    public Resource getResource0() throws DatabaseException {
+        Resource r = tryGetResource();
+        if (r != null)
+            return r;
+
+        Session s = ResourceInputs.peekSession();
+        if (s == null)
+            return null;
+
+        r = ResourceInputs.resolveResource( s, resourceId );
+        this.resource = ResourceInputs.makeReference( r );
+        return r;
+    }
+
+    public Resource getModel0() throws DatabaseException {
+        Resource r = tryGetModel();
+        if (r != null)
+            return r;
+
+        Session s = ResourceInputs.peekSession();
+        if (s == null)
+            return null;
+
+        r = ResourceInputs.resolveResource( s, modelId );
+        this.model = ResourceInputs.makeReference( r );
+        return r;
+    }
+    
+    @Override
+    public Resource getResource() {
+        try {
+            return getResource0();
+        } catch (DatabaseException e) {
+            ErrorLogger.defaultLogError(e);
+            return null;
+        }
+    }
+
+    @Override
+    @Deprecated
+    public ResourceArray getResourceArray() {
+        Resource r = getResource();
+        return r == null ? ResourceArray.EMPTY : new ResourceArray(r);
+    }
+    
+    public Resource getModel(ReadGraph graph) {
+        try {
+            return getModel0();
+        } catch (DatabaseException e) {
+            ErrorLogger.defaultLogError(e);
+            return null;
+        }
+    }
+    
+
+    @Override
+    public String getRVI() {
+        return rvi;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IEditorInput#getImageDescriptor()
+     */
+    @Override
+    public ImageDescriptor getImageDescriptor() {
+        return imageDesc;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IEditorInput#getName()
+     */
+    @Override
+    public String getName() {
+        return name;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IEditorInput#getToolTipText()
+     */
+    @Override
+    public String getToolTipText() {
+        return tooltip;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IEditorInput#getPersistable()
+     */
+    @Override
+    public IPersistableElement getPersistable() {
+        // Don't allow persistability when it's not possible.
+        if (!isPersistable())
+            return null;
+        return this;
+    }
+
+    protected boolean isPersistable() {
+        Session session = Simantics.peekSession();
+        if (session == null)
+            return false;
+        LifecycleSupport lc = session.peekService(LifecycleSupport.class);
+        if (lc == null)
+            return false;
+        if (lc.isClosed())
+            return false;
+        return true;
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.ui.IPersistableElement#getFactoryId()
+     */
+    @Override
+    public String getFactoryId() {
+        return ResourceEditorInputFactory2.getFactoryId();
+    }
+
+    /**
+     * Saves the state of the given resource editor input into the given memento.
+     *
+     * @param memento the storage area for element state
+     * @see org.eclipse.ui.IPersistable#saveState(org.eclipse.ui.IMemento)
+     */
+    @Override
+    public void saveState(IMemento memento) {
+        IMemento child = memento.createChild(ResourceEditorInputFactory2.TAG_RESOURCE_ID);
+        child.putTextData(resourceId);
+        memento.putString(ResourceEditorInputFactory2.TAG_EDITOR_ID, editorID);
+        memento.putString(ResourceEditorInputFactory2.TAG_MODEL_ID, modelId);
+        memento.putString(ResourceEditorInputFactory2.TAG_RVI, rvi);
+        memento.putString(ResourceEditorInputFactory2.TAG_EXTERNAL_MEMENTO_ID, persistentStore.toString());
+    }
+
+    /* (non-Javadoc)
+     * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
+     */
+    @SuppressWarnings("rawtypes")
+    @Override
+    public Object getAdapter(Class adapter) {
+        //System.out.println("[ResourceEditorInput] getAdapter: " + adapter.getName());
+        return null;
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + editorID.hashCode();
+        // modelURI and rvi may change => can't use either in hashcode.
+//        result = prime * result + ObjectUtils.hashCode(modelURI);
+//        result = prime * result + ObjectUtils.hashCode(rvi);
+        result = prime * result + ObjectUtils.hashCode(modelId);
+        result = prime * result + ObjectUtils.hashCode(resourceId);
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        ResourceEditorInput2 other = (ResourceEditorInput2) obj;
+        if (!editorID.equals(other.editorID))
+            return false;
+        if (!ObjectUtils.objectEquals(modelId, other.modelId))
+            return false;
+        if (!ObjectUtils.objectEquals(rvi, other.rvi))
+            return false;
+        if (!ObjectUtils.objectEquals(resourceId, other.resourceId))
+            return false;
+        return true;
+    }
+
+    private void updateCaches(RequestProcessor processor, boolean sync) throws DatabaseException {
+        ReadRequest req = new ReadRequest() {
+            @Override
+            public void run(ReadGraph g) throws DatabaseException {
+                update(g);
+            }
+        };
+        if (sync) {
+            processor.syncRequest(req);
+        } else {
+            processor.asyncRequest(req);
+        }
+    }
+
+    static class Nonexistant extends DatabaseException {
+        private static final long serialVersionUID = -7964385375237203651L;
+
+        @Override
+        public synchronized Throwable fillInStackTrace() {
+            return this;
+        }
+    }
+
+    /* (non-Javadoc)
+     * @see org.simantics.ui.workbench.IResourceEditorInput#update(org.simantics.db.Graph)
+     */
+    @Override
+    public void update(ReadGraph g) throws DatabaseException {
+        Resource r = getResource();
+        if (r == null)
+            return;
+
+        if (DEBUG_UPDATE)
+            System.out.println("update(" + this + ")");
+
+        try {
+            assertExists(g);
+
+            name = g.syncRequest(new TitleRequest(editorID, this));
+            if (name == null)
+                name = NO_NAME;
+
+            tooltip = g.syncRequest(new ToolTipRequest(editorID, this));
+            if (tooltip == null)
+                tooltip = NO_NAME;
+
+            try {
+                ImageDescriptorProvider idp = g.adapt(r, ImageDescriptorProvider.class);
+                imageDesc = idp.get();
+            } catch (AdaptionException e) {
+                imageDesc = ImageDescriptor.getMissingImageDescriptor();
+            } catch (ProvisionException e) {
+                imageDesc = ImageDescriptor.getMissingImageDescriptor();
+                ErrorLogger.defaultLogError(e);
+            }
+
+            if (DEBUG_UPDATE)
+                System.out.println("update(" + this + ") finished");
+        } catch (DatabaseException e) {
+            if (DEBUG_UPDATE)
+                e.printStackTrace();
+            setNonExistant();
+        }
+    }
+
+    private void assertExists(ReadGraph g) throws DatabaseException {
+        if (DEBUG_EXISTS)
+            System.out.println("ResourceEditorInput2.assertExists(" + this + ") begins");
+
+        // 1. Check resource existence
+        Resource r = getResource();
+        if (r == null)
+            throw new Nonexistant();
+
+        exists = g.hasStatement(r);
+        if (!exists)
+            throw new Nonexistant();
+
+        // 2. Check model existence
+        Resource model = getModel(g);
+        if (model == null)
+            throw new Nonexistant();
+
+        exists = g.hasStatement(model);
+        if (!exists)
+            throw new Nonexistant();
+
+        // 3. Validate rvi
+        if (DEBUG_EXISTS)
+               System.out.println("validating rvi: '" + rvi + "'");
+
+        if(rvi != null && !rvi.isEmpty()) {
+               Variable context = Variables.getPossibleConfigurationContext(g, model);
+               if (context == null)
+                       throw new Nonexistant();
+               RVI rvi_ = RVI.fromResourceFormat(g, rvi);
+               Variable variable = rvi_.resolvePossible(g, context);
+               if (variable == null)
+                       throw new Nonexistant();
+        }
+
+        // Touch the diagram title calculation within this existence
+        // checking request.
+        g.syncRequest(new TitleRequest(editorID, this));
+
+        if (DEBUG_EXISTS)
+            System.out.println("ResourceEditorInput2.assertExists(" + this + ") finished");
+    }
+
+    private void setNonExistant() {
+        if (DEBUG_UPDATE)
+            System.out.println("setNonExistant(" + this + " @ " + System.identityHashCode(this) + ")");
+
+        exists = false;
+        tooltip = name = NO_NAME;
+        imageDesc = ImageDescriptor.getMissingImageDescriptor();
+    }
+
+    public IMemento getPersistentStore() {
+        return persistentStore;
+    }
+
+    @Override
+    public String toString() {
+        return getClass().getSimpleName() + " [name=" + getName() + ", resource=" + resource + ", model=" + model + ", rvi=" + rvi + "]";
+    }
+
+    /**
+     * @see org.simantics.ui.workbench.IResourceEditorInput2#getVariable()
+     */
+    public Variable getVariable() throws DatabaseException {
+        return getSession().syncRequest(new Read<Variable>() {
+            @Override
+            public Variable perform(ReadGraph graph) throws DatabaseException {
+                return getVariable(graph);
+            }
+        });
+    }
+
+    /**
+     * @see org.simantics.ui.workbench.IResourceEditorInput2#getVariable(org.simantics.db.ReadGraph)
+     */
+    public Variable getVariable(ReadGraph graph) throws DatabaseException {
+        Resource model = getModel(graph);
+        String rvi = getRVI();
+        // Model + RVI
+        if (rvi != null) {
+            Variable configuration = Variables.getConfigurationContext(graph, model);
+            RVI rrvi = RVI.fromResourceFormat(graph, rvi);
+            return rrvi.resolve(graph, configuration);
+        }
+        // Absolute URI
+        else {
+            return Variables.getVariable(graph, model);
+        }
+    }
+
+    private Resource tryGetResource() {
+        Reference<Resource> ref = resource;
+        return ref == null ? null : ref.get();
+    }
+
+    private Resource tryGetModel() {
+        Reference<Resource> ref = model;
+        return ref == null ? null : ref.get();
+    }
+
 }
\ No newline at end of file