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