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