eionet.webq.service.CDREnvelopeServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for eionet.webq.service.CDREnvelopeServiceImpl.java

Source

/*
 * 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):
 *        Anton Dmitrijev
 */
package eionet.webq.service;

import eionet.webq.converter.CookiesToStringBidirectionalConverter;
import eionet.webq.dao.orm.KnownHost;
import eionet.webq.dao.orm.UserFile;
import eionet.webq.dto.CdrRequest;
import eionet.webq.dto.XmlSaveResult;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.utils.URIUtils;
import org.apache.log4j.Logger;
import org.apache.xmlrpc.XmlRpcException;
import org.apache.xmlrpc.client.XmlRpcClient;
import org.apache.xmlrpc.client.XmlRpcClientConfig;
import org.apache.xmlrpc.client.XmlRpcClientConfigImpl;
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.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.Cookie;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;

import static java.util.Collections.emptyList;
import org.springframework.web.client.RestOperations;

/**
 */
@Service
public class CDREnvelopeServiceImpl implements CDREnvelopeService {
    /**
     * Logger for this class.
     */
    private static final Logger LOGGER = Logger.getLogger(CDREnvelopeServiceImpl.class);
    /**
     * Save xml files to cdr method name.
     */
    @Value("${cdr.save.xml}")
    String saveXmlFilesMethod;
    /**
     * Convert cookie objects to string and vice versa.
     */
    @Autowired
    CookiesToStringBidirectionalConverter cookiesConverter;
    /**
     * XML-RPC client.
     */
    @Autowired
    private XmlRpcClient xmlRpcClient;
    /**
     * Rest client.
     */
    @Autowired
    @Qualifier("defaultRestTemplate")
    private RestOperations restOperations;
    /**
     * Get envelope xml files remote method name.
     */
    @Value("${cdr.envelope.get.xml.files}")
    private String getEnvelopeXmlFilesMethod;
    /**
     * Conversion service.
     */
    @Autowired
    private ConversionService conversionService;
    /**
     * Known hosts service.
     */
    @Autowired
    private KnownHostsService knownHostsService;

    @Override
    public MultiValueMap<String, XmlFile> getXmlFiles(CdrRequest parameters) {
        try {
            Object xmlFilesMappedBySchema = xmlRpcClient.execute(buildConfig(parameters), getEnvelopeXmlFilesMethod,
                    emptyList());
            return transformGetXmlFilesResponse(xmlFilesMappedBySchema);
        } catch (XmlRpcException e) {
            throw new CDREnvelopeException("Unable to call envelope XML-RPC service", e);
        }
    }

    @Override
    @Transactional
    public XmlSaveResult pushXmlFile(UserFile file) {
        if (!file.isFromCdr()) {
            LOGGER.error("File is not belong to cdr. " + file);
            throw new IllegalArgumentException("Provided file is not belong to CDR!");
        }
        String saveXmlUrl = file.getEnvelope() + '/' + saveXmlFilesMethod;
        HttpEntity<MultiValueMap<String, Object>> requestParameters = prepareXmlSaveRequestParameters(file);

        ResponseEntity<String> entity = restOperations.postForEntity(saveXmlUrl, requestParameters, String.class);

        String responseBody = entity.getBody();
        if (entity.getStatusCode() != HttpStatus.OK) {
            LOGGER.info("Response headers from saveXml=" + entity.getHeaders());
            return XmlSaveResult.valueOfError("Service unavailable.");
        }
        LOGGER.info("Response headers from saveXml=" + entity.getHeaders());
        LOGGER.info("Response from saveXml=" + responseBody);
        return XmlSaveResult.valueOf(responseBody);
    }

    @Override
    public ResponseEntity<byte[]> fetchFileFromCdr(UserFile file, String remoteFileUrl)
            throws FileNotAvailableException, URISyntaxException {

        HttpHeaders authorization = new HttpHeaders();
        // use user provided auth info only when the remote file is in the same host as UserFile.
        if (URIUtils.extractHost(new URI(remoteFileUrl))
                .equals(URIUtils.extractHost(new URI(file.getEnvelope())))) {
            authorization = getAuthorizationHeader(file);
        }
        ResponseEntity<byte[]> download = null;
        try {
            download = restOperations.exchange(new URI(remoteFileUrl), HttpMethod.GET,
                    new HttpEntity<Object>(authorization), byte[].class);
        } catch (RestClientException e) {
            LOGGER.error("Unable to download remote file.", e);
        }
        if (download == null || !download.hasBody()) {
            throw new FileNotAvailableException("Response is not OK or body not attached for " + remoteFileUrl);
        }
        return download;
    }

    @Override
    public String submitRequest(UserFile file, String uri, String body) throws URISyntaxException {
        HttpHeaders authorization = new HttpHeaders();
        // use user provided auth info only when the remote file is in the same host as UserFile.
        LOGGER.info(URIUtils.extractHost(new URI(uri)));
        if (URIUtils.extractHost(new URI(uri)).equals(URIUtils.extractHost(new URI(file.getEnvelope())))) {
            authorization = getAuthorizationHeader(file);
        }
        HttpEntity<String> httpEntity = new HttpEntity<String>(body, authorization);
        return restOperations.postForObject(new URI(uri), httpEntity, String.class);
    }

    /**
     * Prepares parameters for saveXml remote method.
     *
     * @param file file to be saved.
     * @return http entity representing request
     */
    HttpEntity<MultiValueMap<String, Object>> prepareXmlSaveRequestParameters(UserFile file) {

        HttpHeaders authorization = getAuthorizationHeader(file);

        HttpHeaders fileHeaders = new HttpHeaders();
        fileHeaders.setContentDispositionFormData("file", file.getName());
        fileHeaders.setContentType(MediaType.TEXT_XML);

        MultiValueMap<String, Object> request = new LinkedMultiValueMap<String, Object>();
        byte[] content = file.getContent();
        if (StringUtils.isNotEmpty(file.getConversionId())) {
            content = conversionService.convert(file, file.getConversionId()).getBody();
        }
        request.add("file", new HttpEntity<byte[]>(content, fileHeaders));
        request.add("file_id", new HttpEntity<String>(file.getName()));
        request.add("title", new HttpEntity<String>(StringUtils.defaultString(file.getTitle())));
        if (file.isApplyRestriction()) {
            request.add("applyRestriction", new HttpEntity<String>("1"));
            request.add("restricted", new HttpEntity<String>(file.isRestricted() ? "1" : "0"));
        }

        return new HttpEntity<MultiValueMap<String, Object>>(request, authorization);
    }

    @Override
    public HttpHeaders getAuthorizationHeader(UserFile file) {
        HttpHeaders authorization = new HttpHeaders();
        if (file.isAuthorized()) {
            String authorizationInfo = file.getAuthorization();
            if (StringUtils.isNotEmpty(authorizationInfo)) {
                authorization.add("Authorization", authorizationInfo);
                LOGGER.info("Use basic auth for file: " + file.getId());
            }
            String cookiesInfo = file.getCookies();
            if (StringUtils.isNotEmpty(cookiesInfo)) {
                Cookie[] cookies = cookiesConverter.convertStringToCookies(cookiesInfo);
                for (Cookie cookie : cookies) {
                    authorization.add("Cookie", cookie.getName() + "=" + cookie.getValue());
                    LOGGER.info("User cookie auth for file: " + file.getId());
                }
            }
        }
        return authorization;
    }

    /**
     * Transform raw envelope service response to usable form.
     *
     * @param response service response
     * @return {@link XmlFile} grouped by xml schema.
     */
    @SuppressWarnings("unchecked")
    private MultiValueMap<String, XmlFile> transformGetXmlFilesResponse(Object response) {
        LinkedMultiValueMap<String, XmlFile> result = new LinkedMultiValueMap<String, XmlFile>();
        if (response != null) {
            try {
                for (Map.Entry<String, Object[]> entry : ((Map<String, Object[]>) response).entrySet()) {
                    String xmlSchema = entry.getKey();
                    for (Object values : entry.getValue()) {
                        Object[] xmlFileData = (Object[]) values;
                        result.add(xmlSchema, new XmlFile(xmlFileData[0].toString(), xmlFileData[1].toString()));
                    }
                }
            } catch (ClassCastException e) {
                LOGGER.error("received response=" + response);
                throw new CDREnvelopeException("unexpected response format from CDR envelope service.", e);
            }
        } else {
            LOGGER.warn("expected not null response from envelope service");
        }
        LOGGER.info("Xml files received=" + result);
        return result;
    }

    /**
     * Builds XmlRpcClientConfig from {@link eionet.webq.dto.CdrRequest}.
     *
     * @param parameters parameters
     * @return config
     */
    private XmlRpcClientConfig buildConfig(CdrRequest parameters) {
        XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl();
        config.setServerURL(createUrlFromString(parameters.getEnvelopeUrl()));
        if (parameters.isAuthorizationSet()) {
            if (StringUtils.isNotEmpty(parameters.getUserName())) {
                config.setBasicUserName(parameters.getUserName());
                config.setBasicPassword(parameters.getPassword());
            } else {
                KnownHost knownHost = knownHostsService.getKnownHost(parameters.getEnvelopeUrl());
                if (knownHost != null) {
                    config.setBasicUserName(knownHost.getKey());
                    config.setBasicPassword(knownHost.getTicket());
                }
            }
        }
        return config;
    }

    /**
     * Creates {@link URL} instance wrapping {@link java.net.MalformedURLException}.
     *
     * @param url string
     * @return url object
     */
    private URL createUrlFromString(String url) {
        try {
            return new URL(url);
        } catch (MalformedURLException e) {
            throw new CDREnvelopeException("Envelope URL is malformed", e);
        }
    }
}