001: package org.ontoware.rdfreactor.generator.java;
002:
003: import java.util.ArrayList;
004: import java.util.Collections;
005: import java.util.Comparator;
006: import java.util.HashSet;
007: import java.util.List;
008: import java.util.Set;
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.OWL;
014: import org.ontoware.rdf2go.vocabulary.RDFS;
015:
016: /**
017: * A <b>JClass</b> represents a class in a JModel.
018: *
019: * Every JClass has a name, a comment, a List of properties and inverse
020: * properties, a List of superclasses (multiple superclasses are allowed), and
021: * an URI to which the JClass is mapped.
022: *
023: * Properties are represented by JProperty instances.
024: *
025: * @author mvo
026: */
027: public class JClass extends JMapped {
028:
029: public static final JClass STRING = new JClass(JPackage.JAVA_LANG,
030: String.class.getName(), RDFS.Literal);
031:
032: public static final JClass RESOURCE = new JClass(
033: JPackage.RDFSCHEMA,
034: org.ontoware.rdfreactor.schema.rdfs.Resource.class
035: .getName(), RDFS.Resource);
036:
037: public static final JClass RDFS_CLASS = new JClass(
038: JPackage.RDFSCHEMA,
039: org.ontoware.rdfreactor.schema.rdfs.Class.class.getName(),
040: RDFS.Class);
041:
042: public static final JClass OWL_CLASS = new JClass(
043: JPackage.OWL,
044: org.ontoware.rdfreactor.schema.owl.OwlClass.class.getName(),
045: OWL.Class);
046:
047: private static final Log log = LogFactory.getLog(JClass.class);
048:
049: /** List of properties, represented by JProperty instances */
050: private List<JProperty> properties = new ArrayList<JProperty>();
051:
052: /** List of inverse properties, represented by JProperty instances */
053: private List<JProperty> inverseProperties = new ArrayList<JProperty>();
054:
055: /** List of superclasses, represented by JClass instances */
056: private List<JClass> super classes = new ArrayList<JClass>();
057:
058: /** as used for code generation */
059: private JClass javaSuperclass;
060:
061: /** the JPackage, to which this JClass belongs */
062: private JPackage packagge;
063:
064: private Set<JClass> javaSubclasses = new HashSet<JClass>();
065:
066: public boolean cardinalityexception = false;
067:
068: /**
069: * property names need only to be unique within a class FIXME and in all
070: * super-classes of that class
071: *
072: * @return all property names that have been used in this class or a
073: * super-class
074: */
075: public Set<String> getUsedPropertyNames() {
076: // look in all sub- and super-classes and collect used names
077: Set<String> usedNames = new HashSet<String>();
078:
079: addUsedPropertyNames(usedNames, this );
080:
081: JClass super class = getSuperclass();
082: while (super class != null) {
083: addUsedPropertyNames(usedNames, super class);
084: super class = super class.getSuperclass();
085: }
086: addUsedPropertyNamesFromSubClasses(usedNames, this );
087: return usedNames;
088: }
089:
090: private void addUsedPropertyNamesFromSubClasses(
091: Set<String> usedNames, JClass jclass) {
092: for (JClass subclass : jclass.getSubclasses()) {
093: addUsedPropertyNames(usedNames, subclass);
094: addUsedPropertyNamesFromSubClasses(usedNames, subclass);
095: }
096: }
097:
098: private Set<JClass> getSubclasses() {
099: return this .javaSubclasses;
100: }
101:
102: /**
103: * Add all names used by a property in jclass to usedNames
104: *
105: * @param usedNames
106: * @param jclass
107: */
108: private void addUsedPropertyNames(Set<String> usedNames,
109: JClass jclass) {
110: for (JProperty jprop : jclass.getProperties()) {
111: usedNames.add(jprop.getName());
112: }
113: }
114:
115: /**
116: * creating a class adds it to the package the only constructor:
117: *
118: * @param packagge
119: * is the JPackage to which this JClass belongs
120: * @param name
121: * is the Name identyfing this JClass
122: * @param mappedTo
123: * is an URI to which this JClass should be mapped
124: */
125: public JClass(JPackage packagge, String name, URI mappedTo) {
126: super (name, mappedTo);
127: this .packagge = packagge;
128: // wire
129: this .packagge.getClasses().add(this );
130: }
131:
132: public String toString() {
133: return this .getName();
134: }
135:
136: public String getDotfree() {
137: return this .getName().replace(".", "_");
138: }
139:
140: public String toDebug() {
141: StringBuffer buf = new StringBuffer();
142: buf.append(" JClass " + getName() + " -> " + getMappedTo()
143: + "\n");
144: if (super classes.size() > 0)
145: buf.append(" extends: ");
146: for (JClass jc : super classes) {
147: buf.append(jc.getName()).append(", ");
148: }
149: if (super classes.size() > 0)
150: buf.append("\n");
151:
152: if (getComment() != null)
153: buf.append(" comment: ").append(getComment()).append(
154: "\n");
155:
156: for (JProperty jp : properties) {
157: buf.append(jp.toDebug());
158: }
159: return buf.toString();
160: }
161:
162: /**
163: * @return true if this JClass has a JProperty with a cardinality greater
164: * then one
165: */
166: public boolean hasMultiValuePropeties() {
167: for (JProperty jp : properties)
168: if (jp.getMaxCardinality() > 1)
169: return true;
170: return false;
171: }
172:
173: /**
174: * @return true if the template generates code that throws a
175: * RDFDataException
176: */
177: public boolean throwsRDFDataException() {
178: for (JProperty jp : properties) {
179: if (jp.getMaxCardinality() == JProperty.NOT_SET
180: || jp.getMaxCardinality() == 1)
181: return true;
182: }
183: return false;
184: }
185:
186: // /**
187: // * @return true if the template generates code that throws a
188: // * CardinalityException
189: // */
190: // public boolean throwsCardinalityException() {
191: // for (JProperty jp : properties) {
192: // if (jp.getMinCardinality() != JProperty.NOT_SET)
193: // return true;
194: // if (jp.getMaxCardinality() > 1)
195: // return true;
196: // }
197: // return false;
198: // }
199:
200: /**
201: * @return all direct super-classes
202: */
203: public List<JClass> getSuperclasses() {
204: return this .super classes;
205: }
206:
207: /**
208: * @return all super-classes, and their super-classes, and so on until root
209: */
210: public Set<JClass> getTransitiveSuperclasses() {
211: Set<JClass> transitiveSuperclasses = new HashSet<JClass>();
212: addSuperClasses(transitiveSuperclasses, this );
213: return transitiveSuperclasses;
214: }
215:
216: private static void addSuperClasses(Set<JClass> result, JClass clazz) {
217: for (JClass super Class : clazz.getSuperclasses()) {
218: result.add(super Class);
219: addSuperClasses(result, super Class);
220: }
221: }
222:
223: public void addSuperclass(JClass super class) {
224: this .super classes.add(super class);
225: }
226:
227: /**
228: * Double-link
229: *
230: * @param javaSuperclass
231: */
232: public void setJavaSuperclass(JClass javaSuperclass) {
233: this .javaSuperclass = javaSuperclass;
234: javaSuperclass.addJavaSubclass(this );
235: }
236:
237: private void addJavaSubclass(JClass javaSubclass) {
238: this .javaSubclasses.add(javaSubclass);
239:
240: }
241:
242: public List<JProperty> getProperties() {
243: // sort properties
244: Collections.sort(this .properties, new Comparator<JProperty>() {
245:
246: public int compare(JProperty a, JProperty b) {
247: return a.getName().compareTo(b.getName());
248: }
249:
250: });
251:
252: // return
253: return this .properties;
254: }
255:
256: /**
257: * apply consistency checks to this JClass and all instances of JProperty in
258: * it.
259: *
260: * A JClass is not consistent if it has more then one superclass.
261: *
262: * @return true if the JClass and all its parts are consistent
263: */
264: public boolean isConsistent() {
265: boolean result = true;
266: if (this .javaSuperclass == null) {
267: log.warn(getName() + " has no superclass to inherit from");
268: result &= false;
269: }
270: for (JProperty jp : properties) {
271: if (!jp.isConsistent())
272: log.warn(jp.getName() + " is not consistent");
273: result &= jp.isConsistent();
274: }
275: return result;
276: }
277:
278: /**
279: * @return first superclass, null if none exists
280: */
281: public JClass getSuperclass() {
282: return this .javaSuperclass;
283: }
284:
285: private JPackage getPackage() {
286: return this .packagge;
287: }
288:
289: /**
290: * Calculate the inheritance distance of this JClass from the given root
291: * JClass.
292: *
293: * @param root
294: * is a JClass
295: * @return the number of classes in the inheritance tree between this JClass
296: * and the given root JClass
297: */
298: public int getInheritanceDistanceFrom(JClass root) {
299: return this .getInheritanceDistanceFrom(root, 0,
300: new HashSet<JClass>());
301: }
302:
303: /**
304: * Calculate the inheritance distance of this JClass from the given root
305: * JClass. The calculation is done through recursion.
306: *
307: * @param root
308: * is the JClass from which the distance should be calculated
309: * @param steps
310: * is passed as an argument because it is recursivly counted
311: * upwards
312: * @param seen
313: * contains all JClasses through which this function passed as
314: * part of the recursion
315: * @return the number of steps until the given root JClass is reached
316: * recursivly
317: */
318: private int getInheritanceDistanceFrom(JClass root, int steps,
319: Set<JClass> seen) {
320: log.debug("visiting '" + this .getName() + "' step = " + steps
321: + " seen = " + seen.size() + " root = '" + root + "'");
322:
323: if (this .getName().equals(root.getName()))
324: return steps;
325: else if (seen.contains(this ))
326: return steps;
327: else {
328: Set<JClass> localseen = new HashSet<JClass>();
329: localseen.addAll(seen);
330: localseen.add(this );
331:
332: // return maximum
333: int max = 0;
334: for (JClass super class : getSuperclasses()) {
335: int current = super class.getInheritanceDistanceFrom(
336: root, steps + 1, localseen);
337: if (current > max)
338: max = current;
339: }
340: return steps + max;
341: }
342: }
343:
344: public List<JProperty> getInverseProperties() {
345: return inverseProperties;
346: }
347:
348: /** generate a verbose report of this JClass */
349: public String toReport() {
350: StringBuffer buf = new StringBuffer();
351: buf.append("\n" + getName());
352: if (super classes.size() > 0)
353: buf.append(" extends: ");
354: for (JClass jc : super classes) {
355: buf.append(jc.getN3Name()).append(", ");
356: }
357: buf.append("| URI: " + getMappedTo().toSPARQL() + "\n");
358:
359: if (getComment() != null)
360: buf.append("''").append(getComment()).append("''\n");
361:
362: buf.append("properties:\n");
363: for (JProperty jp : properties) {
364: buf.append(jp.toReport());
365: }
366: buf.append("inverse properties:\n");
367: for (JProperty jp : inverseProperties) {
368: buf.append(jp.toReport());
369: }
370: return buf.toString();
371: }
372:
373: /**
374: * two JClass instances are equal if they have the same name and belong to
375: * the same JPackage
376: */
377: public boolean equals(Object other) {
378: if (other instanceof JClass) {
379: JClass otherclass = (JClass) other;
380: return (this .getName().equals(otherclass.getName()) && this
381: .getPackage().equals(otherclass.getPackage()));
382: }
383: return false;
384: }
385:
386: public boolean getCardinalityexception() {
387: return cardinalityexception;
388: }
389: }
|