/* * Copyright (c) 2007, 2010, James Leigh All 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 net.enilink.komma.em.internal; import java.io.Closeable; import java.io.IOException; import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.common.collect.MapMaker; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.Provider; import com.google.inject.name.Named; import net.enilink.commons.iterator.ConvertingIterator; import net.enilink.commons.iterator.Filter; import net.enilink.commons.iterator.IExtendedIterator; import net.enilink.commons.iterator.WrappedIterator; import net.enilink.composition.ClassResolver; import net.enilink.composition.cache.annotations.Cacheable; import net.enilink.composition.mappers.RoleMapper; import net.enilink.composition.properties.PropertySet; import net.enilink.composition.properties.komma.ConversionUtil; import net.enilink.composition.properties.traits.Mergeable; import net.enilink.composition.properties.traits.PropertySetOwner; import net.enilink.composition.properties.traits.Refreshable; import net.enilink.composition.traits.Behaviour; import net.enilink.komma.core.IEntity; import net.enilink.komma.core.IEntityManager; import net.enilink.komma.core.IEntityManagerFactory; import net.enilink.komma.core.IGraph; import net.enilink.komma.core.ILiteral; import net.enilink.komma.core.INamespace; import net.enilink.komma.core.IQuery; import net.enilink.komma.core.IReference; import net.enilink.komma.core.IReferenceable; import net.enilink.komma.core.IStatement; import net.enilink.komma.core.IStatementPattern; import net.enilink.komma.core.ITransaction; import net.enilink.komma.core.IUpdate; import net.enilink.komma.core.IValue; import net.enilink.komma.core.InferencingCapability; import net.enilink.komma.core.Initializable; import net.enilink.komma.core.KommaException; import net.enilink.komma.core.Literal; import net.enilink.komma.core.LockModeType; import net.enilink.komma.core.Statement; import net.enilink.komma.core.StatementPattern; import net.enilink.komma.core.TransactionRequiredException; import net.enilink.komma.core.URI; import net.enilink.komma.core.URIs; import net.enilink.komma.dm.IDataManager; import net.enilink.komma.dm.IDataManagerUpdate; import net.enilink.komma.em.concepts.IResource; import net.enilink.komma.em.internal.behaviours.IEntityManagerAware; import net.enilink.komma.em.internal.query.Query; import net.enilink.komma.em.internal.query.Update; import net.enilink.komma.em.util.RESULTS; import net.enilink.komma.literals.LiteralConverter; import net.enilink.vocab.rdf.RDF; import net.enilink.vocab.xmlschema.XMLSCHEMA; /** * Handles operations of {@link IEntityManager}. */ public abstract class AbstractEntityManager implements IEntityManager, IEntityManagerInternal { protected static Logger log = LoggerFactory.getLogger(AbstractEntityManager.class); private static final URI RESULT_NODE = RESULTS.TYPE_RESULT; private ClassResolver<URI> classResolver; protected IDataManager dm; @Inject protected IEntityManagerFactory factory; @Inject protected Injector injector; @Inject private LiteralConverter literalConverter; @Inject private Provider<Locale> locale; private RoleMapper<URI> mapper; private Map<Object, IReference> merged = new MapMaker().weakKeys().makeMap(); private volatile ResourceManager resourceManager; private volatile TypeManager typeManager; private volatile Map<URI, String> uriToPrefix = new ConcurrentHashMap<>(); private volatile Map<String, URI> prefixToUri = new ConcurrentHashMap<>(); private static final URI[] NO_CONTEXTS = new URI[0]; private URI[] readContexts = NO_CONTEXTS; private URI[] modifyContexts = NO_CONTEXTS; protected Map<String, Object> properties; @Override public void add(Iterable<? extends IStatement> statements) { // defaults to consider the imports to avoid adding duplicate statements add(statements, false); } @Override public void add(Iterable<? extends IStatement> statements, boolean ignoreImports) { dm.add(new ConvertingIterator<IStatement, IStatement>(statements.iterator()) { @Override protected IStatement convert(IStatement stmt) { if (!(stmt.getSubject() instanceof Behaviour || stmt.getPredicate() instanceof Behaviour) && stmt.getObject() instanceof IValue) { return stmt; } return new Statement(getReference(stmt.getSubject()), getReference(stmt.getPredicate()), toValue(stmt.getObject()), stmt.getContext(), stmt.isInferred()); } }, ignoreImports ? modifyContexts : readContexts, modifyContexts); } private <C extends Collection<URI>> C addConcept(IReference resource, Class<?> role, C set) { URI type = mapper.findType(role); if (type == null) { throw new KommaException("Concept is anonymous or is not registered: " + role.getSimpleName()); } getTypeManager().addType(resource, type); set.add(type); return set; } private void appendFilter(Class<?> concept, StringBuilder query) { Collection<URI> types = new HashSet<URI>(); mapper.findSubTypes(concept, types); Iterator<URI> iter = types.iterator(); if (iter.hasNext()) { while (iter.hasNext()) { query.append("{ ?subj a <"); query.append(iter.next()).append(">}\n"); if (iter.hasNext()) { query.append(" UNION "); } } } else { throw new KommaException("Concept not registered: " + concept.getSimpleName()); } } private boolean assertConceptsRecorded(IEntity bean, Class<?>... concepts) { for (Class<?> concept : concepts) { assert !concept.isInterface() || concept.isAssignableFrom(bean.getClass()) : "Concept has not been recorded: " + concept.getSimpleName(); } return true; } private IReference assignReference(Object bean) { synchronized (merged) { if (merged.containsKey(bean)) { return merged.get(bean); } IReference reference = getReference(bean); if (reference == null) { reference = getResourceManager().createResource(null); } merged.put(bean, reference); return reference; } } @Override public void clear() { dm.remove(new Statement(null, null, null), modifyContexts); } @Override public void clearNamespaces() { uriToPrefix = null; dm.clearNamespaces(); } @Override public void close() { if (dm != null) { dm.close(); } dm = null; } @Override public void close(Iterator<?> iter) { if (iter instanceof Closeable) { try { ((Closeable) iter).close(); } catch (IOException e) { throw new KommaException(e); } } } private <T> Class<?>[] combine(Class<T> concept, Class<?>... concepts) { Class<?>[] roles; if (concepts == null || concepts.length == 0) { roles = new Class<?>[] { concept }; } else { roles = new Class<?>[concepts.length + 1]; roles[0] = concept; System.arraycopy(concepts, 0, roles, 1, concepts.length); } return roles; } @Override public boolean contains(Object entity) { if (entity instanceof IEntity) { return this.equals(((IEntity) entity).getEntityManager()); } else if (entity instanceof Behaviour<?>) { Behaviour<?> behaviour = (Behaviour<?>) entity; Object delegate = behaviour.getBehaviourDelegate(); if (delegate instanceof IEntity) { return this.equals(((IEntity) delegate).getEntityManager()); } } return false; } @Override public <T> T create(Class<T> concept, Class<?>... concepts) { return createNamed((net.enilink.komma.core.URI) null, concept, concepts); } @Override public IEntity create(IReference... concepts) { return createNamed(null, concepts); } @SuppressWarnings("unchecked") public IEntity createBean(IReference resource, Collection<URI> entityTypes, Collection<Class<?>> concepts, boolean restrictTypes, boolean initialize, IGraph graph) { if (resource == null) { throw new IllegalArgumentException("Resource argument must not be null."); } entityTypes = entityTypes != null ? new HashSet<URI>(entityTypes) : new HashSet<URI>(); if (!restrictTypes) { boolean retrieveTypes = true; if (graph != null) { // this ensures that only types with an IRI are added to // entityTypes for (IReference type : (Collection<IReference>) (Collection<?>) graph .filter(resource, RDF.PROPERTY_TYPE, null).objects()) { URI typeUri = type.getURI(); if (typeUri != null) { entityTypes.add(typeUri); retrieveTypes = false; } } } if (retrieveTypes) { entityTypes.addAll(getTypeManager().getTypes(resource)); } } if (concepts != null && !concepts.isEmpty()) { for (Class<?> concept : concepts) { if (IValue.class == concept || IReference.class == concept || IEntity.class == concept || Object.class == concept) { continue; } URI type = mapper.findType(concept); if (type != null) { entityTypes.add(type); } else { log.warn("Unknown rdf type for concept class: " + concept); } } } IEntity bean = createBeanForClass(resource, classResolver.resolveComposite(entityTypes)); if (initialize) { if (bean instanceof Initializable) { // bean knows how to initialize itself ((Initializable) bean).init(graph); } if (graph != null) { initializeBean(bean, graph); } } return bean; } protected IEntity createBeanForClass(IReference resource, Class<?> type) { Object obj; try { obj = type.newInstance(); injector.injectMembers(obj); assert obj instanceof IEntityManagerAware : "core roles are not registered, check your deployed classpath"; IEntityManagerAware bean = (IEntityManagerAware) obj; bean.initReference(getReference(resource)); return (IEntity) bean; } catch (Exception e) { throw new KommaException(e); } } public ILiteral createLiteral(Object value, URI datatype) { return literalConverter.createLiteral(value, datatype); } public ILiteral createLiteral(String label, URI datatype, String language) { if (language != null) { return new Literal(label, language); } return createLiteral(label, datatype); } @SuppressWarnings("unchecked") public <T> T createNamed(net.enilink.komma.core.URI uri, Class<T> concept, Class<?>... concepts) { IReference resource = getResourceManager().createResource(uri); Set<URI> types = new HashSet<URI>(); boolean isActive = false; try { isActive = getTransaction().isActive(); if (!isActive) { getTransaction().begin(); } addConcept(resource, concept, types); for (Class<?> c : concepts) { addConcept(resource, c, types); } if (!isActive) { getTransaction().commit(); } } catch (Exception e) { if (!isActive && getTransaction().isActive()) { getTransaction().rollback(); } if (e instanceof KommaException) { throw (KommaException) e; } throw new KommaException(e); } Class<?>[] allConcepts = combine(concept, concepts); IEntity bean = createBean(resource, types, Arrays.asList(allConcepts), true, false, null); assert assertConceptsRecorded(bean, allConcepts); return (T) bean; } @Override public IEntity createNamed(net.enilink.komma.core.URI uri, IReference... concepts) { IReference resource = getResourceManager().createResource(uri); try { boolean active = dm.getTransaction().isActive(); if (!active) { dm.getTransaction().begin(); } for (IReference concept : concepts) { dm.add(new Statement(resource, RDF.PROPERTY_TYPE, concept), modifyContexts); } if (!active) { dm.getTransaction().commit(); } } catch (KommaException e) { if (dm.getTransaction().isActive()) { dm.getTransaction().rollback(); } throw new KommaException(e); } // include at least the given concepts as rdf:types of the resulting // bean List<URI> types = null; if (concepts.length > 0) { types = new ArrayList<URI>(); for (IReference concept : concepts) { if (concept.getURI() != null) { types.add(concept.getURI()); } } } return createBean(resource, types, null, true, false, null); } public IQuery<?> createQuery(String query) { return createQuery(query, null, true); } public IQuery<?> createQuery(String query, String baseURI) { return createQuery(query, baseURI, true); } public IQuery<?> createQuery(String query, boolean includeInferred) { return createQuery(query, null, includeInferred); } public IQuery<?> createQuery(String query, String baseURI, boolean includeInferred) { log.debug("Query: {}", query); IQuery<?> result = new Query<Object>(this, dm.createQuery(query, baseURI, includeInferred, readContexts)); injector.injectMembers(result); if (properties != null) { // set properties on the query object for (String propertyName : result.getSupportedProperties()) { Object value = properties.get(propertyName); if (value != null) { result.setProperty(propertyName, value); } } } return result; } @Override public IReference createReference() { return dm.blankNode(); } @Override public IReference createReference(String id) { return dm.blankNode(id); } public IUpdate createUpdate(String update, String baseURI, boolean includeInferred) { log.debug("Update: {}", update); IDataManagerUpdate dmUpdate = dm.createUpdate(update, baseURI, includeInferred, readContexts, modifyContexts); injector.injectMembers(dmUpdate); IUpdate result = new Update(this, dmUpdate); injector.injectMembers(result); return result; } @Override @SuppressWarnings("unchecked") public <T> T assignTypes(Object entity, Class<T> concept, Class<?>... concepts) { IReference resource = getReference(entity); Collection<URI> types = new ArrayList<URI>(); boolean isActive = false; try { getTypes(entity.getClass(), types); isActive = getTransaction().isActive(); if (!isActive) { getTransaction().begin(); } addConcept(resource, concept, types); for (Class<?> c : concepts) { addConcept(resource, c, types); } if (!isActive) { getTransaction().commit(); } } catch (Exception e) { if (!isActive && getTransaction().isActive()) { getTransaction().rollback(); } } Class<?>[] allConcepts = combine(concept, concepts); IEntity bean = createBean(resource, types, null, false, true, null); assert assertConceptsRecorded(bean, allConcepts); return (T) bean; } protected <T> IExtendedIterator<T> filterResultNode(Set<T> values) { return WrappedIterator.create(values.iterator()).filterDrop(new Filter<T>() { @Override public boolean accept(T o) { return RESULT_NODE.equals(o); } }); } @Override public IEntity find(IReference reference) { return createBean(reference, null, null, false, true, null); } @Override @SuppressWarnings("unchecked") public <T> T find(IReference reference, Class<T> concept, Class<?>... concepts) { Class<?>[] allConcepts = Arrays.copyOf(concepts, concepts.length + 1); allConcepts[allConcepts.length - 1] = concept; return (T) find(reference, Arrays.asList(allConcepts)); } public IEntity find(IReference reference, Collection<Class<?>> concepts) { return createBean(reference, null, concepts, false, true, null); } public <T> IExtendedIterator<T> findAll(final Class<T> concept) { StringBuilder querySb = new StringBuilder(); querySb.append("SELECT DISTINCT ?subj WHERE {"); appendFilter(concept, querySb); querySb.append("}"); return createQuery(querySb.toString()).bindResultType(concept).evaluate(); } @Override @SuppressWarnings("unchecked") public <T> T findRestricted(IReference reference, Class<T> concept, Class<?>... concepts) { return (T) findRestricted(reference, Arrays.asList(combine(concept, concepts))); } @Override public IReference findRestricted(IReference reference, Collection<Class<?>> concepts) { // if type is restricted to IReference then simply return the // corresponding reference value if (concepts.size() == 1) { Class<?> concept = concepts.iterator().next(); if ((IValue.class.equals(concept) || IReference.class.equals(concept))) { return reference; } } return createBean(reference, null, concepts, true, true, null); } @Override public IEntityManagerFactory getFactory() { return factory; } @Override public InferencingCapability getInferencing() { return dm.getInferencing(); } protected List<Object> getInstances(Iterator<?> values, Class<?> type, IGraph graph) { List<Object> instances = new ArrayList<Object>(); while (values.hasNext()) { instances.add(toInstance(values.next(), type, graph)); } return instances; } @Override public Locale getLocale() { return locale.get(); } @Override public LockModeType getLockMode(Object entity) { return null; } @Override public URI getNamespace(String prefix) { if (prefixToUri.isEmpty()) { cacheNamespaces(); } return prefixToUri.get(prefix); } @Override public IExtendedIterator<INamespace> getNamespaces() { return dm.getNamespaces(); } @Override public String getPrefix(URI namespaceUri) { if (uriToPrefix.isEmpty()) { cacheNamespaces(); } return uriToPrefix.get(namespaceUri); } protected void clearNamespaceCache() { uriToPrefix.clear(); prefixToUri.clear(); } protected void cacheNamespaces() { for (INamespace ns : getNamespaces()) { uriToPrefix.put(ns.getURI(), ns.getPrefix()); prefixToUri.put(ns.getPrefix(), ns.getURI()); } } @Override public Map<String, Object> getProperties() { return properties == null ? Collections.<String, Object> emptyMap() : Collections.unmodifiableMap(properties); } protected IReference getReference(Object bean) { if (bean instanceof IReferenceable) { return ((IReferenceable) bean).getReference(); } if (bean instanceof IReference) { return (IReference) bean; } return null; } private IReference getReferenceOrFail(Object entity) { IReference reference = getReference(entity); if (reference == null) { throw new KommaException("Unknown Entity: " + entity); } return reference; } @Override public ITransaction getTransaction() { return dm.getTransaction(); } private <C extends Collection<URI>> C getTypes(Class<?> role, C set) { URI type = mapper.findType(role); if (type == null) { Class<?> superclass = role.getSuperclass(); if (superclass != null) { getTypes(superclass, set); } Class<?>[] interfaces = role.getInterfaces(); for (int i = 0, n = interfaces.length; i < n; i++) { getTypes(interfaces[i], set); } } else { set.add(type); } return set; } @Override public boolean hasMatch(IReference subject, IReference predicate, Object object) { return dm.hasMatch(subject, predicate, toValue(object), true, readContexts); } protected void initializeBean(IEntity bean, IGraph graph) { if (!graph.contains(bean, null, null)) { return; } try { if (bean instanceof PropertySetOwner) { for (IReference predicate : new ArrayList<IReference>(graph.filter(bean, null, null).predicates())) { if (graph.contains(bean, predicate, null)) { PropertySet<Object> propertySet = ((PropertySetOwner) bean) .getPropertySet(predicate.toString()); if (propertySet != null) { Set<Object> objects = new LinkedHashSet<Object>( graph.filter(bean, predicate, null).objects()); graph.remove(bean, predicate, null); propertySet .init(getInstances(filterResultNode(objects), propertySet.getElementType(), graph)); } } } } for (Method method : bean.getClass().getMethods()) { if (method.getParameterTypes().length > 0) { continue; } // initialize a cached method if (method.isAnnotationPresent(Cacheable.class)) { Cacheable cacheable = method.getAnnotation(Cacheable.class); if (cacheable.key().isEmpty()) { continue; } // initialize cache entries Class<?> returnType = method.getReturnType(); boolean isIterator = false; boolean isBoolean = false; Collection<Object> collection = null; if (Iterator.class.isAssignableFrom(returnType)) { isIterator = true; collection = new ArrayList<Object>(); } else if (Set.class.isAssignableFrom(returnType)) { collection = new HashSet<Object>(); } else if (List.class.isAssignableFrom(returnType)) { collection = new ArrayList<Object>(); } else if (Collection.class.isAssignableFrom(returnType)) { collection = new ArrayList<Object>(); } else if (Boolean.class.equals(returnType) || Boolean.TYPE.equals(returnType)) { isBoolean = true; } if (collection != null || isBoolean) { URI keyUri = URIs.createURI(cacheable.key()); if (graph.contains(bean, keyUri, null)) { Set<Object> objects = new LinkedHashSet<Object>(graph.filter(bean, keyUri, null).objects()); graph.remove(bean, keyUri, null); IExtendedIterator<Object> valuesIt = filterResultNode(objects); Object value = null; if (collection != null) { // get element type Type t = method.getGenericReturnType(); Class<?> valueType = null; if (t instanceof ParameterizedType) { ParameterizedType pt = (ParameterizedType) t; Type[] args = pt.getActualTypeArguments(); if (args.length == 1 && args[0] instanceof Class<?>) { valueType = (Class<?>) args[0]; } } collection.addAll(getInstances(valuesIt, valueType, graph)); if (isIterator) { value = collection.iterator(); } else { value = collection; } } else if (isBoolean) { value = valuesIt.hasNext(); } initializeCache(bean, cacheable.key(), value); } } } } } catch (Exception e) { throw new KommaException(e); } } protected void initializeCache(IEntity entity, Object property, Object value) { // does nothing - overridden by subclasses } private boolean isEntity(Class<?> type) { if (type == null) return false; for (Class<?> face : type.getInterfaces()) { if (mapper.findType(face) != null) return true; } if (mapper.findType(type) != null) return true; return isEntity(type.getSuperclass()); } @Override public boolean isOpen() { return dm != null && dm.isOpen(); } @Override public void joinTransaction() { if (!isOpen()) throw new TransactionRequiredException(); } public void lock(Object entity, LockModeType mode) { throw new UnsupportedOperationException("locking is not supported"); } @Override public void lock(Object entity, LockModeType lockMode, Map<String, Object> properties) { lock(entity, lockMode); } @Override public IExtendedIterator<IStatement> match(IReference subject, IReference predicate, Object object) { return dm.match(subject, predicate, toValue(object), true, readContexts); } @Override public IExtendedIterator<IStatement> matchAsserted(IReference subject, IReference predicate, IValue object) { return dm.match(subject, predicate, toValue(object), false, readContexts); } @Override public boolean hasMatchAsserted(IReference subject, IReference predicate, Object object) { return dm.hasMatch(subject, predicate, toValue(object), false, readContexts); } @SuppressWarnings("unchecked") public <T> T merge(T bean) { if (bean == null) { return null; } else if (bean instanceof Set<?>) { // so we can merge both a List and a Set Set<?> old = (Set<?>) bean; Set<Object> set = new HashSet<Object>(old.size()); for (Object o : old) { set.add(merge(o)); } return (T) set; } else { IReference resource = assignReference(bean); boolean isActive = getTransaction().isActive(); if (!isActive) { getTransaction().begin(); } try { Class<?> proxy = bean.getClass(); Set<URI> types = new HashSet<URI>(); if (bean instanceof IResource) { // this is already a mapped RDF resource for (IReference type : ((IResource) bean).getRdfTypes()) { if (type.getURI() != null) { types.add(type.getURI()); } } } else { // this is a detached object types = getTypes(proxy, types); for (URI type : types) { getTypeManager().addType(resource, type); } } Object result = createBean(resource, types, null, false, true, null); if (result instanceof Mergeable) { ((Mergeable) result).merge(bean); } if (!isActive) { getTransaction().commit(); } return (T) result; } catch (Throwable t) { throw new KommaException(t); } finally { if (!isActive && getTransaction().isActive()) { getTransaction().rollback(); } } } } public void refresh(Object entity) { if (entity instanceof Refreshable) { ((Refreshable) entity).refresh(); } } @Override public void refresh(Object entity, LockModeType lockMode) { refresh(entity); } @Override public void refresh(Object entity, LockModeType lockMode, Map<String, Object> properties) { refresh(entity); } @Override public void refresh(Object entity, Map<String, Object> properties) { refresh(entity); } @Override public void remove(Iterable<? extends IStatementPattern> statements) { dm.remove(new ConvertingIterator<IStatementPattern, IStatementPattern>(statements.iterator()) { @Override protected IStatementPattern convert(IStatementPattern stmt) { if (!(stmt.getSubject() instanceof Behaviour || stmt.getPredicate() instanceof Behaviour) && stmt.getObject() instanceof IValue) { return stmt; } IReference s = getReference(stmt.getSubject()); IReference p = getReference(stmt.getPredicate()); IValue o = toValue(stmt.getObject()); return stmt instanceof IStatement ? new Statement(s, p, o, stmt.getContext(), ((IStatement) stmt).isInferred()) : new StatementPattern(s, p, o, stmt.getContext()); } }, modifyContexts); } public void remove(Object entity) { if (entity instanceof IStatementPattern) { remove(Collections.singleton((IStatementPattern) entity)); } else { IReference resource = getReferenceOrFail(entity); getResourceManager().removeResource(resource); } } private boolean canDelete(IReference deletedSubject, Object object, boolean anonymousOnly) { if (!(object instanceof IReference && (((IReference) object).getURI() == null || !anonymousOnly))) { return false; } // this could also be done with // if (! em.hasMatchAsserted(null, null, node)) // { ... } // iff no transaction is running IExtendedIterator<IStatement> refs = matchAsserted(null, null, (IReference) object); boolean canDelete = true; for (IStatement refStmt : refs) { if (!refStmt.getSubject().equals(deletedSubject)) { canDelete = false; break; } } refs.close(); return canDelete; } public void removeRecursive(Object entity, boolean anonymousOnly) { IReference resource = null; if (entity instanceof IStatement) { IStatement stmt = (IStatement) entity; remove(Collections.singleton(stmt)); resource = getReference(stmt.getObject()); } else { resource = getReferenceOrFail(entity); } if (resource != null) { Set<IReference> seen = new HashSet<>(); Queue<IReference> nodes = new LinkedList<IReference>(); nodes.add(((IReference) resource)); while (!nodes.isEmpty()) { IReference node = nodes.remove(); if (seen.add(node)) { for (IStatement stmt : matchAsserted(node, null, null)) { Object o = stmt.getObject(); if (canDelete(node, o, anonymousOnly)) { nodes.add((IReference) o); } } remove(node); } } } } @Override public void removeTypes(Object entity, Class<?>... concepts) { IReference resource = getReferenceOrFail(entity); boolean isActive = false; try { isActive = getTransaction().isActive(); if (!isActive) { getTransaction().begin(); } for (Class<?> c : concepts) { URI type = mapper.findType(c); if (type == null) { continue; } getTypeManager().removeType(resource, type); } if (!isActive) { getTransaction().commit(); } } catch (KommaException e) { if (!isActive && getTransaction().isActive()) { getTransaction().rollback(); } } } @Override public void removeNamespace(String prefix) { dm.removeNamespace(prefix); clearNamespaceCache(); } @SuppressWarnings("unchecked") @Override public <T> T rename(T bean, net.enilink.komma.core.URI uri) { IReference before = getReferenceOrFail(bean); IReference after = getResourceManager().createResource(uri); getResourceManager().renameResource(before, after); T newBean = (T) createBean(after, null, null, false, true, null); Object renamed = bean instanceof Behaviour<?> ? ((Behaviour<?>) bean).getBehaviourDelegate() : bean; if (renamed instanceof IEntityManagerAware) { ((IEntityManagerAware) renamed).initReference(((IReferenceable) newBean).getReference()); } return newBean; } @Inject protected void setClassResolver(ClassResolver<URI> classResolver) { this.classResolver = classResolver; } @Inject protected void setDataManager(IDataManager dm) { this.dm = dm; } protected ResourceManager getResourceManager() { if (resourceManager == null) { resourceManager = new ResourceManager(dm, modifyContexts); } return resourceManager; } protected TypeManager getTypeManager() { if (typeManager == null) { typeManager = new TypeManager(dm, readContexts, modifyContexts); } return typeManager; } @Inject(optional = true) protected void setContexts(@Named("modifyContexts") Set<URI> modifyContexts, @Named("readContexts") Set<URI> readContexts) { this.modifyContexts = modifyContexts.toArray(new URI[modifyContexts.size()]); LinkedHashSet<URI> readAndModifyContexts = new LinkedHashSet<URI>(readContexts); readAndModifyContexts.retainAll(modifyContexts); readAndModifyContexts.addAll(readContexts); this.readContexts = readAndModifyContexts.toArray(new URI[readAndModifyContexts.size()]); } /** * If it is bound then the current child entity manager factory is injected * with this method that overrides the previously injected field. * * @param factory * The current child entity manager factory. */ @Inject(optional = true) protected void setCurrentFactory(@Named("currentFactory") IEntityManagerFactory factory) { this.factory = factory; } @Override public void setNamespace(String prefix, URI uri) { dm.setNamespace(prefix, uri); clearNamespaceCache(); } protected Map<String, Object> ensureProperties() { if (properties == null) { properties = new HashMap<>(); } return properties; } @Override public void setProperty(String propertyName, Object value) { ensureProperties().put(propertyName, value); } @Inject(optional = true) protected void setProperties(@Named("net.enilink.komma.properties") Map<String, Object> properties) { ensureProperties().putAll(properties); } @Inject protected void setRoleMapper(RoleMapper<URI> mapper) { this.mapper = mapper; } @Override public boolean supportsRole(Class<?> role) { return mapper.findType(role) != null; } @Override public Collection<Class<?>> rolesForType(URI type) { return mapper.findRoles(type, new HashSet<Class<?>>()); } @Override public Object toInstance(IValue value) { return toInstance(value, null, null); } @Override public Object toInstance(Object value, Class<?> type, IGraph graph) { if (value instanceof IReference) { Collection<URI> types = null; if (type != null) { URI typeUri = mapper.findType(type); if (typeUri != null) { // ensure that specified type is added as role to resulting // object types = Collections.singleton(typeUri); } } IEntity bean = createBean((IReference) value, types, null, false, true, graph); if (log.isTraceEnabled()) { if (!createQuery("ASK {?s ?p ?o}").setParameter("s", (IReference) value).getBooleanResult()) { log.trace("Warning: Unknown entity: " + value); } } return bean; } ILiteral literal = (ILiteral) value; Object instance; if (type != null && IValue.class.isAssignableFrom(type)) { instance = createLiteral(literal.getLabel(), literal.getDatatype(), literal.getLanguage()); } else { instance = literalConverter.createObject(literal); if (type != null) { if (instance == null) { if (type.isPrimitive()) { instance = ConversionUtil.convertValue(type, 0, null); } } else if (!type.isAssignableFrom(ConversionUtil.wrapperType(instance.getClass()))) { // convert instance if actual type is not compatible // with valueType instance = ConversionUtil.convertValue(type, instance, instance); } } } return instance; } @Override public IValue toValue(Object instance) { if (instance == null) { return null; } IReference reference = getReference(instance); if (reference != null) { return reference; } if (instance instanceof IValue) { return (IValue) instance; } Class<?> type = instance.getClass(); if (literalConverter.isDatatype(type)) { return literalConverter.createLiteral(instance, null); } synchronized (merged) { if (merged.containsKey(instance)) { return merged.get(instance); } } if (IEntity.class.isAssignableFrom(type) || isEntity(type)) { return toValue(merge(instance)); } return literalConverter.createLiteral(String.valueOf(instance), XMLSCHEMA.TYPE_STRING); } }