You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@marmotta.apache.org by ja...@apache.org on 2013/02/21 16:30:45 UTC
[19/55] MARMOTTA-106: renamed packages in sesame-facading
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/at/newmedialab/sesame/facading/util/FacadeUtils.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/at/newmedialab/sesame/facading/util/FacadeUtils.java b/commons/sesame-tools-facading/src/main/java/at/newmedialab/sesame/facading/util/FacadeUtils.java
deleted file mode 100644
index f53d2a0..0000000
--- a/commons/sesame-tools-facading/src/main/java/at/newmedialab/sesame/facading/util/FacadeUtils.java
+++ /dev/null
@@ -1,359 +0,0 @@
-/**
- * Copyright (C) 2013 Salzburg Research.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package at.newmedialab.sesame.facading.util;
-
-import at.newmedialab.sesame.facading.model.Facade;
-
-import org.apache.marmotta.commons.util.DateUtils;
-import org.openrdf.model.Resource;
-import org.openrdf.model.Value;
-
-import java.lang.annotation.Annotation;
-import java.text.ParseException;
-import java.util.Collection;
-import java.util.Date;
-import java.util.Locale;
-
-/**
- * @author Sebastian Schaffert
- *
- */
-public class FacadeUtils {
-
- /**
- * Check whether a type is a Facade, i.e. inherits from the {@link Facade} interface
- *
- * @param <C>
- * @param clazz
- * @return
- */
- public static <C> boolean isFacade(Class<C> clazz) {
- return Facade.class.isAssignableFrom(clazz);
- }
-
- /**
- * Check whether a type is a {@link Value}.
- *
- * @param <C>
- * @param clazz
- * @return
- */
- public static <C> boolean isValue(Class<C> clazz) {
- return Value.class.isAssignableFrom(clazz);
- }
-
- /**
- * Check whether a type is a {@link Resource}.
- *
- * @param <C>
- * @param clazz
- * @return
- */
- public static <C> boolean isResource(Class<C> clazz) {
- return Resource.class.isAssignableFrom(clazz);
- }
-
-
- /**
- * Check whether a type is a {@link Facade}, i.e. the type or one of its superinterfaces has the
- * {@link Facade} annotation.
- *
- * @param <C>
- * @param clazz
- * @return
- */
- public static <C> boolean isFacadeAnnotationPresent(Class<C> clazz, Class<? extends Annotation> annotation) {
- if (clazz.isAnnotationPresent(annotation)) {
- return true;
- } else {
- for(final Class<?> iface : clazz.getInterfaces()) {
- if(iface.isAnnotationPresent(annotation)) {
- return true;
- }
- }
- if (clazz.getSuperclass() != null) {
- return isFacadeAnnotationPresent(clazz.getSuperclass(),annotation);
- }
- return false;
- }
- }
-
-
- public static <C extends Annotation,D> C getFacadeAnnotation(Class<D> clazz, Class<C> annotation) {
- if (clazz.isAnnotationPresent(annotation)) {
- return clazz.getAnnotation(annotation);
- } else {
- for(final Class<?> iface : clazz.getInterfaces()) {
- if(iface.isAnnotationPresent(annotation)) {
- return iface.getAnnotation(annotation);
- }
- }
- if (clazz.getSuperclass() != null) {
- return getFacadeAnnotation(clazz.getSuperclass(),annotation);
- }
- return null;
- }
-
- }
-
-
- /**
- * Returns true if the <code>clazz</code> argument is a {@link Facade}, otherwise it returns
- * false.
- *
- * @param in
- * the argument to test.
- * @return true if the <code>clazz</code> argument is a {@link Facade}.
- */
- public static boolean isFacade(Object in) {
-
- if (in == null) {
- return false;
- }
-
- final Class<?> clazz = in.getClass();
- final boolean result = isFacade(clazz);
-
- return result;
- }
-
- /**
- * Check whether a type is a collection (List, Set, ...).
- *
- * @param <C> the type of the class modeled by the
- * <code>clazz</code> argument Class object. For
- * example, the type of String.class is Class
- * <String>
- * @param clazz the type to test.
- * @return true if the type to test is a a type is a
- * collection (List, Set, ...).
- */
- public static <C> boolean isCollection(Class<C> clazz) {
-
- if (clazz == null) {
- return false;
- }
-
- return Collection.class.isAssignableFrom(clazz);
- }
-
-
- /**
- * Returns true if the <code>clazz</code> argument is a:
- * <ul>
- * <li>a primitive
- * <li>a primitive wrapper
- * <li>a java.lang.Locale class
- * <li>a java.lang.Date class
- * <li>a java.lang.String class
- * </ul>
- * otherwise it returns false.
- *
- * @param <C>
- * the type of the class modeled by the <code>clazz</code> argument Class object. For
- * example, the type of String.class is Class <String>.
- * @param clazz
- * the argument to test.
- * @return true if the <code>clazz</code> argument is a primitive, primitive wrapper, locale,
- * date or String.
- */
- public static <C> boolean isBaseType(Class<C> clazz) {
-
- if (clazz == null) {
- return false;
- }
-
- final boolean isPrimitive = clazz.isPrimitive();
- if (isPrimitive) {
- return true;
- }
-
- // if I compare the Locale.class with the clazz argument
- // I can avoid the infamous case when the clazz is null,
- // the Locale.class.equals(null) is false, always - at
- // least this sustains the theory. The same logic for
- // the other equals realtions.
- final boolean isLocale = Locale.class.equals(clazz);
- if (isLocale) {
- return true;
- }
-
- final boolean isDate = Date.class.equals(clazz);
- if (isDate) {
- return true;
- }
-
- final boolean isString = String.class.equals(clazz);
- if (isString) {
- return true;
- }
-
- final boolean isBoolean = Boolean.class.equals(clazz);
- if (isBoolean) {
- return true;
- }
-
- final Class<? super C> superClass = clazz.getSuperclass();
- final boolean isNumber = Number.class.equals(superClass);
- if (isNumber) {
- return true;
- }
-
- // even if the char is a primitive is not a number
- final boolean isCharacter = Character.class.equals(clazz);
- if (isCharacter) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns true if the <code>clazz</code> argument is a:
- * <ul>
- * <li>a primitive
- * <li>a primitive wrapper
- * </ul>
- * otherwise it returns false.
- *
- * @param <C> the type of the class modeled by the
- * <code>clazz</code> argument Class object. For
- * example, the type of String.class is Class
- * <String>.
- * @param clazz the argument to test.
- * @return true if the <code>clazz</code> argument is a
- * primitive or primitive wrapper.
- */
- public static <C> boolean isPrimitive(Class<C> clazz) {
-
- if (clazz == null) {
- return false;
- }
-
- final boolean isPrimitive = clazz.isPrimitive();
- if (isPrimitive) {
- return true;
- }
-
- // even if the char is a primitive is not a number
- final boolean isCharacter = Character.class.equals(clazz);
- if (isCharacter) {
- return true;
- }
-
- final Class<? super C> superClass = clazz.getSuperclass();
- final boolean isNumber = Number.class.equals(superClass);
- if (isNumber) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Returns true if the <code>in</code> argument is a:
- * <ul>
- * <li>a primitive
- * <li>a primitive wrapper
- * </ul>
- * otherwise it returns false.
- *
- * @param in the argument to test.
- * @return true if the <code>clazz</code> argument is a
- * primitive or primitive wrapper.
- */
- public static boolean isPrimitive(Object in) {
- if (in == null) {
- return false;
- }
-
- final Class<?> clazz = in.getClass();
- return isPrimitive(clazz);
- }
-
-
- /**
- * Transform a value passed as string to the base type (i.e. non-complex type) given as argument
- *
- * @param <T>
- * @param value
- * @param returnType
- * @return
- * @throws IllegalArgumentException
- */
- public static <T> T transformToBaseType(String value, Class<T> returnType) throws IllegalArgumentException {
- // transformation to appropriate primitive type
- if(Integer.class.equals(returnType) || int.class.equals(returnType)) {
- if(value == null) {
- return returnType.cast(0);
- }
- return returnType.cast(Integer.parseInt(value));
- } else if(Long.class.equals(returnType) || long.class.equals(returnType)) {
- if(value == null) {
- return returnType.cast(0L);
- }
- return returnType.cast(Long.parseLong(value));
- } else if(Double.class.equals(returnType) || double.class.equals(returnType)) {
- if(value == null) {
- return returnType.cast(0.0);
- }
- return returnType.cast(Double.parseDouble(value));
- } else if(Float.class.equals(returnType) || float.class.equals(returnType)) {
- if(value == null) {
- return returnType.cast(0.0F);
- }
- return returnType.cast(Float.parseFloat(value));
- } else if(Byte.class.equals(returnType) || byte.class.equals(returnType)) {
- if(value == null) {
- return returnType.cast((byte) 0);
- }
- return returnType.cast(Byte.parseByte(value));
- } else if(Boolean.class.equals(returnType) || boolean.class.equals(returnType)) {
- return returnType.cast(Boolean.parseBoolean(value));
- } else if(Character.class.equals(returnType) || char.class.equals(returnType)) {
- if(value == null) {
- return null;
- } else if(value.length() > 0) {
- return returnType.cast(value.charAt(0));
- } else {
- return null;
- }
- } else if (Locale.class.equals(returnType)) {
- if(value == null) {
- return null;
- } else {
- return returnType.cast(new Locale(value));
- }
- } else if (Date.class.equals(returnType)) {
- if(value == null) {
- return null;
- } else {
- try {
- return returnType.cast(DateUtils.ISO8601FORMAT.parse(value));
- } catch (final ParseException e) {
- e.printStackTrace();
- return null;
- }
- }
- } else if(String.class.equals(returnType)) {
- return returnType.cast(value);
- } else {
- throw new IllegalArgumentException("primitive type "+returnType.getName()+" not supported by transformation");
- }
- }
-
-
-}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/FacadingFactory.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/FacadingFactory.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/FacadingFactory.java
new file mode 100644
index 0000000..f703bdf
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/FacadingFactory.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading;
+
+import org.apache.marmotta.commons.sesame.facading.api.Facading;
+import org.apache.marmotta.commons.sesame.facading.impl.FacadingImpl;
+import org.openrdf.repository.RepositoryConnection;
+
+/**
+ * A factory to simplify the creation of facading services.
+ * <p/>
+ * Author: Sebastian Schaffert
+ */
+public class FacadingFactory {
+
+ /**
+ * Create a facading for an existing repository connection.
+ *
+ * @param connection the repository connection to use for facading
+ * @return a new facading service wrapping the given connection
+ */
+ public static Facading createFacading(RepositoryConnection connection) {
+ return new FacadingImpl(connection);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDF.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDF.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDF.java
new file mode 100644
index 0000000..3bb0e21
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDF.java
@@ -0,0 +1,54 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.annotations;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * This annotation indicates that a certain field should be
+ * persisted to the KiWi triple store using the property URI
+ * passed as annotation parameter.<br>
+ * The TripleStore class checks for <b>RDF</b> annotations
+ * during persist and load. <br>
+ * Classes using this annotation must currently implement the
+ * {@link kiwi.core.model.rdf.KiWiEntity} interface, so that the
+ * KnowledgeSpace has access to the resource associated with the
+ * entity.<br>
+ * This is a runtime annotation and it is applicable on fields
+ * and on getter methods.<br>
+ *
+ * @author Sebastian Schaffert
+ * @see kiwi.core.model.rdf.KiWiEntity
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target( {ElementType.FIELD, ElementType.METHOD})
+public @interface RDF {
+
+ /**
+ * Return the URI of the RDF predicate to use for the field
+ * or method.
+ *
+ * @returns URI of the RDF predicate to use for the field or
+ * method.
+ */
+ String[] value();
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFContext.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFContext.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFContext.java
new file mode 100644
index 0000000..a08529d
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFContext.java
@@ -0,0 +1,35 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation indicates that a certain interface should be
+ * persisted to the KiWi triple store using the context uri and type
+ * for the default context for all implementations of this class.<br>
+ *
+ * @author Stefan Robert
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target( { ElementType.TYPE } )
+public @interface RDFContext {
+
+ String value();
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFFilter.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFFilter.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFFilter.java
new file mode 100644
index 0000000..cc269d0
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFFilter.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Specifies a filter for facades that selects the content items that may be facaded based on the
+ * type of the content item. Only of a content item satisfies all types specified here is it accepted in
+ * a result set.
+ *
+ * @author Sebastian Schaffert
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target( { ElementType.TYPE } )
+public @interface RDFFilter {
+ /**
+ * The URI of the RDF type to use for the class
+ * @return
+ */
+ String[] value();
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFInverse.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFInverse.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFInverse.java
new file mode 100644
index 0000000..5044b0b
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFInverse.java
@@ -0,0 +1,59 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation indicates that a certain KiWi facade field should be mapped
+ * inversely to a property in the triple store. It is the inverse of the
+ * <code>@RDF</code> annotation, e.g. when using
+ * <code>@RDFInverse("rdfs:subClassOf")</code>, the annotated method returns the
+ * subclasses, while the annotation <code>@RDF("rdfs:subClassOf")</code> would
+ * return the superclasses. Note that <code>@RDFInverse</code> only works on
+ * ObjectProperties; for all other properties it behaves exactly like
+ * <code>@RDF</code>
+ * <p>
+ * The KiWiEntityManager and TripleStore check for the presence of this
+ * annotation on methods and dynamically maps them to queries on the triple
+ * store, using the resource of the annotated interface or class (which must
+ * implement KiWiEntity to provide a getResource() method) as object.
+ * <p>
+ * This is a runtime annotation and it is applicable on getter methods.<br>
+ * <p>
+ * TODO: currently, only KiWiFacades are supported; also, it is currently not
+ * possible to provide {@link @RDF} and {@link @RDFInverse} on the same method
+ * at the same time.
+ *
+ * @author Sebastian Schaffert
+ */
+
+@Retention(RetentionPolicy.RUNTIME)
+@Target( {ElementType.METHOD})
+public @interface RDFInverse {
+
+ /**
+ * Return the URI of the RDF predicate to use for the field
+ * or method.
+ *
+ * @returns URI of the RDF predicate to use for the field or
+ * method.
+ */
+ String[] value();
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFPropertyBuilder.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFPropertyBuilder.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFPropertyBuilder.java
new file mode 100644
index 0000000..15e08ed
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFPropertyBuilder.java
@@ -0,0 +1,37 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ *
+ */
+package org.apache.marmotta.commons.sesame.facading.annotations;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.apache.marmotta.commons.sesame.facading.api.FacadingPredicateBuilder;
+
+/**
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface RDFPropertyBuilder {
+
+ Class<? extends FacadingPredicateBuilder> value();
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFType.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFType.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFType.java
new file mode 100644
index 0000000..2b72a49
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/annotations/RDFType.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+
+/**
+ * This annotation specifies the RDF-type of an object-class
+ *
+ * @author Stephanie Stroka
+ *
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target( { ElementType.TYPE } )
+public @interface RDFType {
+ /**
+ * The URI of the RDF type to use for the class
+ * @return
+ */
+ String[] value();
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/api/Facading.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/api/Facading.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/api/Facading.java
new file mode 100644
index 0000000..0069fd2
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/api/Facading.java
@@ -0,0 +1,122 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.api;
+
+import org.apache.marmotta.commons.sesame.facading.model.Facade;
+import org.openrdf.model.Resource;
+import org.openrdf.model.URI;
+
+import java.util.Collection;
+
+/**
+ * Offers methods for loading and proxying KiWiFacades. A KiWi Facade is an interface that defines a Java
+ * object with convenient Java methods around a KiWiResource 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.
+ *
+ *
+ * <p/>
+ * User: sschaffe
+ */
+public interface Facading {
+
+ /**
+ * Create an instance of C that facades the resource given as argument using the @RDF annotations provided
+ * to the getter or setter methods of Cto 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
+ */
+ public <C extends Facade> C createFacade(Resource r, Class<C> type);
+
+ /**
+ * Create an instance of C that facades the resource given as argument using the @RDF annotations provided
+ * to the getter or setter methods of Cto map to properties of the resource in the triple store.
+ * Additionally, it puts the facade into the given context.
+ * This is useful if the @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 into which the facade should be put
+ * @return
+ */
+ public <C extends Facade> C createFacade(Resource r, Class<C> type, URI context);
+
+ /**
+ * Create a collection of instances of C that facade the resources given in the collection passed as argument.
+ * The facade uses the @RDF annotations provided to the getter or setter methods of C. The returned collection
+ * is of the same kind as the passed collection.
+ *
+ *
+ * @param list the collection containing the resources to facade
+ * @param type the facade type as a class
+ * @return
+ */
+ public <C extends Facade> Collection<C> createFacade(Collection<? extends Resource> list, Class<C> type);
+
+ /**
+ * Create an instance of C that facades the resource identified by the uri given as argument, using the @RDF
+ * annotations provided to the getter or setter methods of C to map to properties of the resource in the triple
+ * store.
+ *
+ * @param uri the uri of the resource to facade
+ * @param type the facade type as a class
+ * @param <C> the facade type as a generic parameter
+ * @return
+ */
+ public <C extends Facade> C createFacade(String uri, Class<C> type);
+
+ /**
+ * Check whether the resource fits into the facade.
+ *
+ *
+ * @param r the resource to check
+ * @param type the facade to check for
+ * @param context limit all checks to this context
+ * @return <code>true</code> if the resource <code>r</code> fulfills all {@link org.apache.marmotta.commons.sesame.facading.annotations.RDFType} and
+ * {@link org.apache.marmotta.commons.sesame.facading.annotations.RDFFilter} requirements of <code>type</code>
+ */
+ public <C extends Facade> boolean isFacadeable(Resource r, Class<C> type, URI context);
+
+ /**
+ * Check whether the resource fits into the facade.
+ *
+ *
+ * @param r the resource to check
+ * @param type the facade to check for
+ * @return <code>true</code> if the resource <code>r</code> fulfills all {@link org.apache.marmotta.commons.sesame.facading.annotations.RDFType} and
+ * {@link org.apache.marmotta.commons.sesame.facading.annotations.RDFFilter} requirements of <code>type</code>
+ */
+ public <C extends Facade> boolean isFacadeable(Resource r, Class<C> type);
+
+ /**
+ * Create a collection of instances of C that facade the resources given in the collection passed as argument.
+ * The facade uses the {@link org.apache.marmotta.commons.sesame.facading.annotations.RDF} annotations provided to the getter or setter methods of C. The returned collection
+ * is of the same kind as the passed collection.
+ *
+ *
+ * @param list the collection containing the resources to facade
+ * @param type the facade type as a class
+ * @return
+ */
+ <C extends Facade> Collection<C> createFacade(Collection<? extends Resource> list, Class<C> type, URI context);
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/api/FacadingPredicateBuilder.java
----------------------------------------------------------------------
diff --git a/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/api/FacadingPredicateBuilder.java b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/api/FacadingPredicateBuilder.java
new file mode 100644
index 0000000..1ce75eb
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/api/FacadingPredicateBuilder.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.api;
+
+
+import java.lang.reflect.Method;
+
+import org.apache.marmotta.commons.sesame.facading.impl.FacadingPredicate;
+import org.apache.marmotta.commons.sesame.facading.model.Facade;
+
+/**
+ * Dynamically create the RDF-property uri for facading.
+ * <p>
+ * <strong>NOTE: All implementations MUST provide either a public no-arg Constructor or a public
+ * static no-arg <code>getInstance()</code>-method!</strong>
+ * <p>
+ *
+ */
+public interface FacadingPredicateBuilder {
+
+ public FacadingPredicate getFacadingPredicate(String fieldName, Class<? extends Facade> facade, Method method);
+
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/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
new file mode 100644
index 0000000..6146d9f
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingImpl.java
@@ -0,0 +1,271 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.impl;
+
+import java.lang.reflect.Proxy;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import org.apache.marmotta.commons.sesame.facading.annotations.RDF;
+import org.apache.marmotta.commons.sesame.facading.annotations.RDFContext;
+import org.apache.marmotta.commons.sesame.facading.annotations.RDFFilter;
+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;
+import org.openrdf.repository.RepositoryException;
+import org.slf4j.Logger;
+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
+ * 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.
+ *
+ *
+ * <p/>
+ * User: Sebastian Schaffert
+ */
+public class FacadingImpl implements Facading {
+
+ private static Logger log = LoggerFactory.getLogger(FacadingImpl.class);
+
+
+ private final RepositoryConnection connection;
+
+
+ public FacadingImpl(RepositoryConnection connection) {
+ this.connection = connection;
+ }
+
+ /**
+ * 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.
+ *
+ *
+ * @param r the resource to facade
+ * @param type the facade type as a class
+ * @return
+ */
+ @Override
+ public <C extends Facade> C createFacade(Resource r, Class<C> type) {
+ // support @RDFContext annotation in facade
+ URI context = null;
+ if(FacadeUtils.isFacadeAnnotationPresent(type, RDFContext.class)) {
+ String s_context = FacadeUtils.getFacadeAnnotation(type,RDFContext.class).value();
+ context = connection.getValueFactory().createURI(s_context);
+ }
+ 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.
+ * 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
+ */
+ @Override
+ public <C extends Facade> C createFacade(Resource r, Class<C> type, URI context) {
+ if(r == null) {
+ return null;
+ } else if(type.isInterface()) {
+ // 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)) {
+ try {
+ // support @RDFType annotation in facade
+ if(FacadeUtils.isFacadeAnnotationPresent(type,RDFType.class)) {
+ 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);
+ }
+ }
+
+ FacadingInvocationHandler handler = new FacadingInvocationHandler(r,context,type,this,connection);
+ return type.cast(Proxy.newProxyInstance(type.getClassLoader(),
+ new Class[]{type},
+ handler));
+ } catch (RepositoryException 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() + ")");
+ }
+ }
+
+ /**
+ * Create a collection of instances of C that facade the resources given in the collection passed as argument.
+ * The facade uses the {@link RDF} annotations provided to the getter or setter methods of C. The returned collection
+ * is of the same kind as the passed collection.
+ *
+ *
+ * @param list the collection containing the resources to facade
+ * @param type the facade type as a class
+ * @return
+ */
+ @Override
+ public <C extends Facade> Collection<C> createFacade(Collection<? extends Resource> list, Class<C> type) {
+ URI context = null;
+ if(FacadeUtils.isFacadeAnnotationPresent(type, RDFContext.class)) {
+ String s_context = FacadeUtils.getFacadeAnnotation(type,RDFContext.class).value();
+ context = connection.getValueFactory().createURI(s_context);
+ }
+ return createFacade(list, type, context);
+ }
+
+ /**
+ * Create a collection of instances of C that facade the resources given in the collection passed as argument.
+ * The facade uses the {@link RDF} annotations provided to the getter or setter methods of C. The returned collection
+ * is of the same kind as the passed collection.
+ *
+ *
+ * @param list the collection containing the resources to facade
+ * @param type the facade type as a class
+ * @return
+ */
+ @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());
+ LinkedList<C> result = new LinkedList<C>();
+ if(type.isAnnotationPresent(RDFFilter.class)) {
+ try {
+ final URI p_type = connection.getValueFactory().createURI(Namespaces.NS_RDF + "type");
+
+ // if the RDFType annotation is present, filter out content items that are of the wrong type
+ LinkedList<URI> acceptable_types = new LinkedList<URI>();
+ if(FacadeUtils.isFacadeAnnotationPresent(type,RDFFilter.class)) {
+ String[] a_type = FacadeUtils.getFacadeAnnotation(type,RDFFilter.class).value();
+ for(String s_type : a_type) {
+ URI r_type = connection.getValueFactory().createURI(s_type);
+ acceptable_types.add(r_type);
+ }
+ }
+
+ // add facades for all content items to the result list
+ 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)) {
+ accept = true;
+ log.debug("accepting resource #0 because type matches (#1)",item.toString(),rdf_type.stringValue());
+ break;
+ }
+ }
+ if(accept) {
+ 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());
+ } catch (RepositoryException ex) {
+ log.error("error while accessing RDF repository",ex);
+ }
+ } else {
+ // add facades for all content items to the result list
+ for(Resource item : list) {
+ result.add(createFacade(item,type,context));
+ }
+ }
+ return result;
+ }
+
+
+ /**
+ * Create an instance of C that facades the resource identified by the uri given as argument, using the {@link RDF}
+ * annotations provided to the getter or setter methods of C to map to properties of the resource in the triple
+ * store.
+ *
+ * @param uri the uri of the resource to facade
+ * @param type the facade type as a class
+ * @param <C> the facade type as a generic parameter
+ * @return
+ */
+ @Override
+ public <C extends Facade> C createFacade(String uri, Class<C> type) {
+ return createFacade(connection.getValueFactory().createURI(uri), type);
+ }
+
+ /**
+ * Check whether the resource fits into the facade.
+ *
+ *
+ * @param r the resource to check
+ * @param type the facade to check for
+ * @return <code>true</code> if the resource <code>r</code> fulfills all {@link RDFType} and
+ * {@link RDFFilter} requirements of <code>type</code>
+ */
+ @Override
+ public <C extends Facade> boolean isFacadeable(Resource r, Class<C> type) {
+ return isFacadeable(r, type, null);
+ }
+
+ /**
+ * Check whether the resource fits into the facade.
+ *
+ *
+ * @param r the resource to check
+ * @param type the facade to check for
+ * @param context limit all checks to this context
+ * @return <code>true</code> if the resource <code>r</code> fulfills all {@link RDFType} and
+ * {@link RDFFilter} requirements of <code>type</code>
+ */
+ @Override
+ 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");
+
+ 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);
+ }
+ // 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);
+ }
+ }
+ return facadeable;
+ } catch(RepositoryException ex) {
+ log.error("error while accessing RDF repository",ex);
+ }
+ }
+ return false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/incubator-marmotta/blob/ee5998d3/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
new file mode 100644
index 0000000..4ccdf32
--- /dev/null
+++ b/commons/sesame-tools-facading/src/main/java/org/apache/marmotta/commons/sesame/facading/impl/FacadingInvocationHandler.java
@@ -0,0 +1,801 @@
+/**
+ * Copyright (C) 2013 Salzburg Research.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.marmotta.commons.sesame.facading.impl;
+
+
+import org.apache.marmotta.commons.sesame.facading.annotations.RDF;
+import org.apache.marmotta.commons.sesame.facading.annotations.RDFInverse;
+import org.apache.marmotta.commons.sesame.facading.annotations.RDFPropertyBuilder;
+import org.apache.marmotta.commons.sesame.facading.api.Facading;
+import org.apache.marmotta.commons.sesame.facading.api.FacadingPredicateBuilder;
+import org.apache.marmotta.commons.sesame.facading.model.Facade;
+import org.apache.marmotta.commons.sesame.facading.util.FacadeUtils;
+import org.apache.marmotta.commons.util.DateUtils;
+import org.openrdf.model.Literal;
+import org.openrdf.model.Resource;
+import org.openrdf.model.Statement;
+import org.openrdf.model.URI;
+import org.openrdf.model.Value;
+import org.openrdf.repository.RepositoryConnection;
+import org.openrdf.repository.RepositoryException;
+import org.openrdf.repository.RepositoryResult;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.*;
+
+/**
+ * This class implements an invocation handler to be used for proxy classes that delegate to a
+ * content item and to data in the triple store. It has to be constructed using the triple store
+ * implementation as parameter. Interfaces that make use of this invocation handler need to extend
+ * the {@link Facade} interface.
+ *
+ * @author Sebastian Schaffert
+ */
+class FacadingInvocationHandler implements InvocationHandler {
+
+ public static enum OPERATOR {
+ GET(false, 0, "get"),
+ SET(true, 1, "set"),
+ ADD(true, 1, "add"),
+ DEL(true, 0, "del", "delete", "remove"),
+ HAS(false, 0, "has", "is");
+
+
+ private static final String[] PX, SPX;
+ static {
+ LinkedList<String> ops = new LinkedList<String>();
+ for (OPERATOR op : OPERATOR.values()) {
+ for (String px : op.prefixes) {
+ ops.add(px);
+ }
+ }
+ PX = ops.toArray(new String[ops.size()]);
+ SPX = ops.toArray(new String[ops.size()]);
+ Arrays.sort(SPX, new Comparator<String>() {
+ @Override
+ public int compare(String o1, String o2) {
+ return o2.length() - o1.length();
+ }
+ });
+ }
+
+ final String[] prefixes;
+ final int numArgs;
+ final boolean writeOp;
+
+ private OPERATOR(boolean isWriteOp, int args, String... strings) {
+ this.writeOp = isWriteOp;
+ this.numArgs = args;
+ this.prefixes = strings;
+ }
+
+ @Override
+ public String toString() {
+ return prefixes[0];
+ }
+
+ public static String[] getOperatorPrefixes() {
+ return PX;
+ }
+
+ public static String[] getLengthSortedOperatorPrefixes() {
+ return SPX;
+ }
+
+ public static OPERATOR getOperator(Method m) {
+ for (OPERATOR op : values()) {
+ for (String px : op.prefixes) {
+ if (m.getName().startsWith(px)) {
+ final int numP = m.getParameterTypes().length;
+ if (numP == op.numArgs || numP == op.numArgs + 1) { return op; }
+ }
+ }
+ }
+ return valueOf(m.getName());
+ }
+ }
+
+ private final RepositoryConnection connection;
+
+ private final Facading facadingService;
+
+ private final Class<? extends Facade> declaredFacade;
+
+ private final FacadingPredicateBuilder propBuilder;
+
+ private final Resource delegate;
+
+ private final URI context;
+
+ private final HashMap<String, Object> fieldCache;
+
+ private Logger log = LoggerFactory.getLogger(FacadingInvocationHandler.class);
+
+ /**
+ * Indicates if the cache is used, by default is false.
+ */
+ private boolean useCache;
+
+ public FacadingInvocationHandler(Resource item, URI context, Class<? extends Facade> facade, Facading facadingService, RepositoryConnection connection) {
+ this.delegate = item;
+ this.facadingService = facadingService;
+ this.declaredFacade = facade;
+ this.connection = connection;
+
+ if (declaredFacade.isAnnotationPresent(RDFPropertyBuilder.class)) {
+ final Class<? extends FacadingPredicateBuilder> bClass = declaredFacade.getAnnotation(RDFPropertyBuilder.class).value();
+ FacadingPredicateBuilder _b = null;
+ try {
+ // Look for a no-arg Constructor
+ _b = bClass.getConstructor().newInstance();
+ } catch (NoSuchMethodException e) {
+ // If there is no no-arg Constructor, try static getInstance()
+ try {
+ for (Method m : bClass.getMethods()) {
+ if (Modifier.isStatic(m.getModifiers()) && "getInstance".equals(m.getName()) && m.getParameterTypes().length == 0) {
+ _b = (FacadingPredicateBuilder) m.invoke(null);
+ break;
+ }
+ }
+ if (_b == null) { throw new IllegalArgumentException("Could not find no-arg Constructor or static no-arg factory-method 'getInstance' for "
+ + bClass.getName()); }
+ } catch (Exception e1) {
+ throw new IllegalArgumentException("Could not load instance of " + bClass.getSimpleName() + " from static factory 'getInstance()': "
+ + e.getMessage(), e);
+ }
+ } catch (Exception e) {
+ throw new IllegalArgumentException("Could not create instance of " + bClass.getSimpleName() + ": " + e.getMessage(), e);
+ }
+ this.propBuilder = _b;
+ } else {
+ this.propBuilder = null;
+ }
+
+ if (context != null) {
+ this.context = context;
+ } else {
+ // FIXME
+ this.context = null;
+ }
+
+ fieldCache = new HashMap<String, Object>();
+
+ // disable cache, it does not work well with deleted triples ...
+ useCache = false;
+ }
+
+ /**
+ * Indicates if the cache is allow or not.
+ *
+ * @return the useCache true if the cache is done.
+ */
+ public boolean isUseCache() {
+ return useCache;
+ }
+
+ /**
+ * Used to enable/disable the cache mechanism.
+ *
+ * @param useCache
+ * true foe enable cache, false - no cache.
+ */
+ public void setUseCache(boolean useCache) {
+ this.useCache = useCache;
+ }
+
+ /**
+ * @return the item
+ */
+ public Resource getDelegate() {
+ return delegate;
+ }
+
+ /**
+ * Invoke the invocation handler for the given proxy object, method, and arguments. In order to
+ * execute the passed method, this method does the following: - if the method has a
+ * <code>RDF</code> annotation or if it is a setter and the corresponding getter has a
+ * <code>RDF</code> annotation, we try to retrieve the appropriate value by querying the triple
+ * store and converting the triple store data to the return type of the method; if the return
+ * type is again an interface
+ *
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method,
+ * java.lang.Object[])
+ * @see org.apache.marmotta.commons.sesame.facading.annotations.RDF
+ */
+ @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"); }
+
+ // handle default methods:
+ if (FacadingInvocationHelper.checkMethodSig(method, "hashCode")) {
+ return delegate.hashCode();
+ } else if (FacadingInvocationHelper.checkMethodSig(method, "equals", 1)) {
+ final Object other = args[0];
+ return other != null && other.getClass().equals(proxy.getClass()) && other.hashCode() == proxy.hashCode();
+ } else if (FacadingInvocationHelper.checkMethodSig(method, "toString")) {
+ return declaredFacade.getSimpleName() + " with delegate to " + delegate.toString();
+ } else if (FacadingInvocationHelper.checkMethodSig(method, "getDelegate")) { return delegate; }
+
+ // caching
+ final String fieldName = FacadingInvocationHelper.getBaseName(method);
+ if (useCache && method.getName().startsWith("get")) {
+ if (fieldCache.get(fieldName) != null) { return fieldCache.get(fieldName); }
+ }
+
+ final FacadingPredicate fp = getFacadingPredicate(method);
+
+ // distinguish getters and setters and more...
+ switch (OPERATOR.getOperator(method)) {
+ case GET:
+ return handleGet(method, args, fp);
+ case SET:
+ return handleSet(method, args, fp);
+ case ADD:
+ return handleAdd(method, args, fp);
+ case DEL:
+ return handleDel(method, args, fp);
+ case HAS:
+ return handleHas(method, args, fp);
+ default:
+ throw new IllegalArgumentException("Unsupported method: " + method.getName());
+ }
+ }
+
+ private FacadingPredicate getFacadingPredicate(Method method) throws IllegalArgumentException {
+ final String[] rdf_property;
+ final boolean inverse;
+ // look for RDF annotation and extract the property from it; if not on the getter, look
+ // for the corresponding setter and check whether it has a @RDF annotation; if neither has,
+ // throw an IllegalArgumentException
+ RDF rdf = FacadingInvocationHelper.getAnnotation(method, RDF.class);
+ if (rdf != null) {
+ rdf_property = rdf.value();
+ inverse = false;
+ return new FacadingPredicate(inverse, rdf_property);
+ } else {
+ RDFInverse rdfi = FacadingInvocationHelper.getAnnotation(method, RDFInverse.class);
+ if (rdfi != null) {
+ rdf_property = rdfi.value();
+ inverse = true;
+ return new FacadingPredicate(inverse, rdf_property);
+ } else {
+ if (propBuilder != null) {
+ String fName = FacadingInvocationHelper.getBaseName(method);
+ if (fName.length() > 1) {
+ fName = fName.substring(0, 1).toLowerCase(Locale.ENGLISH) + fName.substring(1);
+ }
+ return propBuilder.getFacadingPredicate(fName, declaredFacade, method);
+ } else {
+ throw new IllegalArgumentException("Could not find facading predicate for " + method.getName() + " in " + declaredFacade.getName());
+ }
+ }
+ }
+ }
+
+ private Boolean handleHas(Method method, Object[] args, FacadingPredicate predicate) throws RepositoryException {
+ final Locale loc;
+ if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(Locale.class)) {
+ loc = (Locale) args[0];
+ } else {
+ loc = null;
+ }
+
+ if (predicate.isInverse()) {
+ if (loc != null) { throw new IllegalArgumentException("@RDFInverse not supported for language tagged properties"); }
+ else {
+ for (String p : predicate.getProperties()) {
+ final URI prop = connection.getValueFactory().createURI(p);
+ final RepositoryResult<Statement> result = connection.getStatements(null, prop, delegate, true, context);
+ try {
+ if (result.hasNext()) { return true; }
+ } finally {
+ result.close();
+ }
+ }
+ }
+ } else {
+ for (String p : predicate.getProperties()) {
+ final URI prop = connection.getValueFactory().createURI(p);
+ final RepositoryResult<Statement> result = connection.getStatements(delegate, prop, null, true, context);
+ try {
+ if (loc == null) {
+ if (result.hasNext()) { return true; }
+ } else {
+ while (result.hasNext()) {
+ final Value o = result.next().getObject();
+ if (FacadingInvocationHelper.checkLocale(loc, o)) { return true; }
+ }
+ }
+ } finally {
+ result.close();
+ }
+ }
+ }
+
+
+ return false;
+ }
+
+ private Object handleDel(Method method, Object[] args, FacadingPredicate predicate) throws RepositoryException {
+ final Locale loc;
+ if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(Locale.class)) {
+ loc = (Locale) args[0];
+ } else {
+ loc = null;
+ }
+
+ delProperties(predicate, loc);
+
+ return null;
+ }
+
+ private Object handleAdd(Method method, Object[] args, FacadingPredicate predicate) throws RepositoryException, IllegalArgumentException {
+ final Locale loc;
+ if (method.getParameterTypes().length == 2 && method.getParameterTypes()[1].equals(Locale.class)) {
+ loc = (Locale) args[1];
+ } else {
+ loc = null;
+ }
+
+ final Class<?> paramType = method.getParameterTypes()[0];
+ addProperties(method, args, predicate.getProperties(), predicate.isInverse(), loc, paramType);
+
+ return null;
+ }
+
+ private Object handleSet(Method method, Object[] args, FacadingPredicate predicate)
+ throws RepositoryException, IllegalArgumentException {
+
+ final Locale loc;
+ if (method.getParameterTypes().length == 2 && method.getParameterTypes()[1].equals(Locale.class)) {
+ loc = (Locale) args[1];
+ } else {
+ loc = null;
+ }
+
+ // add to cache
+ if (useCache) {
+ fieldCache.put(FacadingInvocationHelper.getBaseName(method), args[0]);
+ }
+
+ // This is SET, so delete all previous properties
+ delProperties(predicate, loc);
+
+ // *** set the value of a certain RDF property
+ final Class<?> paramType = method.getParameterTypes()[0];
+
+ addProperties(method, args, predicate.getProperties(), predicate.isInverse(), loc, paramType);
+
+
+ return null;
+ }
+
+ private void addProperties(Method method, Object[] args, final String[] rdf_property, final boolean inverse, final Locale loc, final Class<?> paramType)
+ throws RepositoryException, IllegalArgumentException {
+ if (args[0] == null || "".equals(args[0])) {
+ // nop;
+ } else if (FacadeUtils.isBaseType(paramType) && !inverse) {
+ for (String v : rdf_property) {
+ final URI prop = connection.getValueFactory().createURI(v);
+ connection.add(delegate, prop, createLiteral(args[0], loc), context);
+ }
+ } else if (FacadeUtils.isValue(paramType) && !inverse) {
+ for (String v : rdf_property) {
+ final URI prop = connection.getValueFactory().createURI(v);
+ // create a new triple for this property, subject, and object
+ connection.add(delegate, prop, (Value) args[0], context);
+ }
+ } else if (FacadeUtils.isResource(paramType) && inverse) {
+ for (String v : rdf_property) {
+ final URI prop = connection.getValueFactory().createURI(v);
+ // create a new triple for this property, subject, and object
+ connection.add((Resource) args[0], prop, delegate, context);
+ }
+ } else if (FacadeUtils.isFacade(paramType) && !inverse) {
+ for (String v : rdf_property) {
+ final URI prop = connection.getValueFactory().createURI(v);
+ // create a new triple for this property, subject, and object
+ connection.add(delegate, prop, ((Facade) args[0]).getDelegate(), context);
+ }
+ } else if (FacadeUtils.isFacade(paramType) && inverse) {
+ for (String v : rdf_property) {
+ final URI prop = connection.getValueFactory().createURI(v);
+ // create a new triple for this property, subject, and object
+ connection.add(((Facade) args[0]).getDelegate(), prop, delegate, context);
+ }
+ } else if (FacadeUtils.isCollection(paramType)) {
+ for (String v : rdf_property) {
+ final Collection<?> c = (Collection<?>) args[0];
+
+ final URI prop = connection.getValueFactory().createURI(v);
+
+ // add each of the elements in the collection as new triple with prop
+ for (final Object o : c) {
+ if (o == null) {
+ // skip
+ } else if (FacadeUtils.isBaseType(o.getClass()) && !inverse) {
+ connection.add(delegate, prop, createLiteral(o, loc), context);
+ } else if (FacadeUtils.isFacade(o.getClass()) && !inverse) {
+ connection.add(delegate, prop, ((Facade) o).getDelegate(), context);
+ } else if (FacadeUtils.isFacade(o.getClass()) && inverse) {
+ connection.add(((Facade) o).getDelegate(), prop, delegate, context);
+ } else if (FacadeUtils.isValue(o.getClass()) && !inverse) {
+ connection.add(delegate, prop, (Value) o, context);
+ } else if (FacadeUtils.isResource(o.getClass()) && inverse) {
+ connection.add((Resource) o, prop, delegate, context);
+ } else if (inverse) {
+ throw new IllegalArgumentException("method " + method.getName() + ": @RDFInverse not supported for parameter type "
+ + paramType.getName());
+ } else {
+ throw new IllegalArgumentException("the type " + o.getClass().getName() + " is not supported in collections");
+ }
+ }
+ }
+ } else if (inverse) {
+ throw new IllegalArgumentException("method " + method.getName() + ": @RDFInverse not supported for parameter type " + paramType.getName());
+ } else {
+ throw new IllegalArgumentException("method " + method.getName() + ": unsupported parameter type " + paramType.getName());
+ }
+ }
+
+ private void delProperties(final FacadingPredicate predicate, final Locale loc) throws RepositoryException {
+ for (String v : predicate.getProperties()) {
+ final URI prop = connection.getValueFactory().createURI(v);
+
+ if (!predicate.isInverse() && loc == null) {
+ // remove all properties prop that have this subject;
+ connection.remove(delegate, prop, null, context);
+ } else if (predicate.isInverse() && loc == null) {
+ // remove all properties prop that have this object;
+ 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);
+ }
+ }
+ statements.close();
+ } else if (predicate.isInverse() && loc != null) { throw new IllegalArgumentException("A combination of @RDFInverse and a Literal is not possible");
+ }
+ }
+ }
+
+ private Object handleGet(Method method, Object[] args, FacadingPredicate predicate) throws IllegalAccessException, InstantiationException,
+ RepositoryException {
+ final Locale loc;
+ if (method.getParameterTypes().length == 1 && method.getParameterTypes()[0].equals(Locale.class)) {
+ loc = (Locale) args[0];
+ } else {
+ loc = null;
+ }
+
+ // *** get the value of a certain RDF property ***
+
+ final Class<?> returnType = method.getReturnType();
+ final Type typeOfGeneric = method.getGenericReturnType();
+
+ // we believe that the result is universal for each property
+ // and therefore just return the result for the firstly defined property
+ final Object result = transform(returnType, typeOfGeneric, delegate, predicate.getProperties()[0], loc, predicate.isInverse());
+
+ if (useCache) {
+ fieldCache.put(FacadingInvocationHelper.getBaseName(method), result);
+ }
+
+ return result;
+ }
+
+ /**
+ * Helper method to transform the object reachable via rdf_property from r to the given
+ * returnType; if the returnType is a collection, it is also necessary to provide the generic
+ * type. The KiWiEntityManager is used for further querying.<br>
+ * Please note that if the <code>returnType</code>is a collection you <b>must</b> use a concrete
+ * class (e.g. <code>java.util.ArrayList</code>) not an abstract class or interface.
+ *
+ * @param <C>
+ * @param returnType
+ * @param typeOfGeneric
+ * @param rdf_property
+ * @return
+ * @throws InstantiationException
+ * @throws IllegalAccessException
+ */
+ private <C, D extends Facade> C transform(Class<C> returnType, Type typeOfGeneric, Resource entity, String rdf_property, Locale loc, boolean inverse)
+ throws IllegalAccessException, InstantiationException, RepositoryException {
+ // should not happen actually
+ if (entity == null) { return null; }
+
+ if (FacadeUtils.isBaseType(returnType) && !inverse) {
+ /*
+ * if the return type is string or primitive, get the literal value of the property and
+ * transform it appropriately
+ */
+ final URI property = connection.getValueFactory().createURI(rdf_property);
+ final String value = getProperty(entity, property, loc, context);
+
+ try {
+ // transformation to appropriate primitive type
+ final C result = FacadeUtils.transformToBaseType(value, returnType);
+
+ return result;
+ } catch (final IllegalArgumentException ex) {
+ return null;
+ }
+
+ } else if (FacadeUtils.isValue(returnType) && !inverse) {
+ return queryOutgoingSingle(entity, rdf_property, returnType);
+ } else if (FacadeUtils.isValue(returnType) && inverse) {
+ return queryIncomingSingle(entity, rdf_property, returnType);
+ } else if (FacadeUtils.isFacade(returnType) && !inverse) {
+ /*
+ * for KiWi entities, we retrieve the resource that is targeted by this property (by
+ * using getObject) and create a query on the triple store using createQuery() and the
+ * resource's uri that returns the result in the appropriate type (can e.g. be again a
+ * proxy using this invocation handler!)
+ */
+ Resource object = queryOutgoingSingle(entity, rdf_property, Resource.class);
+
+ if (object != null) {
+ return returnType.cast(facadingService.createFacade(object, returnType.asSubclass(Facade.class), context));
+ } else {
+ return null;
+ }
+ } else if (FacadeUtils.isFacade(returnType) && inverse) {
+ /*
+ * for KiWi entities, we retrieve the resource that is targeted by this property (by
+ * using getObject) and create a query on the triple store using createQuery() and the
+ * resource's uri that returns the result in the appropriate type (can e.g. be again a
+ * proxy using this invocation handler!)
+ */
+ Resource subject = queryIncomingSingle(entity, rdf_property, Resource.class);
+
+ if (subject != null) {
+ return returnType.cast(facadingService.createFacade(subject, returnType.asSubclass(Facade.class), context));
+ } else {
+ return null;
+ }
+ } else if (FacadeUtils.isCollection(returnType)) {
+ /*
+ * if we have a collection, we try to infer the generic type of its contents and use
+ * this to generate values; if the generic type is a kiwi entity, we issue a createQuery
+ * to the tripleStore to retrieve the corresponding values; if the generic type is a
+ * base type, we transform the results to the base type and query for literals
+ */
+ if (typeOfGeneric instanceof ParameterizedType) {
+ final ParameterizedType t = (ParameterizedType) typeOfGeneric;
+ final Class<?> tCls = (Class<?>) t.getActualTypeArguments()[0];
+
+ @SuppressWarnings("rawtypes")
+ final Class<? extends Collection> collectionType = returnType.asSubclass(Collection.class);
+
+ if (FacadeUtils.isFacade(tCls) && !inverse) {
+ return returnType.cast(FacadingInvocationHelper.createCollection(
+ collectionType,
+ facadingService.createFacade(queryOutgoingAll(entity, rdf_property, Resource.class), tCls.asSubclass(Facade.class), context)));
+ } else if (FacadeUtils.isFacade(tCls) && inverse) {
+ return returnType.cast(FacadingInvocationHelper.createCollection(
+ collectionType,
+ facadingService.createFacade(queryIncomingAll(entity, rdf_property, Resource.class), tCls.asSubclass(Facade.class), context)));
+ } else if (FacadeUtils.isValue(tCls) && !inverse) {
+ return returnType.cast(FacadingInvocationHelper.createCollection(
+ collectionType,
+ queryOutgoingAll(entity, rdf_property, tCls.asSubclass(Value.class))));
+ } else if (FacadeUtils.isValue(tCls) && inverse) {
+ return returnType.cast(FacadingInvocationHelper.createCollection(
+ collectionType,
+ queryIncomingAll(entity, rdf_property, tCls.asSubclass(Value.class))));
+ } else if (inverse) {
+ throw new IllegalArgumentException("@RDFInverse not supported for mappings of type " + rdf_property);
+ } else if (FacadeUtils.isBaseType(tCls)) {
+ 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)) {
+ result.add(FacadeUtils.transformToBaseType(s, tCls));
+ }
+
+ return returnType.cast(result);
+ } else {
+ throw new IllegalArgumentException("return type is using generic type " + tCls.getName()
+ + ", which is not supported in RDF-based collections; please use either Java primitive types or KiWi Entities in KiWiFacades");
+ }
+ } else {
+ throw new IllegalArgumentException("return type is unparametrized collection type " + returnType.getName()
+ + ", which is not supported; please use an explicit type parameter in Facades");
+ }
+ } else if (inverse) {
+ throw new IllegalArgumentException("@RDFInverse not supported for mappings of type " + rdf_property);
+ } else {
+ throw new IllegalArgumentException("unsupported return type " + returnType.getName());
+ }
+
+ }
+
+ /**
+ * Return the single object of type C that is reachable from entity by rdf_property. Returns
+ * null if there is no such object or if the type of the object does not match the type passed
+ * as argument.
+ *
+ */
+ private <C> C queryOutgoingSingle(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);
+
+ try {
+ if (triples.hasNext()) {
+ Statement triple = triples.next();
+
+ Value object = triple.getObject();
+
+ if (returnType.isInstance(object)) {
+ return returnType.cast(object);
+ } else {
+ log.error("cannot cast retrieved object {} for property {} to return type {}", object, rdf_property, returnType);
+ return null;
+ }
+
+ } else {
+ return null;
+ }
+ } finally {
+ triples.close();
+ }
+
+ }
+
+ /**
+ * Return the single subject of type C that can reach entity by rdf_property. Returns null if
+ * there is no such object or if the type of the object does not match the type passed as
+ * argument.
+ *
+ */
+ private <C> C queryIncomingSingle(Resource entity, String rdf_property, Class<C> returnType) throws RepositoryException {
+ URI property = connection.getValueFactory().createURI(rdf_property);
+
+ RepositoryResult<Statement> triples = connection.getStatements(null, property, entity, false);
+
+ try {
+ if (triples.hasNext()) {
+ Statement triple = triples.next();
+
+ Value subject = triple.getSubject();
+
+ if (returnType.isInstance(subject)) {
+ return returnType.cast(subject);
+ } else {
+ log.error("cannot cast retrieved object {} for property {} to return type {}", subject, rdf_property, returnType);
+ return null;
+ }
+
+ } else {
+ return null;
+ }
+ } finally {
+ triples.close();
+ }
+ }
+
+ /**
+ * Return the all objects of type C that are reachable from entity by rdf_property. Returns
+ * empty set if there is no such object or if the type of the object does not match the type
+ * passed as argument.
+ *
+ */
+ 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>();
+
+ while (triples.hasNext()) {
+ Statement triple = triples.next();
+ if (returnType.isInstance(triple.getObject())) {
+ dupSet.add(returnType.cast(triple.getObject()));
+ }
+ }
+ triples.close();
+
+ return dupSet;
+
+ }
+
+ /**
+ * Return the all objects of type C that are can reach the entity by rdf_property. Returns empty
+ * set if there is no such object or if the type of the object does not match the type passed as
+ * argument.
+ *
+ */
+ private <C> Set<C> queryIncomingAll(Resource entity, String rdf_property, Class<C> returnType) throws RepositoryException {
+
+ 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()));
+ }
+ }
+ triples.close();
+
+ return dupSet;
+ }
+
+ private Value createLiteral(Object o, Locale loc) {
+ if (o instanceof Date) {
+ return connection.getValueFactory().createLiteral(DateUtils.getXMLCalendar((Date) o));
+ } else if (Integer.class.isAssignableFrom(o.getClass())) {
+ return connection.getValueFactory().createLiteral((Integer) o);
+ } else if (Long.class.isAssignableFrom(o.getClass())) {
+ return connection.getValueFactory().createLiteral((Long) o);
+ } else if (Double.class.isAssignableFrom(o.getClass())) {
+ return connection.getValueFactory().createLiteral((Double) o);
+ } else if (Float.class.isAssignableFrom(o.getClass())) {
+ return connection.getValueFactory().createLiteral((Float) o);
+ } else if (Boolean.class.isAssignableFrom(o.getClass())) {
+ return connection.getValueFactory().createLiteral((Boolean) o);
+ } else if (loc != null) {
+ return connection.getValueFactory().createLiteral(o.toString(), loc.getLanguage());
+ } else {
+ return connection.getValueFactory().createLiteral(o.toString());
+ }
+ }
+
+ 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);
+
+ Set<String> values = new HashSet<String>();
+ while (candidates.hasNext()) {
+ Statement triple = candidates.next();
+
+ if (triple.getObject() instanceof Literal) {
+ Literal l = (Literal) triple.getObject();
+
+ if (lang == null || lang.equals(l.getLanguage())) {
+ values.add(l.stringValue());
+ }
+ }
+ }
+ candidates.close();
+
+ return values;
+ }
+
+ private String getProperty(Resource entity, URI property, Locale loc, URI context) throws RepositoryException {
+ Set<String> values = getProperties(entity, property, loc, context);
+
+ if (values.size() > 0) {
+ return values.iterator().next();
+ } else {
+ return null;
+ }
+ }
+}