/***************************************************************** 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.core; import jade.util.leap.Map; import jade.util.leap.HashMap; // Class for the Local Agent Descriptor Table. /** @author Giovanni Rimassa - Universita' di Parma @version $Date: 2008-01-07 15:49:34 +0100 (lun, 07 gen 2008) $ $Revision: 6013 $ */ class LADT { // Rows of the LADT are protected by a recursive mutex lock private static class Row { private Agent value; // DEBUG private Agent bakValue; // DEBUG private String target = "ma"; private Thread owner; private long depth; public Row(Agent a) { value = a; // DEBUG bakValue = value; depth = 0; } public synchronized Agent get() { return value; } public synchronized void clear() { value = null; } public synchronized void lock() { if (value != null) { try { Thread me = Thread.currentThread(); while((owner != null) && (owner != me)) { // DEBUG boolean b = false; // DEBUG if (bakValue.getLocalName().equals(target)) { // DEBUG System.out.println("Thread "+Thread.currentThread().getName()+" start waiting on "+target); // DEBUG b = true; // DEBUG } wait(); // DEBUG if (b) { // DEBUG System.out.println("Thread "+Thread.currentThread().getName()+" stop waiting on "+target); // DEBUG } if (value == null) { return; } } owner = me; ++depth; } catch(InterruptedException ie) { return; } } } public synchronized void unlock() { // Must be owner to unlock if(owner != Thread.currentThread()) return; --depth; if(depth == 0 || value == null) { // Note that if the row has just been cleared we must wake up // hanging threads even if depth is > 0, otherwise they will // hang forever owner = null; // DEBUG try { // DEBUG if (bakValue.getLocalName().equals(target)) { // DEBUG System.out.println("Thread "+Thread.currentThread().getName()+" notifying all on "+target); // DEBUG } // DEBUG } // DEBUG catch (Exception e) {} notifyAll(); } } // For debugging purpose public String toString() { if (value != null) { return "("+value.getName()+" :owner "+(owner != null ? owner.toString() : "null")+")"; } else { return "null"; } } } // End of Row class // Initial size of agent hash table //private static final int MAP_SIZE = 50; // Load factor of agent hash table //private static final float MAP_LOAD_FACTOR = 0.50f; //private Map agents = new HashMap(MAP_SIZE, MAP_LOAD_FACTOR); private Map agents; public LADT(int size) { agents = new HashMap(size); } public Agent put(AID aid, Agent a) { Row r; synchronized(agents) { r = (Row)agents.get(aid); } if(r == null) { agents.put(aid, new Row(a)); return null; } else { r.lock(); Agent old = r.get(); // Re-putting an existing agent must have no effect if (a != old) { agents.put(aid, new Row(a)); } r.unlock(); return old; } } public Agent remove(AID key) { Row r; synchronized(agents) { r = (Row)agents.get(key); } if(r == null) return null; else { r.lock(); agents.remove(key); Agent a = r.get(); // Clear the row value, to avoid pending acquire() using the // removed agent... r.clear(); r.unlock(); return a; } } // The caller must call release() after it has finished with the row public Agent acquire(AID key) { Row r; synchronized(agents) { r = (Row)agents.get(key); } if(r == null) return null; else { r.lock(); return r.get(); } } public void release(AID key) { Row r; synchronized(agents) { r = (Row)agents.get(key); } if(r != null) { r.unlock(); } } public AID[] keys() { synchronized(agents) { Object[] objs = agents.keySet().toArray(); AID[] result = new AID[objs.length]; // Patch on 11/12/02 by NL to bypass J2ME bug with System.arraycopy for (int i=0;i<result.length;i++) { result[i]=(AID)objs[i]; } return result; } } public Agent[] values() { synchronized(agents) { Object[] objs = agents.values().toArray(); Agent[] result = new Agent[objs.length]; for(int i = 0; i < objs.length; i++) { Row r = (Row)objs[i]; result[i] = r.get(); } return result; } } synchronized boolean contains(AID key) { return agents.containsKey(key); } // For debugging purpose public String[] getStatus() { synchronized(agents) { Object[] objs = agents.values().toArray(); String[] status = new String[objs.length]; for(int i = 0; i < objs.length; i++) { Row r = (Row)objs[i]; status[i] = r.toString(); } return status; } } }