001: /*
002: * <copyright>
003: *
004: * Copyright 1997-2004 BBNT Solutions, LLC
005: * under sponsorship of the Defense Advanced Research Projects
006: * Agency (DARPA).
007: *
008: * You can redistribute this software and/or modify it under the
009: * terms of the Cougaar Open Source License as published on the
010: * Cougaar Open Source Website (www.cougaar.org).
011: *
012: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
013: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
014: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
015: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
016: * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
017: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
018: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
019: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
020: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
021: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
022: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
023: *
024: * </copyright>
025: */
026: package org.cougaar.mts.rmi;
027:
028: import java.io.ObjectOutput;
029: import java.net.URI;
030: import java.rmi.server.RemoteObject;
031: import java.rmi.server.RemoteRef;
032:
033: import org.cougaar.mts.base.SocketFactory;
034:
035: import sun.rmi.server.UnicastRef;
036:
037: /**
038: * Encode an RMI RemoteObject as a URI.
039: *
040: * @see RMIRemoteObjectDecoder
041: */
042: public final class RMIRemoteObjectEncoder {
043:
044: private RMIRemoteObjectEncoder() {
045: }
046:
047: /**
048: * Encode an rmi RemoteObject as a URI.
049: * <p>
050: * The object must be a RemoteObject, and the ".getRef()" must be
051: * of type UnicastRef. This implementation is <i>strongly</i> tied
052: * to the serialization format of the RMI infrastructure. However,
053: * Sun strives to keep RMI stable across JDK releases, so I don't
054: * expect this to be a problem...
055: * <p>
056: * For example, given an object with a ".toString()" of:<pre>
057: * "com.foo.Bar_Stub[RemoteStub [ref: [endpoint:[127.0.0.1:45123](remote),objID:[189d0c:f2389d89ac:-8000, 0]]]]"
058: * </pre>the generated URI will look like:<pre>
059: * "rmi://127.0.0.1:45123/com.foo.Bar_Stub/1_189d0c_f2389d89ac_-8000_0"
060: * </pre>. Note that the server-side object's ".toString()" will
061: * hide the ObjID and look more like:<pre>
062: * "com.foo.Bar_Stub[RemoteStub [ref: [endpoint:[127.0.0.1:45123](local),objID:[0]]]]"
063: * </pre> but we work around that here.
064: *
065: * @param o a RemoteObject to encode
066: * @return the URI representation
067: * @see RMIRemoteObjectDecoder#decode(URI)
068: */
069: public static URI encode(Object o) throws Exception {
070: return encode(o, true);
071: }
072:
073: /**
074: * @param forceRemote force remote flag -- I think this only makes
075: * a difference if a client passed a decoded object off to a
076: * third party.
077: */
078: public static URI encode(Object o, boolean forceRemote)
079: throws Exception {
080: RemoteObject ro = (RemoteObject) o;
081: String clname = o.getClass().getName();
082: RemoteRef ref = ro.getRef();
083: MyObjectOutput oo = new MyObjectOutput();
084: ((UnicastRef) ref).writeExternal(oo);
085: // Later add the two csf flags use_ssl and use_aspects
086: StringBuffer buf = new StringBuffer();
087: buf.append("rmi://");
088: buf.append(oo.tcp_host);
089: buf.append(':');
090: buf.append(oo.tcp_port);
091: buf.append('/');
092: buf.append(clname);
093: buf.append('/');
094: buf.append((forceRemote || oo.ref_remote) ? "1" : "0");
095: buf.append('_');
096: buf.append(Integer.toString(oo.uid_unique, 16));
097: buf.append('_');
098: buf.append(Long.toString(oo.uid_time, 16));
099: buf.append('_');
100: buf.append(Integer.toString(oo.uid_count, 16));
101: buf.append('_');
102: buf.append(oo.oid_num);
103: buf.append('/');
104: if (oo.has_csf) {
105: buf.append(oo.use_ssl ? "1" : "0");
106: buf.append(oo.use_aspects ? "1" : "0");
107: }
108: return new URI(buf.toString());
109: }
110:
111: /** custom object output, exactly matching UnicastRef */
112: private static class MyObjectOutput implements ObjectOutput {
113:
114: public String tcp_host;
115: public int tcp_port;
116: public long oid_num;
117: public int uid_unique;
118: public long uid_time;
119: public short uid_count;
120: public boolean ref_remote;
121: public boolean has_csf;
122: public boolean use_ssl;
123: public boolean use_aspects;
124:
125: private int state = 0;
126:
127: private int state() {
128: return has_csf ? state - 1 : state;
129: }
130:
131: public void writeInt(int v) {
132: ++state;
133: if (state() == 2) {
134: tcp_port = v;
135: } else if (state() == 4) {
136: uid_unique = v;
137: } else {
138: die();
139: }
140: }
141:
142: public void writeLong(long v) {
143: ++state;
144: if (state() == 3) {
145: oid_num = v;
146: } else if (state() == 5) {
147: uid_time = v;
148: } else {
149: die();
150: }
151: }
152:
153: public void writeShort(int v) {
154: ++state;
155: if (state() == 6) {
156: uid_count = (short) v;
157: } else {
158: die();
159: }
160: }
161:
162: public void writeUTF(String str) {
163: ++state;
164: if (state() == 1) {
165: tcp_host = str;
166: } else {
167: die();
168: }
169: }
170:
171: public void writeBoolean(boolean v) {
172: ++state;
173: if (state() == 7) {
174: ref_remote = v;
175: } else {
176: die();
177: }
178: }
179:
180: public void writeByte(int v) {
181: // Only called if the object has a csf
182: ++state;
183: if (state == 1) {
184: has_csf = true;
185: } else {
186: die();
187: }
188: }
189:
190: public void writeObject(Object obj) {
191: if (!has_csf)
192: die();
193: if (!(obj instanceof SocketFactory))
194: die();
195: if (state != 3)
196: die();
197: SocketFactory csf = (SocketFactory) obj;
198: use_ssl = csf.usesSSL();
199: use_aspects = csf.isMTS();
200: }
201:
202: // die:
203: private void die() {
204:
205: throw new RuntimeException(
206: "RemoteObject writer has changed (state=" + state
207: + ")");
208: }
209:
210: // DataOutput:
211: public void write(int b) {
212: die();
213: }
214:
215: public void write(byte b[]) {
216: die();
217: }
218:
219: public void write(byte b[], int off, int len) {
220: die();
221: }
222:
223: public void writeChar(int v) {
224: die();
225: }
226:
227: public void writeFloat(float v) {
228: die();
229: }
230:
231: public void writeDouble(double v) {
232: die();
233: }
234:
235: public void writeBytes(String s) {
236: die();
237: }
238:
239: public void writeChars(String s) {
240: die();
241: }
242:
243: // ObjectOutput:
244: public void flush() {
245: die();
246: }
247:
248: public void close() {
249: die();
250: }
251: }
252: }
|