Java tutorial
/** * Copyright 2012 Charles du Jeu * * 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. * * This file is part of the AjaXplorer Java Client * More info on http://ajaxplorer.info/ */ package info.ajaxplorer.client.http; import info.ajaxplorer.client.http.CountingMultipartRequestEntity.ProgressListener; import info.ajaxplorer.client.model.Server; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.URI; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.NameValuePair; import org.apache.http.StatusLine; import org.apache.http.auth.AuthenticationException; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.message.BasicNameValuePair; import org.apache.http.params.HttpConnectionParams; import org.apache.http.util.EncodingUtils; import org.json.JSONObject; import org.w3c.dom.Document; import org.w3c.dom.Node; public class RestRequest { String httpUser; String httpPassword; Boolean serversNeedsCredentials = false; String authStep = ""; Boolean loginStateChanged = false; MessageListener handler; public static String STATUS_REFRESHING_AUTH = "refreshing_auth"; public static String STATUS_LOADING_DATA = "loading_data"; public static String STATUS_PARSING_RESPONSE = "parsing_response"; public static String AUTH_ERROR_NOSERVER = "nocurrent_server"; public static String AUTH_ERROR_LOCKEDOUT = "locked_out"; public static String AUTH_ERROR_LOGIN_FAILED = "login_failed"; public void setHandler(MessageListener handler) { this.handler = handler; } public void clearHandler() { this.handler = null; } public void setTimeout(int timeoutMillis) { HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), timeoutMillis); } public int getTimeout() { return HttpConnectionParams.getConnectionTimeout(httpClient.getParams()); } protected AjxpHttpClient httpClient; protected RestStateHolder.ServerStateListener internalListener; public RestRequest() { RestStateHolder state = RestStateHolder.getInstance(); internalListener = new RestStateHolder.ServerStateListener() { public void onServerChange(Server newServer, Server oldServer) { initWithServer(newServer); if (oldServer != null && AjxpHttpClient.cookieStore != null) { String currentHost = oldServer.getHost(); String currentUser = oldServer.getUser(); if (newServer.getHost().equals(currentHost) && !newServer.getUser().equals(currentUser)) { AjxpHttpClient.cookieStore.clear(); } } } }; state.registerStateListener(internalListener); this.initWithServer(state.getServer()); } public void release() { RestStateHolder.getInstance().unRegisterStateListener(internalListener); } private void initWithServer(Server server) { boolean trustSSL = (server != null && server.shouldTrustSSL()); if (httpClient != null) { httpClient.destroy(); } httpClient = new AjxpHttpClient(trustSSL); if (server != null) { setHttpUser(server.getUser()); setHttpPassword(server.getPassword()); refreshCredentials(); } } private CountingMultipartRequestEntity.ProgressListener uploadListener; public void setUploadProgressListener(CountingMultipartRequestEntity.ProgressListener uploadList) { this.uploadListener = uploadList; } private HttpResponse issueRequest(URI uri) throws Exception { return this.issueRequest(uri, null, null, null, null); } @SuppressWarnings("unused") private HttpResponse issueRequest(URI uri, Map<String, String> postParameters) throws Exception { return this.issueRequest(uri, postParameters, null, null, null); } private HttpResponse issueRequest(URI uri, Map<String, String> postParameters, File file, String fileName, AjxpFileBody fileBody) throws Exception { URI originalUri = new URI(uri.toString()); if (RestStateHolder.getInstance().getSECURE_TOKEN() != null) { uri = new URI( uri.toString().concat("&secure_token=" + RestStateHolder.getInstance().getSECURE_TOKEN())); } //Log.d("RestRequest", "Issuing request : " + uri.toString()); HttpResponse response = null; try { HttpRequestBase request; if (postParameters != null || file != null) { request = new HttpPost(); if (file != null) { if (fileBody == null) { if (fileName == null) fileName = file.getName(); fileBody = new AjxpFileBody(file, fileName); ProgressListener origPL = this.uploadListener; Map<String, String> caps = RestStateHolder.getInstance().getServer() .getRemoteCapacities(this); this.uploadListener = origPL; int maxUpload = 0; if (caps != null && caps.containsKey(Server.capacity_UPLOAD_LIMIT)) maxUpload = new Integer(caps.get(Server.capacity_UPLOAD_LIMIT)); maxUpload = Math.min(maxUpload, 60000000); if (maxUpload > 0 && maxUpload < file.length()) { fileBody.chunkIntoPieces(maxUpload); if (uploadListener != null) { uploadListener.partTransferred(fileBody.getCurrentIndex(), fileBody.getTotalChunks()); } } } else { if (uploadListener != null) { uploadListener.partTransferred(fileBody.getCurrentIndex(), fileBody.getTotalChunks()); } } MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE); reqEntity.addPart("userfile_0", fileBody); if (fileName != null && !EncodingUtils .getAsciiString(EncodingUtils.getBytes(fileName, "US-ASCII")).equals(fileName)) { reqEntity.addPart("urlencoded_filename", new StringBody(java.net.URLEncoder.encode(fileName, "UTF-8"))); } if (fileBody != null && !fileBody.getFilename().equals(fileBody.getRootFilename())) { reqEntity.addPart("appendto_urlencoded_part", new StringBody(java.net.URLEncoder.encode(fileBody.getRootFilename(), "UTF-8"))); } if (postParameters != null) { Iterator<Map.Entry<String, String>> it = postParameters.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); reqEntity.addPart(entry.getKey(), new StringBody(entry.getValue())); } } if (uploadListener != null) { CountingMultipartRequestEntity countingEntity = new CountingMultipartRequestEntity( reqEntity, uploadListener); ((HttpPost) request).setEntity(countingEntity); } else { ((HttpPost) request).setEntity(reqEntity); } } else { List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(postParameters.size()); Iterator<Map.Entry<String, String>> it = postParameters.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } ((HttpPost) request).setEntity(new UrlEncodedFormEntity(nameValuePairs)); } } else { request = new HttpGet(); } request.setURI(uri); if (this.httpUser.length() > 0 && this.httpPassword.length() > 0) { request.addHeader("Ajxp-Force-Login", "true"); } response = httpClient.executeInContext(request); if (isAuthenticationRequested(response)) { sendMessageToHandler(MessageListener.MESSAGE_WHAT_STATE, STATUS_REFRESHING_AUTH); this.discardResponse(response); this.authenticate(); if (loginStateChanged) { // RELOAD loginStateChanged = false; sendMessageToHandler(MessageListener.MESSAGE_WHAT_STATE, STATUS_LOADING_DATA); if (fileBody != null) fileBody.resetChunkIndex(); return this.issueRequest(originalUri, postParameters, file, fileName, fileBody); } } else if (fileBody != null && fileBody.isChunked() && !fileBody.allChunksUploaded()) { this.discardResponse(response); this.issueRequest(originalUri, postParameters, file, fileName, fileBody); } } catch (ClientProtocolException e) { sendMessageToHandler(MessageListener.MESSAGE_WHAT_ERROR, e.getMessage()); e.printStackTrace(); } catch (IOException e) { sendMessageToHandler(MessageListener.MESSAGE_WHAT_ERROR, e.getMessage()); e.printStackTrace(); } catch (AuthenticationException e) { sendMessageToHandler(MessageListener.MESSAGE_WHAT_ERROR, e.getMessage()); throw e; } catch (Exception e) { sendMessageToHandler(MessageListener.MESSAGE_WHAT_ERROR, e.getMessage()); e.printStackTrace(); } finally { uploadListener = null; } return response; } private void authenticate() throws AuthenticationException { loginStateChanged = false; AjxpAPI API = AjxpAPI.getInstance(); try { if (authStep.equals("RENEW-TOKEN")) { JSONObject jObject = this.getJSonContent(API.getGetSecureTokenUri()); RestStateHolder.getInstance().setSECURE_TOKEN(jObject.getString("SECURE_TOKEN")); loginStateChanged = true; } else { String seed = this.getStringContent(API.getGetLoginSeedUri()); if (seed != null) seed = seed.trim(); if (seed.indexOf("captcha") > -1) { throw new AuthenticationException(AUTH_ERROR_LOCKEDOUT); } if (!RestStateHolder.getInstance().isServerSet()) { throw new AuthenticationException(AUTH_ERROR_NOSERVER); } String user = RestStateHolder.getInstance().getServer().getUser(); String password = RestStateHolder.getInstance().getServer().getPassword(); if (!seed.trim().equals("-1")) { password = RestRequest.md5(password) + seed; password = RestRequest.md5(password); } Document doc = this.getDocumentContent(API.makeLoginUri(user, password, seed)); if (doc.getElementsByTagName("logging_result").getLength() > 0) { String result = doc.getElementsByTagName("logging_result").item(0).getAttributes() .getNamedItem("value").getNodeValue(); if (result.equals("1")) { //Log.d("RestRequest Authentication", "LOGGING SUCCEED! REFRESHING TOKEN"); String newToken = doc.getElementsByTagName("logging_result").item(0).getAttributes() .getNamedItem("secure_token").getNodeValue(); RestStateHolder.getInstance().setSECURE_TOKEN(newToken); loginStateChanged = true; } else { //Log.d("RestRequest Authentication", "Login Failed"); throw new AuthenticationException(AUTH_ERROR_LOGIN_FAILED); } } } } catch (AuthenticationException e) { throw e; } catch (Exception e) { throw new AuthenticationException(e.getMessage()); } } private boolean isAuthenticationRequested(HttpResponse response) { Header[] heads = response.getHeaders("Content-type"); boolean xml = false; for (int i = 0; i < heads.length; i++) { if (heads[i].getValue().contains("text/xml")) xml = true; } if (!xml || loginStateChanged) return false; try { HttpEntity ent = response.getEntity(); Document doc; if (ent.getClass() == XMLDocEntity.class) { doc = ((XMLDocEntity) ent).getDoc(); ((XMLDocEntity) ent).toLogger(); } else { XMLDocEntity docEntity = new XMLDocEntity(ent); ent.consumeContent();// Make sure to clear resources doc = docEntity.getDoc(); response.setEntity(docEntity); docEntity.toLogger(); } if (doc.getElementsByTagName("ajxp_registry_part").getLength() > 0 && doc.getDocumentElement().getAttribute("xPath").equals("user/repositories") && doc.getElementsByTagName("repositories").getLength() == 0) { //Log.d("RestRequest Authentication", "EMPTY REGISTRY : AUTH IS REQUIRED"); this.authStep = "LOG-USER"; return true; } if (doc.getElementsByTagName("require_auth").getLength() > 0) { //Log.d("RestRequest Authentication", "REQUIRE_AUTH TAG : AUTH IS REQUIRED"); this.authStep = "LOG-USER"; return true; } if (doc.getElementsByTagName("message").getLength() > 0) { if (doc.getElementsByTagName("message").item(0).getFirstChild().getNodeValue().trim() .contains("You are not allowed to access this resource.")) { //Log.d("RestRequest Authentication", "REQUIRE_AUTH TAG : TOKEN IS REQUIRED"); this.authStep = "RENEW-TOKEN"; return true; } } } catch (Exception e) { sendMessageToHandler(MessageListener.MESSAGE_WHAT_ERROR, e.getMessage()); e.printStackTrace(); } return false; } public String getStringContent(URI uri) throws Exception { return this.getStringContent(uri, null, null, null); } public String getStringContent(URI uri, Map<String, String> parameters) throws Exception { return this.getStringContent(uri, parameters, null, null); } public String getStringContent(URI uri, Map<String, String> parameters, File file, String fileName) throws Exception { BufferedReader in = null; try { HttpResponse response = this.issueRequest(uri, parameters, file, fileName, null); if (response == null) { throw new Exception("Empty Http response"); } in = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); StringBuffer sb = new StringBuffer(""); String line = ""; String NL = System.getProperty("line.separator"); while ((line = in.readLine()) != null) { sb.append(line + NL); } in.close(); String page = sb.toString(); return page; } finally { if (in != null) { try { in.close(); } catch (IOException e) { e.printStackTrace(); } } } } public HttpEntity getNotConsumedResponseEntity(URI uri, Map<String, String> params, File uploadFile) throws Exception { HttpResponse response = this.issueRequest(uri, params, uploadFile, null, null); StatusLine status = response.getStatusLine(); if (status.getStatusCode() != 200) { throw new Exception("Status code :" + status.getStatusCode()); } return response.getEntity(); } public HttpEntity getNotConsumedResponseEntity(URI uri, Map<String, String> params) throws Exception { return this.getNotConsumedResponseEntity(uri, params, null); } public Document getDocumentContent(URI uri) throws Exception { HttpResponse response = this.issueRequest(uri); HttpEntity ent = response.getEntity(); Document doc; sendMessageToHandler(MessageListener.MESSAGE_WHAT_STATE, STATUS_PARSING_RESPONSE); if (ent.getClass() == XMLDocEntity.class) { doc = ((XMLDocEntity) ent).getDoc(); } else { XMLDocEntity docEntity = new XMLDocEntity(ent); ent.consumeContent(); doc = docEntity.getDoc(); response.setEntity(docEntity); } return doc; } public JSONObject getJSonContent(URI uri) throws Exception { return new JSONObject(this.getStringContent(uri)); } /** * @param uri * Target uri that might require http basic auth * @return true or false depending if the target uri requires http basic * auth */ public Boolean credentialsRequired(URI uri) { Boolean credentialsRequired = false; try { int status = getStatusCodeForRequest(uri); if (status == 401) { credentialsRequired = true; serversNeedsCredentials = true; } } catch (Exception e) { e.printStackTrace(); } return credentialsRequired; } public Boolean credentialsRequired() { return serversNeedsCredentials; } public void parseDocumentMessage(Document doc) { try { parseDocumentMessage(doc, false); } catch (Exception e) { } } public void parseDocumentMessage(Document doc, boolean throwOnError) throws Exception { if (doc.getElementsByTagName("message").getLength() > 0) { Node node = doc.getElementsByTagName("message").item(0); String type = node.getAttributes().getNamedItem("type").getNodeValue(); String message = node.getTextContent(); if (type.equalsIgnoreCase("error")) { if (throwOnError) { throw new Exception(message); } sendMessageToHandler(MessageListener.MESSAGE_WHAT_ERROR, message); } else { sendMessageToHandler(MessageListener.MESSAGE_WHAT_STATE, message); } } } public String getHttpUser() { return httpUser; } public void setHttpUser(String httpUser) { this.httpUser = httpUser; //setAuthenticator(); } public String getHttpPassword() { return httpPassword; } public void setHttpPassword(String httpPassword) { this.httpPassword = httpPassword; //setAuthenticator(); } public void refreshCredentials() { this.getHttpClient().refreshCredentials(httpUser, httpPassword); } /* public void setAuthenticator() { if (httpPassword != null && httpUser != null) { Authenticator.setDefault(new Authenticator() { protected PasswordAuthentication getPasswordAuthentication() { return new PasswordAuthentication(httpUser, httpPassword.toCharArray()); } }); } } */ public int getStatusCodeForRequest(URI uri) { HttpResponse response; try { response = issueRequest(uri); if (response != null) { int status = response.getStatusLine().getStatusCode(); // we need to read the whole response-body stream if we want to // avoid problems with the SingleConnexionManager discardResponse(response); return status; } else { return -1; } } catch (Exception e) { e.printStackTrace(); return -1; } } public void discardResponse(HttpResponse response) { try { BufferedReader in = null; in = new BufferedReader(new InputStreamReader(response.getEntity().getContent())); StringBuffer sb = new StringBuffer(""); String line = ""; String NL = System.getProperty("line.separator"); while ((line = in.readLine()) != null) { sb.append(line + NL); } in.close(); } catch (IllegalStateException e) { // Silent, was already consumed } catch (Exception e) { e.printStackTrace(); } } public synchronized AjxpHttpClient getHttpClient() { return httpClient; } public static final String md5(final String s) { try { // Create MD5 Hash MessageDigest digest = java.security.MessageDigest.getInstance("MD5"); digest.update(s.getBytes()); byte messageDigest[] = digest.digest(); // Create Hex String StringBuffer hexString = new StringBuffer(); for (int i = 0; i < messageDigest.length; i++) { String h = Integer.toHexString(0xFF & messageDigest[i]); while (h.length() < 2) h = "0" + h; hexString.append(h); } return hexString.toString(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } return ""; } protected void sendMessageToHandler(int messageType, Object obj) { if (handler == null) return; handler.sendMessage(messageType, obj); } }