001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: *
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: */
018:
019: /**
020: * @author Mikhail A. Markov
021: * @version $Revision: 1.1.2.2 $
022: */package org.apache.harmony.rmi.transport;
023:
024: import java.io.OutputStream;
025: import java.io.ObjectOutputStream;
026: import java.io.IOException;
027: import java.rmi.Remote;
028: import java.rmi.server.RemoteObject;
029: import java.rmi.server.RemoteStub;
030: import java.rmi.server.RMIClassLoader;
031: import java.rmi.server.UID;
032: import java.security.AccessController;
033: import java.security.PrivilegedAction;
034:
035: import org.apache.harmony.rmi.internal.nls.Messages;
036: import org.apache.harmony.rmi.server.ExportManager;
037:
038: /**
039: * The RMIObjectOutputStream is a subclass of ObjectOutputStream performing
040: * serialization for RMI calls. The following rules are used in addition to
041: * normal serialization ones:
042: * - if codebase URL is available for a class, the class will be annotated
043: * with this URL
044: * - remote objects are represented in RMIOutputStream by serialized forms
045: * of their stubs
046: *
047: * @author Mikhail A. Markov
048: * @version $Revision: 1.1.2.2 $
049: */
050: public class RMIObjectOutputStream extends ObjectOutputStream {
051:
052: // ObjectOutputStream to write annotations.
053: private ObjectOutputStream locStream;
054:
055: /** True if at least one of written annotations is not null. */
056: protected boolean hasAnnotations;
057:
058: // True if this stream was created in RemoteCall.getResultStream() method.
059: private boolean isResultStream = false;
060:
061: // UID to be written to the stream as DGC ack UID.
062: private UID uid = new UID();
063:
064: /**
065: * Constructs a RMIObjectOutputStream that writes to the specified
066: * OutputStream.
067: *
068: * @param out underlying OutputStream
069: *
070: * @throws IOException if an I/O error occurred during stream initialization
071: */
072: public RMIObjectOutputStream(OutputStream out) throws IOException {
073: this (out, false);
074: }
075:
076: /**
077: * Constructs a RMIObjectOutputStream that writes to the specified
078: * OutputStream.
079: *
080: * @param out underlying OutputStream
081: * @param isResultStream true if this stream was created
082: * in RemoteCall.getResultStream() method
083: *
084: * @throws IOException if an I/O error occurred during stream initialization
085: */
086: public RMIObjectOutputStream(OutputStream out,
087: boolean isResultStream) throws IOException {
088: super (out);
089: this .isResultStream = isResultStream;
090: locStream = this ;
091: hasAnnotations = false;
092: AccessController.doPrivileged(new PrivilegedAction() {
093: public Object run() {
094: enableReplaceObject(true);
095: return null;
096: }
097: });
098: }
099:
100: /**
101: * Replaces exported Remote objects with their stubs.
102: *
103: * @param obj Object to be replaced if needed
104: *
105: * @return stub for exported Remote object or unmodified object otherwise
106: *
107: * @throws IOException
108: */
109: protected Object replaceObject(Object obj) throws IOException {
110: return ((obj instanceof Remote) && !(obj instanceof RemoteStub) && ExportManager
111: .isExported((Remote) obj)) ? RemoteObject
112: .toStub((Remote) obj) : obj;
113: }
114:
115: /**
116: * Annotates specified class with it's codebase URL if available.
117: *
118: * @param cl class to be annotated
119: */
120: protected void annotateClass(Class cl) throws IOException {
121: String annot = RMIClassLoader.getClassAnnotation(cl);
122: hasAnnotations |= (annot != null);
123: locStream.writeObject(annot);
124: }
125:
126: /**
127: * Annotates specified proxy class with it's codebase URL if available.
128: *
129: * @param cl proxy class to be annotated
130: */
131: protected void annotateProxyClass(Class cl) throws IOException {
132: annotateClass(cl);
133: }
134:
135: /**
136: * Flushes the stream.
137: *
138: * @throws IOException If an I/O error has occurred.
139: */
140: public void flush() throws IOException {
141: super .flush();
142:
143: if (locStream != this ) {
144: locStream.flush();
145: }
146: }
147:
148: /**
149: * Sets annotation's stream to the value specified.
150: * Subclasses should call this method if they want to write annotations to
151: * the stream other then one for objects themselves.
152: *
153: * @param out stream for annotations
154: */
155: protected void setLocStream(ObjectOutputStream out) {
156: locStream = out;
157: }
158:
159: /**
160: * Returns true if at least one of written annotations is not null and
161: * false otherwise.
162: *
163: * @return true if at least one of written annotations is not null
164: */
165: protected boolean hasAnnotations() {
166: return hasAnnotations;
167: }
168:
169: /**
170: * Write specified obj (possibly primitive) to the stream.
171: *
172: * @param obj object (possibly primitive) to be written to the stream
173: * @param cl type of object to be written to the stream
174: *
175: * @throws IOException if an I/O error occurred during serialization
176: */
177: public void writeRMIObject(Object obj, Class cl) throws IOException {
178: if (cl.isPrimitive()) {
179: if (cl == Boolean.TYPE) {
180: writeBoolean(((Boolean) obj).booleanValue());
181: } else if (cl == Byte.TYPE) {
182: writeByte(((Byte) obj).byteValue());
183: } else if (cl == Short.TYPE) {
184: writeShort(((Short) obj).shortValue());
185: } else if (cl == Integer.TYPE) {
186: writeInt(((Integer) obj).intValue());
187: } else if (cl == Long.TYPE) {
188: writeLong(((Long) obj).longValue());
189: } else if (cl == Float.TYPE) {
190: writeFloat(((Float) obj).floatValue());
191: } else if (cl == Double.TYPE) {
192: writeDouble(((Double) obj).doubleValue());
193: } else if (cl == Character.TYPE) {
194: writeChar(((Character) obj).charValue());
195: } else if (cl == Void.TYPE) {
196: } else {
197: // rmi.7E=Unable to serialize primitive class: {0}
198: throw new IOException(Messages.getString("rmi.7E", cl));//$NON-NLS-1$
199: }
200: } else {
201: writeObject(obj);
202: }
203: }
204:
205: /**
206: * Returns true if this stream was created in RemoteCall.getResultStream()
207: * method and false otherwise.
208: *
209: * @return true if this stream was created in RemoteCall.getResultStream()
210: * method and false otherwise
211: */
212: public boolean isResultStream() {
213: return isResultStream;
214: }
215:
216: /**
217: * Writes DGC ack UID to this stream.
218: *
219: * @throws IOException if any I/O error occurred while writing
220: */
221: public void writeUID() throws IOException {
222: uid.write(this );
223: }
224:
225: /**
226: * Returns uid used for DGC ack.
227: *
228: * @return uid used for DGC ack
229: */
230: public UID getUID() {
231: return uid;
232: }
233: }
|