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;
020:
021: import java.io.IOException;
022: import java.util.ArrayList;
023: import java.util.List;
024: import java.util.logging.Level;
025:
026: import org.restlet.data.LocalReference;
027: import org.restlet.data.MediaType;
028: import org.restlet.data.Reference;
029: import org.restlet.data.ReferenceList;
030: import org.restlet.data.Request;
031: import org.restlet.data.Response;
032: import org.restlet.resource.Representation;
033: import org.restlet.resource.Resource;
034: import org.restlet.resource.Variant;
035: import org.restlet.util.Engine;
036:
037: /**
038: * Finder mapping a directory of local resources. Those resources have
039: * representations accessed by the file system or the class loaders.<br/>
040: *
041: * An automatic content negotiation mechanism (similar to the one in Apache HTTP
042: * server) is used to select the best representation of a resource based on the
043: * available variants and on the client capabilities and preferences.<br/>
044: *
045: * The directory can be used in read-only or modifiable mode. In the latter
046: * case, you just need to set the "modifiable" property to true. The currently
047: * supported methods are PUT and DELETE.
048: *
049: * @see <a href="http://www.restlet.org/documentation/1.0/tutorial#part06">Tutorial: Serving
050: * static files</a>
051: * @author Jerome Louvel (contact@noelios.com)
052: */
053: public class Directory extends Finder {
054: /** Indicates if the best content is automatically negotiated. */
055: private boolean negotiateContent;
056:
057: /** Indicates if the subdirectories are deeply accessible (true by default). */
058: private boolean deeplyAccessible;
059:
060: /** The index name, without extensions (ex: "index" or "home"). */
061: private String indexName;
062:
063: /** The absolute root reference (file, clap URI). */
064: private Reference rootRef;
065:
066: /**
067: * Indicates if modifications to local resources are allowed (false by
068: * default).
069: */
070: private boolean modifiable;
071:
072: /**
073: * Indicates if the display of directory listings is allowed when no index
074: * file is found.
075: */
076: private boolean listingAllowed;
077:
078: /**
079: * Constructor.
080: *
081: * @param context
082: * The context.
083: * @param rootLocalReference
084: * The root URI.
085: */
086: public Directory(Context context, LocalReference rootLocalReference) {
087: super (context);
088:
089: // First, let's normalize the root reference to prevent any issue with
090: // relative paths inside the reference leading to listing issues.
091: String rootIdentifier = rootLocalReference.getTargetRef()
092: .getIdentifier();
093:
094: if (rootIdentifier.endsWith("/")) {
095: this .rootRef = new Reference(rootIdentifier);
096: } else {
097: // We don't take the risk of exposing directory "file:///C:/AA"
098: // if only "file:///C:/A" was intended
099: this .rootRef = new Reference(rootIdentifier + "/");
100: }
101:
102: this .deeplyAccessible = true;
103: this .indexName = "index";
104: this .listingAllowed = false;
105: this .modifiable = false;
106: }
107:
108: /**
109: * Constructor.
110: *
111: * @param context
112: * The context.
113: * @param rootUri
114: * The absolute root URI. <br>
115: * <br>
116: * If you serve files from the file system, use file:// URIs and
117: * make sure that you register a FILE connector with your parent
118: * Component. On Windows, make sure that you add enough slash
119: * characters at the beginning, for example: file:///c:/dir/file<br>
120: * <br>
121: * If you serve files from a class loader, use clap:// URIs and
122: * make sure that you register a CLAP connector with your parent
123: * Component.<br>
124: * <br>
125: */
126: public Directory(Context context, String rootUri) {
127: this (context, new LocalReference(rootUri));
128: }
129:
130: /**
131: * Finds the target Resource if available.
132: *
133: * @param request
134: * The request to filter.
135: * @param response
136: * The response to filter.
137: * @return The target resource if available or null.
138: */
139: public Resource findTarget(Request request, Response response) {
140: try {
141: return Engine.getInstance().createDirectoryResource(this ,
142: request, response);
143: } catch (IOException ioe) {
144: getLogger().log(Level.WARNING,
145: "Unable to find the directory's resource", ioe);
146: return null;
147: }
148: }
149:
150: /**
151: * Returns the index name, without extensions. Returns "index" by default.
152: *
153: * @return The index name.
154: */
155: public String getIndexName() {
156: return this .indexName;
157: }
158:
159: /**
160: * Returns an actual index representation for a given variant.
161: *
162: * @param variant
163: * The selected variant.
164: * @param indexContent
165: * The directory index to represent.
166: * @return The actual index representation.
167: */
168: public Representation getIndexRepresentation(Variant variant,
169: ReferenceList indexContent) {
170: Representation result = null;
171: if (variant.getMediaType().equals(MediaType.TEXT_HTML)) {
172: result = indexContent.getWebRepresentation();
173: } else if (variant.getMediaType().equals(
174: MediaType.TEXT_URI_LIST)) {
175: result = indexContent.getTextRepresentation();
176: }
177: return result;
178: }
179:
180: /**
181: * Returns the variant representations of a directory index. This method can
182: * be subclassed in order to provide alternative representations. By default
183: * it returns a simple HTML document and a textual URI list as variants.
184: *
185: * @param indexContent
186: * The list of references contained in the directory index.
187: * @return The variant representations of a directory.
188: */
189: public List<Variant> getIndexVariants(ReferenceList indexContent) {
190: List<Variant> result = new ArrayList<Variant>();
191: result.add(new Variant(MediaType.TEXT_HTML));
192: result.add(new Variant(MediaType.TEXT_URI_LIST));
193: return result;
194: }
195:
196: /**
197: * Returns the root URI.
198: *
199: * @return The root URI.
200: */
201: public Reference getRootRef() {
202: return this .rootRef;
203: }
204:
205: /**
206: * Indicates if the subdirectories are deeply accessible (true by default).
207: *
208: * @return True if the subdirectories are deeply accessible.
209: */
210: public boolean isDeeplyAccessible() {
211: return deeplyAccessible;
212: }
213:
214: /**
215: * Indicates if the display of directory listings is allowed when no index
216: * file is found.
217: *
218: * @return True if the display of directory listings is allowed when no
219: * index file is found.
220: */
221: public boolean isListingAllowed() {
222: return this .listingAllowed;
223: }
224:
225: /**
226: * Indicates if modifications to local resources (most likely files) are
227: * allowed. Returns false by default.
228: *
229: * @return True if modifications to local resources are allowed.
230: */
231: public boolean isModifiable() {
232: return this .modifiable;
233: }
234:
235: /**
236: * Indicates if the best content is automatically negotiated. Default value
237: * is true.
238: *
239: * @return True if the best content is automatically negotiated.
240: */
241: public boolean isNegotiateContent() {
242: return this .negotiateContent;
243: }
244:
245: /**
246: * Indicates if the subdirectories are deeply accessible (true by default).
247: *
248: * @param deeplyAccessible
249: * True if the subdirectories are deeply accessible.
250: */
251: public void setDeeplyAccessible(boolean deeplyAccessible) {
252: this .deeplyAccessible = deeplyAccessible;
253: }
254:
255: /**
256: * Sets the index name, without extensions.
257: *
258: * @param indexName
259: * The index name.
260: */
261: public void setIndexName(String indexName) {
262: this .indexName = indexName;
263: }
264:
265: /**
266: * Indicates if the display of directory listings is allowed when no index
267: * file is found.
268: *
269: * @param listingAllowed
270: * True if the display of directory listings is allowed when no
271: * index file is found.
272: */
273: public void setListingAllowed(boolean listingAllowed) {
274: this .listingAllowed = listingAllowed;
275: }
276:
277: /**
278: * Indicates if modifications to local resources are allowed.
279: *
280: * @param modifiable
281: * True if modifications to local resources are allowed.
282: */
283: public void setModifiable(boolean modifiable) {
284: this .modifiable = modifiable;
285: }
286:
287: /**
288: * Indicates if the best content is automatically negotiated. Default value
289: * is true.
290: *
291: * @param negotiateContent
292: * True if the best content is automatically negotiated.
293: */
294: public void setNegotiateContent(boolean negotiateContent) {
295: this.negotiateContent = negotiateContent;
296: }
297:
298: }
|