net.oneandone.sushi.fs.webdav.WebdavRoot.java Source code

Java tutorial

Introduction

Here is the source code for net.oneandone.sushi.fs.webdav.WebdavRoot.java

Source

/**
 * Copyright 1&1 Internet AG, https://github.com/1and1/
 *
 * 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 net.oneandone.sushi.fs.webdav;

import net.oneandone.sushi.fs.Root;
import net.oneandone.sushi.util.Base64;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpException;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;

import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class WebdavRoot implements Root<WebdavNode> {
    private final WebdavFilesystem filesystem;
    public final HttpHost host;
    private final HttpParams params;
    private String authorization;

    public WebdavRoot(WebdavFilesystem filesystem, String protocol, String host, int port) {
        this.filesystem = filesystem;
        this.host = new HttpHost(host, port, protocol);
        this.authorization = null;
        this.params = new BasicHttpParams();

        HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
        HttpProtocolParams.setContentCharset(params, WebdavFilesystem.ENCODING);
    }

    public void setUserInfo(String userinfo) {
        int idx;

        idx = userinfo.indexOf(':');
        if (idx == -1) {
            setCredentials(userinfo, "");
        } else {
            setCredentials(userinfo.substring(0, idx), userinfo.substring(idx + 1));
        }
    }

    public void setCredentials(String username, String password) {
        authorization = "Basic " + new Base64(true).run(username + ":" + password);
    }

    public int getConnectionTimeout() {
        return HttpConnectionParams.getConnectionTimeout(params);
    }

    public void setConnectionTimeout(int millis) {
        HttpConnectionParams.setSoTimeout(params, millis);
    }

    public int getSoTimeout() {
        return HttpConnectionParams.getSoTimeout(params);
    }

    public void setSoTimeout(int millis) {
        HttpConnectionParams.setSoTimeout(params, millis);
    }

    @Override
    public boolean equals(Object obj) {
        WebdavRoot root;

        if (obj instanceof WebdavRoot) {
            root = (WebdavRoot) obj;
            return filesystem == root.filesystem /* TODO params etc */;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return host.hashCode();
    }

    public WebdavFilesystem getFilesystem() {
        return filesystem;
    }

    public String getId() {
        int port;

        port = host.getPort();
        // TODO: credentials?
        return "//" + host.getHostName() + (port == 80 ? "" : ":" + port) + "/";
    }

    public WebdavNode node(String path, String encodedQuery) {
        return new WebdavNode(this, path, encodedQuery, false);
    }

    private final List<WebdavConnection> pool = new ArrayList<WebdavConnection>();
    private int allocated = 0;

    public synchronized WebdavConnection allocate() throws IOException {
        int size;

        allocated++;
        size = pool.size();
        if (size > 0) {
            return pool.remove(size - 1);
        } else {
            Socket socket;

            if ("https".equals(host.getSchemeName())) {
                socket = SSLSocketFactory.getDefault().createSocket(host.getHostName(), host.getPort());
            } else {
                socket = new Socket(host.getHostName(), host.getPort());
            }
            return WebdavConnection.open(socket, params);
        }
    }

    public synchronized void free(HttpResponse response, WebdavConnection connection) throws IOException {
        HttpEntity entity;

        if (allocated == 0) {
            throw new IllegalStateException();
        }
        allocated--;
        if (response != null) {
            entity = response.getEntity();
            if (entity != null) {
                entity.getContent().close();
            }
        }
        if (wantsClose(response)) {
            connection.close();
        }
        if (connection.isOpen() && pool.size() < 10) {
            pool.add(connection);
        }
    }

    public synchronized int getAllocated() {
        return allocated;
    }

    private static boolean wantsClose(HttpResponse response) {
        if (response == null) {
            // no response yet
            return true;
        }
        for (Header header : response.getHeaders(HTTP.CONN_DIRECTIVE)) {
            if ("close".equalsIgnoreCase(header.getValue())) {
                return true;
            }
        }
        return false;
    }

    //--

    public void send(WebdavConnection conn, HttpRequest request) throws IOException {
        // TODO: side effect
        request.addHeader(HTTP.TARGET_HOST, host.getHostName());
        if (authorization != null) {
            request.addHeader("Authorization", authorization);
        }
        // TODO: request.addHeader("Keep-Alive", "300");

        try {
            conn.sendRequestHeader(request);
            if (request instanceof HttpEntityEnclosingRequest) {
                conn.sendRequestEntity((HttpEntityEnclosingRequest) request);
            }
            conn.flush();
        } catch (IOException e) {
            free(null, conn);
            throw e;
        } catch (HttpException e) {
            free(null, conn);
            // TODO
            throw new IOException(e);
        } catch (RuntimeException e) {
            free(null, conn);
            throw e;
        }
    }

    public HttpResponse receive(WebdavConnection conn, boolean head) throws IOException {
        HttpResponse response;
        int statuscode;

        response = null;
        try {
            do {
                response = conn.receiveResponseHeader();
                if (canResponseHaveBody(response, head)) {
                    conn.receiveResponseEntity(response);
                }
                statuscode = response.getStatusLine().getStatusCode();
            } while (response == null || statuscode < HttpStatus.SC_OK);
            return response;
        } catch (IOException e) {
            free(response, conn);
            throw e;
        } catch (HttpException e) {
            free(response, conn);
            // TODO
            throw new IOException(e);
        } catch (RuntimeException e) {
            free(response, conn);
            throw e;
        }
    }

    private boolean canResponseHaveBody(HttpResponse response, boolean head) {
        int status;

        status = response.getStatusLine().getStatusCode();
        if (status == HttpStatus.SC_OK && head) {
            return false;
        }
        return status >= HttpStatus.SC_OK && status != HttpStatus.SC_NO_CONTENT
                && status != HttpStatus.SC_NOT_MODIFIED && status != HttpStatus.SC_RESET_CONTENT;
    }
}