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;
018:
019: import org.apache.avalon.framework.component.ComponentManager;
020:
021: import org.apache.cocoon.ProcessingException;
022: import org.apache.cocoon.ResourceNotFoundException;
023:
024: import org.apache.excalibur.source.SourceParameters;
025: import org.apache.excalibur.source.SourceUtil;
026:
027: import java.io.File;
028: import java.io.FileInputStream;
029: import java.io.FileNotFoundException;
030: import java.io.IOException;
031: import java.io.InputStream;
032: import java.lang.reflect.Method;
033: import java.net.HttpURLConnection;
034: import java.net.JarURLConnection;
035: import java.net.URL;
036: import java.net.URLConnection;
037: import java.util.Iterator;
038: import java.util.jar.JarEntry;
039:
040: /**
041: * Description of a source which is described by an URL.
042: *
043: * @deprecated by the Avalon Exalibur Source Resolving
044: * @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
045: * @version CVS $Id: URLSource.java 433543 2006-08-22 06:22:54Z crossley $
046: */
047: public class URLSource extends AbstractStreamSource {
048:
049: /** Identifier for file urls */
050: private final String FILE = "file:";
051:
052: /** The last modification date or 0 */
053: private long lastModificationDate;
054:
055: /** The content length */
056: private long contentLength;
057:
058: /** Is the content html or xml? */
059: private boolean isHTMLContent = false;
060:
061: /** The system id */
062: private String systemId;
063:
064: /** The URL of the source */
065: private URL url;
066:
067: /** The connection for a real URL */
068: private URLConnection connection;
069:
070: /** Is this a file or a "real" URL */
071: private boolean isFile;
072:
073: /** Are we initialized? */
074: private boolean gotInfos;
075:
076: /** The <code>SourceParameters</code> for post */
077: private SourceParameters postParameters;
078:
079: /**
080: * Construct a new object
081: */
082: public URLSource(URL url, ComponentManager manager)
083: throws IOException {
084: super (manager);
085: this .systemId = url.toExternalForm();
086: this .isFile = systemId.startsWith(FILE);
087: if (this .isFile == true) {
088: if (systemId.endsWith(".htm") || systemId.endsWith(".html")) {
089: this .isHTMLContent = true;
090: }
091: }
092: this .url = url;
093: this .gotInfos = false;
094: }
095:
096: protected boolean isHTMLContent() {
097: return this .isHTMLContent;
098: }
099:
100: /**
101: * Get the last modification date and content length of the source.
102: * Any exceptions are ignored.
103: */
104: private void getInfos() {
105: if (!this .gotInfos) {
106: if (this .isFile) {
107: File file = new File(systemId.substring(FILE.length()));
108: this .lastModificationDate = file.lastModified();
109: this .contentLength = file.length();
110: } else {
111: if (this .postParameters == null) {
112: try {
113: if (this .connection == null) {
114: this .connection = this .url.openConnection();
115: String userInfo = this .getUserInfo();
116: if (this .url.getProtocol().startsWith(
117: "http")
118: && userInfo != null) {
119: this .connection
120: .setRequestProperty(
121: "Authorization",
122: "Basic "
123: + SourceUtil
124: .encodeBASE64(userInfo));
125: }
126: }
127: if (this .connection instanceof JarURLConnection) {
128: JarEntry entry = ((JarURLConnection) this .connection)
129: .getJarEntry();
130: this .lastModificationDate = entry.getTime();
131: } else {
132: this .lastModificationDate = this .connection
133: .getLastModified();
134: }
135: this .contentLength = this .connection
136: .getContentLength();
137: } catch (IOException ignore) {
138: this .lastModificationDate = 0;
139: this .contentLength = -1;
140: }
141: } else {
142: // do not open connection when using post!
143: this .lastModificationDate = 0;
144: this .contentLength = -1;
145: }
146: }
147: this .gotInfos = true;
148: }
149: }
150:
151: /**
152: * Get the last modification date of the source or 0 if it
153: * is not possible to determine the date.
154: */
155: public long getLastModified() {
156: this .getInfos();
157: return this .lastModificationDate;
158: }
159:
160: /**
161: * Get the content length of the source or -1 if it
162: * is not possible to determine the length.
163: */
164: public long getContentLength() {
165: this .getInfos();
166: return this .contentLength;
167: }
168:
169: /**
170: * Return an <code>InputStream</code> object to read from the source.
171: *
172: * @throws ResourceNotFoundException if file not found or
173: * HTTP location does not exist.
174: * @throws IOException if I/O error occured.
175: */
176: public InputStream getInputStream() throws IOException,
177: ProcessingException {
178: this .getInfos();
179: try {
180: InputStream input = null;
181: if (this .isFile) {
182: input = new FileInputStream(this .systemId
183: .substring(FILE.length()));
184: } else {
185: if (this .connection == null) {
186: this .connection = this .url.openConnection();
187: /* The following requires a jdk 1.3 */
188: String userInfo = this .getUserInfo();
189: if (this .url.getProtocol().startsWith("http")
190: && userInfo != null) {
191: this .connection
192: .setRequestProperty(
193: "Authorization",
194: "Basic "
195: + SourceUtil
196: .encodeBASE64(userInfo));
197: }
198: // do a post operation
199: if (this .connection instanceof HttpURLConnection
200: && this .postParameters != null) {
201: StringBuffer buffer = new StringBuffer(2000);
202: String key;
203: Iterator i = postParameters.getParameterNames();
204: Iterator values;
205: String value;
206: boolean first = true;
207: while (i.hasNext()) {
208: key = (String) i.next();
209: values = this .postParameters
210: .getParameterValues(key);
211: while (values.hasNext() == true) {
212: value = SourceUtil
213: .encode((String) values.next());
214: if (first == false)
215: buffer.append('&');
216: first = false;
217: buffer.append(key.toString());
218: buffer.append('=');
219: buffer.append(value);
220: }
221: }
222: HttpURLConnection httpCon = (HttpURLConnection) connection;
223: httpCon.setDoInput(true);
224:
225: if (buffer.length() > 1) { // only post if we have parameters
226: String postString = buffer.toString();
227: httpCon.setRequestMethod("POST"); // this is POST
228: httpCon.setDoOutput(true);
229: httpCon
230: .setRequestProperty("Content-type",
231: "application/x-www-form-urlencoded");
232:
233: // A content-length header must be contained in a POST request
234: httpCon.setRequestProperty(
235: "Content-length", Integer
236: .toString(postString
237: .length()));
238: java.io.OutputStream out = new java.io.BufferedOutputStream(
239: httpCon.getOutputStream());
240: out.write(postString.getBytes());
241: out.close();
242: }
243: if ("text/html"
244: .equals(httpCon.getContentType()) == true) {
245: this .isHTMLContent = true;
246: }
247: input = httpCon.getInputStream();
248: this .connection = null; // make sure a new connection is created next time
249: return input;
250: }
251: }
252: if ("text/html"
253: .equals(this .connection.getContentType()) == true) {
254: this .isHTMLContent = true;
255: }
256: input = this .connection.getInputStream();
257: this .connection = null; // make sure a new connection is created next time
258: }
259: return input;
260: } catch (FileNotFoundException e) {
261: throw new ResourceNotFoundException("Resource not found "
262: + this .systemId, e);
263: }
264: }
265:
266: private static boolean checkedURLClass = false;
267: private static boolean urlSupportsGetUserInfo = false;
268: private static Method urlGetUserInfo = null;
269: private static Object[] emptyParams = new Object[0];
270:
271: /**
272: * Check if the <code>URL</code> class supports the getUserInfo()
273: * method which is introduced in jdk 1.3
274: */
275: private String getUserInfo() {
276: if (URLSource.checkedURLClass) {
277: if (URLSource.urlSupportsGetUserInfo) {
278: try {
279: return (String) URLSource.urlGetUserInfo.invoke(
280: this .url, URLSource.emptyParams);
281: } catch (Exception e) {
282: // ignore this anyway
283: }
284: }
285: return null;
286: } else {
287: // test if the url class supports the getUserInfo method
288: try {
289: URLSource.urlGetUserInfo = URL.class.getMethod(
290: "getUserInfo", null);
291: String ui = (String) URLSource.urlGetUserInfo.invoke(
292: this .url, URLSource.emptyParams);
293: URLSource.checkedURLClass = true;
294: URLSource.urlSupportsGetUserInfo = true;
295: return ui;
296: } catch (Exception e) {
297: }
298: URLSource.checkedURLClass = true;
299: URLSource.urlSupportsGetUserInfo = false;
300: URLSource.urlGetUserInfo = null;
301: return null;
302: }
303: }
304:
305: /**
306: * Return the unique identifer for this source
307: */
308: public String getSystemId() {
309: return this .systemId;
310: }
311:
312: /**
313: * Refresh this object and update the last modified date
314: * and content length.
315: */
316: public void refresh() {
317: // reset connection
318: this .connection = null;
319: this .gotInfos = false;
320: }
321:
322: public void recycle() {
323: refresh();
324: }
325:
326: /**
327: * Set the post parameters
328: */
329: public void setPostParameters(SourceParameters pars) {
330: this.postParameters = pars;
331: }
332:
333: }
|