org.easyrec.service.core.impl.ActionServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.easyrec.service.core.impl.ActionServiceImpl.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.service.core.impl;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.easyrec.model.core.ActionVO;
import org.easyrec.model.core.ItemVO;
import org.easyrec.model.core.transfer.TimeConstraintVO;
import org.easyrec.service.core.ActionService;
import org.easyrec.store.dao.core.ActionDAO;
import org.easyrec.utils.io.autoimport.AutoImportService;
import org.easyrec.utils.io.autoimport.AutoImportUtils;

import java.io.*;
import java.util.Iterator;
import java.util.List;

/**
 * Implementation of the {@link org.easyrec.service.core.ActionService} interface.
 * <p/>
 * <p><b>Company:&nbsp;</b>
 * SAT, Research Studios Austria</p>
 * <p/>
 * <p><b>Copyright:&nbsp;</b>
 * (c) 2007</p>
 * <p/>
 * <p><b>last modified:</b><br/>
 * $Author: dmann $<br/>
 * $Date: 2011-12-20 15:22:22 +0100 (Di, 20 Dez 2011) $<br/>
 * $Revision: 18685 $</p>
 *
 * @author Roman Cerny
 */
public class ActionServiceImpl implements ActionService {
    //////////////////////////////////////////////////////////////////////////////
    // constants

    // logging
    private final Log logger = LogFactory.getLog(this.getClass());

    //////////////////////////////////////////////////////////////////////////////
    // members
    private ActionDAO actionDAO;

    // CSV import
    private int reportBlockSize = AutoImportService.DEFAULT__REPORT__BLOCK_SIZE;

    public ActionServiceImpl(ActionDAO actionDAO) {
        this.actionDAO = actionDAO;
    }

    // interface "ActionService" implementation
    public Iterator<ActionVO<Integer, Integer>> getActionIterator(int bulkSize) {
        return actionDAO.getActionIterator(bulkSize);
    }

    public Iterator<ActionVO<Integer, Integer>> getActionIterator(int bulkSize, TimeConstraintVO timeConstraint) {
        return actionDAO.getActionIterator(bulkSize, timeConstraint);
    }

    public List<ActionVO<Integer, Integer>> getActionsFromUser(Integer tenantId, Integer userId, String sessionId) {
        return actionDAO.getActionsFromUser(tenantId, userId, sessionId);
    }

    public int insertAction(ActionVO<Integer, Integer> action) {
        return actionDAO.insertAction(action, false);
    }

    public int insertAction(ActionVO<Integer, Integer> action, boolean useDateFromVO) {
        return actionDAO.insertAction(action, useDateFromVO);
    }

    public int removeActionsByTenant(Integer tenantId) {
        return actionDAO.removeActionsByTenant(tenantId);
    }

    public List<ItemVO<Integer, Integer>> getItemsOfTenant(final Integer tenant, final Integer consideredItemType) {
        return actionDAO.getItemsOfTenant(tenant, consideredItemType);
    }

    public List<ItemVO<Integer, Integer>> getItemsByUserActionAndType(Integer tenantId, Integer userId,
            String sessionId, Integer consideredActionType, Integer consideredItemType, Double ratingThreshold,
            Integer numberOfLastActionsConsidered) {
        return actionDAO.getItemsByUserActionAndType(tenantId, userId, sessionId, consideredActionType,
                consideredItemType, ratingThreshold, numberOfLastActionsConsidered);
    }

    public void importActionsFromCSV(String fileName) {
        importActionsFromCSV(fileName, null);
    }

    public void importActionsFromCSV(String fileName, ActionVO<Integer, Integer> defaults) {
        long start = System.currentTimeMillis();
        if (logger.isInfoEnabled()) {
            logger.info("==================== starting importing 'action' =======================");
            logger.info("importing 'action' from CSV '" + fileName + "'");
            logger.info("using interface defaults '" + defaults + "'");
            logger.info("========================================================================");
        }

        if (fileName == null) {
            throw new IllegalArgumentException("missing 'fileName'");
        }

        BufferedReader br = null;
        int lineCounter = 3;
        int savedCounter = 0;
        int removedCounter = 0;
        int skippedCounter = 0;
        int errorCounter = 0;
        int currentSavedCounter = 0;
        String command = null;

        try {
            try {
                br = new BufferedReader(new InputStreamReader(new FileInputStream(fileName)));
            } catch (FileNotFoundException e) {
                throw new IllegalArgumentException("file '" + fileName + "' not found", e);
            }
            String line = null;
            String elementsOfLine[] = null;

            // read command
            try {
                line = br.readLine();
            } catch (IOException e) {
                throw new IllegalStateException("unexpected IOException", e);
            }
            try {
                // in case of we have an 'old style' file format, containing no 'type' definition, then the first line would contain the command
                command = AutoImportUtils.retrieveCommandFromLine(line);
            } catch (IllegalArgumentException e) {
                // this should be the normal case, the file contains a 'type' definition, so we need to skip this line
                // read/skip type
                try {
                    line = br.readLine();
                } catch (IOException ioe) {
                    throw new IllegalStateException("unexpected IOException", ioe);
                }
                command = AutoImportUtils.retrieveCommandFromLine(line);
            }

            // skip file if the command is not an 'insert' command
            if (!AutoImportUtils.COMMAND_INSERT.equalsIgnoreCase(command)) {
                throw new IllegalStateException("command '" + command + "' is not allowed for the type 'action'");
            }

            // read header and generate headerDefaults
            try {
                line = br.readLine();
            } catch (IOException e) {
                throw new IllegalStateException("unexpected IOException", e);
            }

            ActionVO<Integer, Integer> headerDefaults = generateDefaultsFromHeader(line, defaults);
            if (logger.isInfoEnabled()) {
                logger.info("extracted header defaults from csv file, using: " + headerDefaults);
            }

            // fetch next line
            try {
                while ((line = br.readLine()) != null) {
                    lineCounter++;

                    // skip empty lines
                    if ("".equals(line)) {
                        AutoImportUtils.logSkippedLine(logger, lineCounter, line, "line is empty");
                        skippedCounter++;
                        continue;
                    }

                    // skip comment lines
                    if (line.startsWith(Character.toString(AutoImportUtils.CSV_COMMENT_CHAR))) {
                        AutoImportUtils.logSkippedLine(logger, lineCounter, line, "line is a comment");
                        skippedCounter++;
                        continue;
                    }

                    // skip lines, with wrong number of columns
                    elementsOfLine = line.split(AutoImportUtils.CSV_SEPARATOR, ActionVO.CSV_NUMBER_OF_COLUMNS);
                    if (elementsOfLine.length != ActionVO.CSV_NUMBER_OF_COLUMNS) {
                        StringBuilder s = new StringBuilder("', number of columns should be '");
                        s.append(ActionVO.CSV_NUMBER_OF_COLUMNS);
                        s.append("', but was '");
                        s.append(elementsOfLine.length);
                        s.append("'");
                        AutoImportUtils.logSkippedLine(logger, lineCounter, line, s.toString());
                        skippedCounter++;
                        continue;
                    }

                    ActionVO<Integer, Integer> action = null;
                    try {
                        action = (ActionVO<Integer, Integer>) headerDefaults.clone();
                    } catch (CloneNotSupportedException e) {
                        throw new IllegalStateException(
                                "value object 'ActionVO' does not support .clone() anymore, check that!!");
                    }

                    // parse 'tenantId'
                    if (!"".equals(elementsOfLine[0])) {
                        try {
                            action.setTenant(Integer.parseInt(elementsOfLine[0]));
                        } catch (NumberFormatException nfe) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "value for field 'tenantId' is no valid 'Integer'");
                            skippedCounter++;
                            continue;
                        }
                    } else { // 'tenantId' NOT NULL
                        if (action.getTenant() == null) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "no value for field 'tenantId' is set");
                            skippedCounter++;
                            continue;
                        }
                    }

                    // parse 'userId'
                    if (!"".equals(elementsOfLine[1])) {
                        try {
                            action.setUser(Integer.parseInt(elementsOfLine[1]));
                        } catch (NumberFormatException nfe) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "value for field 'userId' is no valid 'Integer'");
                            skippedCounter++;
                            continue;
                        }
                    }

                    // parse 'sessionId'
                    if (!"".equals(elementsOfLine[2])) {
                        action.setSessionId(elementsOfLine[2]);
                    }

                    // parse 'ip'
                    if (!"".equals(elementsOfLine[3])) {
                        action.setIp(elementsOfLine[3]);
                    }

                    // parse 'itemId'
                    if (!"".equals(elementsOfLine[4])) {
                        try {
                            action.getItem().setItem(Integer.parseInt(elementsOfLine[4]));
                        } catch (NumberFormatException nfe) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "value for field 'itemId' is no valid 'Integer'");
                            skippedCounter++;
                            continue;
                        }
                    }

                    // parse 'itemTypeId'
                    if (!"".equals(elementsOfLine[5])) {
                        try {
                            action.getItem().setType(Integer.parseInt(elementsOfLine[5]));
                        } catch (NumberFormatException nfe) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "value for field 'itemTypeId' is no valid 'Integer'");
                            skippedCounter++;
                            continue;
                        }
                    } else { // 'itemTypeId' NOT NULL
                        if (action.getItem().getType() == null) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "no value for field 'itemTypeId' is set");
                            skippedCounter++;
                            continue;
                        }
                    }

                    // parse 'actionTypeId'
                    if (!"".equals(elementsOfLine[6])) {
                        try {
                            action.setActionType(Integer.parseInt(elementsOfLine[6]));
                        } catch (NumberFormatException nfe) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "value for field 'actionTypeId' is no valid 'Integer'");
                            skippedCounter++;
                            continue;
                        }
                    } else { // 'actionTypeId' NOT NULL
                        if (action.getActionType() == null) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "no value for field 'actionTypeId' is set");
                            skippedCounter++;
                            continue;
                        }
                    }

                    // parse 'ratingValue'
                    if (!"".equals(elementsOfLine[7])) {
                        try {
                            action.setRatingValue(Integer.parseInt(elementsOfLine[7]));
                        } catch (NumberFormatException nfe) {
                            AutoImportUtils.logSkippedLine(logger, lineCounter, line,
                                    "value for field 'ratingValue' is no valid 'Integer'");
                            skippedCounter++;
                            continue;
                        }
                    }

                    // parse 'description'
                    if (!"".equals(elementsOfLine[8])) {
                        action.setActionInfo(elementsOfLine[8]);
                    }

                    try {
                        int savedThisIteration = 0;
                        // inserting action (no update allowed for type 'action')
                        savedThisIteration = insertAction(action);
                        currentSavedCounter += savedThisIteration;
                        savedCounter += savedThisIteration;
                        int currentSavedMultiplier = currentSavedCounter / reportBlockSize;
                        if (currentSavedMultiplier > 0) {
                            if (logger.isInfoEnabled()) {
                                logger.info("number of saved 'action' entries: "
                                        + (currentSavedMultiplier * reportBlockSize));
                            }
                            currentSavedCounter %= reportBlockSize;
                        }
                        /*} catch (DataIntegrityViolationException dive) {
                        // wait a little, we have two identical actions, without an actionDate
                        try {
                        Thread.sleep(1000);
                        } catch (InterruptedException ie) {
                        logger.info("error occured during (delayed try of) insertAction() '" + action + "'", ie);
                        }
                            
                        int savedThisIteration = 0;
                        // inserting action (no update allowed for type 'action')
                        savedThisIteration = insertAction(action);
                        currentSavedCounter += savedThisIteration;
                        savedCounter += savedThisIteration;
                        int currentSavedMultiplier = currentSavedCounter / reportBlockSize;
                        if (currentSavedMultiplier > 0) {
                        if (logger.isInfoEnabled()) {
                            logger.info("number of saved 'action' entries: " + (currentSavedMultiplier * reportBlockSize));
                        }
                        currentSavedCounter %= reportBlockSize;
                        }*/
                    } catch (Exception e) {
                        errorCounter++;
                        logger.error("error occured during insertAction() '" + action + "'", e);
                    }
                } // end of while
            } catch (IOException e) {
                throw new IllegalStateException("unexpected IOException", e);
            }

        } finally {
            // close stream
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    throw new IllegalStateException("unexpected IOException", e);
                }
            }
        }
        if (logger.isInfoEnabled()) {
            if (currentSavedCounter > 0) {
                logger.info("number of saved 'action' entries: " + currentSavedCounter);
            }
            logger.info(
                    "==================== finished importing from file '" + fileName + "' ====================");
            logger.info("total number of saved 'action' entries: " + savedCounter);
            logger.info("total number of removed 'action' entries: " + removedCounter);
            logger.info("total number of skipped 'action' entries: " + skippedCounter);
            logger.info("total number of errors occured while import: " + errorCounter);
            logger.info("used defaults: '" + defaults + "'");
            logger.info("time taken: " + (System.currentTimeMillis() - start) + " ms");
            logger.info("========================================================================");
        }
    }

    //////////////////////////////////////////////////////////////////////////////
    // private methods
    private ActionVO<Integer, Integer> generateDefaultsFromHeader(String header,
            ActionVO<Integer, Integer> defaults) throws IllegalArgumentException {
        String[] elementsOfHeader = header.split(AutoImportUtils.CSV_SEPARATOR, ActionVO.CSV_NUMBER_OF_COLUMNS);

        if (elementsOfHeader.length != ActionVO.CSV_NUMBER_OF_COLUMNS) {
            throw new IllegalArgumentException(
                    "the number of columns in the header of an 'action' .CSV file must be '"
                            + ActionVO.CSV_NUMBER_OF_COLUMNS + "', but was '" + elementsOfHeader.length + "'");
        }

        ActionVO<Integer, Integer> action;
        if (defaults != null) {
            try {
                action = (ActionVO<Integer, Integer>) defaults.clone();
            } catch (CloneNotSupportedException e) {
                throw new IllegalStateException(
                        "value object 'ActionVO' does not support .clone() anymore, check that!!");
            }
        } else {
            action = new ActionVO<>(null, null, null, null, new ItemVO<Integer, Integer>(null, null, null), null,
                    null, null);
        }

        // parse 'tenantId'
        String defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[0]);
        if (defaultValue != null) {
            try {
                action.setTenant(Integer.parseInt(defaultValue));
            } catch (NumberFormatException nfe) {
                logger.warn(
                        "the default value for 'tenantId' in the CSV header is no valid 'Integer', passed type='"
                                + defaultValue + "'; the passed type will be ignored!");
            }
        }

        // parse 'userId'
        defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[1]);
        if (defaultValue != null) {
            try {
                action.setUser(Integer.parseInt(defaultValue));
            } catch (NumberFormatException nfe) {
                logger.warn("the default value for 'userId' in the CSV header is no valid 'Integer', passed type='"
                        + defaultValue + "'; the passed type will be ignored!");
            }
        }

        // parse 'sessionId'
        defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[2]);
        if (defaultValue != null) {
            action.setSessionId(defaultValue);
        }

        // parse 'ip'
        defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[3]);
        if (defaultValue != null) {
            action.setIp(defaultValue);
        }

        // parse 'itemId'
        defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[4]);
        if (defaultValue != null) {
            try {
                action.getItem().setItem(Integer.parseInt(defaultValue));
            } catch (NumberFormatException nfe) {
                logger.warn("the default value for 'itemId' in the CSV header is no valid 'Integer', passed type='"
                        + defaultValue + "'; the passed type will be ignored!");
            }
        }

        // parse 'itemTypeId'
        defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[5]);
        if (defaultValue != null) {
            try {
                action.getItem().setType(Integer.parseInt(defaultValue));
            } catch (NumberFormatException nfe) {
                logger.warn(
                        "the default value for 'itemTypeId' in the CSV header is no valid 'Integer', passed type='"
                                + defaultValue + "'; the passed type will be ignored!");
            }
        }

        // parse 'actionTypeId'
        defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[6]);
        if (defaultValue != null) {
            try {
                action.setActionType(Integer.parseInt(defaultValue));
            } catch (NumberFormatException nfe) {
                logger.warn(
                        "the default value for 'actionTypeId' in the CSV header is no valid 'Integer', passed type='"
                                + defaultValue + "'; the passed type will be ignored!");
            }
        }

        // parse 'ratingValue'
        defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[7]);
        if (defaultValue != null) {
            try {
                action.setRatingValue(Integer.parseInt(defaultValue));
            } catch (NumberFormatException nfe) {
                logger.warn(
                        "the default value for 'ratingValue' in the CSV header is no valid 'Integer', passed type='"
                                + defaultValue + "'; the passed type will be ignored!");
            }
        }

        // parse 'description'
        defaultValue = AutoImportUtils.getDefaultFromHeaderPart(elementsOfHeader[8]);
        if (defaultValue != null) {
            action.setActionInfo(defaultValue);
        }

        return action;
    }
}