Java tutorial
/******************************************************************************* * Educational Online Test Delivery System * Copyright (c) 2014 American Institutes for Research * * Distributed under the AIR Open Source License, Version 1.0 * See accompanying file AIR-License-1_0.txt or at * http://www.smarterapp.org/documents/American_Institutes_for_Research_Open_Source_Software_License.pdf ******************************************************************************/ package org.opentestsystem.shared.test.interactioncontext; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; import java.net.CookieManager; import java.net.CookiePolicy; import java.net.HttpCookie; import java.net.HttpURLConnection; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.opentestsystem.shared.test.api.InteractiveUser; import org.opentestsystem.shared.test.api.WebApplication; import org.opentestsystem.shared.test.pagedriver.FastPageDriver; import org.opentestsystem.shared.test.statistics.InteractionTimingRecord; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class FastInteractionContext extends AbstractInteractionContext<FastInteractionResponse> { private static final Logger _logger = LoggerFactory.getLogger(FastInteractionContext.class); private FastPageDriver _currentPage; private URL _baseURL; private URI _baseURI; private Map<String, Object> _contextState = new HashMap<String, Object>(); // Note, we don't want to use the system-wide cookie manager because we want // each context to be independent. private CookieManager _cookies = new CookieManager(null, CookiePolicy.ACCEPT_ALL); public FastInteractionContext() { super(); } public void init(InteractiveUser<FastInteractionResponse> interactiveUser) { super.init(interactiveUser); } @Override public FastInteractionResponse browse(WebApplication webApplication, String path, long timeout) throws Exception { _baseURL = webApplication.getIndexUrl(); _baseURI = _baseURL.toURI(); URL targetURL = null; if (path == null) { targetURL = _baseURL; } else { targetURL = new URL(_baseURL, path); } this.startNewInteraction("BROWSE_INDEX", String.format("Browse the index for web application %s", webApplication.getIndexUrl())); return sendGetRequest(targetURL, timeout); } public FastPageDriver getCurrentPage() { return _currentPage; } void setCurrentPage(FastPageDriver currentPage) { _currentPage = currentPage; } @Override public String getCookie(String key) { final List<HttpCookie> cookieList = _cookies.getCookieStore().get(_baseURI); for (HttpCookie cookie_i : cookieList) { if (cookie_i.getName().equalsIgnoreCase(key)) { return cookie_i.getValue(); } } return null; } @Override public void shutdown() { } @Override public FastInteractionResponse sendGetRequest(URL url, long timeout) throws Exception { return buildResponse("GET", url, null, null, timeout); } @Override public URL getBaseUrl() { return _baseURL; } public FastInteractionResponse buildResponse(String method, URL url, Map<String, List<String>> headers, Reader body, long timeout) throws IOException { URI uri = null; try { uri = url.toURI(); } catch (URISyntaxException e) { synchronized (this) { getActiveTimingRecord().fail(String.format("Invalid URL: %s", url.toString()), e); } } int iTimeout = (int) Math.min(Integer.MAX_VALUE, timeout); FastInteractionResponse response = null; HttpURLConnection connection = null; // This value is only used if an error causes things to fail before the connection is created. long t_start = System.currentTimeMillis(); try { connection = (HttpURLConnection) url.openConnection(); connection.setConnectTimeout(iTimeout); connection.setReadTimeout(iTimeout); // Expect to send ouptut if a body has been supplied connection.setDoOutput(body != null); // Set headers (except cookies) if (headers != null) { for (Entry<String, List<String>> header_i : headers.entrySet()) { connection.setRequestProperty(header_i.getKey(), StringUtils.join(header_i.getValue(), ',')); } } else { headers = new HashMap<String, List<String>>(); } // Set cookies for (Entry<String, List<String>> header_i : _cookies.get(uri, headers).entrySet()) { for (String cookie_j : header_i.getValue()) { connection.addRequestProperty(header_i.getKey(), cookie_j); } } // Log the request, if desired if (_logger.isDebugEnabled()) { StringBuilder msg = new StringBuilder("Posted HTTP request:\r\n\r\n"); msg.append(method).append("\r\n"); msg.append(uri.toString()).append("\r\n"); for (Entry<String, List<String>> header_i : connection.getRequestProperties().entrySet()) { for (String value_j : header_i.getValue()) msg.append(header_i.getKey()).append(": ").append(value_j).append("\r\n"); } msg.append("\r\n"); if (body != null) { String bodyString = IOUtils.toString(body); IOUtils.closeQuietly(body); body = new StringReader(bodyString); msg.append(bodyString); } _logger.debug(msg.toString()); } // Start timing // We update here because we don't really want to count time spent above. t_start = System.currentTimeMillis(); // Send the request connection.connect(); // Send the body if (body != null) { try (OutputStream os = connection.getOutputStream();) { IOUtils.copy(body, os, "UTF-8"); } finally { IOUtils.closeQuietly(body); } } // Record the cookies // SB-547 workaround: multiple set-cookie headers are sent for the same // cookie. Process the last. Map<String, String> cookieMap = new HashMap<>(); for (Entry<String, List<String>> header_i : connection.getHeaderFields().entrySet()) { if (StringUtils.equals(header_i.getKey(), "Set-Cookie")) { for (String value_j : header_i.getValue()) { for (String value_k : StringUtils.split(value_j, ',')) { String[] cookieParts = StringUtils.split(value_k, "=", 2); if (cookieParts.length > 0) { String oldValue = cookieMap.get(cookieParts[0]); if (oldValue == null || oldValue.length() < value_k.length()) { cookieMap.put(cookieParts[0], value_k); } } } } } } List<String> cookieValues = new ArrayList<>(cookieMap.values()); Map<String, List<String>> cookieHeaders = new HashMap<>(); cookieHeaders.put("Set-Cookie", cookieValues); _cookies.put(uri, cookieHeaders); // Retrieve the response InputStream is = connection.getInputStream(); response = new FastInteractionResponse(this, is, connection, timeout, t_start + timeout); IOUtils.closeQuietly(is); connection.disconnect(); // Stop timing long t_end = System.currentTimeMillis(); synchronized (this) { InteractionTimingRecord timingRecord = getActiveTimingRecord(); if (timingRecord != null) { timingRecord.accumulate("REMOTE_TIME", t_end - t_start); timingRecord.accumulate("N_REQ", 1); } } // Log the response, if desired if (_logger.isDebugEnabled()) { StringBuilder msg = new StringBuilder("Response from HTTP request:\r\n\r\n"); msg.append(uri.toString()).append("\r\n\r\n"); for (Entry<String, List<String>> header_i : connection.getHeaderFields().entrySet()) { for (String value_j : header_i.getValue()) { msg.append(header_i.getKey()).append(": ").append(value_j).append("\r\n"); } } msg.append("\r\n"); String bodyString = response.getResponseBodyAsString(); if (bodyString != null) { if (bodyString.length() <= 1024) { msg.append(bodyString); } else { msg.append(String.format("Body length %d. Showing first 1024 characters\r\n\r\n", bodyString.length())); msg.append(bodyString.subSequence(0, 1024)); } } _logger.debug(msg.toString()); } return response; } catch (IOException e) { synchronized (this) { failActiveInteraction(String.format("IO Error trying to fill request to %s", url.toString()), e); InputStream es = null; es = connection.getErrorStream(); response = new FastInteractionResponse(this, es, connection, timeout, t_start + timeout); IOUtils.closeQuietly(es); } } return response; } public Map<String, Object> getContextState() { return _contextState; } }