de.loercher.localpress.core.api.LocalPressController.java Source code

Java tutorial

Introduction

Here is the source code for de.loercher.localpress.core.api.LocalPressController.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package de.loercher.localpress.core.api;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import de.loercher.localpress.commons.LocalPressProperties;
import de.loercher.localpress.commons.exception.GeneralLocalPressException;
import de.loercher.localpress.commons.exception.UnauthorizedException;
import de.loercher.localpress.geo.AddArticleEntityDTO;
import de.loercher.localpress.geo.LocalPressArticleEntity;
import de.loercher.localpress.transformation.ResponseMapFilterImpl;
import de.loercher.localpress.weighting.WeightingPolicy;
import de.loercher.localpress.weighting.WeightingPolicyImpl;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
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.RestController;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

/**
 *
 * @author Jimmy
 */
@RestController
@RequestMapping("localpress/")
public class LocalPressController {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    private final ObjectMapper objectMapper;

    private final Properties prop;
    private final String RATING_URL;
    private final String GEO_URL;

    @Autowired
    public LocalPressController(LocalPressProperties pProperties, ObjectMapper pMapper) {
        prop = pProperties.getProp();
        RATING_URL = prop.getProperty("ratingURL");
        GEO_URL = prop.getProperty("geoURL");
        objectMapper = pMapper;
    }

    @RequestMapping(value = "/articles", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> addArticleEntry(@RequestBody LocalPressArticleEntity entity,
            @RequestHeader HttpHeaders headers)
            throws UnauthorizedException, GeneralLocalPressException, JsonProcessingException {
        AddArticleEntityDTO geoDTO = new AddArticleEntityDTO(entity.getRelease());

        List<String> userHeader = headers.get("UserID");
        if (userHeader == null || userHeader.isEmpty()) {
            throw new UnauthorizedException("There needs to be set a UserID-Header!", "", "");
        }

        MultiValueMap<String, String> geoHeaders = new LinkedMultiValueMap<>();
        geoHeaders.add("UserID", userHeader.get(0));

        HttpEntity<AddArticleEntityDTO> request = new HttpEntity<>(geoDTO, geoHeaders);

        RestTemplate template = new RestTemplate();
        String ratingURL = RATING_URL + "feedback";
        ResponseEntity<Map> result;
        try {
            result = template.postForEntity(ratingURL, request, Map.class);
        } catch (RestClientException e) {
            GeneralLocalPressException ex = new GeneralLocalPressException(
                    "There happened an error by trying to invoke the geo API!", e);
            log.error(ex.getLoggingString());
            throw ex;
        }

        if (!result.getStatusCode().equals(HttpStatus.CREATED)) {
            GeneralLocalPressException e = new GeneralLocalPressException(result.getStatusCode().getReasonPhrase());
            log.error(e.getLoggingString());
            throw e;
        }

        String articleID = (String) result.getBody().get("articleID");
        if (articleID == null) {
            GeneralLocalPressException e = new GeneralLocalPressException(
                    "No articleID found in response from rating module by trying to add new article!");
            log.error(e.getLoggingString());
            throw e;
        }

        HttpEntity<LocalPressArticleEntity> second = new HttpEntity<>(entity, geoHeaders);

        template.put(GEO_URL + articleID, second);

        String url = (String) result.getBody().get("feedbackURL");

        Map<String, Object> returnMap = new LinkedHashMap<>();
        returnMap.put("articleID", articleID);
        returnMap.put("userID", userHeader.get(0));

        Timestamp now = new Timestamp(new Date().getTime());
        returnMap.put("timestamp", now);
        returnMap.put("status", 201);
        returnMap.put("message", "Created.");

        returnMap.put("feedbackURL", url);

        return new ResponseEntity<>(objectMapper.writeValueAsString(returnMap), HttpStatus.CREATED);
    }

    // TODO needs to be reworked especially considering readability and therefore maintainability
    @RequestMapping(value = "/articles", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> getArticlesAround(@RequestParam Double lat, @RequestParam Double lon)
            throws InterruptedException, ExecutionException, JsonProcessingException {
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(GEO_URL).queryParam("lat", lat.toString())
                .queryParam("lon", lon.toString());

        RestTemplate template = new RestTemplate();
        List<Map<String, Object>> geoResponse = template.getForObject(builder.build().encode().toUri(), List.class);

        Iterator<Map<String, Object>> it = geoResponse.iterator();
        List<Future<ResponseEntity<Map>>> jobs = new ArrayList<>();

        // to be able to merge answers from rating to geoitems there is a need 
        // to map the article to its articleID
        // (articleID) => (articleItem)
        Map<String, Map<String, Object>> mappedResponseObjects = new HashMap<>();
        while (it.hasNext()) {
            Map<String, Object> item = it.next();

            AsyncRestTemplate async = new AsyncRestTemplate();
            Future<ResponseEntity<Map>> futureResult = async.getForEntity((String) item.get("rating"), Map.class);
            jobs.add(futureResult);
            mappedResponseObjects.put((String) item.get("articleID"), item);
        }

        for (Future<ResponseEntity<Map>> job : jobs) {
            Map<String, Object> ratingMap = job.get().getBody();
            String articleID = (String) ratingMap.get("articleID");

            if ((Boolean) ratingMap.get("appropriate")) {
                mappedResponseObjects.get(articleID).putAll(ratingMap);
            } else {
                mappedResponseObjects.remove(articleID);
            }
        }

        WeightingPolicy policy = new WeightingPolicyImpl();
        List<Map<String, Object>> orderedResponse = policy.sortIncludingRating(mappedResponseObjects.values());
        List<Map<String, Object>> result = new ResponseMapFilterImpl().filter(orderedResponse);

        return new ResponseEntity<>(objectMapper.writeValueAsString(result), HttpStatus.OK);
    }

    @RequestMapping(value = "/articles/new", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public ResponseEntity<String> getNewArticlesAround(@RequestParam Double lat, @RequestParam Double lon)
            throws InterruptedException, ExecutionException, JsonProcessingException {
        UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(GEO_URL).queryParam("lat", lat.toString())
                .queryParam("lon", lon.toString());

        RestTemplate template = new RestTemplate();
        List<Map<String, Object>> geoResponse = template.getForObject(builder.build().encode().toUri(), List.class);

        Iterator<Map<String, Object>> it = geoResponse.iterator();
        List<Future<ResponseEntity<Map>>> jobs = new ArrayList<>();

        // to be able to merge answers from rating to geoitems there is a need 
        // to map the article to its articleID
        // (articleID) => (articleItem)
        Map<String, Map<String, Object>> mappedResponseObjects = new HashMap<>();
        while (it.hasNext()) {
            Map<String, Object> item = it.next();

            AsyncRestTemplate async = new AsyncRestTemplate();
            Future<ResponseEntity<Map>> futureResult = async.getForEntity((String) item.get("rating"), Map.class);
            jobs.add(futureResult);
            mappedResponseObjects.put((String) item.get("articleID"), item);
        }

        for (Future<ResponseEntity<Map>> job : jobs) {
            Map<String, Object> ratingMap = job.get().getBody();
            String articleID = (String) ratingMap.get("articleID");

            mappedResponseObjects.get(articleID).putAll(ratingMap);
        }

        WeightingPolicy policy = new WeightingPolicyImpl();
        List<Map<String, Object>> orderedResponse = policy.sortExcludingRating(mappedResponseObjects.values());
        List<Map<String, Object>> result = new ResponseMapFilterImpl().filter(orderedResponse);

        return new ResponseEntity<>(objectMapper.writeValueAsString(result), HttpStatus.OK);
    }

    @RequestMapping(value = "/**/**", method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE)
    public void defaultRequest() {
        throw new IndexOutOfBoundsException("There is no resource on this path.");
    }

}