blob: 6965d6907f2f0751af3f140de3f7b6dbc26affca [file] [log] [blame]
/*
* Copyright 1999-2004 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.components.source;
import org.apache.avalon.framework.component.ComponentManager;
import org.apache.cocoon.ProcessingException;
import org.apache.cocoon.ResourceNotFoundException;
import org.apache.excalibur.source.SourceParameters;
import org.apache.excalibur.source.SourceUtil;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.net.HttpURLConnection;
import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.Iterator;
import java.util.jar.JarEntry;
/**
* Description of a source which is described by an URL.
*
* @deprecated by the Avalon Exalibur Source Resolving
* @author <a href="mailto:cziegeler@apache.org">Carsten Ziegeler</a>
* @version CVS $Id: URLSource.java,v 1.3 2004/03/05 13:02:40 bdelacretaz Exp $
*/
public class URLSource extends AbstractStreamSource {
/** Identifier for file urls */
private final String FILE = "file:";
/** The last modification date or 0 */
private long lastModificationDate;
/** The content length */
private long contentLength;
/** Is the content html or xml? */
private boolean isHTMLContent = false;
/** The system id */
private String systemId;
/** The URL of the source */
private URL url;
/** The connection for a real URL */
private URLConnection connection;
/** Is this a file or a "real" URL */
private boolean isFile;
/** Are we initialized? */
private boolean gotInfos;
/** The <code>SourceParameters</code> for post */
private SourceParameters postParameters;
/**
* Construct a new object
*/
public URLSource(URL url, ComponentManager manager)
throws IOException {
super(manager);
this.systemId = url.toExternalForm();
this.isFile = systemId.startsWith(FILE);
if (this.isFile == true) {
if (systemId.endsWith(".htm") || systemId.endsWith(".html")) {
this.isHTMLContent = true;
}
}
this.url = url;
this.gotInfos = false;
}
protected boolean isHTMLContent() {
return this.isHTMLContent;
}
/**
* Get the last modification date and content length of the source.
* Any exceptions are ignored.
*/
private void getInfos() {
if (!this.gotInfos) {
if (this.isFile) {
File file = new File(systemId.substring(FILE.length()));
this.lastModificationDate = file.lastModified();
this.contentLength = file.length();
} else {
if (this.postParameters == null) {
try {
if (this.connection == null) {
this.connection = this.url.openConnection();
String userInfo = this.getUserInfo();
if (this.url.getProtocol().startsWith("http") && userInfo != null) {
this.connection.setRequestProperty("Authorization","Basic "+SourceUtil.encodeBASE64(userInfo));
}
}
if(this.connection instanceof JarURLConnection) {
JarEntry entry = ((JarURLConnection)this.connection).getJarEntry();
this.lastModificationDate = entry.getTime();
} else {
this.lastModificationDate = this.connection.getLastModified();
}
this.contentLength = this.connection.getContentLength();
} catch (IOException ignore) {
this.lastModificationDate = 0;
this.contentLength = -1;
}
} else {
// do not open connection when using post!
this.lastModificationDate = 0;
this.contentLength = -1;
}
}
this.gotInfos = true;
}
}
/**
* Get the last modification date of the source or 0 if it
* is not possible to determine the date.
*/
public long getLastModified() {
this.getInfos();
return this.lastModificationDate;
}
/**
* Get the content length of the source or -1 if it
* is not possible to determine the length.
*/
public long getContentLength() {
this.getInfos();
return this.contentLength;
}
/**
* Return an <code>InputStream</code> object to read from the source.
*
* @throws ResourceNotFoundException if file not found or
* HTTP location does not exist.
* @throws IOException if I/O error occured.
*/
public InputStream getInputStream()
throws IOException, ProcessingException {
this.getInfos();
try {
InputStream input = null;
if ( this.isFile ) {
input = new FileInputStream(this.systemId.substring(FILE.length()));
} else {
if (this.connection == null) {
this.connection = this.url.openConnection();
/* The following requires a jdk 1.3 */
String userInfo = this.getUserInfo();
if (this.url.getProtocol().startsWith("http") && userInfo != null) {
this.connection.setRequestProperty("Authorization","Basic "+SourceUtil.encodeBASE64(userInfo));
}
// do a post operation
if (this.connection instanceof HttpURLConnection
&& this.postParameters != null) {
StringBuffer buffer = new StringBuffer(2000);
String key;
Iterator i = postParameters.getParameterNames();
Iterator values;
String value;
boolean first = true;
while ( i.hasNext() ) {
key = (String)i.next();
values = this.postParameters.getParameterValues(key);
while (values.hasNext() == true) {
value = SourceUtil.encode((String)values.next());
if (first == false) buffer.append('&');
first = false;
buffer.append(key.toString());
buffer.append('=');
buffer.append(value);
}
}
HttpURLConnection httpCon = (HttpURLConnection)connection;
httpCon.setDoInput(true);
if (buffer.length() > 1) { // only post if we have parameters
String postString = buffer.toString();
httpCon.setRequestMethod("POST"); // this is POST
httpCon.setDoOutput(true);
httpCon.setRequestProperty("Content-type", "application/x-www-form-urlencoded");
// A content-length header must be contained in a POST request
httpCon.setRequestProperty("Content-length", Integer.toString(postString.length()));
java.io.OutputStream out = new java.io.BufferedOutputStream(httpCon.getOutputStream());
out.write(postString.getBytes());
out.close();
}
if ("text/html".equals(httpCon.getContentType()) == true) {
this.isHTMLContent = true;
}
input = httpCon.getInputStream();
this.connection = null; // make sure a new connection is created next time
return input;
}
}
if ("text/html".equals(this.connection.getContentType()) == true) {
this.isHTMLContent = true;
}
input = this.connection.getInputStream();
this.connection = null; // make sure a new connection is created next time
}
return input;
} catch (FileNotFoundException e) {
throw new ResourceNotFoundException("Resource not found "
+ this.systemId, e);
}
}
private static boolean checkedURLClass = false;
private static boolean urlSupportsGetUserInfo = false;
private static Method urlGetUserInfo = null;
private static Object[] emptyParams = new Object[0];
/**
* Check if the <code>URL</code> class supports the getUserInfo()
* method which is introduced in jdk 1.3
*/
private String getUserInfo() {
if (URLSource.checkedURLClass) {
if (URLSource.urlSupportsGetUserInfo) {
try {
return (String) URLSource.urlGetUserInfo.invoke(this.url, URLSource.emptyParams);
} catch (Exception e){
// ignore this anyway
}
}
return null;
} else {
// test if the url class supports the getUserInfo method
try {
URLSource.urlGetUserInfo = URL.class.getMethod("getUserInfo", null);
String ui = (String)URLSource.urlGetUserInfo.invoke(this.url, URLSource.emptyParams);
URLSource.checkedURLClass = true;
URLSource.urlSupportsGetUserInfo = true;
return ui;
} catch (Exception e){
}
URLSource.checkedURLClass = true;
URLSource.urlSupportsGetUserInfo = false;
URLSource.urlGetUserInfo = null;
return null;
}
}
/**
* Return the unique identifer for this source
*/
public String getSystemId() {
return this.systemId;
}
/**
* Refresh this object and update the last modified date
* and content length.
*/
public void refresh() {
// reset connection
this.connection = null;
this.gotInfos = false;
}
public void recycle() {
refresh();
}
/**
* Set the post parameters
*/
public void setPostParameters(SourceParameters pars) {
this.postParameters = pars;
}
}