package de.uni_goettingen.sub.commons.ocr.abbyy.server.hotfolder;
/*
© 2009,2010, SUB Göttingen. All rights reserved.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as
published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HostConfiguration;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpConnectionManager;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.FileRequestEntity;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.HeadMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.io.IOUtils;
import org.apache.jackrabbit.webdav.DavConstants;
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.MultiStatus;
import org.apache.jackrabbit.webdav.MultiStatusResponse;
import org.apache.jackrabbit.webdav.client.methods.DeleteMethod;
import org.apache.jackrabbit.webdav.client.methods.PropFindMethod;
import org.apache.jackrabbit.webdav.client.methods.PutMethod;
import org.apache.jackrabbit.webdav.property.DavPropertyName;
import org.apache.jackrabbit.webdav.property.DavPropertySet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import de.unigoettingen.sub.commons.ocr.util.Pause;
public class JackrabbitHotfolder extends ServerHotfolder implements
Hotfolder, Serializable {
private static final long serialVersionUID = 1L;
private final static Logger log = LoggerFactory.getLogger(JackrabbitHotfolder.class);
private HttpClient client;
private Pause pause = new Pause();
// for unit tests
void setHttpClient(HttpClient newClient) {
client = newClient;
}
void setPause(Pause newPause) {
pause = newPause;
}
public void configureConnection(String serverUrl, String username, String password) {
URL url;
try {
url = new URL(serverUrl);
} catch (MalformedURLException e) {
throw new IllegalStateException("no valid host given: "
+ e.toString());
}
HostConfiguration hostConfig = new HostConfiguration();
hostConfig.setHost(url.getHost(), url.getDefaultPort(),
url.getProtocol());
HttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams params = new HttpConnectionManagerParams();
int maxHostConnections = 10;
params.setMaxConnectionsPerHost(hostConfig, maxHostConnections);
params.setStaleCheckingEnabled(true);
params.setSoTimeout(10000);
connectionManager.setParams(params);
client = new HttpClient(connectionManager);
if (username != null || password != null) {
Credentials creds = new UsernamePasswordCredentials(username,
password);
client.getParams().setAuthenticationPreemptive(true);
client.getState().setCredentials(AuthScope.ANY, creds);
}
client.setHostConfiguration(hostConfig);
}
@Override
public void upload(URI fromLocal, URI toRemote) throws IOException {
File sourceFile = new File(fromLocal);
String targetUri = toRemote.toString();
if (!fileAccess.fileExists(sourceFile)) {
log.error("File " + sourceFile + " doesn't exist.");
throw new IllegalArgumentException("File " + sourceFile
+ " doesn't exist.");
}
PutMethod putMethod = new PutMethod(targetUri);
String mimeType = URLConnection.guessContentTypeFromName(sourceFile.getPath());
putMethod.setRequestEntity(new FileRequestEntity(sourceFile, mimeType));
try {
execute(putMethod);
} finally {
putMethod.releaseConnection();
}
}
@Override
public void download(URI fromRemote, URI toLocal) throws IOException {
String sourceUri = fromRemote.toString();
File targetFile = new File(toLocal);
GetMethod getMethod = new GetMethod(sourceUri);
InputStream responseStream = null;
try {
responseStream = execute(getMethod);
fileAccess.copyStreamToFile(responseStream, targetFile);
} finally {
responseStream.close();
getMethod.releaseConnection();
}
}
private InputStream execute(HttpMethod method) throws URIException {
InputStream responseStream = null;
int responseCode = 0;
int timesToTry = 10;
try {
for (int i = 1; i <= timesToTry; i++) {
try {
responseCode = client.executeMethod(method);
log.trace("Response code in executeMethod: " + responseCode);
if (responseCode >= HttpStatus.SC_MOVED_PERMANENTLY) {
throw new IOException("Got illegal response code " + responseCode);
}
// method was executed correctly, stop retrying
responseStream = method.getResponseBodyAsStream();
break;
} catch (IOException e) {
if (i == timesToTry) {
log.error("Error connecting to server. URL is " + method.getURI());
throw new IllegalStateException("Error connecting to server. URL is " + method.getURI(), e);
}
log.warn("Problem connecting to server. Retry number " + i + "... URL is " + method.getURI());
pause.forMilliseconds(10000);
}
}
} finally {
if (responseStream == null) {
responseStream = new ByteArrayInputStream(new byte[]{});
}
}
return responseStream;
}
@Override
public void delete(URI uri) throws IOException {
DeleteMethod delMethod = new DeleteMethod(uri.toString());
try {
execute(delMethod);
} finally {
delMethod.releaseConnection();
}
}
@Override
public boolean exists(URI uri) throws IOException {
HeadMethod headMethod = new HeadMethod(uri.toString());
try {
headMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(10, false));
int responseCode = client.executeMethod(headMethod);
if (responseCode == HttpStatus.SC_OK) {
return true;
}
return false;
} finally {
headMethod.releaseConnection();
}
}
@Override
public long getUsedSpace(URI uri) throws IOException {
long size = 0;
PropFindMethod propFindMethod = new PropFindMethod(uri.toString(),
DavConstants.PROPFIND_ALL_PROP, DavConstants.DEPTH_1);
try {
execute(propFindMethod);
MultiStatus multiStatus = getMultiStatus(propFindMethod);
for (MultiStatusResponse response : multiStatus.getResponses()) {
DavPropertySet props = response.getProperties(200);
if (props.contains(DavPropertyName.GETCONTENTLENGTH)
&& props.get(DavPropertyName.GETCONTENTLENGTH).getValue() != null) {
size += Long.parseLong((String) props.get(
DavPropertyName.GETCONTENTLENGTH).getValue());
}
}
} catch (DavException e) {
throw new IOException("Could not execute MultiStatus method", e);
} finally {
propFindMethod.releaseConnection();
}
return size;
}
// for unit tests
MultiStatus getMultiStatus(PropFindMethod method) throws IOException, DavException {
return method.getResponseBodyAsMultiStatus();
}
@Override
public byte[] getResponse(URI uri) throws IOException {
GetMethod getMethod = new GetMethod(uri.toString());
InputStream responseStream = null;
try {
responseStream = execute(getMethod);
byte[] responseBytes = IOUtils.toByteArray(responseStream);
return responseBytes;
} finally {
responseStream.close();
getMethod.releaseConnection();
}
}
}