com.serotonin.m2m2.Common.java Source code

Java tutorial

Introduction

Here is the source code for com.serotonin.m2m2.Common.java

Source

/*
Copyright (C) 2006-2011 Serotonin Software Technologies Inc. All rights reserved.
@author Matthew Lohbihler
 */
package com.serotonin.m2m2;

import java.io.File;
import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
import java.util.TimeZone;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.codec.binary.Base64;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.directwebremoting.WebContext;
import org.directwebremoting.WebContextFactory;
import org.joda.time.DateTimeZone;
import org.joda.time.Period;

import com.serotonin.ShouldNeverHappenException;
import com.serotonin.db.pair.StringStringPair;
import com.serotonin.json.JsonContext;
import com.serotonin.m2m2.db.DatabaseProxy;
import com.serotonin.m2m2.db.dao.SystemSettingsDao;
import com.serotonin.m2m2.i18n.TranslatableMessage;
import com.serotonin.m2m2.i18n.Translations;
import com.serotonin.m2m2.module.ModuleRegistry;
import com.serotonin.m2m2.rt.EventManager;
import com.serotonin.m2m2.rt.RuntimeManager;
import com.serotonin.m2m2.rt.maint.BackgroundProcessing;
import com.serotonin.m2m2.shared.VersionData;
import com.serotonin.m2m2.util.BackgroundContext;
import com.serotonin.m2m2.util.CommPortConfigException;
import com.serotonin.m2m2.util.DocumentationManifest;
import com.serotonin.m2m2.util.ExportCodes;
import com.serotonin.m2m2.util.license.InstanceLicense;
import com.serotonin.m2m2.util.license.LicenseFeature;
import com.serotonin.m2m2.view.DynamicImage;
import com.serotonin.m2m2.view.ImageSet;
import com.serotonin.m2m2.vo.CommPortProxy;
import com.serotonin.m2m2.vo.User;
import com.serotonin.m2m2.web.comparators.StringStringPairComparator;
import com.serotonin.monitor.MonitoredValues;
import com.serotonin.timer.CronTimerTrigger;
import com.serotonin.timer.RealTimeTimer;
import com.serotonin.util.StringUtils;
import com.serotonin.util.properties.ReloadingProperties;

import freemarker.template.Configuration;
import gnu.io.CommPortIdentifier;

public class Common {
    private static final String SESSION_USER = "sessionUser";

    // Note the start time of the application.
    public static final long START_TIME = System.currentTimeMillis();

    /**
     * @deprecated Use MA_HOME instead
     */
    @Deprecated
    public static String M2M2_HOME;
    public static String MA_HOME;
    public static final String UTF8 = "UTF-8";
    public static final Charset UTF8_CS = Charset.forName(UTF8);
    public static final Charset ASCII_CS = Charset.forName("ASCII");

    public static final int NEW_ID = -1;

    public static ReloadingProperties envProps;
    public static Configuration freemarkerConfiguration;
    public static DatabaseProxy databaseProxy;
    public static BackgroundProcessing backgroundProcessing;
    public static EventManager eventManager;
    public static RuntimeManager runtimeManager;

    public static String applicationLogo = "/images/logo.png";
    public static String applicationFavicon = "/images/favicon.ico";
    public static final List<String> moduleStyles = new ArrayList<String>();
    public static final List<String> moduleScripts = new ArrayList<String>();
    public static final List<String> moduleJspfs = new ArrayList<String>();

    public static final DocumentationManifest documentationManifest = new DocumentationManifest();
    public static final List<ImageSet> imageSets = new ArrayList<ImageSet>();
    public static final List<DynamicImage> dynamicImages = new ArrayList<DynamicImage>();

    public static final RealTimeTimer timer = new RealTimeTimer();
    public static final MonitoredValues MONITORED_VALUES = new MonitoredValues();
    public static final JsonContext JSON_CONTEXT = new JsonContext();

    //
    // License
    static InstanceLicense license;

    public static InstanceLicense license() {
        return license;
    }

    public static LicenseFeature licenseFeature(String name) {
        if (license != null)
            return license.getFeature(name);
        return null;
    }

    /*
     * Updating the MA version: - Create a DBUpdate subclass for the old version number. This may not do anything in
     * particular to the schema, but is still required to update the system settings so that the database has the
     * correct version.
     */
    public static final VersionData getVersion() {
        return new VersionData(getMajorVersion(), getMinorVersion(), getMicroVersion());
    }

    public static final int getMajorVersion() {
        return 2;
    }

    public static final int getMinorVersion() {
        return 1;
    }

    public static final int getMicroVersion() {
        return 0;
    }

    public static final int getDatabaseSchemaVersion() {
        return 9;
    }

    public static String getWebPath(String path) {
        return M2M2_HOME + "/web" + (path.startsWith("/") ? path : "/" + path);
    }

    public static File getLogsDir() {
        File file = new File(M2M2_HOME, "logs");
        file.mkdirs();
        return file;
    }

    public interface ContextKeys {
        String IMAGE_SETS = "IMAGE_SETS";
        String DYNAMIC_IMAGES = "DYNAMIC_IMAGES";
    }

    public interface TimePeriods {
        int MILLISECONDS = 8;
        int SECONDS = 1;
        int MINUTES = 2;
        int HOURS = 3;
        int DAYS = 4;
        int WEEKS = 5;
        int MONTHS = 6;
        int YEARS = 7;
    }

    public static ExportCodes TIME_PERIOD_CODES = new ExportCodes();
    static {
        TIME_PERIOD_CODES.addElement(TimePeriods.MILLISECONDS, "MILLISECONDS");
        TIME_PERIOD_CODES.addElement(TimePeriods.SECONDS, "SECONDS");
        TIME_PERIOD_CODES.addElement(TimePeriods.MINUTES, "MINUTES");
        TIME_PERIOD_CODES.addElement(TimePeriods.HOURS, "HOURS");
        TIME_PERIOD_CODES.addElement(TimePeriods.DAYS, "DAYS");
        TIME_PERIOD_CODES.addElement(TimePeriods.WEEKS, "WEEKS");
        TIME_PERIOD_CODES.addElement(TimePeriods.MONTHS, "MONTHS");
        TIME_PERIOD_CODES.addElement(TimePeriods.YEARS, "YEARS");
    }

    /**
     * Returns the length of time in milliseconds that the
     * 
     * @param timePeriod
     * @param numberOfPeriods
     * @return
     */
    public static long getMillis(int periodType, int periods) {
        return getPeriod(periodType, periods).toDurationFrom(null).getMillis();
    }

    public static Period getPeriod(int periodType, int periods) {
        switch (periodType) {
        case TimePeriods.MILLISECONDS:
            return Period.millis(periods);
        case TimePeriods.SECONDS:
            return Period.seconds(periods);
        case TimePeriods.MINUTES:
            return Period.minutes(periods);
        case TimePeriods.HOURS:
            return Period.hours(periods);
        case TimePeriods.DAYS:
            return Period.days(periods);
        case TimePeriods.WEEKS:
            return Period.weeks(periods);
        case TimePeriods.MONTHS:
            return Period.months(periods);
        case TimePeriods.YEARS:
            return Period.years(periods);
        default:
            throw new ShouldNeverHappenException("Unsupported time period: " + periodType);
        }
    }

    public static TranslatableMessage getPeriodDescription(int periodType, int periods) {
        String periodKey;
        switch (periodType) {
        case TimePeriods.MILLISECONDS:
            periodKey = "common.tp.milliseconds";
            break;
        case TimePeriods.SECONDS:
            periodKey = "common.tp.seconds";
            break;
        case TimePeriods.MINUTES:
            periodKey = "common.tp.minutes";
            break;
        case TimePeriods.HOURS:
            periodKey = "common.tp.hours";
            break;
        case TimePeriods.DAYS:
            periodKey = "common.tp.days";
            break;
        case TimePeriods.WEEKS:
            periodKey = "common.tp.weeks";
            break;
        case TimePeriods.MONTHS:
            periodKey = "common.tp.months";
            break;
        case TimePeriods.YEARS:
            periodKey = "common.tp.years";
            break;
        default:
            throw new ShouldNeverHappenException("Unsupported time period: " + periodType);
        }

        return new TranslatableMessage("common.tp.description", periods, new TranslatableMessage(periodKey));
    }

    //
    // Session user
    public static User getUser() {
        WebContext webContext = WebContextFactory.get();
        if (webContext == null) {
            // If there is no web context, check if there is a background context
            BackgroundContext backgroundContext = BackgroundContext.get();
            if (backgroundContext == null)
                return null;
            return backgroundContext.getUser();
        }
        return getUser(webContext.getHttpServletRequest());
    }

    public static User getUser(HttpServletRequest request) {
        // Check first to see if the user object is in the request.
        User user = (User) request.getAttribute(SESSION_USER);
        if (user != null)
            return user;

        // If not, get it from the session.
        user = (User) request.getSession().getAttribute(SESSION_USER);

        if (user != null) {
            // Add the user to the request. This prevents race conditions in which long-ish lasting requests have the
            // user object swiped from them by a quicker (logout) request.
            request.setAttribute(SESSION_USER, user);
        }
        return user;
    }

    public static void setUser(HttpServletRequest request, User user) {
        request.getSession().setAttribute(SESSION_USER, user);
    }

    public static TimeZone getUserTimeZone(User user) {
        if (user != null)
            return user.getTimeZoneInstance();
        return TimeZone.getDefault();
    }

    public static DateTimeZone getUserDateTimeZone(User user) {
        if (user != null)
            return user.getDateTimeZoneInstance();
        return DateTimeZone.forID(TimeZone.getDefault().getID());
    }

    //
    // Background process description. Used for audit logs when the system automatically makes changes to data, such as
    // safe mode disabling stuff.
    public static String getBackgroundProcessDescription() {
        BackgroundContext backgroundContext = BackgroundContext.get();
        if (backgroundContext == null)
            return null;
        return backgroundContext.getProcessDescriptionKey();
    }

    //
    // Image sets and dynamic images
    public static List<String> getImageSetIds() {
        List<String> result = new ArrayList<String>();
        for (ImageSet s : imageSets)
            result.add(s.getId());
        return result;
    }

    public static ImageSet getImageSet(String id) {
        for (ImageSet imageSet : imageSets) {
            if (imageSet.getId().equals(id))
                return imageSet;
        }
        return null;
    }

    public static List<String> getDynamicImageIds() {
        List<String> result = new ArrayList<String>();
        for (DynamicImage d : dynamicImages)
            result.add(d.getId());
        return result;
    }

    public static DynamicImage getDynamicImage(String id) {
        for (DynamicImage dynamicImage : dynamicImages) {
            if (dynamicImage.getId().equals(id))
                return dynamicImage;
        }
        return null;
    }

    private static String lazyFiledataPath = null;

    public static String getFiledataPath() {
        if (lazyFiledataPath == null) {
            String name = SystemSettingsDao.getValue(SystemSettingsDao.FILEDATA_PATH);
            if (name.startsWith("~"))
                name = getWebPath(name.substring(1));

            File file = new File(name);
            if (!file.exists())
                file.mkdirs();

            lazyFiledataPath = name;
        }
        return lazyFiledataPath;
    }

    public static CronTimerTrigger getCronTrigger(int periodType, int delaySeconds) {
        int delayMinutes = 0;
        if (delaySeconds >= 60) {
            delayMinutes = delaySeconds / 60;
            delaySeconds %= 60;

            if (delayMinutes >= 60)
                delayMinutes = 59;
        }

        try {
            switch (periodType) {
            case TimePeriods.MILLISECONDS:
                throw new ShouldNeverHappenException("Can't create a cron trigger for milliseconds");
            case TimePeriods.SECONDS:
                return new CronTimerTrigger("* * * * * ?");
            case TimePeriods.MINUTES:
                return new CronTimerTrigger(delaySeconds + " * * * * ?");
            case TimePeriods.HOURS:
                return new CronTimerTrigger(delaySeconds + " " + delayMinutes + " * * * ?");
            case TimePeriods.DAYS:
                return new CronTimerTrigger(delaySeconds + " " + delayMinutes + " 0 * * ?");
            case TimePeriods.WEEKS:
                return new CronTimerTrigger(delaySeconds + " " + delayMinutes + " 0 ? * MON");
            case TimePeriods.MONTHS:
                return new CronTimerTrigger(delaySeconds + " " + delayMinutes + " 0 1 * ?");
            case TimePeriods.YEARS:
                return new CronTimerTrigger(delaySeconds + " " + delayMinutes + " 0 1 JAN ?");
            default:
                throw new ShouldNeverHappenException("Invalid cron period type: " + periodType);
            }
        } catch (ParseException e) {
            throw new ShouldNeverHappenException(e);
        }
    }

    //
    // Misc
    public static List<CommPortProxy> getCommPorts() throws CommPortConfigException {
        try {
            List<CommPortProxy> ports = new LinkedList<CommPortProxy>();
            Enumeration<?> portEnum = CommPortIdentifier.getPortIdentifiers();
            CommPortIdentifier cpid;
            while (portEnum.hasMoreElements()) {
                cpid = (CommPortIdentifier) portEnum.nextElement();
                if (cpid.getPortType() == CommPortIdentifier.PORT_SERIAL)
                    ports.add(new CommPortProxy(cpid));
            }
            return ports;
        } catch (UnsatisfiedLinkError e) {
            throw new CommPortConfigException(e.getMessage());
        } catch (NoClassDefFoundError e) {
            throw new CommPortConfigException(
                    "Comm configuration error. Check that rxtx DLL or libraries have been correctly installed.");
        }
    }

    public synchronized static String encrypt(String plaintext) {
        try {
            String alg = envProps.getString("security.hashAlgorithm", "SHA");
            if ("NONE".equals(alg))
                return plaintext;

            MessageDigest md = MessageDigest.getInstance(alg);
            if (md == null)
                throw new ShouldNeverHappenException("MessageDigest algorithm " + alg
                        + " not found. Set the 'security.hashAlgorithm' property in env.properties appropriately. "
                        + "Use 'NONE' for no hashing.");
            md.update(plaintext.getBytes(UTF8_CS));
            byte raw[] = md.digest();
            String hash = new String(Base64.encodeBase64(raw));
            return hash;
        } catch (NoSuchAlgorithmException e) {
            // Should never happen, so just wrap in a runtime exception and rethrow
            throw new ShouldNeverHappenException(e);
        }
    }

    //
    // HttpClient
    public static HttpClient getHttpClient() {
        return getHttpClient(30000); // 30 seconds.
    }

    public static HttpClient getHttpClient(int timeout) {
        DefaultHttpClient client = new DefaultHttpClient();
        client.getParams().setParameter("http.socket.timeout", timeout);
        client.getParams().setParameter("http.connection.timeout", timeout);
        client.getParams().setParameter("http.connection-manager.timeout", timeout);
        client.getParams().setParameter("http.protocol.head-body-timeout", timeout);

        if (SystemSettingsDao.getBooleanValue(SystemSettingsDao.HTTP_CLIENT_USE_PROXY)) {
            String proxyHost = SystemSettingsDao.getValue(SystemSettingsDao.HTTP_CLIENT_PROXY_SERVER);
            int proxyPort = SystemSettingsDao.getIntValue(SystemSettingsDao.HTTP_CLIENT_PROXY_PORT);
            String username = SystemSettingsDao.getValue(SystemSettingsDao.HTTP_CLIENT_PROXY_USERNAME, "");
            String password = SystemSettingsDao.getValue(SystemSettingsDao.HTTP_CLIENT_PROXY_PASSWORD, "");

            client.getCredentialsProvider().setCredentials(new AuthScope(proxyHost, proxyPort),
                    new UsernamePasswordCredentials(username, password));
        }

        return client;
    }

    //
    //
    // i18n
    //
    private static Object i18nLock = new Object();
    private static String systemLanguage;
    private static Translations systemTranslations;
    private static List<StringStringPair> languages;

    public static String translate(String key) {
        ensureI18n();
        return systemTranslations.translate(key);
    }

    public static Translations getTranslations() {
        ensureI18n();
        return systemTranslations;
    }

    public static Locale getLocale() {
        ensureI18n();
        return parseLocale(systemLanguage);
    }

    private static void ensureI18n() {
        if (systemLanguage == null) {
            synchronized (i18nLock) {
                if (systemLanguage == null) {
                    systemLanguage = SystemSettingsDao.getValue(SystemSettingsDao.LANGUAGE);
                    Locale locale = parseLocale(systemLanguage);
                    if (locale == null)
                        throw new IllegalArgumentException(
                                "Locale for given language not found: " + systemLanguage);
                    systemTranslations = Translations.getTranslations(locale);
                }
            }
        }
    }

    public static String getMessage(String key, Object... args) {
        String pattern = translate(key);
        return MessageFormat.format(pattern, args);
    }

    public static void setSystemLanguage(String language) {
        if (parseLocale(language) == null)
            throw new IllegalArgumentException("Locale for given language not found: " + language);
        new SystemSettingsDao().setValue(SystemSettingsDao.LANGUAGE, language);
        systemLanguage = null;
        systemTranslations = null;
    }

    public static List<StringStringPair> getLanguages() {
        if (languages == null) {
            languages = new ArrayList<StringStringPair>();

            for (String localeStr : ModuleRegistry.getLocales()) {
                Locale locale = parseLocale(localeStr);
                if (locale != null)
                    languages.add(new StringStringPair(localeStr,
                            Translations.getTranslations(locale).translate("locale.name")));
            }

            StringStringPairComparator.sort(languages);
        }

        return languages;
    }

    private static Locale parseLocale(String str) {
        String[] parts = str.split("_");
        Locale locale = null;
        if (parts.length == 1)
            locale = new Locale(parts[0]);
        else if (parts.length == 2)
            locale = new Locale(parts[0], parts[1]);
        else if (parts.length == 3)
            locale = new Locale(parts[0], parts[1], parts[2]);
        return locale;
    }

    public static String generateXid(String prefix) {
        return prefix + StringUtils.generateRandomString(6, "0123456789");
    }
}