- fixed handling of primitve types in sesame-facading (MARMOTTA-235) - improved connection handling (try-finally-close) - added more expressive logging
Project: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/commit/79265a7f Tree: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/tree/79265a7f Diff: http://git-wip-us.apache.org/repos/asf/incubator-marmotta/diff/79265a7f Branch: refs/heads/develop Commit: 79265a7f8dd2a0659ec3bc92367141f0c753bfdc Parents: b0e0c99 Author: Jakob Frank <[email protected]> Authored: Tue May 7 10:30:29 2013 +0200 Committer: Jakob Frank <[email protected]> Committed: Tue May 7 10:30:29 2013 +0200 ---------------------------------------------------------------------- .../commons/sesame/facading/impl/FacadingImpl.java | 84 +++++++------ .../facading/impl/FacadingInvocationHandler.java | 95 ++++++++------- .../commons/sesame/facading/util/FacadeUtils.java | 39 ++++-- .../src/test/resources/logback.xml | 1 + 4 files changed, 123 insertions(+), 96 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/79265a7f/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingImpl.java ---------------------------------------------------------------------- diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingImpl.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingImpl.java index e10cd13..4976592 100644 --- a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingImpl.java +++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingImpl.java @@ -27,7 +27,6 @@ import org.apache.marmotta.commons.sesame.facading.annotations.RDFType; import org.apache.marmotta.commons.sesame.facading.api.Facading; import org.apache.marmotta.commons.sesame.facading.model.Facade; import org.apache.marmotta.commons.sesame.facading.util.FacadeUtils; -import org.apache.marmotta.commons.sesame.model.Namespaces; import org.openrdf.model.Resource; import org.openrdf.model.URI; import org.openrdf.repository.RepositoryConnection; @@ -38,18 +37,19 @@ import org.slf4j.LoggerFactory; /** * Offers methods for loading and proxying Facades. A {@link Facade} is an interface that defines a - * Java object with convenient Java methods around a KiWiResource and makes it possible to use RDF + * Java object with convenient Java methods around a {@link Resource} and makes it possible to use RDF * properties like Java Bean properties from inside Java. * <p/> - * The facading service is used by many other services, e.g. ContentItemService and TaggingService, - * to provide access on a higher level than raw RDF resources. - * - * + * The facading service is to provide access on a higher level than raw RDF resources. * <p/> - * User: Sebastian Schaffert + * @author Sebastian Schaffert <[email protected]> + * @author Jakob Frank <[email protected]> */ public class FacadingImpl implements Facading { + private static final URI RDF_TYPE = org.openrdf.model.vocabulary.RDF.TYPE; + + private static Logger log = LoggerFactory.getLogger(FacadingImpl.class); @@ -61,13 +61,13 @@ public class FacadingImpl implements Facading { } /** - * Create an instance of C that facades the resource given as argument using the {@link RDF} annotations provided - * to the getter or setter methods of Cto map to properties of the resource in the triple store. + * Create an instance of {@code C} that facades the resource given as argument using the {@link RDF} annotations provided + * to the getter or setter methods of {@code C} to map to properties of the resource in the triple store. * * * @param r the resource to facade * @param type the facade type as a class - * @return + * @return a facading proxy of type {@code C} */ @Override public <C extends Facade> C createFacade(Resource r, Class<C> type) { @@ -76,57 +76,62 @@ public class FacadingImpl implements Facading { if(FacadeUtils.isFacadeAnnotationPresent(type, RDFContext.class)) { String s_context = FacadeUtils.getFacadeAnnotation(type,RDFContext.class).value(); context = connection.getValueFactory().createURI(s_context); + log.debug("applying context {} for facade {} of {}", context, type.getSimpleName(), r); } return createFacade(r, type, context); } /** - * Create an instance of C that facades the resource given as argument using the {@link RDF} annotations provided - * to the getter or setter methods of Cto map to properties of the resource in the triple store. + * Create an instance of {@code C} that facades the resource given as argument using the {@link RDF} annotations provided + * to the getter or setter methods of {@code C} to map to properties of the resource in the triple store. * Additionally, it puts the facade into the given context, a present {@link RDFContext} annotation is ignored. * This is useful if the {@link RDFContext} annotation for Facades is not applicable, * e.g. if the context is dynamically generated. - - * * * @param r the resource to facade * @param type the facade type as a class * @param context the context of the facade - * @return + * @return a facading proxy of type {@code C} */ @Override public <C extends Facade> C createFacade(Resource r, Class<C> type, URI context) { if(r == null) { + log.trace("null facade for null resouce"); return null; - } else if(type.isInterface()) { + } else // if the interface is a Facade, we execute the query and then // create an invocation handler for each result to create proxy objects - if(FacadeUtils.isFacade(type)) { + if(type.isInterface() && FacadeUtils.isFacade(type)) { try { // support @RDFType annotation in facade - if(FacadeUtils.isFacadeAnnotationPresent(type,RDFType.class)) { - String[] a_type = FacadeUtils.getFacadeAnnotation(type,RDFType.class).value(); + if(FacadeUtils.isFacadeAnnotationPresent(type, RDFType.class)) { + if (!connection.isOpen()) { throw new IllegalStateException("the connection is already closed, cannot access triple-store."); } + if (!connection.isActive()) { throw new IllegalStateException("no active transaction, cannot access triple-store."); } + + String[] a_type = FacadeUtils.getFacadeAnnotation(type, RDFType.class).value(); for(String s_type : a_type) { - URI r_type = connection.getValueFactory().createURI(s_type); - URI p_type = connection.getValueFactory().createURI(Namespaces.NS_RDF + "type"); - connection.add(r, p_type, r_type, context); + final URI r_type = connection.getValueFactory().createURI(s_type); + connection.add(r, RDF_TYPE, r_type, context); + log.trace("added type {} to {} because of RDFType-Annotation", r_type, r); } } - FacadingInvocationHandler handler = new FacadingInvocationHandler(r,context,type,this,connection); - return type.cast(Proxy.newProxyInstance(type.getClassLoader(), - new Class[]{type}, - handler)); + FacadingInvocationHandler handler = new FacadingInvocationHandler(r, context, type, this, connection); + if (log.isDebugEnabled()) { + if (context != null) { + log.debug("New Facading: {} delegating to {} (@{})", type.getSimpleName(), r, context); + } else { + log.debug("New Facading: {} delegating to {}", type.getSimpleName(), r); + } + } + return type.cast(Proxy.newProxyInstance(type.getClassLoader(), new Class[]{type}, handler)); } catch (RepositoryException e) { - log.error("error while accessing triple store",e); + log.error("error while accessing triple store", e); return null; } } else { throw new IllegalArgumentException("interface passed as parameter is not a Facade (" + type.getCanonicalName() + ")"); } - } else { - throw new IllegalArgumentException("interface passed as parameter is not a Facade (" + type.getCanonicalName() + ")"); - } } /** @@ -145,6 +150,7 @@ public class FacadingImpl implements Facading { if(FacadeUtils.isFacadeAnnotationPresent(type, RDFContext.class)) { String s_context = FacadeUtils.getFacadeAnnotation(type,RDFContext.class).value(); context = connection.getValueFactory().createURI(s_context); + log.debug("applying context {} for facade {} of {}", context, type.getSimpleName(), list); } return createFacade(list, type, context); } @@ -161,11 +167,12 @@ public class FacadingImpl implements Facading { */ @Override public <C extends Facade> Collection<C> createFacade(Collection<? extends Resource> list, Class<C> type, URI context) { - log.debug("createFacadeList: creating {} facade over {} content items",type.getName(),list.size()); + log.trace("createFacadeList: creating {} facade over {} content items",type.getName(),list.size()); LinkedList<C> result = new LinkedList<C>(); if(type.isAnnotationPresent(RDFFilter.class)) { try { - final URI p_type = connection.getValueFactory().createURI(Namespaces.NS_RDF + "type"); + if (!connection.isOpen()) { throw new IllegalStateException("the connection is already closed, cannot access triple-store."); } + if (!connection.isActive()) { throw new IllegalStateException("no active transaction, cannot access triple-store."); } // if the RDFType annotation is present, filter out content items that are of the wrong type LinkedList<URI> acceptable_types = new LinkedList<URI>(); @@ -181,9 +188,9 @@ public class FacadingImpl implements Facading { for(Resource item : list) { boolean accept = acceptable_types.size() == 0; // true for empty filter for(URI rdf_type : acceptable_types) { - if(connection.hasStatement(item, p_type, rdf_type, true)) { + if(connection.hasStatement(item, RDF_TYPE, rdf_type, true)) { accept = true; - log.debug("accepting resource #0 because type matches (#1)",item.toString(),rdf_type.stringValue()); + log.trace("accepting resource {} because type matches ({})",item.toString(),rdf_type.stringValue()); break; } } @@ -191,7 +198,7 @@ public class FacadingImpl implements Facading { result.add(createFacade(item,type,context)); } } - log.debug("createFacadeList: filtered #0 content items because they did not match the necessary criteria",list.size()-result.size()); + log.debug("createFacadeList: filtered {} content items because they did not match the necessary criteria",list.size()-result.size()); } catch (RepositoryException ex) { log.error("error while accessing RDF repository",ex); } @@ -248,18 +255,19 @@ public class FacadingImpl implements Facading { public <C extends Facade> boolean isFacadeable(Resource r, Class<C> type, URI context) { if (FacadeUtils.isFacadeAnnotationPresent(type, RDFType.class)) { try { - final URI p_type = connection.getValueFactory().createURI(Namespaces.NS_RDF + "type"); + if (!connection.isOpen()) { throw new IllegalStateException("the connection is already closed, cannot access triple store."); } + if (!connection.isActive()) { throw new IllegalStateException("no active transaction, cannot access triple-store."); } String[] rdfTypes = FacadeUtils.getFacadeAnnotation(type, RDFType.class).value(); boolean facadeable = true; for (String s_type : rdfTypes) { - facadeable &= connection.hasStatement(r, p_type, connection.getValueFactory().createURI(s_type), true, context); + facadeable &= connection.hasStatement(r, RDF_TYPE, connection.getValueFactory().createURI(s_type), true, context); } // also check for @RDFFilter if (FacadeUtils.isFacadeAnnotationPresent(type, RDFFilter.class)) { String[] filterTypes = FacadeUtils.getFacadeAnnotation(type, RDFFilter.class).value(); for (String s_type : filterTypes) { - facadeable &= connection.hasStatement(r, p_type, connection.getValueFactory().createURI(s_type), true, context); + facadeable &= connection.hasStatement(r, RDF_TYPE, connection.getValueFactory().createURI(s_type), true, context); } } return facadeable; http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/79265a7f/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingInvocationHandler.java ---------------------------------------------------------------------- diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingInvocationHandler.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingInvocationHandler.java index fb3fbcd..fb70791 100644 --- a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingInvocationHandler.java +++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingInvocationHandler.java @@ -49,7 +49,8 @@ import java.util.*; * implementation as parameter. Interfaces that make use of this invocation handler need to extend * the {@link Facade} interface. * - * @author Sebastian Schaffert + * @author Sebastian Schaffert <[email protected]> + * @author Jakob Frank <[email protected]> */ class FacadingInvocationHandler implements InvocationHandler { @@ -57,7 +58,7 @@ class FacadingInvocationHandler implements InvocationHandler { GET(false, 0, "get"), SET(true, 1, "set"), ADD(true, 1, "add"), - DEL(true, 0, "del", "delete", "remove"), + DEL(true, 0, "del", "delete", "remove", "rm"), HAS(false, 0, "has", "is"); @@ -129,7 +130,7 @@ class FacadingInvocationHandler implements InvocationHandler { private final HashMap<String, Object> fieldCache; - private Logger log = LoggerFactory.getLogger(FacadingInvocationHandler.class); + private final Logger log; /** * Indicates if the cache is used, by default is false. @@ -137,6 +138,7 @@ class FacadingInvocationHandler implements InvocationHandler { private boolean useCache; public FacadingInvocationHandler(Resource item, URI context, Class<? extends Facade> facade, Facading facadingService, RepositoryConnection connection) { + this.log = LoggerFactory.getLogger(facade.getName() + "!" + this.getClass().getSimpleName() + "@" + item.stringValue()); this.delegate = item; this.facadingService = facadingService; this.declaredFacade = facade; @@ -224,7 +226,8 @@ class FacadingInvocationHandler implements InvocationHandler { */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws InstantiationException, IllegalAccessException, RepositoryException { - if (!connection.isOpen()) { throw new IllegalAccessException("the connection is already closed, cannot access proxy methods"); } + if (!connection.isOpen()) { throw new IllegalAccessException("the connection is already closed, cannot access proxy methods."); } + if (!connection.isActive()) { throw new IllegalAccessException("no active transaction, cannot access triple-store."); } // handle default methods: if (FacadingInvocationHelper.checkMethodSig(method, "hashCode")) { @@ -470,13 +473,16 @@ class FacadingInvocationHandler implements InvocationHandler { connection.remove((Resource) null, prop, delegate, context); } else if (!predicate.isInverse() && loc != null) { final RepositoryResult<Statement> statements = connection.getStatements(delegate, prop, null, false, context); - while (statements.hasNext()) { - final Statement s = statements.next(); - if (FacadingInvocationHelper.checkLocale(loc, s.getObject())) { - connection.remove(s); + try { + while (statements.hasNext()) { + final Statement s = statements.next(); + if (FacadingInvocationHelper.checkLocale(loc, s.getObject())) { + connection.remove(s); + } } + } finally { + statements.close(); } - statements.close(); } else if (predicate.isInverse() && loc != null) { throw new IllegalArgumentException("A combination of @RDFInverse and a Literal is not possible"); } } @@ -612,7 +618,7 @@ class FacadingInvocationHandler implements InvocationHandler { final Collection<Object> result = FacadingInvocationHelper.createCollection(collectionType, Collections.<Object> emptyList()); final URI property = connection.getValueFactory().createURI(rdf_property); - for (final String s : getProperties(entity, property, null, null)) { + for (final String s : getProperties(entity, property, loc, context)) { result.add(FacadeUtils.transformToBaseType(s, tCls)); } @@ -643,7 +649,6 @@ class FacadingInvocationHandler implements InvocationHandler { URI property = connection.getValueFactory().createURI(rdf_property); RepositoryResult<Statement> triples = connection.getStatements(entity, property, null, false); - try { if (triples.hasNext()) { Statement triple = triples.next(); @@ -676,7 +681,6 @@ class FacadingInvocationHandler implements InvocationHandler { URI property = connection.getValueFactory().createURI(rdf_property); RepositoryResult<Statement> triples = connection.getStatements(null, property, entity, false); - try { if (triples.hasNext()) { Statement triple = triples.next(); @@ -705,19 +709,20 @@ class FacadingInvocationHandler implements InvocationHandler { * */ private <C> Set<C> queryOutgoingAll(Resource entity, String rdf_property, Class<C> returnType) throws RepositoryException { - URI property = connection.getValueFactory().createURI(rdf_property); - - RepositoryResult<Statement> triples = connection.getStatements(entity, property, null, false); - - Set<C> dupSet = new LinkedHashSet<C>(); + final URI property = connection.getValueFactory().createURI(rdf_property); - while (triples.hasNext()) { - Statement triple = triples.next(); - if (returnType.isInstance(triple.getObject())) { - dupSet.add(returnType.cast(triple.getObject())); + final Set<C> dupSet = new LinkedHashSet<C>(); + final RepositoryResult<Statement> triples = connection.getStatements(entity, property, null, false); + try { + while (triples.hasNext()) { + Statement triple = triples.next(); + if (returnType.isInstance(triple.getObject())) { + dupSet.add(returnType.cast(triple.getObject())); + } } + } finally { + triples.close(); } - triples.close(); return dupSet; @@ -730,20 +735,20 @@ class FacadingInvocationHandler implements InvocationHandler { * */ private <C> Set<C> queryIncomingAll(Resource entity, String rdf_property, Class<C> returnType) throws RepositoryException { + final URI property = connection.getValueFactory().createURI(rdf_property); - URI property = connection.getValueFactory().createURI(rdf_property); - - RepositoryResult<Statement> triples = connection.getStatements(null, property, entity, false); - - Set<C> dupSet = new LinkedHashSet<C>(); - - while (triples.hasNext()) { - Statement triple = triples.next(); - if (returnType.isInstance(triple.getSubject())) { - dupSet.add(returnType.cast(triple.getSubject())); + final Set<C> dupSet = new LinkedHashSet<C>(); + final RepositoryResult<Statement> triples = connection.getStatements(null, property, entity, false); + try { + while (triples.hasNext()) { + Statement triple = triples.next(); + if (returnType.isInstance(triple.getSubject())) { + dupSet.add(returnType.cast(triple.getSubject())); + } } + } finally { + triples.close(); } - triples.close(); return dupSet; } @@ -769,23 +774,25 @@ class FacadingInvocationHandler implements InvocationHandler { } private Set<String> getProperties(Resource entity, URI property, Locale loc, URI context) throws RepositoryException { - String lang = loc == null ? null : loc.getLanguage().toLowerCase(); - - RepositoryResult<Statement> candidates = connection.getStatements(entity, property, null, false, context); + final String lang = loc == null ? null : loc.getLanguage().toLowerCase(); - Set<String> values = new HashSet<String>(); - while (candidates.hasNext()) { - Statement triple = candidates.next(); + final Set<String> values = new HashSet<String>(); + final RepositoryResult<Statement> candidates = connection.getStatements(entity, property, null, false, context); + try { + while (candidates.hasNext()) { + Statement triple = candidates.next(); - if (triple.getObject() instanceof Literal) { - Literal l = (Literal) triple.getObject(); + if (triple.getObject() instanceof Literal) { + Literal l = (Literal) triple.getObject(); - if (lang == null || lang.equals(l.getLanguage())) { - values.add(l.stringValue()); + if (lang == null || lang.equals(l.getLanguage())) { + values.add(l.stringValue()); + } } } + } finally { + candidates.close(); } - candidates.close(); return values; } http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/79265a7f/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/util/FacadeUtils.java ---------------------------------------------------------------------- diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/util/FacadeUtils.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/util/FacadeUtils.java index f5bf702..a9a777f 100644 --- a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/util/FacadeUtils.java +++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/util/FacadeUtils.java @@ -17,6 +17,7 @@ package org.apache.marmotta.commons.sesame.facading.util; +import org.apache.commons.lang.LocaleUtils; import org.apache.marmotta.commons.sesame.facading.model.Facade; import org.apache.marmotta.commons.util.DateUtils; import org.openrdf.model.Resource; @@ -295,40 +296,50 @@ public class FacadeUtils { * @return * @throws IllegalArgumentException */ + @SuppressWarnings("unchecked") public static <T> T transformToBaseType(String value, Class<T> returnType) throws IllegalArgumentException { // transformation to appropriate primitive type + /* + * README: the "dirty" cast: "(T) x" instead of "returnType.cast(x)" is required since + * .cast does not work for primitive types (int, double, float, etc...). + * Somehow it results in a ClassCastException + */ if(Integer.class.equals(returnType) || int.class.equals(returnType)) { if(value == null) { - return returnType.cast(0); + return (T)(Integer)(0); } - return returnType.cast(Integer.parseInt(value)); + return (T)(Integer.decode(value)); } else if(Long.class.equals(returnType) || long.class.equals(returnType)) { if(value == null) { - return returnType.cast(0L); + return (T)(Long)(0L); } - return returnType.cast(Long.parseLong(value)); + return (T)(Long.decode(value)); } else if(Double.class.equals(returnType) || double.class.equals(returnType)) { if(value == null) { - return returnType.cast(0.0); + return (T)(Double)(0.0); } - return returnType.cast(Double.parseDouble(value)); + return (T)(Double.valueOf(value)); } else if(Float.class.equals(returnType) || float.class.equals(returnType)) { if(value == null) { - return returnType.cast(0.0F); + return (T)(Float)(0.0F); } - return returnType.cast(Float.parseFloat(value)); + return (T)(Float.valueOf(value)); } else if(Byte.class.equals(returnType) || byte.class.equals(returnType)) { if(value == null) { - return returnType.cast((byte) 0); + return (T)(Byte)((byte) 0); } - return returnType.cast(Byte.parseByte(value)); + return (T)(Byte.decode(value)); } else if(Boolean.class.equals(returnType) || boolean.class.equals(returnType)) { - return returnType.cast(Boolean.parseBoolean(value)); + return (T)(Boolean.valueOf(value)); } else if(Character.class.equals(returnType) || char.class.equals(returnType)) { if(value == null) { - return null; + if (Character.class.equals(returnType)){ + return null; + } else { + return (T) new Character((char) 0); + } } else if(value.length() > 0) { - return returnType.cast(value.charAt(0)); + return (T)(Character)(value.charAt(0)); } else { return null; } @@ -336,7 +347,7 @@ public class FacadeUtils { if(value == null) { return null; } else { - return returnType.cast(new Locale(value)); + return returnType.cast(LocaleUtils.toLocale(value)); } } else if (Date.class.equals(returnType)) { if(value == null) { http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/79265a7f/commons/sesame-tools-facading/src/test/resources/logback.xml ---------------------------------------------------------------------- diff --git a/commons/sesame-tools-facading/src/test/resources/logback.xml b/commons/sesame-tools-facading/src/test/resources/logback.xml index 1bfecff..864df3a 100644 --- a/commons/sesame-tools-facading/src/test/resources/logback.xml +++ b/commons/sesame-tools-facading/src/test/resources/logback.xml @@ -21,6 +21,7 @@ <pattern>%d{HH:mm:ss.SSS} %highlight(%level) %cyan(%logger{15}) - %m%n</pattern> </encoder> </appender> + <logger name="org.apache.marmotta.commons.sesame.facading.concurrent.model" level="TRACE" /> <root level="${root-level:-INFO}"> <appender-ref ref="CONSOLE"/> </root>
