Package org.apache.ojb.broker

Source Code of org.apache.ojb.broker.Identity

package org.apache.ojb.broker;

/* Copyright 2002-2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import org.apache.ojb.broker.metadata.ClassDescriptor;
import org.apache.ojb.broker.metadata.ClassNotPersistenceCapableException;
import org.apache.ojb.broker.core.ValueContainer;
import org.apache.ojb.broker.core.proxy.IndirectionHandler;
import org.apache.ojb.broker.core.proxy.ProxyHelper;
import org.apache.ojb.broker.util.BrokerHelper;
import org.apache.commons.lang.builder.HashCodeBuilder;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Arrays;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
* represents the identity of an object.
* identity (it's primary keys) must be unique accross extents !
*
* @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
* @version $Id: Identity.java,v 1.36 2004/04/09 13:22:30 tomdz Exp $
*/
public class Identity implements Serializable
{
  static final long serialVersionUID = 3182285550574178710L;

    /**
     * the top-level Class of the identified object<br>
     * ie: an Interface
     */
    private Class m_objectsTopLevelClass;

    /**
     * the real Class of the identified object<br>
     * ie: the implementing Class
     */
    private Class m_objectsRealClass = null;

    /**
     * The ordered list of primary key values maintaining the objects identity in the underlying RDBMS
     */
    private Object[] m_pkValues;

    /*
    In distributed enviroments the Identity object have to recalculate the
    hashCode and toString values, because the hash code of the Class object
    differs in different JVM
    */
    private transient String m_stringRepresentation = null;
    private transient Integer m_hashCode;

    /**
     * creates an Identity from a class and the objects primary key values.
     * used for the definition of proxies.
     *
     * @param realClass the concrete class of the object, or null if not known.
     * @param topLevel the highest persistence-capable class or
     * interface (in the inheritance hierarchy) that the identified object is an instance of
     * @param pkValues (unique across the extents !)
    */
    public Identity(Class realClass, Class topLevel, Object[] pkValues)
    {
        m_objectsTopLevelClass = topLevel;
        m_objectsRealClass = realClass;
        m_pkValues = pkValues;
        checkForPrimaryKeys();
    }

    public Identity(Object objectToIdentitify, PersistenceBroker targetBroker)
    {
        init(objectToIdentitify, targetBroker, null);
    }

    public Identity(Object objectToIdentitify, PersistenceBroker targetBroker, ClassDescriptor cld)
    {
        init(objectToIdentitify, targetBroker, cld);
    }

    private void init(Object objectToIdentify, PersistenceBroker targetBroker, ClassDescriptor cld)
    {
        if(objectToIdentify == null) throw new OJBRuntimeException("Can't create Identity for 'null'-object");
        try
        {
            IndirectionHandler handler = ProxyHelper.getIndirectionHandler(objectToIdentify);

            if (handler != null)
            {
                Identity sourceOID = handler.getIdentity();
                m_objectsTopLevelClass = sourceOID.m_objectsTopLevelClass;
                m_objectsRealClass = sourceOID.m_objectsRealClass;
                m_pkValues = sourceOID.m_pkValues;
            }
            else
            {
                if (cld == null)
                {
                    cld = targetBroker.getClassDescriptor(objectToIdentify.getClass());
                }

                // identities must be unique accross extents !
                m_objectsTopLevelClass = targetBroker.getTopLevelClass(objectToIdentify.getClass());
                m_objectsRealClass = objectToIdentify.getClass();

                // BRJ: definitely do NOT convertToSql
                // conversion is done when binding the sql-statement
                BrokerHelper helper = targetBroker.serviceBrokerHelper();
                m_pkValues = helper.extractValueArray( helper.getKeyValues(cld, objectToIdentify, false) );
            }

            checkForPrimaryKeys();
        }
        catch (Exception e)
        {
            throw new ClassNotPersistenceCapableException("Can not init Identity for given object " +
                    objectToIdentify, e);
        }
    }

    /**
     * Factory method that returns an Identity object from the given
     * byte array - see {@link #serialize}.
     */
    public static Identity fromByteArray(byte[] anArray) throws PersistenceBrokerException
    {
        // reverse of the serialize() algorithm:
        // read from byte[] with a ByteArrayInputStream, decompress with
        // a GZIPInputStream and then deserialize by reading from the ObjectInputStream
        try
        {
            ByteArrayInputStream bais = new ByteArrayInputStream(anArray);
            GZIPInputStream gis = new GZIPInputStream(bais);
            ObjectInputStream ois = new ObjectInputStream(gis);
            Identity result = (Identity) ois.readObject();
            ois.close();
            gis.close();
            bais.close();
            return result;
        }
        catch (Exception ex)
        {
            throw new PersistenceBrokerException(ex);
        }
    }

    /**
     * Return the top-level class of the real
     * subject (means class name of a base class,
     * base interface denoted in the repository or
     * objects real class name if none top-level was found)
     *
     */
    public Class getObjectsTopLevelClass()
    {
        return m_objectsTopLevelClass;
    }

    /**
     * Return the "real" Class of the real subject
     */
    public Class getObjectsRealClass()
    {
        return m_objectsRealClass;
    }

    /**
     * Set the objects real class
     */
    public void setObjectsRealClass(Class objectsRealClass)
    {
        this.m_objectsRealClass = objectsRealClass;
    }

    /**
     * Return a serialized Identity as byte[].
     * @see #fromByteArray
     */
    public byte[] serialize() throws PersistenceBrokerException
    {
        // Identity is serialized and written to an ObjectOutputStream
        // This ObjectOutputstream is compressed by a GZIPOutputStream
        // and finally written to a ByteArrayOutputStream.
        // the resulting byte[] is returned
        try
        {
            ByteArrayOutputStream bao = new ByteArrayOutputStream();
            GZIPOutputStream gos = new GZIPOutputStream(bao);
            ObjectOutputStream oos = new ObjectOutputStream(gos);
            oos.writeObject(this);
            oos.close();
            gos.close();
            bao.close();
            byte[] result = bao.toByteArray();
            return result;
        }
        catch (Exception ignored)
        {
            throw new PersistenceBrokerException(ignored);
        }
    }

    /**
     * return a String representation.
     * @return java.lang.String
     */
    public String toString()
    {
        if (m_stringRepresentation == null)
        {
            StringBuffer buf = new StringBuffer();
            buf.append(m_objectsTopLevelClass.getName());
            for (int i = 0; i < m_pkValues.length; i++)
            {
                buf.append((i == 0) ? "{" : ",");
                buf.append(m_pkValues[i]);
            }
            buf.append("}");
            m_stringRepresentation = buf.toString();
        }
        return m_stringRepresentation;
    }


    /**
     * OJB can handle only classes that declare at least one primary key attribute,
     * this method checks this condition.
     * @exception ClassNotPersistenceCapableException thrown if no primary key is
     * specified for the objects class
     */
    protected void checkForPrimaryKeys() throws ClassNotPersistenceCapableException
    {
        // if no PKs are specified OJB can't handle this class !
        if (m_pkValues.length == 0)
        {
            throw new ClassNotPersistenceCapableException(
                    "OJB needs at least one primary key attribute for class "
                    + " objectsRealClass=" + m_objectsRealClass
                    + ", objectTopLevelClass=" + m_objectsTopLevelClass);

        }
        if(m_pkValues[0] instanceof ValueContainer)
            throw new RuntimeException("Can't handle pk values of type "+ValueContainer.class.getName());
    }

    /**
     * return the list of Primary Key Values of the real subject
     * @return Object[]
     */
    public Object[] getPrimaryKeyValues()
    {
        return m_pkValues;
    }

    /**
     * Compare this Identity object to any other object. This comparison is delegated
     * to the super-class.
     */
    public boolean equals(Object obj)
    {
        if(this == obj) return true;

        boolean result = false;
        if (obj instanceof org.apache.ojb.broker.Identity)
        {
            Identity id = (Identity) obj;
            Object[] otherPkValues = id.getPrimaryKeyValues();

            result = getObjectsTopLevelClass().equals(id.getObjectsTopLevelClass())
                    && (m_pkValues.length == otherPkValues.length);
            for (int i = 0; result && i < m_pkValues.length; i++)
            {
                result = (m_pkValues[i] == null) ? (otherPkValues[i] == null)
                        : m_pkValues[i].equals(otherPkValues[i]);

                // special treatment for byte[]
                if (!result && m_pkValues[i] instanceof byte[] && otherPkValues[i] instanceof byte[])
                {
                    result = Arrays.equals((byte[]) m_pkValues[i], (byte[]) otherPkValues[i]);
                }
            }
        }
        return result;
    }

    /**
     * Calculate a hashcode for this Identity. The Hashcode should be
     * equal for Identities where Identity.equals() returns true. Therefore
     * all primary key values that return a hashcode depending on its content
     * (this is assumed for String and Number) are taken into account. Additionally
     * the hashCode() of the Class this Identity is representing is taken into
     * account.
     */
    public int hashCode()
    {
        /*
        arminw:
        identity is quasi immutable (toplevel class and PK fields
        never change), thus we can note hashCode
        */
        if(m_hashCode == null)
        {
            HashCodeBuilder hb = new HashCodeBuilder();
            hb.append(getObjectsTopLevelClass().hashCode());

            for (int i = 0; i < m_pkValues.length; i++)
            {
              hb.append(m_pkValues[i]);
            }
            m_hashCode = new Integer(hb.toHashCode());
        }
        return m_hashCode.intValue();
    }
}
TOP

Related Classes of org.apache.ojb.broker.Identity

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.