All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openrdf.repository.object.ObjectFactory Maven / Gradle / Ivy

Go to download

The Object Repository maps Java objects to and from RDF resources and OWL classes to Java classes in a non-intrusive manner that enables developers to work at the object level.

The newest version!
/*
 * Copyright (c) 2009-2010, James Leigh and 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;

import org.openrdf.idGenerator.IDGenerator;
import org.openrdf.model.*;
import org.openrdf.model.vocabulary.RDF;
import org.openrdf.repository.object.advisers.helpers.ObjectQueryFactory;
import org.openrdf.repository.object.composition.ClassResolver;
import org.openrdf.repository.object.exceptions.ObjectCompositionException;
import org.openrdf.repository.object.managers.LiteralManager;
import org.openrdf.repository.object.traits.ManagedRDFObject;
import org.openrdf.repository.object.traits.RDFObjectBehaviour;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.*;

/**
 * Converts between {@link Value} and objects without accessing the repository.
 * 
 * @author James Leigh
 * 
 */
public class ObjectFactory {
	static final String VAR_PREFIX = "subj"; 
	private LiteralManager lm;
	private ClassResolver resolver;
	private ObjectConnection connection;
	private Map, ObjectQueryFactory> factories;
    private IDGenerator idGenerator;

	protected ObjectFactory(ClassResolver resolver, LiteralManager lm) {
		assert lm != null;
		assert resolver != null;
		this.lm = lm;
		this.resolver = resolver;
	}

	/**
	 * @return The ClassLoader used by this ObjectFactory.
	 */
	public ClassLoader getClassLoader() {
		return resolver.getClassLoader();
	}

	/**
	 * Converts a literal into an object.
	 */
	public Object createObject(Literal literal) {
		return lm.createObject(literal);
	}

	/**
	 * Converts an object back into a literal.
	 */
	public Literal createLiteral(Object object) {
		return lm.createLiteral(object);
	}

	/**
	 * Converts an object into a literal or resource.
	 */
	public Value createValue(Object instance) {
		if (instance instanceof RDFObjectBehaviour) {
			RDFObjectBehaviour support = (RDFObjectBehaviour) instance;
			Object entity = support.getBehaviourDelegate();
			if (entity != instance)
				return createValue(entity);
		}
		if (instance instanceof RDFObject)
			return ((RDFObject) instance).getResource();
		if (instance instanceof Class) {
			URI type = getNameOf((Class) instance);
			if (type != null)
				return type;
		}
		return lm.createLiteral(instance);
	}

	/**
	 * Creates an anonymous object with no rdf:type.
	 */
	public RDFObject createObject() {
		if (connection == null)
			throw new IllegalStateException("No ObjectConnection");
		BNode node = connection.getValueFactory().createBNode();
		return createBean(node, resolver.resolveBlankEntity());

	}

	/**
	 * Creates an object with no rdf:type.
	 */
	public RDFObject createObject(String uri) {
		if (connection == null)
			throw new IllegalStateException("No ObjectConnection");
		ValueFactory vf = connection.getValueFactory();
		return createObject(vf.createURI(uri));
	}

	/**
	 * Creates an object with no rdf:type.
	 */
	public RDFObject createObject(Resource resource) {
		assert resource != null;
		if (resource instanceof URI)
			return createBean(resource, resolver.resolveEntity((URI) resource));
		return createBean(resource, resolver.resolveBlankEntity());
	}

	/**
	 * Creates an object with an assumed rdf:type.
	 */
	public  T createObject(String uri, Class type) {
		if (connection == null)
			throw new IllegalStateException("No ObjectConnection");
		ValueFactory vf = connection.getValueFactory();
		return createObject(vf.createURI(uri), type);
	}

	/**
	 * Creates an object with an assumed rdf:type.
	 */
	public  T createObject(Resource resource, Class type) {
		RDFObject obj;
		URI rdftype = getNameOf(type);
		if (rdftype == null) {
			obj = createObject(resource);
		} else {
			Set types = Collections.singleton(rdftype);
			obj = createObject(resource, types);
		}
		try {
			return type.cast(obj);
		} catch (ClassCastException e) {
			String msg = "Cannot cast resource " + obj + " to a "
					+ type.getName();
			ClassCastException cce = new ClassCastException(msg);
			cce.initCause(e);
			throw cce;
		}
	}

	/**
	 * Creates an object with assumed rdf:types.
	 */
	public RDFObject createObject(String uri, URI... types) {
		if (connection == null)
			throw new IllegalStateException("No ObjectConnection");
		ValueFactory vf = connection.getValueFactory();
		return createObject(vf.createURI(uri), types);
	}

	/**
	 * Creates an object with assumed rdf:types.
	 */
	public RDFObject createObject(Resource resource, URI... types) {
		assert types != null && types.length > 0;
		Set list =  new HashSet(Arrays.asList(types));
		return createObject(resource, list);
	}

	/**
	 * Creates an object with assumed rdf:types.
	 */
	public RDFObject createObject(String uri, Set types) {
		if (connection == null)
			throw new IllegalStateException("No ObjectConnection");
		ValueFactory vf = connection.getValueFactory();
		return createObject(vf.createURI(uri), types);
	}

	/**
	 * Creates an object with assumed rdf:types.
	 */
	public RDFObject createObject(Resource resource, Set types) {
		assert resource != null;

        // generate a new id in the case of a initial resource
        if(IDGenerator.BLANK_RESOURCE.equals(resource)) {
            if(idGenerator == null) {
                throw new IllegalStateException("No ID generator available");
            } else {
                resource = idGenerator.generateID(types);
            }
        }

		return createBean(resource, getObjectClass(resource, types));
	}

	/**
	 * @return true If the given type can be used as a concept
	 *         parameter.
	 */
	public boolean isNamedConcept(Class type) {
		return resolver.getRoleMapper().findType(type) != null;
	}

	public boolean isDatatype(Class type) {
		return lm.isDatatype(type);
	}

	public URI getNameOf(Class concept) {
		return resolver.getRoleMapper().findType(concept);
	}

	protected void setObjectConnection(ObjectConnection connection) {
		this.connection = connection;
		factories = new HashMap, ObjectQueryFactory>();
	}

	protected String createObjectQuery(Class concept, int bindings) {
		Collection subjectProperties = resolver.getPropertyMapper()
				.findFunctionalProperties(concept);
		Collection subjectFields = resolver.getPropertyMapper()
				.findFunctionalFields(concept);
		StringBuilder select = new StringBuilder();
		StringBuilder where = new StringBuilder();
		select.append("SELECT REDUCED ?subj");
		boolean namedTypePresent = resolver.getRoleMapper().isNamedTypePresent();
		if (namedTypePresent) {
			select.append(" ?subj_class");
		}
		where.append("\nWHERE { ");
		URI uri = getNameOf(concept);
		boolean typed = uri != null && bindings == 0;
		if (typed) {
			Collection types = new HashSet();
			resolver.getRoleMapper().findSubTypes(concept, types);
			Iterator iter = types.iterator();
			assert iter.hasNext();
			while (iter.hasNext()) {
				where.append("\n{ ?subj a <");
				where.append(iter.next().stringValue()).append(">}");
				if (iter.hasNext()) {
					where.append(" UNION ");
				}
			}
			if (namedTypePresent) {
				where.append("\nOPTIONAL {").append(" ?subj <");
				where.append(RDF.TYPE);
				where.append("> ?subj_class } ");
			}
		} else {
			where.append("\n?subj a ?subj_class .");
		}
		String type = RDF.TYPE.stringValue();
		for (PropertyDescriptor pd : subjectProperties) {
			String name = pd.getName();
			String pred = resolver.getPropertyMapper().findPredicate(pd);
			optional(select, name, where.append("\n"), null, pred);
			if (pd.getPropertyType().equals(Object.class)) {
				if (namedTypePresent) {
					String name_class = name + "_class";
					StringBuilder w = where.append("\n\t");
					optional(select, name_class, w, name, type).append("}\n");
				}
			} else if (isNamedConcept(pd.getPropertyType())) {
				Map map = findEagerProperties(pd.getPropertyType());
				for (String n : map.keySet()) {
					StringBuilder w = where.append("\n\t");
					optional(select, name + "_" + n, w, name, map.get(n)).append("}");
				}
				where.append("\n");
			}
			where.append("}");
		}
		for (Field f : subjectFields) {
			String name = f.getName();
			String pred = resolver.getPropertyMapper().findPredicate(f);
			optional(select, name, where.append("\n"), null, pred);
			if (f.getType().equals(Object.class)) {
				if (namedTypePresent) {
					String name_class = name + "_class";
					StringBuilder w = where.append("\n\t");
					optional(select, name_class, w, name, type).append("}\n");
				}
			} else if (isNamedConcept(f.getType())) {
				Map map = findEagerProperties(f.getType());
				for (String n : map.keySet()) {
					StringBuilder w = where.append("\n\t");
					optional(select, name + "_" + n, w, name, map.get(n)).append("}");
				}
				where.append("\n");
			}
			where.append("}");
		}
		if (bindings > 1) {
			where.append("\nFILTER (");
			for (int i = 0; i < bindings; i++) {
				where.append(" ?subj = $subj").append(i).append(" ||");
			}
			where.delete(where.length() - 2, where.length());
			where.append(")");
		}
		where.append(" } ");
		if (bindings > 1) {
			where.append("\nORDER BY ?subj");
		}
		return select.append(where).toString();
	}

	Class getObjectClass(Resource resource, Set types) {
		Class proxy;
		if (resource instanceof URI) {
			if (types.isEmpty()) {
				proxy = resolver.resolveEntity((URI) resource);
			} else {
				proxy = resolver.resolveEntity((URI) resource, types);
			}
		} else {
			if (types.isEmpty()) {
				proxy = resolver.resolveBlankEntity();
			} else {
				proxy = resolver.resolveBlankEntity(types);
			}
		}
		return proxy;
	}

	RDFObject createBean(Resource resource, Class proxy) {
		if (connection == null)
			throw new IllegalStateException("No ObjectConnection");
		try {
			ObjectQueryFactory factory = createObjectQueryFactory(proxy);
			Object obj = newInstance(proxy);
			ManagedRDFObject bean = (ManagedRDFObject) obj;
			bean.initRDFObject(resource, factory, connection);
			return (RDFObject) obj;
		} catch (InstantiationException e) {
			throw new ObjectCompositionException(e);
		} catch (IllegalAccessException e) {
			throw new ObjectCompositionException(e);
		}
	}

	private Map findEagerProperties(Class type) {
		Map result = resolver.getPropertyMapper().findEagerProperties(type);
		if (result == null && resolver.getRoleMapper().isNamedTypePresent())
			return Collections.singletonMap("class", RDF.TYPE.stringValue());
		if (result == null)
			return Collections.emptyMap();
		return result;
	}

	private StringBuilder optional(StringBuilder select, String name,
			StringBuilder where, String subj, String pred) {
		select.append(" ?subj_").append(name);
		where.append("OPTIONAL {");
		if (subj == null) {
			where.append(" ?subj");
		} else {
			where.append(" ?subj_").append(subj);
		}
		where.append(" <");
		return where.append(pred).append("> ?subj_").append(name);
	}

	private ObjectQueryFactory createObjectQueryFactory(Class proxy) {
		if (factories == null)
			return null;
		synchronized (factories) {
			ObjectQueryFactory factory = factories.get(proxy);
			if (factory == null) {
				factory = new ObjectQueryFactory(connection, resolver.getPropertyMapper());
				factories.put(proxy, factory);
			}
			return factory;
		}
	}

	private Object newInstance(Class proxy) throws InstantiationException,
			IllegalAccessException {
		ClassLoader pcl = proxy.getClassLoader();
		if (pcl == null)
			return proxy.newInstance();
		synchronized (pcl) {
			return proxy.newInstance();
		}
	}

    public IDGenerator getIdGenerator() {
        return idGenerator;
    }

    public void setIdGenerator(IDGenerator idGenerator) {
        this.idGenerator = idGenerator;
    }

	public ClassResolver getResolver() {
		return resolver;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy