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]