Hi Armin,

never mind, I should have posted this earlier. (And I did learn a lot from OJB,
by the way :-)

Ok, our buildKey method looks like this:

private Object buildKey(Identity oid)
{
    switch (cachingKeyType)
    {
        case 0 :
            return new OrderedTuple(oid);
        case 1 :
            return new OrderedTuple(broker.getPBKey().getAlias(), oid);
        case 2 :
            return new OrderedTuple(broker.getDescriptorRepository(), oid);
        case 3 :
            return new OrderedTuple(
                broker.getDescriptorRepository(),
                broker.getPBKey().getAlias(),
                oid);
        default :
            throw new IllegalStateException(
                "Unsupported caching key type: " + cachingKeyType);
    }
}

and it uses a simple class OrderedTuple shown below. We did not pay particular
attantion to choosing good hashCode multipliers (except using prime numbers), so
it might be better to use jakarta-commons HashCodeBuilder for the hash code
calculation. We just did not want to have an external dependency in this class.

package de.lexcom.common.util;

/**
 * Implements equals() and hashCode() for an ordered tuple of constant(!) 
 * objects
 * 
 * @author  Gerhard Grosse
 * @version $Id: OrderedTuple.java,v 1.2 2004/11/02 09:54:09 grosse Exp $
 * @since   Oct 12, 2004
 */
public class OrderedTuple
{
    private static int[] multipliers =
        new int[] { 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 51 };

    private Object[] elements;
    private int hashCode;

    public OrderedTuple(Object element)
    {
        elements = new Object[1];
        elements[0] = element;
        hashCode = calcHashCode();
    }

    public OrderedTuple(Object element1, Object element2)
    {
        elements = new Object[2];
        elements[0] = element1;
        elements[1] = element2;
        hashCode = calcHashCode();
    }

    public OrderedTuple(Object element1, Object element2, Object element3)
    {
        elements = new Object[3];
        elements[0] = element1;
        elements[1] = element2;
        elements[2] = element3;
        hashCode = calcHashCode();
    }

    public OrderedTuple(Object[] elements)
    {
        this.elements = elements;
        this.hashCode = calcHashCode();
    }

    private int calcHashCode()
    {
        int code = 7;
        for (int i = 0; i < elements.length; i++)
        {
            int m = i % multipliers.length;
            code += elements[i].hashCode() * multipliers[m];
        }
        return code;
    }

    public boolean equals(Object obj)
    {
        if (!(obj instanceof OrderedTuple))
        {
            return false;
        }
        else
        {
            OrderedTuple other = (OrderedTuple) obj;
            if (this.hashCode != other.hashCode)
            {
                return false;
            }
            else if (this.elements.length != other.elements.length)
            {
                return false;
            }
            else
            {
                for (int i = 0; i < elements.length; i++)
                {
                    if (!this.elements[i].equals(other.elements[i]))
                    {
                        return false;
                    }
                }
                return true;
            }
        }
    }

    public int hashCode()
    {
        return hashCode;
    }

    public String toString()
    {
        StringBuffer s = new StringBuffer();
        s.append('{');
        for (int i = 0; i < elements.length; i++)
        {

s.append(elements[i]).append('#').append(elements[i].hashCode()).append(',');
        }
        s.setCharAt(s.length() - 1, '}');
        s.append("#").append(hashCode);
        return s.toString();
    }

}


Cheers,
Gerhard


On Thu, 18 Nov 2004 16:42:40 +0100, Armin Waibel <[EMAIL PROTECTED]> wrote:

>Hi Gerhard and Nikolaus,
>
> > hashCode() as keys into a Hashtable. Since hash codes of different 
>objects can
> > be equal, this sooner or later had to fail.
> >
>
>sorry this was my fault I only think about PK values of type Integer 
>(here #hashCode and #equals has same result) and best performance, 
>completely ignoring Long, String,...
>
> > If you are using the default cache setting, you can simply change the 
>buildKey
> > method to return an Object, namely oid itself. If you are using one 
>of the other
> > options I can post a utility class that combines several objects to a 
>single
> > hash table key and you can use this in your ObjectCache. Let me know.
>
>if you send me your utility class I will integrate it in CVS trunk/branch
>
>Sorry again, think I should take a java beginner's course.
>
>regards,
>Armin
>
>
>Gerhard Grosse wrote:
>> Hi Nikolaus,
>> 
>> This is copied from ObjectCacheDefaultImpl:
>> 
>>     private Integer buildKey(Identity oid)
>>     {
>>         int key = 0;
>>         switch(cachingKeyType)
>>         {
>>             case 0:
>>                 key = oid.hashCode();
>>                 break;
>>             case 1:
>>                 key = new
>> HashCodeBuilder().append(broker.getPBKey().getAlias().hashCode()).append(oid.hashCode()).toHashCode();
>>                 break;
>>             case 2:
>>                 key = new
>> HashCodeBuilder().append(broker.getDescriptorRepository().hashCode()).append(oid.hashCode()).toHashCode();
>>                 break;
>>             case 3:
>>                 key = new
>> HashCodeBuilder().append(broker.getDescriptorRepository().hashCode()).append(broker.getPBKey().getAlias().hashCode()).append(oid.hashCode()).toHashCode();
>>                 break;
>>             default:
>>                 throw new OJBRuntimeException("Unexpected error, 'cacheType
>> ="+cachingKeyType+"' was not supported");
>>         }
>>         return new Integer(key);
>>     }
>> 
>> 
>> It is interesting that someone finally discovered this bug in action. Indeed
>> OJB's latest object cache implementations use an object based on the PK's
>> hashCode() as keys into a Hashtable. Since hash codes of different objects 
>> can
>> be equal, this sooner or later had to fail.
>> 
>> We are using own ObjectCache implementations for some other reasons but 
>> stumbled
>> about this when adapting our caches to version 1.0.1. I always wanted to post
>> something about this problem to the list, but, alas, I forgot about it.
>> 
>> If you are using the default cache setting, you can simply change the 
>> buildKey
>> method to return an Object, namely oid itself. If you are using one of the 
>> other
>> options I can post a utility class that combines several objects to a single
>> hash table key and you can use this in your ObjectCache. Let me know.
>> 
>> But of course I hope someone of the OJB gurus will fix this in the official
>> code...
>> 
>> Gerhard
>> 
>> On Thu, 18 Nov 2004 15:55:41 +0100, [EMAIL PROTECTED]
>> wrote:
>> 
>> 
>>>
>>>
>>>
>>>Hi,
>>>
>>>i am using OJB since 1 and 1/2 years. This week i tried to move from
>>>Version 1.0 to 1.0.1.
>>>
>>>I detected the following problem:
>>>
>>>I have two objects of two different classes (aClass and bClass) with the
>>>same base class.
>>>I use strings as primary keys. Object a has the string 'WR' as pk, object b
>>>the string 'X3'.
>>>If i first search for object of aClass with objectId = WR and then for
>>>object of bClass with objectID = X3, i retrieve the object a two times.
>>>
>>>The reason seems to be that both strings are mapped two the same Integer in
>>>org.apache.ojb.broker.Identity.hashCode()
>>>
>>>This behaviour of the Object Cache was not in OJB 1.0.
>>>
>>>Is this a known problem in OBJ 1.0.1?
>>>
>>>Best regards
>>>
>>>Nikolaus Bininda.
>> 
>> 
>> 
>> 
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: [EMAIL PROTECTED]
>> For additional commands, e-mail: [EMAIL PROTECTED]
>> 
>> 
>> 



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to