]> gerrit.simantics Code Review - simantics/platform.git/blob - 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
1 /*******************************************************************************
2  * Copyright (c) 2007, 2013 Association for Decentralized Information Management
3  * in Industry THTH ry.
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
8  *
9  * Contributors:
10  *     VTT Technical Research Centre of Finland - initial API and implementation
11  *     Semantum Oy - issue #4384
12  *******************************************************************************/
13 package org.simantics.ui.workbench;
14
15 import java.lang.ref.Reference;
16
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;
44
45 /**
46  * This is an input class for editors that have as their input the a tuple:
47  * (Input Resource, Model URI, RVI).
48  * 
49  * Editor extensions requiring these as input should always use
50  * {@link ResourceEditorInputMatchingStrategy} as their matchingStrategy.
51  * 
52  * @author Tuukka Lehtonen
53  * @see ResourceEditorInput
54  * @see ResourceEditorInputMatchingStrategy
55  */
56 public class ResourceEditorInput2 extends PlatformObject implements IResourceEditorInput2, IPersistableElement {
57
58     private final static boolean          DEBUG_EXISTS    = false;
59     private final static boolean          DEBUG_UPDATE    = false;
60
61     private static final String           NO_NAME         = ResourceEditorInput.NO_NAME;
62
63     private final String                  editorID;
64
65     /**
66      * A random access ID to {@link #resource}.
67      */
68     protected String                        modelId;
69
70     protected String                        rvi;
71
72     /**
73      * A random access ID to {@link #resource}.
74      */
75     private String                        resourceId;
76
77     private transient Reference<Resource> model;
78
79     private transient Reference<Resource> resource;
80
81     private transient boolean             exists;
82
83     private transient String              name;
84
85     private transient String              tooltip;
86
87     private transient ImageDescriptor     imageDesc;
88
89     /** Persistent memento for external data */
90     private final StringMemento           persistentStore = new StringMemento();
91
92     ResourceEditorInput2(String editorID, String resourceId, String modelId, String rvi) {
93         
94         if (editorID == null)
95             throw new IllegalArgumentException("null editor id");
96         if (resourceId == null)
97             throw new IllegalArgumentException("null resource id");
98
99         this.editorID = editorID;
100         this.resourceId = resourceId;
101         this.resource = null;
102         this.modelId = modelId;
103         this.model = null;
104         this.rvi = rvi;
105
106         setNonExistant();
107     }
108     
109     /**
110      * @param editorID
111      * @param resourceId
112      * @param modelURI
113      * @param rvi
114      */
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");
120
121         this.editorID = editorID;
122         this.resourceId = resourceId;
123         this.resource = null;
124         this.modelId = modelId;
125         this.model = null;
126         this.rvi = rvi.toString();
127
128         setNonExistant();
129     }
130
131     @Deprecated
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");
137         if (model == null)
138             throw new IllegalArgumentException("null model");
139
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);
145         this.rvi = rvi;
146
147         setNonExistant();
148     }
149     
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");
155         if (model == null)
156             throw new IllegalArgumentException("null model");
157
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;
164
165         setNonExistant();
166     }
167     
168     @Override
169     public void init(IAdaptable adapter) throws DatabaseException {
170         Resource r = getResource();
171         if (r != null)
172             updateCaches(getSession(), true);
173     }
174
175     @Override
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.
182         resource = null;
183         model = null;
184     }
185
186     /**
187      * @return a graph instance if it exists and has not yet been disposed,
188      *         <code>null</code> otherwise
189      */
190     public Session getSession() {
191         Session s = Simantics.getSession();
192         if (s.getService(LifecycleSupport.class).isClosed())
193             throw new IllegalStateException("database session is closed");
194         return s;
195     }
196
197     @Override
198     public boolean exists() {
199         return exists;
200     }
201
202     @Override
203     public boolean exists(ReadGraph graph) throws DatabaseException {
204         try {
205             assertExists(graph);
206             return true;
207         } catch (MissingVariableException e) {
208         } catch (ResourceNotFoundException e) {
209         } catch (Nonexistant e) {
210         }
211         return false;
212     }
213
214     public Resource getResource0() throws DatabaseException {
215         Resource r = tryGetResource();
216         if (r != null)
217             return r;
218
219         Session s = ResourceInputs.peekSession();
220         if (s == null)
221             return null;
222
223         r = ResourceInputs.resolveResource( s, resourceId );
224         this.resource = ResourceInputs.makeReference( r );
225         return r;
226     }
227
228     public Resource getModel0() throws DatabaseException {
229         Resource r = tryGetModel();
230         if (r != null)
231             return r;
232
233         Session s = ResourceInputs.peekSession();
234         if (s == null)
235             return null;
236
237         r = ResourceInputs.resolveResource( s, modelId );
238         this.model = ResourceInputs.makeReference( r );
239         return r;
240     }
241     
242     @Override
243     public Resource getResource() {
244         try {
245             return getResource0();
246         } catch (DatabaseException e) {
247             ErrorLogger.defaultLogError(e);
248             return null;
249         }
250     }
251
252     @Override
253     @Deprecated
254     public ResourceArray getResourceArray() {
255         Resource r = getResource();
256         return r == null ? ResourceArray.EMPTY : new ResourceArray(r);
257     }
258     
259     public Resource getModel(ReadGraph graph) {
260         try {
261             return getModel0();
262         } catch (DatabaseException e) {
263             ErrorLogger.defaultLogError(e);
264             return null;
265         }
266     }
267     
268
269     @Override
270     public String getRVI() {
271         return rvi;
272     }
273
274     /* (non-Javadoc)
275      * @see org.eclipse.ui.IEditorInput#getImageDescriptor()
276      */
277     @Override
278     public ImageDescriptor getImageDescriptor() {
279         return imageDesc;
280     }
281
282     /* (non-Javadoc)
283      * @see org.eclipse.ui.IEditorInput#getName()
284      */
285     @Override
286     public String getName() {
287         return name;
288     }
289
290     /* (non-Javadoc)
291      * @see org.eclipse.ui.IEditorInput#getToolTipText()
292      */
293     @Override
294     public String getToolTipText() {
295         return tooltip;
296     }
297
298     /* (non-Javadoc)
299      * @see org.eclipse.ui.IEditorInput#getPersistable()
300      */
301     @Override
302     public IPersistableElement getPersistable() {
303         // Don't allow persistability when it's not possible.
304         if (!isPersistable())
305             return null;
306         return this;
307     }
308
309     protected boolean isPersistable() {
310         Session session = Simantics.peekSession();
311         if (session == null)
312             return false;
313         LifecycleSupport lc = session.peekService(LifecycleSupport.class);
314         if (lc == null)
315             return false;
316         if (lc.isClosed())
317             return false;
318         return true;
319     }
320
321     /* (non-Javadoc)
322      * @see org.eclipse.ui.IPersistableElement#getFactoryId()
323      */
324     @Override
325     public String getFactoryId() {
326         return ResourceEditorInputFactory2.getFactoryId();
327     }
328
329     /**
330      * Saves the state of the given resource editor input into the given memento.
331      *
332      * @param memento the storage area for element state
333      * @see org.eclipse.ui.IPersistable#saveState(org.eclipse.ui.IMemento)
334      */
335     @Override
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());
343     }
344
345     /* (non-Javadoc)
346      * @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
347      */
348     @SuppressWarnings("rawtypes")
349     @Override
350     public Object getAdapter(Class adapter) {
351         //System.out.println("[ResourceEditorInput] getAdapter: " + adapter.getName());
352         return null;
353     }
354
355     @Override
356     public int hashCode() {
357         final int prime = 31;
358         int result = 1;
359         result = prime * result + editorID.hashCode();
360         // modelURI and rvi may change => can't use either in hashcode.
361 //        result = prime * result + ObjectUtils.hashCode(modelURI);
362 //        result = prime * result + ObjectUtils.hashCode(rvi);
363         result = prime * result + ObjectUtils.hashCode(modelId);
364         result = prime * result + ObjectUtils.hashCode(resourceId);
365         return result;
366     }
367
368     @Override
369     public boolean equals(Object obj) {
370         if (this == obj)
371             return true;
372         if (obj == null)
373             return false;
374         if (getClass() != obj.getClass())
375             return false;
376         ResourceEditorInput2 other = (ResourceEditorInput2) obj;
377         if (!editorID.equals(other.editorID))
378             return false;
379         if (!ObjectUtils.objectEquals(modelId, other.modelId))
380             return false;
381         if (!ObjectUtils.objectEquals(rvi, other.rvi))
382             return false;
383         if (!ObjectUtils.objectEquals(resourceId, other.resourceId))
384             return false;
385         return true;
386     }
387
388     private void updateCaches(RequestProcessor processor, boolean sync) throws DatabaseException {
389         ReadRequest req = new ReadRequest() {
390             @Override
391             public void run(ReadGraph g) throws DatabaseException {
392                 update(g);
393             }
394         };
395         if (sync) {
396             processor.syncRequest(req);
397         } else {
398             processor.asyncRequest(req);
399         }
400     }
401
402     static class Nonexistant extends DatabaseException {
403         private static final long serialVersionUID = -7964385375237203651L;
404
405         @Override
406         public synchronized Throwable fillInStackTrace() {
407             return this;
408         }
409     }
410
411     /* (non-Javadoc)
412      * @see org.simantics.ui.workbench.IResourceEditorInput#update(org.simantics.db.Graph)
413      */
414     @Override
415     public void update(ReadGraph g) throws DatabaseException {
416         Resource r = getResource();
417         if (r == null)
418             return;
419
420         if (DEBUG_UPDATE)
421             System.out.println("update(" + this + ")");
422
423         try {
424             assertExists(g);
425
426             name = g.syncRequest(new TitleRequest(editorID, this));
427             if (name == null)
428                 name = NO_NAME;
429
430             tooltip = g.syncRequest(new ToolTipRequest(editorID, this));
431             if (tooltip == null)
432                 tooltip = NO_NAME;
433
434             try {
435                 ImageDescriptorProvider idp = g.adapt(r, ImageDescriptorProvider.class);
436                 imageDesc = idp.get();
437             } catch (AdaptionException e) {
438                 imageDesc = ImageDescriptor.getMissingImageDescriptor();
439             } catch (ProvisionException e) {
440                 imageDesc = ImageDescriptor.getMissingImageDescriptor();
441                 ErrorLogger.defaultLogError(e);
442             }
443
444             if (DEBUG_UPDATE)
445                 System.out.println("update(" + this + ") finished");
446         } catch (DatabaseException e) {
447             if (DEBUG_UPDATE)
448                 e.printStackTrace();
449             setNonExistant();
450         }
451     }
452
453     private void assertExists(ReadGraph g) throws DatabaseException {
454         if (DEBUG_EXISTS)
455             System.out.println("ResourceEditorInput2.assertExists(" + this + ") begins");
456
457         // 1. Check resource existence
458         Resource r = getResource();
459         if (r == null)
460             throw new Nonexistant();
461
462         exists = g.hasStatement(r);
463         if (!exists)
464             throw new Nonexistant();
465
466         // 2. Check model existence
467         Resource model = getModel(g);
468         if (model == null)
469             throw new Nonexistant();
470
471         exists = g.hasStatement(model);
472         if (!exists)
473             throw new Nonexistant();
474
475         // 3. Validate rvi
476         if (DEBUG_EXISTS)
477                 System.out.println("validating rvi: '" + rvi + "'");
478
479         if(rvi != null && !rvi.isEmpty()) {
480                 Variable context = Variables.getPossibleConfigurationContext(g, model);
481                 if (context == null)
482                         throw new Nonexistant();
483                 RVI rvi_ = RVI.fromResourceFormat(g, rvi);
484                 Variable variable = rvi_.resolvePossible(g, context);
485                 if (variable == null)
486                         throw new Nonexistant();
487         }
488
489         // Touch the diagram title calculation within this existence
490         // checking request.
491         g.syncRequest(new TitleRequest(editorID, this));
492
493         if (DEBUG_EXISTS)
494             System.out.println("ResourceEditorInput2.assertExists(" + this + ") finished");
495     }
496
497     private void setNonExistant() {
498         if (DEBUG_UPDATE)
499             System.out.println("setNonExistant(" + this + " @ " + System.identityHashCode(this) + ")");
500
501         exists = false;
502         tooltip = name = NO_NAME;
503         imageDesc = ImageDescriptor.getMissingImageDescriptor();
504     }
505
506     public IMemento getPersistentStore() {
507         return persistentStore;
508     }
509
510     @Override
511     public String toString() {
512         return getClass().getSimpleName() + " [name=" + getName() + ", resource=" + resource + ", model=" + model + ", rvi=" + rvi + "]";
513     }
514
515     /**
516      * @see org.simantics.ui.workbench.IResourceEditorInput2#getVariable()
517      */
518     public Variable getVariable() throws DatabaseException {
519         return getSession().syncRequest(new Read<Variable>() {
520             @Override
521             public Variable perform(ReadGraph graph) throws DatabaseException {
522                 return getVariable(graph);
523             }
524         });
525     }
526
527     /**
528      * @see org.simantics.ui.workbench.IResourceEditorInput2#getVariable(org.simantics.db.ReadGraph)
529      */
530     public Variable getVariable(ReadGraph graph) throws DatabaseException {
531         Resource model = getModel(graph);
532         String rvi = getRVI();
533         // Model + RVI
534         if (rvi != null) {
535             Variable configuration = Variables.getConfigurationContext(graph, model);
536             RVI rrvi = RVI.fromResourceFormat(graph, rvi);
537             return rrvi.resolve(graph, configuration);
538         }
539         // Absolute URI
540         else {
541             return Variables.getVariable(graph, model);
542         }
543     }
544
545     private Resource tryGetResource() {
546         Reference<Resource> ref = resource;
547         return ref == null ? null : ref.get();
548     }
549
550     private Resource tryGetModel() {
551         Reference<Resource> ref = model;
552         return ref == null ? null : ref.get();
553     }
554
555 }