/interpreter/tags/at2dist220411/src/edu/vub/at/actors/natives/Packet.java
Java | 183 lines | 104 code | 19 blank | 60 comment | 1 complexity | 6151448447978890529d94f13c7976e0 MD5 | raw file
1/** 2 * AmbientTalk/2 Project 3 * Packet.java created on 29-dec-2006 at 19:15:00 4 * (c) Programming Technology Lab, 2006 - 2007 5 * Authors: Tom Van Cutsem & Stijn Mostinckx 6 * 7 * Permission is hereby granted, free of charge, to any person 8 * obtaining a copy of this software and associated documentation 9 * files (the "Software"), to deal in the Software without 10 * restriction, including without limitation the rights to use, 11 * copy, modify, merge, publish, distribute, sublicense, and/or 12 * sell copies of the Software, and to permit persons to whom the 13 * Software is furnished to do so, subject to the following 14 * conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 21 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 26 * OTHER DEALINGS IN THE SOFTWARE. 27 */ 28package edu.vub.at.actors.natives; 29 30import edu.vub.at.actors.net.SerializationException; 31import edu.vub.at.exceptions.InterpreterException; 32import edu.vub.at.exceptions.XClassNotFound; 33import edu.vub.at.exceptions.XIOProblem; 34import edu.vub.at.objects.ATObject; 35 36import java.io.ByteArrayInputStream; 37import java.io.ByteArrayOutputStream; 38import java.io.IOException; 39import java.io.InputStream; 40import java.io.ObjectInputStream; 41import java.io.ObjectOutputStream; 42import java.io.ObjectStreamClass; 43import java.io.Serializable; 44import java.lang.reflect.Proxy; 45 46/** 47 * Packet instances are the serialized representation of AmbientTalk messages or other objects. 48 * They are exchanged directly in between local actors and in a wrapped VMCommand object between 49 * remote actors. 50 * 51 * @author tvcutsem 52 */ 53public class Packet implements Serializable { 54 55 private final byte[] payload_; 56 private final String description_; 57 58 public Packet(String description, ATObject object) throws XIOProblem { 59 description_ = description; 60 try { 61 payload_ = serialize(object); 62 } catch (IOException e) { 63 throw new XIOProblem(e); 64 } 65 } 66 67 public Packet(ATObject object) throws XIOProblem { 68 this(object.toString(), object); 69 } 70 71 public byte[] getPayload() { 72 return payload_; 73 } 74 75 /** 76 * Deserialize this message using the default class loader. 77 * In 99% of all cases this is okay, but on the Dalvik VM (used by Android) 78 * it needs a specific classloader. It also fails on java6 systems sometimes. 79 * Therefore, we try all three flavors of classloaders. 80 */ 81 public ATObject unpack() throws InterpreterException { 82 try { 83 ClassLoader c = this.getClass().getClassLoader(); 84 return unpackUsingClassLoader(c); 85 } catch ( XClassNotFound e) { 86 try { 87 ClassLoader s = ClassLoader.getSystemClassLoader(); 88 return unpackUsingClassLoader(s); 89 } catch (XClassNotFound ef) { 90 ClassLoader t = Thread.currentThread().getContextClassLoader(); 91 return unpackUsingClassLoader(t); 92 } 93 } 94 } 95 96 /** deserialize this message, using a custom class loader to load the classes into the JVM */ 97 public ATObject unpackUsingClassLoader(ClassLoader cld) throws InterpreterException { 98 try { 99 return (ATObject) deserialize(payload_, cld); 100 } catch (SerializationException e) { 101 throw e.getWrappedException(); 102 } catch (IOException e) { 103 throw new XIOProblem(e); 104 } catch (ClassNotFoundException e) { 105 throw new XClassNotFound(e.getMessage(), e); 106 } 107 } 108 109 /** 110 * Beware: the same object serialized into 2 different packets results in 111 * 2 non-equal packets. It is NOT the case that 112 * <code>new Packet(o).equals(new Packet(o))</code> 113 */ 114 public boolean equals(Object other) { 115 return ((other instanceof Packet) && 116 ((Packet) other).payload_.equals(payload_)); 117 } 118 119 public int hashCode() { return payload_.hashCode(); } 120 121 public String toString() { return "packet["+description_+"]"; } 122 123 private static byte[] serialize(Object o) throws IOException { 124 ByteArrayOutputStream out = new ByteArrayOutputStream(); 125 ObjectOutputStream stream = new ObjectOutputStream(out); 126 stream.writeObject(o); 127 stream.flush(); 128 stream.close(); 129 return out.toByteArray(); 130 } 131 132 private static Object deserialize(byte[] b) throws IOException, ClassNotFoundException { 133 ByteArrayInputStream in = new ByteArrayInputStream(b); 134 ObjectInputStream instream = new ObjectInputStream(in); 135 return instream.readObject(); 136 } 137 138 /** 139 * A dedicated subclass of {@link ObjectInputStream} that hooks into 140 * that class's facility to define additional sources to look for classes 141 * that are read from the input stream. 142 */ 143 private static class HookedObjectInputStream extends ObjectInputStream { 144 private final ClassLoader loader_; 145 protected HookedObjectInputStream(ClassLoader cld, InputStream is) throws IOException, SecurityException { 146 super(is); 147 loader_ = cld; 148 } 149 150 protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { 151 /* This does not work in the Sun Java 6 VM because of http://bugs.sun.com/view_bug.do?bug_id=6434149 152 * Using the suggested workaround. 153 */ 154 // return loader_.loadClass(desc.getName()); 155 return Class.forName(desc.getName(), false, loader_); 156 } 157 158 /** 159 * Creates the proxy class that implements the interfaces specified in 160 * {@code interfaceNames}. 161 */ 162 protected Class resolveProxyClass(String[] interfaceNames) 163 throws IOException, ClassNotFoundException { 164 Class[] interfaces = new Class[interfaceNames.length]; 165 for (int i = 0; i < interfaceNames.length; i++) { 166 interfaces[i] = Class.forName(interfaceNames[i], false, loader_); 167 } 168 try { 169 return Proxy.getProxyClass(loader_, interfaces); 170 } catch (IllegalArgumentException e) { 171 throw new ClassNotFoundException(e.toString(), e); 172 } 173 } 174 } 175 176 // deserialize and use the given class loader to try and load any missing classes 177 private static Object deserialize(byte[] b, ClassLoader cld) throws IOException, ClassNotFoundException { 178 ByteArrayInputStream in = new ByteArrayInputStream(b); 179 ObjectInputStream instream = new HookedObjectInputStream(cld, in); 180 return instream.readObject(); 181 } 182 183}