extensions/proxy/src/main/java/uk/co/tfd/sm/proxy/ProxyClientServiceImpl.java
public ProxyResponse executeCall(Map<String, Object> config,
			Map<String, Object> headers, Map<String, Object> input,
			InputStream requestInputStream, long requestContentLength,
			String requestContentType) throws ProxyClientException {
		try {
			LOGGER.info(
					"Calling Execute Call with Config:[{}] Headers:[{}] Input:[{}] "
							+ "RequestInputStream:[{}] InputStreamContentLength:[{}] RequestContentType:[{}] ",
					new Object[] { config, headers, input, requestInputStream,
							requestContentLength, requestContentType });
			bindConfig(config);

			if (config != null
					&& config.containsKey(CONFIG_REQUEST_PROXY_ENDPOINT)) {
				// setup the post request
				String endpointURL = (String) config
						.get(CONFIG_REQUEST_PROXY_ENDPOINT);
				if (isUnsafeProxyDefinition(config)) {
					try {
						URL u = new URL(endpointURL);
						String host = u.getHost();
						if (host.indexOf('$') >= 0) {
							throw new ProxyClientException(
									"Invalid Endpoint template, relies on request to resolve valid URL "
											+ u);
						}
					} catch (MalformedURLException e) {
						throw new ProxyClientException(
								"Invalid Endpoint template, relies on request to resolve valid URL",
								e);
					}
				}
				
				LOGGER.info("Valied Endpoint Def");

				Map<String, Object> context = Maps.newHashMap(input);

				// add in the config properties from the bundle overwriting
				// everything else.
				context.put("config", configProperties);

				endpointURL = processUrlTemplate(endpointURL, context);
				
				LOGGER.info("Calling URL {} ",endpointURL);

				ProxyMethod proxyMethod = ProxyMethod.GET;
				if (config.containsKey(CONFIG_REQUEST_PROXY_METHOD)) {
					try {
						proxyMethod = ProxyMethod.valueOf((String) config
								.get(CONFIG_REQUEST_PROXY_METHOD));
					} catch (Exception e) {

					}
				}

				HttpClient client = getHttpClient();

				HttpUriRequest method = null;
				switch (proxyMethod) {
				case GET:
					if (config.containsKey(CONFIG_LIMIT_GET_SIZE)) {
						long maxSize = (Long) config.get(CONFIG_LIMIT_GET_SIZE);
						HttpHead h = new HttpHead(endpointURL);

						HttpParams params = h.getParams();
						// make certain we reject the body of a head
						params.setBooleanParameter(
								"http.protocol.reject-head-body", true);
						h.setParams(params);
						populateMessage(method, config, headers);
						HttpResponse response = client.execute(h);
						if (response.getStatusLine().getStatusCode() == 200) {
							// Check if the content-length is smaller than the
							// maximum (if any).
							Header contentLengthHeader = response
									.getLastHeader("Content-Length");
							if (contentLengthHeader != null) {
								long length = Long
										.parseLong(contentLengthHeader
												.getValue());
								if (length > maxSize) {
									return new ProxyResponseImpl(
											HttpServletResponse.SC_PRECONDITION_FAILED,
											"Response too large", response);
								}
							}
						} else {
							return new ProxyResponseImpl(response);
						}
					}
					method = new HttpGet(endpointURL);
					break;
				case HEAD:
					method = new HttpHead(endpointURL);
					break;
				case OPTIONS:
					method = new HttpOptions(endpointURL);
					break;
				case POST:
					method = new HttpPost(endpointURL);
					break;
				case PUT:
					method = new HttpPut(endpointURL);
					break;
				default:
					method = new HttpGet(endpointURL);
				}

				populateMessage(method, config, headers);

				if (requestInputStream == null
						&& !config.containsKey(CONFIG_PROXY_REQUEST_TEMPLATE)) {
					if (method instanceof HttpPost) {
						HttpPost postMethod = (HttpPost) method;
						MultipartEntity multipart = new MultipartEntity();
						for (Entry<String, Object> param : input.entrySet()) {
							String key = param.getKey();
							Object value = param.getValue();
							if (value instanceof Object[]) {
								for (Object val : (Object[]) value) {
									addPart(multipart, key, val);
								}
							} else {
								addPart(multipart, key, value);
							}
							postMethod.setEntity(multipart);
						}
					}
				} else {

					if (method instanceof HttpEntityEnclosingRequestBase) {
						String contentType = requestContentType;
						if (contentType == null
								&& config
										.containsKey(CONFIG_REQUEST_CONTENT_TYPE)) {
							contentType = (String) config
									.get(CONFIG_REQUEST_CONTENT_TYPE);

						}
						if (contentType == null) {
							contentType = APPLICATION_OCTET_STREAM;
						}
						HttpEntityEnclosingRequestBase eemethod = (HttpEntityEnclosingRequestBase) method;
						if (requestInputStream != null) {
							eemethod.setHeader(HttpHeaders.CONTENT_TYPE,
									contentType);
							eemethod.setEntity(new InputStreamEntity(
									requestInputStream, requestContentLength));
						} else {
							// build the request
							StringWriter body = new StringWriter();
							templateService.evaluate(context, body, (String) config
											.get("path"), (String) config
											.get(CONFIG_PROXY_REQUEST_TEMPLATE));
							byte[] soapBodyContent = body.toString().getBytes(
									"UTF-8");
							eemethod.setHeader(HttpHeaders.CONTENT_TYPE,
									contentType);
							eemethod.setEntity(new InputStreamEntity(
									new ByteArrayInputStream(soapBodyContent),
									soapBodyContent.length));

						}
					}
				}

				HttpResponse response = client.execute(method);
				if (response.getStatusLine().getStatusCode() == 302
						&& method instanceof HttpEntityEnclosingRequestBase) {
					// handle redirects on post and put
					String url = response.getFirstHeader("Location").getValue();
					method = new HttpGet(url);
					response = client.execute(method);
				}

				return new ProxyResponseImpl(response);
			}

		} catch (ProxyClientException e) {
			throw e;
		} catch (Exception e) {
			LOGGER.error(e.getMessage(),e);
			throw new ProxyClientException("The Proxy request specified by  "
					+ config + " failed, cause follows:", e);
		} finally {
			unbindConfig();
		}
		throw new ProxyClientException("The Proxy request specified by "
				+ config + " does not contain a valid endpoint specification ");
	}
public ProxyResponse executeCall(Map<String, Object> config,
			Map<String, Object> headers, Map<String, Object> input,
			InputStream requestInputStream, long requestContentLength,
			String requestContentType) throws ProxyClientException {
		try {
			LOGGER.info(
					"Calling Execute Call with Config:[{}] Headers:[{}] Input:[{}] "
							+ "RequestInputStream:[{}] InputStreamContentLength:[{}] RequestContentType:[{}] ",
					new Object[] { config, headers, input, requestInputStream,
							requestContentLength, requestContentType });
			bindConfig(config);

			if (config != null
					&& config.containsKey(CONFIG_REQUEST_PROXY_ENDPOINT)) {
				// setup the post request
				String endpointURL = (String) config
						.get(CONFIG_REQUEST_PROXY_ENDPOINT);
				if (isUnsafeProxyDefinition(config)) {
					try {
						URL u = new URL(endpointURL);
						String host = u.getHost();
						if (host.indexOf('$') >= 0) {
							throw new ProxyClientException(
									"Invalid Endpoint template, relies on request to resolve valid URL "
											+ u);
						}
					} catch (MalformedURLException e) {
						throw new ProxyClientException(
								"Invalid Endpoint template, relies on request to resolve valid URL",
								e);
					}
				}
				
				LOGGER.info("Valied Endpoint Def");

				Map<String, Object> context = Maps.newHashMap(input);

				// add in the config properties from the bundle overwriting
				// everything else.
				context.put("config", configProperties);

				endpointURL = processUrlTemplate(endpointURL, context);
				
				LOGGER.info("Calling URL {} ",endpointURL);

				ProxyMethod proxyMethod = ProxyMethod.GET;
				if (config.containsKey(CONFIG_REQUEST_PROXY_METHOD)) {
					try {
						proxyMethod = ProxyMethod.valueOf((String) config
								.get(CONFIG_REQUEST_PROXY_METHOD));
					} catch (Exception e) {

					}
				}

				HttpClient client = getHttpClient();

				HttpUriRequest method = null;
				switch (proxyMethod) {
				case GET:
					if (config.containsKey(CONFIG_LIMIT_GET_SIZE)) {
						long maxSize = (Long) config.get(CONFIG_LIMIT_GET_SIZE);
						HttpHead h = new HttpHead(endpointURL);

						HttpParams params = h.getParams();
						// make certain we reject the body of a head
						params.setBooleanParameter(
								"http.protocol.reject-head-body", true);
						h.setParams(params);
						populateMessage(method, config, headers);
						HttpResponse response = client.execute(h);
						if (response.getStatusLine().getStatusCode() == 200) {
							// Check if the content-length is smaller than the
							// maximum (if any).
							Header contentLengthHeader = response
									.getLastHeader("Content-Length");
							if (contentLengthHeader != null) {
								long length = Long
										.parseLong(contentLengthHeader
												.getValue());
								if (length > maxSize) {
									return new ProxyResponseImpl(
											HttpServletResponse.SC_PRECONDITION_FAILED,
											"Response too large", response);
								}
							}
						} else {
							return new ProxyResponseImpl(response);
						}
					}
					method = new HttpGet(endpointURL);
					break;
				case HEAD:
					method = new HttpHead(endpointURL);
					break;
				case OPTIONS:
					method = new HttpOptions(endpointURL);
					break;
				case POST:
					method = new HttpPost(endpointURL);
					break;
				case PUT:
					method = new HttpPut(endpointURL);
					break;
				default:
					method = new HttpGet(endpointURL);
				}

				populateMessage(method, config, headers);

				if (requestInputStream == null
						&& !config.containsKey(CONFIG_PROXY_REQUEST_TEMPLATE)) {
					if (method instanceof HttpPost) {
						HttpPost postMethod = (HttpPost) method;
						MultipartEntity multipart = new MultipartEntity();
						for (Entry<String, Object> param : input.entrySet()) {
							String key = param.getKey();
							Object value = param.getValue();
							if (value instanceof Object[]) {
								for (Object val : (Object[]) value) {
									addPart(multipart, key, val);
								}
							} else {
								addPart(multipart, key, value);
							}
							postMethod.setEntity(multipart);
						}
					}
				} else {

					if (method instanceof HttpEntityEnclosingRequestBase) {
						String contentType = requestContentType;
						if (contentType == null
								&& config
										.containsKey(CONFIG_REQUEST_CONTENT_TYPE)) {
							contentType = (String) config
									.get(CONFIG_REQUEST_CONTENT_TYPE);

						}
						if (contentType == null) {
							contentType = APPLICATION_OCTET_STREAM;
						}
						HttpEntityEnclosingRequestBase eemethod = (HttpEntityEnclosingRequestBase) method;
						if (requestInputStream != null) {
							eemethod.setHeader(HttpHeaders.CONTENT_TYPE,
									contentType);
							eemethod.setEntity(new InputStreamEntity(
									requestInputStream, requestContentLength));
						} else {
							// build the request
							StringWriter body = new StringWriter();
							templateService.evaluate(context, body, (String) config
											.get("path"), (String) config
											.get(CONFIG_PROXY_REQUEST_TEMPLATE));
							byte[] soapBodyContent = body.toString().getBytes(
									"UTF-8");
							eemethod.setHeader(HttpHeaders.CONTENT_TYPE,
									contentType);
							eemethod.setEntity(new InputStreamEntity(
									new ByteArrayInputStream(soapBodyContent),
									soapBodyContent.length));

						}
					}
				}

				HttpResponse response = client.execute(method);
				if (response.getStatusLine().getStatusCode() == 302
						&& method instanceof HttpEntityEnclosingRequestBase) {
					// handle redirects on post and put
					String url = response.getFirstHeader("Location").getValue();
					method = new HttpGet(url);
					response = client.execute(method);
				}

				return new ProxyResponseImpl(response);
			}

		} catch (ProxyClientException e) {
			throw e;
		} catch (Exception e) {
			LOGGER.error(e.getMessage(),e);
			throw new ProxyClientException("The Proxy request specified by  "
					+ config + " failed, cause follows:", e);
		} finally {
			unbindConfig();
		}
		throw new ProxyClientException("The Proxy request specified by "
				+ config + " does not contain a valid endpoint specification ");
	}
Executes a HTTP call using a path in the JCR to point to a template and a
map of properties to populate that template with. An example might be a
SOAP call.

<pre>
{http://www.w3.org/2001/12/soap-envelope}Envelope:{
{http://www.w3.org/2001/12/soap-envelope}Body:{
{http://www.example.org/stock}GetStockPriceResponse:{
&gt;body:[       ]
{http://www.example.org/stock}Price:{
&gt;body:[34.5]
}
}
&gt;body:[  ]
}
&gt;body:[   ]
{http://www.w3.org/2001/12/soap-envelope}encodingStyle:[http://www.w3.org/2001/12/soap-encoding]
}

</pre>

@param resource
the resource containing the proxy end point specification.
@param headers
a map of headers to set int the request.
@param input
a map of parameters for all templates (both url and body)
@param requestInputStream
containing the request body (can be null if the call requires
no body or the template will be used to generate the body)
@param requestContentLength
if the requestImputStream is specified, the length specifies
the lenght of the body.
@param requerstContentType
the content type of the request, if null the node property
sakai:proxy-request-content-type will be used.
@throws ProxyClientException