/** * *************************************************************** * JADE - Java Agent DEvelopment Framework is a framework to develop * multi-agent systems in compliance with the FIPA specifications. * Copyright (C) 2000 CSELT S.p.A. * * GNU Lesser General Public License * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation, * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. * ************************************************************** */ package jade.content.abs; import jade.core.CaseInsensitiveString; import jade.util.leap.ArrayList; import jade.util.leap.HashMap; import jade.util.leap.Iterator; /** * Base class for all non-primitive abstract descriptor classes. * This class is not intended to be used by programmers. * @author Federico Bergenti - Universita` di Parma * @author Giovanni Caire - TILAB */ public class AbsObjectImpl implements AbsObject { private HashMap elements = new HashMap(); /** This list keeps the keys in the same order as they were added **/ private ArrayList orderedKeys = new ArrayList(); private String typeName = null; /** true if this object is changed and its hash must be recomputed **/ private boolean changed = true; private int hashCode = 0; /** * Construct an Abstract descriptor to hold an object of * the proper type. * @param typeName The name of the type of the object held by this * abstract descriptor. */ protected AbsObjectImpl(String typeName) { this.typeName = typeName; } /** * @return The name of the type of the object held by this * abstract descriptor. * @see AbsObject#getTypeName() */ public String getTypeName() { return typeName; } /** * Sets an attribute of the object held by this * abstract descriptor. * @param name The name of the attribute to be set. * @param value The new value of the attribute. If <code>value</code> * is null the current mapping with <code>name</code> (if any) is * removed. */ protected void set(String name, AbsObject value) { CaseInsensitiveString ciName = new CaseInsensitiveString(name); if (value == null) { orderedKeys.remove(name); elements.remove(ciName); } else { if (!orderedKeys.contains(name)) { orderedKeys.add(name); } elements.put(ciName, value); } changed = true; } /** * Gets the value of an attribute of the object held by this * abstract descriptor. * @param name The name of the attribute. * @return value The value of the attribute. * @see AbsObject#getAbsObject(String) */ public AbsObject getAbsObject(String name) { return (AbsObject) elements.get(new CaseInsensitiveString(name)); } /** * @return the name of all attributes. * @see AbsObject#getNames() */ public String[] getNames() { String[] names = new String[orderedKeys.size()]; int j=0; for (Iterator i=orderedKeys.iterator(); i.hasNext(); ) names[j++] = (String)i.next(); return names; } /** * Tests if the object is grounded, i.e., if no one of its attributes * is associated with a variable * @return <code>true</code> if the object is grounded. * @see AbsObject#isGrounded() */ public boolean isGrounded() { for (Iterator i = elements.values().iterator(); i.hasNext(); ) { AbsObject abs = (AbsObject) i.next(); if (!abs.isGrounded()) { return false; } } return true; } /** * Gets the number of attributes. * @return the number of attributes. * @see AbsObject#getCount() */ public int getCount() { return elements.size(); } /** * This method is here just for debugging. Notice that it is highly innefficient. * The method StringCodec.encode() should be used instead. * @see StringCodec.encode(AbsContentElement content) */ public String toString() { StringBuffer sb = new StringBuffer("("); sb.append(getTypeName()); String[] names = getNames(); for (int i = 0; i < names.length; i++) { sb.append(" :"); sb.append(names[i]); sb.append(" "); sb.append(getAbsObject(names[i])); } sb.append(")"); return sb.toString(); } //ADDED BY SANDER FAAS: /** * Returns true if the attribute is equal to * this abstract descriptor, based on the contents * of both descriptors. */ public boolean equals(Object obj) { if (obj instanceof AbsObjectImpl) { AbsObjectImpl abs = (AbsObjectImpl) obj; if (abs.getClass().equals(getClass()) && abs.getTypeName().equals(typeName)) { return f(abs) == f(this); } } return false; } /** * Returns an integer hashcode calculated from the * contents of this abstract descriptor */ public int hashCode() { // if this object is changed, then recompute its hash, otherwise use the previous value if (changed) { hashCode = f(this); changed = false; } return hashCode; } /** * Calculates the hashcode according to a formula based on the * slot names and values taken in an lexicographical order */ private final int f(AbsObjectImpl o, int x) { String slotNames[] = o.getNames(); sort(slotNames); int[] v = new int[2*slotNames.length + 1]; int j=0; for(int i = 0; i < slotNames.length; i++) { v[j++] = slotNames[i].hashCode(); v[j++] = o.getAbsObject(slotNames[i]).hashCode(); } v[j++] = o.getTypeName().hashCode(); int sum = 0; int counter = 0; for (int i=0; i<v.length; i++ ) { sum += v[i] * x^counter; counter++; } return sum; } private final int f(AbsObjectImpl o) { return f(o, 2); } private final void sort(String[] strs) { for (int i = 1; i < strs.length; ++i) { for (int j = i; j > 0 && (strs[j-1].compareTo(strs[j]) > 0); --j) { swap(strs, j, j-1); } } } private final void swap(String[] strs, int x, int y) { String t = strs[x]; strs[x] = strs[y]; strs[y] = t; } public int getAbsType() { return UNKNOWN; } }