Java tutorial
/* Licensed to the Sakai Foundation (SF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The SF licenses this file * to you 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.sakaiproject.nakamura.grouper.changelog.util; import java.net.URL; import net.sf.json.JSONException; import net.sf.json.JSONObject; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpState; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.NameValuePair; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.sakaiproject.nakamura.grouper.changelog.exceptions.GroupAlreadyExistsException; import org.sakaiproject.nakamura.grouper.changelog.exceptions.GroupModificationException; public class NakamuraHttpUtils { public static Log log = LogFactory.getLog(NakamuraHttpUtils.class); // This could be anything but I think this is explanatory private static final String HTTP_REFERER = "/system/console/grouper"; private static final String HTTP_USER_AGENT = "Nakamura Grouper Sync"; /** * Construct an {@link HttpClient} which is configured to authenticate to Nakamura. * @return the configured client. */ public static HttpClient getHttpClient(URL url, String username, String password) { HttpClient client = new HttpClient(); HttpState state = client.getState(); state.setCredentials(new AuthScope(url.getHost(), getPort(url)), new UsernamePasswordCredentials(username, password)); client.getParams().setAuthenticationPreemptive(true); client.getParams().setParameter("http.useragent", HTTP_USER_AGENT); client.getParams().setParameter("_charset_", "utf-8"); return client; } /** * If you don't specify a port when creating a {@link URL} {@link URL#getPort()} will return -1. * This function uses the default HTTP/s ports * @return the port for this.url. 80 or 433 if not specified. */ public static int getPort(URL url) { int port = url.getPort(); if (port == -1) { if (url.getProtocol().equals("http")) { port = 80; } else if (url.getProtocol().equals("https")) { port = 443; } } return port; } /** * Prepare an HTTP request to Sakai OAE and parse the response (if JSON). * @param client an {@link HttpClient} to execute the request. * @param method an HTTP method to send * @return a JSONObject of the response if the request returns JSON * @throws GroupModificationException if there was an error updating the group information. */ public static JSONObject http(HttpClient client, HttpMethod method) throws GroupModificationException { method.setRequestHeader("User-Agent", HTTP_USER_AGENT); method.setRequestHeader("Referer", HTTP_REFERER); String errorMessage = null; String responseString = null; JSONObject responseJSON = null; boolean isJSONRequest = !method.getPath().toString().endsWith(".html"); if (log.isDebugEnabled() && method instanceof PostMethod) { log.debug(method.getName() + " " + method.getPath() + " params:"); for (NameValuePair nvp : ((PostMethod) method).getParameters()) { log.debug(nvp.getName() + " = " + nvp.getValue()); } } int responseCode = -1; try { responseCode = client.executeMethod(method); responseString = StringUtils.trimToNull(IOUtils.toString(method.getResponseBodyAsStream())); if (isJSONRequest) { responseJSON = parseJSONResponse(responseString); } if (log.isDebugEnabled()) { log.debug(responseCode + " " + method.getName() + " " + method.getPath()); } if (log.isTraceEnabled()) { log.trace("reponse: " + responseString); } switch (responseCode) { case HttpStatus.SC_OK: // 200 case HttpStatus.SC_CREATED: // 201 break; case HttpStatus.SC_BAD_REQUEST: // 400 case HttpStatus.SC_UNAUTHORIZED: // 401 case HttpStatus.SC_NOT_FOUND: // 404 case HttpStatus.SC_INTERNAL_SERVER_ERROR: // 500 if (isJSONRequest && responseJSON != null) { errorMessage = responseJSON.getString("status.message"); } if (errorMessage == null) { errorMessage = "Empty " + responseCode + " error. Check the logs on the Sakai OAE server."; } break; default: errorMessage = "Unknown HTTP response " + responseCode; break; } } catch (Exception e) { errorMessage = "An exception occurred communicatingSakai OAE. " + e.toString(); } finally { method.releaseConnection(); } if (errorMessage != null) { log.error(errorMessage); errorToException(responseCode, errorMessage); } return responseJSON; } /** * Try to parse the HTTP response as JSON. * @param response the HTTP response body as a String. * @return a JSONObject representing the parsed response. null if not JSON or null. */ protected static JSONObject parseJSONResponse(String response) { JSONObject json = null; if (response != null) { try { json = JSONObject.fromObject(response); } catch (JSONException je) { if (response.startsWith("<html>")) { log.debug("Expected a JSON response, got html"); } else { log.error("Could not parse JSON response. " + response); } } } return json; } /** * Throw a specific exception given a JSON response from a Sakai OAE server. * @param response * @throws GroupModificationException * @throws GroupAlreadyExistsException */ protected static void errorToException(int code, String errorMessage) throws GroupModificationException, GroupAlreadyExistsException { if (errorMessage == null) { return; } // TODO: If this is a constant somewhere include the nakamura jar in the // lib directory and use the constant. if (errorMessage.startsWith("A principal already exists with the requested name")) { throw new GroupAlreadyExistsException(errorMessage); } throw new GroupModificationException(code, errorMessage); } }