View Javadoc

1   /*	
2   	Copyright 2007-2014 Fraunhofer IGD, http://www.igd.fraunhofer.de
3   	Fraunhofer-Gesellschaft - Institute for Computer Graphics Research
4   	
5   	See the NOTICE file distributed with this work for additional 
6   	information regarding copyright ownership
7   	
8   	Licensed under the Apache License, Version 2.0 (the "License");
9   	you may not use this file except in compliance with the License.
10  	You may obtain a copy of the License at
11  	
12  	  http://www.apache.org/licenses/LICENSE-2.0
13  	
14  	Unless required by applicable law or agreed to in writing, software
15  	distributed under the License is distributed on an "AS IS" BASIS,
16  	WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  	See the License for the specific language governing permissions and
18  	limitations under the License.
19   */
20  package org.universAAL.middleware.owl;
21  
22  import java.util.HashMap;
23  import java.util.Hashtable;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  import org.universAAL.middleware.rdf.Resource;
28  import org.universAAL.middleware.util.MatchLogEntry;
29  
30  /**
31   * A class for the concept of OWL class expressions and OWL data ranges, which
32   * represent sets of individuals by formally specifying conditions on the
33   * individuals' properties. Example conditions are intersection of individuals,
34   * or restrictions. Each type expression represents a set of individuals (just
35   * like a class in an object-oriented programming language represents a set of
36   * objects). There are three main methods to compare type expression:
37   * <ul>
38   * <li>
39   * hasMember: determines if the given object is a member of the class
40   * represented by this type expression</li>
41   * <li>
42   * matches: determines if the given type expression is a subset of the class
43   * represented by this type expression</li>
44   * <li>
45   * isDisjointWith: determines if the given type expression has no member in
46   * common with the class represented by this type expression</li>
47   * </ul>
48   * 
49   * All three methods have three parameters in common:
50   * <ul>
51   * <li>
52   * context: context of the matchmaking. The <code>context</code> table maps the
53   * URIs of certain variables onto values currently assigned to them. The
54   * variables are either standard variables managed by the universAAL middleware
55   * or parameters of a specific service in whose context this method is called.
56   * If there is already a value assigned to such a referenced variable, it must
57   * be replaced by the associated value, otherwise this method may expand the
58   * <code>context</code> table by deriving a value for such unassigned but
59   * referenced variables with which the goal of the method can be asserted. In
60   * case of returning true, the caller must check the size of the
61   * <code>context</code> table to see if new conditions are added in. If the
62   * <code>context</code> map is null, the method does a global and unconditional
63   * check.</li>
64   * <li>
65   * ttl: time-to-live parameter. For each subsequent call to one of these methods
66   * the ttl parameter is decreased by one. If it reaches zero, an
67   * {@link IllegalArgumentException} is thrown with the text provided in
68   * {@link #EXCEPTION_TTL}. This can be used to avoid cycles in the type
69   * expression.</li>
70   * <li>
71   * log: list that can be filled with log entries and that shows at which point
72   * the matchmaking failed. May be null.</li>
73   * </ul>
74   * 
75   * 
76   * @author mtazari - <a href="mailto:Saied.Tazari@igd.fraunhofer.de">Saied
77   *         Tazari</a>
78   * @author Carsten Stockloew
79   */
80  public abstract class TypeExpression extends Resource {
81  
82      /** URI namespace for OWL. */
83      public static final String OWL_NAMESPACE = "http://www.w3.org/2002/07/owl#";
84  
85      /** URI for owl:Thing. */
86      public static final String TYPE_OWL_THING = OWL_NAMESPACE + "Thing";
87  
88      /** URI for rdfs:Datatype. */
89      public static final String RDFS_DATATYPE = Resource.RDFS_NAMESPACE
90  	    + "Datatype";
91  
92      /** URI for owl:class. */
93      public static final String OWL_CLASS = OWL_NAMESPACE + "Class";
94  
95      /** URI for rdfs:subClassOf. */
96      public static final String PROP_RDFS_SUB_CLASS_OF = Resource.RDFS_NAMESPACE
97  	    + "subClassOf";
98  
99      private static final int TTL = 100;
100 
101     public static final String EXCEPTION_TTL = "TTL exceeded. Maybe the TypeExpression has a cycle!";
102 
103     /** Constructor for use with serializers. */
104     protected TypeExpression() {
105 	super();
106 	addType(OWL_CLASS, true);
107     }
108 
109     /** Constructor to create a new instance with the given URI. */
110     protected TypeExpression(String uri) {
111 	super(uri);
112 	addType(OWL_CLASS, true);
113     }
114 
115     /** Constructor. */
116     protected TypeExpression(String[] additionalTypes) {
117 	super();
118 	addType(OWL_CLASS, false);
119 	for (int i = 0; i < additionalTypes.length - 1; i++)
120 	    addType(additionalTypes[i], false);
121 	if (additionalTypes.length - 1 >= 0)
122 	    addType(additionalTypes[additionalTypes.length - 1], true);
123     }
124 
125     /**
126      * Provided that the given list is already a minimized list of type URIs,
127      * i.e. no two members have any hierarchical relationships with each other,
128      * adds the given typeURI to the list so that the above condition continues
129      * to hold and no information is lost. In case of a hierarchical
130      * relationship, the given typeURI is added if it is more specialized, i.e.
131      * a sub class, than any existing type (the less spcialized, i.e. a super
132      * class, is then removed from the list).
133      */
134     protected void collectTypesMinimized(String typeURI, List l) {
135 	if (typeURI != null) {
136 	    boolean toAdd = true;
137 	    for (Iterator j = l.iterator(); j.hasNext();) {
138 		String uri = (String) j.next();
139 		if (ManagedIndividual.checkCompatibility(uri, typeURI)) {
140 		    j.remove();
141 		    break;
142 		} else if (ManagedIndividual.checkCompatibility(typeURI, uri)) {
143 		    toAdd = false;
144 		    break;
145 		}
146 	    }
147 	    if (toAdd)
148 		l.add(typeURI);
149 	}
150     }
151 
152     /**
153      * Create a copy of this object, i.e. create a new object of this class and
154      * copy the necessary properties.
155      * 
156      * @return The newly created copy.
157      */
158     public abstract TypeExpression copy();
159 
160     /**
161      * Get the set of class URIs for all super classes of the individuals of
162      * this class expression.
163      */
164     public abstract String[] getNamedSuperclasses();
165 
166     /**
167      * Each type expression can contain multiple objects; this method returns
168      * this set of objects.
169      */
170     public abstract Object[] getUpperEnumeration();
171 
172     /**
173      * Returns <tt>true</tt> if the given object is a member of the class
174      * represented by this type expression, otherwise false.
175      * 
176      * @param member
177      *            the object whose membership is going to be checked
178      * @return <tt>true</tt> if the specified member is a member of this type
179      *         expression
180      */
181     public final boolean hasMember(Object member) {
182 	return hasMember(member, null, TTL, null);
183     }
184 
185     /**
186      * @deprecated replaced by {@link #hasMember(Object, HashMap, int, List)}.
187      */
188     public final boolean hasMember(Object member, Hashtable context) {
189 	HashMap map = context == null ? null : new HashMap(context);
190 	boolean res = hasMember(member, map, TTL, null);
191 	if (map != null) {
192 	    context.clear();
193 	    context.putAll(map);
194 	}
195 	return res;
196     }
197 
198     /**
199      * Returns <tt>true</tt> if the given object is a member of the class
200      * represented by this type expression, otherwise false. The
201      * <code>context</code> table maps the URIs of certain variables onto values
202      * currently assigned to them. The variables are either standard variables
203      * managed by the universAAL middleware or parameters of a specific service
204      * in whose context this method is called. Both the object whose membership
205      * is going to be checked and this type expression may contain references to
206      * such variables. If there is already a value assigned to such a referenced
207      * variable, it must be replaced by the associated value, otherwise this
208      * method may expand the <code>context</code> table by deriving a value for
209      * such unassigned but referenced variables with which the membership can be
210      * asserted. In case of returning true, the caller must check the size of
211      * the <code>context</code> table to see if new conditions are added in
212      * order for the membership to be asserted. If the <code>context</code>
213      * table is null, the method does a global and unconditional check.
214      * 
215      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_ACCESSING_BUS_MEMBER
216      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_ACCESSING_HUMAN_USER
217      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_CURRENT_DATETIME
218      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_SERVICE_TO_SELECT
219      * 
220      * @param member
221      *            the object whose membership is going to be checked
222      * @param context
223      *            context of the matchmaking. May be null.
224      * @param ttl
225      *            time-to-live parameter
226      * @param log
227      *            list that can be filled with log entries. May be null.
228      * @return <tt>true</tt> if the specified member is a member of this type
229      *         expression
230      */
231     public abstract boolean hasMember(Object member, HashMap context, int ttl,
232 	    List<MatchLogEntry> log);
233 
234     /**
235      * Returns <tt>true</tt> if the given type expression has no member in
236      * common with the class represented by this type expression, otherwise
237      * false.
238      * 
239      * @param other
240      *            the type expression with which the disjointness is going to be
241      *            checked
242      * @return <tt>true</tt> if the given type expression has no member in
243      *         common with the class represented by this type expression,
244      *         otherwise false
245      */
246     public final boolean isDisjointWith(TypeExpression other) {
247 	return isDisjointWith(other, null, TTL, null);
248     }
249 
250     /**
251      * @deprecated replaced by
252      *             {@link #isDisjointWith(Object, HashMap, int, List)}.
253      */
254     public final boolean isDisjointWith(TypeExpression other, Hashtable context) {
255 	HashMap map = context == null ? null : new HashMap(context);
256 	boolean res = isDisjointWith(other, map, TTL, null);
257 	if (map != null) {
258 	    context.clear();
259 	    context.putAll(map);
260 	}
261 	return res;
262     }
263 
264     /**
265      * Returns <tt>true</tt> if the given type expression has no member in
266      * common with the class represented by this type expression, otherwise
267      * false. The <code>context</code> table maps the URIs of certain variables
268      * onto values currently assigned to them. The variables are either standard
269      * variables managed by the universAAL middleware or parameters of a
270      * specific service in whose context this method is called. Both of the type
271      * expressions may contain references to such variables. If there is already
272      * a value assigned to such a referenced variable, it must be replaced by
273      * the associated value, otherwise this method may expand the
274      * <code>context</code> table by deriving a value for such unassigned but
275      * referenced variables with which the disjointness of the two classes can
276      * be asserted. In case of returning true, the caller must check the size of
277      * the <code>context</code> table to see if new conditions are added in
278      * order for the disjointness to be asserted. If the <code>context</code>
279      * table is null, the method does a global and unconditional check.
280      * 
281      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_ACCESSING_BUS_MEMBER
282      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_ACCESSING_HUMAN_USER
283      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_CURRENT_DATETIME
284      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_SERVICE_TO_SELECT
285      * 
286      * @param other
287      *            the type expression with which the disjointness is going to be
288      *            checked
289      * @param context
290      *            context of the matchmaking. May be null.
291      * @param ttl
292      *            time-to-live parameter
293      * @param log
294      *            list that can be filled with log entries. May be null.
295      * @return <tt>true</tt> if the given type expression has no member in
296      *         common with the class represented by this type expression,
297      *         otherwise false
298      */
299     public abstract boolean isDisjointWith(TypeExpression other,
300 	    HashMap context, int ttl, List<MatchLogEntry> log);
301 
302     /**
303      * Returns <tt>true</tt>, if the state of the resource is valid, otherwise
304      * false. Redefined in this class as abstract to force subclasses to
305      * override it.
306      * 
307      * @see org.universAAL.middleware.rdf.Resource#isWellFormed()
308      */
309     public abstract boolean isWellFormed();
310 
311     /**
312      * Returns <tt>true</tt> if the given type expression is a subset of the
313      * class represented by this type expression, otherwise false.
314      * 
315      * @param subset
316      *            the type expression with which the compatibility is going to
317      *            be checked
318      * @return <tt>true</tt> if the given type expression is a subset of the
319      *         class represented by this type expression, otherwise false
320      */
321     public final boolean matches(TypeExpression subset) {
322 	return matches(subset, null, TTL, null);
323     }
324 
325     /**
326      * @deprecated replaced by {@link #matches(Object, HashMap, int, List)}.
327      */
328     public final boolean matches(TypeExpression subset, Hashtable context) {
329 	HashMap map = context == null ? null : new HashMap(context);
330 	boolean res = matches(subset, map, TTL, null);
331 	if (map != null) {
332 	    context.clear();
333 	    context.putAll(map);
334 	}
335 	return res;
336     }
337 
338     /**
339      * Returns true if the given type expression is a subset of the class
340      * represented by this type expression, otherwise false. The
341      * <code>context</code> table maps the URIs of certain variables onto values
342      * currently assigned to them. The variables are either standard variables
343      * managed by the universAAL middleware or parameters of a specific service
344      * in whose context this method is called. Both of the type expressions may
345      * contain references to such variables. If there is already a value
346      * assigned to such a referenced variable, it must be replaced by the
347      * associated value, otherwise this method may expand the
348      * <code>context</code> table by deriving a value for such unassigned but
349      * referenced variables with which the compatibility of the two classes can
350      * be asserted. In case of returning true, the caller must check the size of
351      * the <code>context</code> table to see if new conditions are added in
352      * order for the compatibility to be asserted. If the <code>context</code>
353      * table is null, the method does a global and unconditional check.
354      * 
355      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_ACCESSING_BUS_MEMBER
356      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_ACCESSING_HUMAN_USER
357      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_CURRENT_DATETIME
358      * @see org.universAAL.middleware.util.Constants#VAR_uAAL_SERVICE_TO_SELECT
359      * @param subset
360      *            the type expression with which the compatibility is going to
361      *            be checked
362      * @param context
363      *            context of the matchmaking. May be null.
364      * @param ttl
365      *            time-to-live parameter
366      * @param log
367      *            list that can be filled with log entries. May be null.
368      * @return <tt>true</tt> if the given type expression is a subset of the
369      *         class represented by this type expression, otherwise false
370      */
371     public abstract boolean matches(TypeExpression subset, HashMap context,
372 	    int ttl, List<MatchLogEntry> log);
373 
374     /**
375      * Synchronize two HashMap to ensure that the first HashMap contains a value
376      * for each key of the second HashMap. The values themselves are not
377      * checked; if 'cloned' contains a key which is not contained in 'context',
378      * then the according (key/value)-pair is added to 'context'. The second
379      * HashMap, 'cloned', is not changed.
380      * 
381      * @param context
382      *            The HashMap to be extended by (key/value)-pairs from the
383      *            second HashMap.
384      * @param cloned
385      *            The second HashMap.
386      */
387     protected void synchronize(HashMap context, HashMap cloned) {
388 	if (cloned != null && cloned.size() > context.size()) {
389 	    for (Iterator i = cloned.keySet().iterator(); i.hasNext();) {
390 		Object key = i.next();
391 		if (!context.containsKey(key))
392 		    context.put(key, cloned.get(key));
393 	    }
394 	}
395     }
396 
397     /**
398      * Check the time-to-live parameter. If this value is zero, the method will
399      * throw an {@link IllegalArgumentException}, otherwise the parameter will
400      * be decreased by one and returned.
401      * 
402      * @throws IllegalArgumentException
403      *             if the specified value is zero.
404      * @param ttl
405      *            the time-to-live value
406      * @return the time-to-live value decreased by one
407      */
408     protected int checkTTL(int ttl) {
409 	if (ttl < 0)
410 	    ttl = getDefaultMatchmakingTTL();
411 	ttl--;
412 	if (ttl < 0)
413 	    throw new IllegalArgumentException(EXCEPTION_TTL);
414 	return ttl;
415     }
416 
417     /**
418      * Returns the default value for time-to-live.
419      * 
420      * @return the default value for time-to-live
421      */
422     public final static int getDefaultMatchmakingTTL() {
423 	return TTL;
424     }
425 }