Java tutorial
/** * Copyright 2010 Eric Taix 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.jared.synodroid.ds.server; import java.io.BufferedReader; import java.io.EOFException; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.SocketException; import java.net.URL; import java.security.SecureRandom; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.TrustManager; import org.jared.synodroid.ds.Synodroid; import org.jared.synodroid.ds.protocol.DSMException; import org.jared.synodroid.ds.protocol.DSMHandlerFactory; import org.jared.synodroid.ds.protocol.MultipartBuilder; import org.jared.synodroid.ds.protocol.https.AcceptAllHostNameVerifier; import org.jared.synodroid.ds.protocol.https.AcceptAllTrustManager; import org.jared.synodroid.ds.utils.GenericException; import org.jared.synodroid.ds.utils.ServerParam; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.jared.synodroid.ds.data.DSMVersion; import android.net.Uri; import android.util.Log; /** * This is a light weight class for the synology server. This class assumes that you are already connected and reuse the cookie of * the normal SynoServer class to to its transaction. This is used by content providers and external intents. * * @author Steve Garon */ public class SimpleSynoServer { public boolean DEBUG = false; protected String cookies = ""; protected DSMHandlerFactory dsmFactory; protected DSMVersion dsmVersion = DSMVersion.VERSION2_2; protected boolean autoDetect = false; protected String url; /** * Static intialization of the SSL factory to accept each certificate, even if a certificate is self signed */ static { SSLContext sc; try { sc = SSLContext.getInstance("TLS"); sc.init(null, new TrustManager[] { new AcceptAllTrustManager() }, new SecureRandom()); HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory()); HttpsURLConnection.setDefaultHostnameVerifier(new AcceptAllHostNameVerifier()); } catch (Exception ex) { ex.printStackTrace(); } } /** * Constructor which set all server's informations. No connection are made when calling the constructor. */ public SimpleSynoServer() { } /** * This is the actual initialisation function * @param params */ public void setParams(ServerParam params) { cookies = params.getCookie(); url = params.getUrl(); dsmVersion = DSMVersion.titleOf(params.getDSMVersion()); autoDetect = false; DEBUG = params.getDbg(); dsmFactory = DSMHandlerFactory.getFactory(dsmVersion, this, DEBUG, autoDetect); } /** * Return the handler factory * * @return */ public DSMHandlerFactory getDSMHandlerFactory() { return dsmFactory; } /** * @return the dsmVersion */ public DSMVersion getDsmVersion() { return dsmVersion; } public String getUrl() { return url; } public void setCookie(String cookieP) { cookies = cookieP; } public String getCookies() { return cookies; } /** * Create a connection and add all required cookies information * * @param uriP * @param requestP * @param methodP * @return * @throws MalformedURLException * @throws IOException */ protected HttpURLConnection createConnection(String uriP, String requestP, String methodP, boolean log) throws MalformedURLException, IOException { // Prepare the connection HttpURLConnection con = (HttpURLConnection) new URL(getUrl() + Uri.encode(uriP, "/")).openConnection(); // Add cookies if exist if (cookies != null) { con.addRequestProperty("Cookie", getCookies()); if (DEBUG) Log.v(Synodroid.DS_TAG, "Added cookie to the request: " + cookies); } con.setDoOutput(true); con.setDoInput(true); con.setUseCaches(false); con.setRequestMethod(methodP); con.setConnectTimeout(20000); if (DEBUG) { if (log) { Log.i(Synodroid.DS_TAG, methodP + ": " + uriP + "?" + requestP); } else { Log.i(Synodroid.DS_TAG, methodP + ": " + uriP + " (hidden request)"); } } return con; } /** * Send a request to the server. * * @param uriP * The part of the URI ie: /webman/doit.cgi * @param requestP * The query in the form 'param1=foo¶m2=yes' * @param methodP * The method to send this request * @return A JSONObject containing the response of the server * @throws DSMException */ public JSONObject sendJSONRequest(String uriP, String requestP, String methodP) throws Exception { return sendJSONRequest(uriP, requestP, methodP, true); } /** * Send a request to the server. * * @param uriP * The part of the URI ie: /webman/doit.cgi * @param requestP * The query in the form 'param1=foo¶m2=yes' * @param methodP * The method to send this request * @return A JSONArray containing the response of the server * @throws DSMException */ public JSONArray sendJSONRequestArray(String uriP, String requestP, String methodP) throws Exception { return sendJSONRequestArray(uriP, requestP, methodP, true); } /** * Send a request to the server. * * @param uriP * The part of the URI ie: /webman/doit.cgi * @param requestP * The query in the form 'param1=foo¶m2=yes' * @param methodP * The method to send this request * @return A JSONObject containing the response of the server * @throws DSMException */ public JSONArray sendJSONRequestArray(String uriP, String requestP, String methodP, boolean log) throws Exception { HttpURLConnection con = null; OutputStreamWriter wr = null; BufferedReader br = null; StringBuffer sb = null; Exception last_exception = null; try { // For some reason in Gingerbread I often get a response code of -1. // Here I retry for a maximum of MAX_RETRY to send the request and it usually succeed at the second try... int retry = 0; int MAX_RETRY = 2; while (retry <= MAX_RETRY) { try { // Create the connection con = createConnection(uriP, requestP, methodP, log); // Add the parameters wr = new OutputStreamWriter(con.getOutputStream()); wr.write(requestP); // Send the request wr.flush(); wr.close(); // Try to retrieve the session cookie String newCookie = con.getHeaderField("set-cookie"); if (newCookie != null) { synchronized (this) { setCookie(newCookie); } if (DEBUG) Log.v(Synodroid.DS_TAG, "Retreived cookies: " + cookies); } // Now read the reponse and build a string with it br = new BufferedReader(new InputStreamReader(con.getInputStream())); sb = new StringBuffer(); String line; while ((line = br.readLine()) != null) { sb.append(line); } br.close(); // Verify is response if not -1, otherwise take reason from the header if (con.getResponseCode() == -1) { retry++; if (DEBUG) Log.w(Synodroid.DS_TAG, "Response code is -1 (retry: " + retry + ")"); } else { if (DEBUG) Log.d(Synodroid.DS_TAG, "Response is: " + sb.toString()); JSONArray respJSO = null; try { respJSO = new JSONArray(sb.toString()); } catch (JSONException je) { respJSO = new JSONArray(); } return respJSO; } } catch (EOFException e) { if (DEBUG) Log.w(Synodroid.DS_TAG, "Caught EOFException while contacting the server, retying..."); retry++; last_exception = e; } catch (SocketException e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught SocketException while contacting the server, stopping..."); throw e; } catch (SSLHandshakeException e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught SSLHandshakeException while contacting the server, stopping..."); throw e; } catch (FileNotFoundException e) { String msg = e.getMessage(); if (DEBUG) Log.e(Synodroid.DS_TAG, "Could not find file " + msg + "\nProbably wrong DSM version, stopping..."); throw e; } catch (Exception e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught exception while contacting the server, retying...", e); retry++; last_exception = e; } finally { con.disconnect(); } } if (last_exception != null) throw last_exception; throw new GenericException(); } finally { wr = null; br = null; sb = null; con = null; } } public JSONObject sendJSONRequest(String uriP, String requestP, String methodP, boolean log) throws Exception { return sendJSONRequest(uriP, requestP, methodP, log, 2); } /** * Send a request to the server. * * @param uriP * The part of the URI ie: /webman/doit.cgi * @param requestP * The query in the form 'param1=foo¶m2=yes' * @param methodP * The method to send this request * @return A JSONObject containing the response of the server * @throws DSMException */ public JSONObject sendJSONRequest(String uriP, String requestP, String methodP, boolean log, int MAX_RETRY) throws Exception { HttpURLConnection con = null; OutputStreamWriter wr = null; BufferedReader br = null; StringBuffer sb = null; Exception last_exception = null; try { // For some reason in Gingerbread I often get a response code of -1. // Here I retry for a maximum of MAX_RETRY to send the request and it usually succeed at the second try... int retry = 0; while (retry <= MAX_RETRY) { try { // Create the connection con = createConnection(uriP, requestP, methodP, log); // Add the parameters wr = new OutputStreamWriter(con.getOutputStream()); wr.write(requestP); // Send the request wr.flush(); wr.close(); // Try to retrieve the session cookie String newCookie = con.getHeaderField("set-cookie"); if (newCookie != null) { synchronized (this) { setCookie(newCookie); } if (DEBUG) Log.v(Synodroid.DS_TAG, "Retreived cookies: " + cookies); } // Now read the reponse and build a string with it br = new BufferedReader(new InputStreamReader(con.getInputStream())); sb = new StringBuffer(); String line; while ((line = br.readLine()) != null) { sb.append(line); } br.close(); // Verify is response if not -1, otherwise take reason from the header if (con.getResponseCode() == -1) { retry++; last_exception = null; if (DEBUG) Log.w(Synodroid.DS_TAG, "Response code is -1 (retry: " + retry + ")"); } else { if (DEBUG) Log.d(Synodroid.DS_TAG, "Response is: " + sb.toString()); JSONObject respJSO = null; try { respJSO = new JSONObject(sb.toString()); } catch (JSONException je) { respJSO = new JSONObject(); } return respJSO; } } catch (EOFException e) { if (DEBUG) Log.w(Synodroid.DS_TAG, "Caught EOFException while contacting the server, retying..."); retry++; last_exception = e; } catch (SocketException e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught SocketException while contacting the server, stopping..."); throw e; } catch (SSLHandshakeException e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught SSLHandshakeException while contacting the server, stopping..."); throw e; } catch (FileNotFoundException e) { String msg = e.getMessage(); if (DEBUG) Log.e(Synodroid.DS_TAG, "Could not find file " + msg + "\nProbably wrong DSM version, stopping..."); throw e; } catch (Exception e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught exception while contacting the server, retying...", e); retry++; last_exception = e; } finally { con.disconnect(); } } if (last_exception != null) throw last_exception; throw new GenericException(); } // Finally close everything finally { wr = null; br = null; sb = null; con = null; } } /** * Upload a file which is located on the mobile */ public JSONObject sendMultiPart(String uriP, MultipartBuilder multiPartP) throws Exception { HttpURLConnection conn = null; JSONObject respJSO = null; int retry = 0; int MAX_RETRY = 2; Exception last_exception = null; try { while (retry <= MAX_RETRY) { try { // Create the connection conn = createConnection(uriP, "", "POST", true); conn.setRequestProperty("Connection", "keep-alive"); conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + multiPartP.getBoundary()); // Write the multipart multiPartP.writeData(conn.getOutputStream()); // Now read the reponse and build a string with it BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream())); StringBuffer sb = new StringBuffer(); String line; while ((line = br.readLine()) != null) { sb.append(line); } br.close(); if (conn.getResponseCode() == -1) { retry++; if (DEBUG) Log.w(Synodroid.DS_TAG, "Response code is -1 (retry: " + retry + ")"); } else { if (DEBUG) Log.d(Synodroid.DS_TAG, "Response is: " + sb.toString()); respJSO = new JSONObject(sb.toString()); return respJSO; } } catch (EOFException e) { if (DEBUG) Log.w(Synodroid.DS_TAG, "Caught EOFException while contacting the server, retying..."); retry++; last_exception = e; } catch (SocketException e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught SocketException while contacting the server, stopping..."); throw e; } catch (SSLHandshakeException e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught SSLHandshakeException while contacting the server, stopping..."); throw e; } catch (FileNotFoundException e) { String msg = e.getMessage(); if (DEBUG) Log.e(Synodroid.DS_TAG, "Could not find file " + msg + "\nProbably wrong DSM version, stopping..."); throw e; } catch (Exception e) { if (DEBUG) Log.e(Synodroid.DS_TAG, "Caught exception while contacting the server, retying...", e); retry++; last_exception = e; } finally { conn.disconnect(); } } } finally { conn = null; } if (last_exception != null) throw last_exception; throw new GenericException(); } /** * @return the connected */ public boolean isConnected() { return true; } /* * (non-Javadoc) * * @see java.lang.Object#hashCode() */ @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((url == null) ? 0 : url.hashCode()); return result; } /* * (non-Javadoc) * * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; SimpleSynoServer other = (SimpleSynoServer) obj; if (url == null) { if (other.url != null) return false; } else if (!url.equals(other.url)) return false; return true; } ////NULLIFYING FUNCTIONS ********************************************////////////// public String getUser() { return "user"; } public StringBuffer download(String uri, String path) throws Exception { return new StringBuffer(); } public void setConnected(boolean nil) { } public void setDsmVersion(DSMVersion dsm, boolean nil) { } public String getPassword() { return "password"; } }