ch.sdi.plugins.oxwall.job.OxSqlJob.java Source code

Java tutorial

Introduction

Here is the source code for ch.sdi.plugins.oxwall.job.OxSqlJob.java

Source

/**
 * Copyright (c) 2014 by the original author or authors.
 *
 * This code is free software; you can redistribute it and/or modify it under the terms of the
 * GNU Lesser General Public License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */

package ch.sdi.plugins.oxwall.job;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.ParameterExpression;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.ejb.HibernateEntityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import ch.sdi.core.exc.SdiException;
import ch.sdi.core.impl.cfg.ConfigUtils;
import ch.sdi.core.impl.data.Person;
import ch.sdi.core.impl.data.PersonKey;
import ch.sdi.core.impl.data.converter.ConverterNumberList;
import ch.sdi.core.intf.SdiMainProperties;
import ch.sdi.core.intf.SqlJob;
import ch.sdi.plugins.oxwall.OxTargetConfiguration;
import ch.sdi.plugins.oxwall.OxTargetJobContext;
import ch.sdi.plugins.oxwall.OxUtils;
import ch.sdi.plugins.oxwall.profile.OxProfileQuestion;
import ch.sdi.plugins.oxwall.profile.OxProfileQuestionDate;
import ch.sdi.plugins.oxwall.profile.OxProfileQuestionNumber;
import ch.sdi.plugins.oxwall.profile.OxProfileQuestionString;
import ch.sdi.plugins.oxwall.profile.OxQuestionFactory;
import ch.sdi.plugins.oxwall.profile.OxQuestionType;
import ch.sdi.plugins.oxwall.sql.entity.OxAvatar;
import ch.sdi.plugins.oxwall.sql.entity.OxProfileData;
import ch.sdi.plugins.oxwall.sql.entity.OxUser;
import ch.sdi.plugins.oxwall.sql.entity.OxUserGroupMembership;
import ch.sdi.plugins.oxwall.sql.entity.OxUserRole;
import ch.sdi.report.ReportMsg;
import ch.sdi.report.ReportMsg.ReportType;

/**
 * SQL job implementation for the oxwall platform.
 *
 * @version 1.0 (24.11.2014)
 * @author  Heri
 */
@Component
public class OxSqlJob implements SqlJob {
    /** logger for this class */
    private Logger myLog = LogManager.getLogger(OxSqlJob.class);
    public static final String KEY_PREFIX_PROFILE_QUESTION = "ox.target.qn.";
    public static final String KEY_DEFAULT_GROUPS = "ox.target.defaultGroups";
    public static final String KEY_DEFAULT_ROLES = "ox.target.defaultRoles";
    public static final String KEY_GROUP_PRIVACY = "ox.target.groups.privacy";

    @Autowired
    private Environment myEnv;
    @Autowired
    private OxQuestionFactory myQuestionFactory;

    // does not work: @PersistenceContext(unitName="oxwall")
    protected HibernateEntityManager myEntityManager;
    private boolean myDryRun;
    private boolean myCheckDuplicateOnDryRun;
    private long myDummyId = 1;
    private List<OxProfileQuestion> myProfileQuestions;
    private List<Long> myDefaultGroups;
    private List<Long> myDefaultRoles;
    private String myGroupPrivacy;
    private String myUserAccountType;
    private Integer myJoinIp;
    private boolean myEmailVerify;

    /**
     * Constructor
     *
     */
    public OxSqlJob() {
        super();
    }

    /**
     * @see ch.sdi.core.intf.TargetJob#execute(ch.sdi.core.impl.data.Person)
     */
    @Override
    public void execute(Person<?> aPerson) throws SdiException {
        List<Object> dbEntities = new ArrayList<Object>();

        myLog.debug("creating new user entity");
        OxUser user = new OxUser();
        user.setUsername(aPerson.getStringProperty(PersonKey.THING_ALTERNATENAME.getKeyName()));
        user.setAccountType(myUserAccountType);
        user.setActivityStamp(OxUtils.dateToLong(new Date()));
        user.setEmail(aPerson.getEMail());
        user.setJoinIp(myJoinIp.longValue());
        user.setJoinStamp(OxUtils.dateToLong(new Date()));
        user.setPassword(aPerson.getStringProperty(OxTargetJobContext.KEY_ENCRYPTED_PASSWORD));
        user.setEmailVerify(myEmailVerify);
        saveEntity(dbEntities, user);

        aPerson.setProperty(OxTargetJobContext.KEY_PERSON_USER_ID, user.getId());
        ;

        List<Long> roles = resolveRoles(aPerson);
        if (roles.size() > 0) {
            myLog.debug("creating group membership entities");
            for (Long role : roles) {
                OxUserRole roleEntity = new OxUserRole();
                roleEntity.setUserId(user.getId());
                roleEntity.setRoleId(role);
                saveEntity(dbEntities, roleEntity);
            }
        } // if groups.size() > 0

        myLog.debug("creating profile question entities");
        for (OxProfileQuestion question : myProfileQuestions) {
            if (!question.hasValue(aPerson)) {
                continue;
            } // if !question.hasValue( aPerson )

            OxProfileData profileData = new OxProfileData();
            profileData.setUserId(user.getId());
            question.fillValues(profileData, aPerson);
            saveEntity(dbEntities, profileData);
        }

        Long avatarHash = aPerson.getProperty(OxTargetJobContext.KEY_AVATAR_HASH, Long.class);
        if (avatarHash != null) {
            myLog.debug("creating avatar entities");
            OxAvatar avatar = new OxAvatar();
            avatar.setUserId(user.getId());
            avatar.setHash(avatarHash);
            saveEntity(dbEntities, avatar);
        } // if StringUtils.hasText( avatarHash )

        List<Long> groups = resolveMembership(aPerson);
        if (groups.size() > 0) {
            myLog.debug("creating group membership entities");
            for (Long group : groups) {
                OxUserGroupMembership groupEntity = new OxUserGroupMembership();
                groupEntity.setGroupId(group);
                groupEntity.setUserId(user.getId());
                groupEntity.setTimeStamp(OxUtils.dateToLong(new Date()));
                groupEntity.setPrivacy(myGroupPrivacy);
                saveEntity(dbEntities, groupEntity);
            }
        } // if groups.size() > 0

        ReportMsg msg = new ReportMsg(ReportType.SQL_TARGET, aPerson.getEMail(), dbEntities.toArray());
        myLog.info(msg);
    }

    /**
     * @param aPerson
     * @return
     */
    private List<Long> resolveRoles(Person<?> aPerson) {
        List<Long> result = new ArrayList<Long>(); // TODO: add roles per user, as with group membership
        myLog.debug("collected roles of person: " + result);
        result.addAll(myDefaultRoles);
        myLog.debug("resolved roles of person: " + result);
        return result;
    }

    /**
     * @param aPerson
     * @return
     * @throws SdiException
     */
    private List<Long> resolveMembership(Person<?> aPerson) throws SdiException {
        List<Long> result = aPerson.getLongListProperty(PersonKey.PERSON_MEMBEROF.getKeyName());
        myLog.debug("collected groups of person: " + result);
        result.addAll(myDefaultGroups);
        myLog.debug("resolved groups of person: " + result);
        return result;
    }

    /**
     * @param dbEntities
     * @param aEntity
     * @throws SdiException
     */
    private void saveEntity(List<Object> dbEntities, Object aEntity) throws SdiException {
        if (myDryRun) {
            myLog.trace("DryRun: Going to save entity: " + aEntity);

            try {
                MethodUtils.invokeExactMethod(aEntity, "setId", new Object[] { Long.valueOf(myDummyId) });
            } catch (Throwable t) {
                throw new SdiException("Entity has no 'setId( Long )' method", t,
                        SdiException.EXIT_CODE_UNKNOWN_ERROR);
            }

            myDummyId++;
        } else {
            myLog.trace("Going to save entity: " + aEntity);
            myEntityManager.persist(aEntity);
        } // if..else myDryRun

        dbEntities.add(aEntity);
    }

    /**
     * @see ch.sdi.core.intf.SqlJob#isAlreadyPresent(ch.sdi.core.impl.data.Person)
     */
    @Override
    public boolean isAlreadyPresent(Person<?> aPerson) throws SdiException {
        if (myDryRun && !myCheckDuplicateOnDryRun) {
            myLog.debug("DryRun is active. Not checking for duplicate person");
            return false;
        } // if myDryRun

        CriteriaBuilder cb = myEntityManager.getCriteriaBuilder();

        CriteriaQuery<OxUser> criteria = cb.createQuery(OxUser.class);
        Root<OxUser> root = criteria.from(OxUser.class);
        ParameterExpression<String> mailParam = cb.parameter(String.class);
        criteria.select(root).where(cb.equal(root.get("email"), mailParam));

        TypedQuery<OxUser> queryEMail = myEntityManager.createQuery(criteria);

        queryEMail.setParameter(mailParam, aPerson.getEMail());
        List<OxUser> results = queryEMail.getResultList();

        if (results.size() > 0) {
            myLog.debug("given Person is already present: " + results.get(0));
            return true;
        } // if results.size() > 0

        return false;
    }

    /**
     * Checks if the given hash is present in the ow_base_avatar table
     *
     * @param aHash
     * @return
     */
    public boolean isAvatarHashPresent(Long aHash) {
        if (myDryRun) {
            myLog.debug("DryRun is active. Not checking for duplicate avatar hash");
            return false;
        } // if myDryRun

        CriteriaBuilder cb = myEntityManager.getCriteriaBuilder();

        CriteriaQuery<OxAvatar> criteria = cb.createQuery(OxAvatar.class);
        Root<OxAvatar> root = criteria.from(OxAvatar.class);
        ParameterExpression<Long> avatarParam = cb.parameter(Long.class);
        avatarParam = cb.parameter(Long.class);
        criteria.select(root).where(cb.equal(root.get("hash"), avatarParam));
        TypedQuery<OxAvatar> query = myEntityManager.createQuery(criteria);
        query.setParameter(avatarParam, aHash);
        List<OxAvatar> results = query.getResultList();

        if (results.size() > 0) {
            myLog.debug("given avatar hash is already present: " + aHash);
            return true;
        } // if results.size() > 0

        return false;
    }

    /**
     * @see ch.sdi.core.intf.TargetJob#init()
     */
    @Override
    public void init() throws SdiException {
        myDryRun = ConfigUtils.getBooleanProperty(myEnv, SdiMainProperties.KEY_DRYRUN, false);
        myCheckDuplicateOnDryRun = ConfigUtils.getBooleanProperty(myEnv,
                SdiMainProperties.KEY_CHECK_DUPLICATE_ON_DRYRUN, false);
        myGroupPrivacy = myEnv.getProperty(KEY_GROUP_PRIVACY, "everybody");
        myUserAccountType = myEnv.getProperty(OxTargetConfiguration.KEY_USER_ACCOUNT_TYPE);
        myJoinIp = ConfigUtils.getIntProperty(myEnv, OxTargetConfiguration.KEY_USER_JOINIP, 12345);
        myEmailVerify = ConfigUtils.getBooleanProperty(myEnv, OxTargetConfiguration.KEY_USER_EMAIL_VERIFY);

        myEntityManager = EntityManagerProvider.getEntityManager("oxwall");

        if (myEntityManager == null) {
            throw new SdiException("Problems initializing EntityManager", SdiException.EXIT_CODE_CONFIG_ERROR);
        } // if em == null

        initProfileQuestions();
        initDefaultGroups();
        initDefaultRoles();

    }

    /**
     *
     */
    private void initDefaultRoles() throws SdiException {
        String configured = myEnv.getProperty(KEY_DEFAULT_ROLES, "");
        myDefaultRoles = ConverterNumberList.toLongList(configured, ",");
        myLog.debug("Configured default roles: " + myDefaultRoles);

    }

    /**
     * @throws SdiException
     */
    private void initDefaultGroups() throws SdiException {
        String configured = myEnv.getProperty(KEY_DEFAULT_GROUPS, "");
        myDefaultGroups = ConverterNumberList.toLongList(configured, ",");
        myLog.debug("Configured default groups: " + myDefaultGroups);
    }

    /**
     * Checks the configuration if there are profile questions configured and populates the
     * myProfileQuestions member with the found configurations.
     * <p>
     * @throws SdiException
     */
    private void initProfileQuestions() throws SdiException {
        myProfileQuestions = new ArrayList<OxProfileQuestion>();

        for (String personKey : PersonKey.getKeyNames()) {
            String key = KEY_PREFIX_PROFILE_QUESTION + personKey;
            myLog.trace("Looking up profile question configuration " + key);
            String configured = myEnv.getProperty(key);

            if (!StringUtils.hasText(configured)) {
                continue;
            } // if !StringUtils.hasText( configured )

            myLog.trace("Found profile question configuration " + configured);

            String[] values = configured.trim().split(":");
            if (values.length < 2) {
                throw new SdiException("Profile question not configured correctly: " + configured,
                        SdiException.EXIT_CODE_CONFIG_ERROR);
            }

            OxQuestionType type;
            try {
                type = OxQuestionType.valueOf(values[0]);
            } catch (IllegalArgumentException t) {
                throw new SdiException("Profile question not configured correctly: " + configured + "; "
                        + "type cannot be resolved", SdiException.EXIT_CODE_CONFIG_ERROR);
            }

            OxProfileQuestion question = null;

            switch (type) {
            case text:
                question = new OxProfileQuestionString(values[1], personKey);
                break;
            case number:
                question = new OxProfileQuestionNumber(values[1], personKey);
                break;
            case date:
                question = new OxProfileQuestionDate(values[1], personKey);
                break;
            case custom:
                if (values.length < 3) {
                    throw new SdiException("Profile question not configured correctly: " + values,
                            SdiException.EXIT_CODE_CONFIG_ERROR);
                }

                question = myQuestionFactory.getCustomQuestion(values[1], values[2], personKey);
                break;
            default:
                throw new SdiException("unhandled question type: " + type, SdiException.EXIT_CODE_UNKNOWN_ERROR);
            }

            question.init(myEnv);
            myLog.debug("Adding profile question for key '" + personKey + "': " + question);
            myProfileQuestions.add(question);

        }
    }

    /**
     * @see ch.sdi.core.intf.TargetJob#close()
     */
    @Override
    public void close() throws SdiException {
        if (myEntityManager != null) {
            myEntityManager.close();
        } // if em != null
    }

    /**
     * @see ch.sdi.core.intf.SqlJob#startTransaction()
     */
    @Override
    public void startTransaction() {
        myEntityManager.getTransaction().begin();
    }

    /**
     * @see ch.sdi.core.intf.SqlJob#commitTransaction()
     */
    @Override
    public void commitTransaction() {
        if (myEntityManager != null) {
            if (myEntityManager.getTransaction().isActive()) {
                myEntityManager.getTransaction().commit();
            } // if myEntityManager.getTransaction().isActive()
        } // if em != null
    }

    /**
     * @see ch.sdi.core.intf.SqlJob#rollbackTransaction()
     */
    @Override
    public void rollbackTransaction() {
        if (myEntityManager != null) {
            if (myEntityManager.getTransaction().isActive()) {
                myEntityManager.getTransaction().rollback();
            } // if myEntityManager.getTransaction().isActive()
        } // if em != null
    }

}