1 /*******************************************************************************
2 * Copyright (c) 2007, 2013 Association for Decentralized Information Management
4 * All rights reserved. This program and the accompanying materials
5 * are made available under the terms of the Eclipse Public License v1.0
6 * which accompanies this distribution, and is available at
7 * http://www.eclipse.org/legal/epl-v10.html
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 * Semantum Oy - issue #4384
12 *******************************************************************************/
13 package org.simantics.ui.workbench;
15 import java.lang.ref.Reference;
17 import org.eclipse.core.runtime.IAdaptable;
18 import org.eclipse.core.runtime.PlatformObject;
19 import org.eclipse.jface.resource.ImageDescriptor;
20 import org.eclipse.ui.IMemento;
21 import org.eclipse.ui.IPersistableElement;
22 import org.simantics.Simantics;
23 import org.simantics.db.ReadGraph;
24 import org.simantics.db.RequestProcessor;
25 import org.simantics.db.Resource;
26 import org.simantics.db.Session;
27 import org.simantics.db.common.ResourceArray;
28 import org.simantics.db.common.request.ReadRequest;
29 import org.simantics.db.exception.AdaptionException;
30 import org.simantics.db.exception.DatabaseException;
31 import org.simantics.db.exception.ResourceNotFoundException;
32 import org.simantics.db.layer0.exception.MissingVariableException;
33 import org.simantics.db.layer0.variable.RVI;
34 import org.simantics.db.layer0.variable.Variable;
35 import org.simantics.db.layer0.variable.Variables;
36 import org.simantics.db.request.Read;
37 import org.simantics.db.service.LifecycleSupport;
38 import org.simantics.ui.icons.ImageDescriptorProvider;
39 import org.simantics.ui.workbench.editor.input.ResourceEditorInputMatchingStrategy;
40 import org.simantics.utils.ObjectUtils;
41 import org.simantics.utils.datastructures.cache.ProvisionException;
42 import org.simantics.utils.ui.ErrorLogger;
43 import org.simantics.utils.ui.workbench.StringMemento;
46 * This is an input class for editors that have as their input the a tuple:
47 * (Input Resource, Model URI, RVI).
49 * Editor extensions requiring these as input should always use
50 * {@link ResourceEditorInputMatchingStrategy} as their matchingStrategy.
52 * @author Tuukka Lehtonen
53 * @see ResourceEditorInput
54 * @see ResourceEditorInputMatchingStrategy
56 public class ResourceEditorInput2 extends PlatformObject implements IResourceEditorInput2, IPersistableElement {
58 private final static boolean DEBUG_EXISTS = false;
59 private final static boolean DEBUG_UPDATE = false;
61 private static final String NO_NAME = ResourceEditorInput.NO_NAME;
63 private final String editorID;
66 * A random access ID to {@link #resource}.
68 protected String modelId;
73 * A random access ID to {@link #resource}.
75 private String resourceId;
77 private transient Reference<Resource> model;
79 private transient Reference<Resource> resource;
81 private transient boolean exists;
83 private transient String name;
85 private transient String tooltip;
87 private transient ImageDescriptor imageDesc;
89 /** Persistent memento for external data */
90 private final StringMemento persistentStore = new StringMemento();
92 ResourceEditorInput2(String editorID, String resourceId, String modelId, String rvi) {
95 throw new IllegalArgumentException("null editor id");
96 if (resourceId == null)
97 throw new IllegalArgumentException("null resource id");
99 this.editorID = editorID;
100 this.resourceId = resourceId;
101 this.resource = null;
102 this.modelId = modelId;
115 public ResourceEditorInput2(String editorID, String resourceId, String modelId, RVI rvi) {
116 if (editorID == null)
117 throw new IllegalArgumentException("null editor id");
118 if (resourceId == null)
119 throw new IllegalArgumentException("null resource id");
121 this.editorID = editorID;
122 this.resourceId = resourceId;
123 this.resource = null;
124 this.modelId = modelId;
126 this.rvi = rvi.toString();
132 public ResourceEditorInput2(String editorID, Resource resource, Resource model, String rvi) {
133 if (editorID == null)
134 throw new IllegalArgumentException("null editor id");
135 if (resource == null)
136 throw new IllegalArgumentException("null resource");
138 throw new IllegalArgumentException("null model");
140 this.editorID = editorID;
141 this.resourceId = ResourceInputs.getRandomAccessId(resource);
142 this.resource = ResourceInputs.makeReference(resource);
143 this.modelId = ResourceInputs.getRandomAccessId(model);
144 this.model = ResourceInputs.makeReference(model);
150 public ResourceEditorInput2(String editorID, Resource resource, Resource model, RVI rvi) {
151 if (editorID == null)
152 throw new IllegalArgumentException("null editor id");
153 if (resource == null)
154 throw new IllegalArgumentException("null resource");
156 throw new IllegalArgumentException("null model");
158 this.editorID = editorID;
159 this.resourceId = ResourceInputs.getRandomAccessId(resource);
160 this.resource = ResourceInputs.makeReference(resource);
161 this.modelId = ResourceInputs.getRandomAccessId(model);
162 this.model = ResourceInputs.makeReference(model);
163 this.rvi = rvi != null ? rvi.toString() : null;
169 public void init(IAdaptable adapter) throws DatabaseException {
170 Resource r = getResource();
172 updateCaches(getSession(), true);
176 public void dispose() {
177 //System.out.println("dispose resource editor input: " + name);
178 // NOTE: this has to be done since Eclipse will cache these IEditorInput
179 // instances within EditorHistoryItem's that are stored in an EditorHistory
180 // instance. They are held by strong reference which means that the session
181 // cannot be collected if it is not nulled here.
187 * @return a graph instance if it exists and has not yet been disposed,
188 * <code>null</code> otherwise
190 public Session getSession() {
191 Session s = Simantics.getSession();
192 if (s.getService(LifecycleSupport.class).isClosed())
193 throw new IllegalStateException("database session is closed");
198 public boolean exists() {
203 public boolean exists(ReadGraph graph) throws DatabaseException {
207 } catch (MissingVariableException e) {
208 } catch (ResourceNotFoundException e) {
209 } catch (Nonexistant e) {
214 public Resource getResource0() throws DatabaseException {
215 Resource r = tryGetResource();
219 Session s = ResourceInputs.peekSession();
223 r = ResourceInputs.resolveResource( s, resourceId );
224 this.resource = ResourceInputs.makeReference( r );
228 public Resource getModel0() throws DatabaseException {
229 Resource r = tryGetModel();
233 Session s = ResourceInputs.peekSession();
237 r = ResourceInputs.resolveResource( s, modelId );
238 this.model = ResourceInputs.makeReference( r );
243 public Resource getResource() {
245 return getResource0();
246 } catch (DatabaseException e) {
247 ErrorLogger.defaultLogError(e);
254 public ResourceArray getResourceArray() {
255 Resource r = getResource();
256 return r == null ? ResourceArray.EMPTY : new ResourceArray(r);
259 public Resource getModel(ReadGraph graph) {
262 } catch (DatabaseException e) {
263 ErrorLogger.defaultLogError(e);
270 public String getRVI() {
275 * @see org.eclipse.ui.IEditorInput#getImageDescriptor()
278 public ImageDescriptor getImageDescriptor() {
283 * @see org.eclipse.ui.IEditorInput#getName()
286 public String getName() {
291 * @see org.eclipse.ui.IEditorInput#getToolTipText()
294 public String getToolTipText() {
299 * @see org.eclipse.ui.IEditorInput#getPersistable()
302 public IPersistableElement getPersistable() {
303 // Don't allow persistability when it's not possible.
304 if (!isPersistable())
309 protected boolean isPersistable() {
310 Session session = Simantics.peekSession();
313 LifecycleSupport lc = session.peekService(LifecycleSupport.class);
322 * @see org.eclipse.ui.IPersistableElement#getFactoryId()
325 public String getFactoryId() {
326 return ResourceEditorInputFactory2.getFactoryId();
330 * Saves the state of the given resource editor input into the given memento.
332 * @param memento the storage area for element state
333 * @see org.eclipse.ui.IPersistable#saveState(org.eclipse.ui.IMemento)
336 public void saveState(IMemento memento) {
337 IMemento child = memento.createChild(ResourceEditorInputFactory2.TAG_RESOURCE_ID);
338 child.putTextData(resourceId);
339 memento.putString(ResourceEditorInputFactory2.TAG_EDITOR_ID, editorID);
340 memento.putString(ResourceEditorInputFactory2.TAG_MODEL_ID, modelId);
341 memento.putString(ResourceEditorInputFactory2.TAG_RVI, rvi);
342 memento.putString(ResourceEditorInputFactory2.TAG_EXTERNAL_MEMENTO_ID, persistentStore.toString());
346 * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
349 public <T> T getAdapter(Class<T> adapter) {
350 //System.out.println("[ResourceEditorInput] getAdapter: " + adapter.getName());
355 public int hashCode() {
356 final int prime = 31;
358 result = prime * result + editorID.hashCode();
359 // modelURI and rvi may change => can't use either in hashcode.
360 // result = prime * result + ObjectUtils.hashCode(modelURI);
361 // result = prime * result + ObjectUtils.hashCode(rvi);
362 result = prime * result + ObjectUtils.hashCode(modelId);
363 result = prime * result + ObjectUtils.hashCode(resourceId);
368 public boolean equals(Object obj) {
373 if (getClass() != obj.getClass())
375 ResourceEditorInput2 other = (ResourceEditorInput2) obj;
376 if (!editorID.equals(other.editorID))
378 if (!ObjectUtils.objectEquals(modelId, other.modelId))
380 if (!ObjectUtils.objectEquals(rvi, other.rvi))
382 if (!ObjectUtils.objectEquals(resourceId, other.resourceId))
387 private void updateCaches(RequestProcessor processor, boolean sync) throws DatabaseException {
388 ReadRequest req = new ReadRequest() {
390 public void run(ReadGraph g) throws DatabaseException {
395 processor.syncRequest(req);
397 processor.asyncRequest(req);
401 static class Nonexistant extends DatabaseException {
402 private static final long serialVersionUID = -7964385375237203651L;
405 public synchronized Throwable fillInStackTrace() {
411 * @see org.simantics.ui.workbench.IResourceEditorInput#update(org.simantics.db.Graph)
414 public void update(ReadGraph g) throws DatabaseException {
415 Resource r = getResource();
420 System.out.println("update(" + this + ")");
425 name = g.syncRequest(new TitleRequest(editorID, this));
429 tooltip = g.syncRequest(new ToolTipRequest(editorID, this));
434 ImageDescriptorProvider idp = g.adapt(r, ImageDescriptorProvider.class);
435 imageDesc = idp.get();
436 } catch (AdaptionException e) {
437 imageDesc = ImageDescriptor.getMissingImageDescriptor();
438 } catch (ProvisionException e) {
439 imageDesc = ImageDescriptor.getMissingImageDescriptor();
440 ErrorLogger.defaultLogError(e);
444 System.out.println("update(" + this + ") finished");
445 } catch (DatabaseException e) {
452 private void assertExists(ReadGraph g) throws DatabaseException {
454 System.out.println("ResourceEditorInput2.assertExists(" + this + ") begins");
456 // 1. Check resource existence
457 Resource r = getResource();
459 throw new Nonexistant();
461 exists = g.hasStatement(r);
463 throw new Nonexistant();
465 // 2. Check model existence
466 Resource model = getModel(g);
468 throw new Nonexistant();
470 exists = g.hasStatement(model);
472 throw new Nonexistant();
476 System.out.println("validating rvi: '" + rvi + "'");
478 if(rvi != null && !rvi.isEmpty()) {
479 Variable context = Variables.getPossibleConfigurationContext(g, model);
481 throw new Nonexistant();
482 RVI rvi_ = RVI.fromResourceFormat(g, rvi);
483 Variable variable = rvi_.resolvePossible(g, context);
484 if (variable == null)
485 throw new Nonexistant();
488 // Touch the diagram title calculation within this existence
490 g.syncRequest(new TitleRequest(editorID, this));
493 System.out.println("ResourceEditorInput2.assertExists(" + this + ") finished");
496 private void setNonExistant() {
498 System.out.println("setNonExistant(" + this + " @ " + System.identityHashCode(this) + ")");
501 tooltip = name = NO_NAME;
502 imageDesc = ImageDescriptor.getMissingImageDescriptor();
505 public IMemento getPersistentStore() {
506 return persistentStore;
510 public String toString() {
511 return getClass().getSimpleName() + " [name=" + getName() + ", resource=" + resource + ", model=" + model + ", rvi=" + rvi + "]";
515 * @see org.simantics.ui.workbench.IResourceEditorInput2#getVariable()
517 public Variable getVariable() throws DatabaseException {
518 return getSession().syncRequest(new Read<Variable>() {
520 public Variable perform(ReadGraph graph) throws DatabaseException {
521 return getVariable(graph);
527 * @see org.simantics.ui.workbench.IResourceEditorInput2#getVariable(org.simantics.db.ReadGraph)
529 public Variable getVariable(ReadGraph graph) throws DatabaseException {
530 Resource model = getModel(graph);
531 String rvi = getRVI();
534 Variable configuration = Variables.getConfigurationContext(graph, model);
535 RVI rrvi = RVI.fromResourceFormat(graph, rvi);
536 return rrvi.resolve(graph, configuration);
540 return Variables.getVariable(graph, model);
544 private Resource tryGetResource() {
545 Reference<Resource> ref = resource;
546 return ref == null ? null : ref.get();
549 private Resource tryGetModel() {
550 Reference<Resource> ref = model;
551 return ref == null ? null : ref.get();