Java tutorial
/* * The contents of this file are subject to the Mozilla Public * License Version 1.1 (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.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Web Questionnaires 2 * * The Initial Owner of the Original Code is European Environment * Agency. Portions created by TripleDev are Copyright * (C) European Environment Agency. All Rights Reserved. * * Contributor(s): * TripleDev */ package eionet.webq.web.controller; import eionet.webq.converter.JsonXMLBidirectionalConverter; import eionet.webq.dao.orm.KnownHost; import eionet.webq.dao.orm.UserFile; import eionet.webq.dto.KnownHostAuthenticationMethod; import eionet.webq.service.CDREnvelopeService; import eionet.webq.service.FileNotAvailableException; import eionet.webq.service.KnownHostsService; import eionet.webq.web.controller.util.ProxyDelegationHelper; import eionet.webq.web.controller.util.UserFileHelper; import org.apache.commons.lang3.StringUtils; import org.apache.commons.net.util.Base64; import org.apache.log4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpEntity; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; import org.springframework.stereotype.Controller; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.client.RestTemplate; import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartHttpServletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.util.Map; /** * Base controller for WebQ proxy delegations. * * @author enver */ @Controller @RequestMapping public class WebQProxyDelegation { /** * Logger for this class. */ private static final Logger LOGGER = Logger.getLogger(WebQProxyDelegation.class); /** * Helper web layer service to match request parameters and UserFle object in database. */ @Autowired UserFileHelper userFileHelper; /** * Known host service. */ @Autowired KnownHostsService knownHostsService; /** * Json to XML converter. */ @Autowired JsonXMLBidirectionalConverter jsonXMLConverter; /** * Cdr envelope service. */ @Autowired private CDREnvelopeService envelopeService; @Autowired @Qualifier("restTemplate") private RestTemplate restTemplate; @Value("${cas.service}") String webqUrl; /** * This method delegates GET request to remote host. See: * http://stackoverflow.com/questions/14595245/rest-service-pass-through-via-spring This method also works when a method is not * defined. * * @param uri the actual uri to make the request * @param fileId optional user session file ID * @param request standard HttpServletRequest * @return result request results received from uri * @throws UnsupportedEncodingException unable to convert the remote file to UTF-8 * @throws URISyntaxException wrong uri of remote file * @throws FileNotAvailableException the remote file is not available */ @RequestMapping(value = "/restProxy", method = RequestMethod.GET, produces = "text/html;charset=utf-8") @ResponseBody public String restProxyGet(@RequestParam("uri") String uri, @RequestParam(required = false) Integer fileId, HttpServletRequest request) throws UnsupportedEncodingException, URISyntaxException, FileNotAvailableException { if (fileId != null && fileId > 0) { return restProxyGetWithAuth(uri, fileId, request); } LOGGER.info("/restProxy [GET] uri=" + uri); return restTemplate.getForObject(new URI(uri), String.class); } // end of method restProxyGet /** * This method delegates POST request to remote host. * * @param uri the actual uri to make the request * @param body body request body to forward to remote host * @param fileId optional user session file ID * @param request standard HttpServletRequest * @return result request results received from uri * @throws URISyntaxException wrong uri of remote file * @throws FileNotAvailableException the remote file is not available */ @RequestMapping(value = "/restProxy", method = RequestMethod.POST, produces = "text/html;charset=utf-8") @ResponseBody public String restProxyPost(@RequestParam("uri") String uri, @RequestBody String body, @RequestParam(required = false) Integer fileId, HttpServletRequest request) throws URISyntaxException, FileNotAvailableException { if (fileId != null && fileId > 0) { return restProxyPostWithAuth(uri, body, fileId, request); } LOGGER.info("/restProxy [POST] uri=" + uri); return restTemplate.postForObject(new URI(uri), body, String.class); } // end of method restProxyPost /** * /** * This method delegates GET request to remote host using authorisation stored in UserFile. * * @param uri the actual uri to make the request * @param fileId user session file id * @param request standard HttpServletRequest * @return result request results received from uri * @throws URISyntaxException wrong uri of remote file * @throws FileNotAvailableException the remote file is not available * @throws UnsupportedEncodingException unable to convert the remote file to UTF-8 */ @RequestMapping(value = "/restProxyWithAuth", method = RequestMethod.GET, produces = "text/html;charset=utf-8") @ResponseBody public String restProxyGetWithAuth(@RequestParam("uri") String uri, @RequestParam int fileId, HttpServletRequest request) throws URISyntaxException, FileNotAvailableException, UnsupportedEncodingException { UserFile file = userFileHelper.getUserFile(fileId, request); if (file != null && ProxyDelegationHelper.isCompanyIdParameterValidForBdrEnvelope(uri, file.getEnvelope())) { if (StringUtils.startsWith(uri, file.getEnvelope())) { return new String(envelopeService.fetchFileFromCdr(file, uri).getBody(), "UTF-8"); } else if (file.isAuthorized()) { // check if we have known host in db KnownHost knownHost = knownHostsService.getKnownHost(uri); if (knownHost != null) { if (knownHost.getAuthenticationMethod() == KnownHostAuthenticationMethod.REQUEST_PARAMETER) { // add ticket parameter to request URI if needed LOGGER.info("Add ticket parameter from known hosts to URL: " + uri); uri += (uri.contains("?")) ? "&" : "?"; uri += knownHost.getKey() + "=" + knownHost.getTicket(); } else if (knownHost.getAuthenticationMethod() == KnownHostAuthenticationMethod.BASIC) { // Add basic authorisation if needed HttpHeaders authorization = getHttpHeaderWithBasicAuthentication(knownHost); LOGGER.info("Add basic auth from known hosts to URL: " + uri); String response = (restTemplate.exchange(new URI(uri), HttpMethod.GET, new HttpEntity<Object>(authorization), String.class)).getBody(); return response; } } } } LOGGER.info("/restProxy [GET] uri=" + uri); if (new URI(uri).isAbsolute()) { return restTemplate.getForObject(uri, String.class); } else { // todo fix for local /download/file_id= return restTemplate.getForObject(new URI(uri), String.class); } } /** * This method delegates multipart POST request to remote host using authorisation stored in UserFile. * * @param uri the actual uri to make the request * @param body body request body to forward to remote host * @param fileId user session file id * @param request standard HttpServletRequest * @return result request results received from uri * @throws URISyntaxException wrong uri of remote file * @throws FileNotAvailableException the remote file is not available */ @RequestMapping(value = "/restProxyWithAuth", method = RequestMethod.POST, produces = "text/html;charset=utf-8") @ResponseBody public String restProxyPostWithAuth(@RequestParam("uri") String uri, @RequestBody String body, @RequestParam int fileId, HttpServletRequest request) throws URISyntaxException, FileNotAvailableException { UserFile file = userFileHelper.getUserFile(fileId, request); if (file != null && ProxyDelegationHelper.isCompanyIdParameterValidForBdrEnvelope(uri, file.getEnvelope())) { if (StringUtils.startsWith(uri, file.getEnvelope())) { return envelopeService.submitRequest(file, uri, body); } else if (file.isAuthorized()) { // check if we have known host in db KnownHost knownHost = knownHostsService.getKnownHost(uri); if (knownHost != null) { if (knownHost.getAuthenticationMethod() == KnownHostAuthenticationMethod.REQUEST_PARAMETER) { // add ticket parameter to request URI if needed LOGGER.info("Add ticket parameter from known hosts to URL: " + uri); uri += (uri.contains("?")) ? "&" : "?"; uri += knownHost.getKey() + "=" + knownHost.getTicket(); } else if (knownHost.getAuthenticationMethod() == KnownHostAuthenticationMethod.BASIC) { // Add basic authorisation if needed HttpHeaders authorization = getHttpHeaderWithBasicAuthentication(knownHost); LOGGER.info("Add basic auth from known hosts to URL: " + uri); HttpEntity<String> httpEntity = new HttpEntity<String>(body, authorization); return new RestTemplate().postForObject(new URI(uri), httpEntity, String.class); } } } } LOGGER.info("/restProxy [POST] uri=" + uri); return restTemplate.postForObject(new URI(uri), body, String.class); } /** * The method proxies multipart POST requests. If the request target is CDR envelope, then USerFile authorization info is used. * * @param uri the address to forward the request * @param fileId UserFile id stored in session * @param multipartRequest file part in multipart request * @return response from remote host * @throws URISyntaxException provide URI is incorrect * @throws IOException could not read file from request */ @RequestMapping(value = "/restProxyFileUpload", method = RequestMethod.POST, produces = "text/html;charset=utf-8") @ResponseBody public String restProxyFileUpload(@RequestParam("uri") String uri, @RequestParam int fileId, MultipartHttpServletRequest multipartRequest) throws URISyntaxException, IOException { UserFile file = userFileHelper.getUserFile(fileId, multipartRequest); if (!multipartRequest.getFileNames().hasNext()) { throw new IllegalArgumentException("File not found in multipart request."); } Map<String, String[]> parameters = multipartRequest.getParameterMap(); // limit request to one file String fileName = multipartRequest.getFileNames().next(); MultipartFile multipartFile = multipartRequest.getFile(fileName); HttpHeaders authorization = new HttpHeaders(); if (file != null && StringUtils.startsWith(uri, file.getEnvelope())) { authorization = envelopeService.getAuthorizationHeader(file); } HttpHeaders fileHeaders = new HttpHeaders(); fileHeaders.setContentDispositionFormData("file", multipartFile.getOriginalFilename()); fileHeaders.setContentType(MediaType.valueOf(multipartFile.getContentType())); MultiValueMap<String, Object> request = new LinkedMultiValueMap<String, Object>(); byte[] content = multipartFile.getBytes(); request.add("file", new HttpEntity<byte[]>(content, fileHeaders)); for (Map.Entry<String, String[]> parameter : parameters.entrySet()) { if (!parameter.getKey().equals("uri") && !parameter.getKey().equals("fileId") && !parameter.getKey().equals("sessionid") && !parameter.getKey().equals("restricted")) { request.add(parameter.getKey(), new HttpEntity<String>(StringUtils.defaultString(parameter.getValue()[0]))); } } HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<MultiValueMap<String, Object>>( request, authorization); LOGGER.info("/restProxyFileUpload [POST] uri=" + uri); return restTemplate.postForObject(uri, requestEntity, String.class); } /** * Fetches XML file from given xmlUri and applies XSLT conversion with xsltUri. * The resulting xml is converted to json, if format parameter equals 'json'. * Applies authorisation information to fetch XML request, if it is available through UserFile. * * @param xmlUri remote xml file URI * @param fileId WebQ session file ID to be used for applying authorisation info * @param xsltUri remote xslt file URI * @param format optional response format. Only json is supported, default is xml * @param request standard HttpServletRequest * @param response standard HttpServletResponse * @return converted XML content * @throws UnsupportedEncodingException Cannot convert xml to UTF-8 * @throws URISyntaxException xmlUri or xsltUri is incorrect * @throws FileNotAvailableException xml or xslt file is not available * @throws TransformerException error when applying xslt transformation on xml */ @RequestMapping(value = "/proxyXmlWithConversion", method = RequestMethod.GET, produces = "text/html;charset=utf-8") @ResponseBody public byte[] proxyXmlWithConversion(@RequestParam("xmlUri") String xmlUri, @RequestParam(required = false) Integer fileId, @RequestParam("xsltUri") String xsltUri, @RequestParam(required = false) String format, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException, URISyntaxException, FileNotAvailableException, TransformerException { byte[] xml = null; UserFile file = userFileHelper.getUserFile(fileId, request); if (file != null && ProxyDelegationHelper.isCompanyIdParameterValidForBdrEnvelope(request.getRequestURI(), file.getEnvelope())) { xml = restProxyGetWithAuth(xmlUri, fileId, request).getBytes("UTF-8"); } else { xml = new RestTemplate().getForObject(new URI(xmlUri), byte[].class); } byte[] xslt = new RestTemplate().getForObject(new URI(xsltUri), byte[].class); Source xslSource = new StreamSource(new ByteArrayInputStream(xslt)); ByteArrayOutputStream xmlResultOutputStream = new ByteArrayOutputStream(); try { Transformer transformer = TransformerFactory.newInstance().newTransformer(xslSource); for (Map.Entry<String, String[]> parameter : request.getParameterMap().entrySet()) { if (!parameter.getKey().equals("xmlUri") && !parameter.getKey().equals("fileId") && !parameter.getKey().equals("xsltUri") && !parameter.getKey().equals("format")) { transformer.setParameter(parameter.getKey(), StringUtils.defaultString(parameter.getValue()[0])); } } transformer.transform(new StreamSource(new ByteArrayInputStream(xml)), new StreamResult(xmlResultOutputStream)); } catch (TransformerException e1) { LOGGER.error("Unable to transform xml uri=" + xmlUri + " with stylesheet=" + xsltUri); e1.printStackTrace(); throw e1; } byte[] result; if (StringUtils.isNotEmpty(format) && format.equals("json")) { result = jsonXMLConverter.convertXmlToJson(xmlResultOutputStream.toByteArray()); response.setContentType(String.valueOf(MediaType.APPLICATION_JSON)); } else { result = xmlResultOutputStream.toByteArray(); response.setContentType(String.valueOf(MediaType.APPLICATION_XML)); } LOGGER.info("Converted xml uri=" + xmlUri + " with stylesheet=" + xsltUri); response.setCharacterEncoding("utf-8"); return result; } // end of method proxyXmlWithConversion /** * Create HttpHeader with basic authentication info. * * @param knownHost KnownHost object * @return HttpHeader with authorization attribute */ private HttpHeaders getHttpHeaderWithBasicAuthentication(KnownHost knownHost) { HttpHeaders authorization = new HttpHeaders(); try { authorization .add("Authorization", "Basic " + Base64 .encodeBase64String( (knownHost.getKey() + ":" + knownHost.getTicket()).getBytes("utf-8")) .trim()); } catch (UnsupportedEncodingException e) { LOGGER.warn("UnsupportedEncodingException: utf-8"); } return authorization; } } // end of class WebQProxyDelegation