You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2006/04/26 22:58:50 UTC

svn commit: r396882 [4/11] - in /incubator/cayenne: branches/ tags/ trunk/ trunk/cayenne-jpa-tck/ trunk/cayenne-jpa-tck/.settings/ trunk/cayenne-jpa-tck/src/ trunk/cayenne-jpa-tck/src/main/ trunk/cayenne-jpa-tck/src/main/java/ trunk/cayenne-jpa-tck/src...

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/MemberAnnotationProcessorFactory.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,628 @@
+/* ====================================================================
+ * 
+ * The ObjectStyle Group Software License, version 1.1
+ * ObjectStyle Group - http://objectstyle.org/
+ * 
+ * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
+ * of the software. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 
+ * 3. The end-user documentation included with the redistribution, if any,
+ *    must include the following acknowlegement:
+ *    "This product includes software developed by independent contributors
+ *    and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ * 
+ * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
+ *    or promote products derived from this software without prior written
+ *    permission. For written permission, email
+ *    "andrus at objectstyle dot org".
+ * 
+ * 5. Products derived from this software may not be called "ObjectStyle"
+ *    or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
+ *    names without prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ * 
+ * This software consists of voluntary contributions made by many
+ * individuals and hosted on ObjectStyle Group web site.  For more
+ * information on the ObjectStyle Group, please see
+ * <http://objectstyle.org/>.
+ */
+package org.objectstyle.cayenne.jpa.conf;
+
+import java.lang.reflect.AnnotatedElement;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.regex.Matcher;
+
+import javax.persistence.AttributeOverride;
+import javax.persistence.AttributeOverrides;
+import javax.persistence.Basic;
+import javax.persistence.Column;
+import javax.persistence.EmbeddedId;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.JoinColumns;
+import javax.persistence.JoinTable;
+import javax.persistence.ManyToMany;
+import javax.persistence.ManyToOne;
+import javax.persistence.MapKey;
+import javax.persistence.OneToMany;
+import javax.persistence.OneToOne;
+import javax.persistence.OrderBy;
+import javax.persistence.Temporal;
+
+import org.objectstyle.cayenne.jpa.map.JpaAbstractEntity;
+import org.objectstyle.cayenne.jpa.map.JpaAttribute;
+import org.objectstyle.cayenne.jpa.map.JpaAttributeOverride;
+import org.objectstyle.cayenne.jpa.map.JpaBasic;
+import org.objectstyle.cayenne.jpa.map.JpaColumn;
+import org.objectstyle.cayenne.jpa.map.JpaEmbeddable;
+import org.objectstyle.cayenne.jpa.map.JpaEmbeddableAttribute;
+import org.objectstyle.cayenne.jpa.map.JpaEmbeddedId;
+import org.objectstyle.cayenne.jpa.map.JpaGeneratedValue;
+import org.objectstyle.cayenne.jpa.map.JpaId;
+import org.objectstyle.cayenne.jpa.map.JpaJoinColumn;
+import org.objectstyle.cayenne.jpa.map.JpaJoinTable;
+import org.objectstyle.cayenne.jpa.map.JpaManyToMany;
+import org.objectstyle.cayenne.jpa.map.JpaManyToOne;
+import org.objectstyle.cayenne.jpa.map.JpaOneToMany;
+import org.objectstyle.cayenne.jpa.map.JpaOneToOne;
+
+/**
+ * A factory of member annotation processors.
+ * 
+ * @author Andrus Adamchik
+ */
+class MemberAnnotationProcessorFactory extends AnnotationProcessorFactory {
+
+    static String getMemberName(
+            AnnotatedElement element,
+            AnnotationProcessorContext context,
+            Class annotatedType) {
+
+        if (element instanceof Field) {
+            return ((Field) element).getName();
+        }
+        else if (element instanceof Method) {
+
+            String name = ((Method) element).getName();
+            Matcher getterMatcher = EntityMapAnnotationLoader.GETTER_PATTERN
+                    .matcher(name);
+
+            if (getterMatcher.matches()) {
+                return getterMatcher.group(2);
+            }
+            else {
+                // TODO: andrus, 4/23/2006 - may need to check other getter properties
+                // to see if it is valid
+                context.recordConflict(
+                        element,
+                        annotatedType,
+                        "Annotated method is not a property getter: " + name);
+            }
+        }
+
+        return null;
+    }
+
+    static final class FlushModeProcessor implements AnnotationProcessor {
+
+        public void onStartElement(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+
+            // TODO: andrus, 4/23/2006 - where does this annotation belong??
+
+            context.recordConflict(
+                    element,
+                    EmbeddedId.class,
+                    "FlushMode annotation is not fully defined in the specification");
+        }
+
+        public void onFinishElement(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+        }
+    }
+
+    static final class EmbeddedIdProcessor implements AnnotationProcessor {
+
+        public void onStartElement(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+
+            JpaEmbeddedId id = new JpaEmbeddedId();
+            id.setName(getMemberName(element, context, EmbeddedId.class));
+            
+            Object parent = context.peek();
+            if (parent instanceof JpaAbstractEntity) {
+                ((JpaAbstractEntity) parent).setEmbeddedId(id);
+            }
+            else {
+                context.recordConflict(element, AnnotationProcessorFactory
+                        .annotationClass(getClass()), "Unsupported in this place");
+            }
+            
+            context.push(id);
+        }
+
+        public void onFinishElement(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+
+            context.pop();
+        }
+    }
+
+    static final class IdProcessor implements AnnotationProcessor {
+
+        public void onStartElement(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+
+            JpaId id = new JpaId();
+            id.setName(getMemberName(element, context, Id.class));
+
+            Object parent = context.peek();
+            if (parent instanceof JpaAbstractEntity) {
+                ((JpaAbstractEntity) parent).getIds().add(id);
+            }
+            else {
+                context.recordConflict(element, AnnotationProcessorFactory
+                        .annotationClass(getClass()), "Unsupported in this place");
+            }
+
+            context.push(id);
+        }
+
+        public void onFinishElement(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+
+            context.pop();
+        }
+    }
+
+    abstract static class AbstractChildProcessor implements AnnotationProcessor {
+
+        public void onStartElement(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+
+            Object parent = context.peek();
+
+            if (parent instanceof JpaAttribute) {
+                onAttribute((JpaAttribute) parent, element, context);
+            }
+            else if (parent instanceof JpaId) {
+                onId((JpaId) parent, element, context);
+            }
+            else if (parent instanceof JpaEmbeddedId) {
+                onEmbeddedId((JpaEmbeddedId) parent, element, context);
+            }
+            else if (parent instanceof JpaAbstractEntity) {
+                JpaAbstractEntity entity = (JpaAbstractEntity) parent;
+
+                // attribute implied...
+                JpaAttribute attribute = new JpaAttribute();
+                attribute.setName(getMemberName(
+                        element,
+                        context,
+                        AnnotationProcessorFactory.annotationClass(getClass())));
+                entity.getAttributes().add(attribute);
+                context.push(attribute);
+
+                onAttribute(attribute, element, context);
+            }
+            else if (parent instanceof JpaEmbeddableAttribute) {
+                onEmbeddableAttribute((JpaEmbeddableAttribute) parent, element, context);
+            }
+            else if (parent instanceof JpaEmbeddable) {
+                JpaEmbeddable embeddable = (JpaEmbeddable) parent;
+
+                // embeddable attribute implied...
+                JpaEmbeddableAttribute attribute = new JpaEmbeddableAttribute();
+                attribute.setName(getMemberName(
+                        element,
+                        context,
+                        AnnotationProcessorFactory.annotationClass(getClass())));
+                embeddable.getEmbeddableAttributes().add(attribute);
+                context.push(attribute);
+
+                onEmbeddableAttribute(attribute, element, context);
+            }
+        }
+
+        public void onFinishElement(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+
+            Object stackTop = context.peek();
+            if (stackTop instanceof JpaAttribute) {
+                context.pop();
+            }
+            else if (stackTop instanceof JpaEmbeddableAttribute) {
+                context.pop();
+            }
+        }
+
+        void onEmbeddedId(
+                JpaEmbeddedId id,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            recordUnsupportedAnnotation(element, context);
+        }
+
+        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorContext context) {
+            recordUnsupportedAnnotation(element, context);
+        }
+
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            recordUnsupportedAnnotation(element, context);
+        }
+
+        void onEmbeddableAttribute(
+                JpaEmbeddableAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            recordUnsupportedAnnotation(element, context);
+        }
+
+        void recordUnsupportedAnnotation(
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            context.recordConflict(element, AnnotationProcessorFactory
+                    .annotationClass(getClass()), "Unsupported in this place");
+        }
+    }
+
+    // ====== Concrete processor classes ========
+
+    static final class AttributeOverrideProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            AttributeOverride annotation = element.getAnnotation(AttributeOverride.class);
+            attribute.getAttributeOverrides().add(new JpaAttributeOverride(annotation));
+        }
+
+        @Override
+        void onEmbeddedId(
+                JpaEmbeddedId id,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            AttributeOverride annotation = element.getAnnotation(AttributeOverride.class);
+            id.getAttributeOverrides().add(new JpaAttributeOverride(annotation));
+        }
+    }
+
+    static final class AttributeOverridesProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            AttributeOverrides annotation = element
+                    .getAnnotation(AttributeOverrides.class);
+
+            for (int i = 0; i < annotation.value().length; i++) {
+                attribute.getAttributeOverrides().add(
+                        new JpaAttributeOverride(annotation.value()[i]));
+            }
+        }
+
+        @Override
+        void onEmbeddedId(
+                JpaEmbeddedId id,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            AttributeOverrides annotation = element
+                    .getAnnotation(AttributeOverrides.class);
+
+            for (int i = 0; i < annotation.value().length; i++) {
+                id.getAttributeOverrides().add(
+                        new JpaAttributeOverride(annotation.value()[i]));
+            }
+        }
+    }
+
+    static final class BasicProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setBasic(new JpaBasic(element.getAnnotation(Basic.class)));
+        }
+
+        @Override
+        void onEmbeddableAttribute(
+                JpaEmbeddableAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setBasic(new JpaBasic(element.getAnnotation(Basic.class)));
+        }
+    }
+
+    static final class ColumnProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            Column annotation = element.getAnnotation(Column.class);
+            attribute.setColumn(new JpaColumn(annotation));
+        }
+
+        @Override
+        void onEmbeddableAttribute(
+                JpaEmbeddableAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            Column annotation = element.getAnnotation(Column.class);
+            attribute.setColumn(new JpaColumn(annotation));
+        }
+
+        @Override
+        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorContext context) {
+            Column annotation = element.getAnnotation(Column.class);
+            id.setColumn(new JpaColumn(annotation));
+        }
+    }
+
+    static final class EmbeddedProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setEmbedded(true);
+        }
+    }
+
+    static final class EnumeratedProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            Enumerated annotation = element.getAnnotation(Enumerated.class);
+            attribute.setEnumerated(annotation.value());
+        }
+
+        @Override
+        void onEmbeddableAttribute(
+                JpaEmbeddableAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            Enumerated annotation = element.getAnnotation(Enumerated.class);
+            attribute.setEnumerated(annotation.value());
+        }
+    }
+
+    static final class GeneratedValueProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorContext context) {
+            GeneratedValue annotation = element.getAnnotation(GeneratedValue.class);
+            id.setGeneratedValue(new JpaGeneratedValue(annotation));
+        }
+    }
+
+    static final class JoinColumnProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            JoinColumn annotation = element.getAnnotation(JoinColumn.class);
+            attribute.getJoinColumns().add(new JpaJoinColumn(annotation));
+        }
+    }
+
+    static final class JoinColumnsProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            JoinColumns annotation = element.getAnnotation(JoinColumns.class);
+
+            for (int i = 0; i < annotation.value().length; i++) {
+                attribute.getJoinColumns().add(new JpaJoinColumn(annotation.value()[i]));
+            }
+        }
+    }
+
+    static final class JoinTableProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            JoinTable annotation = element.getAnnotation(JoinTable.class);
+            attribute.setJoinTable(new JpaJoinTable(annotation));
+        }
+    }
+
+    static final class LobProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setLob(true);
+        }
+
+        @Override
+        void onEmbeddableAttribute(
+                JpaEmbeddableAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setLob(true);
+        }
+    }
+
+    static final class ManyToManyProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            ManyToMany annotation = element.getAnnotation(ManyToMany.class);
+            attribute.setManyToMany(new JpaManyToMany(annotation));
+        }
+    }
+
+    static final class ManyToOneProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setManyToOne(new JpaManyToOne(element
+                    .getAnnotation(ManyToOne.class)));
+        }
+    }
+
+    static final class MapKeyProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            MapKey annotation = element.getAnnotation(MapKey.class);
+            attribute.setMapKey(annotation.name());
+        }
+    }
+
+    static final class OneToManyProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setOneToMany(new JpaOneToMany(element
+                    .getAnnotation(OneToMany.class)));
+        }
+    }
+
+    static final class OneToOneProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setOneToOne(new JpaOneToOne(element.getAnnotation(OneToOne.class)));
+        }
+    }
+
+    static final class OrderByProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            OrderBy annotation = element.getAnnotation(OrderBy.class);
+            attribute.setOrderBy(annotation.value());
+        }
+    }
+
+    static final class TemporalProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            Temporal annotation = element.getAnnotation(Temporal.class);
+            attribute.setTemporal(annotation.value());
+        }
+
+        @Override
+        void onEmbeddableAttribute(
+                JpaEmbeddableAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            Temporal annotation = element.getAnnotation(Temporal.class);
+            attribute.setTemporal(annotation.value());
+        }
+
+        @Override
+        void onId(JpaId id, AnnotatedElement element, AnnotationProcessorContext context) {
+            Temporal annotation = element.getAnnotation(Temporal.class);
+            id.setTemporal(annotation.value());
+        }
+    }
+
+    static final class TransientProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setTransient(true);
+        }
+    }
+
+    static final class VersionProcessor extends AbstractChildProcessor {
+
+        @Override
+        void onAttribute(
+                JpaAttribute attribute,
+                AnnotatedElement element,
+                AnnotationProcessorContext context) {
+            attribute.setVersion(true);
+        }
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/PersistenceDescriptorParser.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/PersistenceDescriptorParser.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/PersistenceDescriptorParser.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/PersistenceDescriptorParser.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,219 @@
+package org.objectstyle.cayenne.jpa.conf;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Properties;
+
+import javax.xml.XMLConstants;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.parsers.SAXParser;
+import javax.xml.parsers.SAXParserFactory;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+
+import org.objectstyle.cayenne.jpa.spi.JpaPersistenceProvider;
+import org.objectstyle.cayenne.jpa.spi.JpaPersistenceUnitInfo;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * A parser of persistence descriptor files. Can be used in serial processing of multiple
+ * documents.
+ * 
+ * @author Andrus Adamchik
+ */
+public class PersistenceDescriptorParser {
+
+    static final String PERSISTENCE_SCHEMA = "META-INF/schemas/persistence_1_0.xsd";
+
+    static final String PERSISTENCE = "persistence";
+    static final String PERSISTENCE_UNIT = "persistence-unit";
+    static final String DESCRIPTION = "description";
+    static final String NAME = "name";
+    static final String PROVIDER = "provider";
+    static final String TRANSACTION_TYPE = "transaction-type";
+    static final String JTA_DATASOURCE = "jta-data-source";
+    static final String NON_JTA_DATASOURCE = "non-jta-data-source";
+    static final String MAPPING_FILE = "mapping-file";
+    static final String JAR_FILE = "jar-file";
+    static final String CLASS = "class";
+    static final String EXCLUDE_UNLISTED_CLASSES = "exclude-unlisted-classes";
+    static final String PROPERTIES = "properties";
+    static final String PROPERTY = "property";
+    static final String VALUE = "value";
+
+    protected SAXParser parser;
+
+    public PersistenceDescriptorParser() throws SAXException,
+            ParserConfigurationException {
+        this(false);
+    }
+
+    public PersistenceDescriptorParser(boolean validatesAgainstSchema)
+            throws SAXException, ParserConfigurationException {
+
+        SAXParserFactory parserFactory = SAXParserFactory.newInstance();
+        parserFactory.setNamespaceAware(true);
+
+        // note that validation requires that persistence.xml declares a schema like this:
+        // <persistence xmlns="http://java.sun.com/xml/ns/persistence"
+        // xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+        // xsi:schemaLocation="http://java.sun.com/xml/ns/persistence
+        // http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
+
+        if (validatesAgainstSchema) {
+            URL schemaURL = Thread.currentThread().getContextClassLoader().getResource(
+                    PERSISTENCE_SCHEMA);
+
+            SchemaFactory factory = SchemaFactory
+                    .newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
+            StreamSource ss = new StreamSource(schemaURL.toExternalForm());
+            Schema schema = factory.newSchema(ss);
+            parserFactory.setSchema(schema);
+        }
+
+        this.parser = parserFactory.newSAXParser();
+    }
+
+    /**
+     * Factory method called during parsing that allows subclasses to customize unit info
+     * creation (as long as it is still JpaPersistenceUnitInfo).
+     */
+    protected JpaPersistenceUnitInfo newUnitInfo() {
+        return new JpaPersistenceUnitInfo();
+    }
+
+    /**
+     * Loads and returns a Collection of PersistenceUnitInfos from the XML descriptor.
+     */
+    public synchronized Collection<JpaPersistenceUnitInfo> getPersistenceUnits(
+            InputSource in,
+            final URL persistenceUnitRootUrl) throws SAXException, IOException {
+
+        final Collection<JpaPersistenceUnitInfo> unitInfos = new ArrayList<JpaPersistenceUnitInfo>(
+                2);
+
+        parser.reset();
+        parser.parse(in, new DefaultHandler() {
+
+            JpaPersistenceUnitInfo unit;
+            Properties properties;
+            StringBuilder charBuffer;
+
+            @Override
+            public void error(SAXParseException e) throws SAXException {
+                throw e;
+            }
+
+            @Override
+            public void startElement(
+                    String uri,
+                    String localName,
+                    String qName,
+                    Attributes attributes) throws SAXException {
+
+                if (PERSISTENCE_UNIT.equals(qName)) {
+                    String name = attributes.getValue("", NAME);
+                    String transactionType = attributes.getValue("", TRANSACTION_TYPE);
+
+                    unit = newUnitInfo();
+                    unit.setPersistenceUnitName(name);
+                    unit.setPersistenceUnitRootUrl(persistenceUnitRootUrl);
+
+                    if (transactionType != null) {
+                        unit.putProperty(
+                                JpaPersistenceProvider.TRANSACTION_TYPE_PROPERTY,
+                                transactionType);
+                    }
+                }
+                else if (PROPERTIES.equals(qName)) {
+                    properties = new Properties();
+                }
+                else if (PROPERTY.equals(qName)) {
+                    String name = attributes.getValue("", NAME);
+                    String value = attributes.getValue("", VALUE);
+                    properties.put(name, value);
+                }
+                else if (EXCLUDE_UNLISTED_CLASSES.equals(qName)) {
+                    unit.setExcludeUnlistedClasses(true);
+                }
+            }
+
+            @Override
+            public void endElement(String uri, String localName, String qName)
+                    throws SAXException {
+                if (PERSISTENCE_UNIT.equals(qName)) {
+                    unitInfos.add(unit);
+                }
+                else if (PROPERTIES.equals(qName)) {
+                    unit.addProperties(properties);
+                }
+                else {
+                    // process string values
+                    String string = resetCharBuffer();
+
+                    if (string != null) {
+                        if (CLASS.equals(qName)) {
+                            unit.addManagedClassName(string);
+                        }
+                        else if (PROVIDER.equals(qName)) {
+                            unit.putProperty(
+                                    JpaPersistenceProvider.PROVIDER_PROPERTY,
+                                    string);
+                        }
+                        else if (JAR_FILE.equals(qName)) {
+                            unit.addJarFileUrl(string);
+                        }
+                        else if (MAPPING_FILE.equals(qName)) {
+                            unit.addMappingFileName(string);
+                        }
+                        else if (JTA_DATASOURCE.equals(qName)) {
+                            unit.putProperty(
+                                    JpaPersistenceProvider.JTA_DATA_SOURCE_PROPERTY,
+                                    string);
+                        }
+                        else if (NON_JTA_DATASOURCE.equals(qName)) {
+                            unit.putProperty(
+                                    JpaPersistenceProvider.NON_JTA_DATA_SOURCE_PROPERTY,
+                                    string);
+                        }
+                        else if (DESCRIPTION.equals(qName)) {
+                            unit.setDescription(string);
+                        }
+                    }
+                }
+            }
+
+            @Override
+            public void characters(char[] ch, int start, int length) throws SAXException {
+                if (charBuffer == null) {
+                    charBuffer = new StringBuilder();
+                }
+
+                charBuffer.append(ch, start, length);
+            }
+
+            String resetCharBuffer() {
+                if (charBuffer == null) {
+                    return null;
+                }
+
+                String string = charBuffer.toString().trim();
+                if (string.length() == 0) {
+                    string = null;
+                }
+                charBuffer = null;
+
+                return string;
+            }
+
+        });
+        return unitInfos;
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/PersistenceUnitLoader.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/PersistenceUnitLoader.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/PersistenceUnitLoader.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/conf/PersistenceUnitLoader.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,75 @@
+package org.objectstyle.cayenne.jpa.conf;
+
+import java.net.URL;
+import java.util.Collection;
+import java.util.Enumeration;
+
+import org.objectstyle.cayenne.jpa.spi.JpaPersistenceUnitInfo;
+import org.xml.sax.InputSource;
+
+/**
+ * A class that locates persistent units in the environment and loads their definitions.
+ * 
+ * @author Andrus Adamchik
+ */
+public class PersistenceUnitLoader {
+
+    static final String DESCRIPTOR_LOCATION = "META-INF/persistence.xml";
+
+    protected PersistenceDescriptorParser parser;
+
+    public PersistenceUnitLoader(boolean validateDescriptors) {
+        try {
+            this.parser = new PersistenceDescriptorParser(validateDescriptors);
+        }
+        catch (Exception e) {
+            throw new RuntimeException("Error creating XML parser", e);
+        }
+    }
+
+    /**
+     * Loads PersistenceUnitInfo from standard locations. Returns null if no persistent
+     * unit with requested name is found.
+     * <p>
+     * <i>Implementation note: the loader performs no local caching of unit data. It will
+     * scan all available peristence unit descriptors every time this method is called.</i>
+     * </p>
+     */
+    public JpaPersistenceUnitInfo getInfo(String persistenceUnitName) {
+
+        if (persistenceUnitName == null) {
+            throw new IllegalArgumentException("Null persistenceUnitName");
+        }
+
+        // load descriptors
+        ClassLoader loader = Thread.currentThread().getContextClassLoader();
+        try {
+            Enumeration<URL> descriptors = loader.getResources(DESCRIPTOR_LOCATION);
+            while (descriptors.hasMoreElements()) {
+
+                String descriptorURL = descriptors.nextElement().toExternalForm();
+
+                // determine descriptor "root"
+
+                String descriptorRoot = descriptorURL.substring(0, descriptorURL.length()
+                        - DESCRIPTOR_LOCATION.length());
+
+                Collection<JpaPersistenceUnitInfo> units = parser.getPersistenceUnits(
+                        new InputSource(descriptorURL),
+                        new URL(descriptorRoot));
+
+                for (JpaPersistenceUnitInfo unit : units) {
+                    if (persistenceUnitName.equals(unit.getPersistenceUnitName())) {
+                        return unit;
+                    }
+                }
+            }
+        }
+        catch (Exception e) {
+            // throw on bad unit
+            throw new RuntimeException("Error loading persistence descriptors", e);
+        }
+
+        return null;
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaDataSourceFactory.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaDataSourceFactory.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaDataSourceFactory.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaDataSourceFactory.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,49 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.sql.DataSource;
+
+import org.objectstyle.cayenne.access.DataDomain;
+import org.objectstyle.cayenne.access.DataNode;
+import org.objectstyle.cayenne.conf.Configuration;
+import org.objectstyle.cayenne.jpa.spi.JpaDataSourceFactory;
+
+/**
+ * A {@link JpaDataSourceFactory} that returns a DataSource from the existing in Cayenne
+ * stack, matching JPA descriptor names against Cayenne names. It is assumed that there
+ * Configuration singleton is set. The name of the DataDomain is assumed to be equal to
+ * peristence unit name and the name of the DataSource - DataNode name.
+ * 
+ * @author Andrus Adamchik
+ */
+public class CjpaDataSourceFactory implements JpaDataSourceFactory {
+
+    public DataSource getJtaDataSource(String name, PersistenceUnitInfo info) {
+        return getDataSource(name, info);
+    }
+
+    public DataSource getNonJtaDataSource(String name, PersistenceUnitInfo info) {
+        return getDataSource(name, info);
+    }
+
+    protected DataSource getDataSource(String name, PersistenceUnitInfo info) {
+        if (name == null) {
+            return null;
+        }
+
+        Configuration config = Configuration.getSharedConfiguration();
+        DataDomain domain = config.getDomain(info.getPersistenceUnitName());
+
+        // try default domain
+        if (domain == null) {
+            domain = config.getDomain();
+        }
+
+        if (domain == null) {
+            return null;
+        }
+
+        DataNode node = domain.getNode(name);
+        return node != null ? node.getDataSource() : null;
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityManager.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityManager.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityManager.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityManager.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,94 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.PersistenceContextType;
+import javax.persistence.PersistenceException;
+import javax.persistence.Query;
+
+import org.objectstyle.cayenne.CayenneRuntimeException;
+import org.objectstyle.cayenne.DataObject;
+import org.objectstyle.cayenne.DataObjectUtils;
+import org.objectstyle.cayenne.Persistent;
+import org.objectstyle.cayenne.access.DataContext;
+import org.objectstyle.cayenne.jpa.JpaEntityManager;
+
+public class CjpaEntityManager extends JpaEntityManager {
+
+    private DataContext ctxt;
+
+    public CjpaEntityManager(EntityManagerFactory factory,
+            PersistenceContextType contextType) {
+        super(factory, contextType);
+
+        ctxt = DataContext.createDataContext();
+    }
+
+    @Override
+    protected void persistInternal(Object entity) {
+        checkEntityType(entity);
+        ctxt.registerNewObject((DataObject) entity);
+    }
+
+    @Override
+    protected <T> T mergeInternal(T entity) {
+        checkEntityType(entity);
+        Persistent dao = (Persistent) entity;
+        return (T) ctxt.localObject(dao.getObjectId(), dao);
+    }
+
+    @Override
+    protected void removeInternal(Object entity) {
+        checkEntityType(entity);
+        ctxt.deleteObject((Persistent) entity);
+    }
+
+    @Override
+    protected <T> T findInternal(Class<T> entityClass, Object primaryKey) {
+        return (T) DataObjectUtils.objectForPK(ctxt, entityClass, primaryKey);
+    }
+
+    @Override
+    protected void flushInternal() {
+        try {
+            ctxt.commitChanges();
+        }
+        catch (CayenneRuntimeException e) {
+            throw new PersistenceException(e);
+        }
+    }
+
+    @Override
+    protected void refreshInternal(Object entity) {
+        // TODO: Andrus, 2/10/2006 - implement
+        throw new UnsupportedOperationException("TODO");
+    }
+
+    @Override
+    protected boolean containsInternal(Object entity) {
+        checkEntityType(entity);
+
+        Persistent p = (Persistent) entity;
+        return p.getObjectContext() == ctxt;
+    }
+    
+    @Override
+    public Query createNamedQuery(String name) {
+        checkClosed();
+
+        return new CjpaQuery(ctxt, name);
+    }
+    
+    @Override
+    public Query createNativeQuery(String sqlString, Class resultClass) {
+        checkClosed();
+        checkEntityType(resultClass);
+        
+        return new CjpaNativeQuery(ctxt, sqlString, resultClass);
+    }
+
+    protected void checkEntityType(Object entity) throws IllegalArgumentException {
+        if (!(entity instanceof Persistent)) {
+            throw new IllegalArgumentException("entity must be Persistent");
+        }
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityManagerFactory.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityManagerFactory.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityManagerFactory.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityManagerFactory.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,29 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import javax.persistence.EntityManager;
+import javax.persistence.PersistenceContextType;
+import javax.persistence.spi.PersistenceUnitInfo;
+
+import org.objectstyle.cayenne.jpa.JpaEntityManagerFactory;
+
+/**
+ * A default EntityManagerFactory used by Cayenne JPA provider.
+ * <h3>Cayenne Compatibility Note</h3>
+ * <p>
+ * CjpaEntityManagerFactory wraps a special Cayenne Configuration object that can load
+ * both JPA and regular Cayenne mappings.
+ * </p>
+ * 
+ * @author Andrus Adamchik
+ */
+public class CjpaEntityManagerFactory extends JpaEntityManagerFactory {
+
+    public CjpaEntityManagerFactory(PersistenceUnitInfo unitInfo) {
+        super(unitInfo);
+    }
+
+    @Override
+    protected EntityManager createEntityManagerInternal(PersistenceContextType type) {
+        return new CjpaEntityManager(this, type);
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityTransaction.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityTransaction.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityTransaction.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaEntityTransaction.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,93 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import java.sql.SQLException;
+
+import javax.persistence.EntityTransaction;
+import javax.persistence.PersistenceException;
+
+import org.objectstyle.cayenne.CayenneException;
+import org.objectstyle.cayenne.access.Transaction;
+
+/**
+ * A JPA wrapper around a cayenne Transaction
+ * 
+ * @see http://objectstyle.org/confluence/display/CAYDOC/Understanding+Transactions
+ */
+public class CjpaEntityTransaction implements EntityTransaction {
+
+    private Transaction transaction;
+
+    public CjpaEntityTransaction(Transaction transaction) {
+        this.transaction = transaction;
+    }
+
+    /**
+     * Start a resource transaction.
+     * 
+     * @throws IllegalStateException
+     *             if isActive() is true.
+     */
+    public void begin() {
+        if (isActive()) {
+            throw new IllegalStateException("transaction active");
+        }
+
+        transaction.begin();
+    }
+
+    /**
+     * Commit the current transaction, writing any unflushed changes to the
+     * database.
+     * 
+     * @throws IllegalStateException
+     *             if isActive() is false.
+     * @throws PersistenceException
+     *             if the commit fails.
+     */
+    public void commit() {
+        if (!isActive()) {
+            throw new IllegalStateException("transaction not active");
+        }
+
+        try {
+            transaction.commit();
+        } catch (SQLException e) {
+            throw new PersistenceException(e.getMessage(), e);
+        } catch (CayenneException e) {
+            throw new PersistenceException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Roll back the current transaction.
+     * 
+     * @throws IllegalStateException
+     *             if isActive() is false.
+     * @throws PersistenceException
+     *             if an unexpected error condition is encountered.
+     */
+    public void rollback() {
+        if (!isActive()) {
+            throw new IllegalStateException("transaction not active");
+        }
+
+        try {
+            transaction.rollback();
+        } catch (SQLException e) {
+            throw new PersistenceException(e.getMessage(), e);
+        } catch (CayenneException e) {
+            throw new PersistenceException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * Indicate whether a transaction is in progress.
+     * 
+     * @throws PersistenceException
+     *             if an unexpected error condition is encountered.
+     */
+    public boolean isActive() {
+        return (transaction.getStatus() == Transaction.STATUS_ACTIVE);
+    }
+
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaNativeQuery.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaNativeQuery.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaNativeQuery.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaNativeQuery.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,54 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import javax.persistence.Query;
+
+import org.objectstyle.cayenne.access.DataContext;
+import org.objectstyle.cayenne.query.SQLTemplate;
+
+public class CjpaNativeQuery extends CjpaQuery {
+
+    private static final String POSITIONAL_PARAM_PREFIX = "positional_";
+
+    public CjpaNativeQuery(DataContext ctxt, String sqlString, Class resultClass) {
+        super(ctxt);
+        // named parameters are like ":parametername" and positional parameters
+        // are like "?123". SQLTemplate support "$parametername"
+
+        // TODO: improve convert as ':' could be used in sql. e.x. in
+        // non-parametrized parameter or postgresql cast.
+
+        sqlString = sqlString.replace(':', '$');
+
+        // handle positional parameters like named
+        if (sqlString.indexOf('?') >= 0) {
+            // convert "?123" to "$positional_123"
+            sqlString = sqlString.replaceAll("\\?([0-9]+)", "\\$" + POSITIONAL_PARAM_PREFIX + "$1");
+        }
+
+        setQuery(new SQLTemplate(resultClass, sqlString));
+    }
+
+
+    /**
+     * Bind an argument to a positional parameter.
+     * 
+     * @param position
+     * @param value
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if position does not correspond to positional parameter of
+     *             query or argument is of incorrect type
+     */
+    public Query setParameter(int position, Object value) {
+
+        // Positional parameters are designated by the question
+        // mark(?) prefix followed by an integer. For example: ?1.
+        String name = POSITIONAL_PARAM_PREFIX + Integer.toString(position);
+        try {
+            return setParameter(name, value);
+        } catch (IllegalArgumentException e) {
+            throw new IllegalArgumentException("Invalid positional parameter: " + position, e);
+        }
+    }
+    
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaPersistenceProvider.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaPersistenceProvider.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaPersistenceProvider.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaPersistenceProvider.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,43 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.spi.PersistenceUnitInfo;
+import javax.persistence.spi.PersistenceUnitTransactionType;
+
+import org.objectstyle.cayenne.jpa.spi.JpaPersistenceProvider;
+
+/**
+ * A PersistenceProvider implementation based on Cayenne stack.
+ * 
+ * @author Andrus Adamchik
+ */
+public class CjpaPersistenceProvider extends JpaPersistenceProvider {
+
+    /**
+     * Creates a new PersistenceProvider with properties configured to run in a standalone
+     * mode with Cayenne stack.
+     */
+    public CjpaPersistenceProvider() {
+        this(false);
+    }
+
+    public CjpaPersistenceProvider(boolean validateDescriptors) {
+        super(validateDescriptors);
+
+        // override default properties
+        defaultProperties.put(DATA_SOURCE_FACTORY_PROPERTY, CjpaDataSourceFactory.class
+                .getName());
+        defaultProperties.put(
+                TRANSACTION_TYPE_PROPERTY,
+                PersistenceUnitTransactionType.RESOURCE_LOCAL.name());
+    }
+
+    /**
+     * Registers Cayenne-specific ClassTransformers with PersistenceUnitInfo and returns
+     * {@link CjpaEntityManagerFactory}.
+     */
+    @Override
+    public EntityManagerFactory createContainerManagerFactory(PersistenceUnitInfo info) {
+        return new CjpaEntityManagerFactory(info);
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaQuery.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaQuery.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaQuery.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/CjpaQuery.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,285 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.persistence.NoResultException;
+import javax.persistence.NonUniqueResultException;
+import javax.persistence.Query;
+import javax.persistence.TemporalType;
+import javax.persistence.TransactionRequiredException;
+
+import org.objectstyle.cayenne.access.DataContext;
+import org.objectstyle.cayenne.query.ParameterizedQuery;
+import org.objectstyle.cayenne.query.ProcedureQuery;
+import org.objectstyle.cayenne.query.SQLTemplate;
+import org.objectstyle.cayenne.query.SelectQuery;
+
+/**
+ * A jpa Query that wraps a Cayenne Query.
+ */
+public class CjpaQuery implements Query {
+
+    protected Map<String, Object> parameters = new HashMap<String, Object>();
+
+    protected org.objectstyle.cayenne.query.Query cquery;
+
+    protected DataContext ctxt;
+
+    public CjpaQuery(DataContext ctxt) {
+        this.ctxt = ctxt;
+    }
+
+    /**
+     * Construct a named query. Will throw
+     * 
+     * @param ctxt
+     * @param name
+     */
+    public CjpaQuery(DataContext ctxt, String name) {
+        this(ctxt);
+
+        org.objectstyle.cayenne.query.Query q = ctxt.getEntityResolver().lookupQuery(name);
+
+        if (q == null) {
+            throw new IllegalArgumentException("Non-existing query: " + name);
+        }
+
+        setQuery(q);
+    }
+
+    protected void setQuery(org.objectstyle.cayenne.query.Query q) {
+        this.cquery = q;
+    }
+
+    protected org.objectstyle.cayenne.query.Query getQuery() {
+        return cquery;
+    }
+
+    /**
+     * Return the same query with parameters set.
+     */
+    private org.objectstyle.cayenne.query.Query queryWithParameters() {
+        if (parameters.size() == 0) {
+            return cquery;
+        }
+
+        return ((ParameterizedQuery) cquery).createQuery(parameters);
+    }
+
+    /**
+     * Execute a SELECT query and return the query results as a List.
+     * 
+     * @return a list of the results
+     * @throws IllegalStateException
+     *             if called for an EJB QL UPDATE or DELETE statement
+     */
+    public List getResultList() {
+        return ctxt.performQuery(queryWithParameters());
+    }
+
+    /**
+     * Execute an update or delete statement.
+     * 
+     * @return the number of entities updated or deleted
+     * @throws IllegalStateException
+     *             if called for an EJB QL SELECT statement
+     * @throws TransactionRequiredException
+     *             if there is no transaction
+     */
+    public int executeUpdate() {
+        // TODO: check transaction
+        int[] res = ctxt.performNonSelectingQuery(queryWithParameters());
+        int num = 0;
+        for (int i = 0; i < res.length; i++) {
+            num = num + res[i];
+        }
+        return num;
+    }
+
+    /**
+     * Execute a SELECT query that returns a single result.
+     * 
+     * @return the result
+     * @throws NoResultException
+     *             if there is no result
+     * @throws NonUniqueResultException
+     *             if more than one result
+     * @throws IllegalStateException
+     *             if called for an EJB QL UPDATE or DELETE statement
+     */
+    public Object getSingleResult() {
+        List rows = getResultList();
+        if (rows.size() == 0) {
+            throw new NoResultException();
+        }
+        if (rows.size() > 1) {
+            throw new NonUniqueResultException();
+        }
+
+        return rows.get(0);
+    }
+
+    /**
+     * Set the maximum number of results to retrieve.
+     * 
+     * @param maxResult
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if argument is negative
+     */
+    public Query setMaxResults(int maxResult) {
+        if (maxResult < 0) {
+            throw new IllegalArgumentException("Invalid max results value: " + maxResult);
+        }
+
+        // TODO: use QueryMetadata?
+        if (getQuery() instanceof SelectQuery) {
+            ((SelectQuery) getQuery()).setFetchLimit(maxResult);
+        } else if (getQuery() instanceof SQLTemplate) {
+            ((SQLTemplate) getQuery()).setFetchLimit(maxResult);
+        } else if (getQuery() instanceof ProcedureQuery) {
+            ((ProcedureQuery) getQuery()).setFetchLimit(maxResult);
+        }
+
+        throw new IllegalArgumentException("query does not support maxResult");
+    }
+
+    /**
+     * Set an implementation-specific hint. If the hint name is not recognized,
+     * it is silently ignored.
+     * 
+     * @param hintName
+     * @param value
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if the second argument is not valid for the implementation
+     */
+    public Query setHint(String hintName, Object value) {
+        return this;
+    }
+
+    /**
+     * Set the position of the first result to retrieve.
+     * 
+     * @param start
+     *            position of the first result, numbered from 0
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if argument is negative
+     */
+    public Query setFirstResult(int startPosition) {
+        if (startPosition < 0) {
+            throw new IllegalArgumentException("Invalid first result value: " + startPosition);
+        }
+        // TODO: support in core like fetchLimit?
+        // TODO: hack a temp solution here based on sub-list?
+        throw new UnsupportedOperationException("TODO");
+    }
+
+    /**
+     * Bind an argument to a named parameter.
+     * 
+     * @param name
+     *            the parameter name
+     * @param value
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if parameter name does not correspond to parameter in query
+     *             string or argument is of incorrect type
+     */
+    public Query setParameter(String name, Object value) {
+        if (!(cquery instanceof ParameterizedQuery)) {
+            throw new IllegalArgumentException("query does not accept parameters");
+        }
+
+        // TODO: check for valid parameter. should probably be built in to
+        // all ParameterizedQuerys
+
+        parameters.put(name, value);
+        return this;
+    }
+
+    /**
+     * Bind an instance of java.util.Date to a named parameter.
+     * 
+     * @param name
+     * @param value
+     * @param temporalType
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if parameter name does not correspond to parameter in query
+     *             string
+     */
+    public Query setParameter(String name, Date value, TemporalType temporalType) {
+        // handled by cayenne.
+        return setParameter(name, value);
+    }
+
+    /**
+     * Bind an instance of java.util.Calendar to a named parameter.
+     * 
+     * @param name
+     * @param value
+     * @param temporalType
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if parameter name does not correspond to parameter in query
+     *             string
+     */
+    public Query setParameter(String name, Calendar value, TemporalType temporalType) {
+        // handled by cayenne.
+        return setParameter(name, value);
+    }
+
+    /**
+     * Bind an argument to a positional parameter.
+     * 
+     * @param position
+     * @param value
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if position does not correspond to positional parameter of
+     *             query or argument is of incorrect type
+     */
+    public Query setParameter(int position, Object value) {
+        // TODO: implement
+        throw new UnsupportedOperationException("TODO");
+    }
+
+    /**
+     * Bind an instance of java.util.Date to a positional parameter.
+     * 
+     * @param position
+     * @param value
+     * @param temporalType
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if position does not correspond to positional parameter of
+     *             query
+     */
+    public Query setParameter(int position, Date value, TemporalType temporalType) {
+        // handled by cayenne.
+        return setParameter(position, value);
+    }
+
+    /**
+     * Bind an instance of java.util.Calendar to a positional parameter.
+     * 
+     * @param position
+     * @param value
+     * @param temporalType
+     * @return the same query instance
+     * @throws IllegalArgumentException
+     *             if position does not correspond to positional parameter of
+     *             query
+     */
+    public Query setParameter(int position, Calendar value, TemporalType temporalType) {
+        // handled by cayenne.
+        return setParameter(position, value);
+    }
+
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/PersistentEnhancementVisitor.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/PersistentEnhancementVisitor.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/PersistentEnhancementVisitor.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/PersistentEnhancementVisitor.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,135 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import static org.objectweb.asm.Opcodes.ACC_PROTECTED;
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_TRANSIENT;
+import static org.objectweb.asm.Opcodes.ALOAD;
+import static org.objectweb.asm.Opcodes.ARETURN;
+import static org.objectweb.asm.Opcodes.GETFIELD;
+import static org.objectweb.asm.Opcodes.ILOAD;
+import static org.objectweb.asm.Opcodes.IRETURN;
+import static org.objectweb.asm.Opcodes.PUTFIELD;
+import static org.objectweb.asm.Opcodes.RETURN;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.objectstyle.cayenne.Persistent;
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * An ASM enhancer that adds Persistent interface enhancements to an arbitrary Java class.
+ * 
+ * @author Andrus Adamchik
+ */
+class PersistentEnhancementVisitor extends ClassAdapter {
+
+    static final String PERSISTENT_INTERFACE = Persistent.class.getName().replace(
+            '.',
+            '/');
+
+    public PersistentEnhancementVisitor(ClassVisitor cv) {
+        super(cv);
+    }
+
+    @Override
+    public void visit(
+            int version,
+            int access,
+            String name,
+            String signature,
+            String superName,
+            String[] interfaces) {
+
+        System.out.println("Enhancing class: " + name);
+
+        if (!ArrayUtils.contains(interfaces, PERSISTENT_INTERFACE)) {
+            interfaces = (String[]) ArrayUtils.add(interfaces, PERSISTENT_INTERFACE);
+        }
+
+        super.visit(version, access, name, signature, superName, interfaces);
+
+        FieldVisitor fv;
+        MethodVisitor mv;
+
+        {
+            fv = cv.visitField(
+                    ACC_PROTECTED,
+                    "__objectId",
+                    "Lorg/objectstyle/cayenne/ObjectId;",
+                    null,
+                    null);
+            fv.visitEnd();
+        }
+
+        {
+            fv = cv.visitField(
+                    ACC_PROTECTED + ACC_TRANSIENT,
+                    "__persistenceState",
+                    "I",
+                    null,
+                    null);
+            fv.visitEnd();
+        }
+
+        {
+            mv = cv.visitMethod(ACC_PUBLIC, "getPersistenceState", "()I", null, null);
+            mv.visitCode();
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitFieldInsn(GETFIELD, name, "__persistenceState", "I");
+            mv.visitInsn(IRETURN);
+            mv.visitMaxs(1, 1);
+            mv.visitEnd();
+        }
+
+        {
+            mv = cv.visitMethod(ACC_PUBLIC, "setPersistenceState", "(I)V", null, null);
+            mv.visitCode();
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitVarInsn(ILOAD, 1);
+            mv.visitFieldInsn(PUTFIELD, name, "__persistenceState", "I");
+            mv.visitInsn(RETURN);
+            mv.visitMaxs(2, 2);
+            mv.visitEnd();
+        }
+
+        {
+            mv = cv.visitMethod(
+                    ACC_PUBLIC,
+                    "getObjectId",
+                    "()Lorg/objectstyle/cayenne/ObjectId;",
+                    null,
+                    null);
+            mv.visitCode();
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitFieldInsn(
+                    GETFIELD,
+                    name,
+                    "__objectId",
+                    "Lorg/objectstyle/cayenne/ObjectId;");
+            mv.visitInsn(ARETURN);
+            mv.visitMaxs(1, 1);
+            mv.visitEnd();
+        }
+        {
+            mv = cv.visitMethod(
+                    ACC_PUBLIC,
+                    "setObjectId",
+                    "(Lorg/objectstyle/cayenne/ObjectId;)V",
+                    null,
+                    null);
+            mv.visitCode();
+            mv.visitVarInsn(ALOAD, 0);
+            mv.visitVarInsn(ALOAD, 1);
+            mv.visitFieldInsn(
+                    PUTFIELD,
+                    name,
+                    "__objectId",
+                    "Lorg/objectstyle/cayenne/ObjectId;");
+            mv.visitInsn(RETURN);
+            mv.visitMaxs(2, 2);
+            mv.visitEnd();
+        }
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/PersistentEnhancer.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/PersistentEnhancer.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/PersistentEnhancer.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/cspi/PersistentEnhancer.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,56 @@
+package org.objectstyle.cayenne.jpa.cspi;
+
+import java.lang.instrument.IllegalClassFormatException;
+import java.security.ProtectionDomain;
+
+import javax.persistence.spi.ClassTransformer;
+
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.util.CheckClassAdapter;
+
+/**
+ * A JPA ClassTransformer implementation that enahnces POJOs to comply with Persistent
+ * interface and accessor conventions.
+ * 
+ * @author Andrus Adamchik
+ */
+public class PersistentEnhancer implements ClassTransformer {
+
+    /**
+     * Invoked when a class is being loaded or redefined. The implementation of this
+     * method may transform the supplied class file and return a new replacement class
+     * file.
+     * 
+     * @param loader The defining loader of the class to be transformed, may be null if
+     *            the bootstrap loader
+     * @param className The name of the class in the internal form of fully qualified
+     *            class and interface names
+     * @param classBeingRedefined If this is a redefine, the class being redefined,
+     *            otherwise null
+     * @param protectionDomain The protection domain of the class being defined or
+     *            redefined
+     * @param classfileBuffer The input byte buffer in class file format - must not be
+     *            modified
+     * @return A well-formed class file buffer (the result of the transform), or null if
+     *         no transform is performed
+     * @throws IllegalClassFormatException If the input does not represent a well-formed
+     *             class file
+     */
+    public byte[] transform(
+            ClassLoader classLoader,
+            String className,
+            Class<?> classBeingRedefined,
+            ProtectionDomain protectionDomain,
+            byte[] classfileBuffer) throws IllegalClassFormatException {
+
+        ClassWriter cw = new ClassWriter(false);
+        ClassVisitor cc = new CheckClassAdapter(cw);
+        ClassVisitor pv = new PersistentEnhancementVisitor(cc);
+
+        ClassReader cr = new ClassReader(classfileBuffer);
+        cr.accept(pv, false);
+        return cw.toByteArray();
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/AccessType.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/AccessType.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/AccessType.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/AccessType.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,7 @@
+package org.objectstyle.cayenne.jpa.map;
+
+// TODO: andrus, 4/17/2006 - should that be a part of jpa.jar?? it is not
+// mentioned in the spec anywhere, but inside the orm_1_0.xsd
+public enum AccessType {
+	PROPERTY, FIELD
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/EnumList.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/EnumList.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/EnumList.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/EnumList.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,118 @@
+/* ====================================================================
+ * 
+ * The ObjectStyle Group Software License, version 1.1
+ * ObjectStyle Group - http://objectstyle.org/
+ * 
+ * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
+ * of the software. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 
+ * 3. The end-user documentation included with the redistribution, if any,
+ *    must include the following acknowlegement:
+ *    "This product includes software developed by independent contributors
+ *    and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ * 
+ * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
+ *    or promote products derived from this software without prior written
+ *    permission. For written permission, email
+ *    "andrus at objectstyle dot org".
+ * 
+ * 5. Products derived from this software may not be called "ObjectStyle"
+ *    or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
+ *    names without prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ * 
+ * This software consists of voluntary contributions made by many
+ * individuals and hosted on ObjectStyle Group web site.  For more
+ * information on the ObjectStyle Group, please see
+ * <http://objectstyle.org/>.
+ */
+package org.objectstyle.cayenne.jpa.map;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * A list that converts added objects to the specified enum type.
+ * 
+ * @author Andrus Adamchik
+ */
+// TODO: andrus, 4/20/2006 - remove this class, replacing it with parameterized
+// collections once CAY-520 gets implemented in Cayenne > 1.2
+class EnumList extends ArrayList {
+
+    private Class enumClass;
+
+    EnumList(Class enumClass, int capacity) {
+        super(capacity);
+        this.enumClass = enumClass;
+    }
+
+    private Object convertValue(Object value) {
+        if (value instanceof String) {
+            value = Enum.valueOf(enumClass, value.toString());
+        }
+
+        return value;
+    }
+    
+    private Collection convertValues(Collection values) {
+        if(values != null && !values.isEmpty()) {
+            Collection converted = new ArrayList(values.size());
+            for(Object value : values) {
+                converted.add(convertValue(value));
+            }
+            
+            return converted;
+        }
+        else {
+            return values;
+        }
+    }
+
+    @Override
+    public void add(int index, Object element) {
+        super.add(index, convertValue(element));
+    }
+
+    @Override
+    public boolean add(Object o) {
+        return super.add(convertValue(o));
+    }
+
+    @Override
+    public boolean addAll(Collection c) {
+        return super.addAll(convertValues(c));
+    }
+
+    @Override
+    public boolean addAll(int index, Collection c) {
+        return super.addAll(index, convertValues(c));
+    }
+}

Added: incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/JpaAbstractEntity.java
URL: http://svn.apache.org/viewcvs/incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/JpaAbstractEntity.java?rev=396882&view=auto
==============================================================================
--- incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/JpaAbstractEntity.java (added)
+++ incubator/cayenne/trunk/cayenne-jpa/src/main/java/org/objectstyle/cayenne/jpa/map/JpaAbstractEntity.java Tue Apr 25 06:43:00 2006
@@ -0,0 +1,231 @@
+/* ====================================================================
+ * 
+ * The ObjectStyle Group Software License, version 1.1
+ * ObjectStyle Group - http://objectstyle.org/
+ * 
+ * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
+ * of the software. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 
+ * 3. The end-user documentation included with the redistribution, if any,
+ *    must include the following acknowlegement:
+ *    "This product includes software developed by independent contributors
+ *    and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
+ *    Alternately, this acknowlegement may appear in the software itself,
+ *    if and wherever such third-party acknowlegements normally appear.
+ * 
+ * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
+ *    or promote products derived from this software without prior written
+ *    permission. For written permission, email
+ *    "andrus at objectstyle dot org".
+ * 
+ * 5. Products derived from this software may not be called "ObjectStyle"
+ *    or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
+ *    names without prior written permission.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ * 
+ * This software consists of voluntary contributions made by many
+ * individuals and hosted on ObjectStyle Group web site.  For more
+ * information on the ObjectStyle Group, please see
+ * <http://objectstyle.org/>.
+ */
+package org.objectstyle.cayenne.jpa.map;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+import org.objectstyle.cayenne.util.TraversableTreeNode;
+
+public abstract class JpaAbstractEntity implements TraversableTreeNode {
+
+    static final Class[] TRAVERSABLE_CHILDREN = new Class[] {
+            JpaAttribute.class, JpaEmbeddedId.class, JpaId.class
+    };
+
+    protected String className;
+    protected AccessType access;
+
+    protected String idClassName;
+    protected boolean excludeDefaultListeners;
+    protected boolean excludeSuperclassListeners;
+    protected JpaEntityListeners entityListeners;
+    protected JpaLifecycleCallback prePersist;
+    protected JpaLifecycleCallback postPersist;
+    protected JpaLifecycleCallback preRemove;
+    protected JpaLifecycleCallback postRemove;
+    protected JpaLifecycleCallback preUpdate;
+    protected JpaLifecycleCallback postUpdate;
+    protected JpaLifecycleCallback postLoad;
+    protected JpaEmbeddedId embeddedId;
+    protected Collection<JpaId> ids;
+    protected Collection<JpaAttribute> attributes;
+
+    public Class[] getTraversableChildTypes() {
+        return JpaAbstractEntity.TRAVERSABLE_CHILDREN;
+    }
+
+    public Object getTraversableChild(int nodeTypeIndex) {
+        switch (nodeTypeIndex) {
+            case 0:
+                return attributes;
+            case 1:
+                return embeddedId;
+            case 2:
+                return ids;
+            default:
+                throw new ArrayIndexOutOfBoundsException(nodeTypeIndex);
+        }
+    }
+
+    public JpaEmbeddedId getEmbeddedId() {
+        return embeddedId;
+    }
+
+    public void setEmbeddedId(JpaEmbeddedId embeddedId) {
+        this.embeddedId = embeddedId;
+    }
+
+    public JpaEntityListeners getEntityListeners() {
+        return entityListeners;
+    }
+
+    public void setEntityListeners(JpaEntityListeners entityListeners) {
+        this.entityListeners = entityListeners;
+    }
+
+    public boolean isExcludeDefaultListeners() {
+        return excludeDefaultListeners;
+    }
+
+    public void setExcludeDefaultListeners(boolean excludeDefaultListeners) {
+        this.excludeDefaultListeners = excludeDefaultListeners;
+    }
+
+    public boolean isExcludeSuperclassListeners() {
+        return excludeSuperclassListeners;
+    }
+
+    public void setExcludeSuperclassListeners(boolean excludeSuperclassListeners) {
+        this.excludeSuperclassListeners = excludeSuperclassListeners;
+    }
+
+    public String getIdClassName() {
+        return idClassName;
+    }
+
+    public void setIdClassName(String idClassName) {
+        this.idClassName = idClassName;
+    }
+
+    public JpaLifecycleCallback getPostLoad() {
+        return postLoad;
+    }
+
+    public void setPostLoad(JpaLifecycleCallback postLoad) {
+        this.postLoad = postLoad;
+    }
+
+    public JpaLifecycleCallback getPostPersist() {
+        return postPersist;
+    }
+
+    public void setPostPersist(JpaLifecycleCallback postPersist) {
+        this.postPersist = postPersist;
+    }
+
+    public JpaLifecycleCallback getPostRemove() {
+        return postRemove;
+    }
+
+    public void setPostRemove(JpaLifecycleCallback postRemove) {
+        this.postRemove = postRemove;
+    }
+
+    public JpaLifecycleCallback getPostUpdate() {
+        return postUpdate;
+    }
+
+    public void setPostUpdate(JpaLifecycleCallback postUpdate) {
+        this.postUpdate = postUpdate;
+    }
+
+    public JpaLifecycleCallback getPrePersist() {
+        return prePersist;
+    }
+
+    public void setPrePersist(JpaLifecycleCallback prePersist) {
+        this.prePersist = prePersist;
+    }
+
+    public JpaLifecycleCallback getPreRemove() {
+        return preRemove;
+    }
+
+    public void setPreRemove(JpaLifecycleCallback preRemove) {
+        this.preRemove = preRemove;
+    }
+
+    public JpaLifecycleCallback getPreUpdate() {
+        return preUpdate;
+    }
+
+    public void setPreUpdate(JpaLifecycleCallback preUpdate) {
+        this.preUpdate = preUpdate;
+    }
+
+    public Collection<JpaId> getIds() {
+        if (ids == null) {
+            ids = new ArrayList<JpaId>();
+        }
+
+        return ids;
+    }
+
+    public Collection<JpaAttribute> getAttributes() {
+        if (attributes == null) {
+            attributes = new ArrayList<JpaAttribute>();
+        }
+
+        return attributes;
+    }
+
+    public AccessType getAccess() {
+        return access;
+    }
+
+    public void setAccess(AccessType access) {
+        this.access = access;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+
+    public void setClassName(String className) {
+        this.className = className;
+    }
+}