Source Code Cross Referenced for ResourceReader.java in  » Content-Management-System » apache-lenya-2.0 » org » apache » cocoon » reading » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Content Management System » apache lenya 2.0 » org.apache.cocoon.reading 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.reading;
018:
019:        import org.apache.avalon.framework.configuration.Configurable;
020:        import org.apache.avalon.framework.configuration.Configuration;
021:        import org.apache.avalon.framework.configuration.ConfigurationException;
022:        import org.apache.avalon.framework.parameters.ParameterException;
023:        import org.apache.avalon.framework.parameters.Parameters;
024:
025:        import org.apache.cocoon.ProcessingException;
026:        import org.apache.cocoon.caching.CacheableProcessingComponent;
027:        import org.apache.cocoon.components.source.SourceUtil;
028:        import org.apache.cocoon.environment.Context;
029:        import org.apache.cocoon.environment.ObjectModelHelper;
030:        import org.apache.cocoon.environment.Request;
031:        import org.apache.cocoon.environment.Response;
032:        import org.apache.cocoon.environment.SourceResolver;
033:        import org.apache.cocoon.environment.http.HttpResponse;
034:        import org.apache.cocoon.util.ByteRange;
035:
036:        import org.apache.excalibur.source.Source;
037:        import org.apache.excalibur.source.SourceException;
038:        import org.apache.excalibur.source.SourceValidity;
039:        import org.xml.sax.SAXException;
040:
041:        import java.io.IOException;
042:        import java.io.InputStream;
043:        import java.io.Serializable;
044:        import java.util.Collections;
045:        import java.util.HashMap;
046:        import java.util.Map;
047:
048:        /**
049:         * The <code>ResourceReader</code> component is used to serve binary data
050:         * in a sitemap pipeline. It makes use of HTTP Headers to determine if
051:         * the requested resource should be written to the <code>OutputStream</code>
052:         * or if it can signal that it hasn't changed.
053:         *
054:         * <p>Configuration:
055:         * <dl>
056:         *   <dt>&lt;expires&gt;</dt>
057:         *   <dd>This parameter is optional. When specified it determines how long
058:         *       in miliseconds the resources can be cached by any proxy or browser
059:         *       between Cocoon and the requesting visitor. Defaults to -1.
060:         *   </dd>
061:         *   <dt>&lt;quick-modified-test&gt;</dt>
062:         *   <dd>This parameter is optional. This boolean parameter controls the
063:         *       last modified test. If set to true (default is false), only the
064:         *       last modified of the current source is tested, but not if the
065:         *       same source is used as last time
066:         *       (see http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=102921894301915 )
067:         *   </dd>
068:         *   <dt>&lt;byte-ranges&gt;</dt>
069:         *   <dd>This parameter is optional. This boolean parameter controls whether
070:         *       Cocoon should support byterange requests (to allow clients to resume
071:         *       broken/interrupted downloads).
072:         *       Defaults to true.
073:         * </dl>
074:         *
075:         * <p>Default configuration:
076:         * <pre>
077:         *   &lt;expires&gt;-1&lt;/expires&gt;
078:         *   &lt;quick-modified-test&gt;false&lt;/quick-modified-test&gt;
079:         *   &lt;byte-ranges&gt;true&lt;/byte-ranges&gt;
080:         * </pre>
081:         *
082:         * <p>In addition to reader configuration, above parameters can be passed
083:         * to the reader at the time when it is used.
084:         *
085:         * @author <a href="mailto:Giacomo.Pati@pwr.ch">Giacomo Pati</a>
086:         * @author <a href="mailto:tcurdt@apache.org">Torsten Curdt</a>
087:         * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
088:         * @version CVS $Id: ResourceReader.java 492792 2007-01-04 22:45:55Z joerg $
089:         */
090:        public class ResourceReader extends AbstractReader implements 
091:                CacheableProcessingComponent, Configurable {
092:
093:            /**
094:             * The list of generated documents
095:             */
096:            private static final Map documents = Collections
097:                    .synchronizedMap(new HashMap());
098:
099:            protected long configuredExpires;
100:            protected boolean configuredQuickTest;
101:            protected int configuredBufferSize;
102:            protected boolean configuredByteRanges;
103:
104:            protected long expires;
105:            protected boolean quickTest;
106:            protected int bufferSize;
107:            protected boolean byteRanges;
108:
109:            protected Response response;
110:            protected Request request;
111:            protected Source inputSource;
112:
113:            /**
114:             * Read reader configuration
115:             */
116:            public void configure(Configuration configuration)
117:                    throws ConfigurationException {
118:                // VG Parameters are deprecated as of 2.2.0-Dev/2.1.6-Dev
119:                final Parameters parameters = Parameters
120:                        .fromConfiguration(configuration);
121:                this .configuredExpires = parameters.getParameterAsLong(
122:                        "expires", -1);
123:                this .configuredQuickTest = parameters.getParameterAsBoolean(
124:                        "quick-modified-test", false);
125:                this .configuredBufferSize = parameters.getParameterAsInteger(
126:                        "buffer-size", 8192);
127:                this .configuredByteRanges = parameters.getParameterAsBoolean(
128:                        "byte-ranges", true);
129:
130:                // Configuration has precedence over parameters.
131:                this .configuredExpires = configuration.getChild("expires")
132:                        .getValueAsLong(configuredExpires);
133:                this .configuredQuickTest = configuration.getChild(
134:                        "quick-modified-test").getValueAsBoolean(
135:                        configuredQuickTest);
136:                this .configuredBufferSize = configuration.getChild(
137:                        "buffer-size").getValueAsInteger(configuredBufferSize);
138:                this .configuredByteRanges = configuration.getChild(
139:                        "byte-ranges").getValueAsBoolean(configuredByteRanges);
140:            }
141:
142:            /* (non-Javadoc)
143:             * @see org.apache.avalon.framework.parameters.Parameterizable#parameterize(Parameters)
144:             */
145:            public void parameterize(Parameters parameters)
146:                    throws ParameterException {
147:            }
148:
149:            /**
150:             * Setup the reader.
151:             * The resource is opened to get an <code>InputStream</code>,
152:             * the length and the last modification date
153:             */
154:            public void setup(SourceResolver resolver, Map objectModel,
155:                    String src, Parameters par) throws ProcessingException,
156:                    SAXException, IOException {
157:                super .setup(resolver, objectModel, src, par);
158:
159:                this .request = ObjectModelHelper.getRequest(objectModel);
160:                this .response = ObjectModelHelper.getResponse(objectModel);
161:
162:                this .expires = par.getParameterAsLong("expires",
163:                        this .configuredExpires);
164:                this .quickTest = par.getParameterAsBoolean(
165:                        "quick-modified-test", this .configuredQuickTest);
166:                this .bufferSize = par.getParameterAsInteger("buffer-size",
167:                        this .configuredBufferSize);
168:                this .byteRanges = par.getParameterAsBoolean("byte-ranges",
169:                        this .configuredByteRanges);
170:
171:                try {
172:                    this .inputSource = resolver.resolveURI(src);
173:                } catch (SourceException e) {
174:                    throw SourceUtil.handle("Error during resolving of '" + src
175:                            + "'.", e);
176:                }
177:                setupHeaders();
178:            }
179:
180:            /**
181:             * Setup the response headers: Accept-Ranges, Expires, Last-Modified
182:             */
183:            protected void setupHeaders() {
184:                // Tell the client whether we support byte range requests or not
185:                if (byteRanges) {
186:                    response.setHeader("Accept-Ranges", "bytes");
187:                } else {
188:                    response.setHeader("Accept-Ranges", "none");
189:                }
190:
191:                if (expires > 0) {
192:                    response.setDateHeader("Expires", System
193:                            .currentTimeMillis()
194:                            + expires);
195:                } else if (expires == 0) {
196:                    response.setDateHeader("Expires", 0);
197:                }
198:
199:                long lastModified = getLastModified();
200:                if (lastModified > 0) {
201:                    response.setDateHeader("Last-Modified", lastModified);
202:                }
203:            }
204:
205:            /**
206:             * Recyclable
207:             */
208:            public void recycle() {
209:                this .request = null;
210:                this .response = null;
211:                if (this .inputSource != null) {
212:                    super .resolver.release(this .inputSource);
213:                    this .inputSource = null;
214:                }
215:                super .recycle();
216:            }
217:
218:            /**
219:             * @return True if byte ranges support is enabled and request has range header.
220:             */
221:            protected boolean hasRanges() {
222:                return this .byteRanges
223:                        && this .request.getHeader("Range") != null;
224:            }
225:
226:            /**
227:             * Generate the unique key.
228:             * This key must be unique inside the space of this component.
229:             *
230:             * @return The generated key hashes the src
231:             */
232:            public Serializable getKey() {
233:                return inputSource.getURI();
234:            }
235:
236:            /**
237:             * Generate the validity object.
238:             *
239:             * @return The generated validity object or <code>null</code> if the
240:             *         component is currently not cacheable.
241:             */
242:            public SourceValidity getValidity() {
243:                if (hasRanges()) {
244:                    // This is a byte range request so we can't use the cache, return null.
245:                    return null;
246:                } else {
247:                    return inputSource.getValidity();
248:                }
249:            }
250:
251:            /**
252:             * @return the time the read source was last modified or 0 if it is not
253:             *         possible to detect
254:             */
255:            public long getLastModified() {
256:                if (hasRanges()) {
257:                    // This is a byte range request so we can't use the cache, return null.
258:                    return 0;
259:                }
260:
261:                if (quickTest) {
262:                    return inputSource.getLastModified();
263:                }
264:
265:                final String systemId = (String) documents.get(request
266:                        .getRequestURI());
267:                if (systemId == null || inputSource.getURI().equals(systemId)) {
268:                    return inputSource.getLastModified();
269:                }
270:
271:                documents.remove(request.getRequestURI());
272:                return 0;
273:            }
274:
275:            protected void processStream(InputStream inputStream)
276:                    throws IOException, ProcessingException {
277:                byte[] buffer = new byte[bufferSize];
278:                int length = -1;
279:
280:                String ranges = request.getHeader("Range");
281:
282:                ByteRange byteRange;
283:                if (byteRanges && ranges != null) {
284:                    try {
285:                        ranges = ranges.substring(ranges.indexOf('=') + 1);
286:                        byteRange = new ByteRange(ranges);
287:                    } catch (NumberFormatException e) {
288:                        byteRange = null;
289:
290:                        // TC: Hm.. why don't we have setStatus in the Response interface ?
291:                        if (response instanceof  HttpResponse) {
292:                            // Respond with status 416 (Request range not satisfiable)
293:                            ((HttpResponse) response).setStatus(416);
294:                            if (getLogger().isDebugEnabled()) {
295:                                getLogger().debug(
296:                                        "malformed byte range header ["
297:                                                + String.valueOf(ranges) + "]");
298:                            }
299:                        }
300:                    }
301:                } else {
302:                    byteRange = null;
303:                }
304:
305:                long contentLength = inputSource.getContentLength();
306:
307:                if (byteRange != null) {
308:                    String entityLength;
309:                    String entityRange;
310:                    if (contentLength != -1) {
311:                        entityLength = "" + contentLength;
312:                        entityRange = byteRange.intersection(
313:                                new ByteRange(0, contentLength)).toString();
314:                    } else {
315:                        entityLength = "*";
316:                        entityRange = byteRange.toString();
317:                    }
318:
319:                    response.setHeader("Content-Range", entityRange + "/"
320:                            + entityLength);
321:                    if (response instanceof  HttpResponse) {
322:                        // Response with status 206 (Partial content)
323:                        ((HttpResponse) response).setStatus(206);
324:                    }
325:
326:                    int pos = 0;
327:                    int posEnd;
328:                    while ((length = inputStream.read(buffer)) > -1) {
329:                        posEnd = pos + length - 1;
330:                        ByteRange intersection = byteRange
331:                                .intersection(new ByteRange(pos, posEnd));
332:                        if (intersection != null) {
333:                            out.write(buffer, (int) intersection.getStart()
334:                                    - pos, (int) intersection.length());
335:                        }
336:                        pos += length;
337:                    }
338:                } else {
339:                    if (contentLength != -1) {
340:                        response.setHeader("Content-Length", Long
341:                                .toString(contentLength));
342:                    }
343:
344:                    while ((length = inputStream.read(buffer)) > -1) {
345:                        out.write(buffer, 0, length);
346:                    }
347:                }
348:
349:                out.flush();
350:            }
351:
352:            /**
353:             * Generates the requested resource.
354:             */
355:            public void generate() throws IOException, ProcessingException {
356:                try {
357:                    InputStream inputStream;
358:                    try {
359:                        inputStream = inputSource.getInputStream();
360:                    } catch (SourceException e) {
361:                        throw SourceUtil
362:                                .handle(
363:                                        "Error during resolving of the input stream",
364:                                        e);
365:                    }
366:
367:                    // Bugzilla Bug #25069: Close inputStream in finally block.
368:                    try {
369:                        processStream(inputStream);
370:                    } finally {
371:                        if (inputStream != null) {
372:                            inputStream.close();
373:                        }
374:                    }
375:
376:                    if (!quickTest) {
377:                        // if everything is ok, add this to the list of generated documents
378:                        // (see http://marc.theaimsgroup.com/?l=xml-cocoon-dev&m=102921894301915 )
379:                        documents.put(request.getRequestURI(), inputSource
380:                                .getURI());
381:                    }
382:                } catch (IOException e) {
383:                    getLogger()
384:                            .debug(
385:                                    "Received an IOException, assuming client severed connection on purpose");
386:                }
387:            }
388:
389:            /**
390:             * Returns the mime-type of the resource in process.
391:             */
392:            public String getMimeType() {
393:                Context ctx = ObjectModelHelper.getContext(objectModel);
394:                if (ctx != null) {
395:                    final String mimeType = ctx.getMimeType(source);
396:                    if (mimeType != null) {
397:                        return mimeType;
398:                    }
399:                }
400:                return inputSource.getMimeType();
401:            }
402:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.