net.cbtltd.server.RazorServer.java Source code

Java tutorial

Introduction

Here is the source code for net.cbtltd.server.RazorServer.java

Source

/**
 * @author   bookingnet
 * @
 * @version   4.0.0
 */
package net.cbtltd.server;

import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.text.ParseException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;
import java.util.regex.PatternSyntaxException;

import javax.servlet.ServletContext;

import net.cbtltd.client.RazorService;
import net.cbtltd.json.JSONService;
import net.cbtltd.rest.flipkey.parse.ParseService;
import net.cbtltd.server.api.IsService;
import net.cbtltd.server.cron4j.Scheduler;
import net.cbtltd.server.job.PendingPayment;
import net.cbtltd.shared.License;
import net.cbtltd.shared.Service;
import net.cbtltd.shared.Time;
import net.cbtltd.shared.api.HasResponse;
import net.cbtltd.shared.api.HasService;
import net.cbtltd.shared.api.HasUrls;
import net.cbtltd.trial.server.SmsService;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.ExecutorType;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.apache.log4j.Logger;

import com.bookingnet.config.RazorConfig;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;

/**
 * The Class RazorServer is the server side for Razor GWT client.
 * <p>
 * A request is dispatched by the execute method to its Service according to the signature of its action.
 * This allows services to be compact and closely allied to the data table(s) that persist their instances.
 * Each service has a single instance accessed via its static getInstance() method.
 * The required service method is dynamically resolved by the value of its action and is invoked.
 * The value returned by the service method forms the response sent back to the client.
 * <p>
 * The class also has a scheduler based on the UNIX cron command.
 * This is used to schedule the execution of periodic housekeeping tasks.
 */
public final class RazorServer extends RemoteServiceServlet implements RazorService {
    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(RazorServer.class.getName());
    private static final HashMap<Service, IsService> SERVICES = new HashMap<Service, IsService>();
    private static SqlSessionFactory sqlMapper = null;

    public static final String ROOT_DIRECTORY = getApplicationRootDirectory();

    /** 
     * Instantiates a new razor server, its services, and starts the scheduler.
     * This can be replaced by a dynamic handler manager but has the benefit of simplicity.
     */
    public RazorServer() {
        super();
        SERVICES.put(Service.ACCOUNT, AccountService.getInstance());
        SERVICES.put(Service.ALERT, AlertService.getInstance());
        SERVICES.put(Service.ASSET, AssetService.getInstance());
        SERVICES.put(Service.ATTRIBUTE, AttributeService.getInstance());
        SERVICES.put(Service.AUDIT, AuditService.getInstance());
        SERVICES.put(Service.CONTRACT, ContractService.getInstance());
        SERVICES.put(Service.FINANCE, FinanceService.getInstance());
        SERVICES.put(Service.JOURNAL, JournalService.getInstance());
        SERVICES.put(Service.IMAGE, ImageService.getInstance());
        SERVICES.put(Service.IMAGETEXT, ImageTextService.getInstance());
        SERVICES.put(Service.LICENSE, LicenseService.getInstance());
        SERVICES.put(Service.LOCATION, LocationService.getInstance());
        SERVICES.put(Service.MAIL, MailService.getInstance());
        SERVICES.put(Service.MONITOR, MonitorService.getInstance());
        SERVICES.put(Service.PARTNER, PartnerService.getInstance());
        SERVICES.put(Service.PARTY, PartyService.getInstance());
        SERVICES.put(Service.PRICE, PriceService.getInstance());
        SERVICES.put(Service.PRODUCT, ProductService.getInstance());
        SERVICES.put(Service.RATE, RateService.getInstance());
        SERVICES.put(Service.REPORT, ReportService.getInstance());
        SERVICES.put(Service.RESERVATION, ReservationService.getInstance());
        SERVICES.put(Service.SESSION, SessionService.getInstance());
        SERVICES.put(Service.SMS, SmsService.getInstance());
        SERVICES.put(Service.TASK, TaskService.getInstance());
        SERVICES.put(Service.TAX, TaxService.getInstance());
        SERVICES.put(Service.TEXT, TextService.getInstance());
        SERVICES.put(Service.WORKFLOW, WorkflowService.getInstance());
        //      startScheduler();
        //      PartnerService.startSchedulers();
    }

    /**
     * Opens the database SQL session using the parameters in the specified configuration file.
     * The database can be tuned using these parameters - but lazy loading may NOT be used.
     * Connections are drawn from and returned to the pool as soon as possible.
     * Ensure that service methods execute with minimum latency - long running tasks should run in forked threads. 
     *
     * @return the current SQL session.
     */
    public static SqlSession openSession() {
        LOG.debug("openSession " + sqlMapper);
        if (sqlMapper == null) {
            try {
                String resource = "net/cbtltd/server/xml/Configuration.xml";
                Reader reader = Resources.getResourceAsReader(resource);
                sqlMapper = new SqlSessionFactoryBuilder().build(reader, RazorConfig.getEnvironmentId());
                LOG.debug("Using Configuration: " + RazorConfig.getEnvironmentId());
                LOG.debug("openSession " + sqlMapper);
            } catch (Throwable x) {
                LOG.error(x.getMessage());
                x.printStackTrace();
            }
        }
        return sqlMapper.openSession();
    }

    /**
     * Opens the database SQL session using the parameters in the specified configuration file.
     * The database can be tuned using these parameters - but lazy loading may NOT be used.
     * Connections are drawn from and returned to the pool as soon as possible.
     * Ensure that service methods execute with minimum latency - long running tasks should run in forked threads. 
     *
     * @return the current SQL session.
     */
    public static SqlSession openBatchSession() {
        LOG.debug("openSession " + sqlMapper);
        if (sqlMapper == null) {
            try {
                String resource = "net/cbtltd/server/xml/Configuration.xml";
                Reader reader = Resources.getResourceAsReader(resource);
                sqlMapper = new SqlSessionFactoryBuilder().build(reader);
                LOG.debug("openSession " + sqlMapper);
            } catch (Throwable x) {
                LOG.error(x.getMessage());
                x.printStackTrace();
            }
        }
        return sqlMapper.openSession(ExecutorType.BATCH);
    }

    /**
     * Gets the current instance of the specified service.
     *
     * @param service the specified service.
     * @return the service instance.
     */
    public static IsService getService(Service service) {
        return SERVICES.get(service);
    }

    /**
     * Gets the reservation service.
     *
     * @return the reservation service.
     */
    public static ReservationService getReservationService() {
        return (ReservationService) SERVICES.get(Service.RESERVATION);
    }

    /* (non-Javadoc)
     * @see javax.servlet.GenericServlet#getServletContext()
     */
    public ServletContext getServletContext() {
        return super.getServletContext();
    }

    /**
     * Gets the real path to the servlet location.
     *
     * @return the path to the servlet.
     */
    public String getPath() {
        return getServletContext().getRealPath("/");
    }

    /**
     * Request.
     *
     * @param request the request
     * @return the string
     * @throws SerializationException the serialization exception
     */
    public String request(String request) throws SerializationException {
        LOG.debug("Invoking " + request.toString());
        return request;
    }

    /* (non-Javadoc)
     * @see net.cbtltd.client.RazorService#send(net.cbtltd.shared.api.HasService)
     */
    public HasResponse send(HasService action) throws SerializationException {
        try {
            Date timestamp = new Date();
            HasResponse response = execute(action);
            MonitorService.monitor(action.getClass().getSimpleName(), timestamp);
            return response;
        } catch (PatternSyntaxException x) {
            LOG.error("PatternSyntaxException " + x.toString());
            throw new SerializationException("PatternSyntaxException");
        }
    }

    /**
     * Executes the specified action on the action.service() service.
     *
     * @param action the action to be executed.
     * @return the response.
     * @throws SerializationException the serialization exception
     */
    public HasResponse execute(HasService action) throws SerializationException {

        HasResponse response = null;
        LOG.debug("\n\nRazorServer execute " + action.getClass().getName() + "\naction " + action);
        String classname = action.service().classname();

        try {
            Class<?> c = Class.forName(classname); // say AccountService
            Method[] allMethods = c.getDeclaredMethods(); // can be static
            for (Method m : allMethods) {
                String mname = m.getName();
                if (mname.equals("execute")) {
                    Type[] pType = m.getGenericParameterTypes();
                    if (pType[1].toString().equals("class " + action.getClass().getName())) {
                        SqlSession sqlSession = openSession();
                        try {
                            m.setAccessible(true);
                            Object t = getService(action.service());
                            response = (HasResponse) m.invoke(t, sqlSession, action);
                            sqlSession.commit();
                        } catch (IllegalAccessException x) {
                            LOG.error("IllegalAccessException " + action.getClass().getName() + "\n"
                                    + x.getMessage());
                        } catch (InvocationTargetException x) {
                            LOG.error("InvocationTargetException exception " + action.getClass().getName() + "\n"
                                    + x.getMessage());
                        } catch (Throwable x) {
                            sqlSession.rollback();
                            MonitorService.log(x);
                        } finally {
                            sqlSession.close();
                        }
                    }
                }
            }
        } catch (ClassNotFoundException x) {
            MonitorService.log(x);
            LOG.error("ClassNotFoundException " + action.getClass().getName() + "\n" + x.getMessage());
        }
        return response;
    }

    /**
     * Schedules runnable tasks according to CRON patterns
     * @see   Scheduler at http://www.sauronsoftware.it/projects/cron4j/manual.php
     * A UNIX crontab-like pattern is a string split in five space separated parts. 
     * Each part is intended as:
     * 
     * 1 Minutes sub-pattern. During which minutes of the hour should the task been launched? 
     * The values range is from 0 to 59. 
     * 
     * 2 Hours sub-pattern. During which hours of the day should the task been launched? 
     * The values range is from 0 to 23. 
     * 
     * 3 Days of month sub-pattern. During which days of the month should the task been launched? 
     * The values range is from 1 to 31. 
     * The special value "L" can be used to recognize the last day of month.
     * 
     * 4 Months sub-pattern. During which months of the year should the task been launched? 
     * The values range is from 1 (January) to 12 (December), otherwise this sub-pattern allows 
     * the aliases "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov" and "dec".
     * 
     * 5 Days of week sub-pattern. During which days of the week should the task been launched? 
     * The values range is from 0 (Sunday) to 6 (Saturday), otherwise this sub-pattern allows 
     * the aliases "sun", "mon", "tue", "wed", "thu", "fri" and "sat".
     * 
     * The star wildcard character is also admitted, indicating "every minute of the hour", 
     * "every hour of the day", "every day of the month", "every month of the year" and 
     * "every day of the week", according to the sub-pattern in which it is used.
     */
    private void startScheduler() {

        //TODO: LicenseService.license(new Date(113, 8, 30)); //30 Sep 2013
        //TODO: LicenseService.balance();
        //TODO: PartyService.progress();
        //TODO:   ReservationService.specialrefresh();
        //TODO: ParseService.reviews();
        //TODO: TextService.createAudio(); //initialize audio files
        //TODO: MonitorService.emailLog();

        //TODO:      Scheduler runMonitor = new Scheduler();
        //      runMonitor.schedule("0 * * * *", new Runnable() { //each hour
        //         public void run() {
        //            MonitorService.monitor();
        //         }
        //      });
        //      runMonitor.start();

        Scheduler runProgress = new Scheduler();
        runProgress.schedule("15 13 * * *", new Runnable() { //each day at 13h15
            public void run() {
                PartyService.progress();
            }
        });
        runProgress.start();

        Scheduler runSpecial = new Scheduler();
        runSpecial.schedule("30 13 * * *", new Runnable() { //each day at 13h30
            public void run() {
                ReservationService.specialrefresh();
            }
        });
        runSpecial.start();

        Scheduler runReviews = new Scheduler();
        runReviews.schedule("0 1 * * *", new Runnable() { //each day at 1h00
            public void run() {
                ParseService.reviews();
            }
        });
        runReviews.start();

        Scheduler runPendingTransactions = new Scheduler();
        runPendingTransactions.schedule("59 23 * * *", new Runnable() { // each day at 23h00
            public void run() {
                PendingPayment.execute();
            }
        });
        runPendingTransactions.start();

        if (isLive()) {
            LOG.error("Start license schedulers at " + new Date());
            Scheduler runLicense = new Scheduler();
            runLicense.schedule("0 0 1 * *", new Runnable() { //start of month end day
                public void run() {
                    LicenseService.license(Time.addDuration(new Date(), -1, Time.DAY));
                }
            });
            runLicense.start();

            Scheduler runBalance = new Scheduler();
            runBalance.schedule("10 14 * * sun", new Runnable() { //each sunday at 14h10
                public void run() {
                    LicenseService.balance();
                }
            });
            runBalance.start();
        }
    }

    /** 
     * @return true if using windows environment. 
     */

    public static boolean isWindowsEnviroment() {
        return System.getProperty("os.name").toLowerCase().indexOf("win") >= 0;
    }

    public static String getApplicationRootDirectory() {
        String hostname = getHostName();
        String directory = HasUrls.ROOT_DIRECTORY;
        String osName = System.getProperty("os.name").toLowerCase();
        boolean isLinux = osName.indexOf("nix") >= 0 || osName.indexOf("nux") >= 0 || osName.indexOf("aix") > 0;

        if (hostname.compareToIgnoreCase("uat.bookingnet.com") == 0 || isLinux) {
            directory = HasUrls.ROOT_LINUX_DIRECTORY;
        } else if (hostname.compareToIgnoreCase("razor-cloud.com") == 0) {
            directory = HasUrls.ROOT_DIRECTORY;
        } else {
            directory = HasUrls.ROOT_DIRECTORY;
        }
        return directory;
    }

    /** 
     * @returns hostname from java: http://stackoverflow.com/questions/7348711/recommended-way-to-get-hostname-in-java 
     */
    public static String getHostName() {
        String hostname = "";
        try {
            hostname = InetAddress.getLocalHost().getHostName();
        } catch (UnknownHostException e) {
            e.printStackTrace();
        } //finally{return hostname;}
        return hostname;
    }

    /**
     * Checks if the live.txt file exists
     * 
     * @return true if the live.txt file exists
     */
    public static boolean isLive() {
        boolean live = true;
        try {
            Resources.getResourceAsReader("net/cbtltd/server/live.txt");
        } catch (IOException x) {
            live = false;
        }
        return live;
    }

    public static void main(String[] args) throws ParseException {
        Calendar c = Calendar.getInstance();
        Date date = JSONService.DF.parse("2015-01-31");
        Locale.setDefault(Locale.US);
        c.setTime(date);
        System.out.println(c.getTime());
        LicenseService.license(c.getTime());
    }
}