db-ojb-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From oliver.m...@ppi.de
Subject RE: [VOTE] Re: Issue #OJB187 - interfaces and abstract class as e lement-class-ref
Date Mon, 23 Jun 2003 11:10:39 GMT
Hej Thomas et al,

> -----Original Message-----
> From: Mahler Thomas [mailto:thomas.mahler@itellium.com]
> > I do not see any risk in my patch, but I dislike it because it is
> > extra code that implements another undesirable behaviour.
> 
> Olli, could you please post me your patch, I did not review 
> the code yet!

I tried so this morning.  Didn't my mail reach you?

Anyway, I will append the class, so everybody can have a look.
(I hope that outlook does not introduce those f*cking linefeeds)

For your convenience: here is what I did:

(I) new method 
    /**
     * Find the first concrete Class in the specified extent.
     * @param mif
     * @return
     */
    private static ClassDescriptor findFirstConcreteClass(ClassDescriptor
mif)
    {
      if (!mif.isInterface())
      {

        return mif;
      }

      Collection extentClasses = mif.getExtentClasses();
      for (Iterator iter = extentClasses.iterator(); 
           iter.hasNext(); )
      {
        Class nextClass = (Class)iter.next();
        ClassDescriptor nextCld = 
            mif.getRepository().getDescriptorFor(nextClass);
        ClassDescriptor firstConcreteCld = 
            findFirstConcreteClass(nextCld);
        if (firstConcreteCld != null)
        {
          return firstConcreteCld;
        }
      }
      return null;
    }


(II)  Replace lines 135-142 with:
    mif = findFirstConcreteClass(mif);
    if (mif == null)
    {
       throw new OJBRuntimeException("There is no concrete class in the
extent of: "
           + mif.getClassNameOfObject());
    }


Regards,
	Olli

--------------------------- snip ---------------------
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 java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;
import java.util.Collection;
import java.lang.reflect.Modifier;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.ojb.broker.OJBRuntimeException;
import org.apache.ojb.broker.PersistenceBrokerException;
import org.apache.ojb.broker.util.logging.LoggerFactory;
import org.apache.ojb.broker.util.logging.Logger;
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 Class m_ClassOfItems = null;
    private Vector m_ForeignKeyFields = new Vector();
    private boolean m_CascadeRetrieve = true;
    private boolean m_CascadeStore = false;
    private boolean m_CascadeDelete = false;
    private Class m_ProxyOfItems = null;
    private boolean m_LookedUpProxy = false;

    //private Logger logger =
LoggerFactory.getLogger(ObjectReferenceDescriptor.class);

    /**
     * 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;
    }

    /**
     * Find the first concrete Class in the specified extent.
     * @param mif
     * @return
     */
    private static ClassDescriptor findFirstConcreteClass(ClassDescriptor
mif)
    {
      if (!mif.isInterface())
      {

        return mif;
      }

      Collection extentClasses = mif.getExtentClasses();
      for (Iterator iter = extentClasses.iterator(); iter.hasNext(); )
      {
        Class nextClass = (Class)iter.next();
        ClassDescriptor nextCld =
mif.getRepository().getDescriptorFor(nextClass);
        ClassDescriptor firstConcreteCld = findFirstConcreteClass(nextCld);
        if (firstConcreteCld != null)
        {
          return firstConcreteCld;
        }
      }
      return null;
    }

    /**
     *
     */
    public FieldDescriptor[] getForeignKeyFieldDescriptors(ClassDescriptor
mif)
    {
        FieldDescriptor[] foreignKeyFieldDescriptors = null;
        if ((foreignKeyFieldDescriptors = (FieldDescriptor[])
fkFieldMap.get(mif)) == 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;
                mif = findFirstConcreteClass(mif);
                if (mif == null)
                {
                  throw new OJBRuntimeException("There is no concrete class
in the extent of: " + mif.getClassNameOfObject());
                }
                ret = new Vector();

                Iterator iter = v.iterator();
                while (iter.hasNext())
                {
                    Object fk = iter.next();
	            FieldDescriptor fkfd;
		    if (fk instanceof Integer)
		    {
			Integer index = (Integer) fk;
			fkfd =
mif.getFieldDescriptorByIndex(index.intValue());
		    }
		    else
		    {
			fkfd = mif.getFieldDescriptorByName((String) fk);
		    }
		    if (fkfd == null)
		    {
			throw new OJBRuntimeException("Incorrect field
reference \"" + fk + "\" in " + this);
		    }
		    ret.add(fkfd);
                }
                foreignKeyFieldDescriptors =
                        (FieldDescriptor[]) ret.toArray(new
FieldDescriptor[ret.size()]);
                fkFieldMap.put(mif, foreignKeyFieldDescriptors);
            }
        }
        return foreignKeyFieldDescriptors;
    }

    /**
     * @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);
        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));

            Object val = f.get(obj);
            result[i] = val;
        }
        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 boolean getCascadeStore()
    {
        return m_CascadeStore;
    }

    /**
     *
     */
    public void setCascadeStore(boolean b)
    {
        m_CascadeStore = b;
    }

    /**
     *
     */
    public boolean getCascadeDelete()
    {
        return m_CascadeDelete;
    }

    /**
     *
     */
    public void setCascadeDelete(boolean b)
    {
        m_CascadeDelete = b;
    }

    public String toString()
    {
        return new ToStringBuilder(this)
                .append("cascade delete", m_CascadeDelete)
                .append("cascade retrieve", m_CascadeRetrieve)
                .append("cascade store", m_CascadeStore)
                .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
        String result = "      " +
tags.getOpeningTagNonClosingById(REFERENCE_DESCRIPTOR) + eol;

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

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

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

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

        //auto retrieve is optional, enabled by default
        if (!getCascadeRetrieve())
        {
            result += "        " + tags.getAttribute(AUTO_RETRIEVE, "false")
+ eol;
        }

        //auto update is optional, disabled by default
        if (getCascadeStore())
        {
            result += "        " + tags.getAttribute(AUTO_UPDATE, "true") +
eol;
        }

        //auto delete is optional, disabled by default
        if (getCascadeDelete())
        {
            result += "        " + tags.getAttribute(AUTO_DELETE, "true") +
eol;
        }

        // close opening tag
        result += "      >" + 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 += "        " +
tags.getOpeningTagNonClosingById(FOREIGN_KEY) + " ";
	        result += tags.getAttribute(FIELD_ID_REF, fkId) + "/>" +
eol;
	    }
	    else
	    {
        	String fk = (String) obj;
                result += "        " +
tags.getOpeningTagNonClosingById(FOREIGN_KEY) + " ";
	        result += tags.getAttribute(FIELD_REF, fk) + "/>" + eol;
	    }
        }

        // closing tag
        result += "      " + tags.getClosingTagById(REFERENCE_DESCRIPTOR) +
eol;
        return result;
    }
}

Mime
View raw message