org.sofun.platform.legigame.LegigameServiceImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.sofun.platform.legigame.LegigameServiceImpl.java

Source

/*
 * Copyright (c)  Sofun Gaming SAS.
 * Copyright (c)  Julien Anguenot <julien@anguenot.org>
 * Copyright (c)  Julien De Preaumont <juliendepreaumont@gmail.com>
 * 
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Julien Anguenot <julien@anguenot.org> - initial API and implementation
*/

package org.sofun.platform.legigame;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import javax.ejb.EJB;
import javax.ejb.Local;
import javax.ejb.Remote;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.NoResultException;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.sofun.core.CoreConstants;
import org.sofun.core.api.exception.CoreException;
import org.sofun.core.api.member.Member;
import org.sofun.core.api.member.MemberAccountStatus;
import org.sofun.core.api.member.MemberAccountType;
import org.sofun.core.api.member.MemberService;
import org.sofun.core.api.member.ejb.MemberServiceLocal;
import org.sofun.core.member.MemberImpl;
import org.sofun.platform.legigame.api.Configuration;
import org.sofun.platform.legigame.api.LegigameService;
import org.sofun.platform.legigame.api.MemberLegigameStatus;
import org.sofun.platform.legigame.api.ResponseCreateOrUpdate;
import org.sofun.platform.legigame.api.ResponseRead;
import org.sofun.platform.legigame.api.ejb.LegigameServiceLocal;
import org.sofun.platform.legigame.api.ejb.LegigameServiceRemote;
import org.sofun.platform.legigame.api.exception.LegigameException;

/**
 * Legigame service implementation.
 * 
 * @author <a href="mailto:julien@anguenot.org">Julien Anguenot</a>
 * 
 */
@Stateless
@Local(LegigameServiceLocal.class)
@Remote(LegigameServiceRemote.class)
public class LegigameServiceImpl implements LegigameService {

    private static final long serialVersionUID = 4828048491713892415L;

    private static final Log log = LogFactory.getLog(LegigameServiceImpl.class);

    private transient HttpClient httpClient;

    @PersistenceContext(unitName = CoreConstants.PERSISTENCE_UNIT)
    protected transient EntityManager em;

    @EJB(beanName = "MemberServiceImpl", beanInterface = MemberServiceLocal.class)
    private MemberService members;

    private static final int LEGIGAME_TIMEOUT = 10000;

    public LegigameServiceImpl() {
    }

    public LegigameServiceImpl(EntityManager em) {
        this.em = em;
    }

    /**
     * Returns an HTTP client.
     * 
     * @return an {@link HttpClient}
     */
    private HttpClient getHttpClient() {
        if (httpClient == null) {
            httpClient = new HttpClient();
            httpClient.getParams().setConnectionManagerTimeout(LEGIGAME_TIMEOUT);
            httpClient.getParams().setSoTimeout(LEGIGAME_TIMEOUT);
            httpClient.getParams().setAuthenticationPreemptive(true);
            httpClient.getParams().setParameter("http.useragent", "Sofun-Platform/" + CoreConstants.VERSION);
            Credentials creds = new UsernamePasswordCredentials(
                    Configuration.getProperties().getProperty("httpauth.username"),
                    Configuration.getProperties().getProperty("httpauth.password"));
            httpClient.getState().setCredentials(AuthScope.ANY, creds);
        }
        return httpClient;
    }

    /**
     * Executes a POST method.
     * 
     * @param method: {@link PostMethod} instance
     * @return a String containing the response body
     */
    private String executeMethod(PostMethod method) {

        StringBuffer sb = new StringBuffer();

        HttpClient client = getHttpClient();
        BufferedReader br = null;
        try {
            client.executeMethod(method);
            br = new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
            String readLine;
            while (((readLine = br.readLine()) != null)) {
                sb.append(readLine + "\n");
            }
        } catch (Exception e) {
            log.error("An error occured while trying to contact Legigame : " + e.getMessage());
            if (log.isDebugEnabled()) {
                e.printStackTrace();
            }
            httpClient = null;
            return null;
        } finally {
            method.releaseConnection();
            if (br != null)
                try {
                    br.close();
                } catch (Exception fe) {
                    log.error(fe.getMessage());
                    if (log.isDebugEnabled()) {
                        fe.printStackTrace();
                    }
                }
        }
        return sb.toString();

    }

    /**
     * Prepares a POST request to create or update a given a {@link Member}
     * 
     * @param member: a {@link Member} instance
     * @param method: a {@link PostMethod} instance
     * @return a {@link PostMethod} instance with all required parameters.
     */
    private PostMethod getPostForCreateOrUpdate(Member member, PostMethod method) {

        method.addParameter("Login", Configuration.getProperties().getProperty("api.login"));
        method.addParameter("Password", Configuration.getProperties().getProperty("api.password"));

        method.addParameter("PlayerID", String.valueOf(member.getId()));
        method.addParameter("Firstname", member.getFirstName());
        method.addParameter("Lastname", member.getLastName());

        final SimpleDateFormat sf = new SimpleDateFormat("dd/MM/yyyy");
        method.addParameter("BirthDate", sf.format(member.getBirthDate()));
        method.addParameter("Email", member.getEmail());

        // IBAN will be used in priority
        if (member.getIBAN() != null && member.getIBAN().getIBAN() != null && member.getIBAN().getSwift() != null
                && member.getIBAN().getIBAN().length() > 0 && member.getIBAN().getSwift().length() > 0) {
            method.addParameter("IBAN", member.getIBAN().getIBAN());
            method.addParameter("BIC", member.getIBAN().getSwift());
        } else if (member.getRIB() != null && member.getRIB().getBank() != null
                && member.getRIB().getBranch() != null && member.getRIB().getKey() != null
                && member.getRIB().getNumber() != null && member.getRIB().getBank().length() > 0
                && member.getRIB().getBranch().length() > 0 && member.getRIB().getKey().length() > 0
                && member.getRIB().getNumber().length() > 0) {
            // Legigame does not support RIB.
            // We use must convert it to IBAN.
            final String iban = member.getRIB().toIban();
            method.addParameter("IBAN", iban);
            method.addParameter("BIC", "");
        } else {
            if (member.getAccountStatus().equals(MemberAccountStatus.PENDING_VERIFIED_FR)) {
                log.error("No IBAN not RIB are available. " + "Account is pending activation though...");
            }
        }

        if (member.getBirthPlace() != null) {
            method.addParameter("CityOfBirth", member.getBirthPlace());
        }
        if (member.getBirthArea() != null) {
            method.addParameter("DepartmentOfBirth", member.getBirthArea());
        }
        if (member.getBirthCountry() != null) {
            method.addParameter("CountryOfBirth", member.getBirthCountry());
        }
        if (member.getMobilePhone() != null) {
            method.addParameter("Mobile", member.getMobilePhone());
        }
        if (member.getActivationKey() != null) {
            method.addParameter("ActivationCode", member.getActivationKey());
        }
        if (member.getPostalAddress().getStreet() != null) {
            method.addParameter("Address", member.getPostalAddress().getStreet());
        }
        if (member.getPostalAddress().getCity() != null) {
            method.addParameter("City", member.getPostalAddress().getCity());
        }
        if (member.getPostalAddress().getZipCode() != null) {
            method.addParameter("ZipCode", member.getPostalAddress().getZipCode());
        }
        if (member.getPostalAddress().getCountry() != null) {
            method.addParameter("Country", member.getPostalAddress().getCountry());
        }

        // Sofun specifics
        if (member.getAccountType().equals(MemberAccountType.GAMBLING_FR)) {
            method.addParameter("Attribut1", String.valueOf("1"));
        } else {
            method.addParameter("Attribut1", String.valueOf("0"));
        }

        if (member.getAccountStatus().equals(MemberAccountStatus.CLOSED)
                || member.getAccountStatus().equals(MemberAccountStatus.MEMBER_SUSPENDED)
                || member.getAccountStatus().equals(MemberAccountStatus.ADMIN_SUSPENDED)
                || member.getAccountStatus().equals(MemberAccountStatus.BANNED_FR)) {
            method.addParameter("ClosingDate", sf.format(member.getModified()));
        } else {
            method.addParameter("ClosingDate", "");
        }

        return method;

    }

    /**
     * Prepares a POST request to read the status of a given {@link Member}
     * 
     * @param member: a {@link Member} instance
     * @param method: a {@link PostMethod} instance
     * @return a {@link PostMethod} instance with all required parameters.
     */

    private PostMethod getPostForRead(Member member, PostMethod method) {

        method.addParameter("Login", Configuration.getProperties().getProperty("api.login"));
        method.addParameter("Password", Configuration.getProperties().getProperty("api.password"));

        method.addParameter("PlayerID", String.valueOf(member.getId()));

        return method;

    }

    /**
     * Returns all members candidates for creation or update.
     * 
     * @return a {@link List} of {@link Member} instance
     * @throws CoreException
     */
    private List<Member> getCandidatesForCreateOrUpdate(int offset, int batchSize) throws LegigameException {
        List<Member> candidates = new ArrayList<Member>();
        for (Iterator<Member> i = members.listMembers(offset, batchSize); i.hasNext();) {
            Member member = i.next();
            MemberLegigameStatus status = getStatusFor(member);
            boolean candidate = false;
            if (status != null) {
                if (status.getUpdated().compareTo(member.getModified()) < 0) {
                    candidate = true;
                }
            } else {
                candidate = true;
            }
            if (candidate) {
                candidates.add(member);
                log.debug("Member with email=" + member.getEmail() + " is candidate for create or update");
            }
        }
        return candidates;
    }

    /**
     * Returns all members candidates for status check.
     * 
     * <p>
     * 
     * We are only interested in pending activation members here.
     * 
     * @return a {@link List} of {@link Member} instance
     */
    @SuppressWarnings("unchecked")
    private List<Member> getCandidatesForRead() throws LegigameException {

        final List<String> status = new ArrayList<String>();
        status.add(MemberAccountStatus.CONFIRMED);
        status.add(MemberAccountStatus.PENDING_VERIFIED_FR);

        final String queryStr = "from " + MemberImpl.class.getSimpleName()
                + " m where m.type=:type AND m.status IN (:status)";
        final Query query = createQuery(queryStr);
        query.setParameter("type", MemberAccountType.GAMBLING_FR);
        query.setParameter("status", status);

        return query.getResultList();

    }

    /**
     * Creates or update a member record legigame side.
     * 
     * @param member: a {@link Member} instance
     */
    private ResponseCreateOrUpdate createOrUpdate(Member member, boolean forceUpdate) throws LegigameException {

        if (member.getAccountStatus().equals(MemberAccountStatus.PENDING_VERIFIED_FR) && !forceUpdate) {
            // This case is covered by the other timer (checkStatus())
            return null;
        }

        log.debug("Member with uuid=" + member.getId() + " scheduled for create or update @ legigame.");

        // Let's generate an activation code if none assigned to user yet.
        if (MemberAccountType.GAMBLING_FR.equals(member.getAccountType()) && member.getActivationKey() == null) {
            final String key = ActivationCodeGenerator.get();
            member.setActivationKey(key);
            log.info("Adding activation key for member with uuid=" + member.getId());
        }

        final String postUrl = Configuration.getProperties().getProperty("api.url.createOrUpdate");

        PostMethod method = new PostMethod(postUrl);
        method = getPostForCreateOrUpdate(member, method);

        String xmlResponse = executeMethod(method);
        if (xmlResponse == null) {
            return null;
        }

        if (log.isDebugEnabled()) {
            log.debug(xmlResponse);
        }

        ResponseCreateOrUpdate resp = new ResponseCreateOrUpdate(xmlResponse);

        MemberLegigameStatus status = getStatusFor(member);
        if (status == null) {
            status = new MemberLegigameStatusImpl();
            status.setMember(member);
            em.persist(status);
        }
        status.setDocumentStatus(String.valueOf(resp.getStatus()));
        status.setIteration(resp.getIteration());
        status.setLastUpdated(Calendar.getInstance().getTime());
        log.debug("Legigame status for member: uuid=" + member.getId() + " document status="
                + status.getDocumentStatus() + " iteration=" + status.getIteration());

        return resp;

    }

    /**
     * Request Legigame for a member record.
     * 
     * @param member: a {@link Member} instance
     * @return a {@link ResponseRead} instance
     * @throws LegigameException
     */
    private ResponseRead getLegiMember(Member member) throws LegigameException {

        final String postUrl = Configuration.getProperties().getProperty("api.url.read");

        PostMethod method = new PostMethod(postUrl);
        method = getPostForRead(member, method);

        String xmlResponse = executeMethod(method);
        if (xmlResponse == null) {
            return null;
        }
        if (log.isDebugEnabled()) {
            log.debug(xmlResponse);
        }
        return new ResponseRead(xmlResponse);

    }

    /**
     * Checks the status for a given member and update properties.
     * 
     * @param member: a {@link Member} instance
     */
    private void checkStatus(Member member) throws LegigameException {

        log.debug("Member with uuid=" + member.getId() + " scheduled for update checks @ legigame.");

        MemberLegigameStatus status = getStatusFor(member);
        boolean candidate = false;
        if (status == null) {
            createOrUpdate(member, true);
        } else {
            /*
             * if ("44".equals(status.getDocumentStatus())) { // Document
             * validated no need to reupload return; }
             */
            if (status.getUpdated().compareTo(member.getModified()) < 0) {
                createOrUpdate(member, true);
            }
            candidate = true;
        }
        if (candidate) {
            final ResponseRead resp = getLegiMember(member);
            if (resp == null) {
                log.error("An error occurred while retrieving member with email=" + member.getEmail());
                return;
            }
            status.setDocumentStatus(String.valueOf(resp.getStatus()));
            final SimpleDateFormat sf = new SimpleDateFormat("dd/MM/yyyy");
            try {
                final Date legiLastModified = sf.parse(resp.getProperties().get("DateLastIteration"));
                status.setLastUpdated(legiLastModified);
            } catch (ParseException e) {
                throw new LegigameException(e);
            }
        }

    }

    @Override
    public void syncMembers(int offset, int batchSize) throws LegigameException {
        List<Member> members = getCandidatesForCreateOrUpdate(offset, batchSize);
        for (Member member : members) {
            createOrUpdate(member, false);
        }
    }

    @Override
    public void syncStatus() throws LegigameException {
        for (Member member : getCandidatesForRead()) {
            checkStatus(member);
        }
    }

    /**
     * Returns a JPA query instance form a query string.
     * 
     * @param queryStr: a query string
     * @return a {@link Query} instance
     */
    private Query createQuery(String queryStr) {
        Query query = em.createQuery(queryStr);
        return query;
    }

    /**
     * Returns the legigame status for a given member.
     * 
     * @param member: a {@link Member} instance
     * @return a {@link MemberLegigameStatus} instance
     */
    private MemberLegigameStatus getStatusFor(Member member) {
        String queryStr = "from " + MemberLegigameStatusImpl.class.getSimpleName()
                + " s where s.member.id=:member_id";
        Query query = createQuery(queryStr);
        query.setParameter("member_id", member.getId());
        try {
            return (MemberLegigameStatus) query.getSingleResult();
        } catch (NoResultException nre) {
            return null;
        }
    }

}