001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.cocoon.components.source.impl;
018:
019: import org.apache.avalon.excalibur.pool.Recyclable;
020: import org.apache.excalibur.source.Source;
021: import org.apache.excalibur.source.SourceException;
022: import org.apache.excalibur.source.SourceValidity;
023:
024: import java.io.IOException;
025: import java.io.InputStream;
026: import java.util.Iterator;
027:
028: /**
029: * A wrapper around a <code>Source</code> that reduces the number of calls to
030: * <code>Source.getLastModified()</code> which can be a costly operation.
031: *
032: * @author <a href="mailto:sylvain@apache.org">Sylvain Wallez</a>
033: * @version CVS $Id: DelayedRefreshSourceWrapper.java 433543 2006-08-22 06:22:54Z crossley $
034: */
035: public final class DelayedRefreshSourceWrapper implements Source {
036:
037: private Source source;
038:
039: private long delay;
040:
041: private long nextCheckTime = 0;
042:
043: private long lastModified = 0;
044:
045: /**
046: * Creates a wrapper for a <code>Source</code> which ensures that
047: * <code>Source.getLastModified()</code> won't be called more than once per
048: * <code>delay</code> milliseconds period.
049: *
050: * @param source the wrapped <code>Source</code>
051: * @param delay the last-modified refresh delay, in milliseconds
052: */
053: public DelayedRefreshSourceWrapper(Source source, long delay) {
054: this .source = source;
055: this .delay = delay;
056: }
057:
058: /**
059: * Get the real source
060: */
061: public Source getSource() {
062: return this .source;
063: }
064:
065: public final InputStream getInputStream() throws SourceException,
066: IOException {
067: return this .source.getInputStream();
068: }
069:
070: public final String getURI() {
071: return this .source.getURI();
072: }
073:
074: /**
075: * Get the Validity object. This can either wrap the last modification
076: * date or the expires information or...
077: * If it is currently not possible to calculate such an information
078: * <code>null</code> is returned.
079: */
080: public SourceValidity getValidity() {
081: return this .source.getValidity();
082: }
083:
084: /**
085: * Return the protocol identifier.
086: */
087: public String getScheme() {
088: return this .source.getScheme();
089: }
090:
091: /**
092: *
093: * @see org.apache.excalibur.source.Source#exists()
094: */
095: public boolean exists() {
096: return this .source.exists();
097: }
098:
099: /**
100: * Get the last modification time for the wrapped <code>Source</code>. The
101: * age of the returned information is guaranteed to be lower than or equal to
102: * the delay specified in the constructor.
103: * <p>
104: * This method is also thread-safe, even if the underlying Source is not.
105: *
106: * @return the last modification time.
107: */
108: public final long getLastModified() {
109:
110: // Do we have to refresh the source ?
111: if (System.currentTimeMillis() >= nextCheckTime) {
112: // Yes
113: this .refresh();
114: }
115: return this .lastModified;
116: }
117:
118: /**
119: * Force the refresh of the wrapped <code>Source</code>, even if the refresh period
120: * isn't over, and starts a new period.
121: * <p>
122: * This method is thread-safe, even if the underlying Source is not.
123: */
124: public synchronized final void refresh() {
125:
126: this .nextCheckTime = System.currentTimeMillis() + this .delay;
127: // Refresh modifiable sources
128: this .source.refresh();
129:
130: // Keep the last modified date
131: this .lastModified = source.getLastModified();
132: }
133:
134: public final long getContentLength() {
135: return this .source.getContentLength();
136: }
137:
138: /**
139: * The mime-type of the content described by this object.
140: * If the source is not able to determine the mime-type by itself
141: * this can be <code>null</code>.
142: */
143: public String getMimeType() {
144: return this .source.getMimeType();
145: }
146:
147: public final void recycle() {
148: if (this .source instanceof Recyclable) {
149: ((Recyclable) this .source).recycle();
150: }
151: }
152:
153: /**
154: * Get the value of a parameter.
155: * Using this it is possible to get custom information provided by the
156: * source implementation, like an expires date, HTTP headers etc.
157: */
158: public String getParameter(String name) {
159: return null;
160: }
161:
162: /**
163: * Get the value of a parameter.
164: * Using this it is possible to get custom information provided by the
165: * source implementation, like an expires date, HTTP headers etc.
166: */
167: public long getParameterAsLong(String name) {
168: return 0;
169: }
170:
171: /**
172: * Get parameter names
173: * Using this it is possible to get custom information provided by the
174: * source implementation, like an expires date, HTTP headers etc.
175: */
176: public Iterator getParameterNames() {
177: return java.util.Collections.EMPTY_LIST.iterator();
178:
179: }
180:
181: }
|