deltaspike-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From t...@apache.org
Subject [05/11] DELTASPIKE-60 Data module initial import
Date Thu, 27 Jun 2013 08:39:05 GMT
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;
+        }
+    }
+
+}


Mime
View raw message