You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltaspike.apache.org by th...@apache.org on 2013/06/27 10:39:05 UTC
[05/11] DELTASPIKE-60 Data module initial import
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryEntity.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryEntity.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryEntity.java
new file mode 100644
index 0000000..08dfb60
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryEntity.java
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta;
+
+import java.io.Serializable;
+
+/**
+ * Data structure to store information about an entity:
+ * <ul>
+ * <li>Stores the class of the entity</li>
+ * <li>Stores the primary key class</li>
+ * </ul>
+ *
+ * @author thomashug
+ */
+public class RepositoryEntity
+{
+
+ private Class<?> entityClass;
+ private Class<? extends Serializable> primaryClass;
+
+ public RepositoryEntity(Class<?> entityClass)
+ {
+ this(entityClass, null);
+ }
+
+ public RepositoryEntity(Class<?> entityClass, Class<? extends Serializable> primaryClass)
+ {
+ this.entityClass = entityClass;
+ this.primaryClass = primaryClass;
+ }
+
+ public Class<?> getEntityClass()
+ {
+ return entityClass;
+ }
+
+ public void setEntityClass(Class<?> entityClass)
+ {
+ this.entityClass = entityClass;
+ }
+
+ public Class<? extends Serializable> getPrimaryClass()
+ {
+ return primaryClass;
+ }
+
+ public void setPrimaryClass(Class<? extends Serializable> primaryClass)
+ {
+ this.primaryClass = primaryClass;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
new file mode 100644
index 0000000..3193fa9
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/RepositoryMethod.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta;
+
+import static org.apache.deltaspike.data.impl.util.QueryUtils.isNotEmpty;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+import org.apache.deltaspike.data.api.Query;
+import org.apache.deltaspike.data.impl.builder.MethodExpressionException;
+import org.apache.deltaspike.data.impl.builder.part.QueryRoot;
+import org.apache.deltaspike.data.impl.builder.result.QueryProcessor;
+import org.apache.deltaspike.data.impl.builder.result.QueryProcessorFactory;
+
+/**
+ * Stores information about a specific method of a Repository:
+ * <ul>
+ * <li>The reference to the Method reflection object</li>
+ * <li>Whether this method delegates, is annotated or is parsed</li>
+ * <li>A reference to the parent Repository</li>
+ * <li>For parsed Repository methods, also the JPQL string is cached</li>
+ * </ul>
+ *
+ * @author thomashug
+ */
+public class RepositoryMethod
+{
+
+ private final Method method;
+ private final MethodType methodType;
+ private final RepositoryComponent repo;
+ private final QueryRoot queryRoot;
+ private final QueryProcessor queryProcessor;
+
+ public RepositoryMethod(Method method, RepositoryComponent repo)
+ {
+ this.method = method;
+ this.repo = repo;
+ this.methodType = extractMethodType();
+ this.queryRoot = initQueryRoot();
+ this.queryProcessor = QueryProcessorFactory.newInstance(method).build();
+ }
+
+ public boolean returns(Class<?> returnType)
+ {
+ return returnType.equals(method.getReturnType());
+ }
+
+ private MethodType extractMethodType()
+ {
+ if (isAnnotated())
+ {
+ return MethodType.ANNOTATED;
+ }
+ if (isMethodExpression())
+ {
+ return MethodType.PARSE;
+ }
+ return MethodType.DELEGATE;
+ }
+
+ private QueryRoot initQueryRoot()
+ {
+ if (methodType == MethodType.PARSE)
+ {
+ return QueryRoot.create(method.getName(), repo);
+ }
+ return QueryRoot.UNKNOWN_ROOT;
+ }
+
+ private boolean isAnnotated()
+ {
+ if (method.isAnnotationPresent(Query.class))
+ {
+ Query query = method.getAnnotation(Query.class);
+ return isValid(query);
+ }
+ return false;
+ }
+
+ private boolean isValid(Query query)
+ {
+ return isNotEmpty(query.value()) || isNotEmpty(query.named());
+ }
+
+ private boolean isMethodExpression()
+ {
+ if (!Modifier.isAbstract(method.getModifiers()))
+ {
+ return false;
+ }
+ try
+ {
+ QueryRoot.create(method.getName(), repo);
+ return true;
+ }
+ catch (MethodExpressionException e)
+ {
+ return false;
+ }
+ }
+
+ public MethodType getMethodType()
+ {
+ return methodType;
+ }
+
+ public RepositoryComponent getRepository()
+ {
+ return repo;
+ }
+
+ public QueryRoot getQueryRoot()
+ {
+ return queryRoot;
+ }
+
+ public QueryProcessor getQueryProcessor()
+ {
+ return queryProcessor;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/AnnotationMetadataExtractor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/AnnotationMetadataExtractor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/AnnotationMetadataExtractor.java
new file mode 100644
index 0000000..4542190
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/AnnotationMetadataExtractor.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.extractor;
+
+import org.apache.deltaspike.data.api.Repository;
+import org.apache.deltaspike.data.impl.meta.RepositoryEntity;
+import org.apache.deltaspike.data.impl.meta.verifier.EntityVerifier;
+import org.apache.deltaspike.data.impl.meta.verifier.Verifier;
+import org.apache.deltaspike.data.impl.util.EntityUtils;
+
+public class AnnotationMetadataExtractor implements MetadataExtractor
+{
+
+ private final Verifier<Class<?>> verifier;
+
+ public AnnotationMetadataExtractor()
+ {
+ this.verifier = new EntityVerifier();
+ }
+
+ @Override
+ public RepositoryEntity extract(Class<?> repoClass)
+ {
+ Repository repo = repoClass.getAnnotation(Repository.class);
+ Class<?> repoEntity = repo.forEntity();
+ boolean isEntityClass = !Object.class.equals(repoEntity) && verifier.verify(repoEntity);
+ if (isEntityClass)
+ {
+ return new RepositoryEntity(repoEntity, EntityUtils.primaryKeyClass(repoEntity));
+ }
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/MetadataExtractor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/MetadataExtractor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/MetadataExtractor.java
new file mode 100644
index 0000000..93cd939
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/MetadataExtractor.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.extractor;
+
+import org.apache.deltaspike.data.impl.meta.RepositoryEntity;
+
+public interface MetadataExtractor
+{
+
+ /**
+ * Read entity meta data for a class.
+ *
+ * @return Meta data packed in a {@link RepositoryEntity},
+ * or {@code null} if the extractor was not able to find data.
+ */
+ RepositoryEntity extract(Class<?> repoClass);
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/TypeMetadataExtractor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/TypeMetadataExtractor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/TypeMetadataExtractor.java
new file mode 100644
index 0000000..8b36d39
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/extractor/TypeMetadataExtractor.java
@@ -0,0 +1,93 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.extractor;
+
+import java.io.Serializable;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import org.apache.deltaspike.data.impl.meta.RepositoryEntity;
+import org.apache.deltaspike.data.impl.util.EntityUtils;
+
+public class TypeMetadataExtractor implements MetadataExtractor
+{
+
+ private static final Logger log = Logger.getLogger(TypeMetadataExtractor.class.getName());
+
+ @Override
+ public RepositoryEntity extract(Class<?> repoClass)
+ {
+ for (Type inf : repoClass.getGenericInterfaces())
+ {
+ RepositoryEntity result = extractFrom(inf);
+ if (result != null)
+ {
+ return result;
+ }
+ }
+ RepositoryEntity result = extractFrom(repoClass.getGenericSuperclass());
+ if (result != null)
+ {
+ return result;
+ }
+ for (Type intf : repoClass.getGenericInterfaces())
+ {
+ result = extractFrom(intf);
+ if (result != null)
+ {
+ return result;
+ }
+ }
+ if (repoClass.getSuperclass() != null)
+ {
+ return extract(repoClass.getSuperclass());
+ }
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ private RepositoryEntity extractFrom(Type type)
+ {
+ log.log(Level.FINER, "extractFrom: type = {0}", type);
+ if (!(type instanceof ParameterizedType))
+ {
+ return null;
+ }
+ ParameterizedType parametrizedType = (ParameterizedType) type;
+ Type[] genericTypes = parametrizedType.getActualTypeArguments();
+ RepositoryEntity result = null;
+ for (Type genericType : genericTypes)
+ {
+ if (genericType instanceof Class && EntityUtils.isEntityClass((Class<?>) genericType))
+ {
+ result = new RepositoryEntity((Class<?>) genericType);
+ continue;
+ }
+ if (result != null && genericType instanceof Class)
+ {
+ result.setPrimaryClass((Class<? extends Serializable>) genericType);
+ return result;
+ }
+ }
+ return result;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/Descriptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/Descriptor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/Descriptor.java
new file mode 100644
index 0000000..8350f36
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/Descriptor.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import java.net.URL;
+
+import org.w3c.dom.Document;
+
+class Descriptor
+{
+
+ private final Document document;
+ private final URL url;
+
+ public Descriptor(Document document, URL url)
+ {
+ this.document = document;
+ this.url = url;
+ }
+
+ public Document getDocument()
+ {
+ return document;
+ }
+
+ public URL getUrl()
+ {
+ return url;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/DescriptorHierarchyBuilder.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/DescriptorHierarchyBuilder.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/DescriptorHierarchyBuilder.java
new file mode 100644
index 0000000..e57099c
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/DescriptorHierarchyBuilder.java
@@ -0,0 +1,88 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import java.util.List;
+
+public final class DescriptorHierarchyBuilder
+{
+
+ private final List<EntityDescriptor> entities;
+ private final List<MappedSuperclassDescriptor> superClasses;
+
+ private DescriptorHierarchyBuilder(List<EntityDescriptor> entities,
+ List<MappedSuperclassDescriptor> superClasses)
+ {
+ this.entities = entities;
+ this.superClasses = superClasses;
+ }
+
+ public static DescriptorHierarchyBuilder newInstance(List<EntityDescriptor> entities,
+ List<MappedSuperclassDescriptor> superClasses)
+ {
+ return new DescriptorHierarchyBuilder(entities, superClasses);
+ }
+
+ public void buildHierarchy()
+ {
+ for (EntityDescriptor descriptor : entities)
+ {
+ buildHierarchy(descriptor);
+ }
+ }
+
+ private void buildHierarchy(PersistentClassDescriptor descriptor)
+ {
+ Class<?> superClass = descriptor.getEntityClass().getSuperclass();
+ while (superClass != null)
+ {
+ PersistentClassDescriptor superDescriptor = findPersistentClassDescriptor(superClass);
+ if (superDescriptor != null)
+ {
+ if (descriptor.getParent() == null)
+ {
+ buildHierarchy(superDescriptor);
+ }
+ descriptor.setParent(superDescriptor);
+ return;
+ }
+ superClass = superClass.getSuperclass();
+ }
+ }
+
+ private PersistentClassDescriptor findPersistentClassDescriptor(Class<?> superClass)
+ {
+ for (MappedSuperclassDescriptor descriptor : superClasses)
+ {
+ if (descriptor.getEntityClass().equals(superClass))
+ {
+ return descriptor;
+ }
+ }
+ for (EntityDescriptor descriptor : entities)
+ {
+ if (descriptor.getEntityClass().equals(superClass))
+ {
+ return descriptor;
+ }
+ }
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/DescriptorReader.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/DescriptorReader.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/DescriptorReader.java
new file mode 100644
index 0000000..e2b6285
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/DescriptorReader.java
@@ -0,0 +1,122 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import static java.lang.Thread.currentThread;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.LinkedList;
+import java.util.List;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+abstract class DescriptorReader
+{
+
+ private final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+
+ List<Descriptor> readAllFromClassPath(String resource) throws IOException
+ {
+ List<Descriptor> result = new LinkedList<Descriptor>();
+ Enumeration<URL> urls = classLoader().getResources(resource);
+ while (urls.hasMoreElements())
+ {
+ URL u = urls.nextElement();
+ result.add(readFromUrl(u));
+ }
+ return Collections.unmodifiableList(result);
+ }
+
+ Descriptor readFromClassPath(String resource) throws IOException
+ {
+ return readFromUrl(classLoader().getResource(resource));
+ }
+
+ Descriptor readFromUrl(URL url) throws IOException
+ {
+ if (!exists(url))
+ {
+ throw new IllegalArgumentException("URL does not exist: " + url);
+ }
+ InputStream stream = url.openStream();
+ try
+ {
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ return new Descriptor(builder.parse(new InputSource(stream)), url);
+ }
+ catch (SAXException e)
+ {
+ throw new RuntimeException("Failed reading XML document", e);
+ }
+ catch (ParserConfigurationException e)
+ {
+ throw new RuntimeException("Failed reading XML document", e);
+ }
+ finally
+ {
+ stream.close();
+ }
+ }
+
+ Descriptor read(String baseUrl, String resource) throws IOException
+ {
+ try
+ {
+ URL url = new URL(baseUrl + resource);
+ return readFromUrl(url);
+ }
+ catch (IllegalArgumentException e)
+ {
+ return readFromClassPath(resource);
+ }
+ }
+
+ String extractBaseUrl(URL fileUrl, String resource)
+ {
+ String file = fileUrl.toString();
+ return file.substring(0, file.length() - resource.length());
+ }
+
+ ClassLoader classLoader()
+ {
+ return currentThread().getContextClassLoader();
+ }
+
+ boolean exists(URL url)
+ {
+ try
+ {
+ return url != null && url.openConnection() != null && url.openConnection().getContentLength() > 0;
+ }
+ catch (IOException e)
+ {
+ return false;
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/EntityDescriptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/EntityDescriptor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/EntityDescriptor.java
new file mode 100644
index 0000000..b8d8dcc
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/EntityDescriptor.java
@@ -0,0 +1,72 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import static org.apache.deltaspike.data.impl.util.QueryUtils.isEmpty;
+
+import java.io.Serializable;
+
+class EntityDescriptor extends PersistentClassDescriptor
+{
+
+ EntityDescriptor(String name, String packageName, String className, String idClass, String id)
+ {
+ super(name, packageName, className, idClass, id);
+ }
+
+ public boolean is(Class<?> entityClass)
+ {
+ return this.entityClass.equals(entityClass);
+ }
+
+ @Override
+ public Class<? extends Serializable> getIdClass()
+ {
+ if (idClass == null && getParent() != null)
+ {
+ return getParent().getIdClass();
+ }
+ return super.getIdClass();
+ }
+
+ @Override
+ public String getId()
+ {
+ if (isEmpty(id) && getParent() != null)
+ {
+ return getParent().getId();
+ }
+ return super.getId();
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append("EntityDescriptor ")
+ .append("[entityClass=").append(className(entityClass))
+ .append(", name=").append(name)
+ .append(", idClass=").append(className(idClass))
+ .append(", id=").append(id)
+ .append(", superClass=").append(getParent())
+ .append("]");
+ return builder.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/EntityDescriptorReader.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/EntityDescriptorReader.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/EntityDescriptorReader.java
new file mode 100644
index 0000000..f61928f
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/EntityDescriptorReader.java
@@ -0,0 +1,167 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class EntityDescriptorReader extends DescriptorReader
+{
+
+ public MappingFile readAll(String baseUrl, String resource) throws IOException
+ {
+ return readFromDocument(read(baseUrl, resource).getDocument());
+ }
+
+ public MappingFile readDefaultOrm(String baseUrl) throws IOException
+ {
+ try
+ {
+ Descriptor desc = read(baseUrl, PersistenceUnit.DEFAULT_ORM_PATH);
+ return readFromDocument(desc.getDocument());
+ }
+ catch (IllegalArgumentException e)
+ {
+ return new MappingFile(Collections.<EntityDescriptor> emptyList(),
+ Collections.<MappedSuperclassDescriptor> emptyList());
+ }
+ }
+
+ public MappingFile readFromDocument(Document doc)
+ {
+ List<EntityDescriptor> entities = new EntityBuilder<EntityDescriptor>()
+ {
+ @Override
+ EntityDescriptor instance(String name, String packageName, String className,
+ String idClass, String id)
+ {
+ return new EntityDescriptor(name, packageName, className, idClass, id);
+ }
+
+ @Override
+ String tagName()
+ {
+ return "entity";
+ }
+ }
+ .build(doc);
+ List<MappedSuperclassDescriptor> superClasses = new EntityBuilder<MappedSuperclassDescriptor>()
+ {
+ @Override
+ MappedSuperclassDescriptor instance(String name, String packageName, String className,
+ String idClass, String id)
+ {
+ return new MappedSuperclassDescriptor(name, packageName, className, idClass, id);
+ }
+
+ @Override
+ String tagName()
+ {
+ return "mapped-superclass";
+ }
+ }
+ .build(doc);
+ return new MappingFile(entities, superClasses);
+ }
+
+ private String extractNodeAttribute(Element element, String childName, String attribute)
+ {
+ NodeList list = element.getElementsByTagName(childName);
+ if (list.getLength() == 0)
+ {
+ return null;
+ }
+ return extractAttribute(list.item(0), attribute);
+ }
+
+ private String extractAttribute(Node item, String name)
+ {
+ Node node = item.getAttributes().getNamedItem(name);
+ if (node != null)
+ {
+ return node.getTextContent();
+ }
+ return null;
+ }
+
+ private String extractNodeContent(Element element, String name)
+ {
+ NodeList list = element.getElementsByTagName(name);
+ if (list.getLength() == 0)
+ {
+ return null;
+ }
+ return list.item(0).getTextContent();
+ }
+
+ public static class MappingFile
+ {
+ private final List<EntityDescriptor> entities;
+ private final List<MappedSuperclassDescriptor> superClasses;
+
+ public MappingFile(List<EntityDescriptor> entities, List<MappedSuperclassDescriptor> superClasses)
+ {
+ this.entities = entities;
+ this.superClasses = superClasses;
+ }
+
+ public List<EntityDescriptor> getEntities()
+ {
+ return entities;
+ }
+
+ public List<MappedSuperclassDescriptor> getSuperClasses()
+ {
+ return superClasses;
+ }
+ }
+
+ private abstract class EntityBuilder<T extends PersistentClassDescriptor>
+ {
+
+ public List<T> build(Document doc)
+ {
+ List<T> result = new LinkedList<T>();
+ String packageName = extractNodeContent(doc.getDocumentElement(), "package");
+ NodeList mappings = doc.getElementsByTagName(tagName());
+ for (int i = 0; i < mappings.getLength(); i++)
+ {
+ String name = extractAttribute(mappings.item(i), "name");
+ String className = extractAttribute(mappings.item(i), "class");
+ String idClass = extractNodeAttribute((Element) mappings.item(i), "id-class", "class");
+ String id = extractNodeAttribute((Element) mappings.item(i), "id", "name");
+ String embeddedId = extractNodeAttribute((Element) mappings.item(i), "embedded-id", "name");
+ result.add(instance(name, packageName, className, idClass, id != null ? id : embeddedId));
+ }
+ return result;
+ }
+
+ abstract T instance(String name, String packageName, String className, String idClass, String id);
+
+ abstract String tagName();
+
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/MappedSuperclassDescriptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/MappedSuperclassDescriptor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/MappedSuperclassDescriptor.java
new file mode 100644
index 0000000..6a6fcfa
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/MappedSuperclassDescriptor.java
@@ -0,0 +1,67 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import static org.apache.deltaspike.data.impl.util.QueryUtils.isEmpty;
+
+import java.io.Serializable;
+
+class MappedSuperclassDescriptor extends PersistentClassDescriptor
+{
+
+ MappedSuperclassDescriptor(String name, String packageName, String className, String idClass, String id)
+ {
+ super(name, packageName, className, idClass, id);
+ }
+
+ @Override
+ public Class<? extends Serializable> getIdClass()
+ {
+ if (idClass == null && getParent() != null)
+ {
+ return getParent().getIdClass();
+ }
+ return super.getIdClass();
+ }
+
+ @Override
+ public String getId()
+ {
+ if (isEmpty(id) && getParent() != null)
+ {
+ return getParent().getId();
+ }
+ return super.getId();
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append("MappedSuperclassDescriptor ")
+ .append("[entityClass=").append(className(entityClass))
+ .append(", name=").append(name)
+ .append(", idClass=").append(className(idClass))
+ .append(", id=").append(id)
+ .append(", parent=").append(getParent())
+ .append("]");
+ return builder.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnit.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnit.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnit.java
new file mode 100644
index 0000000..8494cfa
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnit.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import java.util.List;
+
+class PersistenceUnit
+{
+
+ public static final String RESOURCE_PATH = "META-INF/persistence.xml";
+ public static final String DEFAULT_ORM_PATH = "META-INF/orm.xml";
+
+ private final String unitName;
+ private final List<EntityDescriptor> entities;
+
+ PersistenceUnit(String unitName, List<EntityDescriptor> entities)
+ {
+ this.unitName = unitName;
+ this.entities = entities;
+ }
+
+ public EntityDescriptor find(Class<?> entityClass)
+ {
+ for (EntityDescriptor entity : entities)
+ {
+ if (entity.is(entityClass))
+ {
+ return entity;
+ }
+ }
+ return null;
+ }
+
+ public String getUnitName()
+ {
+ return unitName;
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+ builder.append("PersistenceUnit [unitName=").append(unitName)
+ .append(", entities=").append(entities).append("]");
+ return builder.toString();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnitReader.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnitReader.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnitReader.java
new file mode 100644
index 0000000..64694ea
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnitReader.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.deltaspike.data.impl.meta.unit.EntityDescriptorReader.MappingFile;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+public class PersistenceUnitReader extends DescriptorReader
+{
+
+ public List<PersistenceUnit> readAll() throws IOException
+ {
+ List<PersistenceUnit> result = new LinkedList<PersistenceUnit>();
+ List<Descriptor> persistenceXmls = readAllFromClassPath(PersistenceUnit.RESOURCE_PATH);
+ for (Descriptor desc : persistenceXmls)
+ {
+ result.addAll(lookupUnits(desc));
+ }
+ return Collections.unmodifiableList(result);
+ }
+
+ private List<PersistenceUnit> lookupUnits(Descriptor descriptor)
+ {
+ List<PersistenceUnit> result = new LinkedList<PersistenceUnit>();
+ NodeList list = descriptor.getDocument().getDocumentElement().getElementsByTagName("persistence-unit");
+ for (int i = 0; i < list.getLength(); i++)
+ {
+ Node node = list.item(i);
+ String unitName = extractUnitName(node);
+ String baseUrl = extractBaseUrl(descriptor.getUrl(), PersistenceUnit.RESOURCE_PATH);
+ List<EntityDescriptor> entities = extractMappings((Element) node, baseUrl);
+ result.add(new PersistenceUnit(unitName, entities));
+ }
+ return result;
+ }
+
+ private List<EntityDescriptor> extractMappings(Element element, String baseUrl)
+ {
+ try
+ {
+ EntityDescriptorReader reader = new EntityDescriptorReader();
+ List<EntityDescriptor> entities = new LinkedList<EntityDescriptor>();
+ List<MappedSuperclassDescriptor> superClasses = new LinkedList<MappedSuperclassDescriptor>();
+ NodeList list = element.getElementsByTagName("mapping-file");
+ for (int i = 0; i < list.getLength(); i++)
+ {
+ MappingFile mappings = reader.readAll(baseUrl, list.item(i).getTextContent());
+ entities.addAll(mappings.getEntities());
+ superClasses.addAll(mappings.getSuperClasses());
+ }
+ MappingFile mappings = reader.readDefaultOrm(baseUrl);
+ entities.addAll(mappings.getEntities());
+ superClasses.addAll(mappings.getSuperClasses());
+ DescriptorHierarchyBuilder.newInstance(entities, superClasses).buildHierarchy();
+ return entities;
+ }
+ catch (Exception e)
+ {
+ throw new RuntimeException("Failed initializing mapping files", e);
+ }
+ }
+
+ private String extractUnitName(Node node)
+ {
+ return node.getAttributes().getNamedItem("name").getTextContent();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnits.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnits.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnits.java
new file mode 100644
index 0000000..666003b
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistenceUnits.java
@@ -0,0 +1,119 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.deltaspike.data.impl.meta.RepositoryEntity;
+
+public final class PersistenceUnits
+{
+
+ private static PersistenceUnits instance = new PersistenceUnits();
+
+ private List<PersistenceUnit> persistenceUnits = Collections.emptyList();
+
+ private PersistenceUnits()
+ {
+ }
+
+ public static PersistenceUnits instance()
+ {
+ return instance;
+ }
+
+ public void init()
+ {
+ persistenceUnits = readPersistenceXmls();
+ }
+
+ public boolean isEntity(Class<?> entityClass)
+ {
+ return find(entityClass) != null;
+ }
+
+ public String primaryKeyField(Class<?> entityClass)
+ {
+ EntityDescriptor entity = find(entityClass);
+ if (entity != null)
+ {
+ return entity.getId();
+ }
+ return null;
+ }
+
+ public Class<?> primaryKeyIdClass(Class<?> entityClass)
+ {
+ EntityDescriptor entity = find(entityClass);
+ if (entity != null && entity.getIdClass() != null)
+ {
+ return entity.getIdClass();
+ }
+ return null;
+ }
+
+ public String entityName(Class<?> entityClass)
+ {
+ EntityDescriptor entity = find(entityClass);
+ if (entity != null)
+ {
+ return entity.getName();
+ }
+ return null;
+ }
+
+ public RepositoryEntity lookupMetadata(Class<?> entityClass)
+ {
+ EntityDescriptor entity = find(entityClass);
+ if (entity != null)
+ {
+ return new RepositoryEntity(entityClass, entity.getIdClass());
+ }
+ return null;
+ }
+
+ private List<PersistenceUnit> readPersistenceXmls()
+ {
+ try
+ {
+ PersistenceUnitReader reader = new PersistenceUnitReader();
+ return reader.readAll();
+ }
+ catch (IOException e)
+ {
+ throw new RuntimeException("Failed to read persistence unit info", e);
+ }
+ }
+
+ private EntityDescriptor find(Class<?> entityClass)
+ {
+ for (PersistenceUnit unit : persistenceUnits)
+ {
+ EntityDescriptor entity = unit.find(entityClass);
+ if (entity != null)
+ {
+ return entity;
+ }
+ }
+ return null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistentClassDescriptor.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistentClassDescriptor.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistentClassDescriptor.java
new file mode 100644
index 0000000..a0ba3fa
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/unit/PersistentClassDescriptor.java
@@ -0,0 +1,132 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.unit;
+
+import java.io.Serializable;
+
+import org.apache.deltaspike.data.impl.property.query.NamedPropertyCriteria;
+import org.apache.deltaspike.data.impl.property.query.PropertyQueries;
+import org.apache.deltaspike.data.impl.property.query.PropertyQuery;
+
+abstract class PersistentClassDescriptor
+{
+
+ protected final String name;
+ protected final Class<?> entityClass;
+ protected final Class<? extends Serializable> idClass;
+ protected final String id;
+ private PersistentClassDescriptor parent;
+
+ PersistentClassDescriptor(String name, String packageName, String className, String idClass, String id)
+ {
+ Class<?> clazz = entityClass(className, packageName);
+ this.name = name;
+ this.entityClass = clazz;
+ this.idClass = idClass(clazz, idClass, packageName, id);
+ this.id = id;
+ }
+
+ public Class<? extends Serializable> getIdClass()
+ {
+ return idClass;
+ }
+
+ public String getId()
+ {
+ return id;
+ }
+
+ public String getName()
+ {
+ return name;
+ }
+
+ public Class<?> getEntityClass()
+ {
+ return entityClass;
+ }
+
+ String className(Class<?> clazz)
+ {
+ return clazz == null ? null : clazz.getSimpleName();
+ }
+
+ private Class<?> entityClass(String entityClass, String packageName)
+ {
+ try
+ {
+ String clazzName = buildClassName(entityClass, packageName);
+ return Class.forName(clazzName);
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalArgumentException("Can't create class " + buildClassName(entityClass, packageName), e);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ private Class<? extends Serializable> idClass(Class<?> entity, String idClass, String packageName, String id)
+ {
+ try
+ {
+ return (Class<? extends Serializable>) (idClass != null ? Class
+ .forName(buildClassName(idClass, packageName)) : lookupIdClass(entity, id));
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new IllegalArgumentException("Failed to get ID class", e);
+ }
+ }
+
+ private Class<?> lookupIdClass(Class<?> entity, String id)
+ {
+ if (entity == null || id == null)
+ {
+ return null;
+ }
+ PropertyQuery<Serializable> query = PropertyQueries.<Serializable> createQuery(entity)
+ .addCriteria(new NamedPropertyCriteria(id));
+ return query.getFirstResult().getJavaClass();
+ }
+
+ private String buildClassName(String clazzName, String packageName)
+ {
+ if (clazzName == null && packageName == null)
+ {
+ return null;
+ }
+ return (packageName != null && !isClassNameQualified(clazzName)) ? packageName + "." + clazzName : clazzName;
+ }
+
+ private boolean isClassNameQualified(String name)
+ {
+ return name.contains(".");
+ }
+
+ public PersistentClassDescriptor getParent()
+ {
+ return parent;
+ }
+
+ public void setParent(PersistentClassDescriptor parent)
+ {
+ this.parent = parent;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/verifier/EntityVerifier.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/verifier/EntityVerifier.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/verifier/EntityVerifier.java
new file mode 100644
index 0000000..e37d1a8
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/verifier/EntityVerifier.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.verifier;
+
+import javax.persistence.Entity;
+
+import org.apache.deltaspike.data.impl.meta.unit.PersistenceUnits;
+
+public class EntityVerifier implements Verifier<Class<?>>
+{
+
+ @Override
+ public boolean verify(Class<?> entity)
+ {
+ return entity.isAnnotationPresent(Entity.class) || PersistenceUnits.instance().isEntity(entity);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/verifier/Verifier.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/verifier/Verifier.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/verifier/Verifier.java
new file mode 100644
index 0000000..62fe3ab
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/meta/verifier/Verifier.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.meta.verifier;
+
+public interface Verifier<T>
+{
+
+ boolean verify(T t);
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/IndexedParameter.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/IndexedParameter.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/IndexedParameter.java
new file mode 100644
index 0000000..9f17ef4
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/IndexedParameter.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.param;
+
+import javax.persistence.Query;
+
+/**
+ * Query parameters which have an index (?1).
+ *
+ * @author thomashug
+ */
+public class IndexedParameter extends Parameter
+{
+
+ private final int index;
+
+ public IndexedParameter(int index, Object value, int argIndex)
+ {
+ super(value, argIndex);
+ this.index = index;
+ }
+
+ @Override
+ public void apply(Query query)
+ {
+ query.setParameter(index, value);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/NamedParameter.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/NamedParameter.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/NamedParameter.java
new file mode 100644
index 0000000..14d2aeb
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/NamedParameter.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.param;
+
+import javax.persistence.Query;
+
+/**
+ * Parameters which have a name (:name).
+ *
+ * @author thomashug
+ */
+public class NamedParameter extends Parameter
+{
+
+ private final String name;
+
+ public NamedParameter(String name, Object value, int argIndex)
+ {
+ super(value, argIndex);
+ this.name = name;
+ }
+
+ @Override
+ public void apply(Query query)
+ {
+ query.setParameter(name, value);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameter.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameter.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameter.java
new file mode 100644
index 0000000..24253ab
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameter.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.param;
+
+import javax.persistence.Query;
+
+/**
+ * Base class for parameters.
+ *
+ * @author thomashug
+ */
+public abstract class Parameter
+{
+
+ protected final Object value;
+ protected final int argIndex;
+
+ public Parameter(Object value, int argIndex)
+ {
+ this.value = value;
+ this.argIndex = argIndex;
+ }
+
+ public abstract void apply(Query query);
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java
new file mode 100644
index 0000000..4599d44
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/param/Parameters.java
@@ -0,0 +1,175 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.param;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.persistence.Query;
+
+import org.apache.deltaspike.data.api.FirstResult;
+import org.apache.deltaspike.data.api.MaxResults;
+import org.apache.deltaspike.data.api.QueryParam;
+
+/**
+ * Convenience class to manage method and query parameters.
+ *
+ * @author thomashug
+ */
+public final class Parameters
+{
+
+ private static final Logger LOG = Logger.getLogger(Parameters.class.getName());
+
+ private static final int DEFAULT_MAX = 0;
+ private static final int DEFAULT_FIRST = -1;
+
+ private final List<Parameter> parameterList;
+ private final int max;
+ private final int firstResult;
+
+ private Parameters(List<Parameter> parameters, int max, int firstResult)
+ {
+ this.parameterList = parameters;
+ this.max = max;
+ this.firstResult = firstResult;
+ }
+
+ public static Parameters createEmpty()
+ {
+ List<Parameter> empty = Collections.emptyList();
+ return new Parameters(empty, DEFAULT_MAX, DEFAULT_FIRST);
+ }
+
+ public static Parameters create(Method method, Object[] parameters)
+ {
+ int max = extractSizeRestriction(method);
+ int first = DEFAULT_FIRST;
+ List<Parameter> result = new ArrayList<Parameter>(parameters.length);
+ int paramIndex = 1;
+ Annotation[][] annotations = method.getParameterAnnotations();
+ for (int i = 0; i < parameters.length; i++)
+ {
+ if (isParameter(method.getParameterAnnotations()[i]))
+ {
+ QueryParam qpAnnotation = extractFrom(annotations[i], QueryParam.class);
+ if (qpAnnotation != null)
+ {
+ result.add(new NamedParameter(qpAnnotation.value(), parameters[i], i));
+ }
+ else
+ {
+ result.add(new IndexedParameter(paramIndex++, parameters[i], i));
+ }
+ }
+ else
+ {
+ max = extractInt(parameters[i], annotations[i], MaxResults.class, max);
+ first = extractInt(parameters[i], annotations[i], FirstResult.class, first);
+ }
+ }
+ return new Parameters(result, max, first);
+ }
+
+ public Query applyTo(Query query)
+ {
+ for (Parameter param : parameterList)
+ {
+ param.apply(query);
+ }
+ return query;
+ }
+
+ public boolean hasSizeRestriction()
+ {
+ return max > DEFAULT_MAX;
+ }
+
+ public int getSizeRestriciton()
+ {
+ return max;
+ }
+
+ public boolean hasFirstResult()
+ {
+ return firstResult > DEFAULT_FIRST;
+ }
+
+ public int getFirstResult()
+ {
+ return firstResult;
+ }
+
+ private static int extractSizeRestriction(Method method)
+ {
+ if (method.isAnnotationPresent(org.apache.deltaspike.data.api.Query.class))
+ {
+ return method.getAnnotation(org.apache.deltaspike.data.api.Query.class).max();
+ }
+ return 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ private static <A extends Annotation> A extractFrom(Annotation[] annotations, Class<A> target)
+ {
+ for (Annotation annotation : annotations)
+ {
+ if (annotation.annotationType().isAssignableFrom(target))
+ {
+ return (A) annotation;
+ }
+ }
+ return null;
+ }
+
+ private static <A extends Annotation> int extractInt(Object parameter, Annotation[] annotations,
+ Class<A> target, int defaultVal)
+ {
+ if (parameter != null)
+ {
+ A result = extractFrom(annotations, target);
+ if (result != null)
+ {
+ if (parameter instanceof Integer)
+ {
+ return (Integer) parameter;
+ }
+ else
+ {
+ LOG.log(Level.WARNING, "Method parameter extraction: " +
+ "Param type must be int: {0}->is:{1}",
+ new Object[] { target, parameter.getClass() });
+ }
+ }
+ }
+ return defaultVal;
+ }
+
+ private static boolean isParameter(Annotation[] annotations)
+ {
+ return extractFrom(annotations, MaxResults.class) == null &&
+ extractFrom(annotations, FirstResult.class) == null;
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/FieldProperty.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/FieldProperty.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/FieldProperty.java
new file mode 100644
index 0000000..4c9425e
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/FieldProperty.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.property;
+
+import java.lang.reflect.Field;
+
+public interface FieldProperty<V> extends Property<V>
+{
+
+ @Override
+ Field getAnnotatedElement();
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/FieldPropertyImpl.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/FieldPropertyImpl.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/FieldPropertyImpl.java
new file mode 100644
index 0000000..2d81bb0
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/FieldPropertyImpl.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.property;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Member;
+import java.lang.reflect.Type;
+
+/**
+ * A bean property based on the value contained in a field
+ *
+ * @author Pete Muir
+ * @author Shane Bryzak
+ */
+class FieldPropertyImpl<V> implements FieldProperty<V>
+{
+
+ private final Field field;
+
+ FieldPropertyImpl(Field field)
+ {
+ this.field = field;
+ }
+
+ @Override
+ public String getName()
+ {
+ return field.getName();
+ }
+
+ @Override
+ public Type getBaseType()
+ {
+ return field.getGenericType();
+ }
+
+ @Override
+ public Field getAnnotatedElement()
+ {
+ return field;
+ }
+
+ @Override
+ public Member getMember()
+ {
+ return field;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Class<V> getJavaClass()
+ {
+ return (Class<V>) field.getType();
+ }
+
+ @Override
+ public V getValue(Object instance)
+ {
+ setAccessible();
+ return Reflections.getFieldValue(field, instance, getJavaClass());
+ }
+
+ @Override
+ public void setValue(Object instance, V value)
+ {
+ setAccessible();
+ Reflections.setFieldValue(true, field, instance, value);
+ }
+
+ @Override
+ public Class<?> getDeclaringClass()
+ {
+ return field.getDeclaringClass();
+ }
+
+ @Override
+ public boolean isReadOnly()
+ {
+ return false;
+ }
+
+ @Override
+ public void setAccessible()
+ {
+ Reflections.setAccessible(field);
+ }
+
+ @Override
+ public String toString()
+ {
+ return field.toString();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ return field.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ return field.equals(obj);
+ }
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/MethodProperty.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/MethodProperty.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/MethodProperty.java
new file mode 100644
index 0000000..5a34128
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/MethodProperty.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.property;
+
+import java.lang.reflect.Method;
+
+public interface MethodProperty<V> extends Property<V>
+{
+
+ @Override
+ Method getAnnotatedElement();
+
+}
http://git-wip-us.apache.org/repos/asf/deltaspike/blob/ae1a7147/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/MethodPropertyImpl.java
----------------------------------------------------------------------
diff --git a/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/MethodPropertyImpl.java b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/MethodPropertyImpl.java
new file mode 100644
index 0000000..620ac8c
--- /dev/null
+++ b/deltaspike/modules/data/impl/src/main/java/org/apache/deltaspike/data/impl/property/MethodPropertyImpl.java
@@ -0,0 +1,272 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you 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.deltaspike.data.impl.property;
+
+import java.beans.Introspector;
+import java.lang.reflect.Member;
+import java.lang.reflect.Method;
+import java.lang.reflect.Type;
+
+/**
+ * A bean property based on the value represented by a getter/setter method pair
+ *
+ * @author Pete Muir
+ * @author Shane Bryzak
+ * @author Dan Allen
+ */
+class MethodPropertyImpl<V> implements MethodProperty<V>
+{
+ private static final String GETTER_METHOD_PREFIX = "get";
+ private static final String SETTER_METHOD_PREFIX = "set";
+ private static final String BOOLEAN_GETTER_METHOD_PREFIX = "is";
+
+ private static final int GETTER_METHOD_PREFIX_LENGTH = GETTER_METHOD_PREFIX.length();
+ private static final int SETTER_METHOD_PREFIX_LENGTH = SETTER_METHOD_PREFIX.length();
+ private static final int BOOLEAN_GETTER_METHOD_PREFIX_LENGTH = BOOLEAN_GETTER_METHOD_PREFIX.length();
+
+ private final Method getterMethod;
+ private final String propertyName;
+ private final Method setterMethod;
+
+ public MethodPropertyImpl(Method method)
+ {
+ final String accessorMethodPrefix;
+ final String propertyNameInAccessorMethod;
+ if (method.getName().startsWith(GETTER_METHOD_PREFIX))
+ {
+ if (method.getReturnType() == Void.TYPE)
+ {
+ throw new IllegalArgumentException(
+ "Invalid accessor method, must have return value if starts with 'get'. Method: " + method);
+ }
+ else if (method.getParameterTypes().length > 0)
+ {
+ throw new IllegalArgumentException(
+ "Invalid accessor method, must have zero arguments if starts with 'get'. Method: " + method);
+ }
+ propertyNameInAccessorMethod = method.getName().substring(GETTER_METHOD_PREFIX_LENGTH);
+ accessorMethodPrefix = GETTER_METHOD_PREFIX;
+ }
+ else if (method.getName().startsWith(SETTER_METHOD_PREFIX))
+ {
+ if (method.getReturnType() != Void.TYPE)
+ {
+ throw new IllegalArgumentException(
+ "Invalid accessor method, must not have return value if starts with 'set'. Method: " + method);
+ }
+ else if (method.getParameterTypes().length != 1)
+ {
+ throw new IllegalArgumentException(
+ "Invalid accessor method, must have one argument if starts with 'set'. Method: " + method);
+ }
+ propertyNameInAccessorMethod = method.getName().substring(SETTER_METHOD_PREFIX_LENGTH);
+ accessorMethodPrefix = SETTER_METHOD_PREFIX;
+ }
+ else if (method.getName().startsWith(BOOLEAN_GETTER_METHOD_PREFIX))
+ {
+ if (method.getReturnType() != Boolean.TYPE || !method.getReturnType().isPrimitive())
+ {
+ throw new IllegalArgumentException(
+ "Invalid accessor method, must return boolean primitive if starts " +
+ "with 'is'. Method: " + method);
+ }
+ propertyNameInAccessorMethod = method.getName().substring(BOOLEAN_GETTER_METHOD_PREFIX_LENGTH);
+ accessorMethodPrefix = BOOLEAN_GETTER_METHOD_PREFIX;
+ }
+ else
+ {
+ throw new IllegalArgumentException("Invalid accessor method, must start with 'get', 'set' or 'is'. "
+ + "Method: " + method);
+ }
+ if (propertyNameInAccessorMethod.length() == 0
+ || !Character.isUpperCase(propertyNameInAccessorMethod.charAt(0)))
+ {
+ throw new IllegalArgumentException("Invalid accessor method, prefix '" + accessorMethodPrefix
+ + "' must be followed a non-empty property name, capitalized. Method: " + method);
+ }
+ this.propertyName = Introspector.decapitalize(propertyNameInAccessorMethod);
+ this.getterMethod = getGetterMethod(method.getDeclaringClass(), propertyName);
+ this.setterMethod = getSetterMethod(method.getDeclaringClass(), propertyName);
+ }
+
+ @Override
+ public String getName()
+ {
+ return propertyName;
+ }
+
+ @Override
+ @SuppressWarnings("unchecked")
+ public Class<V> getJavaClass()
+ {
+ return (Class<V>) getterMethod.getReturnType();
+ }
+
+ @Override
+ public Type getBaseType()
+ {
+ return getterMethod.getGenericReturnType();
+ }
+
+ @Override
+ public Method getAnnotatedElement()
+ {
+ return getterMethod;
+ }
+
+ @Override
+ public Member getMember()
+ {
+ return getterMethod;
+ }
+
+ @Override
+ public V getValue(Object instance)
+ {
+ if (getterMethod == null)
+ {
+ throw new UnsupportedOperationException("Property " + this.setterMethod.getDeclaringClass() + "."
+ + propertyName + " cannot be read, as there is no getter method.");
+ }
+ return Reflections.cast(Reflections.invokeMethod(getterMethod, instance));
+ }
+
+ @Override
+ public void setValue(Object instance, V value)
+ {
+ if (setterMethod == null)
+ {
+ throw new UnsupportedOperationException("Property " + this.getterMethod.getDeclaringClass() + "."
+ + propertyName + " is read only, as there is no setter method.");
+ }
+ Reflections.invokeMethod(setterMethod, instance, value);
+ }
+
+ private static Method getSetterMethod(Class<?> clazz, String name)
+ {
+ Method[] methods = clazz.getMethods();
+ for (Method method : methods)
+ {
+ String methodName = method.getName();
+ if (methodName.startsWith(SETTER_METHOD_PREFIX) && method.getParameterTypes().length == 1)
+ {
+ if (Introspector.decapitalize(methodName.substring(SETTER_METHOD_PREFIX_LENGTH)).equals(name))
+ {
+ return method;
+ }
+ }
+ }
+ return null;
+ }
+
+ private static Method getGetterMethod(Class<?> clazz, String name)
+ {
+ for (Method method : clazz.getDeclaredMethods())
+ {
+ String methodName = method.getName();
+ if (method.getParameterTypes().length == 0)
+ {
+ if (methodName.startsWith(GETTER_METHOD_PREFIX))
+ {
+ if (Introspector.decapitalize(methodName.substring(GETTER_METHOD_PREFIX_LENGTH)).equals(name))
+ {
+ return method;
+ }
+ }
+ else if (methodName.startsWith(BOOLEAN_GETTER_METHOD_PREFIX))
+ {
+ if (Introspector.decapitalize(methodName.substring(BOOLEAN_GETTER_METHOD_PREFIX_LENGTH)).equals(
+ name))
+ {
+ return method;
+ }
+ }
+ }
+ }
+ throw new IllegalArgumentException("no such getter method: " + clazz.getName() + '.' + name);
+ }
+
+ @Override
+ public Class<?> getDeclaringClass()
+ {
+ return getterMethod.getDeclaringClass();
+ }
+
+ @Override
+ public boolean isReadOnly()
+ {
+ return setterMethod == null;
+ }
+
+ @Override
+ public void setAccessible()
+ {
+ if (setterMethod != null)
+ {
+ Reflections.setAccessible(setterMethod);
+ }
+ if (getterMethod != null)
+ {
+ Reflections.setAccessible(getterMethod);
+ }
+ }
+
+ @Override
+ public String toString()
+ {
+ StringBuilder builder = new StringBuilder();
+ if (isReadOnly())
+ {
+ builder.append("read-only ").append(setterMethod.toString()).append("; ");
+ }
+ builder.append(getterMethod.toString());
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode()
+ {
+ int hash = 1;
+ hash = hash * 31 + (setterMethod == null ? 0 : setterMethod.hashCode());
+ hash = hash * 31 + getterMethod.hashCode();
+ return hash;
+ }
+
+ @Override
+ public boolean equals(Object obj)
+ {
+ if (obj instanceof MethodPropertyImpl<?>)
+ {
+ MethodPropertyImpl<?> that = (MethodPropertyImpl<?>) obj;
+ if (this.setterMethod == null)
+ {
+ return that.setterMethod == null && this.getterMethod.equals(that.getterMethod);
+ }
+ else
+ {
+ return this.setterMethod.equals(that.setterMethod) && this.getterMethod.equals(that.getterMethod);
+ }
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+}