001    /*
002      Copyright (C) 2001-2002 Renaud Pawlak <renaud@aopsys.com>
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, but
010      WITHOUT ANY WARRANTY; without even the implied warranty of
011      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
012      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.io.*;
022    import java.util.*;
023    import org.apache.log4j.Logger;
024    
025    /**
026     * This class defines all the needed information when (de)serializing
027     * a JAC object.
028     *
029     * <p>It is used to (de)serialize a JacObject by
030     * <code>JacObjectInputStream</code> and
031     * <code>JacObjectOutputStream</code>. To ensure the correct use of
032     * these streams, use only <code>JacObject.(de)serialize()</code>.
033     *
034     * <p>Any aspect component can use a <code>SerializedJacObject</code>
035     * to add any relevant information during the serialization process
036     * (<code>whenSerialized()</code>) or to extract any relevant
037     * information during the deserialization process
038     * (<code>whenDeserialized()</code>).
039     * 
040     * @see JacObjectOutputStream
041     * @see AspectComponent#whenSerialized(Wrappee,SerializedJacObject)
042     * @see JacObjectInputStream
043     * @see AspectComponent#whenDeserialized(SerializedJacObject,Wrappee)
044     *
045     * @author <a href="http://cedric.cnam.fr/~pawlak/index-english.html">Renaud Pawlak</a> */
046     
047    public class SerializedJacObject implements Serializable {
048        static Logger logger = Logger.getLogger("serialization");
049    
050        public static final String STATELESS="SerializedJacObject.STATELESS";
051    
052       /**
053        * Serialize an object into an array of bytes.
054        * 
055        * <p>If the programmer uses this method, the aspect components are
056        * upcalled (<code>whenSerialized()</code>) to parametrize the
057        * serialization by filling a <code>SerializedJacObject</code> instance.
058        *
059        * <p>A symetric process is implemented by <code>deserialize()</code>
060        *
061        * @param src the object to serialize
062        * @return an array of bytes
063        * 
064        * @see AspectComponent#whenSerialized(Wrappee,SerializedJacObject)
065        * @see SerializedJacObject
066        * @see #deserialize(byte[])
067        * @see JacObjectOutputStream */
068        
069       public static byte[] serialize(Object src) {
070    
071          ByteArrayOutputStream baos = new ByteArrayOutputStream();
072          
073          ObjectOutputStream oos = null;
074          byte[] ret = null;
075    
076          if(src instanceof Collaboration) {
077             Collaboration init=(Collaboration)src;
078             Collaboration dest=new Collaboration();
079    
080             Iterator it=Collaboration.globalAttributeNames().iterator();
081             while(it.hasNext()) {
082                String name=(String)it.next();
083                if(init.getAttribute(name)!=null) {
084                   dest.addAttribute(
085                      name,
086                      init.getAttribute(name));
087                }
088             }
089             logger.debug("serializing "+dest);
090             src=dest;
091          }
092    
093          try {
094             oos = (ObjectOutputStream) new JacObjectOutputStream(baos);
095             logger.debug("serialize "+src);
096             oos.writeObject(src);
097             oos.close();
098             ret = baos.toByteArray();
099             baos.close();
100          } catch(Exception e) { 
101             e.printStackTrace(); 
102          }
103          
104          return ret;
105       }   
106    
107        /**
108         * Serialize the arguments of a method. */
109    
110        public static byte[] serializeArgs(Object[] args,Boolean[] refs) {
111    
112            ByteArrayOutputStream baos = new ByteArrayOutputStream();
113          
114            ObjectOutputStream oos = null;
115            byte[] ret = null;
116            byte[][] tmpret = new byte[args.length][];
117    
118            try {
119                oos = (ObjectOutputStream) new JacObjectOutputStream(baos);
120                
121                oos.writeObject(new Integer(args.length));
122    
123                for(int i=0;i<args.length;i++) {
124                 if(refs!=null && refs[i].equals(Boolean.TRUE)) {
125                Collaboration.get().addAttribute(SerializedJacObject.STATELESS, Boolean.TRUE);
126                 }
127               oos.writeObject(args[i]);
128                }
129                
130                oos.close();
131                ret = baos.toByteArray();
132                
133               baos.close();
134            } catch(Exception e) { 
135               e.printStackTrace(); 
136            }
137          
138            return ret;
139         }   
140       
141       /**
142        * Deserialize an object from an array of bytes.
143        *
144        * <p>If the programmer uses this method, the aspect components are
145        * upcalled (<code>whenDeserialized()</code> method) to parametrize the
146        * deserialization by using a corresponding <code>SerializedJacObject</code>
147        * instance.
148        *
149        * <p>A symetric process is implemented by <code>serialize()</code>
150        *
151        * @param data      the array of bytes
152        * @return the object or null if a error has been encountered
153        * 
154        * @see AspectComponent#whenDeserialized(SerializedJacObject,Wrappee)
155        * @see SerializedJacObject
156        * @see #serialize(Object)
157        * @see JacObjectInputStream */
158        
159       public static Object deserialize(byte[] data) {
160       
161          ByteArrayInputStream bais = new ByteArrayInputStream(data);
162          
163          ObjectInputStream ois = null;
164          Object ret = null;
165    
166          try {
167             ois = (ObjectInputStream)new JacObjectInputStream(bais);
168             ret = ois.readObject();
169             //Log.trace("serialization",2,"deserialize "+ret);
170             ois.close();
171             bais.close();
172          } catch(Exception e) { 
173             e.printStackTrace(); 
174          }
175          
176          return ret;
177       }
178    
179        /**
180         * Deserialize the arguments of a method. */
181    
182       public static Object deserializeArgs(byte[] data) {
183       
184          ByteArrayInputStream bais = new ByteArrayInputStream(data);
185          
186          ObjectInputStream ois = null;
187          Object[] ret = null;
188            int nbArgs=0;
189            try {
190             ois = (ObjectInputStream)new JacObjectInputStream(bais);
191             nbArgs = ((Integer)ois.readObject()).intValue();
192             ret=new Object[nbArgs];
193             for(int i=0;i<nbArgs;i++) {
194                  ret[i] = ois.readObject();
195             }
196             ois.close();
197             bais.close();
198     
199          } catch(Exception e) { 
200             e.printStackTrace(); 
201          }
202          
203          return ret;
204       }
205    
206       /** The class name of the serialized JAC object. */
207       protected String jacObjectClassName;
208    
209       /** The serialized fields for this JAC object. */
210       protected HashMap fields = new HashMap();
211    
212       /** Extra Aspect Component related infos to be serialized. */
213       protected HashMap acInfos = new HashMap();
214    
215        /** If true, the deserialized object will be a forwarder towards
216            the actual object. Default is true. */
217        protected boolean forwarder = true;
218    
219       /** 
220        * The constructor of a serialized JacObject.
221        * 
222        * <p>The programmer do not need to call this method since it is
223        * implicitly called by <code>JacObjectOutputStream</code>.
224        * 
225        * @param jacObjectClassName the class name of the serialized JAC object
226        * @see JacObjectOutputStream */
227    
228       public SerializedJacObject ( String jacObjectClassName ) {
229          this.jacObjectClassName = jacObjectClassName;
230       }
231       
232       /** 
233        * Returns a hashtable that contains the field names to be
234        * serialized and their values.
235        *
236        * @return the serialized fields */
237    
238       public HashMap getFields() {
239          return fields;
240       }
241       
242       /**
243        * Add a field to be serialized.
244        *
245        * @param name the field name 
246        * @param value its value */
247    
248       public void addField ( String name, Object value ) {
249          if ( name != null )
250             fields.put ( name, value );
251       }
252    
253       /**
254        * Get a serialized field value.
255        *
256        * <p>This value has been added with the <code>addField</code>
257        * method.
258        * 
259        * @param name the name of the serialized field
260        * @return its value
261        * @see #addField(String,Object) */
262    
263       public Object getField ( String name ) {
264          if ( name == null ) return null;
265          return fields.get ( name );
266       }
267    
268       /** 
269        * Returns the serialized JAC object class name.
270        *
271        * @return the class name */
272    
273       public String getJacObjectClassName() { return jacObjectClassName; }
274    
275       /**
276        * Add some aspect component related infos to be serialized.
277        *
278        * <p>This method can be used by an aspect component within the
279        * <code>whenSerialized()</code> method. It allows the aspect
280        * programmer to add some relevant informations to be serialized
281        * (for instance when transmiting JAC objects to remote host or
282        * saving them on the disk).
283        * 
284        * <p>During the deserialization, an aspect component can retrieve
285        * these added information by using <code>getACInfos()</code>.
286        *
287        * @param acName the name of the aspect component that has set this
288        * information
289        * @param infos any serializable object
290        * 
291        * @see AspectComponent
292        * @see AspectComponent#whenSerialized(Wrappee,SerializedJacObject)
293        * @see #getACInfos(String) */
294    
295       public void setACInfos ( String acName, Object infos ) {
296          if ( acName != null )
297             acInfos.put( acName, infos );
298       }
299       
300       /**
301        * Get some aspect component related infos to be deserialized.
302        *
303        * <p>This method can be used by an aspect component within the
304        * <code>whenDeserialized()</code> method. It allows the aspect
305        * programmer to get some relevant informations to be deserialized
306        * (for instance when transmiting JAC objects to remote host or
307        * saving them on the disk).
308        * 
309        * <p>The retrieved informations are usually set during the
310        * serialization by using <code>setACInfos()</code>.
311        *
312        * @param acName the name of the aspect component that has set this
313        * information
314        * @return the information
315        * 
316        * @see AspectComponent
317        * @see AspectComponent#whenDeserialized(SerializedJacObject,Wrappee)
318        * @see #setACInfos(String,Object) 
319        */
320    
321       public Object getACInfos(String acName) {
322          if (acName == null) return null;
323          return acInfos.get(acName);
324       }
325    
326        /**
327         * Tells if the serialized object is a forwarder. By default, all
328         * the serialized JAC objects are forwarders.
329         * 
330         * <p>When a serialized JAC object is a forwarder, then if, when
331         * deserialized, no name-corresponding JAC object is found, then
332         * the deserialized object is wrapped by a binding wrapper so that
333         * the binding aspect is able to resolve the actual object later
334         * on. Of course, if a corresponding JAC object is found, then the
335         * deserialized JAC object is replaced by the actual object.
336         *
337         * <p>When a serialized JAC object is not a forwarder, then no
338         * replacement or binding mechanism occurs.
339         *
340         * @return true if forwarder
341         * 
342         * @see org.objectweb.jac.aspects.naming.NamingAC#whenSerialized(Wrappee,SerializedJacObject)
343         * @see org.objectweb.jac.aspects.naming.BindingAC#whenDeserialized(SerializedJacObject,Wrappee)
344         */
345    
346       public boolean isForwarder() {
347          return forwarder;
348       }
349    
350        /**
351         * Disable the forwarding.
352         *
353         * <p>If this method is called, the <code>isForwarder</code>
354         * method will return false.
355         *
356         * @see #isForwarder()
357         * @see #enableForwarding() */
358    
359        public void disableForwarding() {
360           forwarder = false;
361        }
362    
363        /**
364         * Enable the forwarding.
365         * 
366         * <p>If this method is called, the <code>isForwarder</code>
367         * method will return true (default).
368         *
369         * @see #isForwarder()
370         * @see #disableForwarding() */
371    
372        public void enableForwarding() {
373           forwarder = true;
374        }
375    
376    }
377    
378    
379    
380