/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright 2000-2009 Sun Microsystems, Inc. All rights reserved. 
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License ("CDDL") (collectively, the "License").  You may
 * not use this file except in compliance with the License.  You can obtain
 * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
 * or mq/legal/LICENSE.txt.  See the License for the specific language
 * governing permissions and limitations under the License.
 * 
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at mq/legal/LICENSE.txt.  Sun designates
 * this particular file as subject to the "Classpath" exception as provided by
 * Sun in the GPL Version 2 section of the License file that accompanied this
 * code.  If applicable, add the following below the License Header, with the
 * fields enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyrighted [year] [name of copyright owner]"
 * 
 * Contributor(s):
 * 
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or  to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright holder. 
 */

/*
 * @(#)LicenseBase.java	1.16 06/28/07
 */ 

package com.sun.messaging.jmq.jmsserver.license;

import com.sun.messaging.jmq.jmsserver.util.BrokerException;
import com.sun.messaging.jmq.jmsserver.Globals;
import com.sun.messaging.jmq.jmsserver.resources.*;
import com.sun.messaging.jmq.util.log.Logger;

import java.io.*;
import java.util.*;
import java.security.*;

/**
 * iMQ broker license base class.
 */
public class LicenseBase {
    //
    // BEGIN core licence attributes and constants.
    //

    /** License attributes. */
    protected Properties props = new Properties();

    private boolean autoChecking = true;

    // Following attributes are derived from PROP_DATE_STRING.
    private int daysToTry = 0;
    private Date expirationDate = null; // expiration date
    private Date startDate = null; // start date of valid date range

    //////// Constant values  ////////

    /** License file magic number */
    protected static final long LICENSE_MAGIC_NUMBER = 1011902605893L;

    /** The license file format version */
    private static final String CURRENT_FILE_VERSION = "4";
    //Bug 6157397  
    /** The release version */
    public static final String CURRENT_LICENSE_VERSION = "4.4 FCS";

    //////// License attribute property names ////////
    public static final String PROP_FILE_VERSION = "imq.file_version";
    public static final String PROP_LICENSE_VERSION = "imq.license_version";
    public static final String PROP_LICENSE_TYPE = "imq.license_type";
    public static final String PROP_DATE_STRING = "date_string";
    public static final String PROP_PRECEDENCE = "imq.precedence";
    public static final String PROP_DESCRIPTION = "description";

    //////// Expiration date string constants ////////
    protected static final String NONE_STRING = "NONE";
    protected static final String TRY_STRING = "TRY";
    protected static final String VALID_STRING = "VALID";
    protected static final String OPEN_BRACKET = "[";
    protected static final String CLOSE_BRACKET = "]";
    protected static final String DASH = "-";

    //////// Other (feature specific) license attributes ////////
    public static final String PROP_CLIENT_CONNLIMIT = "imq.max_client_conns";
    public static final String PROP_BROKER_CONNLIMIT = "imq.max_broker_conns";
    public static final String PROP_MAX_BACKUP_CONS = "imq.max_backup_cons";
    public static final String PROP_MAX_ACTIVE_CONS = "imq.max_active_cons";

    //////// Feature licensing ////////
    public static final String PROP_ENABLE_CLUSTER =
        "imq.enable_cluster";
    public static final String PROP_ENABLE_HTTP =
        "imq.enable_http";
    public static final String PROP_ENABLE_SSL =
        "imq.enable_ssl";
    public static final String PROP_ENABLE_SHAREDPOOL =
        "imq.enable_sharedpool";
    public static final String PROP_ENABLE_C_API =
        "imq.enable_c_api";
    public static final String PROP_ENABLE_FAILOVER =
        "imq.enable_failover";
    public static final String PROP_ENABLE_MONITORING =
        "imq.enable_monitoring";
    public static final String PROP_ENABLE_LOCALDEST =
        "imq.enable_localdest";
    
    //The following features have been added for Shrike
     public static final String PROP_ENABLE_DMQ = "imq.enable_dmq";
     public static final String PROP_ENABLE_CLIENTPING = "imq.enable_clientping";
     public static final String PROP_ENABLE_MSGBODY_COMPRESSION = "imq.enable_msgbody_compression";
     public static final String PROP_ENABLE_SHARED_SUB = "imq.enable_shared_sub";
     public static final String PROP_ENABLE_AUDIT_CCC = "imq.enable_audit_ccc";
     public static final String PROP_ENABLE_NO_ACK = "imq.enable_no_ack";
     public static final String PROP_ENABLE_RECONNECT = "imq.enable_reconnect";

    //The following features have been added for Hawk
     public static final String PROP_ENABLE_HA = "imq.enable_ha";
      
    //
    // END licence attributes and constants.
    //

    protected static final BrokerResources br = Globals.getBrokerResources();
    protected static final Logger logger = Globals.getLogger();

    //
    // License information public access methods.
    //

    /**
     * Get any license attribute.
     */
    public String getProperty(String name) {
        return props.getProperty(name);
    }

    /**
     * Get an integer property.
     */
    public int getIntProperty(String name, int defval) {
        try {
            return Integer.parseInt(getProperty(name));
        }
        catch (Exception e) {
            return defval;
        }
    }

    /**
     * Get a boolean property.
     */
    public boolean getBooleanProperty(String name, boolean defval) {
        try {
            return Boolean.valueOf(getProperty(name)).booleanValue();
        }
        catch (Exception e) {
            return defval;
        }
    }

    /**
     * Get all the license properties.
     */
    public Properties getProperties() {
        return props;
    }

    public int getPrecedence() {
        int ret = 0;
        try {
            ret = Integer.parseInt(props.getProperty(PROP_PRECEDENCE));
        }
        catch (Exception e) {}
        return ret;
    }

    /**
     * Does this license expire.
     */
    public boolean willExpire() {
        String dateString = props.getProperty(PROP_DATE_STRING);
        if (dateString == null || ! dateString.equals(NONE_STRING))
            return true;

        return false;
    }

    public Date getStartDate() {
        return startDate;
    }

    public void setStartDate(Date d) {
        startDate = d;
    }

    public Date getExpirationDate() {
        return expirationDate;
    }

    public void setExpirationDate(Date d) {
        expirationDate = d;
    }

    public int getDaysToTry() {
        return daysToTry;
    }

    public void setDaysToTry(int d) {
        daysToTry = d;
    }

    /**
     * This method is implemented by the subclasses of LicenseBase.
     * It tells the LicenseManager whether to raise an exception if
     * there are no license files.
     */
    public boolean isLicenseFileRequired() {
        return true;
    }

    /**
     * When license is loaded by the LicenseCmd command (used by
     * release engineers only), there is no need to perform the
     * license checks.
     */
    public void setAutoChecking(boolean autoChecking) {
        this.autoChecking = autoChecking;
    }

    /**
     * Superimpose new properties on a license base class.
     */
    public void superimpose(Properties newprops) throws BrokerException {
        // The new superimposed information always takes precedence over the
        // default attributes.
        Enumeration names = newprops.propertyNames();
        while (names.hasMoreElements()) {
            String name = (String) names.nextElement();
            String value = (String) newprops.getProperty(name);

            props.setProperty(name, value);
        }

        processLicenseInfo();
    }

    /**
     * This method is called after the properties are loaded.
     * It does some post-processing and performs some simple sanity checks on
     * the license attributes.
     */
    private void processLicenseInfo() throws BrokerException {
        if (autoChecking == false)
            return;

        // Check the file version.
        String fileVersion = props.getProperty(PROP_FILE_VERSION);
        if (fileVersion == null ||
            ! fileVersion.equals(CURRENT_FILE_VERSION))
            throw new BrokerException(br.getString(br.E_BAD_LICENSE_DATA));

        String licenseVersion = props.getProperty(PROP_LICENSE_VERSION);

        if (licenseVersion == null ||
            ! licenseVersion.equals(CURRENT_LICENSE_VERSION))
            throw new BrokerException(br.getString(br.E_BAD_LICENSE_DATA));

        parseDateString();
        checkValidity();
    }

    /**
     * Parse the expiration date string into appropriate fields.
     */
    private void parseDateString() throws BrokerException {
        String dateString = props.getProperty(PROP_DATE_STRING);
        if (dateString == null)
            throw new BrokerException(br.getString(br.E_BAD_LICENSE_DATA));

        if (dateString.startsWith(NONE_STRING)) {
            // Do nothing.
        }
        else if (dateString.startsWith(TRY_STRING)) {
            // this license contains the number of days to try
            int oindex = dateString.indexOf(OPEN_BRACKET);
            int cindex = dateString.indexOf(CLOSE_BRACKET);
            int d = Integer.parseInt(
                dateString.substring(oindex+1, cindex));
            setDaysToTry(d);
        } else if (dateString.startsWith(VALID_STRING)) {
            // this license contains a date range
            int oindex = dateString.indexOf(OPEN_BRACKET);
            int dashindex = dateString.indexOf(DASH);
            int cindex = dateString.indexOf(CLOSE_BRACKET);

            if ((dashindex - oindex) > 1) {
                // we have a start date
                long start = Long.parseLong(
                    dateString.substring(oindex+1, dashindex));
                setStartDate(new Date(start));
            }

            if ((cindex - dashindex) > 1) {
                // we have an exipriation date
                long end = Long.parseLong(
                    dateString.substring(dashindex+1, cindex));
                setExpirationDate(new Date(end));
            }
        } else {
            // bad format
            throw new BrokerException(br.getString(br.E_BAD_LICENSE_DATA));
        }
    }

    /**
     * Throws exception if the license has expired or not valid yet.
     */
    private void checkValidity() throws BrokerException {
        if (! willExpire())
            return;

        if (getExpirationDate() != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(getExpirationDate());
            cal.set(cal.HOUR_OF_DAY, 0);
            cal.set(cal.MINUTE, 0);
            cal.set(cal.SECOND, 0);
            cal.set(cal.MILLISECOND, 0);
            if (cal.getTime().getTime() <= (new Date()).getTime()) {
                throw new BrokerException(
                    br.getString(br.E_LICENSE_EXPIRED, cal.getTime()));
            }
        } else if (getStartDate() != null) {
            Calendar cal = Calendar.getInstance();
            cal.setTime(getStartDate());

            cal.set(cal.HOUR_OF_DAY, 0);
            cal.set(cal.MINUTE, 0);
            cal.set(cal.SECOND, 0);
            cal.set(cal.MILLISECOND, 0);

            if ((new Date()).getTime() < cal.getTime().getTime()) {
                // now is before the valid start date
                throw new BrokerException(
                    br.getString(br.E_LICENSE_NOT_VALID_YET,
                        getStartDate()));
            }
        }
    }
}

/*
 * EOF
 */
