All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.caucho.burlap.io.BurlapOutput Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2001-2004 Caucho Technology, Inc.  All rights reserved.
 *
 * The Apache Software License, Version 1.1
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution, if
 *    any, must include the following acknowlegement:
 *       "This product includes software developed by the
 *        Caucho Technology (http://www.caucho.com/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 *
 * 4. The names "Burlap", "Resin", and "Caucho" must not be used to
 *    endorse or promote products derived from this software without prior
 *    written permission. For written permission, please contact
 *    [email protected].
 *
 * 5. Products derived from this software may not be called "Resin"
 *    nor may "Resin" appear in their names without prior written
 *    permission of Caucho Technology.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 CAUCHO TECHNOLOGY OR ITS 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.
 *
 * @author Scott Ferguson
 */

package com.caucho.burlap.io;

import com.caucho.hessian.io.Serializer;
import com.caucho.hessian.io.SerializerFactory;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Calendar;
import java.util.Date;
import java.util.IdentityHashMap;
import java.util.TimeZone;

/**
 * Output stream for Burlap requests, compatible with microedition
 * Java.  It only uses classes and types available in JDK.
 *
 * 

Since BurlapOutput does not depend on any classes other than * in the JDK, it can be extracted independently into a smaller package. * *

BurlapOutput is unbuffered, so any client needs to provide * its own buffering. * *

 * OutputStream os = ...; // from http connection
 * BurlapOutput out = new BurlapOutput(os);
 * String value;
 *
 * out.startCall("hello");  // start hello call
 * out.writeString("arg1"); // write a string argument
 * out.completeCall();      // complete the call
 * 
*/ public class BurlapOutput extends AbstractBurlapOutput { // the output stream protected OutputStream os; // map of references private IdentityHashMap _refs; private Date date; private Calendar utcCalendar; private Calendar localCalendar; /** * Creates a new Burlap output stream, initialized with an * underlying output stream. * * @param os the underlying output stream. */ public BurlapOutput(OutputStream os) { init(os); } /** * Creates an uninitialized Burlap output stream. */ public BurlapOutput() { } /** * Initializes the output */ public void init(OutputStream os) { this.os = os; _refs = null; if (_serializerFactory == null) _serializerFactory = new SerializerFactory(); } /** * Writes a complete method call. */ public void call(String method, Object []args) throws IOException { startCall(method); if (args != null) { for (int i = 0; i < args.length; i++) writeObject(args[i]); } completeCall(); } /** * Starts the method call. Clients would use startCall * instead of call if they wanted finer control over * writing the arguments, or needed to write headers. * *
   * <burlap:call>
   * <method>method-name</method>
   * 
* * @param method the method name to call. */ public void startCall(String method) throws IOException { print(""); print(method); print(""); } /** * Starts the method call. Clients would use startCall * instead of call if they wanted finer control over * writing the arguments, or needed to write headers. * *
   * <method>method-name</method>
   * 
* * @param method the method name to call. */ public void startCall() throws IOException { print(""); } /** * Writes the method for a call. * *
   * <method>value</method>
   * 
* * @param method the method name to call. */ public void writeMethod(String method) throws IOException { print(""); print(method); print(""); } /** * Completes. * *
   * </burlap:call>
   * 
*/ public void completeCall() throws IOException { print("
"); } /** * Starts the reply * *

A successful completion will have a single value: * *

   * r
   * 
*/ public void startReply() throws IOException { print(""); } /** * Completes reading the reply * *

A successful completion will have a single value: * *

   * </burlap:reply>
   * 
*/ public void completeReply() throws IOException { print("
"); } /** * Writes a header name. The header value must immediately follow. * *
   * <header>foo</header><int>value</int>
   * 
*/ public void writeHeader(String name) throws IOException { print("
"); printString(name); print("
"); } /** * Writes a fault. The fault will be written * as a descriptive string followed by an object: * *
   * <fault>
   * <string>code
   * <string>the fault code
   *
   * <string>message
   * <string>the fault mesage
   *
   * <string>detail
   * <map>t\x00\xnnjavax.ejb.FinderException
   *     ...
   * </map>
   * </fault>
   * 
* * @param code the fault code, a three digit */ public void writeFault(String code, String message, Object detail) throws IOException { print(""); writeString("code"); writeString(code); writeString("message"); writeString(message); if (detail != null) { writeString("detail"); writeObject(detail); } print(""); } /** * Writes any object to the output stream. */ public void writeObject(Object object) throws IOException { if (object == null) { writeNull(); return; } Serializer serializer; serializer = _serializerFactory.getSerializer(object.getClass()); serializer.writeObject(object, this); } /** * Writes the list header to the stream. List writers will call * writeListBegin followed by the list contents and then * call writeListEnd. * *
   * <list>
   *   <type>java.util.ArrayList</type>
   *   <length>3</length>
   *   <int>1</int>
   *   <int>2</int>
   *   <int>3</int>
   * </list>
   * 
*/ public boolean writeListBegin(int length, String type) throws IOException { print(""); if (type != null) print(type); print(""); print(length); print(""); return true; } /** * Writes the tail of the list to the stream. */ public void writeListEnd() throws IOException { print(""); } /** * Writes the map header to the stream. Map writers will call * writeMapBegin followed by the map contents and then * call writeMapEnd. * *
   * <map>
   *   <type>type</type>
   *   (<key> <value>)*
   * </map>
   * 
*/ public void writeMapBegin(String type) throws IOException { print(""); if (type != null) print(type); print(""); } /** * Writes the tail of the map to the stream. */ public void writeMapEnd() throws IOException { print(""); } /** * Writes a remote object reference to the stream. The type is the * type of the remote interface. * *
   * <remote>
   *   <type>test.account.Account</type>
   *   <string>http://caucho.com/foo;ejbid=bar</string>
   * </remote>
   * 
*/ public void writeRemote(String type, String url) throws IOException { print(""); print(type); print(""); print(url); print(""); } /** * Writes a boolean value to the stream. The boolean will be written * with the following syntax: * *
   * <boolean>0</boolean>
   * <boolean>1</boolean>
   * 
* * @param value the boolean value to write. */ public void writeBoolean(boolean value) throws IOException { if (value) print("1"); else print("0"); } /** * Writes an integer value to the stream. The integer will be written * with the following syntax: * *
   * <int>int value</int>
   * 
* * @param value the integer value to write. */ public void writeInt(int value) throws IOException { print(""); print(value); print(""); } /** * Writes a long value to the stream. The long will be written * with the following syntax: * *
   * <long>int value</long>
   * 
* * @param value the long value to write. */ public void writeLong(long value) throws IOException { print(""); print(value); print(""); } /** * Writes a double value to the stream. The double will be written * with the following syntax: * *
   * <double>value</double>
   * 
* * @param value the double value to write. */ public void writeDouble(double value) throws IOException { print(""); print(value); print(""); } /** * Writes a date to the stream. * *
   * <date>iso8901</date>
   * 
* * @param time the date in milliseconds from the epoch in UTC */ public void writeUTCDate(long time) throws IOException { print(""); if (utcCalendar == null) { utcCalendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); date = new Date(); } date.setTime(time); utcCalendar.setTime(date); printDate(utcCalendar); print(""); } /** * Writes a null value to the stream. * The null will be written with the following syntax * *
   * <null></null>
   * 
* * @param value the string value to write. */ public void writeNull() throws IOException { print(""); } /** * Writes a string value to the stream using UTF-8 encoding. * The string will be written with the following syntax: * *
   * <string>string-value</string>
   * 
* * If the value is null, it will be written as * *
   * <null></null>
   * 
* * @param value the string value to write. */ public void writeString(String value) throws IOException { if (value == null) { print(""); } else { print(""); printString(value); print(""); } } /** * Writes a string value to the stream using UTF-8 encoding. * The string will be written with the following syntax: * *
   * S b16 b8 string-value
   * 
* * If the value is null, it will be written as * *
   * N
   * 
* * @param value the string value to write. */ public void writeString(char []buffer, int offset, int length) throws IOException { if (buffer == null) { print(""); } else { print(""); printString(buffer, offset, length); print(""); } } /** * Writes a byte array to the stream. * The array will be written with the following syntax: * *
   * <base64>bytes</base64>
   * 
* * If the value is null, it will be written as * *
   * <null></null>
   * 
* * @param value the string value to write. */ public void writeBytes(byte []buffer) throws IOException { if (buffer == null) print(""); else writeBytes(buffer, 0, buffer.length); } /** * Writes a byte array to the stream. * The array will be written with the following syntax: * *
   * <base64>bytes</base64>
   * 
* * If the value is null, it will be written as * *
   * <null></null>
   * 
* * @param value the string value to write. */ public void writeBytes(byte []buffer, int offset, int length) throws IOException { if (buffer == null) { print(""); } else { print(""); int i = 0; for (; i + 2 < length; i += 3) { if (i != 0 && (i & 0x3f) == 0) print('\n'); int v = (((buffer[offset + i] & 0xff) << 16) + ((buffer[offset + i + 1] & 0xff) << 8) + (buffer[offset + i + 2] & 0xff)); print(encode(v >> 18)); print(encode(v >> 12)); print(encode(v >> 6)); print(encode(v)); } if (i + 1 < length) { int v = (((buffer[offset + i] & 0xff) << 8) + (buffer[offset + i + 1] & 0xff)); print(encode(v >> 10)); print(encode(v >> 4)); print(encode(v << 2)); print('='); } else if (i < length) { int v = buffer[offset + i] & 0xff; print(encode(v >> 2)); print(encode(v << 4)); print('='); print('='); } print(""); } } /** * Writes a byte buffer to the stream. */ public void writeByteBufferStart() throws IOException { throw new UnsupportedOperationException(); } /** * Writes a byte buffer to the stream. * *
   * b b16 b18 bytes
   * 
*/ public void writeByteBufferPart(byte []buffer, int offset, int length) throws IOException { throw new UnsupportedOperationException(); } /** * Writes a byte buffer to the stream. * *
   * b b16 b18 bytes
   * 
*/ public void writeByteBufferEnd(byte []buffer, int offset, int length) throws IOException { throw new UnsupportedOperationException(); } /** * Encodes a digit */ private char encode(int d) { d &= 0x3f; if (d < 26) return (char) (d + 'A'); else if (d < 52) return (char) (d + 'a' - 26); else if (d < 62) return (char) (d + '0' - 52); else if (d == 62) return '+'; else return '/'; } /** * Writes a reference. * *
   * <ref>int</ref>
   * 
* * @param value the integer value to write. */ public void writeRef(int value) throws IOException { print(""); print(value); print(""); } /** * If the object has already been written, just write its ref. * * @return true if we're writing a ref. */ public boolean addRef(Object object) throws IOException { if (_refs == null) _refs = new IdentityHashMap(); Integer ref = (Integer) _refs.get(object); if (ref != null) { int value = ref.intValue(); writeRef(value); return true; } else { _refs.put(object, new Integer(_refs.size())); return false; } } @Override public int getRef(Object obj) { if (_refs == null) return -1; Integer ref = (Integer) _refs.get(obj); if (ref != null) return ref; else return -1; } /** * Removes a reference. */ public boolean removeRef(Object obj) throws IOException { if (_refs != null) { _refs.remove(obj); return true; } else return false; } /** * Replaces a reference from one object to another. */ public boolean replaceRef(Object oldRef, Object newRef) throws IOException { Integer value = (Integer) _refs.remove(oldRef); if (value != null) { _refs.put(newRef, value); return true; } else return false; } /** * Prints a string to the stream, encoded as UTF-8 * * @param v the string to print. */ public void printString(String v) throws IOException { printString(v, 0, v.length()); } /** * Prints a string to the stream, encoded as UTF-8 * * @param v the string to print. */ public void printString(String v, int offset, int length) throws IOException { for (int i = 0; i < length; i++) { char ch = v.charAt(i + offset); if (ch == '<') { os.write('&'); os.write('#'); os.write('6'); os.write('0'); os.write(';'); } else if (ch == '&') { os.write('&'); os.write('#'); os.write('3'); os.write('8'); os.write(';'); } else if (ch < 0x80) os.write(ch); else if (ch < 0x800) { os.write(0xc0 + ((ch >> 6) & 0x1f)); os.write(0x80 + (ch & 0x3f)); } else { os.write(0xe0 + ((ch >> 12) & 0xf)); os.write(0x80 + ((ch >> 6) & 0x3f)); os.write(0x80 + (ch & 0x3f)); } } } /** * Prints a string to the stream, encoded as UTF-8 * * @param v the string to print. */ public void printString(char []v, int offset, int length) throws IOException { for (int i = 0; i < length; i++) { char ch = v[i + offset]; if (ch < 0x80) os.write(ch); else if (ch < 0x800) { os.write(0xc0 + ((ch >> 6) & 0x1f)); os.write(0x80 + (ch & 0x3f)); } else { os.write(0xe0 + ((ch >> 12) & 0xf)); os.write(0x80 + ((ch >> 6) & 0x3f)); os.write(0x80 + (ch & 0x3f)); } } } /** * Prints a date. * * @param date the date to print. */ public void printDate(Calendar calendar) throws IOException { int year = calendar.get(Calendar.YEAR); os.write((char) ('0' + (year / 1000 % 10))); os.write((char) ('0' + (year / 100 % 10))); os.write((char) ('0' + (year / 10 % 10))); os.write((char) ('0' + (year % 10))); int month = calendar.get(Calendar.MONTH) + 1; os.write((char) ('0' + (month / 10 % 10))); os.write((char) ('0' + (month % 10))); int day = calendar.get(Calendar.DAY_OF_MONTH); os.write((char) ('0' + (day / 10 % 10))); os.write((char) ('0' + (day % 10))); os.write('T'); int hour = calendar.get(Calendar.HOUR_OF_DAY); os.write((char) ('0' + (hour / 10 % 10))); os.write((char) ('0' + (hour % 10))); int minute = calendar.get(Calendar.MINUTE); os.write((char) ('0' + (minute / 10 % 10))); os.write((char) ('0' + (minute % 10))); int second = calendar.get(Calendar.SECOND); os.write((char) ('0' + (second / 10 % 10))); os.write((char) ('0' + (second % 10))); int ms = calendar.get(Calendar.MILLISECOND); os.write('.'); os.write((char) ('0' + (ms / 100 % 10))); os.write((char) ('0' + (ms / 10 % 10))); os.write((char) ('0' + (ms % 10))); os.write('Z'); } /** * Prints a char to the stream. * * @param v the char to print. */ protected void print(char v) throws IOException { os.write(v); } /** * Prints an integer to the stream. * * @param v the integer to print. */ protected void print(int v) throws IOException { print(String.valueOf(v)); } /** * Prints a long to the stream. * * @param v the long to print. */ protected void print(long v) throws IOException { print(String.valueOf(v)); } /** * Prints a double to the stream. * * @param v the double to print. */ protected void print(double v) throws IOException { print(String.valueOf(v)); } /** * Prints a string as ascii to the stream. Used for tags, etc. * that are known to the ascii. * * @param s the ascii string to print. */ protected void print(String s) throws IOException { int len = s.length(); for (int i = 0; i < len; i++) { int ch = s.charAt(i); os.write(ch); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy