org.openrdf.repository.object.compiler.model.RDFClass Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alibaba-composition-object Show documentation
Show all versions of alibaba-composition-object Show documentation
The Object Composition library merges multiple Java objects into a single multi-subject object.
/*
* Copyright (c) 2008-2010, Zepheira LLC Some rights reserved.
* Copyright (c) 2011 Talis Inc., Some rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* - Neither the name of the openrdf.org nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
*/
package org.openrdf.repository.object.compiler.model;
import java.io.File;
import java.io.IOException;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import org.openrdf.annotations.Iri;
import org.openrdf.model.Model;
import org.openrdf.model.Resource;
import org.openrdf.model.URI;
import org.openrdf.model.Value;
import org.openrdf.model.datatypes.XMLDatatypeUtil;
import org.openrdf.model.impl.URIImpl;
import org.openrdf.model.vocabulary.OWL;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.model.vocabulary.RDFS;
import org.openrdf.repository.object.compiler.JavaNameResolver;
import org.openrdf.repository.object.compiler.RDFList;
import org.openrdf.repository.object.compiler.source.JavaMessageBuilder;
import org.openrdf.repository.object.compiler.source.JavaMethodBuilder;
import org.openrdf.repository.object.compiler.source.JavaPropertyBuilder;
import org.openrdf.repository.object.exceptions.ObjectStoreConfigException;
import org.openrdf.repository.object.traits.RDFObjectBehaviour;
import org.openrdf.repository.object.vocabulary.MSG;
/**
* Helper object for traversing the OWL model.
*
* @author James Leigh
*
*/
public class RDFClass extends RDFEntity {
private static final URI NOTHING = new URIImpl(OWL.NAMESPACE + "Nothing");
public RDFClass(Model model, Resource self) {
super(model, self);
}
public boolean isDatatype() {
if (self instanceof URI
&& XMLDatatypeUtil.isBuiltInDatatype((URI) self))
return true;
if (self.equals(RDFS.LITERAL))
return true;
if (self instanceof URI) {
URI uri = (URI) self;
if (uri.getNamespace().equals(RDF.NAMESPACE)
&& uri.getLocalName().equals("PlainLiteral"))
return true;
}
return isA(RDFS.DATATYPE);
}
public RDFClass getRange(URI pred) {
return getRange(new RDFProperty(model, pred));
}
public RDFClass getRange(RDFProperty property) {
return getRange(property, true);
}
public RDFClass getRange(RDFProperty property, boolean convariant) {
RDFClass type = getRangeOrNull(property, convariant);
if (type == null)
return new RDFClass(getModel(), RDFS.RESOURCE);
return type;
}
private RDFClass getRangeOrNull(RDFProperty property, boolean convariant) {
if (convariant) {
for (RDFClass c : getRDFClasses(RDFS.SUBCLASSOF)) {
if (c.isA(OWL.RESTRICTION)) {
if (property.equals(c.getRDFProperty(OWL.ONPROPERTY))) {
RDFClass type = c.getRDFClass(OWL.ALLVALUESFROM);
if (type != null) {
return type;
}
}
}
}
}
for (RDFClass c : getRDFClasses(RDFS.SUBCLASSOF)) {
if (c.isA(OWL.RESTRICTION) || c.equals(this) || MSG.MESSAGE.equals(c.getURI()))
continue;
RDFClass type = ((RDFClass) c).getRangeOrNull(property, convariant);
if (type != null) {
return type;
}
}
for (RDFClass r : property.getRDFClasses(RDFS.RANGE)) {
return r;
}
for (RDFProperty p : property.getRDFProperties(RDFS.SUBPROPERTYOF)) {
RDFClass superRange = getRangeOrNull(p, convariant);
if (superRange != null) {
return superRange;
}
}
return null;
}
public boolean isFunctional(RDFProperty property) {
return isFunctionalProperty(property);
}
public List extends Value> getList(URI pred) {
List extends Value> list = null;
for (Value obj : model.filter(self, pred, null).objects()) {
if (list == null && obj instanceof Resource) {
list = new RDFList(model, (Resource) obj).asList();
} else {
List extends Value> other = new RDFList(model, (Resource) obj)
.asList();
if (!list.equals(other)) {
other.removeAll(list);
((List) list).addAll(other);
}
}
}
return list;
}
public List getParameters() {
TreeSet set = new TreeSet();
addParameters(set, new HashSet());
List list = new ArrayList();
for (String uri : set) {
list.add(new RDFProperty(model, new URIImpl(uri)));
}
return list;
}
public RDFProperty getResponseProperty() {
Set set = new HashSet();
set.add(new RDFProperty(model, MSG.OBJECT_SET));
set.add(new RDFProperty(model, MSG.LITERAL_SET));
set.add(new RDFProperty(model, MSG.OBJECT));
set.add(new RDFProperty(model, MSG.LITERAL));
for (RDFClass c : getRestrictions()) {
RDFProperty property = c.getRDFProperty(OWL.ONPROPERTY);
String valuesFrom = c.getString(OWL.ALLVALUESFROM);
if (RDFS.RESOURCE.stringValue().equals(valuesFrom))
continue;
if (NOTHING.stringValue().equals(valuesFrom))
continue;
BigInteger card = c.getBigInteger(OWL.CARDINALITY);
if (card != null && 0 == card.intValue())
continue;
BigInteger max = c.getBigInteger(OWL.MAXCARDINALITY);
if (max != null && 0 == max.intValue())
continue;
if (set.contains(property))
return property;
}
for (RDFClass c : getRestrictions()) {
RDFProperty property = c.getRDFProperty(OWL.ONPROPERTY);
String valuesFrom = c.getString(OWL.ALLVALUESFROM);
if (RDFS.RESOURCE.stringValue().equals(valuesFrom))
continue;
if (set.contains(property))
return property;
}
for (RDFClass c : getRestrictions()) {
RDFProperty property = c.getRDFProperty(OWL.ONPROPERTY);
if (set.contains(property))
return property;
}
return new RDFProperty(model, MSG.OBJECT_SET);
}
public boolean isMinCardinality(RDFProperty property) {
BigInteger one = BigInteger.valueOf(1);
for (RDFClass c : getRDFClasses(RDFS.SUBCLASSOF)) {
if (c.isA(OWL.RESTRICTION)) {
if (property.equals(c.getRDFProperty(OWL.ONPROPERTY))) {
if (one.equals(c.getBigInteger(OWL.MAXCARDINALITY))
&& one.equals(c.getBigInteger(OWL.MINCARDINALITY))
|| one.equals(c.getBigInteger(OWL.CARDINALITY))) {
return true;
}
}
} else if (equals(c)) {
continue;
} else if (c.isMinCardinality(property)) {
return true;
}
}
return false;
}
public boolean isEmpty(JavaNameResolver resolver) {
Collection properties = getDeclaredProperties();
if (properties.size() > 1)
return false;
if (!properties.isEmpty()) {
URI uri = properties.iterator().next().getURI();
if (!MSG.TARGET.equals(uri))
return false;
}
if (!getDeclaredMessages().isEmpty())
return false;
// TODO check annotations
return false;
}
public File generateSourceCode(File dir, JavaNameResolver resolver)
throws IOException, ObjectStoreConfigException {
File source = createSourceFile(dir, resolver);
if (isDatatype()) {
JavaMessageBuilder builder = new JavaMessageBuilder(source, resolver);
String pkg = resolver.getPackageName(this.getURI());
String simple = resolver.getSimpleName(getURI());
if (pkg == null) {
builder.imports(simple);
} else {
builder.pkg(pkg);
builder.imports(pkg + '.' + simple);
}
classHeader(simple, builder);
stringConstructor(builder);
builder.close();
} else {
JavaMessageBuilder builder = new JavaMessageBuilder(source, resolver);
interfaceHeader(builder);
constants(builder);
for (RDFProperty prop : getDeclaredProperties()) {
property(builder, prop);
}
for (RDFClass type : getDeclaredMessages()) {
builder.message(type);
}
builder.close();
}
return source;
}
public List getFunctionalDatatypeProperties() {
List list = new ArrayList();
for (RDFProperty property : getProperties()) {
if (isFunctional(property) && getRange(property).isDatatype()) {
list.add(property);
}
}
return list;
}
public Collection getDeclaredMessages() {
Set set = new TreeSet();
for (Resource res : model.filter(null, OWL.ALLVALUESFROM, self)
.subjects()) {
if (model.contains(res, OWL.ONPROPERTY, MSG.TARGET)) {
for (Resource msg : model.filter(null, RDFS.SUBCLASSOF, res)
.subjects()) {
if (MSG.MESSAGE.equals(msg))
continue;
RDFClass rc = new RDFClass(model, msg);
if (rc.isMessageClass()) {
set.add(rc);
}
}
}
}
return set;
}
public Collection getDeclaredProperties() {
TreeSet set = new TreeSet();
for (Resource prop : model.filter(null, RDFS.DOMAIN, self).subjects()) {
if (prop instanceof URI) {
set.add(prop.stringValue());
}
}
for (RDFClass res : getRDFClasses(RDFS.SUBCLASSOF)) {
if (res.isA(OWL.RESTRICTION)) {
RDFProperty prop = res.getRDFProperty(OWL.ONPROPERTY);
if (isFunctional(prop) == isFunctionalProperty(prop)) {
set.add(prop.getURI().stringValue());
}
}
}
List list = new ArrayList(set.size());
for (String uri : set) {
list.add(new RDFProperty(model, new URIImpl(uri)));
}
return list;
}
public Collection getRestrictions() {
Collection restrictions = new LinkedHashSet();
for (RDFClass c : getRDFClasses(RDFS.SUBCLASSOF)) {
if (c.isA(OWL.RESTRICTION)) {
restrictions.add(c);
} else if (equals(c)) {
continue;
} else {
restrictions.addAll(c.getRestrictions());
}
}
return restrictions;
}
public RDFProperty getRDFProperty(URI pred) {
Resource subj = model.filter(self, pred, null).objectResource();
if (subj == null)
return null;
return new RDFProperty(model, subj);
}
public boolean isMessageClass() {
return isMessage(this, new HashSet());
}
protected boolean isFunctionalProperty(RDFProperty property) {
if (property.isA(OWL.FUNCTIONALPROPERTY))
return true;
URI uri = property.getURI();
if (uri.equals(MSG.TARGET)
|| uri.equals(MSG.LITERAL)
|| uri.equals(MSG.OBJECT))
return true;
return false;
}
private void interfaceHeader(JavaMessageBuilder builder)
throws ObjectStoreConfigException {
String pkg = builder.getPackageName(this.getURI());
String simple = builder.getSimpleName(this.getURI());
if (pkg == null) {
builder.imports(simple);
} else {
builder.pkg(pkg);
builder.imports(pkg + '.' + simple);
}
builder.comment(this);
if (this.isA(OWL.DEPRECATEDCLASS)) {
builder.annotate(Deprecated.class);
}
builder.annotationProperties(this);
if (!builder.isAnonymous(this.getURI())) {
builder.annotateURI(Iri.class, "value", builder.getType(this.getURI()));
}
builder.interfaceName(simple);
for (RDFClass sups : this.getRDFClasses(RDFS.SUBCLASSOF)) {
if (sups.getURI() == null || sups.equals(this))
continue;
builder.extend(builder.getClassName(sups.getURI()));
}
}
private void constants(JavaMessageBuilder builder) {
List extends Value> oneOf = this.getList(OWL.ONEOF);
if (oneOf != null) {
Map names = new LinkedHashMap();
for (Value one : oneOf) {
if (one instanceof URI) {
URI uri = (URI) one;
String localPart = uri.getLocalName();
if (localPart.length() < 1) {
localPart = uri.stringValue();
}
String name = localPart.replaceAll("^[^a-zA-Z]", "_")
.replaceAll("\\W+", "_");
if (names.containsKey(name)) {
int count = 1;
while (names.containsKey(name + '_' + count)) {
count++;
}
name = name + '_' + count;
}
names.put(name, uri);
}
}
if (!names.isEmpty()) {
names = toUpperCase(names);
for (Map.Entry e : names.entrySet()) {
builder.staticURIField(e.getKey(), e.getValue());
}
if (!names.containsKey("ONEOF")) {
builder.staticURIArrayField("ONEOF", names.keySet());
}
}
}
}
private Map toUpperCase(Map words) {
Map insensitive = new LinkedHashMap();
for (String local : words.keySet()) {
String upper = local.toUpperCase();
if (insensitive.containsKey(upper))
return words; // case sensitive
insensitive.put(upper, words.get(local));
}
return insensitive;
}
private void stringConstructor(JavaMessageBuilder builder)
throws ObjectStoreConfigException {
String cn = builder.getClassName(this.getURI());
String simple = builder.getSimpleName(this.getURI());
JavaMethodBuilder method = builder.staticMethod("valueOf");
method.returnType(cn);
method.param(String.class.getName(), "value");
method.code("return new ").code(simple).code("(value);").end();
boolean child = false;
for (RDFClass sups : this.getRDFClasses(RDFS.SUBCLASSOF)) {
if (sups.getURI() == null || sups.equals(this))
continue;
// rdfs:Literal rdfs:subClassOf rdfs:Resource
if (!sups.isDatatype())
continue;
child = true;
}
if (child) {
JavaMethodBuilder code = builder.constructor();
code.param(String.class.getName(), "value");
code.code("super(value);");
code.end();
} else {
builder.field(String.class.getName(), "value");
JavaMethodBuilder code = builder.constructor();
code.param(String.class.getName(), "value");
code.code("this.value = value;");
code.end();
code = builder.method("toString", false).returnType(
String.class.getName());
code.code("return value;").end();
code = builder.method("hashCode", false).returnType("int");
code.code("return value.hashCode();").end();
code = builder.method("equals", false).returnType("boolean");
code.param(Object.class.getName(), "o");
String equals = "return getClass().equals(o.getClass()) && toString().equals(o.toString());";
code.code(equals).end();
}
}
private void property(JavaMessageBuilder builder, RDFProperty prop)
throws ObjectStoreConfigException {
JavaPropertyBuilder prop1 = builder.property(builder.getPropertyName(
this, prop));
builder.comment(prop1, prop);
if (prop.isA(OWL.DEPRECATEDPROPERTY)) {
prop1.annotate(Deprecated.class);
}
builder.annotationProperties(prop1, prop);
for (RDFClass c : getRestrictions()) {
RDFProperty property = c.getRDFProperty(OWL.ONPROPERTY);
if (prop.equals(property)) {
builder.annotationProperties(prop1, c);
}
}
URI type = builder.getType(prop.getURI());
prop1.annotateURI(Iri.class, "value", type);
String className = builder.getPropertyClassName(this, prop);
if (this.isFunctional(prop)) {
prop1.type(className);
} else {
prop1.setOf(className);
}
prop1.getter();
builder.comment(prop1, prop);
if (prop.isA(OWL.DEPRECATEDPROPERTY)) {
prop1.annotate(Deprecated.class);
}
builder.annotationProperties(prop1, prop);
prop1.annotateURI(Iri.class, "value", type);
prop1.openSetter();
prop1.closeSetter();
prop1.end();
}
private void addParameters(Set parameters, Set skip) {
for (Resource prop : model.filter(null, RDFS.DOMAIN, self).subjects()) {
if (isParameter(prop)) {
parameters.add(prop.stringValue());
}
}
for (Value sup : model.filter(self, RDFS.SUBCLASSOF, null).objects()) {
if (isRDFSOrOWL(sup) || !skip.add(sup))
continue;
new RDFClass(model, (Resource) sup).addParameters(parameters, skip);
}
}
private boolean isRDFSOrOWL(Value sup) {
if (self instanceof URI && sup instanceof URI) {
String ns = ((URI) self).getNamespace();
return ns.equals(RDF.NAMESPACE) || ns.equals(RDFS.NAMESPACE)
|| ns.equals(OWL.NAMESPACE);
}
return false;
}
private boolean isParameter(Resource prop) {
return !model.contains(prop, RDF.TYPE, OWL.ANNOTATIONPROPERTY)
&& prop instanceof URI
&& !prop.stringValue().startsWith(MSG.NAMESPACE);
}
private boolean isMessage(RDFEntity message, Set set) {
if (MSG.MESSAGE.equals(message.getURI()))
return true;
set.add(message);
for (RDFClass sup : message.getRDFClasses(RDFS.SUBCLASSOF)) {
if (!set.contains(sup) && isMessage(sup, set))
return true;
}
return false;
}
private BigInteger getBigInteger(URI pred) {
Value value = model.filter(self, pred, null).objectValue();
if (value == null)
return null;
return new BigInteger(value.stringValue());
}
private Collection getProperties() {
return getProperties(new HashSet(),
new ArrayList());
}
private Collection getProperties(Set exclude,
Collection list) {
if (exclude.add(getResource())) {
list.addAll(getDeclaredProperties());
for (RDFClass sup : getRDFClasses(RDFS.SUBCLASSOF)) {
list = sup.getProperties(exclude, list);
}
}
return list;
}
private void classHeader(String simple, JavaMessageBuilder builder)
throws ObjectStoreConfigException {
builder.comment(this);
if (this.isDatatype()) {
builder.annotationProperties(this);
URI type = builder.getType(this.getURI());
builder.annotateURI(Iri.class, "value", type);
builder.className(simple);
} else {
builder.annotationProperties(this);
builder.abstractName(simple);
}
if (this.isDatatype()) {
List supers = new ArrayList();
for (RDFClass sups : this.getRDFClasses(RDFS.SUBCLASSOF)) {
if (sups.getURI() == null || sups.equals(this))
continue;
// rdfs:Literal rdfs:subClassOf rdfs:Resource
if (!sups.isDatatype())
continue;
supers.add(sups.getURI());
}
if (supers.size() == 1) {
builder.extend(builder.getClassName(supers.get(0)));
}
}
if (!this.isDatatype()) {
URI range = this.getRange(MSG.TARGET).getURI();
if (range != null) {
builder.implement(builder.getClassName(range));
}
builder.implement("org.openrdf.repository.object.RDFObject");
builder.implement(RDFObjectBehaviour.class.getName());
}
}
}