You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@stratos.apache.org by sa...@apache.org on 2013/07/02 11:38:04 UTC

[22/23] Refactoring org.wso2.carbon to org.apache.stratos

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/conf/BillingConfiguration.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/conf/BillingConfiguration.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/conf/BillingConfiguration.java
new file mode 100644
index 0000000..0027f16
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/conf/BillingConfiguration.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.conf;
+
+import org.apache.axiom.om.OMElement;
+import org.apache.axiom.om.impl.builder.StAXOMBuilder;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.billing.core.BillingConstants;
+import org.wso2.carbon.billing.core.BillingException;
+import org.wso2.carbon.billing.core.internal.Util;
+import org.wso2.carbon.ndatasource.common.DataSourceException;
+
+import javax.sql.DataSource;
+import javax.xml.namespace.QName;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
+import javax.xml.stream.XMLStreamReader;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * This class reads the billing-config.xml file and
+ * keeps the billing task configurations in a map.
+ * There are two configurations, one for scheduled bill generation
+ * and the other for on-demand bill generation
+ */
+public class BillingConfiguration {
+    private static final Log log = LogFactory.getLog(BillingConfiguration.class);
+    DataSource dataSource;
+    Map<String, BillingTaskConfiguration> billingTaskConfigs = new HashMap<String, BillingTaskConfiguration>();
+
+    public BillingConfiguration(String billingConfigFile) throws BillingException {
+        try {
+            dataSource = (DataSource) Util.getDataSourceService().getDataSource(BillingConstants.WSO2_BILLING_DS).getDSObject();
+            OMElement billingConfig = buildOMElement(new FileInputStream(billingConfigFile));
+            deserialize(billingConfig);
+        } catch (FileNotFoundException e) {
+            String msg = "Unable to find the file responsible for billing task configs: "
+                            + billingConfigFile;
+            log.error(msg, e);
+            throw new BillingException(msg, e);
+        } catch (DataSourceException e) {
+            String msg = "Error retrieving Billing datasource from master-datasources.xml configuration.";
+            log.error(msg, e);
+            throw new BillingException(msg, e);
+        }
+    }
+
+    private OMElement buildOMElement(InputStream inputStream) throws BillingException {
+        XMLStreamReader parser;
+        try {
+            parser = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
+        } catch (XMLStreamException e) {
+            String msg = "Error in initializing the parser to build the OMElement.";
+            log.error(msg, e);
+            throw new BillingException(msg, e);
+        }
+
+        StAXOMBuilder builder = new StAXOMBuilder(parser);
+        return builder.getDocumentElement();
+    }
+    
+    /*
+       Deserialize the following
+       <billingConfig xmlns="http://wso2.com/carbon/multitenancy/billing/config">
+           <dbConfig>
+                ...
+           </dbConfig>
+           <tasks>
+                <task id="multitenancyScheduledTask">
+                    ...
+                </task>
+                <task id="multitenancyViewingTask">
+                    ...
+                </task>
+            </tasks>
+        </billingConfig>
+     */
+    private void deserialize(OMElement billingConfigEle) throws BillingException {
+        Iterator billingConfigChildIt = billingConfigEle.getChildElements();
+        
+        while (billingConfigChildIt.hasNext()) {
+            OMElement billingConfigChildEle = (OMElement) billingConfigChildIt.next();
+            
+            if (new QName(BillingConstants.CONFIG_NS, BillingConstants.TASKS,
+                    BillingConstants.NS_PREFIX).equals(billingConfigChildEle.getQName())) {
+                //element is "tasks"
+                Iterator taskConfigChildIt = billingConfigChildEle.getChildElements();
+                while (taskConfigChildIt.hasNext()) {
+                    OMElement taskConfigEle = (OMElement) taskConfigChildIt.next();
+                    String id = taskConfigEle.getAttributeValue(new QName(BillingConstants.ATTR_ID));
+                    BillingTaskConfiguration taskConfig =
+                            new BillingTaskConfiguration(id, taskConfigEle);
+                    billingTaskConfigs.put(id, taskConfig);
+                }
+            } else {
+                String msg = "Unknown element in Billing Configuration: " +
+                                billingConfigChildEle.getQName().getLocalPart();
+                log.error(msg);
+                throw new BillingException(msg);
+            }
+        }
+    }
+
+    /*
+     * Deserialise dbConfigElement (Given below) and initialize data source
+        <dbConfig>
+            <url>jdbc:mysql://localhost:3306/billing</url>
+            <userName>billing</userName>
+            <password>billing</password>
+            <driverName>com.mysql.jdbc.Driver</driverName>
+            <maxActive>80</maxActive>
+            <maxWait>60000</maxWait>
+            <minIdle>5</minIdle>
+            <validationQuery>SELECT 1</validationQuery>
+        </dbConfig>
+     */
+    /*private void initDataSource(OMElement dbConfigEle) throws BillingException {
+        // initializing the data source and load the database configurations
+        Iterator dbConfigChildIt = dbConfigEle.getChildElements();
+        dataSource = new BasicDataSource();
+        
+        while (dbConfigChildIt.hasNext()) {
+            
+            OMElement dbConfigChildEle = (OMElement) dbConfigChildIt.next();
+            if (new QName(BillingConstants.CONFIG_NS, BillingConstants.DBCONFIG_URL,
+                    BillingConstants.NS_PREFIX).equals(dbConfigChildEle.getQName())) {
+                dataSource.setUrl(dbConfigChildEle.getText());
+            } else if (new QName(BillingConstants.CONFIG_NS, BillingConstants.DBCONFIG_USER_NAME,
+                    BillingConstants.NS_PREFIX).equals(dbConfigChildEle.getQName())) {
+                dataSource.setUsername(dbConfigChildEle.getText());
+            } else if (new QName(BillingConstants.CONFIG_NS, BillingConstants.DBCONFIG_PASSWORD,
+                    BillingConstants.NS_PREFIX).equals(dbConfigChildEle.getQName())) {
+                dataSource.setPassword(dbConfigChildEle.getText());
+            } else if (new QName(BillingConstants.CONFIG_NS, BillingConstants.DBCONFIG_DRIVER_NAME,
+                    BillingConstants.NS_PREFIX).equals(dbConfigChildEle.getQName())) {
+                dataSource.setDriverClassName(dbConfigChildEle.getText());
+            } else if (new QName(BillingConstants.CONFIG_NS, BillingConstants.DBCONFIG_MAX_ACTIVE,
+                    BillingConstants.NS_PREFIX).equals(dbConfigChildEle.getQName())) {
+                dataSource.setMaxActive(Integer.parseInt(dbConfigChildEle.getText()));
+            } else if (new QName(BillingConstants.CONFIG_NS, BillingConstants.DBCONFIG_MAX_WAIT,
+                    BillingConstants.NS_PREFIX).equals(dbConfigChildEle.getQName())) {
+                dataSource.setMaxWait(Integer.parseInt(dbConfigChildEle.getText()));
+            } else if (new QName(BillingConstants.CONFIG_NS, BillingConstants.DBCONFIG_MIN_IDLE,
+                    BillingConstants.NS_PREFIX).equals(dbConfigChildEle.getQName())) {
+                dataSource.setMinIdle(Integer.parseInt(dbConfigChildEle.getText()));
+            } else if (new QName(BillingConstants.CONFIG_NS, 
+                    BillingConstants.DBCONFIG_VALIDATION_QUERY, BillingConstants.NS_PREFIX)
+                    .equals(dbConfigChildEle.getQName())) {
+                dataSource.setValidationQuery(dbConfigChildEle.getText());
+            } else {
+                String msg = "Unknown element in DBConfig of Billing Configuration: " +
+                                dbConfigChildEle.getQName().getLocalPart();
+                log.error(msg);
+                throw new BillingException(msg);
+            }
+        }
+    }*/
+
+    public Map<String, BillingTaskConfiguration> getBillingTaskConfigs() {
+        return billingTaskConfigs;
+    }
+
+    public DataSource getDataSource() {
+        return dataSource;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/conf/BillingTaskConfiguration.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/conf/BillingTaskConfiguration.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/conf/BillingTaskConfiguration.java
new file mode 100644
index 0000000..5530ed1
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/conf/BillingTaskConfiguration.java
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.conf;
+
+import org.apache.axiom.om.OMElement;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.billing.core.BillingConstants;
+import org.wso2.carbon.billing.core.BillingException;
+import org.wso2.carbon.billing.core.BillingHandler;
+import org.wso2.carbon.billing.core.scheduler.ScheduleHelper;
+
+import javax.xml.namespace.QName;
+import java.util.*;
+
+public class BillingTaskConfiguration {
+    private static final Log log = LogFactory.getLog(BillingTaskConfiguration.class);
+
+    private String id;
+    private ScheduleHelper scheduleHelper = null;
+    private Map<String, String> schedulerHelperArgs;
+    private String schedulerServiceName;
+
+    private List<BillingHandler> billingHandlers = new ArrayList<BillingHandler>();
+    private List<HandlerConfigBean> handlerArgs = new ArrayList<HandlerConfigBean>(); //key - handler service name
+    private static Map<String, ScheduleHelper> schedulerServices =
+            new HashMap<String, ScheduleHelper>(); 
+    private static Map<String, BillingHandler> handlerServices =
+            new HashMap<String, BillingHandler>();
+
+    private class HandlerConfigBean {
+        public String name;
+        public boolean isServiceType;
+        public Map<String, String> constructorArgs;
+
+        public HandlerConfigBean(String name, boolean isServiceType, Map<String, String> constructorArgs){
+            this.name = name;
+            this.isServiceType = isServiceType;
+            this.constructorArgs = constructorArgs;
+        }
+    }
+
+    public BillingTaskConfiguration(String id, OMElement billingConfigEle) throws BillingException {
+        this.id = id;
+        deserialize(billingConfigEle);
+    }
+
+    /*
+     *  Deserialize following and creates tasks
+        <task id="multitenancyScheduledTask">
+            <subscriptionFilter>multitenancy</subscriptionFilter>
+            <schedule scheduleHelperClass="package.ClassName">
+                ...
+            </schedule>
+            <handlers>
+                ...
+            </handlers>
+        </task>
+     */
+    private void deserialize(OMElement taskConfigEle) throws BillingException {
+        Iterator billingConfigChildIt = taskConfigEle.getChildElements();
+        
+        while (billingConfigChildIt.hasNext()) {
+            OMElement childEle = (OMElement) billingConfigChildIt.next();
+            if (new QName(BillingConstants.CONFIG_NS, BillingConstants.SCHEDULE_CONF_KEY,
+                    BillingConstants.NS_PREFIX).equals(childEle.getQName())) {
+                deserializeSchedule(childEle);
+            } else if (new QName(BillingConstants.CONFIG_NS, BillingConstants.HANDLERS,
+                    BillingConstants.NS_PREFIX).equals(childEle.getQName())) {
+                deserializeHandlers(childEle);
+            } else {
+                String msg = "Unknown element in task configuration for task " + id +
+                                ": " + childEle.getQName().getLocalPart();
+                log.error(msg);
+                throw new BillingException(msg);
+            }
+        }
+    }
+
+    /*
+        <handlers>
+            <handler service="serviceName">
+            </handler>
+            <handler class="org.wso2.carbon.billing.core.handlers.EmailSendingHandler">
+                <parameter name="file">email-billing-notifications.xml</parameter>
+            </handler>
+        </handlers>
+     */
+    private void deserializeHandlers(OMElement handlersEle) throws BillingException {
+        // iterate through each billingHandlers
+        Iterator handlersChildIt = handlersEle.getChildElements();
+        
+        while (handlersChildIt.hasNext()) {
+            OMElement handlerEle = (OMElement) handlersChildIt.next();
+            if (!(new QName(BillingConstants.CONFIG_NS, BillingConstants.HANDLER,
+                    BillingConstants.NS_PREFIX).equals(handlerEle.getQName()))) {
+                String msg = "Unknown element in handler configuration for task " + id +
+                                ": " + handlerEle.getQName().getLocalPart();
+                log.error(msg);
+                throw new BillingException(msg);
+            }
+
+            // get the parameters for handler
+            Iterator handlerParametersIt = handlerEle.getChildElements();
+            Map<String, String> constructorArgs = extractConstructorArgs(handlerParametersIt);
+            String handlerClassName =
+                    handlerEle.getAttributeValue(new QName(BillingConstants.HANDLER_CLASS_ATTR));
+            if (handlerClassName == null) {
+                // className is not given. So, it uses a handlerService
+                String handlerServiceName = handlerEle.getAttributeValue(
+                        new QName(BillingConstants.HANDLER_SERVICE_ATTR));
+                HandlerConfigBean bean = new HandlerConfigBean(handlerServiceName, true, constructorArgs);
+                handlerArgs.add(bean);
+            } else {
+                HandlerConfigBean bean = new HandlerConfigBean(handlerClassName, false, constructorArgs);
+                handlerArgs.add(bean);
+            }
+        }
+    }
+
+    /* 
+     * Deserialize following and creates scheduleHelper
+        <schedule scheduleHelperClass="package.ClassName">
+            <parameter name="dayToTriggerOn">1</parameter>
+            <parameter name="hourToTriggerOn">0</parameter>
+            <parameter name="timeZone">GMT-8:00</parameter>
+        </schedule>
+     */
+    private void deserializeSchedule(OMElement scheduleEle) throws BillingException {
+        Iterator scheduleHelperConfigChildIt = scheduleEle.getChildElements();
+        Map<String, String> constructorArgs = extractConstructorArgs(scheduleHelperConfigChildIt);
+        
+        // get the scheduleHelper class name
+        String className = scheduleEle.getAttributeValue(
+                new QName(BillingConstants.TRIGGER_CALCULATOR_CLASS_ATTR));
+        
+        if (className == null) {
+            //className is not given; it is using scheduler service
+            schedulerServiceName = scheduleEle.getAttributeValue(
+                    new QName(BillingConstants.TRIGGER_CALCULATOR_SERVICE_ATTR));
+            schedulerHelperArgs = constructorArgs;
+        } else {
+            //className is given; Construct the object
+            scheduleHelper = (ScheduleHelper) constructObject(className);
+            scheduleHelper.init(constructorArgs);
+        }
+    }
+
+    public ScheduleHelper getScheduleHelper() throws BillingException {
+        if (scheduleHelper == null && schedulerServiceName != null) {
+            scheduleHelper = schedulerServices.get(schedulerServiceName);
+            if (scheduleHelper == null) {
+                String msg = "The scheduler helper service: " + schedulerServiceName +
+                                " is not loaded.";
+                log.error(msg);
+                throw new BillingException(msg);
+            }
+            scheduleHelper.init(schedulerHelperArgs);
+        }
+        return scheduleHelper;
+    }
+
+    public List<BillingHandler> getBillingHandlers() throws BillingException {
+        // We have to combine the handlers and handlerServices as a single list and return. When
+        // creating and initializing handerServices, remove them from the handelerArgs so that they
+        // will be included only once
+        if(!handlerArgs.isEmpty()){
+            for(HandlerConfigBean bean : handlerArgs){
+                if(bean.isServiceType){
+                    BillingHandler handlerService = handlerServices.get(bean.name);
+                    if (handlerService == null) {
+                        billingHandlers = null;
+                        String msg = "The handler service: " + bean.name + " is not loaded.";
+                        log.error(msg);
+                        throw new BillingException(msg);
+                    }
+                    handlerService.init(bean.constructorArgs);
+                    billingHandlers.add(handlerService);
+
+                } else {
+                    BillingHandler handler = (BillingHandler) constructObject(bean.name);
+                    handler.init(bean.constructorArgs);
+                    billingHandlers.add(handler);
+                }
+            }
+
+            //all the billing handler services are initialized properly, can clear handlerArgs
+            handlerArgs.clear();
+        }
+        return billingHandlers;
+    }
+
+    private static Object constructObject(String className) throws BillingException {
+        try {
+            return Class.forName(className).newInstance();
+        } catch (ClassNotFoundException e) {
+            String msg = "The class: " + className + " is not in the classpath.";
+            log.error(msg, e);
+            throw new BillingException(msg, e);
+        } catch (Exception e) {
+            String msg = "Error in initializing the object for " + className + ".";
+            log.error(msg);
+            throw new BillingException(msg, e);
+        }
+    }
+
+    private static Map<String, String> extractConstructorArgs(Iterator parameterIt) {
+        Map<String, String> constructorArgs = new HashMap<String, String>();
+        
+        while (parameterIt.hasNext()) {
+            OMElement paramEle = (OMElement) parameterIt.next();
+            if (!new QName(BillingConstants.CONFIG_NS, BillingConstants.SCHEDULE_CONF_PARAM_KEY,
+                    BillingConstants.NS_PREFIX).equals(paramEle.getQName())) {
+                continue;
+            }
+            
+            String paramName = paramEle.getAttributeValue(
+                    new QName(BillingConstants.SCHEDULE_CONF_PARAM_NAME_KEY));
+            String paramValue = paramEle.getText();
+            constructorArgs.put(paramName, paramValue);
+        }
+        return constructorArgs;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    // the following two methods will be called when the services are available for the schedule
+    // helper and the billing handlers
+    public static void addScheduleHelper(ScheduleHelper scheduleHelper) {
+        schedulerServices.put(scheduleHelper.getClass().getName(), scheduleHelper);
+    }
+
+    public static void addBillingHandler(BillingHandler billingHandler) {
+        handlerServices.put(billingHandler.getClass().getName(), billingHandler);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Cash.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Cash.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Cash.java
new file mode 100644
index 0000000..e9d760a
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Cash.java
@@ -0,0 +1,304 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.dataobjects;
+
+import org.wso2.carbon.billing.core.BillingException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.util.regex.Pattern;
+
+
+public class Cash {
+    private static final Log log = LogFactory.getLog(Cash.class);
+    public static final String CURRENCY_USD = "$";
+    public static final String DEFAULT_CURRENCY = CURRENCY_USD;
+
+    public enum Sign {
+        POSITIVE, NEGATIVE
+    };
+
+    String currency;
+    int wholeNumber;
+    int decimalNumber;
+    Sign sign = Sign.POSITIVE; // true for positive
+
+    private static final String notNumbersRegEx = "[^0-9]";
+    private static final Pattern notNumbersPattern = Pattern.compile(notNumbersRegEx);
+
+    public Cash() {
+        // the default constructor for Cash
+    }
+
+    public Cash(Cash copyFrom) {
+        this.currency = copyFrom.getCurrency();
+        this.wholeNumber = copyFrom.getWholeNumber();
+        this.decimalNumber = copyFrom.getDecimalNumber();
+        this.sign = copyFrom.getSign();
+    }
+
+    public Cash(String cashString) throws BillingException {
+        if (cashString == null) {
+            cashString = "$0";
+        }
+        if (cashString.startsWith(CURRENCY_USD)) {
+            cashString = cashString.substring(CURRENCY_USD.length());
+            currency = CURRENCY_USD;
+        }
+        // possible other currencies
+        else {
+            currency = DEFAULT_CURRENCY;
+        }
+
+        if (cashString.startsWith("-")) {
+            sign = Sign.NEGATIVE;
+            cashString = cashString.substring(1);
+        } else if (cashString.startsWith("+")) {
+            sign = Sign.POSITIVE;
+            cashString = cashString.substring(1);
+        } else {
+            sign = Sign.POSITIVE;
+        }
+
+        if (cashString.contains(".")) {
+            String wholeNumberStr = cashString.substring(0, cashString.indexOf("."));
+            if (wholeNumberStr.trim().equals("")) {
+                String msg = "Whole number can not be empty";
+                throw new BillingException(msg);
+            }
+            if (notNumbersPattern.matcher(wholeNumberStr).find()) {
+                String msg = "The whole number expected to have only 0-9 characters.: " +
+                                wholeNumberStr + " is not a number. ";
+                throw new BillingException(msg);
+            }
+            
+            String decimalNumberStr = cashString.substring(cashString.indexOf(".") + 1);
+            if (notNumbersPattern.matcher(decimalNumberStr).find()) {
+                String msg = "The decimal number expected to have only 0-9 characters.: " +
+                                decimalNumberStr + " is not a number. ";
+                throw new BillingException(msg);
+            }
+            if (decimalNumberStr.length() == 0) {
+                String msg = "String after the decimal point is zero.";
+                throw new BillingException(msg);
+            } else if (decimalNumberStr.length() > 2) {
+                String msg = "String after the decimal point is greater than 2";
+                throw new BillingException(msg);
+            } else if (decimalNumberStr.length() == 1) {
+                decimalNumberStr += "0";
+            }
+            
+            wholeNumber = Integer.parseInt(wholeNumberStr);
+            decimalNumber = Integer.parseInt(decimalNumberStr);
+            
+        } else {
+            if (notNumbersPattern.matcher(cashString).find()) {
+                String msg = "The cash string to have only 0-9 characters.: " + cashString +
+                                " is not a number. ";
+                throw new BillingException(msg);
+            }
+            
+            wholeNumber = Integer.parseInt(cashString);
+            decimalNumber = 0;
+        }
+    }
+
+    public Sign getSign() {
+        return sign;
+    }
+
+    public void setSign(Sign sign) {
+        this.sign = sign;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+
+    public int getWholeNumber() {
+        return wholeNumber;
+    }
+
+    public void setWholeNumber(int wholeNumber) {
+        this.wholeNumber = wholeNumber;
+    }
+
+    public int getDecimalNumber() {
+        return decimalNumber;
+    }
+
+    public void setDecimalNumber(int decimalNumber) {
+        this.decimalNumber = decimalNumber;
+    }
+
+    public String serializeToString() {
+        String str = currency;
+        if (sign == Sign.NEGATIVE) {
+            str += "-";
+        }
+        str += wholeNumber + ".";
+        if (decimalNumber < 10) {
+            str += "0" + decimalNumber;
+        } else {
+            str += decimalNumber;
+        }
+        return str;
+    }
+
+    @Override
+    public String toString() {
+        return serializeToString();
+    }
+
+    public static Cash add(Cash a, Cash b) throws BillingException {
+        if (!a.getCurrency().equals(b.getCurrency())) {
+            // we still not support this.
+            String msg = "Can not add in-similar currencies: " + a.getCurrency() + "!=" +
+                            b.getCurrency() + ".";
+            log.error(msg);
+            throw new BillingException(msg);
+        }
+        
+        if (a.getSign() == Sign.POSITIVE && b.getSign() == Sign.NEGATIVE) {
+            Cash b2 = new Cash(b);
+            b2.setSign(Sign.POSITIVE);
+            return subtract(a, b2);
+        }
+        
+        if (a.getSign() == Sign.NEGATIVE && b.getSign() == Sign.POSITIVE) {
+            Cash a2 = new Cash(a);
+            a2.setSign(Sign.POSITIVE);
+            return subtract(b, a2);
+        }
+        
+        if (a.getSign() == Sign.NEGATIVE && b.getSign() == Sign.NEGATIVE) {
+            Cash a2 = new Cash(a);
+            Cash b2 = new Cash(b);
+            a2.setSign(Sign.POSITIVE);
+            b2.setSign(Sign.POSITIVE);
+            Cash c2 = add(a2, b2);
+            c2.setSign(Sign.NEGATIVE);
+            return c2;
+        }
+        
+        int decimalSum = a.getDecimalNumber() + b.getDecimalNumber();
+        int wholeSum = a.getWholeNumber() + b.getWholeNumber();
+
+        Cash cash = new Cash();
+        cash.setCurrency(a.getCurrency());
+        if (decimalSum >= 100) {
+            decimalSum -= 100;
+            wholeSum += 1;
+        }
+        cash.setDecimalNumber(decimalSum);
+        cash.setWholeNumber(wholeSum);
+        cash.setSign(Sign.POSITIVE);
+        return cash;
+    }
+
+    public static Cash subtract(Cash a, Cash b) throws BillingException {
+        if (!a.getCurrency().equals(b.getCurrency())) {
+            // we still not support this.
+            String msg = "Can not add in-similar currencies: " + a.getCurrency() + "!=" +
+                            b.getCurrency() + ".";
+            log.error(msg);
+            throw new BillingException(msg);
+        }
+        
+        if (a.getSign() == Sign.POSITIVE && b.getSign() == Sign.NEGATIVE) {
+            Cash b2 = new Cash(b);
+            b2.setSign(Sign.POSITIVE);
+            return add(a, b2);
+        }
+        
+        if (a.getSign() == Sign.NEGATIVE && b.getSign() == Sign.POSITIVE) {
+            Cash a2 = new Cash(a);
+            a2.setSign(Sign.POSITIVE);
+            Cash c2 = add(b, a2);
+            c2.setSign(Sign.NEGATIVE);
+            return c2;
+        }
+        
+        if (a.getSign() == Sign.NEGATIVE && b.getSign() == Sign.NEGATIVE) {
+            Cash a2 = new Cash(a);
+            Cash b2 = new Cash(b);
+            a2.setSign(Sign.POSITIVE);
+            b2.setSign(Sign.POSITIVE);
+            Cash c2 = subtract(a2, b2);
+            if (c2.getSign() == Sign.NEGATIVE) {
+                c2.setSign(Sign.POSITIVE);
+            } else {
+                c2.setSign(Sign.NEGATIVE);
+            }
+            return c2;
+        }
+        
+        int decimalSum = a.getDecimalNumber() - b.getDecimalNumber();
+        int wholeSum = a.getWholeNumber() - b.getWholeNumber();
+
+        if (wholeSum < 0 || (decimalSum < 0 && wholeSum == 0)) {
+            // then it is negative value
+            Cash c = subtract(b, a);
+            c.setSign(Sign.NEGATIVE);
+            return c;
+        }
+
+        Cash cash = new Cash();
+        cash.setCurrency(a.getCurrency());
+        if (decimalSum < 0) {
+            decimalSum += 100;
+            wholeSum -= 1;
+        }
+
+        cash.setDecimalNumber(decimalSum);
+        cash.setWholeNumber(wholeSum);
+        return cash;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof Cash)) {
+            return false;
+        }
+        Cash otherCash = (Cash) o;
+        return otherCash.serializeToString().equals(this.serializeToString());
+    }
+
+    @Override
+    public int hashCode() {
+        return serializeToString().hashCode();
+    }
+
+    public Cash multiply(double multiplyBy) {
+        long answerInCent = (long) (wholeNumber * 100 * multiplyBy + decimalNumber * multiplyBy);
+        int newWholeNumber = (int) (answerInCent / 100);
+        int newDecimalNumber = (int) (answerInCent % 100);
+
+        Cash cash = new Cash();
+        cash.setCurrency(this.getCurrency());
+        if (newWholeNumber < 0) {
+            cash.setSign(Sign.NEGATIVE);
+        }
+        cash.setWholeNumber(newWholeNumber);
+        cash.setDecimalNumber(newDecimalNumber);
+        return cash;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Customer.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Customer.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Customer.java
new file mode 100644
index 0000000..e12d5d2
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Customer.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.dataobjects;
+
+import java.util.Date;
+
+/**
+ * Customer class - This holds the information of tenants
+ * i.e. customer=tenant
+ */
+public class Customer {
+    private int id;
+    private String name;
+    private String context;
+    private String fullName;
+    private String email;
+    private Date startedDate;
+    private String address;
+    private Invoice activeInvoice;
+    private long totalBandwidth;
+    private long totalStorage;
+    private long totalCartridgeCPUHours;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getFullName() {
+        return fullName;
+    }
+
+    public void setFullName(String fullName) {
+        this.fullName = fullName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getContext() {
+        return context;
+    }
+
+    public void setContext(String context) {
+        this.context = context;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public Date getStartedDate() {
+        return new Date(startedDate.getTime());
+    }
+
+    public void setStartedDate(Date startedDate) {
+        this.startedDate = new Date(startedDate.getTime());
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    /**
+     * This will be used by rules to retrieve the active invoice
+     *
+     * @return
+     */
+    public final Invoice getActiveInvoice() {
+        return activeInvoice;
+    }
+
+    public final void setActiveInvoice(Invoice invoice) {
+        this.activeInvoice = invoice;
+    }
+
+    public long getTotalBandwidth() {
+        return totalBandwidth;
+    }
+
+    public void setTotalBandwidth(long totalBandwidth) {
+        this.totalBandwidth = totalBandwidth;
+    }
+
+    public long getTotalStorage() {
+        return totalStorage;
+    }
+
+    public void setTotalStorage(long totalStorage) {
+        this.totalStorage = totalStorage;
+    }
+
+    public long getTotalCartridgeCPUHours() {
+        return totalCartridgeCPUHours;
+    }
+
+    public void setTotalCartridgeCPUHours(long totalCartridgeCPUHours) {
+        this.totalCartridgeCPUHours = totalCartridgeCPUHours;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        Customer customer = (Customer) o;
+
+        if (id != customer.id) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return id;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Discount.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Discount.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Discount.java
new file mode 100644
index 0000000..862b1fd
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Discount.java
@@ -0,0 +1,88 @@
+/*
+*  Copyright (c) 2005-2010, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+*
+*  WSO2 Inc. licenses this file to you under the Apache License,
+*  Version 2.0 (the "License"); you may not use this file except
+*  in compliance with the License.
+*  You may obtain a copy of the License at
+*
+*    http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing,
+* software distributed under the License is distributed on an
+* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+* KIND, either express or implied.  See the License for the
+* specific language governing permissions and limitations
+* under the License.
+*/
+package org.wso2.carbon.billing.core.dataobjects;
+
+
+import java.util.Date;
+
+public class Discount {
+    
+    private int id;
+    private int tenantId;
+    private float percentage;
+    private float amount;
+    private Date startDate;
+    private Date endDate;
+    private boolean isPercentageType;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public int getTenantId() {
+        return tenantId;
+    }
+
+    public void setTenantId(int tenantId) {
+        this.tenantId = tenantId;
+    }
+
+    public float getPercentage() {
+        return percentage;
+    }
+
+    public void setPercentage(float percentage) {
+        this.percentage = percentage;
+    }
+
+    public float getAmount() {
+        return amount;
+    }
+
+    public void setAmount(float amount) {
+        this.amount = amount;
+    }
+
+    public Date getStartDate() {
+        return startDate;
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = startDate;
+    }
+
+    public Date getEndDate() {
+        return endDate;
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = endDate;
+    }
+
+    public boolean isPercentageType() {
+        return isPercentageType;
+    }
+
+    public void setPercentageType(boolean percentageType) {
+        isPercentageType = percentageType;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Invoice.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Invoice.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Invoice.java
new file mode 100644
index 0000000..697ae77
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Invoice.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.dataobjects;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Invoice class - holds the invoice information
+ */
+public class Invoice {
+    int id;
+    Date date;
+    Date startDate;
+    Date endDate;
+    Cash boughtForward;
+    Cash carriedForward;
+    Cash totalCost;
+    Cash totalPayment;
+    Customer customer;
+    List<Subscription> subscriptions = new ArrayList<Subscription>();
+    List<Payment> payments = new ArrayList<Payment>();
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        return new Date(date.getTime());
+    }
+
+    public void setDate(Date date) {
+        this.date = new Date(date.getTime());
+    }
+
+    public Date getStartDate() {
+        return new Date(startDate.getTime());
+    }
+
+    public void setStartDate(Date startDate) {
+        this.startDate = new Date(startDate.getTime());
+    }
+
+    public Date getEndDate() {
+        return new Date(endDate.getTime());
+    }
+
+    public void setEndDate(Date endDate) {
+        this.endDate = new Date(endDate.getTime());
+    }
+
+    public Cash getBoughtForward() {
+        return boughtForward;
+    }
+
+    public void setBoughtForward(Cash boughtForward) {
+        this.boughtForward = boughtForward;
+    }
+
+    public Cash getCarriedForward() {
+        return carriedForward;
+    }
+
+    public void setCarriedForward(Cash carriedForward) {
+        this.carriedForward = carriedForward;
+    }
+
+    public Cash getTotalCost() {
+        return totalCost;
+    }
+
+    public void setTotalCost(Cash totalCost) {
+        this.totalCost = totalCost;
+    }
+
+    public Cash getTotalPayment() {
+        return totalPayment;
+    }
+
+    public void setTotalPayment(Cash totalPayment) {
+        this.totalPayment = totalPayment;
+    }
+
+    public Customer getCustomer() {
+        return customer;
+    }
+
+    public void setCustomer(Customer customer) {
+        this.customer = customer;
+    }
+
+    public List<Subscription> getSubscriptions() {
+        return subscriptions;
+    }
+
+    public void setSubscriptions(List<Subscription> subscriptions) {
+        this.subscriptions = subscriptions;
+    }
+
+    public List<Payment> getPayments() {
+        return payments;
+    }
+
+    public void setPayments(List<Payment> payments) {
+        this.payments = payments;
+    }
+
+    public void addPayment(Payment payment) {
+        this.payments.add(payment);
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Item.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Item.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Item.java
new file mode 100644
index 0000000..8c92238
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Item.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.dataobjects;
+
+import java.util.List;
+
+public class Item {
+    private int id;
+    private String name;
+    private Cash cost;
+    private Cash creditLimit; //this is the credit limit defined by the billing rules
+    private int bandwidthLimit;
+    private Cash bandwidthOveruseCharge;
+    private int resourceVolumeLimit;
+    private Cash resourceVolumeOveruseCharge;
+    private int cartridgeCPUHourLimit;
+    private Cash cartridgeCPUOveruseCharge;
+    private String description;
+    private Item parent;
+    private List<? extends Item> children;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Cash getCost() {
+        return cost;
+    }
+
+    public void setCost(Cash cost) {
+        this.cost = cost;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Item getParent() {
+        return parent;
+    }
+
+    public void setParent(Item parent) {
+        this.parent = parent;
+    }
+
+    public List<? extends Item> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<? extends Item> children) {
+        this.children = children;
+    }
+
+    public Cash getCreditLimit() {
+        return creditLimit;
+    }
+
+    public void setCreditLimit(Cash creditLimit) {
+        this.creditLimit = creditLimit;
+    }
+
+    public int getBandwidthLimit() {
+        return bandwidthLimit;
+    }
+
+    public void setBandwidthLimit(int bandwidthLimit) {
+        this.bandwidthLimit = bandwidthLimit;
+    }
+
+    public Cash getBandwidthOveruseCharge() {
+        return bandwidthOveruseCharge;
+    }
+
+    public void setBandwidthOveruseCharge(Cash bandwidthOveruseCharge) {
+        this.bandwidthOveruseCharge = bandwidthOveruseCharge;
+    }
+
+    public int getResourceVolumeLimit() {
+        return resourceVolumeLimit;
+    }
+
+    public void setResourceVolumeLimit(int resourceVolumeLimit) {
+        this.resourceVolumeLimit = resourceVolumeLimit;
+    }
+
+    public Cash getResourceVolumeOveruseCharge() {
+        return resourceVolumeOveruseCharge;
+    }
+
+    public void setResourceVolumeOveruseCharge(Cash resourceVolumeOveruseCharge) {
+        this.resourceVolumeOveruseCharge = resourceVolumeOveruseCharge;
+    }
+
+    public int getCartridgeCPUHourLimit() {
+        return cartridgeCPUHourLimit;
+    }
+
+    public void setCartridgeCPUHourLimit(int cartridgeCPUHourLimit) {
+        this.cartridgeCPUHourLimit = cartridgeCPUHourLimit;
+    }
+
+    public Cash getCartridgeCPUOveruseCharge() {
+        return cartridgeCPUOveruseCharge;
+    }
+
+    public void setCartridgeCPUOveruseCharge(Cash cartridgeCPUOveruseCharge) {
+        this.cartridgeCPUOveruseCharge = cartridgeCPUOveruseCharge;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (o == null || getClass() != o.getClass()) {
+            return false;
+        }
+
+        Item item = (Item) o;
+
+        if (name != null ? !name.equals(item.name) : item.name != null) {
+            return false;
+        }
+
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        return name != null ? name.hashCode() : 0;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Payment.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Payment.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Payment.java
new file mode 100644
index 0000000..e99f5d7
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Payment.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.dataobjects;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+public class Payment {
+    int id;
+    Date date;
+    Cash amount;
+    String description;
+    List<Subscription> subscriptions;
+    Invoice invoice;
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public Date getDate() {
+        if(date!=null){
+            return new Date(date.getTime());
+        }else{
+            return null;
+        }
+    }
+
+    public void setDate(Date date) {
+        if(date!=null){
+            this.date = new Date(date.getTime());
+        }else{
+            this.date = null;
+        }
+    }
+
+    public Cash getAmount() {
+        return amount;
+    }
+
+    public void setAmount(Cash amount) {
+        this.amount = amount;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public List<Subscription> getSubscriptions() {
+        return subscriptions;
+    }
+
+    public void setSubscriptions(List<Subscription> subscriptions) {
+        this.subscriptions = subscriptions;
+    }
+
+    public void addSubscription(Subscription subscription) {
+        if (this.subscriptions == null) {
+            this.subscriptions = new ArrayList<Subscription>();
+        }
+        subscriptions.add(subscription);
+    }
+
+    public Invoice getInvoice() {
+        return invoice;
+    }
+
+    public void setInvoice(Invoice invoice) {
+        this.invoice = invoice;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Subscription.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Subscription.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Subscription.java
new file mode 100644
index 0000000..0b9fbf3
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/dataobjects/Subscription.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.dataobjects;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Subscription class - information on subscriptions which the users
+ * are subscribed to.
+ */
+public class Subscription {
+    int id;
+    Date activeSince;
+    Date activeUntil;
+    Item item;
+    Customer customer;
+    boolean active;
+    int invoiceSubscriptionId = -1; // requires only if associated with an invoice
+    List<Payment> payments;
+    String subscriptionPlan;        //i.e. multitenance-small, multitencay-medium .....
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public Date getActiveSince() {
+        if(activeSince!=null){
+            return  new Date(activeSince.getTime());
+        }else{
+            return null;
+        }
+    }
+
+    public void setActiveSince(Date activeSince) {
+        if(activeSince!=null){
+            this.activeSince = new Date(activeSince.getTime());
+        }else{
+            this.activeSince = null;
+        }
+
+    }
+
+    public Date getActiveUntil() {
+        if(activeUntil!=null){
+            return  new Date(activeUntil.getTime());
+        }else{
+            return null;
+        }
+    }
+
+    public void setActiveUntil(Date activeUntil) {
+        if(activeUntil!=null){
+            this.activeUntil = new Date(activeUntil.getTime());
+        }else{
+            this.activeUntil = null;
+        }
+
+    }
+
+    public Item getItem() {
+        return item;
+    }
+
+    public void setItem(Item item) {
+        this.item = item;
+    }
+
+    public Customer getCustomer() {
+        return customer;
+    }
+
+    public void setCustomer(Customer customer) {
+        this.customer = customer;
+    }
+
+    public boolean isActive() {
+        return active;
+    }
+
+    public void setActive(boolean active) {
+        this.active = active;
+    }
+
+    public int getInvoiceSubscriptionId() {
+        return invoiceSubscriptionId;
+    }
+
+    public void setInvoiceSubscriptionId(int invoiceSubscriptionId) {
+        this.invoiceSubscriptionId = invoiceSubscriptionId;
+    }
+
+    public List<Payment> getPayments() {
+        return payments;
+    }
+
+    public void setPayments(List<Payment> payments) {
+        this.payments = payments;
+    }
+
+    public String getSubscriptionPlan() {
+        return subscriptionPlan;
+    }
+
+    public void setSubscriptionPlan(String subscriptionPlan) {
+        this.subscriptionPlan = subscriptionPlan;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/DefaultFinalizingHandler.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/DefaultFinalizingHandler.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/DefaultFinalizingHandler.java
new file mode 100644
index 0000000..cadc052
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/DefaultFinalizingHandler.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.handlers;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.billing.core.BillingEngineContext;
+import org.wso2.carbon.billing.core.BillingException;
+import org.wso2.carbon.billing.core.BillingHandler;
+import org.wso2.carbon.billing.core.BillingManager;
+import org.wso2.carbon.billing.core.dataobjects.Customer;
+import org.wso2.carbon.billing.core.dataobjects.Invoice;
+import org.wso2.carbon.billing.core.dataobjects.Item;
+import org.wso2.carbon.billing.core.dataobjects.Subscription;
+import org.wso2.carbon.billing.core.jdbc.DataAccessObject;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Stores the generated invoice in the billing database.
+ */
+public class DefaultFinalizingHandler implements BillingHandler {
+
+    private static Log log = LogFactory.getLog(DefaultFinalizingHandler.class);
+    public void init(Map<String, String> handlerConfig) throws BillingException {
+        // nothing to initialize
+    }
+
+    public void execute(BillingEngineContext handlerContext) throws BillingException {
+        // saving the bill
+        saveInvoice(handlerContext);
+    }
+
+    private void saveInvoice(BillingEngineContext handlerContext) throws BillingException {
+        DataAccessObject dataAccessObject = BillingManager.getInstance().getDataAccessObject();
+        List<Subscription> subscriptions = handlerContext.getSubscriptions();
+        Map<Integer, Invoice> invoiceMap = new HashMap<Integer, Invoice>();
+        
+        for (Subscription subscription : subscriptions) {
+            Customer customer = subscription.getCustomer();
+            Invoice invoice = customer.getActiveInvoice();
+            if (invoiceMap.get(customer.getId()) == null) {
+                invoiceMap.put(customer.getId(), invoice);
+            }
+        }
+
+        // from the invoice set we are calculating the purchase orders
+        for (Invoice invoice : invoiceMap.values()) {
+            // save the invoice first
+            dataAccessObject.addInvoice(invoice);
+            subscriptions = invoice.getSubscriptions();
+            for (Subscription subscription : subscriptions) {
+                // associate the subscription with the invoice.
+                int invoiceSubscriptionId =
+                        dataAccessObject.addInvoiceSubscription(invoice, subscription);
+                // now iterate all the items and save it in invoice subscription item space
+                if (subscription.getItem() != null) {
+                    addInvoiceSubscriptionItem(subscription.getItem(), invoiceSubscriptionId);
+                }
+            }
+        }
+        log.info( invoiceMap.size() + " Invoices saved to the database");
+    }
+
+    private void addInvoiceSubscriptionItem(Item item, 
+                                            int invoiceSubscriptionId) throws BillingException {
+        DataAccessObject dataAccessObject = BillingManager.getInstance().getDataAccessObject();
+        dataAccessObject.addInvoiceSubscriptionItem(item, invoiceSubscriptionId);
+        // and iterate through all the item children
+        if (item.getChildren() != null) {
+            for (Item subItem : item.getChildren()) {
+                addInvoiceSubscriptionItem(subItem, invoiceSubscriptionId);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/DefaultSubscriptionFeedingHandler.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/DefaultSubscriptionFeedingHandler.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/DefaultSubscriptionFeedingHandler.java
new file mode 100644
index 0000000..0dc39e1
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/DefaultSubscriptionFeedingHandler.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.handlers;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.billing.core.BillingEngineContext;
+import org.wso2.carbon.billing.core.BillingException;
+import org.wso2.carbon.billing.core.BillingHandler;
+import org.wso2.carbon.billing.core.BillingManager;
+import org.wso2.carbon.billing.core.dataobjects.Customer;
+import org.wso2.carbon.billing.core.dataobjects.Item;
+import org.wso2.carbon.billing.core.dataobjects.Subscription;
+import org.wso2.carbon.billing.core.jdbc.DataAccessObject;
+import org.wso2.carbon.billing.core.utilities.CustomerUtils;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * This class finds all relevant subscription entries for
+ * the period considered in billing (i.e. billing cycle)
+ */
+public class DefaultSubscriptionFeedingHandler implements BillingHandler {
+
+    private static Log log = LogFactory.getLog(DefaultSubscriptionFeedingHandler.class);
+
+    public void init(Map<String, String> handlerConfig) throws BillingException {
+        // nothing to initialize
+    }
+
+    /**
+     *
+     * @param handlerContext - BillingEngineContext which keeps the data
+     * used in the bill generation process
+     * @throws BillingException
+     */
+    public void execute(BillingEngineContext handlerContext) throws BillingException {
+        feedSubscriptions(handlerContext);
+    }
+
+    /**
+     * Finds the subscription of all the tenants applicable for the period being
+     * considered in bill generation
+     * @param handlerContext
+     * @throws BillingException
+     */
+    private void feedSubscriptions(BillingEngineContext handlerContext) throws BillingException {
+        // get the subscriptions right here..
+        Customer customer = handlerContext.getCustomer();
+        List<Subscription> subscriptions = getFilteredActiveSubscriptions(null, customer);
+        // prepare the handler context
+        handlerContext.setSubscriptions(subscriptions);
+        String infoMsg = "Subscription feeding phase completed. ";
+        if (subscriptions!=null){
+            infoMsg += subscriptions.size() + " subscriptions fed. ";
+        }else{
+            infoMsg += "0 subscriptions fed. ";
+        }
+        log.info(infoMsg);
+    }
+
+    /**
+     *
+     * @param filter - currently we pass the string "multitencay" because we
+     * need all the subscriptions. But, if you want subscriptions of a specific usage plan
+     * then you can pass it here. 
+     * @param customer - if generating an interim invoice, this is applicable.
+     * otherwise this will be null
+     * @return a list of subscriptions
+     * @throws BillingException
+     */
+    private List<Subscription> getFilteredActiveSubscriptions(String filter,
+                                                Customer customer) throws BillingException {
+        DataAccessObject dataAccessObject = BillingManager.getInstance().getDataAccessObject();
+        List<Subscription> subscriptions = null;
+        try {
+            dataAccessObject.beginTransaction();
+            if (customer == null) {
+                subscriptions = dataAccessObject.getFilteredActiveSubscriptions(filter);
+            } else {
+                subscriptions = dataAccessObject.getFilteredActiveSubscriptionsForCustomer(filter,
+                                                                                           customer);
+            }
+
+            // iterate through all the subscriptions and assign correct customer and item
+            for (Subscription subscription : subscriptions) {
+                Customer dummyCustomer = subscription.getCustomer();
+                Customer correctCustomer = getCustomer(dummyCustomer.getId());
+                subscription.setCustomer(correctCustomer);
+
+                Item dummyItem = subscription.getItem();
+                Item correctItem = getItem(dummyItem.getId());
+                subscription.setItem(correctItem);
+            }
+            dataAccessObject.commitTransaction();
+        }catch(Exception e){
+            String msg = "Error occurred while feeding subscription entries: " +
+                            e.getMessage();
+            log.error(msg);
+            dataAccessObject.rollbackTransaction();
+            throw new BillingException(msg, e);
+        }
+        return subscriptions;
+    }
+
+    /**
+     * Gets the billable item for a subscription
+     * @param itemId in the subscription entry
+     * @return the item retrieved from the db
+     * @throws BillingException
+     */
+    private Item getItem(int itemId) throws BillingException {
+        DataAccessObject dataAccessObject = BillingManager.getInstance().getDataAccessObject();
+        Item item = null;
+        try {
+            dataAccessObject.beginTransaction();
+            item = dataAccessObject.getItem(itemId);
+            dataAccessObject.commitTransaction();
+        } catch(Exception e){
+            String msg = "Error occurred while retrieving item for item id: " + itemId +
+                            ": " + e.getMessage();
+            dataAccessObject.rollbackTransaction();
+            throw new BillingException(msg, e);
+        }
+        return item;
+    }
+
+    private Customer getCustomer(int customerId) throws BillingException {
+        Customer customer = new Customer();
+        CustomerUtils.fillCustomerData(customerId, customer);
+        return customer;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-stratos/blob/ee2ab783/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/EmailSendingHandler.java
----------------------------------------------------------------------
diff --git a/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/EmailSendingHandler.java b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/EmailSendingHandler.java
new file mode 100644
index 0000000..0990d74
--- /dev/null
+++ b/components/stratos/billing/org.apache.stratos.billing.core/2.1.3/src/main/java/org/wso2/carbon/billing/core/handlers/EmailSendingHandler.java
@@ -0,0 +1,311 @@
+/*
+ * Copyright (c) 2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.wso2.carbon.billing.core.handlers;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.wso2.carbon.billing.core.BillingConstants;
+import org.wso2.carbon.billing.core.BillingEngineContext;
+import org.wso2.carbon.billing.core.BillingException;
+import org.wso2.carbon.billing.core.BillingHandler;
+import org.wso2.carbon.billing.core.dataobjects.Cash;
+import org.wso2.carbon.billing.core.dataobjects.Customer;
+import org.wso2.carbon.billing.core.dataobjects.Invoice;
+import org.wso2.carbon.billing.core.dataobjects.Item;
+import org.wso2.carbon.billing.core.dataobjects.Payment;
+import org.wso2.carbon.billing.core.dataobjects.Subscription;
+import org.wso2.carbon.billing.core.internal.Util;
+import org.wso2.carbon.stratos.common.constants.StratosConstants;
+import org.wso2.carbon.stratos.common.util.ClaimsMgtUtil;
+import org.wso2.carbon.stratos.common.util.CommonUtil;
+import org.wso2.carbon.email.sender.api.BulkEmailSender;
+import org.wso2.carbon.email.sender.api.EmailDataHolder;
+import org.wso2.carbon.email.sender.api.EmailSender;
+import org.wso2.carbon.email.sender.api.EmailSenderConfiguration;
+import org.wso2.carbon.user.api.TenantManager;
+import org.wso2.carbon.user.core.tenant.Tenant;
+import org.wso2.carbon.utils.CarbonUtils;
+
+import java.io.File;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Handles the email notifications after the bill generation
+ */
+public class EmailSendingHandler implements BillingHandler {
+    private static Log log = LogFactory.getLog(EmailSendingHandler.class);
+    private static String DEFAULT_EMAIL_NOTIFICATION_TEMPLATE_FILE = "email-billing-notification.xml";
+    private static String DEFAULT_REPORT_EMAIL_TEMPLATE_FILE = "email-bill-generated.xml";
+    private static String EMAIL_SENDING_CONF_KEY = "file";
+    private static String REPORT_EMAIL_TO_ADDRESS ="cloudservice@wso2.com";
+    BulkEmailSender bulkEmailSender;
+    EmailSender reportMailSender;
+
+    public void init(Map<String, String> handlerConfig) throws BillingException {
+        if(CommonUtil.getStratosConfig()!=null){
+            REPORT_EMAIL_TO_ADDRESS = CommonUtil.getStratosConfig().getNotificationEmail();
+        }
+        
+        String confFileName = handlerConfig.get(EMAIL_SENDING_CONF_KEY);
+        if (confFileName == null) {
+            confFileName = DEFAULT_EMAIL_NOTIFICATION_TEMPLATE_FILE;
+        }
+        confFileName = CarbonUtils.getCarbonConfigDirPath() + File.separator
+                       +StratosConstants.EMAIL_CONFIG+ File.separator + confFileName;
+
+        EmailSenderConfiguration emailSenderConfig =
+                EmailSenderConfiguration.loadEmailSenderConfiguration(confFileName);
+        bulkEmailSender = new BulkEmailSender(emailSenderConfig);
+
+        //this is the email sent to the admin after bill generation
+        String reportMailFileName = DEFAULT_REPORT_EMAIL_TEMPLATE_FILE;
+        reportMailFileName = CarbonUtils.getCarbonConfigDirPath() + File.separator
+                             +StratosConstants.EMAIL_CONFIG+File.separator+ reportMailFileName;
+
+        EmailSenderConfiguration reportEmailSenderConfig =
+                EmailSenderConfiguration.loadEmailSenderConfiguration(reportMailFileName);
+        reportMailSender = new EmailSender(reportEmailSenderConfig);
+
+    }
+
+    public void execute(BillingEngineContext handlerContext) throws BillingException {
+        List<Subscription> subscriptions = handlerContext.getSubscriptions();
+        Map<Integer, Invoice> invoiceMap = new HashMap<Integer, Invoice>();
+        List<Integer> creditLimitExceededCustomers = new ArrayList<Integer>();
+        //this holds the data to be sent to bulk email bulkEmailSender
+        List<EmailDataHolder> emailDataList = new ArrayList<EmailDataHolder>();
+        
+        for (Subscription subscription : subscriptions) {
+            Customer customer = subscription.getCustomer();
+            Invoice invoice = customer.getActiveInvoice();
+            if (invoiceMap.get(customer.getId()) == null) {
+                invoiceMap.put(customer.getId(), invoice);
+            }
+        }
+
+        for (Invoice invoice : invoiceMap.values()) {
+
+            //checkinh whether the carried forward is $0 because we dont want to
+            //send emails for $0 bills
+            Cash diff = Cash.subtract(new Cash("$0"), invoice.getCarriedForward());
+            if(diff.getSign().equals(Cash.Sign.NEGATIVE)){
+                Map<String, String> mailParameters = deriveInvoiceMailParameters(invoice);
+                Customer customer = invoice.getCustomer();
+                String emailAddress = customer.getEmail();
+                EmailDataHolder emailData = new EmailDataHolder();
+                emailData.setEmail(emailAddress);
+                emailData.setEmailParameters(mailParameters);
+                //we keep the data in the list to be sent as bulk
+                emailDataList.add(emailData);
+            }
+
+            //adding the customers who have exceeded the credit limit
+            // to a list to be informed to the admin
+            if(isExceedsCreditLimit(invoice)){
+                log.debug("Customer " + invoice.getCustomer().getName() + " needs to be reported");
+                creditLimitExceededCustomers.add(invoice.getCustomer().getId());
+            }
+
+        }
+
+        try {
+            log.info("Sending emails to the customers: " + emailDataList.size());
+            bulkEmailSender.sendBulkEmails(emailDataList);
+            log.info("Email (invoices) sending completed");
+        } catch (Exception e) {
+            String msg = "Error in sending the invoices to the customers";
+            log.error(msg, e);
+        }
+        //now sending the email with customers who have exceeded the credit limit
+        Map<String, String> reportEmailParameters = deriveReportEmailParameters(creditLimitExceededCustomers, invoiceMap);
+        try {
+            reportMailSender.sendEmail(REPORT_EMAIL_TO_ADDRESS, reportEmailParameters);
+            log.info("Email sent to the admin.");
+        } catch (Exception e) {
+            String msg = "Error in sending the bill generation completed email";
+            log.error(msg, e);
+        }
+
+    }
+
+    public static Map<String, String> deriveInvoiceMailParameters(Invoice invoice) {
+        Map<String, String> mailParameters = new HashMap<String, String>();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy");
+        mailParameters.put("start-date", dateFormat.format(invoice.getStartDate()));
+        mailParameters.put("end-date", dateFormat.format(invoice.getEndDate()));
+
+        Customer customer = invoice.getCustomer();
+
+        try{
+            TenantManager tenantManager = Util.getRealmService().getTenantManager();
+            Tenant tenant = (Tenant) tenantManager.getTenant(customer.getId());
+            mailParameters.put("tenant-domain", tenant.getDomain());
+            String customerName =
+                    ClaimsMgtUtil.getFirstName(Util.getRealmService(), customer.getId());
+            if(customerName!=null){
+                mailParameters.put("customer-name", customerName);
+            }else{
+                mailParameters.put("customer-name", "");
+            }
+
+        }catch(Exception e){
+            log.error("Could not get tenant information for tenant: " +
+                    customer.getName() + "\n" + e.getMessage());
+            mailParameters.put("customer-name", "");
+        }
+
+        List<Subscription> subscriptions = invoice.getSubscriptions();
+        if (subscriptions != null) {
+            StringBuffer subscriptionText = new StringBuffer();
+            for (Subscription subscription : subscriptions) {
+
+                if(subscription.isActive()){
+                    mailParameters.put("current-subscription", subscription.getSubscriptionPlan());
+                }
+                Item item = subscription.getItem();
+                String itemName = item.getDescription();
+                Cash itemCost = item.getCost();
+
+                String subscriptionPlan = subscription.getSubscriptionPlan();
+                if(itemCost!=null){
+                    subscriptionText.append(subscriptionPlan).append("\t\t\t").append(itemCost.toString()).append("\n");
+                }else{
+                    subscriptionText.append(subscriptionPlan).append("\n");
+                }
+
+                List<? extends Item> children = item.getChildren();
+                if (children != null) {
+                    for (Item childItem : children) {
+                        String childItemName = childItem.getDescription();
+                        Cash childItemCost = childItem.getCost();
+                        String childItemCostStr;
+                        if(childItemCost!=null){
+                            childItemCostStr = childItemCost.toString();
+                        }else{
+                            childItemCostStr = "$0.00";
+                        }
+                        subscriptionText.append("\t").append(childItemName).append("\t\t")
+                                .append(childItemCostStr).append("\n");
+                    }
+                }
+                subscriptionText.append("-------------------------------------------").append("\n");
+            }
+            mailParameters.put("subscription-charges", subscriptionText.toString());
+        }
+
+        StringBuffer paymentText = new StringBuffer();
+        if (invoice.getPayments() != null && invoice.getPayments().size()>0) {
+            for (Payment payment : invoice.getPayments()) {
+                Date paymentDate = payment.getDate();
+                Cash paymentAmount = payment.getAmount();
+
+                paymentText.append(dateFormat.format(paymentDate)).append("\t\t")
+                        .append(paymentAmount.toString()).append("\n");
+            }
+        }else{
+            paymentText.append("No payment details during this period");
+        }
+        mailParameters.put("payment-details", paymentText.toString());
+
+        if (invoice.getBoughtForward() != null) {
+            mailParameters.put("bought-forward", invoice.getBoughtForward().toString());
+        } else {
+            mailParameters.put("bought-forward", "$0");
+        }
+        if (invoice.getTotalCost() != null) {
+            mailParameters.put("total-cost", invoice.getTotalCost().toString());
+        } else {
+            mailParameters.put("total-cost", "$0");
+        }
+        if (invoice.getTotalPayment() != null) {
+            mailParameters.put("total-payments", invoice.getTotalPayment().toString());
+        } else {
+            mailParameters.put("total-payments", "$0");
+        }
+        if (invoice.getCarriedForward() != null) {
+            mailParameters.put("carried-forward", invoice.getCarriedForward().toString());
+        } else {
+            mailParameters.put("carried-forward", "$0");
+        }
+
+        return mailParameters;
+    }
+
+    private boolean isExceedsCreditLimit(Invoice invoice) throws BillingException{
+        boolean exceedsCreditLimit = false;
+        Cash creditLimit = new Cash("$0");
+        List<Subscription> subscriptions = invoice.getSubscriptions();
+        for(Subscription subscription : subscriptions){
+            if(subscription.isActive()){
+                List<? extends Item> subItems = subscription.getItem().getChildren();
+                for (Item item : subItems){
+                    if(BillingConstants.SUBSCRIPTION_SUBITEM.equals(item.getName())){
+                        if(item.getCreditLimit()!=null){
+                            creditLimit = Cash.add(creditLimit, item.getCreditLimit());
+                        }else{
+                            creditLimit = Cash.add(creditLimit, new Cash("$0"));
+                        }
+                        break;
+                    }
+                }
+                break;
+            }
+        }
+
+        Cash difference = Cash.subtract(invoice.getCarriedForward(), creditLimit);
+        if(Cash.Sign.POSITIVE == difference.getSign() && difference.getWholeNumber()>0){
+            exceedsCreditLimit = true;
+        }
+        return exceedsCreditLimit;
+    }
+
+    public Map<String, String> deriveReportEmailParameters(List<Integer> creditExceededCustomers, Map<Integer, Invoice> invoiceMap){
+        Map<String, String> mailParameters = new HashMap<String, String>();
+
+        SimpleDateFormat dateFormat = new SimpleDateFormat("dd-MMM-yyyy");
+        //note that I haven't considered the timezone here
+        mailParameters.put("date", dateFormat.format(new Date()));
+
+        StringBuffer reportedCustomers = new StringBuffer();
+        if(creditExceededCustomers.isEmpty()){
+            reportedCustomers.append("No customers to be reported");
+        }else{
+            for(Integer customerId : creditExceededCustomers){
+                Invoice invoice = invoiceMap.get(customerId);
+                List<Subscription> subscriptions = invoice.getSubscriptions();
+                String activeSubscriptionName = "";
+                for(Subscription subscription : subscriptions){
+                    if(subscription.isActive()){
+                        activeSubscriptionName = subscription.getSubscriptionPlan();
+                        break;
+                    }
+                }
+                reportedCustomers.append(invoice.getCustomer().getName()).append("\t\t").
+                        append(activeSubscriptionName).append("\t\t").append(invoice.getCarriedForward().toString()).
+                        append("\n");
+            }
+        }
+        mailParameters.put("reported-customers", reportedCustomers.toString());
+
+        return mailParameters;
+    }    
+}