001    /*
002      Copyright (C) 2001-2002 Renaud Pawlak, Eddy Truyen.
003    
004      This program is free software; you can redistribute it and/or modify
005      it under the terms of the GNU Lesser General Public License as
006      published by the Free Software Foundation; either version 2 of the
007      License, or (at your option) any later version.
008    
009      This program is distributed in the hope that it will be useful,
010      but WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
012      GNU Lesser General Public License for more details.
013    
014      You should have received a copy of the GNU Lesser General Public
015      License along with this program; if not, write to the Free Software
016      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
017      USA */
018    
019    package org.objectweb.jac.core;
020    
021    import java.util.Collection;
022    import java.util.HashMap;
023    import java.util.HashSet;
024    import java.util.Hashtable;
025    import java.util.Iterator;
026    import java.util.Map;
027    
028    /**
029     * This class represents a set of contextual informations for a given
030     * thread of a running JAC system.
031     * 
032     * <p>For each method call on a JAC object, a new interaction is
033     * started on the current collaboration. At any point of the program,
034     * the programmer can get the current collaboration for the current
035     * thread by using <code>get()</code>.
036     *
037     * <p>The <code>CollaborationParticipant</code> interface provides a
038     * more friendly interface to access the current collaboration. In a
039     * clean design, only the classes that implement this interface may
040     * access the collaboration.
041     *
042     * @see Collaboration#get()
043     * @see CollaborationParticipant
044     *
045     * @author Renaud Pawlak
046     * @author Eddy Truyen
047     */
048    
049    public class Collaboration implements java.io.Serializable {
050    
051        /** The attribute is global to all the sites (it is serialized and
052            transmitted with the collaboration) */
053        public static Object GLOBAL=new Integer(1); 
054    
055        transient static Hashtable attrTypes=new Hashtable();
056    
057        /**
058         * Returns true if the attribute is global. The attribute is
059         * then transmitted to the remote sites reached by the
060         * collaboration. Note that a global attribute must always be
061         * serializable. If the attribute is not global, it
062         * always stays on the site where it has been defined.
063         *
064         * <p>By default, if the <code>setGlobal</code> method is not
065         * called, all the attributes are local.
066         *
067         * @see #setGlobal(String) 
068         */
069        public static boolean isGlobal(String attrName) {
070            if(attrTypes.get(attrName)==GLOBAL) {
071                return true;
072            } else {
073                return false;
074            }
075        }
076    
077        /**
078         * Sets an attribute to be global.
079         *
080         * <p>This method should only be called once for each attribute and
081         * before the first initialization of the attribute value in the
082         * collaboration since the globality is an inherent caracteristic
083         * of an attribute. 
084         */
085        public static void setGlobal(String attrName) {
086            attrTypes.put(attrName,GLOBAL);
087        }
088       
089        /** Stores collaborations for all threads. */
090        transient static Hashtable collaborations = new Hashtable();
091    
092        /** Static initialization of the collaborations. */
093    
094        static {
095            Thread current = Thread.currentThread();
096            collaborations.put ( current, new Collaboration() );
097        }
098    
099        /**
100         * Get the collaboration for the current thread.
101         *
102         * @return the current collaboration 
103         */
104        public static Collaboration get() {
105            Thread current = Thread.currentThread();
106            Collaboration ret = (Collaboration) collaborations.get(current);
107            if ( ret == null ) {
108                collaborations.put ( current, ret = new Collaboration() );
109            }
110            return ret;
111        }
112    
113        /**
114         * Set a new collaboration for the current thread.
115         *
116         * @param collaboration the collaboration 
117         */
118        public static void set(Collaboration collaboration) {
119            Thread current = Thread.currentThread();
120            collaborations.put(current, collaboration);
121        }
122       
123        /** Store the attributes of the interaction. */
124        private HashMap attrs;
125    
126        /**
127         * Creates an new collaboration.
128         * 
129         * <p>The programmer should not explicitly create a new
130         * collaboration since this is automatically done by the system for
131         * any new thread.
132         *
133         * <p> At any point of the program, the programmer can get the
134         * current collaboration for the current thread by using
135         * <code>Collaboration.get()</code>.
136         *
137         * @see Collaboration#get() 
138         */
139        public Collaboration() {
140            reset();
141        }
142    
143        /**
144         * Create a new Collaboration and initialiaze it's attribute from a
145         * parent Collaboration.
146         *
147         * @param parent the parent collaboration
148         */
149        public Collaboration(Collaboration parent) {
150            reset();
151            if (parent!=null) {
152                Iterator it = parent.attributeNames().iterator();
153                while (it.hasNext()) {
154                    String attrName = (String)it.next();
155                    addAttribute(
156                        attrName,parent.getAttribute(attrName));
157                }
158            }
159        }
160    
161        /**
162         * Returns a collection of all attribute names
163         */
164        public Collection attributeNames() {
165            HashSet names = new HashSet();
166            names.addAll(attrs.keySet());
167            return names;
168        }
169    
170        public static Collection globalAttributeNames() {
171            HashSet names = new HashSet();
172            names.addAll(attrTypes.keySet());
173            return names;
174        }
175    
176        /**
177         * Returns the map of attribute's name -> value
178         */
179        public Map getAttributes() {
180            return (Map)attrs.clone();
181        }
182    
183        /**
184         * Set some attributes. Do not override current attributes.
185         * @param attributes map of name->value of attributes to set.
186         */
187        public void setAttributes(Map attributes) {
188            Iterator it = attributes.entrySet().iterator();
189            while (it.hasNext()) {
190                Map.Entry entry = (Map.Entry)it.next();
191                if (!attrs.containsKey(entry.getKey()))
192                    attrs.put(entry.getKey(),entry.getValue());
193            }
194        }
195    
196        /**
197         * Reset the Collaboration. 
198         * <p>Clears interactions, and all attributes.
199         */
200        public void reset() {
201            attrs = new HashMap();
202        }
203    
204        /**
205         * Add a persistent attribute to the collaboration (can be done by
206         * any Jac object).
207         * 
208         * <p>NOTE: a persitent attribute is visible for all the objects of a
209         * collaboration.
210         *
211         * @param name the name of the attribute
212         * @param att the value of the attribute 
213         */
214        public Object addAttribute(String name, Object att) {
215            if ( name != null ) {
216                attrs.put(name, att);
217            }
218            return att;
219        }
220    
221        /**
222         * Return the value of an attribute for the current collaboration.
223         * 
224         * <p>This method first seeks into the persistent attributes. If
225         * none matches, it seeks into the transient attributes. If still
226         * not found, finally seeks into the transient local attributes. If
227         * all the lookups failed, return null.
228         *
229         * @param name the name of the attribute
230         * @return the value of the attribute 
231         */
232        public Object getAttribute(String name) {
233            if (attrs.containsKey(name)) {
234                return attrs.get(name);
235            }
236            return null;
237        }
238    
239        /**
240         * Removes the attribute from the current collaboration. 
241         */
242        public void removeAttribute(String name) {
243            attrs.remove(name);
244        }
245    
246        String cur_App;
247    
248        public final void setCurApp(String app) {
249            this.cur_App = app;
250        }
251    
252        public final String getCurApp() {
253            return cur_App;
254        }
255       
256        /**
257         * Returns a textual representation of the collaboration. 
258         */
259        public String toString() {
260            return "Collaboration: \n" + 
261                "attributes = " + attrs.toString();
262        }
263       
264       
265    }