de.mg.stock.server.logic.StockFacade.java Source code

Java tutorial

Introduction

Here is the source code for de.mg.stock.server.logic.StockFacade.java

Source

/*
 * Copyright 2016 Michael Gnatz.
 *
 *  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
 *
 *        http://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 de.mg.stock.server.logic;

import de.mg.stock.dto.AllInOneChartDto;
import de.mg.stock.dto.ChartDataDTO;
import de.mg.stock.dto.StockKeyDataDto;
import de.mg.stock.dto.StocksEnum;
import de.mg.stock.server.Config;
import de.mg.stock.server.dao.StockDAO;
import de.mg.stock.server.model.Stock;
import de.mg.stock.server.util.KeyDataStringBuilder;

import javax.ejb.Stateless;
import javax.ejb.TransactionAttribute;
import javax.inject.Inject;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.logging.Logger;

import static java.time.format.DateTimeFormatter.ofPattern;
import static javax.ejb.TransactionAttributeType.REQUIRED;
import static javax.ws.rs.core.MediaType.APPLICATION_XML;
import static javax.ws.rs.core.MediaType.TEXT_PLAIN;
import static org.apache.commons.lang3.StringUtils.isEmpty;

@Stateless
@TransactionAttribute(REQUIRED)
@Path("/")
public class StockFacade {

    private static Logger logger = Logger.getLogger(StockFacade.class.getName());

    @PersistenceContext
    private EntityManager em;

    @Inject
    private ChartBuilder chartBuilder;

    @Inject
    private StockDAO stockDAO;

    @Inject
    private KeyDataBuilder keyDataBuilder;

    @Inject
    private KeyDataStringBuilder keyDataStringBuilder;

    @Inject
    private Config config;

    @GET
    @Produces(APPLICATION_XML)
    @Path("chartData/{symbol}/{points}")
    public Response getChartData(@PathParam("symbol") String symbol, @PathParam("points") String pointsStr) {

        return getChartDataSince(symbol, "", "", pointsStr);
    }

    @GET
    @Produces(APPLICATION_XML)
    @Path("chartDataSince/{symbol}/{percentages}/{since}/{points}")
    public Response getChartDataSince(@PathParam("symbol") String symbol,
            @PathParam("percentages") String percentagesStr, @PathParam("since") String dateStr,
            @PathParam("points") String pointsStr) {

        Stock stock = stockDAO.findStock(symbol);
        if (stock == null) {
            return Response.status(Response.Status.OK).entity(new ChartDataDTO()).build();
        }
        em.detach(stock);

        ChartDataDTO data = chartBuilder.createOne(stock, Integer.valueOf(pointsStr), toDate(dateStr),
                Boolean.valueOf(percentagesStr));

        data.getItems().stream().filter(item -> !item.isValid())
                .forEach(item -> logger.warning("invalid: " + item));

        return Response.status(Response.Status.OK).entity(data).build();
    }

    @GET
    @Produces(APPLICATION_XML)
    @Path("aggregatedChartData/{date}/{points}")
    public Response getAggregatedChartData(@PathParam("date") String dateStr,
            @PathParam("points") String pointsStr) {

        List<Stock> stocks = new ArrayList<>();
        stocks.add(stockDAO.findStock(StocksEnum.WORLD.getSymbol()));
        stocks.add(stockDAO.findStock(StocksEnum.EMERGING.getSymbol()));
        stocks.add(stockDAO.findStock(StocksEnum.SMALL200.getSymbol()));

        List<Integer> weights = new ArrayList<>();
        weights.add(StocksEnum.WORLD.getWeight());
        weights.add(StocksEnum.EMERGING.getWeight());
        weights.add(StocksEnum.SMALL200.getWeight());

        ChartDataDTO data = chartBuilder.createAggregated(stocks, weights, Integer.valueOf(pointsStr),
                toDate(dateStr));

        return Response.status(Response.Status.OK).entity(data).build();
    }

    private Optional<LocalDate> toDate(String dateStr) {
        LocalDate since = null;
        if (!isEmpty(dateStr)) {
            since = LocalDate.parse(dateStr, ofPattern("ddMMyyyy", Locale.ENGLISH));
        }
        return Optional.ofNullable(since);
    }

    @GET
    @Produces(APPLICATION_XML)
    @Path("allInOneChartData/{date}/{points}")
    public Response getAllInOneChartData(@PathParam("date") String dateStr, @PathParam("points") String pointsStr) {

        List<Stock> all = stockDAO.findAllStocks();
        AllInOneChartDto data = chartBuilder.createAllInOne(all, Integer.valueOf(pointsStr), toDate(dateStr).get());
        return Response.status(Response.Status.OK).entity(data).build();
    }

    @GET
    @Produces(APPLICATION_XML)
    @Path("backup")
    public List<Stock> backup() {
        List<Stock> all = stockDAO.findAllStocks();
        logger.info("backup: " + stockStats(all));
        return all;
    }

    @POST
    @Consumes(APPLICATION_XML)
    @Path("restore")
    public Response restore(List<Stock> stocks) {

        if (!config.isWriteAccessEnabled()) {
            logger.warning("no write access!");

            return Response.status(Response.Status.FORBIDDEN)
                    .entity("server missing -D" + Config.SWITCH_WRITE_ACCESS).build();
        }

        if (stocks == null || stocks.isEmpty()) {
            return Response.status(Response.Status.BAD_REQUEST).entity("missing xml in body").build();
        }
        logger.info("restore: " + stockStats(stocks));

        List<Stock> peristentStocks = backup();
        peristentStocks.forEach(stock -> em.remove(stock));
        em.flush();

        stocks.forEach(s -> {
            s.getDayPrices().forEach(dp -> dp.setStock(s));
            s.getInstantPrices().forEach(ip -> ip.setStock(s));
        });
        stocks.forEach(stock -> em.persist(stock));
        em.flush();

        String msg = String.format("successfully removed %d and inserted %d", peristentStocks.size(),
                stocks.size());
        logger.info(msg);
        return Response.status(Response.Status.OK).build();
    }

    @GET
    @Produces(APPLICATION_XML)
    @Path("statistics")
    public List<StockKeyDataDto> statistics() {
        List<StockKeyDataDto> stockKeyData = keyDataBuilder.create();
        return stockKeyData;
    }

    @GET
    @Produces(TEXT_PLAIN)
    @Path("statisticsCsv")
    public String statisticsCsv() {
        List<StockKeyDataDto> stockKeyData = keyDataBuilder.create();
        return keyDataStringBuilder.asCsv(stockKeyData);
    }

    public static String stockStats(List<Stock> all) {
        String stats = "";
        for (Stock stock : all) {
            stats += stock.toString() + "\n";
        }
        return (stats.length() == 0) ? "empty" : stats;
    }
}