X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=bundles%2Forg.simantics.ui%2Fsrc%2Forg%2Fsimantics%2Fui%2Fworkbench%2FResourceEditorInput2.java;fp=bundles%2Forg.simantics.ui%2Fsrc%2Forg%2Fsimantics%2Fui%2Fworkbench%2FResourceEditorInput2.java;h=a03ea7c45dd177d8e7b88f5f6fc8ab66a6a2344c;hb=969bd23cab98a79ca9101af33334000879fb60c5;hp=0000000000000000000000000000000000000000;hpb=866dba5cd5a3929bbeae85991796acb212338a08;p=simantics%2Fplatform.git diff --git a/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorInput2.java b/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorInput2.java new file mode 100644 index 000000000..a03ea7c45 --- /dev/null +++ b/bundles/org.simantics.ui/src/org/simantics/ui/workbench/ResourceEditorInput2.java @@ -0,0 +1,555 @@ +/******************************************************************************* + * 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 model; + + private transient Reference 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, + * null 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() { + @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 ref = resource; + return ref == null ? null : ref.get(); + } + + private Resource tryGetModel() { + Reference ref = model; + return ref == null ? null : ref.get(); + } + +} \ No newline at end of file