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.client;
023:
024: import java.io.DataInputStream;
025: import java.io.IOException;
026: import java.io.StreamCorruptedException;
027: import java.io.ObjectInput;
028: import java.io.ObjectOutput;
029: import java.lang.reflect.Method;
030: import java.rmi.RemoteException;
031: import java.rmi.UnmarshalException;
032: import java.rmi.UnexpectedException;
033: import java.rmi.server.RemoteCall;
034: import java.rmi.server.UID;
035:
036: import org.apache.harmony.rmi.common.RMILog;
037: import org.apache.harmony.rmi.internal.nls.Messages;
038: import org.apache.harmony.rmi.remoteref.UnicastRef;
039: import org.apache.harmony.rmi.transport.RMIObjectInputStream;
040: import org.apache.harmony.rmi.transport.RMIObjectOutputStream;
041: import org.apache.harmony.rmi.transport.RMIProtocolConstants;
042:
043: /**
044: * RemoteCall implementation used by UnicastRef on client's side.
045: *
046: * @author Mikhail A. Markov
047: * @version $Revision: 1.1.2.2 $
048: */
049: public class ClientRemoteCall implements RemoteCall,
050: RMIProtocolConstants {
051:
052: // Connection to remote server.
053: private ClientConnection conn;
054:
055: // InputStream for reading objects.
056: private RMIObjectInputStream oin = null;
057:
058: // OutputStream for sending objects.
059: private RMIObjectOutputStream oout = null;
060:
061: // true if this remote call was closed
062: private boolean isClosed = false;
063:
064: // UID received from server
065: private UID uid;
066:
067: // Method this remote call was created for.
068: private Method m = null;
069:
070: /**
071: * Constructs ClientRemoteCall from existing connection.
072: *
073: * @param conn opened ClientConnection
074: */
075: public ClientRemoteCall(ClientConnection conn) {
076: this .conn = conn;
077: }
078:
079: /**
080: * Constructs ObjectInputStream (if it was not created yet) and returns
081: * this created stream.
082: *
083: * @return ObjectInputStream to read objects from
084: *
085: * @throws IOException if an I/O error occurred during stream construction
086: */
087: public ObjectInput getInputStream() throws IOException {
088: if (oin == null) {
089: oin = new RMIObjectInputStream(conn.getInputStream(), true);
090: }
091: return oin;
092: }
093:
094: /**
095: * Constructs ObjectOutputStream (if it was not created yet) and returns
096: * this created stream.
097: *
098: * @return ObjectOutputStream to write objects to
099: *
100: * @throws IOException if an I/O error occurred during stream construction
101: */
102:
103: public ObjectOutput getOutputStream() throws IOException {
104: if (oout == null) {
105: oout = new RMIObjectOutputStream(conn.getOutputStream());
106: }
107: return oout;
108: }
109:
110: /**
111: * @see RemoteCall.getResultStream(boolean)
112: */
113: public ObjectOutput getResultStream(boolean success)
114: throws IOException, StreamCorruptedException {
115: return getOutputStream();
116: }
117:
118: /**
119: * @see RemoteCall.releaseInputStream()
120: */
121: public void releaseInputStream() throws IOException {
122: }
123:
124: /**
125: * @see RemoteCall.releaseOutputStream()
126: */
127: public void releaseOutputStream() throws IOException {
128: getOutputStream().flush();
129: conn.releaseOutputStream();
130: }
131:
132: /**
133: * @see RemoteCall.done()
134: */
135: public void done() throws IOException {
136: if (!isClosed) {
137: if (oin.isRemoteCallStream() && oin.isDGCAckNeeded()) {
138: // we need to make a DGC ack call
139: conn.sendDGCAck(uid == null ? (uid = new UID()) : uid);
140: }
141: conn.done();
142: }
143: }
144:
145: /**
146: * Closes connection/this remote call.
147: *
148: */
149: public void close() {
150: conn.close();
151: isClosed = true;
152: }
153:
154: /**
155: * @see RemoteCall.executeCall()
156: */
157: public void executeCall() throws Exception {
158: if (isClosed) {
159: // rmi.38=Remote call is already closed.
160: throw new RemoteException(Messages.getString("rmi.38")); //$NON-NLS-1$
161: }
162: byte data;
163:
164: try {
165: // read input
166: if ((data = (new DataInputStream(conn.getInputStream()))
167: .readByte()) != CALL_OK) {
168: // rmi.39=Unknown call status response: {0}
169: throw new UnmarshalException(Messages.getString(
170: "rmi.39", data)); //$NON-NLS-1$
171: }
172:
173: // read return value id
174: getInputStream();
175: data = oin.readByte();
176: } catch (UnmarshalException re) {
177: throw re;
178: } catch (IOException ioe) {
179: // rmi.3A=Unable to read call return header:
180: throw new UnmarshalException(Messages.getString("rmi.3A"), //$NON-NLS-1$
181: ioe);
182: }
183:
184: if (data != RETURN_VAL && data != RETURN_EX) {
185: // rmi.3B=Unknown call result response: {0}
186: throw new UnmarshalException(Messages.getString(
187: "rmi.3B", data)); //$NON-NLS-1$
188: }
189: uid = UID.read(oin);
190:
191: if (data == RETURN_EX) {
192: getExceptionFromServer();
193: }
194: }
195:
196: /**
197: * Sets the method for this RemoteCall to the given value.
198: * This value will be used later for throwing UnexpectedException.
199: *
200: * @param m Method this call was created for
201: */
202: public void setMethod(Method m) {
203: this .m = m;
204: }
205:
206: /**
207: * Returns string representation of this RemoteCall.
208: *
209: * @return string representation of this RemoteCall
210: */
211: public String toString() {
212: return "ClientRemoteCall: " + conn; //$NON-NLS-1$
213: }
214:
215: /*
216: * Reads exception thrown by server from the opened ObjectInputStream,
217: * processes it and throws appropriate exception.
218: *
219: * @throws Exception exception depending on one thrown by the server side
220: */
221: private void getExceptionFromServer() throws Exception {
222: Object obj = null;
223:
224: try {
225: obj = oin.readObject();
226: } catch (IOException ioe) {
227: // rmi.3C=IOException occurred while unmarshalling returned exception
228: throw new UnmarshalException(
229: Messages.getString("rmi.3C"), ioe); //$NON-NLS-1$
230:
231: } catch (ClassNotFoundException cnfe) {
232: // rmi.3D=ClassNotFoundException occurred while unmarshalling returned exception
233: throw new UnmarshalException(
234: Messages.getString("rmi.3D"), cnfe); //$NON-NLS-1$
235: }
236:
237: if (obj instanceof Exception) {
238: Exception resEx = (Exception) obj;
239:
240: if (!(resEx instanceof RuntimeException) && m != null) {
241: boolean ok = false;
242: Class[] declaredExs = m.getExceptionTypes();
243:
244: for (int i = 0; i < declaredExs.length; ++i) {
245: if (declaredExs[i].isAssignableFrom(resEx
246: .getClass())) {
247: ok = true;
248: break;
249: }
250: }
251:
252: if (!ok) {
253: // rmi.3E=Remote method threw unexpected exception
254: resEx = new UnexpectedException(Messages
255: .getString("rmi.3E"), resEx); //$NON-NLS-1$
256: }
257: }
258:
259: // Add our stacktrace to the stacktrace of exception received
260: StackTraceElement[] origST = resEx.getStackTrace();
261: StackTraceElement[] curST = (new Exception())
262: .getStackTrace();
263: StackTraceElement[] resST = new StackTraceElement[origST.length
264: + curST.length];
265: System.arraycopy(origST, 0, resST, 0, origST.length);
266: System.arraycopy(curST, 0, resST, origST.length,
267: curST.length);
268: resEx.setStackTrace(resST);
269:
270: // logs exception from server
271: if (UnicastRef.clientCallsLog.isLoggable(RMILog.BRIEF)) {
272: UnicastRef.clientCallsLog.log(RMILog.BRIEF, Messages
273: .getString("rmi.log.92", conn), resEx); //$NON-NLS-1$
274: }
275: throw resEx;
276: } else {
277: // rmi.3F=Not Exception type thrown: {0}
278: throw new UnexpectedException(Messages.getString(
279: "rmi.3F", obj)); //$NON-NLS-1$
280: }
281: }
282: }
|