org.easyrec.servlet.PluginStarter.java Source code

Java tutorial

Introduction

Here is the source code for org.easyrec.servlet.PluginStarter.java

Source

/*
 * Copyright 2010 Research Studios Austria Forschungsgesellschaft mBH
 *
 * This file is part of easyrec.
 *
 * easyrec is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * easyrec is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with easyrec.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.easyrec.servlet;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.easyrec.model.core.web.ErrorMessage;
import org.easyrec.model.core.web.Message;
import org.easyrec.model.core.web.RemoteTenant;
import org.easyrec.model.core.web.SuccessMessage;
import org.easyrec.model.plugin.LogEntry;
import org.easyrec.model.plugin.NamedConfiguration;
import org.easyrec.model.plugin.archive.ArchivePseudoConfiguration;
import org.easyrec.model.plugin.archive.ArchivePseudoGenerator;
import org.easyrec.model.plugin.archive.ArchivePseudoStatistics;
import org.easyrec.model.web.*;
import org.easyrec.plugin.configuration.GeneratorContainer;
import org.easyrec.plugin.container.PluginRegistry;
import org.easyrec.plugin.model.PluginId;
import org.easyrec.plugin.stats.GeneratorStatistics;
import org.easyrec.plugin.stats.StatisticsConstants;
import org.easyrec.service.core.TenantService;
import org.easyrec.service.web.RemoteTenantService;
import org.easyrec.service.web.nodomain.ShopRecommenderService;
import org.easyrec.store.dao.web.RemoteTenantDAO;
import org.easyrec.util.core.Security;
import org.easyrec.vocabulary.MSG;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import java.io.IOException;
import java.io.OutputStream;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Properties;
import java.util.Set;
import org.easyrec.model.plugin.sessiontousermapping.SessionToUserMappingConfiguration;
import org.easyrec.model.plugin.sessiontousermapping.SessionToUserMappingGenerator;
import org.easyrec.store.dao.plugin.LogEntryDAO;

/**
 * Servlet implementation class for Servlet: PluginStarter
 */
public class PluginStarter extends javax.servlet.http.HttpServlet implements javax.servlet.Servlet {

    @SuppressWarnings({ "UnusedDeclaration" })
    private static final long serialVersionUID = 5919514564735863894L;
    private TenantService tenantService;
    private RemoteTenantDAO remoteTenantDAO;
    private RemoteTenantService remoteTenantService;
    private ShopRecommenderService shopRecommenderService;
    private EasyRecSettings easyrecSettings;
    private PluginRegistry pluginRegistry;
    private GeneratorContainer generatorContainer;
    private LogEntryDAO logEntryDAO;
    private boolean initialized = false;
    // logging
    private final Log logger = LogFactory.getLog(this.getClass());

    /* (non-Java-doc)
     * @see javax.servlet.http.HttpServlet#HttpServlet()
     */
    public PluginStarter() {
        super();
    }

    private void initialize() {
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(getServletContext());

        this.tenantService = context.getBean("tenantService", TenantService.class);
        this.remoteTenantDAO = context.getBean("remoteTenantDAO", RemoteTenantDAO.class);
        this.remoteTenantService = context.getBean("remoteTenantService", RemoteTenantService.class);
        this.shopRecommenderService = context.getBean("shopRecommenderService", ShopRecommenderService.class);
        this.easyrecSettings = context.getBean("easyrecSettings", EasyRecSettings.class);
        this.pluginRegistry = context.getBean("pluginRegistry", PluginRegistry.class);
        this.generatorContainer = context.getBean("generatorContainer", GeneratorContainer.class);
        this.logEntryDAO = context.getBean("logEntryDAO", LogEntryDAO.class);

        initialized = true;
    }

    @SuppressWarnings({ "UnusedDeclaration" })
    @XmlRootElement(name = "generators")
    private static class GeneratorsResponse {
        @XmlElement(name = "generator")
        private List<GeneratorResponse> generatorResponses;

        private GeneratorsResponse() {
        }

        public GeneratorsResponse(List<GeneratorResponse> generatorResponses) {
            this.generatorResponses = generatorResponses;
        }

        public List<GeneratorResponse> getGeneratorResponses() {
            return generatorResponses;
        }
    }

    @SuppressWarnings({ "UnusedDeclaration" })
    @XmlRootElement(name = "generator")
    private static class GeneratorResponse {
        @XmlElement(name = "success", required = false)
        private SuccessMessage successMessage;
        @XmlElement(name = "error", required = false)
        private ErrorMessage errorMessage;
        @XmlElement(name = "action")
        private String action;
        @XmlAttribute(name = "id")
        @XmlJavaTypeAdapter(PluginId.URIAdapter.class)
        private PluginId pluginId;

        private GeneratorResponse() {
        }

        public GeneratorResponse(Message message, String action, PluginId pluginId) {
            if (message.getClass().equals(ErrorMessage.class))
                errorMessage = (ErrorMessage) message;
            else
                successMessage = (SuccessMessage) message;
            this.action = action;
            this.pluginId = pluginId;
        }

        public Message getMessage() {
            return errorMessage != null ? errorMessage : successMessage;
        }

        public String getAction() {
            return action;
        }

        public PluginId getPluginId() {
            return pluginId;
        }
    }

    private void marshalResponseXml(GeneratorsResponse generatorsResponse, OutputStream output) {
        try {
            Set<Class<?>> classes = Sets.newHashSet(GeneratorsResponse.class, GeneratorResponse.class,
                    ErrorMessage.class, SuccessMessage.class);

            for (GeneratorResponse generatorResponse : generatorsResponse.getGeneratorResponses()) {
                Object content = generatorResponse.getMessage().getContent();

                // TODO workaround classes that are not @XmlRootElement annotated
                if (content != null)
                    classes.add(content.getClass());
            }

            Class[] classesArray = classes.toArray(new Class[classes.size()]);

            JAXBContext jaxbContext = JAXBContext.newInstance(classesArray);
            Marshaller marshaller = jaxbContext.createMarshaller();

            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            marshaller.marshal(generatorsResponse, output);
        } catch (JAXBException e) {
            logger.error("failed to marshal response!", e);
        }
    }

    private void marshalResponseXml(GeneratorResponse generatorResponse, OutputStream output) {
        try {
            Set<Class<?>> classes = Sets.newHashSet(GeneratorsResponse.class, GeneratorResponse.class,
                    ErrorMessage.class, SuccessMessage.class);

            Object content = generatorResponse.getMessage().getContent();

            // TODO workaround classes that are not @XmlRootElement annotated
            if (content != null)
                classes.add(content.getClass());

            Class[] classesArray = classes.toArray(new Class[classes.size()]);

            JAXBContext jaxbContext = JAXBContext.newInstance(classesArray);
            Marshaller marshaller = jaxbContext.createMarshaller();

            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            marshaller.marshal(generatorResponse, output);
        } catch (JAXBException e) {
            logger.error("failed to marshal response!", e);
        }
    }

    /* (non-Java-doc)
     * @see javax.servlet.http.HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/xml; charset=utf-8");

        if (!initialized) {
            initialize();
        }

        if (!easyrecSettings.isGenerator()) {
            marshalResponseXml(
                    new GeneratorResponse(
                            MSG.GENERATOR_ALREADY_EXECUTING
                                    .replace("Cannot start the generator! easyrec is running in frontend mode!"),
                            "startPlugin",
                            new PluginId("http://www.easyrec.org/internal/starter", easyrecSettings.getVersion())),
                    response.getOutputStream());

            return;
        }

        if (!pluginRegistry.isAllExecutablesStopped()) { // already running
            marshalResponseXml(
                    new GeneratorResponse(
                            MSG.GENERATOR_ALREADY_EXECUTING.replace(
                                    "Cannot start the calculation! Another calculation is currently running!"),
                            "startPlugin",
                            new PluginId("http://www.easyrec.org/internal/starter", easyrecSettings.getVersion())),
                    response.getOutputStream());

            return;
        }

        String tenantId = request.getParameter("tenantId");
        String operatorId = request.getParameter("operatorId");
        RemoteTenant remoteTenant = remoteTenantDAO.get(operatorId, tenantId);

        if (remoteTenant == null || !Security.isSignedIn(request)) {
            logger.info("No tenant specified. Start mining for all tenants.");

            marshalResponseXml(
                    new GeneratorResponse(MSG.GENERATOR_ALREADY_EXECUTING.replace("No tenant specified!"),
                            "startPlugin",
                            new PluginId("http://www.easyrec.org/internal/starter", easyrecSettings.getVersion())),
                    response.getOutputStream());

            return;
        }

        logger.info("Starting generator for tenant: " + operatorId + ":" + tenantId);

        final Properties tenantConfig = tenantService.getTenantConfig(remoteTenant.getId());

        if (tenantConfig == null) {
            logger.warn("could not get tenant configuration, aborting");

            marshalResponseXml(new GeneratorResponse(
                    MSG.GENERATOR_ALREADY_EXECUTING.replace("Could not get tenant configuration!"), "startPlugin",
                    new PluginId("http://www.easyrec.org/internal/starter", easyrecSettings.getVersion())),
                    response.getOutputStream());

            return;
        }

        if ("true".equals(tenantConfig.getProperty(RemoteTenant.AUTO_ARCHIVER_ENABLED))) {
            String daysString = tenantConfig.getProperty(RemoteTenant.AUTO_ARCHIVER_TIME_RANGE);
            final int days = Integer.parseInt(daysString);
            ArchivePseudoConfiguration configuration = new ArchivePseudoConfiguration(days);
            configuration.setAssociationType("ARCHIVE");
            NamedConfiguration namedConfiguration = new NamedConfiguration(remoteTenant.getId(), 0,
                    ArchivePseudoGenerator.ID, "Archive", configuration, true);

            logger.info("Archiving actions older than " + days + " day(s)");

            generatorContainer.runGenerator(namedConfiguration,
                    // create a log entry only for archiver runs where actions were actually archived
                    // --> remove log entries where the number of archived actions is 0
                    new Predicate<GeneratorStatistics>() {
                        public boolean apply(GeneratorStatistics input) {
                            ArchivePseudoStatistics archivePseudoStatistics = (ArchivePseudoStatistics) input;

                            return archivePseudoStatistics.getNumberOfArchivedActions() > 0;
                        }
                    }, true, true);
        }

        if ("true".equals(tenantConfig.getProperty(RemoteTenant.SESSION_TO_USER_MAPPING_ENABLED))) {
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date lastRun;
            try {
                lastRun = sdf.parse(remoteTenant.getCreationDate());
            } catch (ParseException ex) {
                logger.error("Error parsing Tenant creationDate! Using fallback.");
                lastRun = new Date(System.currentTimeMillis() - (365 * 86400000l)); //fallback one year
            }
            List<LogEntry> lastRunEntry = logEntryDAO.getLogEntriesForTenant(remoteTenant.getId(),
                    SessionToUserMappingGenerator.ASSOCTYPE, 0, 1);

            if ((lastRunEntry != null) && (!lastRunEntry.isEmpty())) {
                LogEntry le = lastRunEntry.get(0);
                lastRun = le.getStartDate();
            }

            SessionToUserMappingConfiguration configuration = new SessionToUserMappingConfiguration(lastRun);
            configuration.setAssociationType("SESSION_USER_MAPPING");
            NamedConfiguration namedConfiguration = new NamedConfiguration(remoteTenant.getId(),
                    SessionToUserMappingGenerator.ASSOCTYPE, SessionToUserMappingGenerator.ID,
                    "Session-to-User-mapping", configuration, true);

            logger.info("Mapping Sessions to users since lastRun: " + lastRun);

            generatorContainer.runGenerator(namedConfiguration, true);
        } else {
            logger.info("Session-to-User-mapping disabled for tenant: " + remoteTenant.getOperatorId() + ":"
                    + remoteTenant.getStringId());
        }
        List<LogEntry> generatorRuns = generatorContainer.runGeneratorsForTenant(remoteTenant.getId(), true);

        List<GeneratorResponse> responses = Lists.transform(generatorRuns,
                new Function<LogEntry, GeneratorResponse>() {
                    public GeneratorResponse apply(LogEntry input) {
                        Message message = input.getStatistics().getClass().equals(
                                StatisticsConstants.ExecutionFailedStatistics.class) ? MSG.GENERATOR_FINISHED_FAIL
                                        : MSG.GENERATOR_FINISHED_SUCCESS;
                        message = message.content(input.getStatistics());

                        return new GeneratorResponse(message, "startPlugin", input.getPluginId());
                    }
                });

        GeneratorsResponse generatorsResponse = new GeneratorsResponse(responses);

        // TODO send call to shoprecommendersystem to cache most viewed item of all time
        /*
        // send a call to MOST VIEWED ITEM of ALL TIME to be cached
        shopRecommenderService.mostViewedItems(r.getId(), Item.DEFAULT_STRING_ITEM_TYPE, 50, "ALL", null,
                new Session(null, request.getRemoteAddr()));
         */

        remoteTenantService.updateTenantStatistics(remoteTenant.getId());

        marshalResponseXml(generatorsResponse, response.getOutputStream());
    }

    /* (non-Java-doc)
     * @see javax.servlet.http.HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
    }
}