/*******************************************************************************
* Copyright (c) 2009 MATERNA Information & Communications. All rights reserved.
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html. For further
* project-related information visit http://www.ws4d.org. The most recent
* version of the JMEDS framework can be obtained from
* http://sourceforge.net/projects/ws4d-javame.
******************************************************************************/
package org.ws4d.java.attachment;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import org.ws4d.java.configuration.AttachmentProperties;
import org.ws4d.java.service.parameter.ParameterValue;
import org.ws4d.java.types.InternetMediaType;
import org.ws4d.java.util.IDGenerator;
import org.ws4d.java.util.Log;
import org.ws4d.java.util.ObjectPool;
import org.ws4d.java.util.ObjectPool.InstanceCreator;
/**
* This class represents an attachment which can be obtained and read as a
* <code>java.io.InputStream</code> <em>exactly once</em>. That is, the stream
* returned by {@link #getInputStream()} is always the same and will usually not
* support resetting. The use of the method {@link #getBytes()} is not supported
* on this type of attachment and will always throw an
* {@link AttachmentException}. Moreover, the method {@link #size()} will return
* a potentially incorrect estimate (as obtained by
* <code>java.io.InputStream.available()</code>).
* <p>
* In order to support easy and fast type checking, method {@link #getType()}
* will return always {@link #STREAM_ATTACHMENT} for instances of this class.
* </p>
*/
class InputStreamAttachment extends AbstractAttachment implements IncomingAttachment, OutgoingAttachment {
private static final ObjectPool STREAM_BUFFERS = new ObjectPool(new InstanceCreator() {
/*
* (non-Javadoc )
* @see org .ws4d .
* java. util.
* ObjectPool .
* InstanceCreator #
* createInstance ()
*/
public Object createInstance() {
return new byte[AttachmentProperties.getInstance().getStreamBufferSize()];
}
}, 1);
private InputStream in;
/**
* Creates an attachment by reading its raw data from the given stream
* <code>in</code>. A unique {@link #getContentId() content ID} for this
* attachment is automatically generated. Its {@link #getContentType()
* content type} will be unspecified.
*
* @param in an input stream from which to obtain the attachment's raw data
*/
InputStreamAttachment(InputStream in) {
this(in, (InternetMediaType) null);
}
/**
* Creates an attachment by reading its raw data from the given stream
* <code>in</code>. A unique {@link #getContentId() content ID} for this
* attachment is automatically generated.
*
* @param in an input stream to obtain the attachment's raw data from
* @param contentType the MIME content type of the attachment
*/
InputStreamAttachment(InputStream in, InternetMediaType contentType) {
this(in, IDGenerator.getUUID(), contentType);
}
/**
* Creates an attachment by reading its raw data from the given stream
* <code>in</code>. A unique {@link #getContentId() content ID} for this
* attachment is automatically generated.
*
* @param in an input stream from which to obtain the attachment's raw data
* @param contentType the MIME content type of the attachment
*/
InputStreamAttachment(InputStream in, String contentType) {
this(in, IDGenerator.getUUID(), contentType);
}
/**
* Creates an attachment by reading its raw data from the given stream
* <code>in</code> and assigns the specified <code>contentId</code> to it.
*
* @param in an input stream from which to obtain the attachment's raw data
* @param contentId the MIME content ID of the attachment, which should be
* unique within the scope of the MIME package in which the
* attachment is contained; in the case of DPWS this scope
* corresponds to a single invocation message, i.e. the content
* ID must be unique within the {@link ParameterValue} hierarchy
* of an operations input or output parameters
* @param contentType the MIME content type of the attachment
*/
InputStreamAttachment(InputStream in, String contentId, InternetMediaType contentType) {
super(contentId, contentType);
this.in = in;
}
/**
* Creates an attachment by reading its raw data from the given stream
* <code>in</code> and assigns the specified <code>contentId</code> to it.
*
* @param in an input stream from which to obtain the attachment's raw data
* @param contentId the MIME content ID of the attachment, which should be
* unique within which the scope of the MIME package the
* attachment is contained; in the case of DPWS this scope
* corresponds to a single invocation message, i.e. the content
* ID must be unique within the {@link ParameterValue} hierarchy
* of an operations input or output parameters
* @param contentType the MIME content type of the attachment
*/
InputStreamAttachment(InputStream in, String contentId, String contentType) {
this(in, contentId, maskContentType(contentType));
}
/**
* Always returns {@link #STREAM_ATTACHMENT}.
*/
public final int getType() throws AttachmentException {
return STREAM_ATTACHMENT;
}
/*
* (non-Javadoc)
* @see org.ws4d.java.attachment.AbstractAttachment#dispose()
*/
public void dispose() {
if (in == null) {
return;
}
try {
in.close();
} catch (IOException e) {
Log.warn("Unable to close attachment input stream on dispose: " + e);
Log.printStackTrace(e);
}
in = null;
}
/**
* Returns a reference to the same input stream with which this stream
* attachment instance was created. Note that this stream is not required to
* support resetting, so reading it more than once may not be possible.
*/
public InputStream getInputStream() throws AttachmentException, IOException {
if (readInException != null) {
throw readInException;
}
return in;
}
/**
* Always throws an {@link AttachmentException} indicating that this class
* doesn't support byte access.
*/
public byte[] getBytes() throws AttachmentException, IOException {
throw new AttachmentException("byte access not supported for stream attachments");
}
/**
* Returns the amount of bytes that can be obtained from the enclosed input
* stream as provided by method <code>java.io.InputStream.available()</code>
* .
*/
public long size() throws AttachmentException {
if (readInException != null) {
throw readInException;
}
if (in == null) {
return 0;
}
try {
return in.available();
} catch (IOException e) {
throw new AttachmentException("unable to access attachment input stream: " + e);
}
}
/*
* (non-Javadoc)
* @see
* org.ws4d.java.communication.protocol.mime.MIMEEntity#serialize(java.io
* .OutputStream)
*/
public void serialize(OutputStream out) throws IOException {
if (in == null) {
return;
}
DefaultAttachmentStore.readOut(in, out, (byte[]) STREAM_BUFFERS.acquire());
/*
* as this method should only be called on the sender side when
* transmitting the attachment's data to a remote receiver, we assume no
* one is going to use this attachment instance after that anymore;
* thus, ensure input stream is closed
*/
dispose();
}
/*
* (non-Javadoc)
* @see org.ws4d.java.attachment.Attachment#isLocal()
*/
public boolean isLocal() {
return true;
}
/*
* (non-Javadoc)
* @see org.ws4d.java.attachment.Attachment#getFilePath()
*/
public String getFilePath() throws AttachmentException {
throw new AttachmentException("file system operations not supported for stream attachments");
}
/*
* (non-Javadoc)
* @see org.ws4d.java.attachment.Attachment#save(java.lang.String)
*/
public void save(String targetFilePath) throws AttachmentException, IOException {
throw new AttachmentException("file system operations not supported for stream attachments");
}
/*
* (non-Javadoc)
* @see org.ws4d.java.attachment.Attachment#move(java.lang.String)
*/
public boolean move(String newFilePath) throws AttachmentException {
throw new AttachmentException("file system operations not supported for stream attachments");
}
}