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

org.restlet.resource.Representation Maven / Gradle / Ivy

Go to download

This OSGi bundle wraps org.restlet, and com.noelios.restlet ${pkgVersion} jar files.

The newest version!
/**
 * Copyright 2005-2008 Noelios Technologies.
 * 
 * The contents of this file are subject to the terms of the following open
 * source licenses: LGPL 3.0 or LGPL 2.1 or CDDL 1.0 (the "Licenses"). You can
 * select the license that you prefer but you may not use this file except in
 * compliance with one of these Licenses.
 * 
 * You can obtain a copy of the LGPL 3.0 license at
 * http://www.gnu.org/licenses/lgpl-3.0.html
 * 
 * You can obtain a copy of the LGPL 2.1 license at
 * http://www.gnu.org/licenses/lgpl-2.1.html
 * 
 * You can obtain a copy of the CDDL 1.0 license at
 * http://www.sun.com/cddl/cddl.html
 * 
 * See the Licenses for the specific language governing permissions and
 * limitations under the Licenses.
 * 
 * Alternatively, you can obtain a royaltee free commercial license with less
 * limitations, transferable or non-transferable, directly at
 * http://www.noelios.com/products/restlet-engine
 * 
 * Restlet is a registered trademark of Noelios Technologies.
 */

package org.restlet.resource;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.Reader;
import java.io.Writer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.security.DigestInputStream;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.logging.Level;

import org.restlet.Context;
import org.restlet.data.Digest;
import org.restlet.data.MediaType;
import org.restlet.data.Range;
import org.restlet.data.Tag;
import org.restlet.util.ByteUtils;

/**
 * Current or intended state of a resource. The content of a representation can
 * be retrieved several times if there is a stable and accessible source, like a
 * local file or a string. When the representation is obtained via a temporary
 * source like a network socket, its content can only be retrieved once. The
 * "transient" and "available" properties are available to help you figure out
 * those aspects at runtime.
*
* For performance purpose, it is essential that a minimal overhead occurs upon * initialization. The main overhead must only occur during invocation of * content processing methods (write, getStream, getChannel and toString).
*
* "REST components perform actions on a resource by using a representation to * capture the current or intended state of that resource and transferring that * representation between components. A representation is a sequence of bytes, * plus representation metadata to describe those bytes. Other commonly used but * less precise names for a representation include: document, file, and HTTP * message entity, instance, or variant." Roy T. Fielding * * @see Source dissertation * @author Jerome Louvel */ public abstract class Representation extends Variant { /** * Empty representation with no content. */ private static class EmptyRepresentation extends Representation { /** * Constructor. */ public EmptyRepresentation() { setAvailable(false); setTransient(true); setSize(0); } @Override public ReadableByteChannel getChannel() throws IOException { return null; } @Override public Reader getReader() throws IOException { return null; } @Override public InputStream getStream() throws IOException { return null; } @Override public void write(OutputStream outputStream) throws IOException { // Do nothing } @Override public void write(WritableByteChannel writableChannel) throws IOException { // Do nothing } @Override public void write(Writer writer) throws IOException { // Do nothing } } /** * Indicates that the size of the representation can't be known in advance. */ public static final long UNKNOWN_SIZE = -1L; /** * Returns a new empty representation with no content. * * @return A new empty representation. */ public static Representation createEmpty() { return new EmptyRepresentation(); } /** Indicates if the representation's content is available. */ private volatile boolean available; /** * The representation digest if any. */ private volatile Digest digest; /** Indicates if the representation is downloadable. */ private volatile boolean downloadable; /** * Indicates the suggested download file name for the representation's * content. */ private volatile String downloadName; /** Indicates if the representation's content is transient. */ private volatile boolean isTransient; /** * Indicates where in the full content the partial content available should * be applied. */ private volatile Range range; /** * Default constructor. */ public Representation() { this(null); } /** * Constructor. * * @param mediaType * The media type. */ public Representation(MediaType mediaType) { super(mediaType); this.available = true; this.digest = null; this.downloadable = false; this.downloadName = null; this.isTransient = false; this.range = null; } /** * Check that the digest computed from the representation content and the * digest declared by the representation are the same.
* Since this method relies on the {@link #computeDigest(String)} method, * and since this method reads entirely the representation's stream, user * must take care of the content of the representation in case the latter is * transient. * * {@link #isTransient} * * @return True if both digests are not null and equals. */ public boolean checkDigest() { return (getDigest() != null && checkDigest(getDigest().getAlgorithm())); } /** * Check that the digest computed from the representation content and the * digest declared by the representation are the same. It also first checks * that the algorithms are the same.
* Since this method relies on the {@link #computeDigest(String)} method, * and since this method reads entirely the representation's stream, user * must take care of the content of the representation in case the latter is * transient. * * {@link #isTransient} * * @param algorithm * The algorithm used to compute the digest to compare with. See * constant values in {@link Digest}. * @return True if both digests are not null and equals. */ public boolean checkDigest(String algorithm) { Digest digest = getDigest(); if (digest != null) { if (algorithm.equals(digest.getAlgorithm())) { return digest.equals(computeDigest(algorithm)); } } return false; } /** * Compute the representation digest according to the given algorithm.
* Since this method reads entirely the representation's stream, user must * take care of the content of the representation in case the latter is * transient. * * {@link #isTransient} * * @param algorithm * The algorithm used to compute the digest. See constant values * in {@link Digest}. * @return The computed digest or null if the digest cannot be computed. */ public Digest computeDigest(String algorithm) { Digest result = null; if (isAvailable()) { try { MessageDigest md = MessageDigest.getInstance(algorithm); DigestInputStream dis = new DigestInputStream(getStream(), md); ByteUtils.exhaust(dis); result = new Digest(algorithm, md.digest()); } catch (NoSuchAlgorithmException e) { Context.getCurrentLogger().log(Level.WARNING, "Unable to check the digest of the representation.", e); } catch (IOException e) { Context.getCurrentLogger().log(Level.WARNING, "Unable to check the digest of the representation.", e); } } return result; } /** * Exhauts the content of the representation by reading it and silently * discarding anything read. * * @return The number of bytes consumed or -1 if unknown. */ public long exhaust() throws IOException { long result = -1L; if (isAvailable()) { result = ByteUtils.exhaust(getStream()); } return result; } /** * Returns the size effectively available. This returns the same value as * {@link #getSize()} if no range is defined, otherwise it returns the size * of the range using {@link Range#getSize()}. * * @return The available size. */ public long getAvailableSize() { if (getRange() == null) { return getSize(); } else if (getRange().getSize() != Range.SIZE_MAX) { return getRange().getSize(); } else if (getSize() != Representation.UNKNOWN_SIZE) { if (getRange().getIndex() != Range.INDEX_LAST) { return getSize() - getRange().getIndex(); } else { return getSize(); } } return Representation.UNKNOWN_SIZE; } /** * Returns a channel with the representation's content.
* If it is supported by a file, a read-only instance of FileChannel is * returned.
* This method is ensured to return a fresh channel for each invocation * unless it is a transient representation, in which case null is returned. * * @return A channel with the representation's content. * @throws IOException */ public abstract ReadableByteChannel getChannel() throws IOException; /** * Returns the representation digest if any. * * @return The representation digest or null. */ public Digest getDigest() { return this.digest; } /** * Returns the suggested download file name for this representation. This is * mainly used to suggest to the client a local name for a downloaded * representation. * * @return The suggested file name for this representation. */ public String getDownloadName() { return this.downloadName; } /** * Returns the future date when this representation expire. If this * information is not known, returns null. * * @return The expiration date. */ @Override @SuppressWarnings("deprecation") public Date getExpirationDate() { return super.getExpirationDate(); } /** * Returns the last date when this representation was modified. If this * information is not known, returns null. * * @return The modification date. */ @Override @SuppressWarnings("deprecation") public Date getModificationDate() { return super.getModificationDate(); } /** * Returns the range where in the full content the partial content available * should be applied. * * @return The content range or null if the full content is available. */ public Range getRange() { return this.range; } /** * Returns a characters reader with the representation's content. This * method is ensured to return a fresh reader for each invocation unless it * is a transient representation, in which case null is returned. If the * representation has no character set defined, the system's default one * will be used. * * @return A reader with the representation's content. * @throws IOException */ public abstract Reader getReader() throws IOException; /** * Returns the size in bytes if known, UNKNOWN_SIZE (-1) otherwise. * * @return The size in bytes if known, UNKNOWN_SIZE (-1) otherwise. */ @Override @SuppressWarnings("deprecation") public long getSize() { return super.getSize(); } /** * Returns a stream with the representation's content. This method is * ensured to return a fresh stream for each invocation unless it is a * transient representation, in which case null is returned. * * @return A stream with the representation's content. * @throws IOException */ public abstract InputStream getStream() throws IOException; /** * Returns the tag. * * @return The tag. */ @Override @SuppressWarnings("deprecation") public Tag getTag() { return super.getTag(); } /** * Converts the representation to a string value. Be careful when using this * method as the conversion of large content to a string fully stored in * memory can result in OutOfMemoryErrors being thrown. * * @return The representation as a string value. */ public String getText() throws IOException { String result = null; if (isAvailable()) { final ByteArrayOutputStream baos = new ByteArrayOutputStream(); write(baos); if (getCharacterSet() != null) { result = baos.toString(getCharacterSet().getName()); } else { result = baos.toString(); } } return result; } /** * Indicates if some fresh content is available, without having to actually * call one of the content manipulation method like getStream() that would * actually consume it. This is especially useful for transient * representation whose content can only be accessed once and also when the * size of the representation is not known in advance. * * @return True if some fresh content is available. */ public boolean isAvailable() { return (getSize() != 0) && this.available; } /** * Indicates if the representation is downloadable which means that it can * be obtained via a download dialog box. * * @return True if the representation's content is downloadable. */ public boolean isDownloadable() { return this.downloadable; } /** * Indicates if the representation's content is transient, which means that * it can be obtained only once. This is often the case with representations * transmitted via network sockets for example. In such case, if you need to * read the content several times, you need to cache it first, for example * into memory or into a file. * * @return True if the representation's content is transient. */ public boolean isTransient() { return this.isTransient; } /** * Releases the representation's content and all associated objects like * sockets, channels or files. If the representation is transient and hasn't * been read yet, all the remaining content will be discarded, any open * socket, channel, file or similar source of content will be immediately * closed. The representation is also no more available. */ public void release() { this.available = false; } /** * Indicates if some fresh content is available. * * @param available * True if some fresh content is available. */ public void setAvailable(boolean available) { this.available = available; } /** * Sets the representation digest. * * @param digest * The representation digest. */ public void setDigest(Digest digest) { this.digest = digest; } /** * Indicates if the representation is downloadable which means that it can * be obtained via a download dialog box. * * @param downloadable * True if the representation's content is downloadable. */ public void setDownloadable(boolean downloadable) { this.downloadable = downloadable; } /** * Set the suggested download file name for this representation. * * @param fileName * The suggested file name. */ public void setDownloadName(String fileName) { this.downloadName = fileName; } /** * Sets the future date when this representation expire. If this information * is not known, pass null. * * @param expirationDate * The expiration date. */ @Override @SuppressWarnings("deprecation") public void setExpirationDate(Date expirationDate) { super.setExpirationDate(expirationDate); } /** * Sets the last date when this representation was modified. If this * information is not known, pass null. * * @param modificationDate * The modification date. */ @Override @SuppressWarnings("deprecation") public void setModificationDate(Date modificationDate) { super.setModificationDate(modificationDate); } /** * Sets the range where in the full content the partial content available * should be applied. * * @param range * The content range. */ public void setRange(Range range) { this.range = range; } /** * Sets the expected size in bytes if known, -1 otherwise. * * @param expectedSize * The expected size in bytes if known, -1 otherwise. */ @Override @SuppressWarnings("deprecation") public void setSize(long expectedSize) { super.setSize(expectedSize); } /** * Sets the tag. * * @param tag * The tag. */ @Override @SuppressWarnings("deprecation") public void setTag(Tag tag) { super.setTag(tag); } /** * Indicates if the representation's content is transient. * * @param isTransient * True if the representation's content is transient. */ public void setTransient(boolean isTransient) { this.isTransient = isTransient; } /** * Writes the representation to a byte stream. This method is ensured to * write the full content for each invocation unless it is a transient * representation, in which case an exception is thrown. * * @param outputStream * The output stream. * @throws IOException */ public abstract void write(OutputStream outputStream) throws IOException; /** * Writes the representation to a byte channel. This method is ensured to * write the full content for each invocation unless it is a transient * representation, in which case an exception is thrown. * * @param writableChannel * A writable byte channel. * @throws IOException */ public abstract void write(WritableByteChannel writableChannel) throws IOException; /** * Writes the representation to a characters writer. This method is ensured * to write the full content for each invocation unless it is a transient * representation, in which case an exception is thrown. * * @param writer * The characters writer. * @throws IOException */ public abstract void write(Writer writer) throws IOException; }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy