--- /dev/null
+/*******************************************************************************\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
+}
\ No newline at end of file