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 }