Skip to content

Method: _generateModel(OWLOntology, JCodeModel, ContextDefinition, String)

1: /**
2: * Copyright (C) 2016 Czech Technical University in Prague
3: * <p>
4: * This program is free software: you can redistribute it and/or modify it under
5: * the terms of the GNU General Public License as published by the Free Software
6: * Foundation, either version 3 of the License, or (at your option) any
7: * later version.
8: * <p>
9: * This program is distributed in the hope that it will be useful, but WITHOUT
10: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
12: * details. You should have received a copy of the GNU General Public License
13: * along with this program. If not, see <http://www.gnu.org/licenses/>.
14: */
15: package cz.cvut.kbss.jopa.owl2java;
16:
17: import com.sun.codemodel.*;
18: import cz.cvut.kbss.jopa.CommonVocabulary;
19: import cz.cvut.kbss.jopa.model.annotations.*;
20: import cz.cvut.kbss.jopa.model.annotations.OWLAnnotationProperty;
21: import cz.cvut.kbss.jopa.model.annotations.OWLDataProperty;
22: import cz.cvut.kbss.jopa.model.annotations.OWLObjectProperty;
23: import cz.cvut.kbss.jopa.model.annotations.Properties;
24: import cz.cvut.kbss.jopa.model.ic.DataParticipationConstraint;
25: import cz.cvut.kbss.jopa.model.ic.ObjectParticipationConstraint;
26: import cz.cvut.kbss.jopa.owlapi.DatatypeTransformer;
27: import org.semanticweb.owlapi.model.*;
28: import org.semanticweb.owlapi.model.OWLClass;
29: import org.slf4j.Logger;
30: import org.slf4j.LoggerFactory;
31:
32: import java.io.File;
33: import java.io.IOException;
34: import java.util.*;
35:
36: import static cz.cvut.kbss.jopa.owl2java.Constants.*;
37:
38: public class JavaTransformer {
39:
40: private static final Logger LOG = LoggerFactory.getLogger(OWL2JavaTransformer.class);
41:
42: private static final String[] KEYWORDS = {"abstract",
43: "assert",
44: "boolean",
45: "break",
46: "byte",
47: "case",
48: "catch",
49: "char",
50: "class",
51: "const",
52: "continue",
53: "default",
54: "do",
55: "double",
56: "else",
57: "enum",
58: "extends",
59: "final",
60: "finally",
61: "float",
62: "for",
63: "goto",
64: "if",
65: "implements",
66: "import",
67: "instanceof",
68: "int",
69: "interface",
70: "long",
71: "native",
72: "new",
73: "package",
74: "private",
75: "protected",
76: "public",
77: "return",
78: "short",
79: "static",
80: "strictfp",
81: "super",
82: "switch",
83: "synchronized",
84: "this",
85: "throw",
86: "throws",
87: "transient",
88: "try",
89: "void",
90: "volatile",
91: "while"};
92:
93: private JDefinedClass voc;
94: private Map<OWLEntity, JFieldRef> entities = new HashMap<>();
95:
96: private Map<OWLClass, JDefinedClass> classes = new HashMap<>();
97:
98: private JFieldVar addField(final String name, final JDefinedClass cls,
99: final JType fieldType) {
100: String newName = name;
101:
102: int i = 0;
103: while (cls.fields().containsKey(newName)) {
104: newName = name + "" + (++i);
105: }
106:
107: final JFieldVar fvId = cls.field(JMod.PROTECTED, fieldType, newName);
108: final String fieldName = fvId.name().substring(0, 1).toUpperCase() + fvId.name().substring(1);
109: final JMethod mSetId = cls.method(JMod.PUBLIC, void.class, "set" + fieldName);
110: final JVar v = mSetId.param(fieldType, fvId.name());
111: mSetId.body().assign(JExpr._this().ref(fvId), v);
112: final JMethod mGetId = cls.method(JMod.PUBLIC, fieldType, "get" + fieldName);
113: mGetId.body()._return(fvId);
114: return fvId;
115: }
116:
117: public void generateModel(final OWLOntology ontology,
118: final ContextDefinition context, final String pkg, String targetDir, boolean withOWLAPI) {
119:
120: try {
121: final JCodeModel cm = new JCodeModel();
122: voc = cm._class(pkg + PACKAGE_SEPARATOR + VOCABULARY_CLASS);
123: generateVocabulary(ontology, cm, context, withOWLAPI);
124: _generateModel(ontology, cm, context, pkg + PACKAGE_SEPARATOR + MODEL_PACKAGE + PACKAGE_SEPARATOR);
125: writeOutModel(cm, targetDir);
126: } catch (JClassAlreadyExistsException e1) {
127: LOG.error("Transformation FAILED.", e1);
128: } catch (IOException e) {
129: LOG.error("File generation FAILED.", e);
130: }
131: }
132:
133: /**
134: * Generates only vocabulary of the loaded ontology.
135: *
136: * @param ontology Ontology from which the vocabulary should be generated
137: * @param context Integrity constraints context, if null is supplied, the whole ontology is interpreted as
138: * integrity constraints.
139: * @param targetDir Directory into which the vocabulary file will be generated
140: * @param pkg Package
141: * @param withOWLAPI Whether OWLAPI-based IRIs of the generated vocabulary items should be created as well
142: */
143: public void generateVocabulary(final OWLOntology ontology, ContextDefinition context, String pkg, String targetDir,
144: boolean withOWLAPI) {
145: try {
146: final JCodeModel cm = new JCodeModel();
147: this.voc = cm._class(pkg + PACKAGE_SEPARATOR + VOCABULARY_CLASS);
148: generateVocabulary(ontology, cm, context, withOWLAPI);
149: writeOutModel(cm, targetDir);
150: } catch (JClassAlreadyExistsException e) {
151: LOG.error("Vocabulary generation FAILED, because the Vocabulary class already exists.", e);
152: } catch (IOException e) {
153: LOG.error("Vocabulary file generation FAILED.", e);
154: }
155: }
156:
157: private void writeOutModel(JCodeModel cm, String targetDir) throws IOException {
158: final File file = new File(targetDir);
159: file.mkdirs();
160: cm.build(file);
161: }
162:
163: private void _generateModel(final OWLOntology ontology, final JCodeModel cm,
164: final ContextDefinition context, final String pkg) {
165: LOG.info("Generating model ...");
166:
167: context.classes.add(ontology.getOWLOntologyManager().getOWLDataFactory().getOWLThing());
168:
169:• for (final OWLClass clazz : context.classes) {
170: LOG.info(" Generating class '{}'.", clazz);
171: final JDefinedClass subj = ensureCreated(context, pkg, cm, clazz, ontology);
172:
173:• for (final org.semanticweb.owlapi.model.OWLObjectProperty prop : context.objectProperties) {
174:
175: final IntegrityConstraintParserImpl.ClassObjectPropertyComputer comp = context.parser.new ClassObjectPropertyComputer(
176: clazz, prop,
177: ontology);
178:
179:• if (OWL2JavaTransformer.Card.NO.equals(comp.getCard())) {
180: continue;
181: }
182:
183: JClass filler = ensureCreated(context, pkg, cm,
184: comp.getObject(), ontology);
185: final String fieldName = validJavaIDForIRI(prop.getIRI());
186:
187:• switch (comp.getCard()) {
188: case ONE:
189: break;
190: case MULTIPLE:
191: filler = cm.ref(java.util.Set.class).narrow(filler);
192: break;
193: case SIMPLELIST:
194: case LIST:
195: filler = cm.ref(java.util.List.class).narrow(filler);
196: break;
197: }
198:
199: final JFieldVar fv = addField(fieldName, subj, filler);
200:
201:• if (comp.getCard().equals(OWL2JavaTransformer.Card.SIMPLELIST)) {
202: fv.annotate(Sequence.class)
203: .param("type", SequenceType.simple);
204: }
205:
206:
207: fv.annotate(OWLObjectProperty.class).param("iri",
208: entities.get(prop));
209:
210: JAnnotationArrayMember use = null;
211:• for (ObjectParticipationConstraint ic : comp
212: .getParticipationConstraints()) {
213:• if (use == null) {
214: use = fv.annotate(ParticipationConstraints.class)
215: .paramArray("value");
216: }
217: JAnnotationUse u = use.annotate(
218: ParticipationConstraint.class).param(
219: // "owlClassIRI",
220: // ic.getSubject().getIRI().toString()).param(
221: // "owlPropertyIRI",
222: // ic.getPredicate().getIRI().toString()).param(
223: "owlObjectIRI", entities.get(ic.getObject()));
224:• if (ic.getMin() != 0) {
225: u.param("min", ic.getMin());
226: }
227:
228:• if (ic.getMax() != -1) {
229: u.param("max", ic.getMax());
230: }
231: }
232: }
233:
234:• for (org.semanticweb.owlapi.model.OWLDataProperty prop : context.dataProperties) {
235: final IntegrityConstraintParserImpl.ClassDataPropertyComputer comp = context.parser
236: .getClassDataPropertyComputer(clazz, prop, ontology);
237:
238:• if (OWL2JavaTransformer.Card.NO.equals(comp.getCard())) {
239: continue;
240: }
241:
242: final JType obj = cm._ref(DatatypeTransformer
243: .transformOWLType(comp.getFiller()));
244:
245: final String fieldName = validJavaIDForIRI(
246: prop.getIRI());
247:
248: JFieldVar fv;
249:
250:• if (OWL2JavaTransformer.Card.MULTIPLE.equals(comp.getCard())) {
251: fv = addField(fieldName, subj, cm.ref(java.util.Set.class)
252: .narrow(obj));
253:• } else if (OWL2JavaTransformer.Card.ONE.equals(comp.getCard())) {
254: fv = addField(fieldName, subj, obj);
255: } else {
256: assert false : "Unknown cardinality type";
257: continue;
258: }
259:
260: fv.annotate(OWLDataProperty.class).param("iri",
261: entities.get(prop));
262:
263: JAnnotationArrayMember use = null;
264:• for (DataParticipationConstraint ic : comp
265: .getParticipationConstraints()) {
266:• if (use == null) {
267: use = fv.annotate(ParticipationConstraints.class)
268: .paramArray("value");
269: }
270:
271: JAnnotationUse u = use.annotate(
272: ParticipationConstraint.class).param(
273: "owlObjectIRI", comp.getFiller().getIRI().toString());
274:
275:• if (ic.getMin() != 0) {
276: u = u.param("min", ic.getMin());
277: }
278:
279:• if (ic.getMax() != -1) {
280: u = u.param("max", ic.getMax());
281: }
282: }
283: }
284: }
285: }
286:
287: private void generateVocabulary(final OWLOntology o, final JCodeModel cm, ContextDefinition context,
288: boolean withOWLAPI) {
289: final Collection<OWLEntity> col = new HashSet<>();
290: col.add(o.getOWLOntologyManager().getOWLDataFactory().getOWLThing());
291: col.addAll(context.classes);
292: col.addAll(context.objectProperties);
293: col.addAll(context.dataProperties);
294: col.addAll(context.annotationProperties);
295: col.addAll(context.individuals);
296:
297: for (final OWLOntology s : o.getOWLOntologyManager().getOntologies()) {
298: IRI iri = s.getOntologyID().getOntologyIRI();
299: voc.field(JMod.PUBLIC | JMod.STATIC
300: | JMod.FINAL, String.class, "ONTOLOGY_IRI_" + validJavaIDForIRI(iri),
301: JExpr.lit(iri.toString()));
302: }
303:
304: for (final OWLEntity c : col) {
305: String prefix = "";
306:
307: if (c.isOWLClass()) {
308: prefix = "c_";
309: } else if (c.isOWLDatatype()) {
310: prefix = "d_";
311: } else if (c.isOWLDataProperty() || c.isOWLObjectProperty()
312: || c.isOWLAnnotationProperty()) {
313: prefix = "p_";
314: } else if (c.isOWLNamedIndividual()) {
315: prefix = "i_";
316: }
317:
318: String id = prefix + validJavaIDForIRI(c.getIRI());
319:
320: while (voc.fields().keySet().contains("s_" + id)) {
321: id += "_A";
322: }
323:
324: final String sFieldName = "s_" + id;
325:
326: final JFieldVar fv1 = voc.field(JMod.PUBLIC | JMod.STATIC
327: | JMod.FINAL, String.class, sFieldName,
328: JExpr.lit(c.getIRI().toString()));
329: if (withOWLAPI) {
330: voc.field(JMod.PUBLIC | JMod.STATIC | JMod.FINAL, IRI.class, id, cm
331: .ref(IRI.class).staticInvoke("create").arg(fv1));
332: }
333:
334: entities.put(c, voc.staticRef(fv1));
335: }
336: }
337:
338: private static String validJavaIDForIRI(final IRI iri) {
339: if (iri.getFragment() != null) {
340: return validJavaID(iri.getFragment());
341: } else {
342: int x = iri.toString().lastIndexOf("/");
343: return validJavaID(iri.toString().substring(x + 1));
344: }
345: }
346:
347:
348: private static String validJavaID(final String s) {
349: String res = s.trim().replace("-", "_").replace("'", "_quote_").replace(".", "_dot_").replace(',', '_');
350: if (Arrays.binarySearch(KEYWORDS, res) >= 0) {
351: res = "_" + res;
352: }
353: return res;
354: }
355:
356: private String javaClassId(OWLOntology ontology, OWLClass owlClass, ContextDefinition ctx) {
357: final Set<OWLAnnotation> annotations = owlClass.getAnnotations(ontology);
358: for (OWLAnnotation a : annotations) {
359: if (isValidJavaClassName(a, ctx)) {
360: if (a.getValue() instanceof OWLLiteral) {
361: return ((OWLLiteral) a.getValue()).getLiteral();
362: }
363: }
364: }
365: return validJavaIDForIRI(owlClass.getIRI());
366: }
367:
368: private JDefinedClass ensureCreated(final ContextDefinition ctx,
369: final String pkg, final JCodeModel cm, final OWLClass clazz,
370: final OWLOntology ontology) {
371: if (classes.containsKey(clazz)) {
372: return classes.get(clazz);
373: }
374:
375: JDefinedClass cls;
376:
377: String name = pkg + javaClassId(ontology, clazz, ctx);
378:
379: try {
380: cls = cm._class(name);
381:
382: cls.annotate(
383: cz.cvut.kbss.jopa.model.annotations.OWLClass.class)
384: .param("iri", entities.get(clazz));
385:
386: final JDocComment dc = cls.javadoc();
387: dc.add("This class was generated by the OWL2Java tool version " + VERSION);
388:
389: // if (clazz.equals(f.getOWLThing())) {
390: // RDFS label
391: final JClass ftLabel = cm.ref(String.class);
392: final JFieldVar fvLabel = addField("name", cls, ftLabel);
393: fvLabel.annotate(OWLAnnotationProperty.class).param("iri",
394: cm.ref(CommonVocabulary.class).staticRef("RDFS_LABEL"));
395:
396: // DC description
397: final JClass ftDescription = cm.ref(String.class);
398: final JFieldVar fvDescription = addField("description", cls, ftDescription);
399: fvDescription.annotate(OWLAnnotationProperty.class).param("iri",
400: cm.ref(CommonVocabulary.class).staticRef("DC_DESCRIPTION"));
401:
402: // @Types Set<String> types;
403: final JClass ftTypes = cm.ref(Set.class).narrow(String.class);
404: final JFieldVar fvTypes = addField("types", cls, ftTypes);
405: fvTypes.annotate(Types.class);
406:
407: // @Id public final String id;
408: final JClass ftId = cm.ref(String.class);
409: final JFieldVar fvId = addField("id", cls, ftId);
410: JAnnotationUse a = fvId.annotate(Id.class);
411:
412: a.param("generated", true);
413:
414: // @Properties public final Map<String,Set<String>> properties;
415: final JClass ftProperties = cm.ref(Map.class).narrow(
416: cm.ref(String.class),
417: cm.ref(Set.class).narrow(String.class));
418: final JFieldVar fvProperties = addField("properties", cls,
419: ftProperties);
420: fvProperties.annotate(Properties.class);
421: // }
422:
423: } catch (JClassAlreadyExistsException e) {
424: LOG.trace("Class already exists. Using the existing version. {}", e.getMessage());
425: cls = cm._getClass(name);
426: }
427: classes.put(clazz, cls);
428:
429: return cls;
430: }
431:
432: private boolean isValidJavaClassName(OWLAnnotation a, ContextDefinition ctx) {
433: // TODO Replace this hardcoded stuff with a configurable solution
434: return a.getProperty().getIRI()
435: .equals(IRI.create("http://krizik.felk.cvut.cz/ontologies/2009/ic.owl#javaClassName"));
436: // Annotation of annotation is currently not supported
437: // for (OWLAnnotation ctxAnn : a.getAnnotations()) {
438: // ctxAnn.getValue().accept(v);
439: // final String icContextName = v.getName();
440: // System.out.println("Context: " + icContextName);
441: // if (icContextName != null && icContextName.equals(ctx.name)) {
442: // return true;
443: // }
444: // }
445: }
446:
447: }