Java tutorial
/* ownCloud Android Library is available under MIT license * Copyright (C) 2015 ownCloud Inc. * Copyright (C) 2012 Bartek Przybylski * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * */ package com.cerema.cloud2.lib.common; import java.io.IOException; import java.io.InputStream; import org.apache.commons.httpclient.Cookie; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HostConfiguration; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpConnectionManager; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpMethodBase; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.HttpVersion; import org.apache.commons.httpclient.URI; import org.apache.commons.httpclient.cookie.CookiePolicy; import org.apache.commons.httpclient.methods.HeadMethod; import org.apache.commons.httpclient.params.HttpMethodParams; import org.apache.commons.httpclient.params.HttpParams; import android.net.Uri; import com.cerema.cloud2.lib.common.OwnCloudCredentialsFactory.OwnCloudAnonymousCredentials; import com.cerema.cloud2.lib.common.accounts.AccountUtils; import com.cerema.cloud2.lib.common.network.RedirectionPath; import com.cerema.cloud2.lib.common.network.WebdavUtils; import com.cerema.cloud2.lib.common.utils.Log_OC; import com.cerema.cloud2.lib.resources.status.OwnCloudVersion; public class OwnCloudClient extends HttpClient { private static final String TAG = OwnCloudClient.class.getSimpleName(); public static final int MAX_REDIRECTIONS_COUNT = 3; private static final String PARAM_SINGLE_COOKIE_HEADER = "http.protocol.single-cookie-header"; private static final boolean PARAM_SINGLE_COOKIE_HEADER_VALUE = true; private static final String PARAM_PROTOCOL_VERSION = "http.protocol.version"; private static byte[] sExhaustBuffer = new byte[1024]; private static int sIntanceCounter = 0; private boolean mFollowRedirects = true; private OwnCloudCredentials mCredentials = null; private int mInstanceNumber = 0; private Uri mBaseUri; private OwnCloudVersion mVersion = null; /** * Constructor */ public OwnCloudClient(Uri baseUri, HttpConnectionManager connectionMgr) { super(connectionMgr); if (baseUri == null) { throw new IllegalArgumentException("Parameter 'baseUri' cannot be NULL"); } mBaseUri = baseUri; mInstanceNumber = sIntanceCounter++; Log_OC.d(TAG + " #" + mInstanceNumber, "Creating OwnCloudClient"); String userAgent = OwnCloudClientManagerFactory.getUserAgent(); getParams().setParameter(HttpMethodParams.USER_AGENT, userAgent); getParams().setParameter(PARAM_PROTOCOL_VERSION, HttpVersion.HTTP_1_1); getParams().setCookiePolicy(CookiePolicy.IGNORE_COOKIES); getParams().setParameter(PARAM_SINGLE_COOKIE_HEADER, // to avoid problems with some web servers PARAM_SINGLE_COOKIE_HEADER_VALUE); applyProxySettings(); clearCredentials(); } private void applyProxySettings() { String proxyHost = System.getProperty("http.proxyHost"); String proxyPortSt = System.getProperty("http.proxyPort"); int proxyPort = 0; try { if (proxyPortSt != null && proxyPortSt.length() > 0) { proxyPort = Integer.parseInt(proxyPortSt); } } catch (Exception e) { // nothing to do here } if (proxyHost != null && proxyHost.length() > 0) { HostConfiguration hostCfg = getHostConfiguration(); hostCfg.setProxy(proxyHost, proxyPort); Log_OC.d(TAG, "Proxy settings: " + proxyHost + ":" + proxyPort); } } public void setCredentials(OwnCloudCredentials credentials) { if (credentials != null) { mCredentials = credentials; mCredentials.applyTo(this); } else { clearCredentials(); } } public void clearCredentials() { if (!(mCredentials instanceof OwnCloudAnonymousCredentials)) { mCredentials = OwnCloudCredentialsFactory.getAnonymousCredentials(); } mCredentials.applyTo(this); } /** * Check if a file exists in the OC server * * @deprecated Use ExistenceCheckOperation instead * * @return 'true' if the file exists; 'false' it doesn't exist * @throws Exception When the existence could not be determined */ @Deprecated public boolean existsFile(String path) throws IOException, HttpException { HeadMethod head = new HeadMethod(getWebdavUri() + WebdavUtils.encodePath(path)); try { int status = executeMethod(head); Log_OC.d(TAG, "HEAD to " + path + " finished with HTTP status " + status + ((status != HttpStatus.SC_OK) ? "(FAIL)" : "")); exhaustResponse(head.getResponseBodyAsStream()); return (status == HttpStatus.SC_OK); } finally { head.releaseConnection(); // let the connection available for other methods } } /** * Requests the received method with the received timeout (milliseconds). * * Executes the method through the inherited HttpClient.executedMethod(method). * * Sets the socket and connection timeouts only for the method received. * * The timeouts are both in milliseconds; 0 means 'infinite'; * < 0 means 'do not change the default' * * @param method HTTP method request. * @param readTimeout Timeout to set for data reception * @param connectionTimeout Timeout to set for connection establishment */ public int executeMethod(HttpMethodBase method, int readTimeout, int connectionTimeout) throws IOException { int oldSoTimeout = getParams().getSoTimeout(); int oldConnectionTimeout = getHttpConnectionManager().getParams().getConnectionTimeout(); try { if (readTimeout >= 0) { method.getParams().setSoTimeout(readTimeout); // this should be enough... getParams().setSoTimeout(readTimeout); // ... but HTTPS needs this } if (connectionTimeout >= 0) { getHttpConnectionManager().getParams().setConnectionTimeout(connectionTimeout); } return executeMethod(method); } finally { getParams().setSoTimeout(oldSoTimeout); getHttpConnectionManager().getParams().setConnectionTimeout(oldConnectionTimeout); } } /** * Requests the received method. * * Executes the method through the inherited HttpClient.executedMethod(method). * * @param method HTTP method request. */ @Override public int executeMethod(HttpMethod method) throws IOException { try { // Update User Agent HttpParams params = method.getParams(); String userAgent = OwnCloudClientManagerFactory.getUserAgent(); params.setParameter(HttpMethodParams.USER_AGENT, userAgent); Log_OC.d(TAG + " #" + mInstanceNumber, "REQUEST " + method.getName() + " " + method.getPath()); // logCookiesAtRequest(method.getRequestHeaders(), "before"); // logCookiesAtState("before"); method.setFollowRedirects(false); int status = super.executeMethod(method); if (mFollowRedirects) { status = followRedirection(method).getLastStatus(); } // logCookiesAtRequest(method.getRequestHeaders(), "after"); // logCookiesAtState("after"); // logSetCookiesAtResponse(method.getResponseHeaders()); return status; } catch (IOException e) { //Log_OC.d(TAG + " #" + mInstanceNumber, "Exception occurred", e); throw e; } } public RedirectionPath followRedirection(HttpMethod method) throws IOException { int redirectionsCount = 0; int status = method.getStatusCode(); RedirectionPath result = new RedirectionPath(status, MAX_REDIRECTIONS_COUNT); while (redirectionsCount < MAX_REDIRECTIONS_COUNT && (status == HttpStatus.SC_MOVED_PERMANENTLY || status == HttpStatus.SC_MOVED_TEMPORARILY || status == HttpStatus.SC_TEMPORARY_REDIRECT)) { Header location = method.getResponseHeader("Location"); if (location == null) { location = method.getResponseHeader("location"); } if (location != null) { Log_OC.d(TAG + " #" + mInstanceNumber, "Location to redirect: " + location.getValue()); String locationStr = location.getValue(); result.addLocation(locationStr); // Release the connection to avoid reach the max number of connections per host // due to it will be set a different url exhaustResponse(method.getResponseBodyAsStream()); method.releaseConnection(); method.setURI(new URI(locationStr, true)); Header destination = method.getRequestHeader("Destination"); if (destination == null) { destination = method.getRequestHeader("destination"); } if (destination != null) { int suffixIndex = locationStr.lastIndexOf( (mCredentials instanceof OwnCloudBearerCredentials) ? AccountUtils.ODAV_PATH : AccountUtils.WEBDAV_PATH_4_0); String redirectionBase = locationStr.substring(0, suffixIndex); String destinationStr = destination.getValue(); String destinationPath = destinationStr.substring(mBaseUri.toString().length()); String redirectedDestination = redirectionBase + destinationPath; destination.setValue(redirectedDestination); method.setRequestHeader(destination); } status = super.executeMethod(method); result.addStatus(status); redirectionsCount++; } else { Log_OC.d(TAG + " #" + mInstanceNumber, "No location to redirect!"); status = HttpStatus.SC_NOT_FOUND; } } return result; } /** * Exhausts a not interesting HTTP response. Encouraged by HttpClient documentation. * * @param responseBodyAsStream InputStream with the HTTP response to exhaust. */ public void exhaustResponse(InputStream responseBodyAsStream) { if (responseBodyAsStream != null) { try { while (responseBodyAsStream.read(sExhaustBuffer) >= 0) ; responseBodyAsStream.close(); } catch (IOException io) { Log_OC.e(TAG, "Unexpected exception while exhausting not interesting HTTP response;" + " will be IGNORED", io); } } } /** * Sets the connection and wait-for-data timeouts to be applied by default to the methods * performed by this client. */ public void setDefaultTimeouts(int defaultDataTimeout, int defaultConnectionTimeout) { if (defaultDataTimeout >= 0) { getParams().setSoTimeout(defaultDataTimeout); } if (defaultConnectionTimeout >= 0) { getHttpConnectionManager().getParams().setConnectionTimeout(defaultConnectionTimeout); } } public Uri getWebdavUri() { if (mCredentials instanceof OwnCloudBearerCredentials) { return Uri.parse(mBaseUri + AccountUtils.ODAV_PATH); } else { return Uri.parse(mBaseUri + AccountUtils.WEBDAV_PATH_4_0); } } /** * Sets the root URI to the ownCloud server. * * Use with care. * * @param uri */ public void setBaseUri(Uri uri) { if (uri == null) { throw new IllegalArgumentException("URI cannot be NULL"); } mBaseUri = uri; } public Uri getBaseUri() { return mBaseUri; } public final OwnCloudCredentials getCredentials() { return mCredentials; } public void setFollowRedirects(boolean followRedirects) { mFollowRedirects = followRedirects; } public boolean getFollowRedirects() { return mFollowRedirects; } private void logCookiesAtRequest(Header[] headers, String when) { int counter = 0; for (int i = 0; i < headers.length; i++) { if (headers[i].getName().toLowerCase().equals("cookie")) { Log_OC.d(TAG + " #" + mInstanceNumber, "Cookies at request (" + when + ") (" + counter++ + "): " + headers[i].getValue()); } } if (counter == 0) { Log_OC.d(TAG + " #" + mInstanceNumber, "No cookie at request before"); } } private void logCookiesAtState(String string) { Cookie[] cookies = getState().getCookies(); if (cookies.length == 0) { Log_OC.d(TAG + " #" + mInstanceNumber, "No cookie at STATE before"); } else { Log_OC.d(TAG + " #" + mInstanceNumber, "Cookies at STATE (before)"); for (int i = 0; i < cookies.length; i++) { Log_OC.d(TAG + " #" + mInstanceNumber, " (" + i + "):" + "\n name: " + cookies[i].getName() + "\n value: " + cookies[i].getValue() + "\n domain: " + cookies[i].getDomain() + "\n path: " + cookies[i].getPath()); } } } private void logSetCookiesAtResponse(Header[] headers) { int counter = 0; for (int i = 0; i < headers.length; i++) { if (headers[i].getName().toLowerCase().equals("set-cookie")) { Log_OC.d(TAG + " #" + mInstanceNumber, "Set-Cookie (" + counter++ + "): " + headers[i].getValue()); } } if (counter == 0) { Log_OC.d(TAG + " #" + mInstanceNumber, "No set-cookie"); } } public String getCookiesString() { Cookie[] cookies = getState().getCookies(); String cookiesString = ""; for (Cookie cookie : cookies) { cookiesString = cookiesString + cookie.toString() + ";"; // logCookie(cookie); } return cookiesString; } public int getConnectionTimeout() { return getHttpConnectionManager().getParams().getConnectionTimeout(); } public int getDataTimeout() { return getParams().getSoTimeout(); } private void logCookie(Cookie cookie) { Log_OC.d(TAG, "Cookie name: " + cookie.getName()); Log_OC.d(TAG, " value: " + cookie.getValue()); Log_OC.d(TAG, " domain: " + cookie.getDomain()); Log_OC.d(TAG, " path: " + cookie.getPath()); Log_OC.d(TAG, " version: " + cookie.getVersion()); Log_OC.d(TAG, " expiryDate: " + (cookie.getExpiryDate() != null ? cookie.getExpiryDate().toString() : "--")); Log_OC.d(TAG, " comment: " + cookie.getComment()); Log_OC.d(TAG, " secure: " + cookie.getSecure()); } public void setOwnCloudVersion(OwnCloudVersion version) { mVersion = version; } public OwnCloudVersion getOwnCloudVersion() { return mVersion; } }