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.data;
020:
021: import java.io.IOException;
022: import java.util.Map;
023: import java.util.TreeMap;
024:
025: import org.restlet.Application;
026: import org.restlet.resource.DomRepresentation;
027: import org.restlet.resource.Representation;
028: import org.restlet.resource.SaxRepresentation;
029: import org.restlet.resource.StringRepresentation;
030: import org.restlet.service.ConverterService;
031:
032: /**
033: * Generic message exchanged between client and server connectors.
034: *
035: * @author Jerome Louvel (contact@noelios.com)
036: */
037: public abstract class Message {
038: /** The modifiable attributes map. */
039: private Map<String, Object> attributes;
040:
041: /** The payload of the message. */
042: private Representation entity;
043:
044: /**
045: * Constructor.
046: */
047: public Message() {
048: this ((Representation) null);
049: }
050:
051: /**
052: * Constructor.
053: *
054: * @param entity
055: * The payload of the message.
056: */
057: public Message(Representation entity) {
058: this .attributes = null;
059: this .entity = entity;
060: }
061:
062: /**
063: * Returns a modifiable attributes map that can be used by developers to
064: * save information relative to the message. This is an easier alternative
065: * to the creation of a wrapper instance around the whole message.<br/>
066: * <br/>
067: *
068: * In addition, this map is a shared space between the developer and the
069: * connectors. In this case, it is used to exchange information that is not
070: * uniform across all protocols and couldn't therefore be directly included
071: * in the API. For this purpose, all attribute names starting with
072: * "org.restlet" are reserved. Currently the following attributes are used:
073: * <table>
074: * <tr>
075: * <th>Attribute name</th>
076: * <th>Class name</th>
077: * <th>Description</th>
078: * </tr>
079: * <tr>
080: * <td>org.restlet.http.headers</td>
081: * <td>org.restlet.data.Form</td>
082: * <td>Server HTTP connectors must provide all request headers and client
083: * HTTP connectors must provide all response headers, exactly as they were
084: * received. In addition, developers can also use this attribute to specify
085: * <b>non-standard</b> headers that should be added to the request or to
086: * the response. </td>
087: * </tr>
088: * </table> Adding standard HTTP headers is forbidden because it could
089: * conflict with the connector's internal behavior, limit portability or
090: * prevent future optimizations.</td>
091: *
092: * @return The modifiable attributes map.
093: */
094: public Map<String, Object> getAttributes() {
095: if (this .attributes == null) {
096: this .attributes = new TreeMap<String, Object>();
097: }
098:
099: return this .attributes;
100: }
101:
102: /**
103: * Returns the converter service.
104: *
105: * @return The converter service.
106: */
107: private ConverterService getConverterService() {
108: ConverterService result = null;
109: Application application = (Application) getAttributes().get(
110: Application.KEY);
111:
112: if (application != null) {
113: result = application.getConverterService();
114: } else {
115: result = new ConverterService();
116: }
117:
118: return result;
119: }
120:
121: /**
122: * Returns the entity representation.
123: *
124: * @return The entity representation.
125: */
126: public Representation getEntity() {
127: return this .entity;
128: }
129:
130: /**
131: * Returns the entity as a DOM representation.<br/> Note that this triggers
132: * the parsing of the entity into a reusable DOM document stored in memory.<br/>
133: * This method and the related getEntity*() methods can only be invoked
134: * once.
135: *
136: * @return The entity as a DOM representation.
137: */
138: public DomRepresentation getEntityAsDom() {
139: return new DomRepresentation(getEntity());
140: }
141:
142: /**
143: * Returns the entity as a form.<br/> Note that this triggers the parsing
144: * of the entity.<br/> This method and the related getEntity*() methods can
145: * only be invoked once.
146: *
147: * @return The entity as a form.
148: */
149: public Form getEntityAsForm() {
150: return new Form(getEntity());
151: }
152:
153: /**
154: * Returns the entity as a higher-level object. This object is created by
155: * the Application's converter service. If you want to use this method to
156: * facilitate the processing of request entities, you need to provide a
157: * custom implementation of the ConverterService class, overriding the
158: * toObject(Representation) method. <br/> Note that this triggers the
159: * parsing of the entity.<br/> This method and the related getEntity*()
160: * methods can only be invoked once.
161: *
162: * @return The entity as a higher-level object.
163: * @see org.restlet.service.ConverterService
164: */
165: public Object getEntityAsObject() {
166: return getConverterService().toObject(getEntity());
167: }
168:
169: /**
170: * Returns the entity as a SAX representation.<br/> Note that this kind of
171: * representation can only be parsed once. If you evaluate an XPath
172: * expression, it can also only be done once. If you need to reuse the
173: * entity multiple times, consider using the getEntityAsDom() method
174: * instead.
175: *
176: * @return The entity as a SAX representation.
177: */
178: public SaxRepresentation getEntityAsSax() {
179: try {
180: return new SaxRepresentation(getEntity());
181: } catch (IOException e) {
182: return null;
183: }
184: }
185:
186: /**
187: * Indicates if a content is available and can be sent. Several conditions
188: * must be met: the content must exists and have some available data.
189: *
190: * @return True if a content is available and can be sent.
191: */
192: public boolean isEntityAvailable() {
193: return (getEntity() != null) && (getEntity().getSize() != 0)
194: && getEntity().isAvailable();
195: }
196:
197: /**
198: * Sets the entity from a higher-level object. This object is converted to a
199: * representation using the Application's converter service. If you want to
200: * use this method to facilitate the setting of entities, you need to
201: * provide a custom implementation of the ConverterService class, overriding
202: * the toRepresentation(Object) method.
203: *
204: * @param object
205: * The higher-level object.
206: * @see org.restlet.service.ConverterService
207: */
208: public void setEntity(Object object) {
209: if (object instanceof Representation) {
210: setEntity((Representation) object);
211: } else {
212: setEntity(getConverterService().toRepresentation(object));
213: }
214: }
215:
216: /**
217: * Sets the entity representation.
218: *
219: * @param entity
220: * The entity representation.
221: */
222: public void setEntity(Representation entity) {
223: this .entity = entity;
224: }
225:
226: /**
227: * Sets a textual entity.
228: *
229: * @param value
230: * The represented string.
231: * @param mediaType
232: * The representation's media type.
233: */
234: public void setEntity(String value, MediaType mediaType) {
235: setEntity(new StringRepresentation(value, mediaType));
236: }
237:
238: }
|