1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package org.openrdf.elmo.codegen;
30
31 import java.beans.BeanDescriptor;
32 import java.beans.BeanInfo;
33 import java.beans.IntrospectionException;
34 import java.beans.Introspector;
35 import java.beans.PropertyDescriptor;
36 import java.lang.reflect.Method;
37 import java.lang.reflect.ParameterizedType;
38 import java.lang.reflect.Type;
39 import java.util.HashMap;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43
44 import org.openrdf.elmo.LiteralManager;
45 import org.openrdf.elmo.annotations.complementOf;
46 import org.openrdf.elmo.annotations.disjointWith;
47 import org.openrdf.elmo.annotations.intersectionOf;
48 import org.openrdf.elmo.annotations.inverseOf;
49 import org.openrdf.elmo.annotations.oneOf;
50 import org.openrdf.elmo.annotations.rdf;
51 import org.openrdf.elmo.exceptions.ElmoConversionException;
52 import org.openrdf.model.BNode;
53 import org.openrdf.model.Literal;
54 import org.openrdf.model.Resource;
55 import org.openrdf.model.URI;
56 import org.openrdf.model.Value;
57 import org.openrdf.model.ValueFactory;
58 import org.openrdf.model.impl.ValueFactoryImpl;
59 import org.openrdf.model.vocabulary.OWL;
60 import org.openrdf.model.vocabulary.RDF;
61 import org.openrdf.model.vocabulary.RDFS;
62 import org.openrdf.model.vocabulary.XMLSchema;
63 import org.openrdf.rio.RDFHandler;
64 import org.openrdf.rio.RDFHandlerException;
65
66
67
68
69
70
71
72
73 public class OwlGenerator {
74 private LiteralManager<URI, Literal> lc;
75
76 private Map<String, String> namespaces = new HashMap<String, String>();
77
78 private RDFHandler target;
79
80 private ValueFactory vf = new ValueFactoryImpl();
81
82 public void setLiteralManager(LiteralManager<URI, Literal> lc) {
83 this.lc = lc;
84 }
85
86 public void setNamespace(String pkgName, String namespace) {
87 namespaces.put(pkgName, namespace);
88 }
89
90 public void exportOntology(List<Class<?>> beans, RDFHandler handler)
91 throws IntrospectionException, RDFHandlerException {
92 if (beans.isEmpty())
93 throw new IllegalArgumentException();
94 target = handler;
95 for (Class<?> bean : beans) {
96 BeanInfo info = Introspector.getBeanInfo(bean);
97 handleBeanClass(info.getBeanDescriptor());
98 }
99 for (Class<?> bean : beans) {
100 BeanInfo info = Introspector.getBeanInfo(bean);
101 URI domain = createURI(info.getBeanDescriptor().getBeanClass());
102 for (PropertyDescriptor desc : info.getPropertyDescriptors()) {
103 handleBeanProperty(domain, desc);
104 }
105 }
106 }
107
108 private String getNamespace(String uri) {
109 String ns;
110 if (uri.endsWith("/") || uri.endsWith("#")) {
111 ns = uri;
112 } else if (uri.contains("#")) {
113 ns = uri.substring(0, uri.indexOf('#') + 1);
114 } else {
115 ns = uri + '#';
116 }
117 return ns;
118 }
119
120 private URI createURI(Object obj) {
121 if (obj instanceof Class)
122 return createURI((Class<?>) obj);
123 return vf.createURI(obj.toString());
124 }
125
126 private URI createURI(Class<?> beanClass) {
127 if (beanClass.isAnnotationPresent(rdf.class)) {
128 String[] values = beanClass.getAnnotation(rdf.class).value();
129 if (values.length > 0)
130 return vf.createURI(values[0]);
131 }
132 String ns = getNamespace(beanClass);
133 String localName = beanClass.getSimpleName();
134 return vf.createURI(ns, localName);
135 }
136
137 private String getNamespace(Class<?> beanClass) {
138 String packageName = beanClass.getPackage().getName();
139 if (namespaces.containsKey(packageName))
140 return namespaces.get(packageName);
141 Package pkg = beanClass.getPackage();
142 if (pkg.isAnnotationPresent(rdf.class)) {
143 String name = pkg.getAnnotation(rdf.class).value()[0];
144 return getNamespace(name);
145 }
146 return "java:" + packageName + '#';
147 }
148
149 private void handleBeanClass(BeanDescriptor desc)
150 throws RDFHandlerException {
151 Class<?> beanClass = desc.getBeanClass();
152 URI uri = createURI(beanClass);
153 handleStatement(uri, RDF.TYPE, OWL.CLASS);
154 handleStatement(uri, RDFS.LABEL, desc.getDisplayName());
155 handleStatement(uri, RDFS.COMMENT, desc.getShortDescription());
156 URI ns = vf.createURI(getNamespace(beanClass));
157 handleStatement(uri, RDFS.ISDEFINEDBY, ns);
158 Class<?> sup = beanClass.getSuperclass();
159 if (sup != null && !sup.equals(Object.class))
160 handleStatement(uri, RDFS.SUBCLASSOF, createURI(sup));
161 for (Class<?> face : beanClass.getInterfaces()) {
162 handleStatement(uri, RDFS.SUBCLASSOF, createURI(face));
163 }
164 if (beanClass.isAnnotationPresent(rdf.class)) {
165 String[] eq = beanClass.getAnnotation(rdf.class).value();
166 for (int i = 1; i < eq.length; i++) {
167 handleStatement(uri, OWL.EQUIVALENTCLASS, vf.createURI(eq[i]));
168 }
169 }
170 if (beanClass.isAnnotationPresent(disjointWith.class)) {
171 disjointWith dw = beanClass.getAnnotation(disjointWith.class);
172 for (Class<?> c : dw.value()) {
173 handleStatement(uri, OWL.DISJOINTWITH, createURI(c));
174 }
175 }
176 if (beanClass.isAnnotationPresent(intersectionOf.class)) {
177 intersectionOf io = beanClass.getAnnotation(intersectionOf.class);
178 BNode list = createList(io.value());
179 handleStatement(uri, OWL.INTERSECTIONOF, list);
180 }
181 if (beanClass.isAnnotationPresent(complementOf.class)) {
182 complementOf co = beanClass.getAnnotation(complementOf.class);
183 handleStatement(uri, OWL.COMPLEMENTOF, createURI(co.value()));
184 }
185 }
186
187 private void handleBeanProperty(URI domain, PropertyDescriptor desc)
188 throws RDFHandlerException {
189 URI uri;
190 if (desc.getReadMethod().isAnnotationPresent(rdf.class)) {
191 rdf ann = desc.getReadMethod().getAnnotation(rdf.class);
192 uri = vf.createURI(ann.value()[0]);
193 } else {
194 uri = vf.createURI(domain.getNamespace(), desc.getName());
195 }
196 URI ns = vf.createURI(uri.getNamespace());
197 Class<?> range = desc.getPropertyType();
198 if (range.equals(Set.class)) {
199 range = Object.class;
200 Type t = desc.getReadMethod().getGenericReturnType();
201 if (t instanceof ParameterizedType) {
202 ParameterizedType pt = (ParameterizedType) t;
203 Type[] args = pt.getActualTypeArguments();
204 if (args.length == 1 && args[0] instanceof Class)
205 range = (Class) args[0];
206 }
207 }
208 URI datatype = getDatatype(range);
209 if (datatype == null) {
210 handleStatement(uri, RDF.TYPE, OWL.OBJECTPROPERTY);
211 handleStatement(uri, RDFS.RANGE, createURI(range));
212 } else if (datatype.equals(RDFS.RESOURCE)) {
213 handleStatement(uri, RDF.TYPE, RDF.PROPERTY);
214 handleStatement(uri, RDFS.RANGE, datatype);
215 } else {
216 handleStatement(uri, RDF.TYPE, OWL.DATATYPEPROPERTY);
217 handleStatement(uri, RDFS.RANGE, datatype);
218 }
219 handleStatement(uri, RDFS.DOMAIN, domain);
220 if (range.equals(desc.getPropertyType()))
221 handleStatement(uri, RDF.TYPE, OWL.FUNCTIONALPROPERTY);
222 handleStatement(uri, RDFS.LABEL, desc.getDisplayName());
223 handleStatement(uri, RDFS.COMMENT, desc.getShortDescription());
224 handleStatement(uri, RDFS.ISDEFINEDBY, ns);
225 Method getter = desc.getReadMethod();
226 if (getter.isAnnotationPresent(rdf.class)) {
227 String[] eq = getter.getAnnotation(rdf.class).value();
228 for (int i = 1; i < eq.length; i++) {
229 handleStatement(uri, RDFS.SUBPROPERTYOF, vf.createURI(eq[i]));
230 }
231 }
232 if (getter.isAnnotationPresent(inverseOf.class)) {
233 inverseOf io = getter.getAnnotation(inverseOf.class);
234 for (String inv : io.value()) {
235 handleStatement(uri, OWL.INVERSEOF, vf.createURI(inv));
236 }
237 }
238 Method setter = desc.getWriteMethod();
239 if (setter.isAnnotationPresent(oneOf.class)) {
240 oneOf oo = setter.getAnnotation(oneOf.class);
241 String dt = oo.datatype();
242 BNode list = createList(oo.label(), dt);
243 if (list != null) {
244 handleStatement(uri, OWL.ONEOF, list);
245 }
246 list = createList(oo.value());
247 if (list != null) {
248 handleStatement(uri, OWL.ONEOF, list);
249 }
250 }
251 }
252
253 private BNode createList(Object[] objects) throws RDFHandlerException {
254 BNode list = null, origin = null;
255 for (Object obj : objects) {
256 if (list == null) {
257 origin = list = vf.createBNode();
258 handleStatement(list, RDF.TYPE, RDF.LIST);
259 } else {
260 BNode rest = vf.createBNode();
261 handleStatement(list, RDF.REST, rest);
262 list = rest;
263 handleStatement(list, RDF.TYPE, RDF.LIST);
264 }
265 handleStatement(list, RDF.FIRST, createURI(obj));
266 }
267 if (list != null) {
268 handleStatement(list, RDF.REST, RDF.NIL);
269 }
270 return origin;
271 }
272
273 private BNode createList(String[] labels, String datatype)
274 throws RDFHandlerException {
275 BNode list = null, origin = null;
276 for (String label : labels) {
277 if (list == null) {
278 origin = list = vf.createBNode();
279 handleStatement(list, RDF.TYPE, RDF.LIST);
280 } else {
281 BNode rest = vf.createBNode();
282 handleStatement(list, RDF.REST, rest);
283 list = rest;
284 handleStatement(list, RDF.TYPE, RDF.LIST);
285 }
286 handleStatement(list, RDF.FIRST, vf.createLiteral(label, datatype));
287 }
288 if (list != null) {
289 handleStatement(list, RDF.REST, RDF.NIL);
290 }
291 return origin;
292 }
293
294 private URI getDatatype(Class<?> range) {
295 if (range.equals(Object.class))
296 return RDFS.RESOURCE;
297 if (range.equals(String.class))
298 return XMLSchema.STRING;
299 try {
300 URI datatype = lc.getDatatype(range);
301 if (datatype.getNamespace().equals("java:"))
302 return null;
303 return datatype;
304 } catch (ElmoConversionException e) {
305 return null;
306 }
307 }
308
309 private void handleStatement(Resource subj, URI pred, String obj)
310 throws RDFHandlerException {
311 handleStatement(subj, pred, vf.createLiteral(obj));
312 }
313
314 private void handleStatement(Resource subj, URI pred, Value obj)
315 throws RDFHandlerException {
316 target.handleStatement(vf.createStatement(subj, pred, obj));
317 }
318
319 }