View Javadoc

1   /*
2    wsmo4j - a WSMO API and Reference Implementation
3    Copyright (c) 2005, University of Innsbruck, Austria
4    This library is free software; you can redistribute it and/or modify it under
5    the terms of the GNU Lesser General Public License as published by the Free
6    Software Foundation; either version 2.1 of the License, or (at your option)
7    any later version.
8    This library is distributed in the hope that it will be useful, but WITHOUT
9    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
10   FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
11   details.
12   You should have received a copy of the GNU Lesser General Public License along
13   with this library; if not, write to the Free Software Foundation, Inc.,
14   59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
15   */
16  package org.deri.wsmo4j.validator;
17  
18  
19  import java.util.*;
20  import java.util.Map.Entry;
21  
22  import org.omwg.logicalexpression.*;
23  import org.omwg.logicalexpression.terms.Term;
24  import org.omwg.ontology.*;
25  import org.wsmo.common.*;
26  import org.wsmo.common.exception.*;
27  import org.wsmo.factory.LogicalExpressionFactory;
28  import org.wsmo.validator.ValidationError;
29  import org.wsmo.validator.ValidationWarning;
30  
31  
32  /**
33   * Checks an ontology for wsml-dl validity.
34   *
35   * <pre>
36   *  Created on Aug 18, 2005
37   *  Committed by $Author: morcen $
38   *  $Source$,
39   * </pre>
40   *
41   * @author Holger Lausen (holger.lausen@deri.org)
42   * @author nathalie.steinmetz@deri.org
43   * @version $Revision: 1946 $ $Date: 2007-04-02 15:13:28 +0300 (Mon, 02 Apr 2007) $
44   */
45  public class WsmlDLValidator
46          extends WsmlFullValidator {
47  
48      public List <Term> idConcepts = new Vector <Term> ();
49      
50      public List <Term> explicitConcepts = new Vector <Term> ();
51  
52      public List <Term> idInstances = new Vector <Term> ();
53      
54      public List <Term> explicitInstances = new Vector <Term> ();
55  
56      public List <Term> idRelations = new Vector <Term> ();
57      
58      public List <Term> explicitRelations = new Vector <Term> ();
59      
60      public List <Term> idAbstractRelations = new Vector <Term> ();
61      
62      public List <Term> idConcreteRelations = new Vector <Term> ();
63      
64      private WsmlDLExpressionValidator dlExprVal = null;
65  
66      public WsmlDLValidator(LogicalExpressionFactory leFactory) {
67          super(leFactory);
68      }
69      
70      /**
71       * Checks if an axiom is valid to wsml-dl.
72       * 
73       * @see org.deri.wsmo4j.validator.WsmlFullValidator#visitAxiom(org.omwg.ontology.Axiom)
74       */
75      protected void visitAxiom(Axiom axiom) {
76          WsmlDLExpressionValidator dlExprVal = new WsmlDLExpressionValidator(axiom, leFactory, errors, this);
77          WsmlFullExpressionValidator fullExprVal = new WsmlFullExpressionValidator(axiom, errors);
78          FunctionSymbolHelper fsHelper = new FunctionSymbolHelper(
79                  axiom, errors, WSML.WSML_DL, this);
80          IDCollectHelper idHelper = new IDCollectHelper();
81          Iterator axioms = axiom.listDefinitions().iterator();
82          while (axioms.hasNext()){
83              LogicalExpression le = (LogicalExpression) axioms.next();
84              
85              le.accept(idHelper);
86              // adding the Axiom's Concepts, Instances and Relations to the vectors
87              idConcepts.addAll(idHelper.getConceptIds());
88              explicitConcepts.addAll(idHelper.getExplicitConcepts());
89              idInstances.addAll(idHelper.getInstanceIds());
90              explicitInstances.addAll(idHelper.getExplicitInstances());
91              idRelations.addAll(idHelper.getRelationIds());
92              explicitRelations.addAll(idHelper.getExplicitRelations());
93              idAbstractRelations.addAll(idHelper.getIdAbstractRelations());
94              idConcreteRelations.addAll(idHelper.getIdConcreteRelations());
95              
96              le.accept(fsHelper);
97              
98              dlExprVal.setup();
99              le.accept(fullExprVal);
100             le.accept(dlExprVal);
101         }
102     }
103 
104     /**
105      * Checks if a concept is valid to wsml-dl.
106      * 
107      * @see org.deri.wsmo4j.validator.WsmlFullValidator#visitConcept(org.omwg.ontology.Concept)
108      */
109     protected void visitConcept(Concept concept) {
110         super.visitConcept(concept);
111         Iterator i = concept.listAttributes().iterator();
112         while (i.hasNext()) {
113             Attribute a = (Attribute)i.next();
114             String id1 = a.getIdentifier().toString();
115             String id2 = concept.getIdentifier().toString();
116             
117             if (a.getIdentifier() instanceof IRI) {
118                 id1 = ((IRI) a.getIdentifier()).getLocalName();
119             }
120             if (concept.getIdentifier() instanceof IRI) {
121                 id2 = ((IRI) concept.getIdentifier()).getLocalName();
122             }
123             
124             // check if the attribute has the transitive feature
125             if (a.isTransitive()) {    
126                 addError(concept, a, ValidationError.ATTR_FEAT_ERR + ": Attributes may " +
127                          "not contain the attribute feature 'transitive' \n("
128                          + id1 + " at Concept " + id2 +  ")");
129             }
130             // check if the attribute has the reflexive feature
131             else if (a.isReflexive()) {
132                 addError(concept, a, ValidationError.ATTR_FEAT_ERR + ": Attributes may " +
133                          "not contain the attribute feature 'reflexive' \n("
134                          + id1 + " at Concept " + id2 + ")");
135             }
136             // check if the attribute has the symmetric feature
137             else if (a.isSymmetric()) {
138                 addError(concept, a, ValidationError.ATTR_FEAT_ERR + ": Attributes may " +
139                          "not contain the attribute feature 'symmetric' \n("
140                          + id1 + " at Concept " + id2 + ")");
141             }
142             // check if the attribute has the inverse feature
143             else if (a.getInverseOf() != null) {
144                 addError(concept, a, ValidationError.ATTR_FEAT_ERR + ": Attributes may " +
145                          "not contain the attribute feature 'inverseOf' \n("
146                          + id1 + " at Concept " + id2 + ")");
147             }
148             // check if an attribute has a cardinality constraint
149             if (a.getMaxCardinality() != Integer.MAX_VALUE || a.getMinCardinality() != 0) {
150                 addError(concept, a, ValidationError.ATTR_CARD_ERR + ": Attributes may " +
151                          "not contain cardinality constraints \n("
152                          + id1 + " at Concept " + id2 + ")");
153             }
154             Iterator it = a.listTypes().iterator();
155             while (it.hasNext()) {
156             	Type t = (Type)it.next();
157                 // check that if the attribute is constraining, it has a datatype range
158                 if (a.isConstraining()) {
159                     if (!(t instanceof WsmlDataType)) {
160                     	addError(concept, a, ValidationError.ATTR_CONS_ERR
161                     			+ ": The attribute type 'ofType' is not allowed, " 
162                     			+ "other than for datatype identifiers \n("
163                     			+ id1 + " at Concept " + id2 + ")");
164                     }
165                 }
166                 else {
167                 	if (t instanceof Concept) {
168             			idConcepts.add(((Concept) t).getIdentifier());	
169             		}
170                 }
171             }
172             // adding all attributes t o a vector
173             idRelations.add(a.getIdentifier());
174             isRelation(a);
175         }
176         // adding all concepts to a vector
177         Identifier id = concept.getIdentifier();
178         idConcepts.add(id);
179         explicitConcepts.add(id);
180         isConcept(concept);
181         
182         //checking for SuperConcepts and adding them to a vector
183         if (!concept.listSuperConcepts().isEmpty()) {
184             Iterator it = concept.listSuperConcepts().iterator();
185             while (it.hasNext()) {
186                 Concept con = (Concept) it.next();
187                 idConcepts.add(con.getIdentifier());
188                 isConcept(con);
189             }
190         }
191     }
192     
193     /*
194      * Check for metamodelling error
195      */
196     private void isConcept(Entity e) {
197         Identifier id = e.getIdentifier();
198         if (idInstances.contains(id) || idRelations.contains(id) || 
199                 constants.isDataType(id.toString())){
200             String idString = id.toString();
201             if (id instanceof IRI) {
202                 idString = ((IRI) id).getLocalName();
203             }
204             addError(e, ValidationError.META_MODEL_ERR
205                     + ": An ID can only denote an entity of one single type: \n("
206                     + "at Concept " + idString + ")");
207         }
208     }
209 
210     /**
211      * Checks if an instance is valid to wsml-dl.
212      * 
213      * @see org.deri.wsmo4j.validator.WsmlFullValidator#visitInstance(org.omwg.ontology.Instance)
214      */
215     protected void visitInstance(Instance instance) {
216         super.visitInstance(instance);
217         
218         // adding all instances to a vector
219         Identifier id = instance.getIdentifier();
220         idInstances.add(id);
221         explicitInstances.add(id);
222         Set entries = instance.listAttributeValues().entrySet();
223         Iterator it = entries.iterator();
224         while (it.hasNext()) {
225 			Entry entry = (Entry) it.next();			
226             Identifier attrId = (Identifier) entry.getKey();
227         	idRelations.add(attrId);
228         	Set valueSet = (Set) entry.getValue();
229         	Iterator it2 = valueSet.iterator();
230         	while (it2.hasNext()) {
231         		Value value = (Value) it2.next();
232             	if (value instanceof Instance) {
233             		idInstances.add(((Instance) value).getIdentifier());
234             		isInstance((Instance) value);
235             	}
236         	}	
237         }
238         isInstance(instance);
239     }
240 
241     /*
242      * Check for metamodelling error
243      */
244     private void isInstance(Entity e) {
245     	Identifier id = e.getIdentifier();
246         if (idConcepts.contains(id) || idRelations.contains(id) ||
247                 constants.isDataType(id.toString())){
248             String idString = id.toString();
249             if (id instanceof IRI) {
250                 idString = ((IRI) id).getLocalName();
251             }
252             addError(e, ValidationError.META_MODEL_ERR
253                     + ": An ID can only denote an entity of one single type: \n("
254                     + "at Instance " + idString + ")");
255         }
256     }
257     
258     /**
259      * Checks if a relation is valid to wsml-dl.
260      * 
261      * @see org.deri.wsmo4j.validator.WsmlFullValidator#visitRelation(org.omwg.ontology.Relation)
262      */
263     protected void visitRelation(Relation relation) {
264         super.visitRelation(relation);
265     
266         // check if the relation is a binary relation
267         if (relation.listParameters().size() != 2) {
268             addError(relation, ValidationError.REL_ARITY_ERR + ": The arity of " +
269                     "relations is restricted to 2 \n");
270         }
271         else {
272             Parameter p1 = relation.getParameter((byte)0);
273             Parameter p2 = relation.getParameter((byte)1);
274 
275             // check that the first parameter hasn't got a datatype at its range
276             Iterator it = p1.listTypes().iterator();
277             while (it.hasNext()) {
278             	Type type = (Type) it.next();
279                 if (type instanceof WsmlDataType) {
280                     addError(relation, ValidationError.REL_ERR + ": The range of " +
281                             "the first parameter of a binary relation may not contain a " +
282                             "datatype\n");
283                 }
284                 else {
285                 	idConcepts.add(((Concept) type).getIdentifier());
286                 	isConcept((Concept) type);
287                 }
288             }
289             
290             // check that the first parameter isn't constraining
291             if (p1.isConstraining()) {
292                 addError(relation, ValidationError.REL_CONS_ERR + ": The 'ofType' " +
293                         "keyword is not allowed for the first parameter of a binary " +
294                         "relation");
295             }
296             
297             /*
298              * check that in case the second parameter is constraining, it
299              * must have a datatype at its range
300              */
301             it = p2.listTypes().iterator();
302             while (it.hasNext()) {
303             	Type type = (Type)it.next();
304             	if (p2.isConstraining()) {
305             		if (!(type instanceof WsmlDataType)) {
306             			addError(relation, ValidationError.REL_CONS_ERR + ": The 'ofType' " +
307             					"keyword is not allowed without a datatype at the parameter's " +
308             					"range\n");
309             		}
310             	}
311             	else {
312             		if (type instanceof Concept) {
313             			idConcepts.add(((Concept) type).getIdentifier());
314             			isConcept((Concept) type);
315             		}
316             	}
317             }
318         }
319         // adding all relations to a vector
320         idRelations.add(relation.getIdentifier());
321         explicitRelations.add(relation.getIdentifier());
322         isRelation(relation);
323         
324         // checking for SuperRelations and adding them to a vector
325         if (!relation.listSuperRelations().isEmpty()) {
326             Iterator it = relation.listSuperRelations().iterator();
327             while (it.hasNext()) {
328                 Relation rel = (Relation) it.next();
329                 idRelations.add(rel.getIdentifier());
330                 isRelation(rel);
331             }
332         }
333     }
334     
335     /*
336      * Check for metamodelling error
337      */
338     private void isRelation(Entity e) {
339         Identifier id = e.getIdentifier();
340         if (idConcepts.contains(id) || idInstances.contains(id) ||
341                 constants.isDataType(id.toString())){
342             String idString = id.toString();
343             if (id instanceof IRI) {
344                 idString = ((IRI) id).getLocalName();
345             }
346             addError(e, ValidationError.META_MODEL_ERR
347                     + ": An ID can only denote an entity of one single type: \n("
348                     + "at Relation " + idString + ")");
349         }
350     }
351     
352     /**
353      * Checks if a relation instance is valid to wsml-dl.
354      * 
355      * @throws InvalidModelException
356      * @throws SynchronisationException
357      * @see org.deri.wsmo4j.validator.WsmlFullValidator#visitRelationInstance(org.omwg.ontology.RelationInstance)
358      */
359     protected void visitRelationInstance(RelationInstance relationInstance)
360             throws SynchronisationException, InvalidModelException {
361         /*
362          * It is not possible to check if the values of a relation correspond to
363          * their signatures, because instance hierarches are not implemented
364          *
365          * Exceptions from relationInstance.getParameterValue(byte) shouldn't be
366          * thrown
367          */
368         super.visitRelationInstance(relationInstance);
369         
370         Value v1 = relationInstance.getParameterValue((byte)0);
371         Value v2 = relationInstance.getParameterValue((byte)1);
372         String id1 = relationInstance.getIdentifier().toString();
373         String id2 = relationInstance.getRelation().getIdentifier().toString();
374         if (relationInstance.getIdentifier() instanceof IRI) {
375             id1 = ((IRI) relationInstance.getIdentifier()).getLocalName();
376         }
377         if (relationInstance.getRelation().getIdentifier() instanceof IRI) {
378             id2 = ((IRI) relationInstance.getRelation().getIdentifier()).getLocalName();
379         }
380         // check that both values of the relation are specified
381         if (v1 == null || v2 == null) {
382              
383             addError(relationInstance, ValidationError.REL_INST_ERR + ": Both values of " +
384                      "the relation have to be specified \n("
385                      + id1 + " at relation "
386                      + id2 + ")");
387         }
388         // check that the first value is not a data value
389         if (v1 instanceof DataValue) {
390             addError(relationInstance, ValidationError.REL_INST_ERR + ": The first value " +
391                      "may not be a data value \n(" + id1 + " at relation " + id2 + ")");
392         }
393         idRelations.add(relationInstance.getIdentifier());
394         isRelation(relationInstance);
395     }
396     
397     /**
398      * @return Returns the idConcepts.
399      */
400     public List getIdConcepts() {
401         return idConcepts;
402     }
403 
404     /**
405      * @return Returns the idInstances.
406      */
407     public List getIdInstances() {
408         return idInstances;
409     }
410 
411     /**
412      * @return Returns the idRelations.
413      */
414     public List getIdRelations() {
415         return idRelations;
416     }
417     
418     /**
419      * 
420      * @return Returns the idAbstractRelations
421      */
422     public List getIdAbstractRelations() {
423         return idAbstractRelations;
424     }
425 
426     /**
427      * @return Returns the idConcreteRelations
428      */
429     public List getIdConcreteRelations() {
430         return idConcreteRelations;
431     }
432 
433     private void checkForMetaModelling() {
434     	Iterator it = idConcepts.iterator();
435     	while (it.hasNext()) {
436     		Object obj = it.next();
437     		if (obj instanceof IRI) {
438     			Identifier id = (Identifier) obj;
439     			if (idInstances.contains(id) || idRelations.contains(id) 
440     					|| constants.isDataType(id.toString())) {
441     				String idString = id.toString();
442     				if (id instanceof IRI) {
443     					idString = ((IRI) id).getLocalName();
444     				}
445     				addError(null, ValidationError.META_MODEL_ERR
446     						+ ": An ID can only denote an entity of one single type: \n("
447     						+ "at Concept " + idString + ")");
448     			}
449     		}
450     	}
451     	it = idInstances.iterator();
452     	while (it.hasNext()) {
453     		Object obj = it.next();
454     		if (obj instanceof IRI) {
455     			Identifier id = (Identifier) obj;
456     			if (idConcepts.contains(id) || idRelations.contains(id) 
457     					|| constants.isDataType(id.toString())) {
458     				String idString = id.toString();
459     				if (id instanceof IRI) {
460     					idString = ((IRI) id).getLocalName();
461     				}
462     				addError(null, ValidationError.META_MODEL_ERR
463     						+ ": An ID can only denote an entity of one single type: \n("
464     						+ "at Instance " + idString + ")");
465     			}
466     		}
467     	}
468     	it = idRelations.iterator();
469     	while (it.hasNext()) {
470     		Object obj = it.next();
471     		if (obj instanceof IRI) {
472     			Identifier id = (Identifier) obj;
473 				if (idInstances.contains(id) || idConcepts.contains(id) 
474 						|| constants.isDataType(id.toString())) {
475 					String idString = id.toString();
476 					if (id instanceof IRI) {
477 						idString = ((IRI) id).getLocalName();
478 					}
479 					addError(null, ValidationError.META_MODEL_ERR
480 							+ ": An ID can only denote an entity of one single type: \n("
481 							+ "at Relation " + idString + ")");
482 				}
483     		}
484     	}
485     }
486     
487     public boolean isValid(TopEntity te, List <ValidationError> errorMessages, List <ValidationWarning> warningMessages) {
488         boolean result = super.isValid(te, errorMessages, warningMessages);
489         
490         checkForMetaModelling();
491         
492         // check if all concepts have been explicitly declared
493         for (int i=0; i<idConcepts.size(); i++) {
494             String id = idConcepts.get(i).toString();
495         
496             if (idConcepts.get(i) instanceof IRI) {
497                 id = ((IRI) idConcepts.get(i)).getLocalName();
498             }
499         
500             if (!explicitConcepts.contains(idConcepts.get(i))) {
501                 addWarning(te, "concept " + id + " not explicitly declared!", null);
502             }
503         }
504         
505 //        // check if all instances have been explicitly declared
506 //        for (int i=0; i<idInstances.size(); i++) {
507 //            String id = idInstances.get(i).toString();
508 //            
509 //            if (idInstances.get(i) instanceof IRI) {
510 //                id = ((IRI) idInstances.get(i)).getLocalName();
511 //            }
512 //            
513 //            if (!explicitInstances.contains(idInstances.get(i))) {
514 //                addWarning(te, "instance " + id + " not explicitly declared!", null);
515 //            }
516 //        }
517         
518 //        // check if all relations have been explicitly declared
519 //        for (int i=0; i<idRelations.size(); i++) {
520 //            String id = idRelations.get(i).toString();
521 //            
522 //            if (idRelations.get(i) instanceof IRI) {
523 //                id = ((IRI) idRelations.get(i)).getLocalName();
524 //            }
525 //            
526 //            if (!explicitRelations.contains(idRelations.get(i))) {
527 //                addWarning(te, "relation " + id + " not explicitly declared!", null);
528 //            }
529 //        }
530         
531         return result;
532     }
533     
534     public boolean isValid(LogicalExpression logExpr, List <ValidationError> errorMessages, List <ValidationWarning> warningMessages) {
535     	super.isValid(logExpr, errorMessages, warningMessages);
536     	errors = errorMessages;
537         warnings = warningMessages;
538 		
539         dlExprVal = new WsmlDLExpressionValidator(null, leFactory, errors, this);
540         WsmlFullExpressionValidator fullExprVal = new WsmlFullExpressionValidator(null, errors);
541         FunctionSymbolHelper fsHelper = new FunctionSymbolHelper(
542         		null, errors, WSML.WSML_DL, this);
543         IDCollectHelper idHelper = new IDCollectHelper();    
544         
545         logExpr.accept(idHelper);
546         // adding the Axiom's Concepts, Instances and Relations to the vectors
547         idConcepts.addAll(idHelper.getConceptIds());
548         explicitConcepts.addAll(idHelper.getExplicitConcepts());
549         idInstances.addAll(idHelper.getInstanceIds());
550         explicitInstances.addAll(idHelper.getExplicitInstances());
551         idRelations.addAll(idHelper.getRelationIds());
552         explicitRelations.addAll(idHelper.getExplicitRelations());
553         idAbstractRelations.addAll(idHelper.getIdAbstractRelations());
554         idConcreteRelations.addAll(idHelper.getIdConcreteRelations());
555         
556         logExpr.accept(fsHelper);
557         
558         dlExprVal.setup();
559         logExpr.accept(fullExprVal);
560         logExpr.accept(dlExprVal);
561         
562         checkForMetaModelling();
563         
564         return (errors.isEmpty());
565     }
566     
567     public Variable getRootVariable(LogicalExpression logExpr) {
568     	return dlExprVal.getRoot();
569     }
570     
571     /*
572      * Adds a new ValidationError to the error list
573      */
574     protected void addError(Entity ent, String msg) {
575         ValidationErrorImpl ve = new ValidationErrorImpl(ent, msg, WSML.WSML_DL);
576         if (!errors.contains(ve)) {
577             errors.add(ve);
578         }
579     }
580     
581     /*
582      * Adds a new AttributeError to the error list
583      */
584     protected void addError(Entity ent, Attribute att, String msg) {
585         AttributeErrorImpl ae = new AttributeErrorImpl(ent, att, msg, WSML.WSML_DL);
586         if (!errors.contains(ae)) {
587             errors.add(ae);
588         }
589     }
590     
591 }