You are viewing a plain text version of this content. The canonical link for it is here.
Posted to ojb-dev@db.apache.org by th...@apache.org on 2002/11/30 18:34:29 UTC
cvs commit: jakarta-ojb/src/java/org/apache/ojb/broker/metadata ClassDescriptor.java
thma 2002/11/30 09:34:29
Modified: src/java/org/apache/ojb/broker/metadata ClassDescriptor.java
Log:
add accept locks attribute to class-descriptor
Revision Changes Path
1.42 +1731 -1702jakarta-ojb/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java
Index: ClassDescriptor.java
===================================================================
RCS file: /home/cvs/jakarta-ojb/src/java/org/apache/ojb/broker/metadata/ClassDescriptor.java,v
retrieving revision 1.41
retrieving revision 1.42
diff -u -r1.41 -r1.42
--- ClassDescriptor.java 21 Nov 2002 22:56:11 -0000 1.41
+++ ClassDescriptor.java 30 Nov 2002 17:34:28 -0000 1.42
@@ -1,1702 +1,1731 @@
-package org.apache.ojb.broker.metadata;
-
-/* ====================================================================
- * The Apache Software License, Version 1.1
- *
- * Copyright (c) 2001 The Apache Software Foundation. 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 acknowledgment:
- * "This product includes software developed by the
- * Apache Software Foundation (http://www.apache.org/)."
- * Alternately, this acknowledgment may appear in the software itself,
- * if and wherever such third-party acknowledgments normally appear.
- *
- * 4. The names "Apache" and "Apache Software Foundation" and
- * "Apache ObjectRelationalBridge" must not be used to endorse or promote products
- * derived from this software without prior written permission. For
- * written permission, please contact apache@apache.org.
- *
- * 5. Products derived from this software may not be called "Apache",
- * "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
- * prior written permission of the Apache Software Foundation.
- *
- * 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 APACHE SOFTWARE FOUNDATION 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 on behalf of the Apache Software Foundation. For more
- * information on the Apache Software Foundation, please see
- * <http://www.apache.org/>.
- */
-
-import org.apache.ojb.broker.OJBRuntimeException;
-import org.apache.ojb.broker.PersistenceBroker;
-import org.apache.ojb.broker.PersistenceBrokerException;
-import org.apache.ojb.broker.PersistenceBrokerFactory;
-import org.apache.ojb.broker.accesslayer.RowReader;
-import org.apache.ojb.broker.accesslayer.RowReaderDefaultImpl;
-import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
-import org.apache.ojb.broker.util.logging.LoggerFactory;
-
-import java.io.Serializable;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.Modifier;
-import java.sql.Timestamp;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Vector;
-
-//#ifdef JDK13
-import java.lang.reflect.Proxy;
-//#else
-/*
-import com.develop.java.lang.reflect.Proxy;
-*/
-//#endif
-
-/**
- * A ClassDescriptor contains all information for mapping objects of a
- * given class to database tables.
- *
- * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
- * @version $Id$
- */
-public class ClassDescriptor extends DescriptorBase implements Serializable, XmlCapable, IsolationLevels
-{
-
- public static final String OJB_CONCRETE_CLASS = "ojbConcreteClass";
-
- private transient DescriptorRepository m_repository;
-
- /**
- * transaction isolation level specified for this class, used in the ODMG server
- */
- private int m_IsolationLevel = IsolationLevels.IL_READ_UNCOMMITTED;
-
- /**
- * the SQL SCHEMA of the underlying table of this class
- */
- private String schema = null;
-
- /**
- * the described class
- */
- private Class m_Class = null;
-
- /**
- * the name of the described class
- */
- private String classname = null;
-
-
- /**
- * the table name used to store the scalar attributes of this class
- */
- private String m_TableName = null;
-
- /**
- * the FieldDescriptors for the primitive attributes
- */
- private FieldDescriptor[] m_FieldDescriptions = null;
-
- /**
- * the descriptors for collection attributes
- */
- private Vector m_CollectionDescriptors = new Vector();
-
- /**
- * the descriptor for 1-1 reference attributes
- */
- private Vector m_ObjectReferenceDescriptors = new Vector();
-
- /**
- * the vector of indices used in DDL generation.
- */
- private Vector indexes = new Vector();
-
- /**
- * the JDBCConnectionDescriptor describing the RDBMS connection to be used for this class
- */
- private JdbcConnectionDescriptor m_ConnDescription = null;
-
- /**
- * the non-primary key FieldDescriptors
- */
- private FieldDescriptor[] nonPrimaryKeyFieldDescriptors = null;
-
- /**
- * the primary key FieldDescriptors
- */
- private FieldDescriptor[] primaryKeyFieldDescriptors = null;
-
- /**
- * the optimistic lockingFieldDescriptors BRJ
- */
- private FieldDescriptor[] lockingFieldDescriptors = null;
-
- /**
- * the RowReader for this class
- */
- private RowReader rowReader = null;
-
- /**
- * the RowReader class name for this class
- */
- private String rowReaderClassName = null;
-
- /**
- * tells whether we tried to lookup multiargs Constructor already
- */
- private boolean alreadyLookedup = false;
-
- /**
- * the types of the arguments for the attributes in m_FieldDescriptions
- */
- private Class[] argsForConstructor = null;
-
- /**
- * the list of classes in the extent of this class. can be empty
- */
- private Vector extentClasses = new Vector();
-
- /**
- * the list of class names in the extent of this class. can be empty
- */
- private Vector extentClassNames = new Vector();
-
- /**
- * the class that this class extends
- */
- private String superClass;
- /**
- * reference column for the superclass
- */
- private int superClassFieldRef;
-
- /**
- * does the described class represent an interface?
- */
- private boolean isInterface = false;
-
- /**
- * the constructor defined by m_Class to initialze all scalar attributes described in m_FieldDescriptions
- */
- private Constructor multiArgumentConstructor = null;
-
- /**
- * the proxy class for the described class, may be null
- */
- private Class proxyClass = null;
-
- /**
- * the proxy class name for the described class, may be null
- */
- private String proxyClassName = null;
-
- private FieldDescriptor m_autoIncrementField = null;
-
- private Map m_fieldDescriptorNameMap = new HashMap();
- private Map m_collectionDescriptorNameMap = new HashMap();
- private Map m_objectReferenceDescriptorsNameMap = new HashMap();
-
-
- /**
- * Constructor declaration
- */
- public ClassDescriptor(DescriptorRepository pRepository)
- {
- this.m_repository = pRepository;
- }
-
- public ClassDescriptor()
- {
- this(DescriptorRepository.getDefaultInstance());
- }
-
-
- /**
- * sets the row reader class for thie class descriptor
- */
- public void setRowReader(RowReader newReader)
- {
- this.rowReader = newReader;
- setRowReaderClassName(newReader.getClass().getName());
- }
-
- /**
- * sets the row reader class name for thie class descriptor
- */
- public void setRowReaderClassName(String newReaderClassName)
- {
- this.rowReaderClassName = newReaderClassName;
- }
-
- public String getRowReaderClassName()
- {
- return this.rowReaderClassName;
- }
-
-
- public synchronized RowReader getRowReader()
- {
- if (rowReader == null)
- {
- // if no RowReader has been declared, use the default reader
- if (rowReaderClassName == null)
- {
- rowReader = new RowReaderDefaultImpl();
- }
- else
- {
- try
- {
- Class rowReaderClass = Class.forName(rowReaderClassName, true,
- Thread.currentThread().getContextClassLoader());
- rowReader = (RowReader) rowReaderClass.newInstance();
- }
- catch (Exception e)
- {
- throw new MetadataException(e);
- }
- }
- }
- return this.rowReader;
- }
-
- /**
- * Method declaration
- * @return
- */
- private String getTableName()
- {
- return m_TableName;
- }
-
- /**
- * Answer Table name including schema BRJ
- */
- public String getFullTableName()
- {
- if (getSchema() != null)
- return getSchema() + "." + getTableName();
- else
- return getTableName();
- }
-
- /**
- * Method declaration
- * @param str
- */
- public void setTableName(String str)
- {
- m_TableName = str;
- }
-
- /**
- * returns the name of the described class
- * @return String name of the described class
- */
- public String getClassNameOfObject()
- {
- return this.classname;
- }
-
-
- /**
- * returns the class object of the described class
- * @return Class the described class
- */
- public Class getClassOfObject()
- {
- if (m_Class != null)
- {
- return m_Class;
- }
- else if (classname != null)
- {
- try
- {
- m_Class = Class.forName(classname, true, Thread.currentThread().getContextClassLoader());
- return m_Class;
- }
- catch (ClassNotFoundException e)
- {
- throw new PersistenceBrokerException(e);
- }
- }
- else
- {
- return null;
- }
- }
-
- /**
- * sets the class object described by this descriptor.
- * @param c the class to describe
- */
- public void setClassOfObject(Class c)
- {
- m_Class = c;
- this.classname = c.getName();
- }
-
- /**
- * sets the name of the class described by this descriptor.
- * @param classname the class to describe
- */
- public void setClassNameOfObject(String classname)
- {
- this.classname = classname;
- // Shouldn't the HashMap in DescriptorRepository be updated as well?
- }
-
-
- /**
- * adds a FIELDDESCRIPTOR to this ClassDescriptor.
- * @param fld
- */
- public void addFieldDescriptor(FieldDescriptor fld)
- {
- fld.setClassDescriptor(this); // BRJ
- if (m_FieldDescriptions == null)
- {
- m_FieldDescriptions = new FieldDescriptor[1];
- m_FieldDescriptions[0] = fld;
- m_fieldDescriptorNameMap = new HashMap();
- }
- else
- {
- int size = m_FieldDescriptions.length;
- FieldDescriptor[] tmpArray = new FieldDescriptor[size + 1];
- System.arraycopy(m_FieldDescriptions, 0, tmpArray, 0, size);
- tmpArray[size] = fld;
- m_FieldDescriptions = tmpArray;
- // 2. Sort fields according to their getOrder() Property
- Arrays.sort(m_FieldDescriptions, FieldDescriptor.getComparator());
- }
- }
-
- /**
- * Method declaration
- * @return
- */
- public Vector getCollectionDescriptors()
- {
- return m_CollectionDescriptors;
- }
-
- /**
- * Method declaration
- * @param cod
- */
- public void addCollectionDescriptor(CollectionDescriptor cod)
- {
- cod.setClassDescriptor(this); // BRJ
- m_CollectionDescriptors.add(cod);
- }
-
- /**
- * Method declaration
- * @return
- */
- public Vector getObjectReferenceDescriptors()
- {
- return m_ObjectReferenceDescriptors;
- }
-
- /**
- * Method declaration
- * @param ord
- */
- public void addObjectReferenceDescriptor(ObjectReferenceDescriptor ord)
- {
- ord.setClassDescriptor(this); // BRJ
- m_ObjectReferenceDescriptors.add(ord);
- }
-
- /**
- * Method declaration
- * @return
- */
- public JdbcConnectionDescriptor getConnectionDescriptor()
- {
- if (m_ConnDescription == null)
- {
- // if class has no special JDBC Connection use the DefaultConnection
- m_ConnDescription = this.getRepository().getDefaultJdbcConnection();
- }
- return m_ConnDescription;
- }
-
- /**
- * Method declaration
- * @param jcd
- */
- public void setConnectionDescriptor(JdbcConnectionDescriptor jcd)
- {
- m_ConnDescription = jcd;
- }
-
- /**
- * Method declaration
- * @param index
- * @return
- */
- public FieldDescriptor getFieldDescriptorByIndex(int index)
- {
- return m_FieldDescriptions[index - 1];
- }
-
- /**
- * Method declaration
- * @return
- */
- public String toString()
- {
- return "table: \t"
- + m_TableName
- + "\n"
- + "FieldDescriptions:\t"
- + (m_FieldDescriptions == null ? "" : m_FieldDescriptions.toString());
-
- }
-
- /**
- * Method declaration
- * @param name
- * @return
- */
- public FieldDescriptor getFieldDescriptorByName(String name)
- {
- if (name == null)
- return null;
- if (m_FieldDescriptions == null)
- return null;
- FieldDescriptor retval = (FieldDescriptor) m_fieldDescriptorNameMap.get(name);
- if (retval == null)
- {
- int size = m_FieldDescriptions.length;
- FieldDescriptor temp = null;
- for (int i = 0; ((i < size) && (retval == null)); i++)
- {
- temp = m_FieldDescriptions[i];
- if (name.equals(temp.getPersistentField().getName()))
- {
- retval = temp;
- m_fieldDescriptorNameMap.put(name, retval);
- break;
- }
- }
- }
- return retval;
- }
-
- /**
- * Get an ObjectReferenceDescriptor by name BRJ
- * @param name
- * @return ObjectReferenceDescriptor or null
- */
- public ObjectReferenceDescriptor getObjectReferenceDescriptorByName(String name)
- {
- if (name == null)
- return null;
- ObjectReferenceDescriptor retval = (ObjectReferenceDescriptor) this.m_objectReferenceDescriptorsNameMap.get(name);
- if (retval == null)
- {
- Vector descr = getObjectReferenceDescriptors();
- int size = descr.size();
- for (int i = 0; i < size; i++)
- {
- ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descr.elementAt(i);
- if (ord.getPersistentField().getName().equals(name))
- {
- retval = ord;
- m_objectReferenceDescriptorsNameMap.put(name, retval);
- break;
- }
- }
- }
- return retval;
- }
-
- /**
- * Get an CollectionDescriptor by name BRJ
- * @param name
- * @return CollectionDescriptor or null
- */
- public CollectionDescriptor getCollectionDescriptorByName(String name)
- {
- if (name == null)
- return null;
- CollectionDescriptor retval = (CollectionDescriptor) this.m_collectionDescriptorNameMap.get(name);
- if (retval == null)
- {
- Vector descr = getCollectionDescriptors();
- int size = descr.size();
- for (int i = 0; i < size; i++)
- {
- CollectionDescriptor ord = (CollectionDescriptor) descr.elementAt(i);
- if (ord.getPersistentField().getName().equals(name))
- {
- retval = ord;
- m_collectionDescriptorNameMap.put(name, retval);
- break;
- }
- }
- }
- return retval;
- }
-
- /**
- * returns the transaction isolation level to be used for this class. Used only in the ODMG server
- */
- public int getIsolationLevel()
- {
- return m_IsolationLevel;
- }
-
- /**
- * Method declaration
- * @param isoLevel
- */
- public void setIsolationLevel(int isoLevel)
- {
- m_IsolationLevel = isoLevel;
- }
-
-
- /**
- * add an Extent class to the current descriptor
- * @param newExtendClass
- */
- public void addExtentClass(Class newExtendClass)
- {
- extentClasses.add(newExtendClass);
- this.addExtentClassName(newExtendClass.getName());
- }
-
- /**
- * add an Extent class to the current descriptor
- * @param newExtendClassName name of the class to add
- */
- public void addExtentClassName(String newExtendClassName)
- {
- extentClassNames.add(newExtendClassName);
- m_repository.addExtent(newExtendClassName, this);
- }
-
- public void setSuperClass(String classname)
- {
- this.superClass = classname;
-
-
- }
-
- public void setSuperClassFieldRef(int fieldId)
- {
- this.superClassFieldRef = fieldId;
- }
-
- public int getSuperClassFieldRef()
- {
- return superClassFieldRef;
- }
-
- public String getSuperClass()
- {
- return superClass;
- }
-
- /**
- * returns a Constructor that takes all persistent attributes
- * of the class as arguments.
- * Returns null, if such a constructor does not exist.
- * PersistenceBroker clients are not urged to implement such constructors
- * for persistence capable classes. But it's strongly recommended as
- * it minimizes the overhead for reflective operations.
- */
- public Constructor getConstructor()
- {
- if (multiArgumentConstructor == null && !alreadyLookedup)
- {
- if (argsForConstructor == null)
- {
- argsForConstructor = new Class[getFieldDescriptions().length];
- for (int i = 0; i < getFieldDescriptions().length; i++)
- {
- argsForConstructor[i] = getFieldDescriptions()[i].getPersistentField().getType();
- }
- }
- try
- {
- multiArgumentConstructor = getClassOfObject().getConstructor(argsForConstructor);
- }
- catch (Exception ignored)
- {
- // this exception is thrown, if no suitable Constructor was
- // found. In this case we tell the user that it is better to have
- // a multiargs constructor defined
- String args = "";
- for (int i = 0; i < argsForConstructor.length; i++)
- {
- args += ((args.length() == 0) ? "(" : ", ");
- args += argsForConstructor[i].getName();
- }
- args += ")";
- LoggerFactory.getDefaultLogger().warn(
- "Please define a public constructor for "
- + this.getClassOfObject()
- + "\nwith the following signature: "
- + args
- + ".\nIt must initialize the classes persistent attributes. This is recommended to increase performance but it's not mandatory!");
- }
- alreadyLookedup = true;
- }
- return multiArgumentConstructor;
- }
-
- /**
- * return all classes in this extent.
- * Creation date: (02.02.2001 17:49:11)
- * @return java.util.Vector
- */
- public synchronized Vector getExtentClasses()
- {
- if (extentClassNames.size() > extentClasses.size())
- {
- extentClasses.clear();
- for (Iterator iter = extentClassNames.iterator(); iter.hasNext();)
- {
- String classname = (String) iter.next();
- Class extentClass;
- try
- {
- extentClass = Class.forName(classname, true,
- Thread.currentThread().getContextClassLoader());
- }
- catch (ClassNotFoundException e)
- {
- throw new MetadataException("Unable to load class [" + classname + "]. Make sure it is available on the classpath.", e);
- }
- extentClasses.add(extentClass);
- }
- }
- return extentClasses;
- }
-
- /**
- * Return the names of all classes in this extent
- * @return java.util.Vector a Vector containing the fully qualified names
- * of all classes in this extent
- */
- public synchronized Vector getExtentClassNames()
- {
- return this.extentClassNames;
- }
-
- /**
- * Insert the method's description here.
- * Creation date: (26.01.2001 09:20:09)
- * @return java.lang.Class
- */
- public synchronized java.lang.Class getProxyClass()
- {
-
- if ((proxyClass == null) && (proxyClassName != null))
- {
- String dynamic = "dynamic";
- if (dynamic.equalsIgnoreCase(proxyClassName))
- {
- proxyClass = getDynamicProxyClass();
- }
- else
- {
- try
- {
- proxyClass = Class.forName(proxyClassName, true,
- Thread.currentThread().getContextClassLoader());
- }
- catch (ClassNotFoundException e)
- {
- throw new MetadataException(e);
- }
- }
- }
- return proxyClass;
- }
-
- /**
- * Insert the method's description here.
- * Creation date: (02.02.2001 17:49:11)
- * @return boolean
- */
- public boolean isExtent()
- {
- return (getExtentClassNames().size() > 0);
- }
-
- /**
- * Insert the method's description here.
- * Creation date: (02.02.2001 17:49:11)
- * @return boolean
- */
- public boolean isInterface()
- {
- return isInterface;
- }
-
- /**
- * Insert the method's description here.
- * Creation date: (02.02.2001 17:49:11)
- * @param newIsInterface boolean
- */
- public void setIsInterface(boolean newIsInterface)
- {
- isInterface = newIsInterface;
- }
-
- /**
- * @return boolean true if the mapped class is abstract
- */
- public boolean isAbstract()
- {
- return Modifier.isAbstract(getClassOfObject().getModifiers());
- }
-
- /**
- * Sets the proxy class to be used.
- * @param newProxyClass java.lang.Class
- */
- public void setProxyClass(java.lang.Class newProxyClass)
- {
- proxyClass = newProxyClass;
- if (proxyClass == null)
- setProxyClassName(null);
- else
- proxyClassName = proxyClass.getName();
- }
-
- /**
- * Sets the name of the proxy class to be used.
- * using "dynamic" instead of a real classname
- * will result in usage of dynamic proxies.
- * @param newProxyClassName the classname or "dynamic"
- */
- public void setProxyClassName(String newProxyClassName)
- {
- proxyClassName = newProxyClassName;
- }
-
- /**
- * Get the name of the proxy class. This method doesn't try to access
- * the real class, so it can be called even if the class doesn't exist.
- */
- public String getProxyClassName()
- {
- return proxyClassName;
- }
-
- /**
- * returns a vector containing values for all the Objects attribute
- * @throws MetadataException if tehre is an erros accessing obj field values
- */
- public Object[] getAllValues(Object obj) throws PersistenceBrokerException
- {
- FieldDescriptor[] allFields = getFieldDescriptions();
- Object[] result = new Object[allFields.length];
-
- for (int i = 0; i < allFields.length; i++)
- {
- FieldDescriptor fmd = allFields[i];
- PersistentField f = fmd.getPersistentField();
- Object cv = f.get(obj);
-
- // handle autoincrement attributes if not filled
- if (fmd.isAutoIncrement())
- {
- cv = getAutoIncrementValue(fmd, obj, cv);
- }
-
- // apply type and value mapping
- cv = fmd.getFieldConversion().javaToSql(cv);
- result[i] = cv;
- }
- return result;
- }
-
- /**
- * returns array of all FieldDescriptors.
- * @return FIELDDESCRIPTOR[]
- */
- public FieldDescriptor[] getFieldDescriptions()
- {
- return m_FieldDescriptions;
- }
-
- /**
- * returns an Array with an Objects PK VALUES, with any java-to-sql
- * FieldConversion applied
- * @throws MetadataException if there is an erros accessing o field values
- */
- public Object[] getKeyValues(Object o) throws PersistenceBrokerException
- {
- return getKeyValues(o, true);
- }
-
- /**
- * returns an Array with an Objects PK VALUES
- * if convertToSql is true, any associated java-to-sql conversions are applied
- * @throws MetadataException if there is an erros accessing o field values
- */
- public Object[] getKeyValues(Object o, boolean convertToSql) throws PersistenceBrokerException
- {
- FieldDescriptor[] pkFields = getPkFields();
- Object[] result = new Object[pkFields.length];
-
- for (int i = 0; i < result.length; i++)
- {
- FieldDescriptor fmd = pkFields[i];
- PersistentField f = fmd.getPersistentField();
- Object cv = f.get(o);
-
- // handle autoincrement attributes if not filled
- if (fmd.isAutoIncrement())
- {
- cv = getAutoIncrementValue(fmd, o, cv);
- }
-
- if (convertToSql)
- {
- // BRJ : apply type and value mapping
- cv = fmd.getFieldConversion().javaToSql(cv);
- }
- result[i] = cv;
- }
- return result;
- }
-
- /**
- * returns an Array with an Objects CURRENT locking VALUES , BRJ
- * @throws MetadataException if there is an erros accessing o field values
- */
- public Object[] getCurrentLockingValues(Object o) throws PersistenceBrokerException
- {
- FieldDescriptor[] fields = getLockingFields();
- Object[] result = new Object[fields.length];
- for (int i = 0; i < result.length; i++)
- {
- FieldDescriptor fmd = fields[i];
- PersistentField f = fmd.getPersistentField();
- Object cv = null;
- cv = f.get(o); // retrieve the Objects value for the specified field
- result[i] = cv;
- }
- return result;
- }
-
- /**
- * updates the values for locking fields , BRJ
- * handles int, long, Timestamp
- * @throws MetadataException if there is an erros accessing obj field values
- */
- public void updateLockingValues(Object obj) throws PersistenceBrokerException
- {
- FieldDescriptor[] fields = getLockingFields();
- for (int i = 0; i < fields.length; i++)
- {
- FieldDescriptor fmd = fields[i];
- PersistentField f = fmd.getPersistentField();
- Object cv = null;
- cv = f.get(obj);
-
- // int
- if ((f.getType() == int.class) || (f.getType() == Integer.class))
-
- {
- int newCv = 0;
- if (cv != null)
- {
- newCv = ((Number) cv).intValue();
- }
- newCv++;
- f.set(obj, new Integer(newCv));
- }
- // long
- else if ((f.getType() == long.class) || (f.getType() == Long.class))
-
- {
- long newCv = 0;
- if (cv != null)
- {
- newCv = ((Number) cv).longValue();
- }
- newCv++;
- f.set(obj, new Long(newCv));
- }
- // Timestamp
- else if (f.getType() == Timestamp.class)
-
- {
- long newCv = (new Date()).getTime();
- f.set(obj, new Timestamp(newCv));
- }
- }
- }
-
- /**
- * @throws MetadataException if there is an erros accessing obj field values
- */
- private Object getAutoIncrementValue(FieldDescriptor fmd, Object obj, Object cv)
- {
- if ((cv == null) || ((cv instanceof Number) && (((Number) cv).intValue() == 0)))
- {
- PersistentField f = fmd.getPersistentField();
- Object result = cv;
- PersistenceBroker broker = null;
- try
- {
- if (m_repository != null)
- {
- // arminw
- // use the PBKey of the associated descriptor repository
- // to match the 'correct' repository
- /* @todo maybe this could be critical in some
- * situations, e.g. if the associated PBKey was always the
- * default PBKey. Check this out.
- */
- broker = PersistenceBrokerFactory.createPersistenceBroker(m_repository.getPBkey());
- }
- else
- {
- // no repository, we use the default PB
- broker = PersistenceBrokerFactory.defaultPersistenceBroker();
- }
- // int
- if ((f.getType() == int.class) || (f.getType() == Integer.class))
- {
- if ((f.get(obj) == null) || (((Number) f.get(obj)).intValue() == 0))
- {
- /*
- arminw
- old version
- Class extent = broker.getExtentClass(this.getClassOfObject());
- result = new Integer(broker.getUniqueId(extent, f.getName()));
-
- we should not give the top-level extent to sequence manager,
- sequence manager itself should take care of uniqueness over the extents
- */
- result = new Integer(broker.getUniqueId(fmd));
- // reflect autoincrement value back into object
- f.set(obj, result);
- }
- }
- // long
- else if ((f.getType() == long.class) || (f.getType() == Long.class))
- {
- if ((f.get(obj) == null) || (((Number) f.get(obj)).longValue() == 0))
- {
- /*
- arminw
- old version
- Class extent = broker.getExtentClass(this.getClassOfObject());
- result = new Long(broker.getUniqueLong(extent, f.getName()));
-
- we should not give the top-level extent to sequence manager,
- sequence manager itself should take care of uniqueness over the extents
- */
-
- result = new Long(broker.getUniqueLong(fmd));
- // reflect autoincrement value back into object
- f.set(obj, result);
- }
- }
- // String
- else if (String.class.isAssignableFrom(f.getType()))
- {
- if (f.get(obj) == null)
- {
- result = broker.getUniqueString(fmd);
- // reflect autoincrement value back into object
- f.set(obj, result);
- }
- }
- // Object
- else if (!f.getType().isPrimitive())
- {
- // only assign a value if attribute == null
- if (f.get(obj) == null)
- {
- result = broker.getUniqueObject(fmd);
- if (result != null)
- {
- // reflect autoincrement value back into object
- f.set(obj, result);
- }
- else
- {
- throw new OJBRuntimeException(
- "OJB ERROR: Dont know how to autoincrement field " +
- f.getDeclaringClass() + "#" + f.getName());
- }
- }
- }
- else
- {
- throw new OJBRuntimeException(
- "OJB ERROR: Dont know how to autoincrement field " +
- f.getDeclaringClass() + "#" + f.getName());
- }
- return result;
- }
- catch (MetadataException e)
- {
- throw new OJBRuntimeException(
- "Error while trying to autoincrement field " +
- f.getDeclaringClass() + "#" + f.getName(), e);
- }
- finally
- {
- if (broker != null)
- {
- broker.close();
- }
- }
- }
- else
- {
- return cv;
- }
-
- }
-
- /**
- * returns an Array with an Objects NON-PK VALUES
- * @throws MetadataException if there is an erros accessing o field values
- */
- public Object[] getNonKeyValues(Object o) throws PersistenceBrokerException
- {
- FieldDescriptor[] nonPkFields = getNonPkFields();
- Object[] result = new Object[nonPkFields.length];
-
- for (int i = 0; i < result.length; i++)
- {
- FieldDescriptor fmd = nonPkFields[i];
- PersistentField f = fmd.getPersistentField();
- Object cv = f.get(o);
-
- // handle autoincrement attributes if not filled
- if (fmd.isAutoIncrement())
- {
- cv = getAutoIncrementValue(fmd, o, cv);
- }
-
- // apply type and value conversion
- cv = fmd.getFieldConversion().javaToSql(cv);
- result[i] = cv;
- }
- return result;
- }
-
- /**
- * return an array of PK FieldDescription sorted ascending
- * according to the field-descriptions getOrder() property
- */
- public FieldDescriptor[] getNonPkFields()
- {
- if (nonPrimaryKeyFieldDescriptors == null)
- {
- // 1. collect all Primary Key fields from Field list
- Vector vec = new Vector();
- for (int i = 0; i < m_FieldDescriptions.length; i++)
- {
- FieldDescriptor fmd = m_FieldDescriptions[i];
- if (!fmd.isPrimaryKey())
- {
- vec.add(fmd);
- }
- }
- // 2. Sort fields according to their getOrder() Property
- Collections.sort(vec, FieldDescriptor.getComparator());
- nonPrimaryKeyFieldDescriptors = (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
- }
- return nonPrimaryKeyFieldDescriptors;
- }
-
- /**
- * return an array of PK FieldDescription sorted ascending
- * according to the field-descriptions getOrder() property
- */
- public FieldDescriptor[] getPkFields()
- {
- if (primaryKeyFieldDescriptors == null)
- {
- // 1. collect all Primary Key fields from Field list
- Vector vec = new Vector();
- FieldDescriptor[] fields = null;
- // 1.a if descriptor describes an interface: take PK fields from an implementors ClassDescriptor
- if (isInterface)
- {
- if (getExtentClasses().size() == 0)
- {
- throw new PersistenceBrokerException(
- "No Implementors declared for interface " + this.getClassOfObject().getName());
- }
- Class implementor = (Class) getExtentClasses().get(0);
- ClassDescriptor implCld = this.getRepository().getDescriptorFor(implementor);
- primaryKeyFieldDescriptors = implCld.getPkFields();
- return primaryKeyFieldDescriptors;
- }
- // 1.b if not an interface The classdescriptor must have FieldDescriptors
- else
- {
- fields = this.getFieldDescriptions();
- }
-
- // now collect all PK fields
- for (int i = 0; i < fields.length; i++)
- {
- FieldDescriptor fmd = fields[i];
- if (fmd.isPrimaryKey())
- {
- vec.add(fmd);
- }
- }
- // 2. Sort fields according to their getOrder() Property
- Collections.sort(vec, FieldDescriptor.getComparator());
- primaryKeyFieldDescriptors = (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
- }
- return primaryKeyFieldDescriptors;
- }
-
- /**
- * return an array of FieldDescription for optimistic locking sorted ascending
- * according to the field-descriptions getOrder() property
- */
- public FieldDescriptor[] getLockingFields()
- {
- if (lockingFieldDescriptors == null)
- {
- // 1. collect all Primary Key fields from Field list
- Vector vec = new Vector();
- for (int i = 0; i < m_FieldDescriptions.length; i++)
- {
- FieldDescriptor fmd = m_FieldDescriptions[i];
- if (fmd.isLocking())
- {
- vec.add(fmd);
- }
- }
- // 2. Sort fields according to their getOrder() Property
- Collections.sort(vec, FieldDescriptor.getComparator());
- lockingFieldDescriptors = (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
- }
- return lockingFieldDescriptors;
- }
-
- /**
- * returns a dynamic Proxy that implements all interfaces of the
- * class described by this ClassDescriptor.
- *
- * @return Class the dynamically created proxy class
- */
- public Class getDynamicProxyClass()
- {
- Class clazz = getClassOfObject();
- Class superClass = clazz;
- Class[] interfaces = clazz.getInterfaces();
-
- // clazz can be an interface itself and when getInterfaces()
- // is called on an interface it returns only the extending
- // interfaces, not the interface itself.
- if (clazz.isInterface())
- {
- Class[] tempInterfaces = new Class[interfaces.length + 1];
- tempInterfaces[0] = clazz;
-
- System.arraycopy(interfaces, 0, tempInterfaces, 1, interfaces.length);
- interfaces = tempInterfaces;
- }
-
- // add all interfaces implemented by superclasses to the interfaces array
- while ((superClass = superClass.getSuperclass()) != null)
- {
- Class[] superInterfaces = superClass.getInterfaces();
- Class[] combInterfaces = new Class[interfaces.length + superInterfaces.length];
- System.arraycopy(interfaces, 0, combInterfaces, 0, interfaces.length);
- System.arraycopy(superInterfaces, 0, combInterfaces, interfaces.length, superInterfaces.length);
- interfaces = combInterfaces;
- }
-
- /**
- * Must remove duplicate interfaces before calling Proxy.getProxyClass().
- * Duplicates can occur if a subclass re-declares that it implements
- * the same interface as one of its ancestor classes.
- **/
- HashMap unique = new HashMap();
- for (int i = 0; i < interfaces.length; i++)
- {
- unique.put(interfaces[i].getName(), interfaces[i]);
- }
- interfaces = (Class[]) unique.values().toArray(new Class[unique.size()]);
- // return dynymic Proxy Class implementing all interfaces
- Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), interfaces);
-
- return proxyClass;
- }
-
- /**
- * return true if optimistic locking is used
- */
- public boolean isLocking()
- {
- return getLockingFields().length > 0;
- }
-
- /**
- * Gets the repository.
- * @return Returns a DescriptorRepository
- */
- public DescriptorRepository getRepository()
- {
- return m_repository;
- }
-
- /**
- * Sets the repository.
- * @param repository The repository to set
- */
- public void setRepository(DescriptorRepository repository)
- {
- m_repository = repository;
- }
-
- /**
- * Gets the schema.
- * @return Returns a String
- */
- public String getSchema()
- {
- return schema;
- }
-
- /**
- * Sets the schema.
- * @param schema The schema to set
- */
- public void setSchema(String schema)
- {
- this.schema = schema;
- }
-
- /**
- * Gets the IndexDescriptors used for DDL generation.
- */
- public Vector getIndexes()
- {
- return indexes;
- }
-
- /**
- * Sets the IndexDescriptors used for DDL generation.
- */
- public void setIndexes(Vector indexes)
- {
- this.indexes = indexes;
- }
-
- /**
- * return the FieldDescriptor for the Attribute referenced in the path<br>
- * the path may contain simple attribut names, functions and path expressions
- * using relationships <br>
- * ie: name, avg(price), adress.street
- * @param aPath the path to the attribute
- * @return the FieldDescriptor or null (ie: for m:n queries)
- */
- public FieldDescriptor getFieldDescriptorForPath(String aPath)
- {
- ArrayList desc = getAttributeDescriptorsForPath(aPath);
- FieldDescriptor fld = null;
- Object temp;
-
- if (!desc.isEmpty())
- {
- temp = desc.get(desc.size() - 1);
- if (temp instanceof FieldDescriptor)
- {
- fld = (FieldDescriptor) temp;
- }
- }
- return fld;
- }
-
-
- /**
- * return all AttributeDescriptors for the path<br>
- * ie: partner.addresses.street returns a Collection of 3 AttributeDescriptors
- * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
- * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
- * (ObjectReferenceDescriptor, CollectionDescriptor)
- * @param aPath the cleaned path to the attribute
- * @return ArrayList of AttributeDescriptors
- */
- public ArrayList getAttributeDescriptorsForPath(String aPath)
- {
- return getAttributeDescriptorsForCleanPath(cleanPath(aPath));
- }
-
- /**
- * return all AttributeDescriptors for the path<br>
- * ie: partner.addresses.street returns a Collection of 3 AttributeDescriptors
- * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
- * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
- * (ObjectReferenceDescriptor, CollectionDescriptor)
- * @param aPath the cleaned path to the attribute
- * @return ArrayList of AttributeDescriptors
- */
- private ArrayList getAttributeDescriptorsForCleanPath(String aPath)
- {
- ArrayList result = new ArrayList();
- ClassDescriptor cld = this;
- ObjectReferenceDescriptor ord = null;
- FieldDescriptor fld = null;
- String currPath = aPath;
- String segment;
- int sepPos;
-
- while (currPath.length() > 0)
- {
- sepPos = currPath.indexOf(".");
- if (sepPos >= 0)
- {
- segment = currPath.substring(0, sepPos);
- currPath = currPath.substring(sepPos + 1);
- }
- else
- {
- segment = currPath;
- currPath = "";
- }
-
- // look for 1:1 or n:1 Relationship
- ord = cld.getObjectReferenceDescriptorByName(segment);
- if (ord == null)
- {
- // look for 1:n or m:n Relationship
- ord = cld.getCollectionDescriptorByName(segment);
- }
-
- if (ord != null)
- {
- cld = cld.getRepository().getDescriptorFor(ord.getItemClass());
- result.add(ord);
- }
- else
- {
- // look for Field
- fld = cld.getFieldDescriptorByName(segment);
- if (fld != null)
- {
- result.add(fld);
- }
- }
- }
-
- return result;
- }
-
- /**
- * remove functions and () from path
- * ie: avg(amount) -> amount <br>
- * ie: sum(accounts.amount) -> accounts.amount
- * @param aPath the path to the attribute
- */
- public static String cleanPath(String aPath)
- {
- int braceBegin;
- int braceEnd;
-
- if (aPath == null)
- {
- return aPath;
- }
-
- braceBegin = aPath.indexOf("(");
- braceEnd = aPath.lastIndexOf(")");
- if (braceBegin >= 0 && braceEnd >= 0)
- {
- return aPath.substring(braceBegin + 1, braceEnd).trim();
- }
- else
- {
- return aPath;
- }
-
- }
-
-
- /*
- * @see XmlCapable#toXML()
- */
- public String toXML()
- {
- RepositoryTags tags = RepositoryTags.getInstance();
- String eol = System.getProperty("line.separator");
-
- // comment on class
- String result = eol + " <!-- Mapping for Class " + this.getClassNameOfObject() + " -->" + eol;
-
- // opening tag and attributes
- result += " " + tags.getOpeningTagNonClosingById(CLASS_DESCRIPTOR) + eol;
-
- // class
- result += " " + tags.getAttribute(CLASS_NAME, this.getClassNameOfObject()) + eol;
-
- // isolation level is optional
- if (getIsolationLevel() != this.getRepository().getDefaultIsolationLevel())
- {
- result += " " + tags.getAttribute(ISOLATION_LEVEL, this.isolationLevelXml()) + eol;
- }
-
-
- Class theProxyClass = null;
- try
- {
- theProxyClass = this.getProxyClass();
- }
- catch (Throwable t)
- {
- // Ignore this exception, just try to get the Class object of the
- // proxy class in order to be able to decide, whether the class
- // is a dynamic proxy or not.
- }
-
- // proxy is optional
- if (theProxyClass != null && Proxy.isProxyClass(theProxyClass))
- {
- result += " " + tags.getAttribute(CLASS_PROXY, "dynamic") + eol;
- }
- else
- {
- result += " " + tags.getAttribute(CLASS_PROXY, this.getProxyClassName()) + eol;
- }
-
- // schema is optional
- if (this.getSchema() != null)
- {
- result += " " + tags.getAttribute(SCHEMA_NAME, this.getSchema()) + eol;
- }
-
- // table name
- if (this.getTableName() != null)
- {
- result += " " + tags.getAttribute(TABLE_NAME, this.getTableName()) + eol;
- }
-
- // rowreader is optional
- if (this.getRowReaderClassName() != null)
- {
- result += " " + tags.getAttribute(ROW_READER, this.getRowReaderClassName()) + eol;
- }
-
- // sequence manager attribute not yet implemented
-
- result += " >" + eol;
-
- // end of attributes
-
- // begin of elements
- if (isInterface())
- {
- // extent-class
- for (int i = 0; i < getExtentClassNames().size(); i++)
- {
- result += " " + tags.getOpeningTagNonClosingById(CLASS_EXTENT) + " ";
- result += tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString());
- result += " />" + eol;
- }
- }
- else
- {
- // class extent is optional
- if (isExtent())
- {
- for (int i = 0; i < getExtentClassNames().size(); i++)
- {
- result += " " + tags.getOpeningTagNonClosingById(CLASS_EXTENT) + " ";
- result += tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString());
- result += " />" + eol;
- }
- }
-
- // write all FieldDescriptors
- FieldDescriptor[] fields = getFieldDescriptions();
- for (int i = 0; i < fields.length; i++)
- {
- result += fields[i].toXML();
- }
-
- // write optional ReferenceDescriptors
- Vector refs = getObjectReferenceDescriptors();
- for (int i = 0; i < refs.size(); i++)
- {
- result += ((ObjectReferenceDescriptor) refs.get(i)).toXML();
- }
-
- // write optional CollectionDescriptors
- Vector cols = getCollectionDescriptors();
- for (int i = 0; i < cols.size(); i++)
- {
- result += ((CollectionDescriptor) cols.get(i)).toXML();
- }
-
- }
-
- result += " " + tags.getClosingTagById(CLASS_DESCRIPTOR);
- return result;
- }
-
- private String isolationLevelXml()
- {
- switch (this.getIsolationLevel())
- {
- case (IL_OPTIMISTIC):
- {
- return LITERAL_IL_OPTIMISTIC;
- }
- case (IL_READ_COMMITTED):
- {
- return LITERAL_IL_READ_COMMITTED;
- }
- case (IL_READ_UNCOMMITTED):
- {
- return LITERAL_IL_READ_UNCOMMITTED;
- }
- case (IL_REPEATABLE_READ):
- {
- return LITERAL_IL_REPEATABLE_READ;
- }
- case (IL_SERIALIZABLE):
- {
- return LITERAL_IL_SERIALIZABLE;
- }
- default :
- {
- return LITERAL_IL_READ_UNCOMMITTED;
- }
-
- }
-
- }
-
- /**
- * Returns the first found autoincrement field
- * defined in this class descriptor. Use carefully
- * when multiple autoincrement field were defined.
- */
- public FieldDescriptor getAutoIncrementField()
- {
- if (m_autoIncrementField == null)
- {
- FieldDescriptor[] fds = getPkFields();
-
- for (int i = 0; i < fds.length; i++)
- {
- FieldDescriptor fd = fds[i];
- if (fd.isAutoIncrement())
- {
- m_autoIncrementField = fd;
- break;
- }
- }
- }
- if(m_autoIncrementField == null)
- {
- LoggerFactory.getDefaultLogger().warn(
- "Could not found autoincrement attribute for class: " + this.getClassNameOfObject());
- }
- return m_autoIncrementField;
- }
-
- /**
- *
- * @return this classes FieldDescriptor's as well as it's parents and so on and so on
- */
- public FieldDescriptor[] getFieldDescriptorsInHeirarchy()
- {
- if (superClass == null)
- {
- return getFieldDescriptions();
- }
- ClassDescriptor cldSuper = getRepository().getDescriptorFor(superClass);
- return appendFieldDescriptorArrays(getFieldDescriptions(), cldSuper.getFieldDescriptorsInHeirarchy());
- }
-
- private FieldDescriptor[] appendFieldDescriptorArrays(FieldDescriptor[] fieldDescriptions, FieldDescriptor[] fieldDescriptorsInHeirarchy)
- {
- // take the 2 arrays and add them into one
- int size = fieldDescriptions.length + fieldDescriptorsInHeirarchy.length;
- FieldDescriptor[] newArray = new FieldDescriptor[size];
- int i;
- int j = 0;
- for (i = 0; i < fieldDescriptions.length; i++, j++)
- {
- FieldDescriptor fieldDescription = fieldDescriptions[i];
- newArray[j] = fieldDescription;
- }
- for (i = 0; i < fieldDescriptorsInHeirarchy.length; i++, j++)
- {
- FieldDescriptor fieldDescription = fieldDescriptorsInHeirarchy[i];
- newArray[j] = fieldDescription;
- }
-
- return newArray;
- }
-
- /**
- * convenience function to get the first primary key
- * <p>
- * useful when there is only one
- * @return
- */
- public FieldDescriptor getPrimaryKey()
- {
- FieldDescriptor[] fds = getPkFields();
- if (fds != null && fds.length > 0)
- {
- return fds[0];
- }
- return null;
- }
-
-
-}
+package org.apache.ojb.broker.metadata;
+
+/* ====================================================================
+ * The Apache Software License, Version 1.1
+ *
+ * Copyright (c) 2001 The Apache Software Foundation. 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 acknowledgment:
+ * "This product includes software developed by the
+ * Apache Software Foundation (http://www.apache.org/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Apache" and "Apache Software Foundation" and
+ * "Apache ObjectRelationalBridge" must not be used to endorse or promote products
+ * derived from this software without prior written permission. For
+ * written permission, please contact apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache",
+ * "Apache ObjectRelationalBridge", nor may "Apache" appear in their name, without
+ * prior written permission of the Apache Software Foundation.
+ *
+ * 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 APACHE SOFTWARE FOUNDATION 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 on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ */
+
+import org.apache.ojb.broker.OJBRuntimeException;
+import org.apache.ojb.broker.PersistenceBroker;
+import org.apache.ojb.broker.PersistenceBrokerException;
+import org.apache.ojb.broker.PersistenceBrokerFactory;
+import org.apache.ojb.broker.accesslayer.RowReader;
+import org.apache.ojb.broker.accesslayer.RowReaderDefaultImpl;
+import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;
+import org.apache.ojb.broker.util.logging.LoggerFactory;
+
+import java.io.Serializable;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.sql.Timestamp;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+//#ifdef JDK13
+import java.lang.reflect.Proxy;
+//#else
+/*
+import com.develop.java.lang.reflect.Proxy;
+*/
+//#endif
+
+/**
+ * A ClassDescriptor contains all information for mapping objects of a
+ * given class to database tables.
+ *
+ * @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
+ * @version $Id$
+ */
+public class ClassDescriptor extends DescriptorBase implements Serializable, XmlCapable, IsolationLevels
+{
+
+ public static final String OJB_CONCRETE_CLASS = "ojbConcreteClass";
+
+ private transient DescriptorRepository m_repository;
+
+ /**
+ * transaction isolation level specified for this class, used in the ODMG server
+ */
+ private int m_IsolationLevel = IsolationLevels.IL_READ_UNCOMMITTED;
+
+ /**
+ * the SQL SCHEMA of the underlying table of this class
+ */
+ private String schema = null;
+
+ /**
+ * the described class
+ */
+ private Class m_Class = null;
+
+ /**
+ * the name of the described class
+ */
+ private String classname = null;
+
+
+ /**
+ * the table name used to store the scalar attributes of this class
+ */
+ private String m_TableName = null;
+
+ /**
+ * the FieldDescriptors for the primitive attributes
+ */
+ private FieldDescriptor[] m_FieldDescriptions = null;
+
+ /**
+ * the descriptors for collection attributes
+ */
+ private Vector m_CollectionDescriptors = new Vector();
+
+ /**
+ * the descriptor for 1-1 reference attributes
+ */
+ private Vector m_ObjectReferenceDescriptors = new Vector();
+
+ /**
+ * the vector of indices used in DDL generation.
+ */
+ private Vector indexes = new Vector();
+
+ /**
+ * the JDBCConnectionDescriptor describing the RDBMS connection to be used for this class
+ */
+ private JdbcConnectionDescriptor m_ConnDescription = null;
+
+ /**
+ * the non-primary key FieldDescriptors
+ */
+ private FieldDescriptor[] nonPrimaryKeyFieldDescriptors = null;
+
+ /**
+ * the primary key FieldDescriptors
+ */
+ private FieldDescriptor[] primaryKeyFieldDescriptors = null;
+
+ /**
+ * the optimistic lockingFieldDescriptors BRJ
+ */
+ private FieldDescriptor[] lockingFieldDescriptors = null;
+
+ /**
+ * the RowReader for this class
+ */
+ private RowReader rowReader = null;
+
+ /**
+ * the RowReader class name for this class
+ */
+ private String rowReaderClassName = null;
+
+ /**
+ * tells whether we tried to lookup multiargs Constructor already
+ */
+ private boolean alreadyLookedup = false;
+
+ /**
+ * the types of the arguments for the attributes in m_FieldDescriptions
+ */
+ private Class[] argsForConstructor = null;
+
+ /**
+ * the list of classes in the extent of this class. can be empty
+ */
+ private Vector extentClasses = new Vector();
+
+ /**
+ * the list of class names in the extent of this class. can be empty
+ */
+ private Vector extentClassNames = new Vector();
+
+ /**
+ * the class that this class extends
+ */
+ private String superClass;
+ /**
+ * reference column for the superclass
+ */
+ private int superClassFieldRef;
+
+ /**
+ * does the described class represent an interface?
+ */
+ private boolean isInterface = false;
+
+ /**
+ * the constructor defined by m_Class to initialze all scalar attributes described in m_FieldDescriptions
+ */
+ private Constructor multiArgumentConstructor = null;
+
+ /**
+ * the proxy class for the described class, may be null
+ */
+ private Class proxyClass = null;
+
+ /**
+ * the proxy class name for the described class, may be null
+ */
+ private String proxyClassName = null;
+
+ private FieldDescriptor m_autoIncrementField = null;
+
+ private Map m_fieldDescriptorNameMap = new HashMap();
+ private Map m_collectionDescriptorNameMap = new HashMap();
+ private Map m_objectReferenceDescriptorsNameMap = new HashMap();
+
+ /**
+ * if false do not accept implicit locks on this class
+ */
+ private boolean acceptLocks = true;
+
+ /**
+ * Constructor declaration
+ */
+ public ClassDescriptor(DescriptorRepository pRepository)
+ {
+ this.m_repository = pRepository;
+ }
+
+ public ClassDescriptor()
+ {
+ this(DescriptorRepository.getDefaultInstance());
+ }
+
+
+ /**
+ * sets the row reader class for thie class descriptor
+ */
+ public void setRowReader(RowReader newReader)
+ {
+ this.rowReader = newReader;
+ setRowReaderClassName(newReader.getClass().getName());
+ }
+
+ /**
+ * sets the row reader class name for thie class descriptor
+ */
+ public void setRowReaderClassName(String newReaderClassName)
+ {
+ this.rowReaderClassName = newReaderClassName;
+ }
+
+ public String getRowReaderClassName()
+ {
+ return this.rowReaderClassName;
+ }
+
+
+ public synchronized RowReader getRowReader()
+ {
+ if (rowReader == null)
+ {
+ // if no RowReader has been declared, use the default reader
+ if (rowReaderClassName == null)
+ {
+ rowReader = new RowReaderDefaultImpl();
+ }
+ else
+ {
+ try
+ {
+ Class rowReaderClass = Class.forName(rowReaderClassName, true,
+ Thread.currentThread().getContextClassLoader());
+ rowReader = (RowReader) rowReaderClass.newInstance();
+ }
+ catch (Exception e)
+ {
+ throw new MetadataException(e);
+ }
+ }
+ }
+ return this.rowReader;
+ }
+
+ /**
+ * Method declaration
+ * @return
+ */
+ private String getTableName()
+ {
+ return m_TableName;
+ }
+
+ /**
+ * Answer Table name including schema BRJ
+ */
+ public String getFullTableName()
+ {
+ if (getSchema() != null)
+ return getSchema() + "." + getTableName();
+ else
+ return getTableName();
+ }
+
+ /**
+ * Method declaration
+ * @param str
+ */
+ public void setTableName(String str)
+ {
+ m_TableName = str;
+ }
+
+ /**
+ * returns the name of the described class
+ * @return String name of the described class
+ */
+ public String getClassNameOfObject()
+ {
+ return this.classname;
+ }
+
+
+ /**
+ * returns the class object of the described class
+ * @return Class the described class
+ */
+ public Class getClassOfObject()
+ {
+ if (m_Class != null)
+ {
+ return m_Class;
+ }
+ else if (classname != null)
+ {
+ try
+ {
+ m_Class = Class.forName(classname, true, Thread.currentThread().getContextClassLoader());
+ return m_Class;
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new PersistenceBrokerException(e);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * sets the class object described by this descriptor.
+ * @param c the class to describe
+ */
+ public void setClassOfObject(Class c)
+ {
+ m_Class = c;
+ this.classname = c.getName();
+ }
+
+ /**
+ * sets the name of the class described by this descriptor.
+ * @param classname the class to describe
+ */
+ public void setClassNameOfObject(String classname)
+ {
+ this.classname = classname;
+ // Shouldn't the HashMap in DescriptorRepository be updated as well?
+ }
+
+
+ /**
+ * adds a FIELDDESCRIPTOR to this ClassDescriptor.
+ * @param fld
+ */
+ public void addFieldDescriptor(FieldDescriptor fld)
+ {
+ fld.setClassDescriptor(this); // BRJ
+ if (m_FieldDescriptions == null)
+ {
+ m_FieldDescriptions = new FieldDescriptor[1];
+ m_FieldDescriptions[0] = fld;
+ m_fieldDescriptorNameMap = new HashMap();
+ }
+ else
+ {
+ int size = m_FieldDescriptions.length;
+ FieldDescriptor[] tmpArray = new FieldDescriptor[size + 1];
+ System.arraycopy(m_FieldDescriptions, 0, tmpArray, 0, size);
+ tmpArray[size] = fld;
+ m_FieldDescriptions = tmpArray;
+ // 2. Sort fields according to their getOrder() Property
+ Arrays.sort(m_FieldDescriptions, FieldDescriptor.getComparator());
+ }
+ }
+
+ /**
+ * Method declaration
+ * @return
+ */
+ public Vector getCollectionDescriptors()
+ {
+ return m_CollectionDescriptors;
+ }
+
+ /**
+ * Method declaration
+ * @param cod
+ */
+ public void addCollectionDescriptor(CollectionDescriptor cod)
+ {
+ cod.setClassDescriptor(this); // BRJ
+ m_CollectionDescriptors.add(cod);
+ }
+
+ /**
+ * Method declaration
+ * @return
+ */
+ public Vector getObjectReferenceDescriptors()
+ {
+ return m_ObjectReferenceDescriptors;
+ }
+
+ /**
+ * Method declaration
+ * @param ord
+ */
+ public void addObjectReferenceDescriptor(ObjectReferenceDescriptor ord)
+ {
+ ord.setClassDescriptor(this); // BRJ
+ m_ObjectReferenceDescriptors.add(ord);
+ }
+
+ /**
+ * Method declaration
+ * @return
+ */
+ public JdbcConnectionDescriptor getConnectionDescriptor()
+ {
+ if (m_ConnDescription == null)
+ {
+ // if class has no special JDBC Connection use the DefaultConnection
+ m_ConnDescription = this.getRepository().getDefaultJdbcConnection();
+ }
+ return m_ConnDescription;
+ }
+
+ /**
+ * Method declaration
+ * @param jcd
+ */
+ public void setConnectionDescriptor(JdbcConnectionDescriptor jcd)
+ {
+ m_ConnDescription = jcd;
+ }
+
+ /**
+ * Method declaration
+ * @param index
+ * @return
+ */
+ public FieldDescriptor getFieldDescriptorByIndex(int index)
+ {
+ return m_FieldDescriptions[index - 1];
+ }
+
+ /**
+ * Method declaration
+ * @return
+ */
+ public String toString()
+ {
+ return "table: \t"
+ + m_TableName
+ + "\n"
+ + "FieldDescriptions:\t"
+ + (m_FieldDescriptions == null ? "" : m_FieldDescriptions.toString());
+
+ }
+
+ /**
+ * Method declaration
+ * @param name
+ * @return
+ */
+ public FieldDescriptor getFieldDescriptorByName(String name)
+ {
+ if (name == null)
+ return null;
+ if (m_FieldDescriptions == null)
+ return null;
+ FieldDescriptor retval = (FieldDescriptor) m_fieldDescriptorNameMap.get(name);
+ if (retval == null)
+ {
+ int size = m_FieldDescriptions.length;
+ FieldDescriptor temp = null;
+ for (int i = 0; ((i < size) && (retval == null)); i++)
+ {
+ temp = m_FieldDescriptions[i];
+ if (name.equals(temp.getPersistentField().getName()))
+ {
+ retval = temp;
+ m_fieldDescriptorNameMap.put(name, retval);
+ break;
+ }
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Get an ObjectReferenceDescriptor by name BRJ
+ * @param name
+ * @return ObjectReferenceDescriptor or null
+ */
+ public ObjectReferenceDescriptor getObjectReferenceDescriptorByName(String name)
+ {
+ if (name == null)
+ return null;
+ ObjectReferenceDescriptor retval = (ObjectReferenceDescriptor) this.m_objectReferenceDescriptorsNameMap.get(name);
+ if (retval == null)
+ {
+ Vector descr = getObjectReferenceDescriptors();
+ int size = descr.size();
+ for (int i = 0; i < size; i++)
+ {
+ ObjectReferenceDescriptor ord = (ObjectReferenceDescriptor) descr.elementAt(i);
+ if (ord.getPersistentField().getName().equals(name))
+ {
+ retval = ord;
+ m_objectReferenceDescriptorsNameMap.put(name, retval);
+ break;
+ }
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * Get an CollectionDescriptor by name BRJ
+ * @param name
+ * @return CollectionDescriptor or null
+ */
+ public CollectionDescriptor getCollectionDescriptorByName(String name)
+ {
+ if (name == null)
+ return null;
+ CollectionDescriptor retval = (CollectionDescriptor) this.m_collectionDescriptorNameMap.get(name);
+ if (retval == null)
+ {
+ Vector descr = getCollectionDescriptors();
+ int size = descr.size();
+ for (int i = 0; i < size; i++)
+ {
+ CollectionDescriptor ord = (CollectionDescriptor) descr.elementAt(i);
+ if (ord.getPersistentField().getName().equals(name))
+ {
+ retval = ord;
+ m_collectionDescriptorNameMap.put(name, retval);
+ break;
+ }
+ }
+ }
+ return retval;
+ }
+
+ /**
+ * returns the transaction isolation level to be used for this class. Used only in the ODMG server
+ */
+ public int getIsolationLevel()
+ {
+ return m_IsolationLevel;
+ }
+
+ /**
+ * Method declaration
+ * @param isoLevel
+ */
+ public void setIsolationLevel(int isoLevel)
+ {
+ m_IsolationLevel = isoLevel;
+ }
+
+
+ /**
+ * add an Extent class to the current descriptor
+ * @param newExtendClass
+ */
+ public void addExtentClass(Class newExtendClass)
+ {
+ extentClasses.add(newExtendClass);
+ this.addExtentClassName(newExtendClass.getName());
+ }
+
+ /**
+ * add an Extent class to the current descriptor
+ * @param newExtendClassName name of the class to add
+ */
+ public void addExtentClassName(String newExtendClassName)
+ {
+ extentClassNames.add(newExtendClassName);
+ m_repository.addExtent(newExtendClassName, this);
+ }
+
+ public void setSuperClass(String classname)
+ {
+ this.superClass = classname;
+
+
+ }
+
+ public void setSuperClassFieldRef(int fieldId)
+ {
+ this.superClassFieldRef = fieldId;
+ }
+
+ public int getSuperClassFieldRef()
+ {
+ return superClassFieldRef;
+ }
+
+ public String getSuperClass()
+ {
+ return superClass;
+ }
+
+ /**
+ * returns a Constructor that takes all persistent attributes
+ * of the class as arguments.
+ * Returns null, if such a constructor does not exist.
+ * PersistenceBroker clients are not urged to implement such constructors
+ * for persistence capable classes. But it's strongly recommended as
+ * it minimizes the overhead for reflective operations.
+ */
+ public Constructor getConstructor()
+ {
+ if (multiArgumentConstructor == null && !alreadyLookedup)
+ {
+ if (argsForConstructor == null)
+ {
+ argsForConstructor = new Class[getFieldDescriptions().length];
+ for (int i = 0; i < getFieldDescriptions().length; i++)
+ {
+ argsForConstructor[i] = getFieldDescriptions()[i].getPersistentField().getType();
+ }
+ }
+ try
+ {
+ multiArgumentConstructor = getClassOfObject().getConstructor(argsForConstructor);
+ }
+ catch (Exception ignored)
+ {
+ // this exception is thrown, if no suitable Constructor was
+ // found. In this case we tell the user that it is better to have
+ // a multiargs constructor defined
+ String args = "";
+ for (int i = 0; i < argsForConstructor.length; i++)
+ {
+ args += ((args.length() == 0) ? "(" : ", ");
+ args += argsForConstructor[i].getName();
+ }
+ args += ")";
+ LoggerFactory.getDefaultLogger().warn(
+ "Please define a public constructor for "
+ + this.getClassOfObject()
+ + "\nwith the following signature: "
+ + args
+ + ".\nIt must initialize the classes persistent attributes. This is recommended to increase performance but it's not mandatory!");
+ }
+ alreadyLookedup = true;
+ }
+ return multiArgumentConstructor;
+ }
+
+ /**
+ * return all classes in this extent.
+ * Creation date: (02.02.2001 17:49:11)
+ * @return java.util.Vector
+ */
+ public synchronized Vector getExtentClasses()
+ {
+ if (extentClassNames.size() > extentClasses.size())
+ {
+ extentClasses.clear();
+ for (Iterator iter = extentClassNames.iterator(); iter.hasNext();)
+ {
+ String classname = (String) iter.next();
+ Class extentClass;
+ try
+ {
+ extentClass = Class.forName(classname, true,
+ Thread.currentThread().getContextClassLoader());
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new MetadataException("Unable to load class [" + classname + "]. Make sure it is available on the classpath.", e);
+ }
+ extentClasses.add(extentClass);
+ }
+ }
+ return extentClasses;
+ }
+
+ /**
+ * Return the names of all classes in this extent
+ * @return java.util.Vector a Vector containing the fully qualified names
+ * of all classes in this extent
+ */
+ public synchronized Vector getExtentClassNames()
+ {
+ return this.extentClassNames;
+ }
+
+ /**
+ * Insert the method's description here.
+ * Creation date: (26.01.2001 09:20:09)
+ * @return java.lang.Class
+ */
+ public synchronized java.lang.Class getProxyClass()
+ {
+
+ if ((proxyClass == null) && (proxyClassName != null))
+ {
+ String dynamic = "dynamic";
+ if (dynamic.equalsIgnoreCase(proxyClassName))
+ {
+ proxyClass = getDynamicProxyClass();
+ }
+ else
+ {
+ try
+ {
+ proxyClass = Class.forName(proxyClassName, true,
+ Thread.currentThread().getContextClassLoader());
+ }
+ catch (ClassNotFoundException e)
+ {
+ throw new MetadataException(e);
+ }
+ }
+ }
+ return proxyClass;
+ }
+
+ /**
+ * Insert the method's description here.
+ * Creation date: (02.02.2001 17:49:11)
+ * @return boolean
+ */
+ public boolean isExtent()
+ {
+ return (getExtentClassNames().size() > 0);
+ }
+
+ /**
+ * Insert the method's description here.
+ * Creation date: (02.02.2001 17:49:11)
+ * @return boolean
+ */
+ public boolean isInterface()
+ {
+ return isInterface;
+ }
+
+ /**
+ * Insert the method's description here.
+ * Creation date: (02.02.2001 17:49:11)
+ * @param newIsInterface boolean
+ */
+ public void setIsInterface(boolean newIsInterface)
+ {
+ isInterface = newIsInterface;
+ }
+
+ /**
+ * @return boolean true if the mapped class is abstract
+ */
+ public boolean isAbstract()
+ {
+ return Modifier.isAbstract(getClassOfObject().getModifiers());
+ }
+
+ /**
+ * Sets the proxy class to be used.
+ * @param newProxyClass java.lang.Class
+ */
+ public void setProxyClass(java.lang.Class newProxyClass)
+ {
+ proxyClass = newProxyClass;
+ if (proxyClass == null)
+ setProxyClassName(null);
+ else
+ proxyClassName = proxyClass.getName();
+ }
+
+ /**
+ * Sets the name of the proxy class to be used.
+ * using "dynamic" instead of a real classname
+ * will result in usage of dynamic proxies.
+ * @param newProxyClassName the classname or "dynamic"
+ */
+ public void setProxyClassName(String newProxyClassName)
+ {
+ proxyClassName = newProxyClassName;
+ }
+
+ /**
+ * Get the name of the proxy class. This method doesn't try to access
+ * the real class, so it can be called even if the class doesn't exist.
+ */
+ public String getProxyClassName()
+ {
+ return proxyClassName;
+ }
+
+ /**
+ * returns a vector containing values for all the Objects attribute
+ * @throws MetadataException if tehre is an erros accessing obj field values
+ */
+ public Object[] getAllValues(Object obj) throws PersistenceBrokerException
+ {
+ FieldDescriptor[] allFields = getFieldDescriptions();
+ Object[] result = new Object[allFields.length];
+
+ for (int i = 0; i < allFields.length; i++)
+ {
+ FieldDescriptor fmd = allFields[i];
+ PersistentField f = fmd.getPersistentField();
+ Object cv = f.get(obj);
+
+ // handle autoincrement attributes if not filled
+ if (fmd.isAutoIncrement())
+ {
+ cv = getAutoIncrementValue(fmd, obj, cv);
+ }
+
+ // apply type and value mapping
+ cv = fmd.getFieldConversion().javaToSql(cv);
+ result[i] = cv;
+ }
+ return result;
+ }
+
+ /**
+ * returns array of all FieldDescriptors.
+ * @return FIELDDESCRIPTOR[]
+ */
+ public FieldDescriptor[] getFieldDescriptions()
+ {
+ return m_FieldDescriptions;
+ }
+
+ /**
+ * returns an Array with an Objects PK VALUES, with any java-to-sql
+ * FieldConversion applied
+ * @throws MetadataException if there is an erros accessing o field values
+ */
+ public Object[] getKeyValues(Object o) throws PersistenceBrokerException
+ {
+ return getKeyValues(o, true);
+ }
+
+ /**
+ * returns an Array with an Objects PK VALUES
+ * if convertToSql is true, any associated java-to-sql conversions are applied
+ * @throws MetadataException if there is an erros accessing o field values
+ */
+ public Object[] getKeyValues(Object o, boolean convertToSql) throws PersistenceBrokerException
+ {
+ FieldDescriptor[] pkFields = getPkFields();
+ Object[] result = new Object[pkFields.length];
+
+ for (int i = 0; i < result.length; i++)
+ {
+ FieldDescriptor fmd = pkFields[i];
+ PersistentField f = fmd.getPersistentField();
+ Object cv = f.get(o);
+
+ // handle autoincrement attributes if not filled
+ if (fmd.isAutoIncrement())
+ {
+ cv = getAutoIncrementValue(fmd, o, cv);
+ }
+
+ if (convertToSql)
+ {
+ // BRJ : apply type and value mapping
+ cv = fmd.getFieldConversion().javaToSql(cv);
+ }
+ result[i] = cv;
+ }
+ return result;
+ }
+
+ /**
+ * returns an Array with an Objects CURRENT locking VALUES , BRJ
+ * @throws MetadataException if there is an erros accessing o field values
+ */
+ public Object[] getCurrentLockingValues(Object o) throws PersistenceBrokerException
+ {
+ FieldDescriptor[] fields = getLockingFields();
+ Object[] result = new Object[fields.length];
+ for (int i = 0; i < result.length; i++)
+ {
+ FieldDescriptor fmd = fields[i];
+ PersistentField f = fmd.getPersistentField();
+ Object cv = null;
+ cv = f.get(o); // retrieve the Objects value for the specified field
+ result[i] = cv;
+ }
+ return result;
+ }
+
+ /**
+ * updates the values for locking fields , BRJ
+ * handles int, long, Timestamp
+ * @throws MetadataException if there is an erros accessing obj field values
+ */
+ public void updateLockingValues(Object obj) throws PersistenceBrokerException
+ {
+ FieldDescriptor[] fields = getLockingFields();
+ for (int i = 0; i < fields.length; i++)
+ {
+ FieldDescriptor fmd = fields[i];
+ PersistentField f = fmd.getPersistentField();
+ Object cv = null;
+ cv = f.get(obj);
+
+ // int
+ if ((f.getType() == int.class) || (f.getType() == Integer.class))
+
+ {
+ int newCv = 0;
+ if (cv != null)
+ {
+ newCv = ((Number) cv).intValue();
+ }
+ newCv++;
+ f.set(obj, new Integer(newCv));
+ }
+ // long
+ else if ((f.getType() == long.class) || (f.getType() == Long.class))
+
+ {
+ long newCv = 0;
+ if (cv != null)
+ {
+ newCv = ((Number) cv).longValue();
+ }
+ newCv++;
+ f.set(obj, new Long(newCv));
+ }
+ // Timestamp
+ else if (f.getType() == Timestamp.class)
+
+ {
+ long newCv = (new Date()).getTime();
+ f.set(obj, new Timestamp(newCv));
+ }
+ }
+ }
+
+ /**
+ * @throws MetadataException if there is an erros accessing obj field values
+ */
+ private Object getAutoIncrementValue(FieldDescriptor fmd, Object obj, Object cv)
+ {
+ if ((cv == null) || ((cv instanceof Number) && (((Number) cv).intValue() == 0)))
+ {
+ PersistentField f = fmd.getPersistentField();
+ Object result = cv;
+ PersistenceBroker broker = null;
+ try
+ {
+ if (m_repository != null)
+ {
+ // arminw
+ // use the PBKey of the associated descriptor repository
+ // to match the 'correct' repository
+ /* @todo maybe this could be critical in some
+ * situations, e.g. if the associated PBKey was always the
+ * default PBKey. Check this out.
+ */
+ broker = PersistenceBrokerFactory.createPersistenceBroker(m_repository.getPBkey());
+ }
+ else
+ {
+ // no repository, we use the default PB
+ broker = PersistenceBrokerFactory.defaultPersistenceBroker();
+ }
+ // int
+ if ((f.getType() == int.class) || (f.getType() == Integer.class))
+ {
+ if ((f.get(obj) == null) || (((Number) f.get(obj)).intValue() == 0))
+ {
+ /*
+ arminw
+ old version
+ Class extent = broker.getExtentClass(this.getClassOfObject());
+ result = new Integer(broker.getUniqueId(extent, f.getName()));
+
+ we should not give the top-level extent to sequence manager,
+ sequence manager itself should take care of uniqueness over the extents
+ */
+ result = new Integer(broker.getUniqueId(fmd));
+ // reflect autoincrement value back into object
+ f.set(obj, result);
+ }
+ }
+ // long
+ else if ((f.getType() == long.class) || (f.getType() == Long.class))
+ {
+ if ((f.get(obj) == null) || (((Number) f.get(obj)).longValue() == 0))
+ {
+ /*
+ arminw
+ old version
+ Class extent = broker.getExtentClass(this.getClassOfObject());
+ result = new Long(broker.getUniqueLong(extent, f.getName()));
+
+ we should not give the top-level extent to sequence manager,
+ sequence manager itself should take care of uniqueness over the extents
+ */
+
+ result = new Long(broker.getUniqueLong(fmd));
+ // reflect autoincrement value back into object
+ f.set(obj, result);
+ }
+ }
+ // String
+ else if (String.class.isAssignableFrom(f.getType()))
+ {
+ if (f.get(obj) == null)
+ {
+ result = broker.getUniqueString(fmd);
+ // reflect autoincrement value back into object
+ f.set(obj, result);
+ }
+ }
+ // Object
+ else if (!f.getType().isPrimitive())
+ {
+ // only assign a value if attribute == null
+ if (f.get(obj) == null)
+ {
+ result = broker.getUniqueObject(fmd);
+ if (result != null)
+ {
+ // reflect autoincrement value back into object
+ f.set(obj, result);
+ }
+ else
+ {
+ throw new OJBRuntimeException(
+ "OJB ERROR: Dont know how to autoincrement field " +
+ f.getDeclaringClass() + "#" + f.getName());
+ }
+ }
+ }
+ else
+ {
+ throw new OJBRuntimeException(
+ "OJB ERROR: Dont know how to autoincrement field " +
+ f.getDeclaringClass() + "#" + f.getName());
+ }
+ return result;
+ }
+ catch (MetadataException e)
+ {
+ throw new OJBRuntimeException(
+ "Error while trying to autoincrement field " +
+ f.getDeclaringClass() + "#" + f.getName(), e);
+ }
+ finally
+ {
+ if (broker != null)
+ {
+ broker.close();
+ }
+ }
+ }
+ else
+ {
+ return cv;
+ }
+
+ }
+
+ /**
+ * returns an Array with an Objects NON-PK VALUES
+ * @throws MetadataException if there is an erros accessing o field values
+ */
+ public Object[] getNonKeyValues(Object o) throws PersistenceBrokerException
+ {
+ FieldDescriptor[] nonPkFields = getNonPkFields();
+ Object[] result = new Object[nonPkFields.length];
+
+ for (int i = 0; i < result.length; i++)
+ {
+ FieldDescriptor fmd = nonPkFields[i];
+ PersistentField f = fmd.getPersistentField();
+ Object cv = f.get(o);
+
+ // handle autoincrement attributes if not filled
+ if (fmd.isAutoIncrement())
+ {
+ cv = getAutoIncrementValue(fmd, o, cv);
+ }
+
+ // apply type and value conversion
+ cv = fmd.getFieldConversion().javaToSql(cv);
+ result[i] = cv;
+ }
+ return result;
+ }
+
+ /**
+ * return an array of PK FieldDescription sorted ascending
+ * according to the field-descriptions getOrder() property
+ */
+ public FieldDescriptor[] getNonPkFields()
+ {
+ if (nonPrimaryKeyFieldDescriptors == null)
+ {
+ // 1. collect all Primary Key fields from Field list
+ Vector vec = new Vector();
+ for (int i = 0; i < m_FieldDescriptions.length; i++)
+ {
+ FieldDescriptor fmd = m_FieldDescriptions[i];
+ if (!fmd.isPrimaryKey())
+ {
+ vec.add(fmd);
+ }
+ }
+ // 2. Sort fields according to their getOrder() Property
+ Collections.sort(vec, FieldDescriptor.getComparator());
+ nonPrimaryKeyFieldDescriptors = (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
+ }
+ return nonPrimaryKeyFieldDescriptors;
+ }
+
+ /**
+ * return an array of PK FieldDescription sorted ascending
+ * according to the field-descriptions getOrder() property
+ */
+ public FieldDescriptor[] getPkFields()
+ {
+ if (primaryKeyFieldDescriptors == null)
+ {
+ // 1. collect all Primary Key fields from Field list
+ Vector vec = new Vector();
+ FieldDescriptor[] fields = null;
+ // 1.a if descriptor describes an interface: take PK fields from an implementors ClassDescriptor
+ if (isInterface)
+ {
+ if (getExtentClasses().size() == 0)
+ {
+ throw new PersistenceBrokerException(
+ "No Implementors declared for interface " + this.getClassOfObject().getName());
+ }
+ Class implementor = (Class) getExtentClasses().get(0);
+ ClassDescriptor implCld = this.getRepository().getDescriptorFor(implementor);
+ primaryKeyFieldDescriptors = implCld.getPkFields();
+ return primaryKeyFieldDescriptors;
+ }
+ // 1.b if not an interface The classdescriptor must have FieldDescriptors
+ else
+ {
+ fields = this.getFieldDescriptions();
+ }
+
+ // now collect all PK fields
+ for (int i = 0; i < fields.length; i++)
+ {
+ FieldDescriptor fmd = fields[i];
+ if (fmd.isPrimaryKey())
+ {
+ vec.add(fmd);
+ }
+ }
+ // 2. Sort fields according to their getOrder() Property
+ Collections.sort(vec, FieldDescriptor.getComparator());
+ primaryKeyFieldDescriptors = (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
+ }
+ return primaryKeyFieldDescriptors;
+ }
+
+ /**
+ * return an array of FieldDescription for optimistic locking sorted ascending
+ * according to the field-descriptions getOrder() property
+ */
+ public FieldDescriptor[] getLockingFields()
+ {
+ if (lockingFieldDescriptors == null)
+ {
+ // 1. collect all Primary Key fields from Field list
+ Vector vec = new Vector();
+ for (int i = 0; i < m_FieldDescriptions.length; i++)
+ {
+ FieldDescriptor fmd = m_FieldDescriptions[i];
+ if (fmd.isLocking())
+ {
+ vec.add(fmd);
+ }
+ }
+ // 2. Sort fields according to their getOrder() Property
+ Collections.sort(vec, FieldDescriptor.getComparator());
+ lockingFieldDescriptors = (FieldDescriptor[]) vec.toArray(new FieldDescriptor[vec.size()]);
+ }
+ return lockingFieldDescriptors;
+ }
+
+ /**
+ * returns a dynamic Proxy that implements all interfaces of the
+ * class described by this ClassDescriptor.
+ *
+ * @return Class the dynamically created proxy class
+ */
+ public Class getDynamicProxyClass()
+ {
+ Class clazz = getClassOfObject();
+ Class superClass = clazz;
+ Class[] interfaces = clazz.getInterfaces();
+
+ // clazz can be an interface itself and when getInterfaces()
+ // is called on an interface it returns only the extending
+ // interfaces, not the interface itself.
+ if (clazz.isInterface())
+ {
+ Class[] tempInterfaces = new Class[interfaces.length + 1];
+ tempInterfaces[0] = clazz;
+
+ System.arraycopy(interfaces, 0, tempInterfaces, 1, interfaces.length);
+ interfaces = tempInterfaces;
+ }
+
+ // add all interfaces implemented by superclasses to the interfaces array
+ while ((superClass = superClass.getSuperclass()) != null)
+ {
+ Class[] superInterfaces = superClass.getInterfaces();
+ Class[] combInterfaces = new Class[interfaces.length + superInterfaces.length];
+ System.arraycopy(interfaces, 0, combInterfaces, 0, interfaces.length);
+ System.arraycopy(superInterfaces, 0, combInterfaces, interfaces.length, superInterfaces.length);
+ interfaces = combInterfaces;
+ }
+
+ /**
+ * Must remove duplicate interfaces before calling Proxy.getProxyClass().
+ * Duplicates can occur if a subclass re-declares that it implements
+ * the same interface as one of its ancestor classes.
+ **/
+ HashMap unique = new HashMap();
+ for (int i = 0; i < interfaces.length; i++)
+ {
+ unique.put(interfaces[i].getName(), interfaces[i]);
+ }
+ interfaces = (Class[]) unique.values().toArray(new Class[unique.size()]);
+ // return dynymic Proxy Class implementing all interfaces
+ Class proxyClass = Proxy.getProxyClass(clazz.getClassLoader(), interfaces);
+
+ return proxyClass;
+ }
+
+ /**
+ * return true if optimistic locking is used
+ */
+ public boolean isLocking()
+ {
+ return getLockingFields().length > 0;
+ }
+
+ /**
+ * Gets the repository.
+ * @return Returns a DescriptorRepository
+ */
+ public DescriptorRepository getRepository()
+ {
+ return m_repository;
+ }
+
+ /**
+ * Sets the repository.
+ * @param repository The repository to set
+ */
+ public void setRepository(DescriptorRepository repository)
+ {
+ m_repository = repository;
+ }
+
+ /**
+ * Gets the schema.
+ * @return Returns a String
+ */
+ public String getSchema()
+ {
+ return schema;
+ }
+
+ /**
+ * Sets the schema.
+ * @param schema The schema to set
+ */
+ public void setSchema(String schema)
+ {
+ this.schema = schema;
+ }
+
+ /**
+ * Gets the IndexDescriptors used for DDL generation.
+ */
+ public Vector getIndexes()
+ {
+ return indexes;
+ }
+
+ /**
+ * Sets the IndexDescriptors used for DDL generation.
+ */
+ public void setIndexes(Vector indexes)
+ {
+ this.indexes = indexes;
+ }
+
+ /**
+ * return the FieldDescriptor for the Attribute referenced in the path<br>
+ * the path may contain simple attribut names, functions and path expressions
+ * using relationships <br>
+ * ie: name, avg(price), adress.street
+ * @param aPath the path to the attribute
+ * @return the FieldDescriptor or null (ie: for m:n queries)
+ */
+ public FieldDescriptor getFieldDescriptorForPath(String aPath)
+ {
+ ArrayList desc = getAttributeDescriptorsForPath(aPath);
+ FieldDescriptor fld = null;
+ Object temp;
+
+ if (!desc.isEmpty())
+ {
+ temp = desc.get(desc.size() - 1);
+ if (temp instanceof FieldDescriptor)
+ {
+ fld = (FieldDescriptor) temp;
+ }
+ }
+ return fld;
+ }
+
+
+ /**
+ * return all AttributeDescriptors for the path<br>
+ * ie: partner.addresses.street returns a Collection of 3 AttributeDescriptors
+ * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
+ * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
+ * (ObjectReferenceDescriptor, CollectionDescriptor)
+ * @param aPath the cleaned path to the attribute
+ * @return ArrayList of AttributeDescriptors
+ */
+ public ArrayList getAttributeDescriptorsForPath(String aPath)
+ {
+ return getAttributeDescriptorsForCleanPath(cleanPath(aPath));
+ }
+
+ /**
+ * return all AttributeDescriptors for the path<br>
+ * ie: partner.addresses.street returns a Collection of 3 AttributeDescriptors
+ * (ObjectReferenceDescriptor, CollectionDescriptor, FieldDescriptor)<br>
+ * ie: partner.addresses returns a Collection of 2 AttributeDescriptors
+ * (ObjectReferenceDescriptor, CollectionDescriptor)
+ * @param aPath the cleaned path to the attribute
+ * @return ArrayList of AttributeDescriptors
+ */
+ private ArrayList getAttributeDescriptorsForCleanPath(String aPath)
+ {
+ ArrayList result = new ArrayList();
+ ClassDescriptor cld = this;
+ ObjectReferenceDescriptor ord = null;
+ FieldDescriptor fld = null;
+ String currPath = aPath;
+ String segment;
+ int sepPos;
+
+ while (currPath.length() > 0)
+ {
+ sepPos = currPath.indexOf(".");
+ if (sepPos >= 0)
+ {
+ segment = currPath.substring(0, sepPos);
+ currPath = currPath.substring(sepPos + 1);
+ }
+ else
+ {
+ segment = currPath;
+ currPath = "";
+ }
+
+ // look for 1:1 or n:1 Relationship
+ ord = cld.getObjectReferenceDescriptorByName(segment);
+ if (ord == null)
+ {
+ // look for 1:n or m:n Relationship
+ ord = cld.getCollectionDescriptorByName(segment);
+ }
+
+ if (ord != null)
+ {
+ cld = cld.getRepository().getDescriptorFor(ord.getItemClass());
+ result.add(ord);
+ }
+ else
+ {
+ // look for Field
+ fld = cld.getFieldDescriptorByName(segment);
+ if (fld != null)
+ {
+ result.add(fld);
+ }
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * remove functions and () from path
+ * ie: avg(amount) -> amount <br>
+ * ie: sum(accounts.amount) -> accounts.amount
+ * @param aPath the path to the attribute
+ */
+ public static String cleanPath(String aPath)
+ {
+ int braceBegin;
+ int braceEnd;
+
+ if (aPath == null)
+ {
+ return aPath;
+ }
+
+ braceBegin = aPath.indexOf("(");
+ braceEnd = aPath.lastIndexOf(")");
+ if (braceBegin >= 0 && braceEnd >= 0)
+ {
+ return aPath.substring(braceBegin + 1, braceEnd).trim();
+ }
+ else
+ {
+ return aPath;
+ }
+
+ }
+
+
+ /*
+ * @see XmlCapable#toXML()
+ */
+ public String toXML()
+ {
+ RepositoryTags tags = RepositoryTags.getInstance();
+ String eol = System.getProperty("line.separator");
+
+ // comment on class
+ String result = eol + " <!-- Mapping for Class " + this.getClassNameOfObject() + " -->" + eol;
+
+ // opening tag and attributes
+ result += " " + tags.getOpeningTagNonClosingById(CLASS_DESCRIPTOR) + eol;
+
+ // class
+ result += " " + tags.getAttribute(CLASS_NAME, this.getClassNameOfObject()) + eol;
+
+ // isolation level is optional
+ if (getIsolationLevel() != this.getRepository().getDefaultIsolationLevel())
+ {
+ result += " " + tags.getAttribute(ISOLATION_LEVEL, this.isolationLevelXml()) + eol;
+ }
+
+
+ Class theProxyClass = null;
+ try
+ {
+ theProxyClass = this.getProxyClass();
+ }
+ catch (Throwable t)
+ {
+ // Ignore this exception, just try to get the Class object of the
+ // proxy class in order to be able to decide, whether the class
+ // is a dynamic proxy or not.
+ }
+
+ // proxy is optional
+ if (theProxyClass != null && Proxy.isProxyClass(theProxyClass))
+ {
+ result += " " + tags.getAttribute(CLASS_PROXY, "dynamic") + eol;
+ }
+ else
+ {
+ result += " " + tags.getAttribute(CLASS_PROXY, this.getProxyClassName()) + eol;
+ }
+
+ // schema is optional
+ if (this.getSchema() != null)
+ {
+ result += " " + tags.getAttribute(SCHEMA_NAME, this.getSchema()) + eol;
+ }
+
+ // table name
+ if (this.getTableName() != null)
+ {
+ result += " " + tags.getAttribute(TABLE_NAME, this.getTableName()) + eol;
+ }
+
+ // rowreader is optional
+ if (this.getRowReaderClassName() != null)
+ {
+ result += " " + tags.getAttribute(ROW_READER, this.getRowReaderClassName()) + eol;
+ }
+
+ //accept-locks is optional, enabled by default
+ if (!this.acceptLocks)
+ {
+ result += " " + tags.getAttribute(ACCEPT_LOCKS,"false") + eol;
+ }
+ // sequence manager attribute not yet implemented
+
+ result += " >" + eol;
+
+ // end of attributes
+
+ // begin of elements
+ if (isInterface())
+ {
+ // extent-class
+ for (int i = 0; i < getExtentClassNames().size(); i++)
+ {
+ result += " " + tags.getOpeningTagNonClosingById(CLASS_EXTENT) + " ";
+ result += tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString());
+ result += " />" + eol;
+ }
+ }
+ else
+ {
+ // class extent is optional
+ if (isExtent())
+ {
+ for (int i = 0; i < getExtentClassNames().size(); i++)
+ {
+ result += " " + tags.getOpeningTagNonClosingById(CLASS_EXTENT) + " ";
+ result += tags.getAttribute(CLASS_REF, getExtentClassNames().get(i).toString());
+ result += " />" + eol;
+ }
+ }
+
+ // write all FieldDescriptors
+ FieldDescriptor[] fields = getFieldDescriptions();
+ for (int i = 0; i < fields.length; i++)
+ {
+ result += fields[i].toXML();
+ }
+
+ // write optional ReferenceDescriptors
+ Vector refs = getObjectReferenceDescriptors();
+ for (int i = 0; i < refs.size(); i++)
+ {
+ result += ((ObjectReferenceDescriptor) refs.get(i)).toXML();
+ }
+
+ // write optional CollectionDescriptors
+ Vector cols = getCollectionDescriptors();
+ for (int i = 0; i < cols.size(); i++)
+ {
+ result += ((CollectionDescriptor) cols.get(i)).toXML();
+ }
+
+ }
+
+ result += " " + tags.getClosingTagById(CLASS_DESCRIPTOR);
+ return result;
+ }
+
+ private String isolationLevelXml()
+ {
+ switch (this.getIsolationLevel())
+ {
+ case (IL_OPTIMISTIC):
+ {
+ return LITERAL_IL_OPTIMISTIC;
+ }
+ case (IL_READ_COMMITTED):
+ {
+ return LITERAL_IL_READ_COMMITTED;
+ }
+ case (IL_READ_UNCOMMITTED):
+ {
+ return LITERAL_IL_READ_UNCOMMITTED;
+ }
+ case (IL_REPEATABLE_READ):
+ {
+ return LITERAL_IL_REPEATABLE_READ;
+ }
+ case (IL_SERIALIZABLE):
+ {
+ return LITERAL_IL_SERIALIZABLE;
+ }
+ default :
+ {
+ return LITERAL_IL_READ_UNCOMMITTED;
+ }
+
+ }
+
+ }
+
+ /**
+ * Returns the first found autoincrement field
+ * defined in this class descriptor. Use carefully
+ * when multiple autoincrement field were defined.
+ */
+ public FieldDescriptor getAutoIncrementField()
+ {
+ if (m_autoIncrementField == null)
+ {
+ FieldDescriptor[] fds = getPkFields();
+
+ for (int i = 0; i < fds.length; i++)
+ {
+ FieldDescriptor fd = fds[i];
+ if (fd.isAutoIncrement())
+ {
+ m_autoIncrementField = fd;
+ break;
+ }
+ }
+ }
+ if(m_autoIncrementField == null)
+ {
+ LoggerFactory.getDefaultLogger().warn(
+ "Could not found autoincrement attribute for class: " + this.getClassNameOfObject());
+ }
+ return m_autoIncrementField;
+ }
+
+ /**
+ *
+ * @return this classes FieldDescriptor's as well as it's parents and so on and so on
+ */
+ public FieldDescriptor[] getFieldDescriptorsInHeirarchy()
+ {
+ if (superClass == null)
+ {
+ return getFieldDescriptions();
+ }
+ ClassDescriptor cldSuper = getRepository().getDescriptorFor(superClass);
+ return appendFieldDescriptorArrays(getFieldDescriptions(), cldSuper.getFieldDescriptorsInHeirarchy());
+ }
+
+ private FieldDescriptor[] appendFieldDescriptorArrays(FieldDescriptor[] fieldDescriptions, FieldDescriptor[] fieldDescriptorsInHeirarchy)
+ {
+ // take the 2 arrays and add them into one
+ int size = fieldDescriptions.length + fieldDescriptorsInHeirarchy.length;
+ FieldDescriptor[] newArray = new FieldDescriptor[size];
+ int i;
+ int j = 0;
+ for (i = 0; i < fieldDescriptions.length; i++, j++)
+ {
+ FieldDescriptor fieldDescription = fieldDescriptions[i];
+ newArray[j] = fieldDescription;
+ }
+ for (i = 0; i < fieldDescriptorsInHeirarchy.length; i++, j++)
+ {
+ FieldDescriptor fieldDescription = fieldDescriptorsInHeirarchy[i];
+ newArray[j] = fieldDescription;
+ }
+
+ return newArray;
+ }
+
+ /**
+ * convenience function to get the first primary key
+ * <p>
+ * useful when there is only one
+ * @return
+ */
+ public FieldDescriptor getPrimaryKey()
+ {
+ FieldDescriptor[] fds = getPkFields();
+ if (fds != null && fds.length > 0)
+ {
+ return fds[0];
+ }
+ return null;
+ }
+
+ /**
+ * Returns acceptLocks.
+ * @return boolean
+ */
+ public boolean isAcceptLocks()
+ {
+ return acceptLocks;
+ }
+
+ /**
+ * Sets acceptLocks.
+ * @param m_acceptLocks The m_acceptLocks to set
+ */
+ public void setAcceptLocks(boolean acceptLocks)
+ {
+ this.acceptLocks = acceptLocks;
+ }
+
+
+
+
+}