// Copyright 2012 Georg-August-Universität Göttingen, Germany // // 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 de.ugoe.cs.autoquest.httpmonitor.proxy; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import org.eclipse.jetty.client.HttpClient; import org.eclipse.jetty.client.api.Request; import org.eclipse.jetty.client.api.Response.CompleteListener; import org.eclipse.jetty.client.api.Result; import org.eclipse.jetty.util.thread.QueuedThreadPool; import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorComponent; import de.ugoe.cs.autoquest.httpmonitor.HttpMonitorException; import de.ugoe.cs.util.console.Console; /** *

* This is a base class that combines common implementations required for connecting to a central * HTTP monitoring server. The class allows for sending HTTP requests to the central server and * waiting for the asynchronous response. *

* * @author Patrick Harms */ public abstract class HttpMonitorRemoteConnection implements CompleteListener, HttpMonitorComponent { /** *

* the HTTP client used internally to send data to the central server *

*/ private HttpClient httpClient; /** *

* the host name of the central server *

*/ private String httpMonitorServer; /** *

* the port of the central server *

*/ private int httpMonitorPort; /** *

* a map of requests send to the central server and the corresponding result. * Initially, the result mapped to a request is null until the result is received. *

*/ private Map openRequests = new HashMap<>(); /** *

* initializes the exchange handler with the host and port of the central server *

* * @param httpMonitorServer the host name of the central server * @param httpMonitorPort the port of the central server */ public HttpMonitorRemoteConnection(String httpMonitorServer, int httpMonitorPort) { this.httpMonitorServer = httpMonitorServer; this.httpMonitorPort = httpMonitorPort; } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.httpmonitor.HttpMonitorComponent#init() */ @Override public void init() throws IllegalStateException, HttpMonitorException { httpClient = createHttpClient(); } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.httpmonitor.HttpMonitorComponent#start() */ @Override public void start() throws IllegalStateException, HttpMonitorException { try { httpClient.start(); httpClient.getContentDecoderFactories().clear(); } catch (Exception e) { throw new HttpMonitorException("could not start client for HTTP-Monitor", e); } } /* (non-Javadoc) * @see de.ugoe.cs.autoquest.httpmonitor.HttpMonitorComponent#stop() */ @Override public void stop() { if (httpClient != null) { try { httpClient.stop(); } catch (Exception e) { Console.traceln(Level.WARNING, "could not stop client for HTTP-Monitor"); Console.logException(e); } } httpClient = null; } /** *

* creates a new request that can be used by subclasses to send something to the central server *

* * @return as described */ protected Request newRequest() { return httpClient.newRequest(httpMonitorServer, httpMonitorPort); } /** *

* used to send a request to the central server. The request is stored internally to be able * to wait for the result. *

* * @param httpMonitorRequest the request to be sent to the central server */ protected synchronized void sendRequest(Request httpMonitorRequest) { openRequests.put(httpMonitorRequest, null); httpMonitorRequest.send(this); } /** *

* used to synchronously wait for the result of a given request. *

* * @param httpMonitorRequest the request for which the result shall be waited for * * @return the result of the request or null, if no result was received after 30 seconds */ protected synchronized Result getResult(Request httpMonitorRequest) { try { // wait for the result of the request to be added to the map asynchronously int count = 30; while (openRequests.containsKey(httpMonitorRequest) && (openRequests.get(httpMonitorRequest) == null)) { this.wait(1000); if (--count == 0) { // after 30 seconds, cancel the sending of the request openRequests.remove(httpMonitorRequest); break; } } } catch (InterruptedException e) { // ignore, as this may only happen on system shutdown } return openRequests.get(httpMonitorRequest); } /* (non-Javadoc) * @see org.eclipse.jetty.client.api.Response.CompleteListener#onComplete(Result) */ @Override public synchronized void onComplete(Result result) { openRequests.put(result.getRequest(), result); this.notify(); } /** *

* convenience method to create an initialize the utilized HTTP client *

*/ private HttpClient createHttpClient() { HttpClient client = new HttpClient(); QueuedThreadPool executor = new QueuedThreadPool(10); executor.setName("HttpMonitorClients"); client.setExecutor(executor); client.setMaxConnectionsPerDestination(10000); client.setIdleTimeout(30000); client.setConnectTimeout(30000); client.setStopTimeout(30000); client.setRequestBufferSize(1024*1024); client.setResponseBufferSize(1024*1024); return client; } }