00001 /************************************************************************** 00002 Copyright (c) 2000-2001, Tony Garnock-Jones 00003 All rights reserved. 00004 00005 Redistribution and use in source and binary forms, with or without 00006 modification, are permitted provided that the following conditions are 00007 met: 00008 00009 * Redistributions of source code must retain the above copyright 00010 notice, this list of conditions and the following disclaimer. 00011 00012 * Redistributions in binary form must reproduce the above 00013 copyright notice, this list of conditions and the following 00014 disclaimer in the documentation and/or other materials provided 00015 with the distribution. 00016 00017 * Neither the names of the copyright holders nor the names of this 00018 software's contributors may be used to endorse or promote 00019 products derived from this software without specific prior 00020 written permission. 00021 00022 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00023 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00024 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00025 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR 00026 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00027 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00028 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00029 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 00030 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 00031 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 00032 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 **************************************************************************/ 00034 00035 package org.hebe.mps; 00036 00037 import java.io.*; 00038 import java.net.*; 00039 00040 /** 00041 * Flattens the bitstream going to an MPS server from MPS primitive 00042 * types. Uses a Connection object to talk to the other end. 00043 * 00044 * @author Tony Garnock-Jones <tonyg@kcbbs.gen.nz> 00045 * @see org.hebe.mps.Connection 00046 * @see org.hebe.mps.InputStream 00047 */ 00048 public class OutputStream { 00049 private Connection connection; 00050 private java.io.OutputStream output; 00051 private StringBuffer buffer; 00052 00053 /** 00054 * Construct an OutputStream which encodes the bits going to a 00055 * Connection object. 00056 * 00057 * @param c the raw connection to use 00058 */ 00059 public OutputStream(Connection c) { 00060 connection = c; 00061 output = null; 00062 setupBuffer(); 00063 } 00064 00065 /** 00066 * Creates and initialises a fresh StringBuffer in member variable buffer. 00067 */ 00068 private void setupBuffer() { 00069 buffer = new StringBuffer(); 00070 } 00071 00072 /** 00073 * Resets our internal buffer to empty. */ 00074 public void resetBuffer() { 00075 setupBuffer(); 00076 } 00077 00078 /** 00079 * Construct an OutputStream which sends bits to an arbitrary 00080 * inputstream. 00081 * 00082 * @param o the raw outputstream to use 00083 */ 00084 public OutputStream(java.io.OutputStream o) { 00085 connection = null; 00086 output = o; 00087 setupBuffer(); 00088 } 00089 00090 /** 00091 * Buffer up a single byte to send. The buffer is not flushed to 00092 * the server until the flush() method is called. 00093 * 00094 * @param ch the byte to buffer up 00095 * @see org.hebe.mps.OutputStream#flush 00096 */ 00097 private void write(int ch) { 00098 //System.out.println("Write: " + ch); 00099 buffer.append((char) ch); 00100 00101 /* 00102 byte[] ba = buffer.toString().getBytes(); 00103 for (int i = 0; i < ba.length; i++) { 00104 System.out.print((int) ba[i]); 00105 System.out.print(" "); 00106 } 00107 System.out.println(""); */ 00108 } 00109 00110 /** 00111 * Causes the connection to the server to open, if it isn't 00112 * already open. 00113 * 00114 * @exception MPSException from connection.getOutputStream() if there's a problem 00115 * @see org.hebe.mps.Connection#getOutputStream 00116 */ 00117 private void open() throws MPSException { 00118 if (output == null) 00119 output = connection.getOutputStream(); 00120 } 00121 00122 /** 00123 * Writes a single <i>int</i> to the server. 00124 * 00125 * @param i the 32-bit signed value to write 00126 */ 00127 public void writeint(int i) { 00128 write((i >> 24) & 255); 00129 write((i >> 16) & 255); 00130 write((i >> 8) & 255); 00131 write(i & 255); 00132 } 00133 00134 /** 00135 * Writes a single <i>java.lang.String</i> to the server. 00136 * 00137 * @param s the string to write 00138 */ 00139 public void writestring(String s) { 00140 for (int i = 0; i < s.length(); i++) { 00141 char c = s.charAt(i); 00142 if (c == 0) 00143 break; 00144 write(c); 00145 } 00146 write(0); 00147 } 00148 00149 /** 00150 * Writes a single <i>boolean</i> to the server. 00151 * 00152 * @param b the boolean to write 00153 */ 00154 public void writebool(boolean b) { 00155 write(b ? 1 : 0); 00156 } 00157 00158 /** 00159 * Writes a single <i>long</i> to the server. 00160 * 00161 * @param i the long to write 00162 */ 00163 public void writelong(long i) { 00164 write((int) (i >> 56) & 255); 00165 write((int) (i >> 48) & 255); 00166 write((int) (i >> 40) & 255); 00167 write((int) (i >> 32) & 255); 00168 write((int) (i >> 24) & 255); 00169 write((int) (i >> 16) & 255); 00170 write((int) (i >> 8) & 255); 00171 write((int) i & 255); 00172 } 00173 00174 /** 00175 * Writes a single <i>char</i> to the server. 00176 * 00177 * @param ch the char to write 00178 */ 00179 public void writechar(char ch) { 00180 write(ch); 00181 } 00182 00183 /** 00184 * Writes a reference to an MPS object to the remote end. Sends a 00185 * canonical name for the object as a string. The remote end will 00186 * then construct a proxy on the other side of the connection to 00187 * make use of the reference that has been sent to it. 00188 * 00189 * @param o the MPS Interface to write 00190 * @exception MPSException if there's a problem writing 00191 * @exception MPSException if <code>o</code> is not being 00192 * served by an instance of Server and <code>o</code> is not an 00193 * instance of <code>Proxy</code> 00194 * 00195 * @see org.hebe.mps.Proxy 00196 * @see org.hebe.mps.InputStream#readReference 00197 */ 00198 public void writeReference(Object o) throws MPSException { 00199 Server svr = Server.serverFor(o); 00200 00201 if (svr == null) { 00202 // No local server for this object. Perhaps we're a Proxy 00203 // for some remote object? 00204 try { 00205 Proxy p = (Proxy) o; 00206 writestring(p.getReference()); 00207 } catch (ClassCastException cce) { 00208 // Nope. 00209 throw new MPSException("Cannot write reference to unserved, non-Proxy object"); 00210 } 00211 } else { 00212 // We have a local server. Send one of its addresses over 00213 // the link. 00214 writestring(svr.getBoundName()); 00215 } 00216 } 00217 00218 /** 00219 * Writes a single <i>float</i> to the server. 00220 * 00221 * @param f the float to write 00222 * @exception MPSException if there's a problem writing 00223 */ 00224 public void writefloat(float f) throws MPSException { 00225 writeint(Float.floatToIntBits(f)); 00226 } 00227 00228 /** 00229 * Sends the total accumulated buffer of bytes over the 00230 * connection. Empties the buffer ready for the next batch of 00231 * bytes. 00232 * 00233 * @exception MPSException if there's a problem writing. 00234 */ 00235 public void flush() throws MPSException { 00236 if (buffer.length() > 0) { 00237 try { 00238 //System.out.println("Flushing OutputStream..."); 00239 open(); 00240 output.write(buffer.toString().getBytes()); 00241 setupBuffer(); 00242 } catch (IOException ioe) { 00243 throw new MPSException("Error flushing OutputStream buffer"); 00244 } 00245 } 00246 } 00247 }