001: package org.ontoware.rdfreactor.generator.java;
002:
003: import java.util.ArrayList;
004: import java.util.Collection;
005: import java.util.Collections;
006: import java.util.Comparator;
007: import java.util.HashSet;
008: import java.util.List;
009:
010: import org.apache.commons.logging.Log;
011: import org.apache.commons.logging.LogFactory;
012: import org.ontoware.rdf2go.model.node.URI;
013: import org.ontoware.rdf2go.vocabulary.RDFS;
014:
015: /**
016: * A <b>JProperty</b> represents a property of a JClass in the JModel.
017: * (A JProperty can be thought of as a property in the Java Bean sense.)
018: *
019: * Every JProperty has a name, a comment, a URI to which it is Mapped in the JModel,
020: * a List of JClasses from which it is a property, an inverse property, as well as
021: * a minimum and maximum cardinality.
022: *
023: * @author $Author: xamde $
024: * @version $Id: JProperty.java,v 1.9 2006/09/11 10:07:57 xamde Exp $
025: *
026: */
027: public class JProperty extends JMapped {
028:
029: /** magic number representing a value, which is not set */
030: public static final int NOT_SET = -1;
031:
032: private static final Log log = LogFactory.getLog(JProperty.class);
033:
034: /** the List of ranges of a JProperty */
035: private Collection<JClass> types = new HashSet<JClass>();
036:
037: /** the minimum cardinality of the JProperty */
038: private int minCardinality = NOT_SET;
039:
040: /** the maximum cardinality of the JProperty */
041: private int maxCardinality = NOT_SET;
042:
043: /**
044: * if a property has an inverse property, that label is used instead of
045: * propertyname+"_Inverse".
046: */
047: private JProperty inverse = null;
048:
049: /** the domain of this property: the resource to which this property belongs */
050: private JClass clazz;
051:
052: /**
053: * constructor with all parameters
054: * @param clazz - JClass which is the domain of this JProperty
055: * @param name of the JProperty
056: * @param mappedTo is the URI to which this JProperty is mapped to
057: * @param minCardinality of the JProperty
058: * @param maxCardinality of the JProperty
059: */
060: public JProperty(JClass clazz, String name, URI mappedTo,
061: int minCardinality, int maxCardinality) {
062: super (name, mappedTo);
063: this .minCardinality = minCardinality;
064: this .maxCardinality = maxCardinality;
065: this .clazz = clazz;
066: }
067:
068: /**
069: * constructor without cardinalities
070: * @param clazz - JClass which is the domain of this JProperty
071: * @param name of the JProperty
072: * @param mappedTo is the URI to which this JProperty is mapped to
073: */
074: public JProperty(JClass clazz, String name, URI mappedTo) {
075: this (clazz, name, mappedTo, NOT_SET, NOT_SET);
076: }
077:
078: /**
079: * @return the JClasses of which this instance is a property
080: */
081: public Collection<JClass> getTypes() {
082: return this .types;
083: }
084:
085: /**
086: * @param type is added to the list of JClasses having this JProperty as a range
087: */
088: public void addType(JClass type) {
089: assert type != null;
090: this .types.add(type);
091: log.debug("added a type, have " + types.size() + " now");
092: }
093:
094: /**
095: * for veloctiy
096: * @return a random JClass of the current types
097: */
098: public JClass getFirstType() {
099: if (this .types.iterator().hasNext())
100: return this .types.iterator().next();
101: else
102: return null;
103: }
104:
105: public int getMaxCardinality() {
106: return maxCardinality;
107: }
108:
109: public int getMinCardinality() {
110: return minCardinality;
111: }
112:
113: public void setMinCardinality(int min) {
114: this .minCardinality = min;
115: }
116:
117: public void setMaxCardinality(int max) {
118: log.debug("Setting max cardiality for " + getName() + " to "
119: + max);
120: this .maxCardinality = max;
121: }
122:
123: public String toDebug() {
124: StringBuffer buf = new StringBuffer();
125: buf.append(" " + getName() + " (" + minCardinality + "/"
126: + maxCardinality + ") " + " -> " + getMappedTo()
127: + ", types: ");
128: for (JClass jc : types) {
129: buf.append("'" + jc.getName() + "'");
130: buf.append(",");
131: }
132: if (this .hasInverse())
133: buf.append(". Inverse: " + getInverse().getName());
134: buf.append(".\n");
135:
136: return buf.toString();
137: }
138:
139: /**
140: * apply consistency checks to this JProperty.
141: *
142: * Every JProperty has to belong to at least one JClass.
143: *
144: * @return true if this JProperty is consistent
145: */
146: public boolean isConsistent() {
147: boolean result = true;
148: if (this .types.size() == 0) {
149: log.warn("property " + getName() + " has no types");
150: result &= false;
151: }
152:
153: // // FIXME if inverse: class should know it
154: // if (inverse != null) {
155: // inverse.getFirstType().equals(this.getJClass());
156: // }
157:
158: return result;
159: }
160:
161: /**
162: * @return JClass which is the domain of this JProperty
163: */
164: public JClass getJClass() {
165: return this .clazz;
166: }
167:
168: /**
169: * fix the list of JClasses which use this property, in case it is out of date
170: *
171: * @param jm is the JModel in which JClasses using this JProperty are searched for
172: */
173: public void fixRanges(JModel jm) {
174: if (this .types.size() == 0) {
175: log.debug("range is null, default to root");
176: this .addType(jm.getRoot());
177: } else {
178: // change Literal to String
179: List<JClass> allTypes = new ArrayList<JClass>();
180: allTypes.addAll(this .types);
181: for (JClass type : allTypes) {
182: assert type != null;
183: if (type.getMappedTo().equals(RDFS.Literal)) {
184: types.remove(type);
185: types.add(JClass.STRING);
186: }
187: }
188:
189: // remove all redundant superclasses
190: // which might be circular linked
191: // keep superclass with greater distance from root
192: // and among equal ones the one with the first name
193: // in lexicographical order
194: allTypes = new ArrayList<JClass>();
195: allTypes.addAll(this .types);
196:
197: // determine maximally nested classes
198: int maxDepth = 0;
199: List<JClass> maximallyNested = new ArrayList<JClass>();
200: for (JClass type : allTypes) {
201: int currentDepth = type.getInheritanceDistanceFrom(jm
202: .getRoot());
203: if (currentDepth > maxDepth) {
204: maxDepth = currentDepth;
205: maximallyNested.clear();
206: maximallyNested.add(type);
207: } else if (currentDepth == maxDepth) {
208: maximallyNested.add(type);
209: } else {
210: // nothing to do
211: }
212: }
213:
214: // sort lexicographically
215: class JClassComparator implements Comparator<JClass> {
216:
217: public int compare(JClass o1, JClass o2) {
218: return o1.getName().compareTo(o2.getName());
219: }
220:
221: }
222:
223: Collections.sort(maximallyNested, new JClassComparator());
224:
225: // take first
226: this .types.clear();
227: this .types.add(maximallyNested.get(0));
228: }
229: }
230:
231: public JProperty getInverse() {
232: return inverse;
233: }
234:
235: public boolean hasInverse() {
236: return getInverse() != null;
237: }
238:
239: public void setInverse(JProperty inverse) {
240: this .inverse = inverse;
241: }
242:
243: /** generate a verbose report of this JProperty */
244: public String toReport() {
245: StringBuffer buf = new StringBuffer();
246: buf.append("* " + getName() + " (" + minCardinality + " / "
247: + maxCardinality + ") " + " URI " + getMappedTo());
248: // + ", types: ");
249: buf.append("\n");
250: for (JClass jc : types) {
251: buf.append("** range: " + jc.getName() + "");
252: buf.append("\n");
253: }
254:
255: return buf.toString();
256: }
257:
258: }
|