/******************************************************************************* * Copyright (c) 2001, 2005 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jem.internal.beaninfo.vm; /* */ import java.beans.*; import java.util.*; import java.lang.reflect.*; /** * This object is used to test for semantic equality (equals()) * between feature objects. It is needed because Feature's don't * provide a semantic equality, only an identity equality. Need * semantic equality so that keys in map can be found equal * semantically. */ public class FeatureDescriptorEquality { protected FeatureDescriptor fFeature; private HashMap fValues; // The key/values for this feature. We grab them out // so that we don't have to keep re-getting them for equality // compares. This is done the first time needed in the equals // statement. private int fHashCode = 0; // Hashcode of this equality object. The hashcode for the feature is expensive // so we will calculate it once (the assumption is that // features once created aren't changed, which for our // purposes here in beaninfo land is good). protected static HashMap MAP_EQUALITY = new HashMap(10); // Map from descriptor to equality type. static { try { MAP_EQUALITY.put(FeatureDescriptor.class, (FeatureDescriptorEquality.class).getConstructor(new Class[] {FeatureDescriptor.class})); } catch (NoSuchMethodException e) { } // Need to set up the others. BeanDescriptorEquality.INIT(); EventSetDescriptorEquality.INIT(); IndexedPropertyDescriptorEquality.INIT(); MethodDescriptorEquality.INIT(); ParameterDescriptorEquality.INIT(); } /** * Create the appropriate descriptor equality for this object. */ public static FeatureDescriptorEquality createEquality(FeatureDescriptor descr) { try { return (FeatureDescriptorEquality) ((Constructor) MAP_EQUALITY.get(descr.getClass())).newInstance(new Object[] {descr}); } catch (IllegalAccessException e) { } catch (InstantiationException e) { } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } public FeatureDescriptorEquality() { } /** * NOTE: Every subclass needs to implement an override for the methods: * calculateHashCode * equals * clearFeature - if it has any cache values */ public FeatureDescriptorEquality(FeatureDescriptor feature) { setFeature(feature); } public final void setFeature(FeatureDescriptor feature) { clearFeature(); fFeature = feature; } /** * A new feature is being set into this object, * clear any cache members so that they can be reconstructed. * * NOTE: Subclasses - remember to call super.clearFeature(); */ protected void clearFeature() { fValues = null; fHashCode = 0; } public final int hashCode() { if (fHashCode == 0) fHashCode = calculateHashCode(); return fHashCode; } protected final HashMap values() { if (fValues == null) { fValues = new HashMap(5); Enumeration keys = fFeature.attributeNames(); while (keys.hasMoreElements()) { String key = (String) keys.nextElement(); fValues.put(key, fFeature.getValue(key)); } } return fValues; } /** * Calculate the hashcode for the current feature, add this * to the hashcode received from super.calculateHashCode * and return the new value. * * NOTE: for subclasses, it is MANDITORY that the first line be: * int hashcode = super.calculateHashCode(); * and the last line be: * return hashcode*31 + (your calculated hashcode for just this subclass); */ protected int calculateHashCode() { int hashcode = 0; if (fFeature.getName() != null) hashcode += fFeature.getName().hashCode(); if (fFeature.getDisplayName() != fFeature.getName()) hashcode += fFeature.getDisplayName().hashCode(); if (fFeature.getShortDescription() != fFeature.getDisplayName()) hashcode += fFeature.getShortDescription().hashCode(); hashcode += (fFeature.isExpert() ? Boolean.TRUE : Boolean.FALSE).hashCode(); hashcode += (fFeature.isHidden() ? Boolean.TRUE : Boolean.FALSE).hashCode(); hashcode += (fFeature.isPreferred() ? Boolean.TRUE : Boolean.FALSE).hashCode(); hashcode += values().hashCode(); return hashcode; } /** * equals: See if this is equal semantically. * * NOTE: Every subclass needs to implement this and * the first few lines should be: * if (identityTest()) * return true; * if (!super.equals(obj)) * return false; */ public boolean equals(Object obj) { if (identityTest(obj)) return true; if (!(obj instanceof FeatureDescriptorEquality)) return false; FeatureDescriptorEquality ofe = (FeatureDescriptorEquality) obj; FeatureDescriptor of = ofe.fFeature; if (fFeature.getClass() != of.getClass()) return false; if (!fFeature.getName().equals(of.getName())) return false; if (!fFeature.getDisplayName().equals(of.getDisplayName())) return false; if (!fFeature.getShortDescription().equals(of.getShortDescription())) return false; if (fFeature.isExpert() != of.isExpert() || fFeature.isHidden() != of.isHidden() || fFeature.isPreferred() != of.isPreferred()) return false; if (!values().equals(ofe.values())) return false; return true; } /* * Identity test: Tests for quick identity of * descriptors. If this returns true, then * no other tests required. */ protected boolean identityTest(Object obj) { if (!(obj instanceof FeatureDescriptorEquality)) return false; if (this == obj) return true; if (((FeatureDescriptorEquality) obj).fFeature == fFeature) return true; return false; } }