/* Copyright (c) 2006-2009 Jan S. Rellermeyer
* Systems Group,
* Department of Computer Science, ETH Zurich.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of ETH Zurich nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package ch.ethz.iks.r_osgi.messages;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.SocketException;
import ch.ethz.iks.r_osgi.RemoteOSGiException;
/**
* <p>
* Abstract base class for all Messages.
* </p>
*
* @author Jan S. Rellermeyer, ETH Zurich
* @since 0.1
*/
public abstract class RemoteOSGiMessage {
/**
* type code for lease messages.
*/
public static final short LEASE = 1;
/**
* type code for fetch service messages.
*/
public static final short REQUEST_SERVICE = 2;
/**
* type code for deliver service messages.
*/
public static final short DELIVER_SERVICE = 3;
/**
* type code for deliver bundle messages.
*
* @deprecated
*/
public static final short DELIVER_BUNDLE = 4;
/**
* type code for invoke method messages.
*/
public static final short REMOTE_CALL = 5;
/**
* type code for method result messages.
*/
public static final short REMOTE_CALL_RESULT = 6;
/**
* type code for remote event messages.
*/
public static final short REMOTE_EVENT = 7;
/**
* type code for time offset messages.
*/
public static final short TIME_OFFSET = 8;
/**
* type code for service attribute updates.
*/
public static final short LEASE_UPDATE = 9;
/**
* type code for stream request messages.
*/
public static final short STREAM_REQUEST = 10;
/**
* type code for stream result messages.
*/
public static final short STREAM_RESULT = 11;
/**
* type code for request dependency message.
*/
public static final short REQUEST_DEPENDENCIES = 12;
/**
* type code for request bundle message
*/
public static final short REQUEST_BUNDLE = 13;
/**
* type code for deliver bundles message
*/
public static final short DELIVER_BUNDLES = 14;
/**
* the type code or functionID in SLP notation.
*/
private short funcID;
/**
* the transaction id.
*/
protected int xid;
/**
* hides the default constructor.
*/
RemoteOSGiMessage(final short funcID) {
this.funcID = funcID;
}
/**
* get the transaction ID.
*
* @return the xid.
* @since 0.6
*/
public final int getXID() {
return xid;
}
/**
* set the xid.
*
* @param xid
* set the xid.
*/
public void setXID(final int xid) {
this.xid = xid;
}
/**
* Get the function ID (type code) of the message.
*
* @return the type code.
* @since 0.6
*/
public final short getFuncID() {
return funcID;
}
/**
* reads in a network packet and constructs the corresponding subtype of
* RemoteOSGiMessage from it. The header is:
*
* <pre>
* 0 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Version | Function-ID | XID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | XID cntd. |
* +-+-+-+-+-+-+-+-+
* </pre>
*
* the body is processed by the subtype class.
*
* @param input
* the DataInput providing the network packet.
* @return the RemoteOSGiMessage.
* @throws IOException
* @throws ClassNotFoundException
* @throws SocketException
* if something goes wrong.
*/
public static RemoteOSGiMessage parse(final ObjectInputStream input)
throws IOException, ClassNotFoundException {
input.readByte(); // version, currently unused
final short funcID = input.readByte();
final int xid = input.readInt();
RemoteOSGiMessage msg;
switch (funcID) {
case LEASE:
msg = new LeaseMessage(input);
break;
case REQUEST_SERVICE:
msg = new RequestServiceMessage(input);
break;
case DELIVER_SERVICE:
msg = new DeliverServiceMessage(input);
break;
case REMOTE_CALL:
msg = new RemoteCallMessage(input);
break;
case REMOTE_CALL_RESULT:
msg = new RemoteCallResultMessage(input);
break;
case REMOTE_EVENT:
msg = new RemoteEventMessage(input);
break;
case TIME_OFFSET:
msg = new TimeOffsetMessage(input);
break;
case LEASE_UPDATE:
msg = new LeaseUpdateMessage(input);
break;
case STREAM_REQUEST:
msg = new StreamRequestMessage(input);
break;
case STREAM_RESULT:
msg = new StreamResultMessage(input);
break;
case REQUEST_DEPENDENCIES:
msg = new RequestDependenciesMessage(input);
break;
case REQUEST_BUNDLE:
msg = new RequestBundleMessage(input);
break;
case DELIVER_BUNDLES:
msg = new DeliverBundlesMessage(input);
break;
default:
throw new RemoteOSGiException("funcID " + funcID //$NON-NLS-1$
+ " not supported."); //$NON-NLS-1$
}
msg.funcID = funcID;
msg.xid = xid;
return msg;
}
/**
* write the RemoteOSGiMessage to an output stream.
*
* @param out
* the ObjectOutputStream.
* @throws IOException
* in case of IO failures.
*/
public final void send(final ObjectOutputStream out) throws IOException {
synchronized (out) {
out.write(1);
out.write(funcID);
out.writeInt(xid);
writeBody(out);
out.reset();
out.flush();
}
}
/**
* write the body of a RemoteOSGiMessage.
*
* @param output
* the output stream.
* @throws IOException
* in case of IO failures.
*/
protected abstract void writeBody(final ObjectOutputStream output)
throws IOException;
/**
* reads the bytes encoded as SLP string.
*
* @param input
* the DataInput.
* @return the byte array.
* @throws IOException
* in case of IO failures.
*/
protected static byte[] readBytes(final ObjectInputStream input)
throws IOException {
final int length = input.readInt();
final byte[] buffer = new byte[length];
input.readFully(buffer);
return buffer;
}
/**
* writes a byte array.
*
* @param out
* the output stream.
* @param bytes
* the bytes.
* @throws IOException
* in case of IO failures.
*/
protected static void writeBytes(final ObjectOutputStream out,
final byte[] bytes) throws IOException {
out.writeInt(bytes.length);
if (bytes.length > 0) {
out.write(bytes);
}
}
/**
* write a string array.
*
* @param out
* the output stream.
* @param strings
* the string array.
* @throws IOException
* in case of IO failures.
*/
protected static void writeStringArray(final ObjectOutputStream out,
final String[] strings) throws IOException {
final short length = (short) strings.length;
out.writeShort(length);
for (short i = 0; i < length; i++) {
out.writeUTF(strings[i]);
}
}
/**
* read a string array.
*
* @param in
* the input stream
* @return the read string array.
* @throws IOException
* in case of IO failures.
*/
protected static String[] readStringArray(final ObjectInputStream in)
throws IOException {
final short length = in.readShort();
final String[] result = new String[length];
for (short i = 0; i < length; i++) {
result[i] = in.readUTF();
}
return result;
}
}