blob: c4424c14fda42f5394fa9a000501d310acf0177e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.taverna.reference.impl.external.http;
import static java.lang.System.currentTimeMillis;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.ProtocolException;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Date;
import org.apache.taverna.reference.AbstractExternalReference;
import org.apache.taverna.reference.DereferenceException;
import org.apache.taverna.reference.ExternalReferenceSPI;
import org.apache.taverna.reference.ExternalReferenceValidationException;
import org.apache.taverna.reference.ReferenceContext;
import org.apache.http.entity.ContentType;
/**
* Implementation of ExternalReference used to refer to data held in a locally
* accessible file. Inherits from
* {@link org.apache.taverna.reference.AbstractExternalReference
* AbstractExternalReference} to enable hibernate based persistence.
*
*/
public class HttpReference extends AbstractExternalReference implements
ExternalReferenceSPI {
private String httpUrlString = null;
private URL httpUrl = null;
private String charsetName = null;
private boolean charsetFetched = false;
private transient Long cachedLength;
private transient Date cacheTime;
/**
* Explicitly declare default constructor, will be used by hibernate when
* constructing instances of this bean from the database.
*/
public HttpReference() {
super();
}
/**
* Return the data at the {@link URL} represented by this external reference
*/
@Override
public InputStream openStream(ReferenceContext context)
throws DereferenceException {
try {
return httpUrl.openStream();
} catch (IOException e) {
throw new DereferenceException(e);
}
}
@Override
public String getCharset() throws DereferenceException {
if (charsetFetched)
return charsetName;
if (!httpUrl.getProtocol().equals("http")
&& !httpUrl.getProtocol().equals("https")) {
// We don't know, probably system charset
return null;
}
// We already ruled out non-http/https above, so somewhat safe cast
HttpURLConnection c;
try {
c = (HttpURLConnection) httpUrl.openConnection();
} catch (IOException e) {
// Does not matter, then we don't know charset. Assume this may fail later as well.
charsetFetched = true;
return null;
}
try {
c.setRequestMethod("HEAD");
} catch (ProtocolException e1) {
throw new RuntimeException("HttpURLConnection does not recognize HEAD method", e1);
}
// We don't use the input stream, but do need to close it after
try (InputStream is = c.getInputStream()) {
//connection.connect();
String type = c.getHeaderField("Content-Type");
if (type != null) {
ContentType ct = ContentType.parse(type);
Charset charset = ct.getCharset();
if (charset != null) {
charsetName = charset.name();
}
}
charsetFetched = true;
return charsetName;
} catch (IOException e) {
// Does not matter, then we don't know charset. Assume this may fail later.
charsetFetched = true;
return null;
}
}
/**
* Setter used by hibernate to set the file path property of the file
* reference
*
* @throws ExternalReferenceValidationException
* if there is some problem parsing the supplied string as a URL
*/
public void setHttpUrlString(String httpUrlString) {
try {
this.httpUrlString = httpUrlString;
this.httpUrl = new URL(httpUrlString);
} catch (MalformedURLException e) {
throw new ExternalReferenceValidationException(e);
}
}
/**
* Getter used by hibernate to retrieve the file path string property
*/
public String getHttpUrlString() {
return this.httpUrlString;
}
/**
* Human readable string form for debugging, should not be regarded as
* stable.
*/
@Override
public String toString() {
return "http{" + httpUrl.toExternalForm() + "}";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((httpUrl == null) ? 0 : httpUrl.toExternalForm().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof HttpReference))
return false;
final HttpReference other = (HttpReference) obj;
if (httpUrl == null) {
if (other.httpUrl != null)
return false;
} else if (!httpUrl.toExternalForm().equals(
other.httpUrl.toExternalForm()))
return false;
return true;
}
// One minute
private static final int CACHE_TIMEOUT = 60000;
@Override
public Long getApproximateSizeInBytes() {
long now = currentTimeMillis();
if (cachedLength != null && cacheTime != null
&& cacheTime.getTime() + CACHE_TIMEOUT > now)
return cachedLength;
try {
HttpURLConnection c = (HttpURLConnection) httpUrl.openConnection();
c.setRequestMethod("HEAD");
c.connect();
String lenString = c.getHeaderField("Content-Length");
if (lenString != null && !lenString.isEmpty()) {
cachedLength = new Long(lenString);
cacheTime = new Date(now);
return cachedLength;
}
// there is no Content-Length field so we cannot know the size
} catch (Exception e) {
// something went wrong, but we don't care what
}
cachedLength = null;
cacheTime = null;
return new Long(-1);
}
/**
* @return the httpUrl
*/
public final URL getHttpUrl() {
return httpUrl;
}
@Override
public float getResolutionCost() {
return (float) 200.0;
}
public void deleteData() {
throw new UnsupportedOperationException(
"Cannot delete data referenced by a URL");
}
@Override
public HttpReference clone() {
HttpReference result = new HttpReference();
result.setHttpUrlString(this.getHttpUrlString());
return result;
}
}