/*
Copyright (c) 2003-2009 ITerative Consulting Pty Ltd. All Rights Reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
o 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.
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS 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 THE COPYRIGHT OWNER OR 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.
*/
package HTTPSupport;
import java.io.Serializable;
import Framework.Array_Of_Object;
import Framework.BinaryData;
import Framework.MemoryStream;
import Framework.Stream;
import Framework.TextData;
/**
* The Entity class provides the default entity class to hold HTTP message data. It implements the {@link GenericEntity} interface, and inherits from the {@link HeaderHolder} class. You can extend and customize the Entity class to provide an entity for a particular MIME type.
* <p>
* <p>
*
*/
@SuppressWarnings("serial")
public class Entity extends HeaderHolder implements Serializable, GenericEntity {
// ----------
// Attributes
// ----------
private MemoryStream data;
private Array_Of_Object<Object> folder;
// ------------
// Constructors
// ------------
public Entity() {
// Explicitly call the superclass constructor to prevent the implicit
// call
super();
this.setHeader(
Constants.HTTP_HEADER_CONTENT_TYPE,
Constants.HTTP_DEFAULT_ENTITY_TYPE);
//
this.data = new MemoryStream();
this.data.open(Framework.Constants.SP_AM_READ_WRITE, true);
// Holding nested entity setup
this.folder = new Array_Of_Object<Object>();
}
// ----------------------
// Accessors and Mutators
// ----------------------
public void setdata(MemoryStream pValue) {
this.data = pValue;
}
public MemoryStream getdata() {
return this.data;
}
public void setfolder(Array_Of_Object<Object> pValue) {
this.folder = pValue;
}
public Array_Of_Object<Object> getfolder() {
return this.folder;
}
// -------
// Methods
// -------
/**
* addEntity
* <p>
* <p>
*
* @param mimeType
* Type: String (default in Forte: NIL)
* @return GenericEntity
*/
public GenericEntity addEntity(String mimeType) {
GenericEntity newEntity = null;
HTTPHelper helper = new HTTPHelper();
newEntity = helper.findFactory().getEntityInstance(mimeType);
this.folder.add(newEntity);
return newEntity;
}
/**
* convertMemoryStream
* <p>
* <p>
*
* @param header
* Type: HeaderHolder
* @param inStream
* Type: MemoryStream
* @param fromWire
* Type: boolean
* @return MemoryStream
*/
public MemoryStream convertMemoryStream(HeaderHolder header,
MemoryStream inStream, boolean fromWire) {
//
// We might need to convert the to-send/received data into
// the local charset. The rules are: if a charset is
// specified in the Content-Type, do not convert.
// The user will access the data as it, knowing the
// charset used thru the getHeaderAttribute(..., charset) call.
// If there is no charset specified and if the content type is
// a subtype of text/, { the default codeset should be ISO-8859-1
// (as specified in the HTTP spec). In this case, we do assume
// that what we received thru the wire is ISO-8859-1 and
// that what we will need to send is also ISO-8859-1.
//
// Therefore, if the local charset is not
// ISO-8859-1, we need either to add the charset='ISO-8859-1'
// to the Content-Type header, or convert the data to the local
// charset. In order to make things easier for the user, this
// latter solution is implemented.
// For example, if a NT HTTP is sent from NT to MVS, the default
// behavior (no charset specified by the sender) will be to
// transparently convert the text body of the NT sender into
// an Ebcdic text body for the MVS receiver.
//
//
// Do the conversion only of the codeset is EBCDIC. This is a change
// from
// the previous implementation where we converted if the codeset was
// not ascii nor iso. This previous case handled all the conversion
// cases,
// relying on the conversion stream to convert those various
// combinations.
// However, we found that on NT the conversion between the WinIso and
// Iso was not working properly. UNtil this is fixed, the following is
// much
// more safe.
//
// TextData txt;
// if (task.LocaleDesc.CodesetId == Constants.CHARSET_EBCDIC)
// {
//
// if (Logger.getLogger(this.getClass()).isDebugEnabled())
// {
// Logger.getLogger(this.getClass()).debug(NX("Entity.convertMemoryStream
// - LocalCodeSet is " +
// task.LocaleDesc.CodesetId);
// }
//
// txt = header.getHeader(Constants.HTTP_HEADER_CONTENT_TYPE);
//
// // Subtype of text and no charset specified => convert as appropriate
// if ((txt.MoveToString("text/") &&
// (header.getHeaderAttribute(Constants.HTTP_HEADER_CONTENT_TYPE,
// Constants.HTTP_CHARSET_ATTRIBUTE) == null)))
// {
// if (Logger.getLogger(this.getClass()).isDebugEnabled())
// {
// if (fromWire)
// {
// Logger.getLogger(this.getClass()).debug("Entity.convertMemoryStream -
// converting text type to EBCDIC");
// }else{
// Logger.getLogger(this.getClass()).debug("Entity.convertMemoryStream -
// converting text type to iso-8859-1");
// }
// }
//
// MemoryStream outStream = new MemoryStream();
// ConversionStream outConv = new ConversionStream();
// ConversionStream inConv = new ConversionStream();
// TextData str = new TextData();
//
// inStream.close();
//
// inConv.SetBufferedStream(inStream);
// outConv.SetBufferedStream(outStream);
//
// if (fromWire)
// {
// inConv.setLocale("en_US.iso");
// outConv.setLocale("");
// }else{
// inConv.setLocale("");
// outConv.setLocale("en_US.iso");
// }
//
// inConv.open(Framework.Constants.SP_AM_READ);
// outConv.open(Framework.Constants.SP_AM_WRITE);
//
// while (inConv.readText(str) >= 0) {
// outConv.writeText(str);
// }
//
// inConv.close();
// outConv.close();
// //outStream.Open(SP_AM_READ_WRITE, isBinary=TRUE); // Opening for
// read/write nukes the contents
// outStream.open(Framework.Constants.SP_AM_UPDATE,
// true);
// return outStream;
// }
// }
return inStream;
}
/**
* getContentData
* <p>
* Function called by httpdc to get the data to send it <br>
* <p>
*
* @return BinaryData
*/
public BinaryData getContentData() {
BinaryData binData = new BinaryData();
if (this.data != null) {
//
// If there is any conversion needed to send the data,
// keep the user data unchanged.
//
MemoryStream dataWire = null;
dataWire = this.convertMemoryStream(this, this.data, false);
int streamOffset = dataWire.getOffset();
dataWire.open(true);
dataWire.seek(0);
dataWire.readBinary(binData);
dataWire.seek(streamOffset);
dataWire.close();
}
return binData;
}
/**
* getContentStream
* <p>
* User method providing a way to get access to the memory stream <br>
* <p>
*
* @return MemoryStream
*/
public MemoryStream getContentStream() {
return this.data;
}
/**
* getContentType
* <p>
* <p>
*
* @return String
*/
public String getContentType() {
return this.getHeader(Constants.HTTP_HEADER_CONTENT_TYPE);
}
/**
* getEntity
* <p>
* <p>
*
* @param pos
* Type: int
* @return GenericEntity
*/
public GenericEntity getEntity(int pos) {
if (this.folder.size() >= pos) {
return (GenericEntity) this.folder.findObjectForRow(pos - 1);
}
return null;
}
/**
* items
* <p>
* The default type should be defined as a stream of bytes. For <br>
* receiving entity, the type will be set by the DC (HTTPDCMessage) <br>
* as the value received within the headers or as a part of <br>
* a multi-part message. <br>
* <p>
*
* @return int
*/
public int items() {
return this.folder.size();
}
/**
* print
* <p>
* <p>
*
* @param stream
* Type: Stream
* @param level
* Type: int (default in Forte: 0)
*/
public void print(Stream stream, int level) {
}
/**
* readBinary
* <p>
* <p>
*
* @param target
* Type: BinaryData
* @param length
* Type: int (default in Forte: 0)
* @return int
*/
public int readBinary(BinaryData target, int length) {
return this.data.readBinary(target, length);
}
/**
* readLine
* <p>
* <p>
*
* @param target
* Type: TextData
* @param includeEOL
* Type: boolean (default in Forte: TRUE)
* @return int
*/
public int readLine(TextData target, boolean includeEOL) {
return this.data.readLine(target, includeEOL);
}
public int readLine(TextData target) { //PM:23/05/2008: added to support the defaule
return this.readLine(target, true);
}
/**
* readSerialized
* <p>
* <p>
*
* @return Object
*/
public Object readSerialized() {
return this.data.readSerialized();
}
/**
* readText
* <p>
* <p>
*
* @param target
* Type: TextData
* @param length
* Type: int (default in Forte: 0)
* @return int
*/
public int readText(TextData target, int length) {
return this.data.readText(target, length);
}
/**
* rewind
* <p>
* <p>
*/
public void rewind() {
this.data.seek(0);
}
/**
* setContentData
* <p>
* Function called by httpdc to set the data received <br>
* <p>
*
* @param data
* Type: BinaryData
* @param length
* Type: int
*/
public void setContentData(BinaryData data, int length) {
this.data.writeBinary(data, length);
this.data = this.convertMemoryStream(this, this.data, true);
this.data.seek(0);
}
/**
* setContentStream
* <p>
* User method providing a way to use another memory stream <br>
* <p>
*
* @param stream
* Type: MemoryStream
*/
public void setContentStream(MemoryStream stream) {
if (stream != null) {
this.data = stream;
}
}
/**
* setContentType
* <p>
* <p>
*
* @param type
* Type: String
*/
public void setContentType(String type) {
this
.setHeader(
HTTPSupport.Constants.HTTP_HEADER_CONTENT_TYPE,
type);
}
/**
* size
* <p>
* <p>
*
* @return int
*/
public int size() {
if (this.data != null) {
return this.data.size();
} else {
return 0;
}
}
/**
* The WriteBinary method writes arbitrary binary data into the entity
* stream, by transferring the contents of an existing BinaryData object.
* The SeekStream must be opened for write or read-write access before
* invoking the WriteBinary method.
*
* You can only call the WriteBinary method on streams that have been opened
* with the isBinary parameter of the Open method set to TRUE.
*
* @param source
* The source parameter must specify an existing BinaryData
* object, whose contents will be transferred into the SeekStream
* object, starting at the current offset. Bytes will be
* transferred from the BinaryData object starting at the
* beginning of the BinaryData object value.
* @param length
* The length parameter specifies the number of bytes to
* transfer. WriteBinary transfers bytes from the source
* BinaryData object up to the number of bytes specified, or to
* the ActualSize of the BinaryData object, whichever is smaller.
* If length is 0, then WriteBinary transfers the entire contents
* of the BinaryData object to the SeekStream.
*
* @return The WriteBinary method returns the number of bytes actually
* transferred into the SeekStream, either before reaching the end
* of the BinaryData object, or by reaching the limit specified by
* the length parameter.
*/
public int writeBinary(BinaryData source, int length) {
// AD:22/07/2008 - Make sure the file is opened in a binary state
this.data.open(Framework.Constants.SP_AM_APPEND, true);
int ret = this.data.writeBinary(source, length);
this.data.close();
return ret;
}
/**
* The WriteBinary method writes arbitrary binary data into the entity
* stream, by transferring the contents of an existing BinaryData object.
* The SeekStream must be opened for write or read-write access before
* invoking the WriteBinary method.
*
* The length is not specified so writeBinary transfers the entire
* contents of the BinaryData object to the SeekStream.
*
* You can only call the WriteBinary method on streams that have been opened
* with the isBinary parameter of the Open method set to TRUE.
*
* @param source
* The source parameter must specify an existing BinaryData
* object, whose contents will be transferred into the SeekStream
* object, starting at the current offset. Bytes will be
* transferred from the BinaryData object starting at the
* beginning of the BinaryData object value.
* @return The WriteBinary method returns the number of bytes actually
* transferred into the SeekStream, either before reaching the end
* of the BinaryData object, or by reaching the limit specified by
* the length parameter.
*/
public int writeBinary(BinaryData source) {
// AD:22/07/2008 - Make sure the file is opened in a binary state
this.data.open(Framework.Constants.SP_AM_APPEND, true);
int ret = this.data.writeBinary(source);
this.data.close();
return ret;
}
/**
* writeLine
* <p>
* <p>
*
* @param source
* Type: TextData
* @param length
* Type: int (default in Forte: 0)
* @return int
*/
public int writeLine(TextData source, int length) {
this.data.open(Framework.Constants.SP_AM_APPEND);
return this.data.writeLine(source, length);
}
/**
* writeLine
* <p>
* <p>
*
* @param source
* Type: String
* @param length
* Type: int (default in Forte: 0)
* @return int
*/
public int writeLine(String source, int length) {
this.data.open(Framework.Constants.SP_AM_APPEND);
return this.data.writeLine(source, length);
}
/**
* writeSerialized
* <p>
* <p>
*
* @param object
* Type: Object
*/
public void writeSerialized(Object object) {
this.data.open(Framework.Constants.SP_AM_APPEND);
this.data.writeSerialized(object);
this.data.close();
}
/**
* writeText
* <p>
* <p>
*
* @param source
* Type: TextData
* @param length
* Type: int (default in Forte: 0)
* @return int
*/
public int writeText(TextData source, int length) {
this.data.open(Framework.Constants.SP_AM_APPEND);
int ret = this.data.writeText(source);
this.data.close();
return ret;
}
/**
* writeText
* <p>
* <p>
*
* @param source
* Type: String
* @param length
* Type: int (default in Forte: 0)
* @return int
*/
public int writeText(String source, int length) {
this.data.open(Framework.Constants.SP_AM_APPEND);
int ret = this.data.writeText(source);
this.data.close();
return ret;
}
public int readText(TextData target) {
this.data.open(Framework.Constants.SP_AM_READ);
return this.data.readText(target);
}
public int writeLine(TextData source) {
this.data.open(Framework.Constants.SP_AM_APPEND);
return this.data.writeLine(source, 0);
}
public int writeLine(String source) {
this.data.open(Framework.Constants.SP_AM_APPEND);
return this.data.writeLine(source, 0);
}
public int writeText(TextData source) {
this.data.open(Framework.Constants.SP_AM_APPEND);
int ret = this.data.writeText(source);
this.data.close();
return ret;
}
public int writeText(String source) {
this.data.open(Framework.Constants.SP_AM_APPEND);
int ret = this.data.writeText(source);
this.data.close();
return ret;
}
}