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