001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package org.restlet.resource;
020:
021: import java.io.ByteArrayOutputStream;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.OutputStream;
025: import java.nio.channels.ReadableByteChannel;
026: import java.nio.channels.WritableByteChannel;
027:
028: import org.restlet.data.MediaType;
029:
030: /**
031: * Current or intended state of a resource. The content of a representation can
032: * be retrieved several times if there is a stable and accessible source, like a
033: * local file or a string. When the representation is obtained via a temporary
034: * source like a network socket, its content can only be retrieved once. The
035: * "transient" and "available" properties are available to help you figure out
036: * those aspects at runtime.<br/><br/> For performance purpose, it is
037: * essential that a minimal overhead occurs upon initialization. The main
038: * overhead must only occur during invocation of content processing methods
039: * (write, getStream, getChannel and toString).<br/><br/> "REST components
040: * perform actions on a resource by using a representation to capture the
041: * current or intended state of that resource and transferring that
042: * representation between components. A representation is a sequence of bytes,
043: * plus representation metadata to describe those bytes. Other commonly used but
044: * less precise names for a representation include: document, file, and HTTP
045: * message entity, instance, or variant." Roy T. Fielding
046: *
047: * @see <a
048: * href="http://roy.gbiv.com/pubs/dissertation/rest_arch_style.htm#sec_5_2_1_2">Source
049: * dissertation</a>
050: * @author Jerome Louvel (contact@noelios.com)
051: */
052: public abstract class Representation extends Variant {
053: /** Indicates if the representation's content is available. */
054: private boolean contentAvailable;
055:
056: /** Indicates if the representation's content is transient. */
057: private boolean contentTransient;
058:
059: /**
060: * Default constructor.
061: */
062: public Representation() {
063: this (null);
064: }
065:
066: /**
067: * Constructor.
068: *
069: * @param mediaType
070: * The media type.
071: */
072: public Representation(MediaType mediaType) {
073: super (mediaType);
074: this .contentAvailable = true;
075: this .contentTransient = false;
076: }
077:
078: /**
079: * Returns a channel with the representation's content.<br/> If it is
080: * supported by a file, a read-only instance of FileChannel is returned.<br/>
081: * This method is ensured to return a fresh channel for each invocation
082: * unless it is a transient representation, in which case null is returned.
083: *
084: * @return A channel with the representation's content.
085: * @throws IOException
086: */
087: public abstract ReadableByteChannel getChannel() throws IOException;
088:
089: /**
090: * Returns a stream with the representation's content. This method is
091: * ensured to return a fresh stream for each invocation unless it is a
092: * transient representation, in which case null is returned.
093: *
094: * @return A stream with the representation's content.
095: * @throws IOException
096: */
097: public abstract InputStream getStream() throws IOException;
098:
099: /**
100: * Converts the representation to a string value. Be careful when using this
101: * method as the conversion of large content to a string fully stored in
102: * memory can result in OutOfMemoryErrors being thrown.
103: *
104: * @return The representation as a string value.
105: */
106: public String getText() throws IOException {
107: String result = null;
108:
109: if (isAvailable()) {
110: ByteArrayOutputStream baos = new ByteArrayOutputStream();
111: write(baos);
112:
113: if (getCharacterSet() != null) {
114: result = baos.toString(getCharacterSet().getName());
115: } else {
116: result = baos.toString();
117: }
118: }
119:
120: return result;
121: }
122:
123: /**
124: * Indicates if some fresh content is available, without having to actually
125: * call one of the content manipulation method like getStream() that would
126: * actually consume it. This is especially useful for transient
127: * representation whose content can only be accessed once and also when the
128: * size of the representation is not known in advance.
129: *
130: * @return True if some fresh content is available.
131: */
132: public boolean isAvailable() {
133: return this .contentAvailable;
134: }
135:
136: /**
137: * Indicates if the representation's content is transient, which means that
138: * it can be obtained only once. This is often the case with representations
139: * transmitted via network sockets for example. In such case, if you need to
140: * read the content several times, you need to cache it first, for example
141: * into memory or into a file.
142: *
143: * @return True if the representation's content is transient.
144: */
145: public boolean isTransient() {
146: return this .contentTransient;
147: }
148:
149: /**
150: * Indicates if some fresh content is available.
151: *
152: * @param available
153: * True if some fresh content is available.
154: */
155: public void setAvailable(boolean available) {
156: this .contentAvailable = available;
157: }
158:
159: /**
160: * Indicates if the representation's content is transient.
161: *
162: * @param isTransient
163: * True if the representation's content is transient.
164: */
165: public void setTransient(boolean isTransient) {
166: this .contentTransient = isTransient;
167: }
168:
169: /**
170: * Writes the representation to a byte stream. This method is ensured to
171: * write the full content for each invocation unless it is a transient
172: * representation, in which case an exception is thrown.
173: *
174: * @param outputStream
175: * The output stream.
176: * @throws IOException
177: */
178: public abstract void write(OutputStream outputStream)
179: throws IOException;
180:
181: /**
182: * Writes the representation to a byte channel. This method is ensured to
183: * write the full content for each invocation unless it is a transient
184: * representation, in which case an exception is thrown.
185: *
186: * @param writableChannel
187: * A writable byte channel.
188: * @throws IOException
189: */
190: public abstract void write(WritableByteChannel writableChannel)
191: throws IOException;
192:
193: }
|