Package org.apache.ojb.broker.metadata

Source Code of org.apache.ojb.broker.metadata.ObjectReferenceDescriptor

package org.apache.ojb.broker.metadata;

/* Copyright 2002-2005 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 java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.ojb.broker.OJBRuntimeException;
import org.apache.ojb.broker.PersistenceBrokerException;
import org.apache.ojb.broker.core.proxy.ProxyHelper;
import org.apache.ojb.broker.metadata.fieldaccess.PersistentField;

/**
* Describes a Field containing a reference to another class. Provides handling for foreign keys etc.
* <br>
* Note: Be careful when use references of this class or caching instances of this class,
* because instances could become invalid (see {@link MetadataManager}).
*
* @author <a href="mailto:thma@apache.org">Thomas Mahler<a>
*
*/
public class ObjectReferenceDescriptor extends AttributeDescriptorBase implements XmlCapable
{
    private static final long serialVersionUID = 5561562217150972131L;

    public static final int CASCADE_NONE = 17;
    public static final int CASCADE_LINK = 19;
    public static final int CASCADE_OBJECT = 23;

    private Class m_ClassOfItems = null;
    private Vector m_ForeignKeyFields = new Vector();
    private boolean m_CascadeRetrieve = true;
    private int m_CascadeStore = CASCADE_NONE;
    private int m_CascadeDelete = CASCADE_NONE;
    private int m_ProxyPrefetchingLimit = 50;

    private Class m_ProxyOfItems = null;
    private boolean m_LookedUpProxy = false;
    private boolean m_OtmDependent = false;

    /**
     * holds the foreign-key field descriptor array for a specified class
     */
    private Hashtable fkFieldMap = new Hashtable();
    /**
     * define loading strategy of the resulting object
     */
    private boolean lazy = false;
    /**
     * if true relationship is refreshed when owner is found in cache
     */
    private boolean refresh = false;

    /**
     *
     */
    public ObjectReferenceDescriptor(ClassDescriptor descriptor)
    {
        super(descriptor);
    }

    /**
     *
     */
    public Class getItemProxyClass() throws PersistenceBrokerException
    {
        if (!m_LookedUpProxy)
        {
            m_ProxyOfItems = getClassDescriptor().getRepository().
                                getDescriptorFor(m_ClassOfItems).getProxyClass();
            m_LookedUpProxy = true;
        }
        return m_ProxyOfItems;
    }

    /**
     *
     */
  public FieldDescriptor[] getForeignKeyFieldDescriptors(ClassDescriptor cld)
  {
    FieldDescriptor[] foreignKeyFieldDescriptors;
    if ((foreignKeyFieldDescriptors = (FieldDescriptor[]) fkFieldMap.get(cld)) == null)
    {
      // 1. collect vector of indices of Fk-Fields
      Vector v = getForeignKeyFields();
      // 2. get FieldDescriptor for each index from Class-descriptor
      // 2A. In a many-to-many relationship foreignkeyfields vector will be null.
      if (v != null)
      {
        Vector ret;
        if (cld.isInterface())
        {
          //exchange interface class descriptor with first concrete
          //class
          Vector extents = cld.getExtentClasses();
          Class firstConcreteClass = (Class) extents.get(0);
          cld = getClassDescriptor().getRepository().getDescriptorFor(firstConcreteClass);
        }
        ret = new Vector();

        Iterator iter = v.iterator();
        while (iter.hasNext())
        {
          Object fk = iter.next();
          FieldDescriptor fkfd = null;
          /*
                    OJB-55
                    it's possible that the FK field is declared in the super classes of this object,
                    so we can search for a valid field in super class-descriptor
                    */
                    ClassDescriptor tmp = cld;
                    while(tmp != null)
                    {
                        if (fk instanceof Integer)
                        {
                            Integer index = (Integer) fk;
                            fkfd = cld.getFieldDescriptorByIndex(index.intValue());
                        }
                        else
                        {
                            fkfd = tmp.getFieldDescriptorByName((String) fk);
                        }
                        if(fkfd != null)
                        {
                            break;
                        }
                        else
                        {
                            tmp = tmp.getSuperClassDescriptor();
                        }
                    }

                    if (fkfd == null)
          {
                        throw new OJBRuntimeException("Incorrect or not found field reference name '"
                                + fk + "' in descriptor " + this + " for class-descriptor '"
                                + (cld != null ? cld.getClassNameOfObject() + "'" : "'null'"));
          }
          ret.add(fkfd);
        }
        foreignKeyFieldDescriptors = (FieldDescriptor[]) ret.toArray(new FieldDescriptor[ret.size()]);
        fkFieldMap.put(cld, foreignKeyFieldDescriptors);
      }
    }
    return foreignKeyFieldDescriptors;
  }

    /**
     * Returns an Object array of all FK field values of the specified object.
     * If the specified object is an unmaterialized Proxy, it will be materialized
     * to read the FK values.
     *
     * @throws MetadataException if an error occours while accessing ForeingKey values on obj
     */
    public Object[] getForeignKeyValues(Object obj, ClassDescriptor mif)
            throws PersistenceBrokerException
    {
        FieldDescriptor[] fks = getForeignKeyFieldDescriptors(mif);
        // materialize object only if FK fields are declared
        if(fks.length > 0) obj = ProxyHelper.getRealObject(obj);
        Object[] result = new Object[fks.length];
        for (int i = 0; i < result.length; i++)
        {
            FieldDescriptor fmd = fks[i];
            PersistentField f = fmd.getPersistentField();

            // BRJ: do NOT convert.
            // conversion is done when binding the sql-statement
            //
            // FieldConversion fc = fmd.getFieldConversion();
            // Object val = fc.javaToSql(f.get(obj));

            result[i] = f.get(obj);
        }
        return result;
    }

    /**
     *
     */
    public Class getItemClass()
    {
        return m_ClassOfItems;
    }

    /**
     * @return the fully qualified name of the item class for this descriptor.
     */
    public String getItemClassName()
    {
        return this.m_ClassOfItems != null ? this.m_ClassOfItems.getName() : null;
    }

    /**
     * sets the item class
     * @param c the items class object
     */
    public void setItemClass(Class c)
    {
        m_ClassOfItems = c;
    }

    /**
     *
     */
    public Vector getForeignKeyFields()
    {
        return m_ForeignKeyFields;
    }

    /**
     *
     */
    public void setForeignKeyFields(Vector vec)
    {
        m_ForeignKeyFields = vec;
    }

    /**
     * add a foreign key field ID
     */
    public void addForeignKeyField(int newId)
    {
        if (m_ForeignKeyFields == null)
        {
            m_ForeignKeyFields = new Vector();
        }
        m_ForeignKeyFields.add(new Integer(newId));
    }

    /**
     * add a foreign key field
     */
    public void addForeignKeyField(String newField)
    {
        if (m_ForeignKeyFields == null)
        {
            m_ForeignKeyFields = new Vector();
        }
        m_ForeignKeyFields.add(newField);
    }

    /**
     * Gets the refresh.
     * @return Returns a boolean
     */
    public boolean isRefresh()
    {
        return refresh;
    }

    /**
     * Sets the refresh.
     * @param refresh The refresh to set
     */
    public void setRefresh(boolean refresh)
    {
        this.refresh = refresh;
    }

    /**
     * Gets the lazy.
     * @return Returns a boolean
     */
    public boolean isLazy()
    {
        return lazy;
    }

    /**
     * Sets the lazy.
     * @param lazy The lazy to set
     */
    public void setLazy(boolean lazy)
    {
        this.lazy = lazy;
    }

    /**
     *
     */
    public boolean getCascadeRetrieve()
    {
        return m_CascadeRetrieve;
    }

    /**
     *
     */
    public void setCascadeRetrieve(boolean b)
    {
        m_CascadeRetrieve = b;
    }

    /**
     *
     */
    public int getCascadingStore()
    {
        return m_CascadeStore;
    }

    /**
     *
     */
    public void setCascadingStore(int cascade)
    {
        m_CascadeStore = cascade;
    }

    public void setCascadingStore(String value)
    {
        setCascadingStore(getCascadeStoreValue(value));
    }

    /**
     * @deprecated use {@link #getCascadingStore} instead.
     */
    public boolean getCascadeStore()
    {
        return getCascadingStore() == CASCADE_OBJECT;
    }

    /**
     * @deprecated use {@link #setCascadingStore(int)} instead.
     */
    public void setCascadeStore(boolean cascade)
    {
        if(cascade)
        {
            setCascadingStore(getCascadeStoreValue("true"));
        }
        else
        {
            setCascadingStore(getCascadeStoreValue("false"));
        }
    }

    /**
     *
     */
    public int getCascadingDelete()
    {
        return m_CascadeDelete;
    }

    /**
     *
     */
    public void setCascadingDelete(int cascade)
    {
        m_CascadeDelete = cascade;
    }

    public void setCascadingDelete(String value)
    {
        setCascadingDelete(getCascadeDeleteValue(value));
    }

    /**
     * @deprecated use {@link #getCascadingDelete} instead.
     */
    public boolean getCascadeDelete()
    {
        return getCascadingDelete() == CASCADE_OBJECT;
    }

    /**
     * @deprecated use {@link #setCascadingDelete(int)}
     */
    public void setCascadeDelete(boolean cascade)
    {
        if(cascade)
        {
            setCascadingDelete(getCascadeDeleteValue("true"));
        }
        else
        {
            setCascadingDelete(getCascadeDeleteValue("false"));
        }
    }

    protected int getCascadeStoreValue(String cascade)
    {
        if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_NONE_STR))
        {
            return CASCADE_NONE;
        }
        else if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_LINK_STR))
        {
            return CASCADE_LINK;
        }
        else if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_OBJECT_STR))
        {
            return CASCADE_OBJECT;
        }
        else if(cascade.equalsIgnoreCase("true"))
        {
            return CASCADE_OBJECT;
        }
        else if(cascade.equalsIgnoreCase("false"))
        {
            /*
            in old implementation the FK values of an 1:1 relation are always
            set. Thus we choose 'link' instead of 'none'
            The CollectionDescriptor should override this behaviour.
            */
            return CASCADE_LINK;
        }
        else
        {
            throw new OJBRuntimeException("Invalid value! Given value was '" + cascade
                    + "', expected values are: " + RepositoryTags.CASCADE_NONE_STR + ", "
                    + RepositoryTags.CASCADE_LINK_STR + ", " + RepositoryTags.CASCADE_OBJECT_STR
                    + " ('false' and 'true' are deprecated but still valid)");
        }
    }

    protected int getCascadeDeleteValue(String cascade)
    {
        if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_NONE_STR))
        {
            return CASCADE_NONE;
        }
        else if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_LINK_STR))
        {
            return CASCADE_LINK;
        }
        else if(cascade.equalsIgnoreCase(RepositoryTags.CASCADE_OBJECT_STR))
        {
            return CASCADE_OBJECT;
        }
        else if(cascade.equalsIgnoreCase("true"))
        {
            return CASCADE_OBJECT;
        }
        else if(cascade.equalsIgnoreCase("false"))
        {
            return CASCADE_NONE;
        }
        else
        {
            throw new OJBRuntimeException("Invalid value! Given value was '" + cascade
                    + "', expected values are: " + RepositoryTags.CASCADE_NONE_STR + ", "
                    + RepositoryTags.CASCADE_LINK_STR + ", " + RepositoryTags.CASCADE_OBJECT_STR
                    + " ('false' and 'true' are deprecated but still valid)");
        }
    }

    public String getCascadeAsString(int cascade)
    {
        String result = null;
        switch(cascade)
        {
            case CASCADE_NONE:
                result = RepositoryTags.CASCADE_NONE_STR;
                break;
            case CASCADE_LINK:
                result = RepositoryTags.CASCADE_LINK_STR;
                break;
            case CASCADE_OBJECT:
                result = RepositoryTags.CASCADE_OBJECT_STR;
                break;
        }
        return result;
    }

    public int getProxyPrefetchingLimit()
    {
        return m_ProxyPrefetchingLimit;
    }

    public void setProxyPrefetchingLimit(int proxyPrefetchingLimit)
    {
        m_ProxyPrefetchingLimit = proxyPrefetchingLimit;
    }

    /**
     *
     */
    public boolean getOtmDependent()
    {
        return m_OtmDependent;
    }

    /**
     *
     */
    public void setOtmDependent(boolean b)
    {
        m_OtmDependent = b;
    }

    /**
     * Returns <code>true</code> if this descriptor was used to
     * describe a reference to a super class of an object.
     *
     * @return always <code>false</code> for this instance.
     */
    public boolean isSuperReferenceDescriptor()
    {
        return false;
    }

    /**
     * Returns <em>true</em> if a foreign key constraint to the referenced object is
     * declared, else <em>false</em> is returned.
     */
    public boolean hasConstraint()
    {
        /*
        arminw: Currently we don't have a ForeignKey descriptor object and
        a official xml-element to support FK settings. As a workaround I introduce
        a custom-attribute to handle FK settings in collection-/reference-decriptor
        */
        String result = getAttribute("constraint");
        return result != null && result.equalsIgnoreCase("true");
    }

    /**
     * Set a foreign key constraint flag for this reference - see {@link #hasConstraint()}
     * @param constraint If set <em>true</em>, signals a foreign key constraint in database.
     */
    public void setConstraint(boolean constraint)
    {
        addAttribute("constraint", constraint ? "true" : "false");
    }

    public String toString()
    {
        return new ToStringBuilder(this)
                .append("cascade_retrieve", getCascadeRetrieve())
                .append("cascade_store", getCascadeAsString(m_CascadeStore))
                .append("cascade_delete", getCascadeAsString(m_CascadeDelete))
                .append("is_lazy", lazy)
                .append("class_of_Items", m_ClassOfItems)
                .toString();
    }

    /*
     * @see XmlCapable#toXML()
     */
    public String toXML()
    {
        RepositoryTags tags = RepositoryTags.getInstance();
        String eol = System.getProperty( "line.separator" );

        // opening tag
        StringBuffer result = new StringBuffer( 1024 );
        result.append( "      " );
        result.append( tags.getOpeningTagNonClosingById( REFERENCE_DESCRIPTOR ) );
        result.append( eol );

        // attributes
        // name
        String name = this.getAttributeName();
        if( name == null )
        {
            name = RepositoryElements.TAG_SUPER;
        }
        result.append( "        " );
        result.append( tags.getAttribute( FIELD_NAME, name ) );
        result.append( eol );

        // class-ref
        result.append( "        " );
        result.append( tags.getAttribute( REFERENCED_CLASS, this.getItemClassName() ) );
        result.append( eol );

        // proxyReference is optional
        if( isLazy() )
        {
            result.append( "        " );
            result.append( tags.getAttribute( PROXY_REFERENCE, "true" ) );
            result.append( eol );
            result.append( "        " );
            result.append( tags.getAttribute( PROXY_PREFETCHING_LIMIT, "" + this.getProxyPrefetchingLimit() ) );
            result.append( eol );
        }

        //reference refresh is optional, disabled by default
        if( isRefresh() )
        {
            result.append( "        " );
            result.append( tags.getAttribute( REFRESH, "true" ) );
            result.append( eol );
        }

        //auto retrieve
        result.append( "        " );
        result.append( tags.getAttribute( AUTO_RETRIEVE, "" + getCascadeRetrieve() ) );
        result.append( eol );

        //auto update
        result.append( "        " );
        result.append( tags.getAttribute( AUTO_UPDATE, getCascadeAsString( getCascadingStore() ) ) );
        result.append( eol );

        //auto delete
        result.append( "        " );
        result.append( tags.getAttribute( AUTO_DELETE, getCascadeAsString( getCascadingDelete() ) ) );
        result.append( eol );

        //otm-dependent is optional, disabled by default
        if( getOtmDependent() )
        {
            result.append( "        " );
            result.append( tags.getAttribute( OTM_DEPENDENT, "true" ) );
            result.append( eol );
        }

        // close opening tag
        result.append( "      >" );
        result.append( eol );

        // elements
        // write foreignkey elements
        for( int i = 0; i < getForeignKeyFields().size(); i++ )
        {
            Object obj = getForeignKeyFields().get( i );
            if( obj instanceof Integer )
            {
                String fkId = obj.toString();
                result.append( "        " );
                result.append( tags.getOpeningTagNonClosingById( FOREIGN_KEY ) );
                result.append( " " );
                result.append( tags.getAttribute( FIELD_ID_REF, fkId ) );
                result.append( "/>" );
                result.append( eol );
            }
            else
            {
                String fk = ( String ) obj;
                result.append( "        " );
                result.append( tags.getOpeningTagNonClosingById( FOREIGN_KEY ) );
                result.append( " " );
                result.append( tags.getAttribute( FIELD_REF, fk ) );
                result.append( "/>" );
                result.append( eol );
            }
        }

        // closing tag
        result.append( "      " );
        result.append( tags.getClosingTagById( REFERENCE_DESCRIPTOR ) );
        result.append( eol );
        return result.toString();
    }
}
TOP

Related Classes of org.apache.ojb.broker.metadata.ObjectReferenceDescriptor

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.