PageRenderTime 40ms CodeModel.GetById 19ms app.highlight 16ms RepoModel.GetById 1ms app.codeStats 0ms

/interpreter/tags/at2dist220411/src/edu/vub/at/actors/natives/Packet.java

http://ambienttalk.googlecode.com/
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}