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;
+ }
+}