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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.ui.workbench.editor.input;
\r
14 import java.util.Arrays;
\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
28 * Composable database read operations designed to be used for defining
\r
29 * validation strategies for resource editor inputs through composition.
\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
35 * @author Tuukka Lehtonen
\r
37 public final class InputValidationCombinators {
\r
40 * Returns a function:
\r
42 * = subject -> exists(URI(subject))
\r
46 public static ParametrizedRead<Resource, Boolean> hasURI() {
\r
51 * Returns a function:
\r
53 * = input -> resource(input)
\r
57 public static ParametrizedRead<IResourceEditorInput, Resource> extractInputResource() {
\r
58 return EXTRACT_INPUT_RESOURCE;
\r
62 * Returns a function:
\r
64 * = subject -> singleObject(subject, resource(relationURI))
\r
68 public static ParametrizedRead<Resource,Resource> completeFunction(String relationURI) {
\r
69 return new CompleteFunctionURI(relationURI);
\r
73 * Returns a function:
\r
75 * = subject -> possibleObject(subject, resource(relationURI))
\r
79 public static ParametrizedRead<Resource,Resource> partialFunction(String relationURI) {
\r
80 return new PartialFunctionURI(relationURI);
\r
84 * Returns a function:
\r
86 * = subject -> true if any of conditions is true for subject, false otherwise
\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
96 // ------------------------------------------------------------------------
\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
102 this.reads = reads;
\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
110 return Boolean.TRUE;
\r
112 return Boolean.FALSE;
\r
115 public int hashCode() {
\r
116 return super.hashCode() * 31 + Arrays.hashCode(reads);
\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
127 // ------------------------------------------------------------------------
\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
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
141 public int hashCode() {
\r
142 return getClass().hashCode() + 31 * Arrays.hashCode(reads);
\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
153 // ------------------------------------------------------------------------
\r
155 private static class HasURI extends UnaryRead<Resource, Boolean> {
\r
156 public HasURI(Resource resource) {
\r
160 public Boolean perform(ReadGraph graph) throws DatabaseException {
\r
161 if (parameter == null)
\r
162 return Boolean.FALSE;
\r
164 String uri = graph.syncRequest(Queries.possibleUri(parameter));
\r
165 //System.out.println("uri(" + parameter + "): " + uri);
\r
167 return Boolean.FALSE;
\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
174 Resource reverseLookup = graph.getPossibleResource(uri);
\r
175 //System.out.println("resource(" + uri + "): " + reverseLookup);
\r
176 return parameter.equals(reverseLookup);
\r
180 public static Read<Boolean> hasURI(Resource resource) {
\r
181 return new HasURI(resource);
\r
184 // ------------------------------------------------------------------------
\r
186 private static class ExtractResource extends UnaryRead<IResourceEditorInput, Resource> {
\r
187 public ExtractResource(IResourceEditorInput input) {
\r
191 public Resource perform(ReadGraph graph) throws DatabaseException {
\r
192 return parameter != null ? parameter.getResource() : null;
\r
196 public static Read<Resource> extractResource(IResourceEditorInput input) {
\r
197 return new ExtractResource(input);
\r
200 // ------------------------------------------------------------------------
\r
202 private static class PossibleObjectURI implements Read<Resource> {
\r
204 String relationURI;
\r
205 public PossibleObjectURI(Resource subject, String relationURI) {
\r
206 this.subject = subject;
\r
207 this.relationURI = relationURI;
\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
217 public int hashCode() {
\r
218 return subject.hashCode() + 31 * relationURI.hashCode();
\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
230 * Returns a read request that reads an object possibly connected to the subject by the relation.
\r
232 public static Read<Resource> possibleObject(Resource subject, String relationURI) {
\r
233 return new PossibleObjectURI(subject, relationURI);
\r
236 // ------------------------------------------------------------------------
\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
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
250 public int hashCode() {
\r
251 return getClass().hashCode() + 31 * relationURI.hashCode();
\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
262 // ------------------------------------------------------------------------
\r
264 private static class SingleObjectURI implements Read<Resource> {
\r
266 String relationURI;
\r
267 public SingleObjectURI(Resource subject, String relationURI) {
\r
268 this.subject = subject;
\r
269 this.relationURI = relationURI;
\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
279 public int hashCode() {
\r
280 return subject.hashCode() + 31 * relationURI.hashCode();
\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
292 * Returns a read request that reads a single object connected to the
\r
293 * subject by the relation.
\r
295 public static Read<Resource> singleObject(Resource subject, String relationURI) {
\r
296 return new SingleObjectURI(subject, relationURI);
\r
299 // ------------------------------------------------------------------------
\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
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
313 public int hashCode() {
\r
314 return getClass().hashCode() + 31 * relationURI.hashCode();
\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
325 // ------------------------------------------------------------------------
\r
327 private static final ParametrizedRead<IResourceEditorInput, Resource> EXTRACT_INPUT_RESOURCE = new ParametrizedRead<IResourceEditorInput, Resource>() {
\r
329 public Read<Resource> get(IResourceEditorInput input) {
\r
330 return extractResource(input);
\r
334 // ------------------------------------------------------------------------
\r
336 private static final ParametrizedRead<Resource, Boolean> HAS_URI = new ParametrizedRead<Resource, Boolean>() {
\r
338 public Read<Boolean> get(Resource resource) {
\r
339 return hasURI(resource);
\r