001: /*
002: * CacheContentFactory.java November 2005
003: *
004: * Copyright (C) 2005, Niall Gallagher <niallg@users.sf.net>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013: * GNU Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General
016: * Public License along with this library; if not, write to the
017: * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
018: * Boston, MA 02111-1307 USA
019: */
020:
021: package simple.http.serve;
022:
023: import simple.util.cache.TimeCache;
024: import java.io.IOException;
025: import java.io.File;
026:
027: /**
028: * The <code>CacheContentFactory</code> is used to create a factory
029: * that can be used to create and cache files as instances of the
030: * <code>Content</code> interface. This is useful when a hot spot
031: * cache is required for frequently referenced files. The defaults
032: * for the file cache use a maximum file size of eight kilobytes.
033: * <p>
034: * This factory object can limit the items stored within the cache
035: * by file size. This ensures that the resources consumed by the
036: * file cache can be restricted. Also the concurrency parameters
037: * for the cache can be specified as regions and region limits.
038: *
039: * @author Niall Gallagher
040: *
041: * @see simple.http.serve.CacheContext
042: * @see simple.util.cache.TimeCache
043: */
044: public class CacheContentFactory implements ContentFactory {
045:
046: /**
047: * This is the default length of time to cache a file.
048: */
049: private static final int DEFAULT_TIMEOUT = 60000;
050:
051: /**
052: * This is the default maximum size for a cached file.
053: */
054: private static final int DEFAULT_SIZE = 8192;
055:
056: /**
057: * This is the default number of regions for the cache.
058: */
059: private static final int DEFAULT_LOCKS = 10;
060:
061: /**
062: * This is the default number of elements per lock.
063: */
064: private static final int DEFAULT_LIMIT = 6;
065:
066: /**
067: * This is used to cache the content objects created.
068: */
069: protected TimeCache cache;
070:
071: /**
072: * This is the maximum allowed size for a cached file.
073: */
074: protected int size;
075:
076: /**
077: * Constructor for the <code>CacheContentFactory</code> object.
078: * This object provides caching for any context implementation
079: * that makes heavy use of <code>Content</code> objects. Caching
080: * done by this object ensures that the content objects are kept
081: * in memory for at least one minute, to change this behaviour
082: * this object can be subclassed and use different settings.
083: */
084: protected CacheContentFactory() {
085: this (DEFAULT_SIZE);
086: }
087:
088: /**
089: * Constructor for the <code>CacheContentFactory</code> object.
090: * This object provides caching for any context implementation
091: * that makes heavy use of <code>Content</code> objects. Caching
092: * done by this object ensures that the content objects are kept
093: * in memory for at least one minute, to change this behaviour
094: * this object can be subclassed and use different settings.
095: *
096: * @param size this is the maximum allow file size to cache
097: */
098: public CacheContentFactory(int size) {
099: this (size, DEFAULT_LOCKS, DEFAULT_LIMIT);
100: }
101:
102: /**
103: * Constructor for the <code>CacheContentFactory</code> object.
104: * This object provides caching for any context implementation
105: * that makes heavy use of <code>Content</code> objects. Caching
106: * done by this object ensures that the content objects are kept
107: * in memory for at least one minute, to change this behaviour
108: * this object can be subclassed and use different settings.
109: *
110: * @param size this is the maximum allow file size to cache
111: * @param regions this is the number of locks the cache uses
112: * @param limit this is the maximum capacity of each LRU list
113: */
114: public CacheContentFactory(int size, int regions, int limit) {
115: this .cache = new TimeCache(regions, limit);
116: this .size = size;
117: }
118:
119: /**
120: * This implementation of the <code>getInstance</code> method will
121: * cache the created <code>Content</code> object. This is done
122: * to increase the performance of the <code>Context</code> for
123: * objects that are requested frequently. The size of the file
124: * that is cached is dependant on the construction parameters.
125: * <p>
126: * If the file referenced is greater than the specified maximum
127: * then a one kilobyte buffer is cached for that file as is used
128: * to transfer the contents of the file to the output stream.
129: *
130: * @param target the request URI for the content required
131: * @param context this is the context used to locate the file
132: *
133: * @return this returns a <code>Content</code> instance
134: *
135: * @throws ContentException this is thrown if there is an error
136: * locating the specified file, or creating the object
137: */
138: public Content getInstance(Context context, String target)
139: throws ContentException {
140: try {
141: if (target.indexOf('?') < 0) {
142: return getContent(context, target, DEFAULT_TIMEOUT);
143: }
144: return getContent(context, target);
145: } catch (IOException e) {
146: throw new ContentException(target);
147: }
148: }
149:
150: /**
151: * This method allows a size to be specified for the maximum
152: * buffer size. If the file resource is less than the buffer size
153: * then the entire contents of the file are buffered within the
154: * issued implementation. This will allocate up to 1 kilobyte for
155: * files that are larger than the specified buffer size.
156: * <p>
157: * This implementation of the <code>getContent</code> method will
158: * cache the created <code>Content</code> object. This is done
159: * to increase the performance of the <code>Context</code> for
160: * objects that are requested frequently. The buffer size that
161: * can be specified provides a guide for how much memory should
162: * be taken up with the content cached object.
163: *
164: * @param context this is the object used to locate the file
165: * @param target this is the request URI that identifies the file
166: * @param timeout the number of milliseconds to cache the file
167: *
168: * @throws IOException this is thrown if the file resource does
169: * not exist or cannot be accessed
170: */
171: protected Content getContent(Context context, String target,
172: int timeout) throws IOException {
173: Object data = cache.lookup(target);
174:
175: if (data != null) {
176: return (Content) data;
177: }
178: data = getContent(context, target);
179: cache.cache(target, data, timeout);
180:
181: return (Content) data;
182: }
183:
184: /**
185: * This is used to create the <code>Content</code> instances. The
186: * <code>getInstance</code> method can be used by subclasses that
187: * want to introduce dynamic <code>Content</code> objects. This
188: * enables the <code>getContent</code> method to cache the
189: * resulting instances without having to know what types they are.
190: * <p>
191: * By default the <code>CacheContentFactory</code> produces objects
192: * that will write static content as it appears on the underlying
193: * file system. This uses the specified size to ensure that the
194: * buffers used by the content are not larger than the maximum.
195: *
196: * @param context this is the object used to locate the file
197: * @param target this is the request URI that identifies the file
198: *
199: * @throws IOException this is thrown if the file resource does
200: * not exist or cannot be accessed
201: */
202: protected Content getContent(Context context, String target)
203: throws IOException {
204: if (context.getFile(target).length() <= size) {
205: return new BufferedContent(context, target);
206: }
207: return new StreamContent(context, target);
208: }
209: }
|