001: // $Id: Marshaller.java,v 1.5 2004/10/04 20:43:35 belaban Exp $
002:
003: package org.jgroups.util;
004:
005: import org.jgroups.conf.ClassConfigurator;
006: import org.jgroups.ChannelException;
007:
008: import java.io.Externalizable;
009: import java.io.IOException;
010: import java.io.ObjectInput;
011: import java.io.ObjectOutput;
012:
013: /**
014: * Title: JGroups Communications
015: * Description: Contact me at <a href="mailto:mail@filip.net">mail@filip.net</a>
016: * Copyright: Copyright (c) 2002
017: * Company: www.filip.net
018: * @author Filip Hanik
019: * @author Bela Ban
020: * @version 1.0
021: *
022: * This class marshalls classes, in other words it serializes and deserializes classes
023: * to and from object streams.
024: * It performs a magic number matching to decrease the number of bytes that are being sent
025: * over the wire.
026: * If no magic number is available for the class, the classname is sent over instead
027: */
028: public class Marshaller {
029: /**
030: * The class configurator maps classes to magic numbers
031: */
032: private static final ClassConfigurator mConfigurator;
033:
034: static {
035: try {
036: mConfigurator = ClassConfigurator.getInstance(true);
037: } catch (ChannelException e) {
038: throw new ExceptionInInitializerError(e.toString());
039: }
040: }
041:
042: public Marshaller() {
043: }
044:
045: /**
046: * reads the magic number, instantiates the class (from the
047: * configurator) and invokes the readExternal method on the object.
048: * If no magic number is present, the method will read the
049: * string and then get the class from the configurator.
050: * @param in an ObjectInput stream - the stream should be composed as follows:<BR>
051: * [boolean -> int|string -> object data]
052: * <BR>
053: * If the boolean is true, then the next value is an int, the magic number.<BR>
054: * If the boolean is false, then the next value is a string (the class name)<BR>
055: * The object data is what the object instance uses to populate its fields<BR>
056: */
057: public static Externalizable read(ObjectInput in)
058: throws IOException {
059: try {
060: boolean is_null = in.readBoolean();
061: if (is_null)
062: return null;
063:
064: //see if we want to use a magic number
065: boolean usemagic = in.readBoolean();
066: //the class that we will use to instantiate the object with
067: Class extclass = null;
068: if (usemagic) {
069: //read the magic number
070: int magic = in.readInt();
071: //from the magic number, get the class
072: extclass = mConfigurator.get(magic);
073: } else {
074: //we don't have a magic number, read the class name
075: String magic = in.readUTF();
076: //get the class, ie let the configurator load it
077: extclass = mConfigurator.get(magic);
078: }//end if
079: //instantiate the object
080: Externalizable newinstance = (Externalizable) extclass
081: .newInstance();
082: //populate the object with its data
083: newinstance.readExternal(in);
084: //return the instance
085: return newinstance;
086: } catch (Throwable x) {
087: if (x instanceof IOException)
088: throw (IOException) x;
089: else
090: throw new IOException(x.toString());
091: }
092: }
093:
094: /**
095: * Writes an object to the ObjectOutput stream.
096: * If possible, we will send over a magic number instead of the class name
097: * so that we transfer less amount of data.
098: * @param inst - an object instance to be serialized, can not be null
099: * @param out - the ObjectOutput stream we will write the serialized data to
100: */
101: public static void write(Externalizable inst, ObjectOutput out)
102: throws IOException {
103: boolean is_null = (inst == null);
104: try {
105: // if inst is a null value we write this first
106: out.writeBoolean(is_null);
107: if (is_null)
108: return;
109:
110: //find out if we have a magic number for this class
111: int magic = mConfigurator.getMagicNumber(inst.getClass());
112: //-1 means no magic number otherwise we have one
113: if (magic != -1) {
114: //true means we use a magic number
115: out.writeBoolean(true);
116: //write the magic number
117: out.writeInt(magic);
118: } else {
119: //we don't have a magic number
120: out.writeBoolean(false);
121: //write the classname instead
122: out.writeUTF(inst.getClass().getName());
123: }//end if
124: //write the object data
125: inst.writeExternal(out);
126: } catch (Exception x) {
127: if (x instanceof IOException)
128: throw (IOException) x;
129: else
130: throw new java.io.IOException(x.toString());
131: }
132: }
133:
134: }
|