001: /*
002: * BufferedContent.java November 2002
003: *
004: * Copyright (C) 2002, 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 java.io.OutputStream;
024: import java.io.InputStream;
025: import java.io.IOException;
026:
027: /**
028: * The <code>BufferedContent</code> represents content that is stored
029: * within an internal buffer. This acquires the meta data of the file
030: * using the issued <code>Context</code> object and buffers the
031: * contents using a byte array. This is provided so that files can
032: * be cached in memory so that repeated requests for a popular file
033: * can be done quicker.
034: * <p>
035: * This implementation of the <code>Content</code> interface is used
036: * when the <code>FileContentFactory.getInstance</code> method is
037: * given a size that is less than the size of the file. For a caching
038: * scheme the file size should not be too large to conserve memory.
039: *
040: * @author Niall Gallagher
041: *
042: * @see simple.http.serve.CacheContentFactory
043: */
044: final class BufferedContent extends IndexedContent {
045:
046: /**
047: * The buffer that contains the contents of the file.
048: */
049: private volatile byte[] cache;
050:
051: /**
052: * Constructor for the <code>BufferedContent</code> acquires the
053: * bytes for the specified file using an <code>InputStream</code>
054: * retrieved from the <code>IndexedContent</code>. This is then
055: * used to acquire the bytes of the file and cache them in main
056: * memory so that invocations of the <code>write</code> method
057: * can be done without refering to the file system.
058: *
059: * @param context the <code>Context</code> used for indexing
060: * @param target the request URI that refers to the file
061: */
062: public BufferedContent(Context context, String target) {
063: super (context, target);
064: }
065:
066: /**
067: * The <code>write</code> method writes the contents of the file
068: * to the issued <code>OutputStream</code>. This is done using the
069: * allocated buffer to which involves a single write operation.
070: *
071: * @param out the <code>OutputStream</code> to write the contents
072: *
073: * @exception IOException this is thrown if the issued stream has
074: * an I/O problem writing the contents
075: */
076: public void write(OutputStream out) throws IOException {
077: if (cache == null) {
078: int size = getLength();
079:
080: if (size > 0) {
081: write(out, size);
082: }
083: } else {
084: out.write(cache);
085: }
086: }
087:
088: /**
089: * This <code>write</code> method writes a specific number of bytes
090: * from the contents of the file. This is simply used as a driver
091: * for acquiring the cache of the file. This will acquire the file
092: * input stream, delegate to the caching write and close the file.
093: *
094: * @param out the <code>OutputStream</code> to write the contents
095: * @param size this is the number of bytes to read from the file
096: *
097: * @exception IOException this is thrown if the issued stream has
098: * an I/O problem writing the contents
099: */
100: private void write(OutputStream out, int size) throws IOException {
101: InputStream in = getInputStream();
102:
103: if (size > 0) {
104: write(out, in, size);
105: }
106: in.close();
107: }
108:
109: /**
110: * The <code>write</code> method acts as a pipe, in that it will
111: * transfer the contents of the provided input stream to the ouput
112: * stream. As this transfers the contents of the resource to the
113: * provided output stream it will buffer the contents of the file
114: * within its internal byte buffer so future requests are quicker.
115: *
116: * @param out the <code>OutputStream</code> to write the contents
117: * @param in this is the <code>InputStream</code> to read from
118: * @param size this is the number of bytes to read from the file
119: *
120: * @exception IOException this is thrown if the issued stream has
121: * an I/O problem writing the contents
122: */
123: private void write(OutputStream out, InputStream in, int size)
124: throws IOException {
125: byte[] buf = new byte[size];
126:
127: for (int off = 0; size > 0;) {
128: int len = in.read(buf, off, size);
129:
130: if (len < 0) {
131: break;
132: }
133: out.write(buf, off, len);
134: size -= len;
135: off += len;
136: }
137: cache = buf;
138: }
139: }
|