]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.ui/src/org/simantics/ui/workbench/editor/input/InputValidationCombinators.java
9b2c1e06ccebf16650796d94b20c2ba768219e45
[simantics/platform.git] / bundles / org.simantics.ui / src / org / simantics / ui / workbench / editor / input / InputValidationCombinators.java
1 /*******************************************************************************
2  * Copyright (c) 2007, 2010 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  *******************************************************************************/
12 package org.simantics.ui.workbench.editor.input;
13
14 import java.util.Arrays;
15
16 import org.simantics.db.ReadGraph;
17 import org.simantics.db.Resource;
18 import org.simantics.db.common.request.ParametrizedRead;
19 import org.simantics.db.common.request.Queries;
20 import org.simantics.db.common.request.UnaryRead;
21 import org.simantics.db.exception.DatabaseException;
22 import org.simantics.db.layer0.request.combinations.Combinators;
23 import org.simantics.db.layer0.request.combinations.Combinators.SynchronizationProcedure;
24 import org.simantics.db.request.Read;
25 import org.simantics.ui.workbench.IResourceEditorInput;
26
27 /**
28  * Composable database read operations designed to be used for defining
29  * validation strategies for resource editor inputs through composition.
30  * 
31  * <p>
32  * For example one validation criterion might be that the editor input or one of
33  * its neighboring resources must have a proper URI.
34  * 
35  * @author Tuukka Lehtonen
36  */
37 public final class InputValidationCombinators {
38
39     /**
40      * Returns a function:
41      * <pre>
42      *   = subject -> exists(URI(subject))
43      *   | null    -> false
44      * </pre>.
45      */
46     public static ParametrizedRead<Resource, Boolean> hasURI() {
47         return HAS_URI;
48     }
49
50     /**
51      * Returns a function:
52      * <pre>
53      *   = input -> resource(input)
54      *   | null  -> null
55      * </pre>.
56      */
57     public static ParametrizedRead<IResourceEditorInput, Resource> extractInputResource() {
58         return EXTRACT_INPUT_RESOURCE;
59     }
60
61     /**
62      * Returns a function:
63      * <pre>
64      *   = subject -> singleObject(subject, resource(relationURI))
65      *   | null    -> null
66      * </pre>.
67      */
68     public static ParametrizedRead<Resource,Resource> completeFunction(String relationURI) {
69         return new CompleteFunctionURI(relationURI);
70     }
71
72     /**
73      * Returns a function:
74      * <pre>
75      *   = subject -> possibleObject(subject, resource(relationURI))
76      *   | null    -> null
77      * </pre>.
78      */
79     public static ParametrizedRead<Resource,Resource> partialFunction(String relationURI) {
80         return new PartialFunctionURI(relationURI);
81     }
82
83     /**
84      * Returns a function:
85      * <pre>
86      *   = subject -> true if any of conditions is true for subject, false otherwise
87      *   | null    -> true
88      * </pre>.
89      */
90     @SuppressWarnings("unchecked")
91     public static ParametrizedRead<Resource, Boolean> or(ParametrizedRead<Resource, Boolean> c1,
92             ParametrizedRead<Resource, Boolean> c2) {
93         return new FunctionOr(new ParametrizedRead[] { c1, c2 });
94     }
95
96     // ------------------------------------------------------------------------
97
98     private static class Or extends UnaryRead<Resource, Boolean> {
99         ParametrizedRead<Resource, Boolean>[] reads;
100         public Or(Resource resource, ParametrizedRead<Resource, Boolean>... reads) {
101             super(resource);
102             this.reads = reads;
103         }
104         @Override
105         public Boolean perform(ReadGraph graph) throws DatabaseException {
106             for (ParametrizedRead<Resource, Boolean> r : reads) {
107                 Read<Boolean> read = r.get(parameter);
108                 Boolean value = graph.syncRequest( read );
109                 if (value)
110                     return Boolean.TRUE;
111             }
112             return Boolean.FALSE;
113         }
114         @Override
115         public int hashCode() {
116             return super.hashCode() * 31 + Arrays.hashCode(reads);
117         }
118         @Override
119         public boolean equals(Object object) {
120             if (this == object) return true;
121             else if (object == null || getClass() != object.getClass()) return false;
122             Or other = (Or) object;
123             return super.equals(object) && Arrays.equals(reads, other.reads);
124         }
125     }
126
127     // ------------------------------------------------------------------------
128
129     private static class FunctionOr implements ParametrizedRead<Resource, Boolean> {
130         ParametrizedRead<Resource, Boolean>[] reads;
131         public FunctionOr(ParametrizedRead<Resource, Boolean>... reads) {
132             this.reads = reads;
133         }
134         @Override
135         public Read<Boolean> get(Resource subject) {
136             if (subject == null || reads.length == 0)
137                 return Combinators.constant(Boolean.TRUE);
138             return new Or(subject, reads);
139         }
140         @Override
141         public int hashCode() {
142             return getClass().hashCode() + 31 * Arrays.hashCode(reads);
143         }
144         @Override
145         public boolean equals(Object obj) {
146             if(obj == this) return true;
147             if(obj == null || obj.getClass() != getClass()) return false;
148             FunctionOr other = (FunctionOr)obj;
149             return Arrays.equals(reads, other.reads);
150         }
151     }
152
153     // ------------------------------------------------------------------------
154
155     private static class HasURI extends UnaryRead<Resource, Boolean> {
156         public HasURI(Resource resource) {
157             super(resource);
158         }
159         @Override
160         public Boolean perform(ReadGraph graph) throws DatabaseException {
161             if (parameter == null)
162                 return Boolean.FALSE;
163
164             String uri = graph.syncRequest(Queries.possibleUri(parameter));
165             //System.out.println("uri(" + parameter + "): " + uri);
166             if (uri == null)
167                 return Boolean.FALSE;
168
169             // FIXME: URI request will return invalid URIs, like
170             // null/Configuration/MyComposite after deleting the parenting model
171             // For this reason we try to reverse lookup the URI back into a
172             // resource which must be equal to the original parameter resource.
173
174             Resource reverseLookup = graph.getPossibleResource(uri);
175             //System.out.println("resource(" + uri + "): " + reverseLookup);
176             return parameter.equals(reverseLookup);
177         }
178     }
179
180     public static Read<Boolean> hasURI(Resource resource) {
181         return new HasURI(resource);
182     }
183
184     // ------------------------------------------------------------------------
185
186     private static class ExtractResource extends UnaryRead<IResourceEditorInput, Resource> {
187         public ExtractResource(IResourceEditorInput input) {
188             super(input);
189         }
190         @Override
191         public Resource perform(ReadGraph graph) throws DatabaseException {
192             return parameter != null ? parameter.getResource() : null;
193         }
194     }
195
196     public static Read<Resource> extractResource(IResourceEditorInput input) {
197         return new ExtractResource(input);
198     }
199
200     // ------------------------------------------------------------------------
201
202     private static class PossibleObjectURI implements Read<Resource> {
203         Resource subject;
204         String relationURI;
205         public PossibleObjectURI(Resource subject, String relationURI) {
206             this.subject = subject;
207             this.relationURI = relationURI;
208         }
209         @Override
210         public Resource perform(ReadGraph graph) throws DatabaseException {
211             SynchronizationProcedure<Resource> procedure = new SynchronizationProcedure<Resource>();
212             Resource relation = graph.getResource(relationURI);
213             graph.forPossibleObject(subject, relation, procedure);
214             return procedure.getResult();
215         }
216         @Override
217         public int hashCode() {
218             return subject.hashCode() + 31 * relationURI.hashCode();
219         }
220         @Override
221         public boolean equals(Object object) {
222             if (this == object) return true;
223             else if (object == null || getClass() != object.getClass()) return false;
224             PossibleObjectURI other = (PossibleObjectURI)object;
225             return subject.equals(other.subject) && relationURI.equals(other.relationURI);
226         }
227     }
228
229     /**
230      * Returns a read request that reads an object possibly connected to the subject by the relation.
231      */
232     public static Read<Resource> possibleObject(Resource subject, String relationURI) {
233         return new PossibleObjectURI(subject, relationURI);
234     }
235
236     // ------------------------------------------------------------------------
237
238     private static class PartialFunctionURI implements ParametrizedRead<Resource, Resource> {
239         String relationURI;
240         public PartialFunctionURI(String relationURI) {
241             this.relationURI = relationURI;
242         }
243         @Override
244         public Read<Resource> get(Resource subject) {
245             if (subject == null)
246                 return Combinators.constant(null);
247             return possibleObject(subject, relationURI);
248         }
249         @Override
250         public int hashCode() {
251             return getClass().hashCode() + 31 * relationURI.hashCode();
252         }
253         @Override
254         public boolean equals(Object obj) {
255             if(obj == this) return true;
256             if(obj == null || obj.getClass() != getClass()) return false;
257             PartialFunctionURI other = (PartialFunctionURI)obj;
258             return relationURI.equals(other.relationURI);
259         }
260     }
261
262     // ------------------------------------------------------------------------
263
264     private static class SingleObjectURI implements Read<Resource> {
265         Resource subject;
266         String relationURI;
267         public SingleObjectURI(Resource subject, String relationURI) {
268             this.subject = subject;
269             this.relationURI = relationURI;
270         }
271         @Override
272         public Resource perform(ReadGraph graph) throws DatabaseException {
273             SynchronizationProcedure<Resource> procedure = new SynchronizationProcedure<Resource>();
274             Resource relation = graph.getResource(relationURI);
275             graph.forSingleObject(subject, relation, procedure);
276             return procedure.getResult();
277         }
278         @Override
279         public int hashCode() {
280             return subject.hashCode() + 31 * relationURI.hashCode();
281         }
282         @Override
283         public boolean equals(Object object) {
284             if (this == object) return true;
285             else if (object == null || getClass() != object.getClass()) return false;
286             SingleObjectURI other = (SingleObjectURI) object;
287             return subject.equals(other.subject) && relationURI.equals(other.relationURI);
288         }
289     }
290
291     /**
292      * Returns a read request that reads a single object connected to the
293      * subject by the relation.
294      */
295     public static Read<Resource> singleObject(Resource subject, String relationURI) {
296         return new SingleObjectURI(subject, relationURI);
297     }
298
299     // ------------------------------------------------------------------------
300
301     private static class CompleteFunctionURI implements ParametrizedRead<Resource, Resource> {
302         String relationURI;
303         public CompleteFunctionURI(String relationURI) {
304             this.relationURI = relationURI;
305         }
306         @Override
307         public Read<Resource> get(Resource subject) {
308             if (subject == null)
309                 return Combinators.constant(null);
310             return singleObject(subject, relationURI);
311         }
312         @Override
313         public int hashCode() {
314             return getClass().hashCode() + 31 * relationURI.hashCode();
315         }
316         @Override
317         public boolean equals(Object obj) {
318             if(obj == this) return true;
319             if(obj == null || obj.getClass() != getClass()) return false;
320             CompleteFunctionURI other = (CompleteFunctionURI)obj;
321             return relationURI.equals(other.relationURI);
322         }
323     }
324
325     // ------------------------------------------------------------------------
326
327     private static final ParametrizedRead<IResourceEditorInput, Resource> EXTRACT_INPUT_RESOURCE = new ParametrizedRead<IResourceEditorInput, Resource>() {
328         @Override
329         public Read<Resource> get(IResourceEditorInput input) {
330             return extractResource(input);
331         }
332     };
333
334     // ------------------------------------------------------------------------
335
336     private static final ParametrizedRead<Resource, Boolean> HAS_URI = new ParametrizedRead<Resource, Boolean>() {
337         @Override
338         public Read<Boolean> get(Resource resource) {
339             return hasURI(resource);
340         }
341     };
342
343 }