HttpRequestDispatcher.java
/*
* Copyright (C) 2012-2024 RRiBbit.org
*
* 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
*
* https://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.rribbit.dispatching;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.rribbit.Request;
import org.rribbit.Response;
import org.rribbit.processing.HttpRequestProcessorServlet;
import org.rribbit.util.Base64Util;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* This {@link RequestDispatcher} dispatches a {@link Request} to an {@link HttpRequestProcessorServlet} via HTTP. Failover and loadbalancing are not supported in this class,
* as opposed to the {@link RmiRequestDispatcher}. The reason for this is that failover and loadbalancing are typically done in another layer of the HTTP stack, which
* does not apply to RMI.
* <p />
* This class uses Apache HTTPClient to make the connection to the {@link HttpRequestProcessorServlet}. It uses the default functionality of Apache HTTPClient to do its work.
* If you want to use more advanced functionality of Apache HTTPClient to make the connection, then it should be fairly straightforward to extend this class or implement your
* own {@link RequestDispatcher} implementation with this class as an example.
*
* @author G.J. Schouten
*
*/
public class HttpRequestDispatcher implements RequestDispatcher {
private static final Logger log = LoggerFactory.getLogger(HttpRequestDispatcher.class);
protected String url;
/**
* Whenever you use this constructor, be sure to set the url with the setter provided by this class. If you don't, runtime exceptions will occur.
*/
public HttpRequestDispatcher() {}
/**
* Creates an {@link HttpRequestDispatcher} that will send the {@link Request}s to the specified URL. An {@link HttpRequestProcessorServlet} is expected to be listening
* at this URL. The URL is a standard HTTP URL, such as "http://host:port/path". It can also be an HTTPS URL, beginning with 'https:'.
*
* This constructor is recommended, since it forces you to specify the url. Passing a null value for this will result in runtime exceptions whenever
* the {@link HttpRequestDispatcher} is used.
*
* @param url
*/
public HttpRequestDispatcher(String url) {
this.url = url;
}
@Override
public <T> Response<T> dispatchRequest(Request request) {
log.info("Dispatching HTTP Request");
HttpPost httpPost = null;
try {
log.info("Encoding Request");
String requestString = Base64Util.encodeObject(request);
log.info("Dispatching encoded Request");
try(CloseableHttpClient httpclient = HttpClientBuilder.create().build()) {
httpPost = new HttpPost(url);
httpPost.setEntity(new StringEntity(requestString));
HttpResponse httpResponse = httpclient.execute(httpPost);
HttpEntity entity = httpResponse.getEntity();
try(InputStream inputStream = entity.getContent()) {
log.info("Decoding Response");
Response<T> response = Base64Util.decodeInputStream(inputStream);
log.info("Returning Response");
return response;
}
}
} catch(Exception e) {
log.error("Something went wrong during the Request. Below are some common errors that can occur in the stacktrace: ");
log.error("\tStreamCorruptedException: Indicates that the client does not understand the response from the server. This may mean that the client gets " +
"a 404 page back, which it cannot decode. Please see the client's org.apache.http logs to see the response that the client got from the server. Please " +
"also check the URL that you have given the client.");
log.error("\tEOFException: Indicates that the client does not get a response from the server. Please check the server logs to see what's wrong.");
throw new RuntimeException(e);
} finally {
if(httpPost != null) {
httpPost.releaseConnection();
}
}
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}