/* ====================================================================
* Limited Evaluation License:
*
* This software is open source, but licensed. The license with this package
* is an evaluation license, which may not be used for productive systems. If
* you want a full license, please contact us.
*
* The exclusive owner of this work is the OpenRate project.
* This work, including all associated documents and components
* is Copyright of the OpenRate project 2006-2015.
*
* The following restrictions apply unless they are expressly relaxed in a
* contractual agreement between the license holder or one of its officially
* assigned agents and you or your organisation:
*
* 1) This work may not be disclosed, either in full or in part, in any form
* electronic or physical, to any third party. This includes both in the
* form of source code and compiled modules.
* 2) This work contains trade secrets in the form of architecture, algorithms
* methods and technologies. These trade secrets may not be disclosed to
* third parties in any form, either directly or in summary or paraphrased
* form, nor may these trade secrets be used to construct products of a
* similar or competing nature either by you or third parties.
* 3) This work may not be included in full or in part in any application.
* 4) You may not remove or alter any proprietary legends or notices contained
* in or on this work.
* 5) This software may not be reverse-engineered or otherwise decompiled, if
* you received this work in a compiled form.
* 6) This work is licensed, not sold. Possession of this software does not
* imply or grant any right to you.
* 7) You agree to disclose any changes to this work to the copyright holder
* and that the copyright holder may include any such changes at its own
* discretion into the work
* 8) You agree not to derive other works from the trade secrets in this work,
* and that any such derivation may make you liable to pay damages to the
* copyright holder
* 9) You agree to use this software exclusively for evaluation purposes, and
* that you shall not use this software to derive commercial profit or
* support your business or personal activities.
*
* This software is provided "as is" and any expressed or impled warranties,
* including, but not limited to, the impled warranties of merchantability
* and fitness for a particular purpose are disclaimed. In no event shall
* The OpenRate Project or its officially assigned agents be liable to any
* direct, indirect, incidental, special, exemplary, or consequential damages
* (including but not limited to, procurement of substitute goods or services;
* Loss of use, data, or profits; or any business interruption) however caused
* and on theory of liability, whether in contract, strict liability, or tort
* (including negligence or otherwise) arising in any way out of the use of
* this software, even if advised of the possibility of such damage.
* This software contains portions by The Apache Software Foundation, Robert
* Half International.
* ====================================================================
*/
package OpenRate.cache;
import OpenRate.OpenRate;
import OpenRate.configurationmanager.ClientManager;
import OpenRate.db.DBUtil;
import OpenRate.exception.InitializationException;
import OpenRate.logging.LogUtil;
import OpenRate.record.TimePacket;
import OpenRate.utils.PropertyUtils;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
/**
* This class implements the time model that can evaluate the date and time of
* the CDR to find the corresponding time segment that the call was made in
* (peak/off-peak etc). The CDR lookup enters the lookup with the name of the
* Logic to search the model, and then use the date and time of the CDR to
* locate the time segment to be used.
*
* The day range used in this is the "Calendar" object, minus 1 i.e. 0 = Sunday
* ... 6 = Saturday
*
* The format of the data to be loaded into the cache is:
*
* Model: Model The identifier of the model Day The idenitifier of the day,
* mapped if necessary through the "day map" startTime The start time of the
* period, in the format HH:MM endTime The end time of the period, in the format
* HH:MM timeResult The result of the mapping
*
* NOTE: that the end times should be defined EXCLUSIVE so that the last minute
* of the day is 23:59 NOT 00:00
*
* @author i.sparkes
*/
public class TimeModelCache
extends AbstractSyncLoaderCache {
// List of Services that this Client supports
private final static String SERVICE_OBJECT_COUNT = "ObjectCount";
private final static String SERVICE_GROUP_COUNT = "GroupCount";
// Queries we will be using to get the data
private String ModelSelectQuery;
private String MappingSelectQuery;
private String DayMappingSelectQuery;
private PreparedStatement StmtModelSelectQuery;
private PreparedStatement StmtMappingSelectQuery;
private PreparedStatement StmtDayMappingSelectQuery;
// this is the persistent result set that we use to incrementally get the records
private ResultSet mrsa = null;
private ResultSet mrsb = null;
private ResultSet mrsc = null;
// This is used to control non-default day mapping loading
private boolean dayMapDefined = false;
/**
* this is the name of the method we are to use in the case that the method
* data source has been defined for loading the day map
*/
protected static String DayCacheMethodName = null;
/**
* this is the name of the method we are to use in the case that the method
* data source has been defined for loading the time model map
*/
protected static String MapCacheMethodName = null;
/**
* this is the name of the method we are to use in the case that the method
* data source has been defined for loading the time model map
*/
protected static String ModelCacheMethodName = null;
/**
* A TimeInterval is a part of a time model. A model is made up of a list of
* intervals that cover the whole of the possible 24 hour x 7 days
*/
private class TimeIntervalNode {
int TimeFrom;
int TimeTo;
String Result = "NEW";
TimeIntervalNode child = null;
}
/**
* A TimeMap is the list of intervals that make up the whole map.
*/
private class TimeMap {
// The vectors for the individual days
TimeIntervalNode[] Intervals;
}
/**
* This holds all of the configurations that make up a time model.
*/
private final HashMap<String, TimeMap> TimeModelCache;
/**
* This is the cache for the model definitions - we enter with an identifier
* and this returns the time model to use
*/
private final HashMap<String, String> ModelCache;
/**
* This is the cache for the model definitions - we enter with an identifier
* and this returns the time model to use
*/
private final HashMap<String, String> DayCache;
/**
* The default return when there is no match
*/
public static final String NO_TIME_MATCH = "NOMATCH";
/**
* Constructor Creates a new instance of the Time Model Cache. The Cache
* contains all of the TimeModels and Days that are known to the module. The
* lookup is performed within the time model and the day, calculated from the
* CDR date retrieveing the match for the day and model map. We can support a
* maximum of 200 Model/Days at the moment.
*/
public TimeModelCache() {
super();
// Initialise the cache objects
TimeModelCache = new HashMap<>(200);
ModelCache = new HashMap<>(100);
DayCache = new HashMap<>(7);
// Call to default days
addDefaultDays();
}
// Adding Default Days
private void addDefaultDays() {
addDay("0", "0"); // Sunday
addDay("1", "1"); // Monday
addDay("2", "2"); // Tuesday
addDay("3", "3"); // Wednesday
addDay("4", "4"); // Thursday
addDay("5", "5"); // Friday
addDay("6", "6"); // Saturday
}
/**
* Add the model mapping between the plan and the model. The plan is generally
* a name, while the model is where the intervals are stored.
*
* @param Plan The name of the plan
* @param Model The model that holds the intervals
*/
public void addModel(String Plan, String Model) {
ModelCache.put(Plan, Model);
}
/**
* Add a day to the day mapping cache. This allows the days as represented in
* the external database to have different idenitfiers to the representation
* in the cache. Internally, the days are integers, running from 0 (Sunday) to
* 6 (Saturday)
*
* @param name The name of the day to add to the map
* @param value The value of the day value to add
*/
public void addDay(String name, String value) {
DayCache.put(name, value);
}
/**
* Add a value into the TimeModelCache, defining the result value that should
* be returned in the case of a match.
*
* @param Model The time model to add the interval to
* @param From The time interval
* @param Day The day the interval covers
* @param To The time from for the interval (hh:mm)
* @param ZoneResult The time interval result
* @throws InitializationException
*/
public void addInterval(String Model, String Day, String From, String To,
String ZoneResult)
throws InitializationException {
int tmpDay;
TimeMap tmpTimeMap;
String[] ZoneTimeBits;
TimeIntervalNode tmpIntervalNode;
// See if we already have the model entry for this model
if (!TimeModelCache.containsKey(Model)) {
// Create the new Model Object
tmpTimeMap = new TimeMap();
// Add to hash
TimeModelCache.put(Model, tmpTimeMap);
// Create the root nodes
tmpTimeMap.Intervals = new TimeIntervalNode[7];
} else {
// get the existing one
tmpTimeMap = TimeModelCache.get(Model);
}
// Now add the node
tmpDay = Integer.parseInt(Day);
tmpIntervalNode = tmpTimeMap.Intervals[tmpDay];
if (tmpIntervalNode == null) {
tmpIntervalNode = new TimeIntervalNode();
tmpTimeMap.Intervals[tmpDay] = tmpIntervalNode;
} else {
// find the end of the list
while (tmpIntervalNode.child != null) {
tmpIntervalNode = tmpIntervalNode.child;
}
// Add a new child
tmpIntervalNode.child = new TimeIntervalNode();
tmpIntervalNode = tmpIntervalNode.child;
}
// prepare the time from and time to
ZoneTimeBits = From.split(":");
tmpIntervalNode.TimeFrom = (Integer.parseInt(ZoneTimeBits[0]) * 60)
+ (Integer.parseInt(ZoneTimeBits[1]));
ZoneTimeBits = To.split(":");
tmpIntervalNode.TimeTo = (Integer.parseInt(ZoneTimeBits[0]) * 60)
+ (Integer.parseInt(ZoneTimeBits[1]));
// deal with the case of "00:00" as midnight
if (tmpIntervalNode.TimeTo == 0) {
// map it to 23:59
tmpIntervalNode.TimeTo = 24 * 60 - 1;
}
// basic sanity checks
if (tmpIntervalNode.TimeFrom > tmpIntervalNode.TimeTo) {
message = "From time <" + From + "> is later than To time <"
+ To + "> in model <" + Model + "> and day <" + Day
+ "> in module <" + getSymbolicName() + ">";
OpenRate.getOpenRateFrameworkLog().error(message);
throw new InitializationException(message, getSymbolicName());
}
tmpIntervalNode.Result = ZoneResult;
}
/**
* Get a value from the TimeModelCache
*
* NO TIME SPLITTING
*
* @param Plan The time model name
* @param Day The day to check
* @param Time The time to check
* @return The return value
*/
public String getEntry(String Plan, int Day, int Time) {
TimeIntervalNode tmpIntervalNode;
String Model;
int CDRMinute;
TimeMap tmpTimeMap;
boolean finished;
// Find the correct Time Model for the plan
Model = ModelCache.get(Plan);
if (Model == null) {
return NO_TIME_MATCH;
}
// Get the interval
tmpTimeMap = TimeModelCache.get(Model);
if (tmpTimeMap == null) {
OpenRate.getOpenRateFrameworkLog().warning("TimeMap for model <" + Plan + "> and day <" + Day + "> is empty in <" + getSymbolicName() + ">");
return NO_TIME_MATCH;
}
// Get the root node for the day
if (Day < 0 | Day > 6) {
OpenRate.getOpenRateFrameworkLog().warning("Day <" + Day + "> is outside of the valid range of 0 (Sunday) to 6 (Saturday)");
return NO_TIME_MATCH;
}
tmpIntervalNode = tmpTimeMap.Intervals[Day];
// Search through the Day Segments
CDRMinute = (Time);
finished = false;
// search the nodes
while (!finished) {
if (tmpIntervalNode == null) {
OpenRate.getOpenRateFrameworkLog().warning("TimeMap for model <" + Plan + "> and day <" + Day + "> is empty in <" + getSymbolicName() + ">");
return NO_TIME_MATCH;
}
if (CDRMinute >= tmpIntervalNode.TimeFrom) {
if (CDRMinute <= tmpIntervalNode.TimeTo) {
return tmpIntervalNode.Result;
}
}
if (tmpIntervalNode.child != null) {
tmpIntervalNode = tmpIntervalNode.child;
} else {
// run out of segments
finished = true;
}
}
return NO_TIME_MATCH;
}
/**
* Evaluate the time models impacted over a time range, returning the result
* as a vector of time packets.
*
* TIME SPLITTING
*
* @param TimeModel The time model we are using
* @param CDRStartDate The start date/time of the event
* @param CDREndDate The end date/time of the event
* @param gCal The calendar object to use
* @return TimePackets The list of periods impacted
*/
public ArrayList<TimePacket> getEntry(String TimeModel, long CDRStartDate, long CDREndDate, GregorianCalendar gCal) {
int TMStartDayOfWeek;
int TMStartTime;
int TMEndTime;
int TMStartSecond;
int TMEndSecond;
int TotalDuration;
// get the total duration, used for calculating the splitting factor
TotalDuration = (int) (CDREndDate - CDRStartDate);
// if we have a 0 duration call, force a duration if 1 (we can't manage a
// 0 duration call) Ticket #679460
if (TotalDuration == 0) {
TotalDuration = 1;
CDREndDate += 1;
}
// initialise the counters and return values
long tmpStartDateCounter = CDRStartDate;
long tmpEndDateCounter;
ArrayList<TimePacket> packets = new ArrayList<>(1);
ArrayList<TimePacket> dayPackets;
// get the first start of day period
gCal.setTimeInMillis(CDRStartDate * 1000);
gCal.set(Calendar.HOUR_OF_DAY, 0);
gCal.set(Calendar.MINUTE, 0);
gCal.set(Calendar.SECOND, 0);
tmpEndDateCounter = gCal.getTimeInMillis() / 1000;
// loop until we have covered the whole period
while (tmpStartDateCounter < CDREndDate) {
// round up to the next day boundary
tmpEndDateCounter += 86400;
// See if we have covered the period
if (tmpEndDateCounter > CDREndDate) {
// yes, so round to the real end date
tmpEndDateCounter = CDREndDate;
// Get the prepared end date
gCal.setTimeInMillis(tmpEndDateCounter * 1000);
TMEndTime = gCal.get(Calendar.HOUR_OF_DAY) * 60;
TMEndTime += gCal.get(Calendar.MINUTE);
TMEndSecond = gCal.get(Calendar.SECOND);
} else {
// Get the default end of day prepared information
TMEndTime = 24 * 60 - 1;
TMEndSecond = 60;
}
// prepare the information for zoning
gCal.setTimeInMillis(tmpStartDateCounter * 1000);
TMStartDayOfWeek = gCal.get(Calendar.DAY_OF_WEEK) - 1;
TMStartTime = gCal.get(Calendar.HOUR_OF_DAY) * 60;
TMStartTime += gCal.get(Calendar.MINUTE);
TMStartSecond = gCal.get(Calendar.SECOND);
// Calculate the day based on the parameters
dayPackets = getDayEntry(TimeModel, TMStartDayOfWeek, TMStartTime, TMStartSecond, TMEndTime, TMEndSecond, TotalDuration);
// add to the current list
packets.addAll(dayPackets);
dayPackets.clear();
// move on
tmpStartDateCounter = tmpEndDateCounter;
}
// return the result
return packets;
}
/**
* Get the time packets for the given day
*
* @param TimeModel The time model to evaluate for
* @param DayofWeek The day of the week we are working on
* @param StartTime The start time to evaluate for
* @param StartSecond The start second to evaluate for
* @param EndTime The end time to evaluate for
* @param EndSecond The end second to evaluate for
* @param TotalDuration The original duration of the call
* @return The time packets in the the given day
*/
private ArrayList<TimePacket> getDayEntry(String TimeModel, int DayofWeek, int StartTime, int StartSecond, int EndTime, int EndSecond, int TotalDuration) {
TimeIntervalNode tmpNode;
ArrayList<TimePacket> packets = new ArrayList<>(1);
int tmpStartTime;
int tmpEndTime;
int tmpStartSecond;
tmpStartTime = StartTime;
tmpStartSecond = StartSecond;
tmpEndTime = EndTime;
do {
tmpNode = getEntryWithNode(TimeModel, DayofWeek, tmpStartTime);
if (tmpNode != null) {
if (tmpNode.TimeTo == 24 * 60 - 1) {
if (EndTime <= tmpNode.TimeTo) {
// last packet for the day - create and we have finished
tmpEndTime = EndTime;
CreateTimePacket(packets, DayofWeek, tmpStartTime, tmpStartSecond, tmpEndTime, EndSecond, TimeModel, tmpNode.Result, TotalDuration);
break;
} else {
// normal packet
tmpEndTime = tmpNode.TimeTo;
CreateTimePacket(packets, DayofWeek, tmpStartTime, tmpStartSecond, tmpEndTime, EndSecond, TimeModel, tmpNode.Result, TotalDuration);
// update the temp variables
tmpStartTime = tmpNode.TimeTo;
tmpEndTime = EndTime;
tmpStartSecond = 0;
}
} else {
if (tmpEndTime <= tmpNode.TimeTo) {
// this covers the remaining time
CreateTimePacket(packets, DayofWeek, tmpStartTime, tmpStartSecond, tmpEndTime, EndSecond, TimeModel, tmpNode.Result, TotalDuration);
break;
} else {
// normal packet, and there is more to do
CreateTimePacket(packets, DayofWeek, tmpStartTime, tmpStartSecond, tmpNode.TimeTo, 60, TimeModel, tmpNode.Result, TotalDuration);
// Update the variables
tmpStartTime = tmpNode.TimeTo + 1;
tmpEndTime = EndTime;
tmpStartSecond = 0;
}
}
}
} while (tmpNode != null);
return packets;
}
/**
* Create a new time packet and fill it accordingly. This does no calculation
* just instead creates the packet and adds it to the packet list
*
* @param packetList The list object to hold the time packets
* @param Day The day
* @param StartTime The start time
* @param StartSecond The start
* @param EndTime The end time
* @param EndSecond The end second
* @param TimeModel The time model
* @param TimeResult The time result
*/
private void CreateTimePacket(ArrayList<TimePacket> packetList,
int Day,
int StartTime,
int StartSecond,
int EndTime,
int EndSecond,
String TimeModel,
String TimeResult,
int TotalDuration) {
TimePacket tmpPacket;
tmpPacket = new TimePacket();
tmpPacket.dayofWeek = Day;
tmpPacket.startTime = StartTime;
tmpPacket.startSecond = StartSecond;
tmpPacket.endTime = EndTime;
tmpPacket.endSecond = EndSecond;
tmpPacket.timeModel = TimeModel;
tmpPacket.timeResult = TimeResult;
tmpPacket.totalDuration = TotalDuration;
// calculate the duration
tmpPacket.duration = (EndTime - StartTime) * 60 - StartSecond + EndSecond;
packetList.add(tmpPacket);
}
/**
* Get a value from the TimeModelCache
*/
private TimeIntervalNode getEntryWithNode(String Plan, int Day, int Time) {
TimeIntervalNode tmpIntervalNode;
String Model;
int CDRMinute;
TimeMap tmpTimeMap;
boolean finished;
// Find the correct Time Model for the plan
Model = ModelCache.get(Plan);
if (Model == null) {
return null;
}
// Get the interval
tmpTimeMap = TimeModelCache.get(Model);
if (tmpTimeMap == null) {
OpenRate.getOpenRateFrameworkLog().warning("TimeMap for model <" + Plan + "> and day <" + Day + "> is empty in <" + getSymbolicName() + ">");
return null;
}
// Get the root node for the day
if (Day < 0 | Day > 6) {
OpenRate.getOpenRateFrameworkLog().warning("Day <" + Day + "> is outside of the valid range of 0 (Sunday) to 6 (Saturday)");
return null;
}
tmpIntervalNode = tmpTimeMap.Intervals[Day];
// Search through the Day Segments
CDRMinute = (Time);
finished = false;
// search the nodes
while (!finished) {
if (tmpIntervalNode == null) {
OpenRate.getOpenRateFrameworkLog().warning("TimeMap for model <" + Plan + "> and day <" + Day + "> is empty in <" + getSymbolicName() + ">");
return null;
}
if (CDRMinute >= tmpIntervalNode.TimeFrom) {
if (CDRMinute <= tmpIntervalNode.TimeTo) {
return tmpIntervalNode;
}
}
if (tmpIntervalNode.child != null) {
tmpIntervalNode = tmpIntervalNode.child;
} else {
// run out of segments
finished = true;
}
}
return null;
}
// -----------------------------------------------------------------------------
// ------------------ Start of inherited Plug In functions ---------------------
// -----------------------------------------------------------------------------
/**
* loadDataFromFile is called automatically on startup of the cache factory,
* as a result of implementing the CacheLoader interface. This will be called
* if the data source is defined as "File"
*
* @throws InitializationException
*/
@Override
public void loadDataFromFile()
throws InitializationException {
// Variable declarations
int ModelsLoaded = 0;
//int TimeModelsLoaded = 0;
int IntervalsLoaded = 0;
int LinesLoaded = 0;
BufferedReader inFile;
String tmpFileRecord;
String[] ZoneFields;
// Find the location of the zone configuration file
OpenRate.getOpenRateFrameworkLog().info("Starting Time Cache Loading from File for cache <" + getSymbolicName() + ">");
// Try to open the file
try {
inFile = new BufferedReader(new FileReader(cacheDataFile));
} catch (FileNotFoundException fnfe) {
message = "Not able to read time model data file <"
+ cacheDataFile + "> in <" + getSymbolicName() + ">";
OpenRate.getOpenRateFrameworkLog().error(message);
throw new InitializationException(message, getSymbolicName());
}
// File open, now get the stuff
try {
while (inFile.ready()) {
tmpFileRecord = inFile.readLine();
if (tmpFileRecord.startsWith("Model")) {
// Get the model name
ZoneFields = tmpFileRecord.split(";");
addInterval(ZoneFields[1], ZoneFields[2], ZoneFields[3],
ZoneFields[4], ZoneFields[5]);
IntervalsLoaded++;
LinesLoaded++;
}
if (tmpFileRecord.startsWith("Mapping")) {
// Get the model name
ZoneFields = tmpFileRecord.split(";");
addModel(ZoneFields[1], ZoneFields[2]);
ModelsLoaded++;
LinesLoaded++;
}
}
} catch (IOException ioe) {
message = "Error reading input file in <" + getSymbolicName()
+ "> at record <" + LinesLoaded + ">. IO Error message = <"
+ ioe.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
} catch (ArrayIndexOutOfBoundsException aiobe) {
message = "Error reading input file in <" + getSymbolicName()
+ "> at record <" + LinesLoaded + ">. Malformed Record.";
OpenRate.getOpenRateFrameworkLog().fatal(message);
} finally {
try {
inFile.close();
} catch (IOException ioe) {
message = "Error closing input file in <" + getSymbolicName()
+ ">. IO Error message = <" + ioe.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
}
}
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + IntervalsLoaded + "> Model intervals Loaded");
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + ModelsLoaded + "> Mappings Loaded");
OpenRate.getOpenRateFrameworkLog().info(
"Time Model Data Loading completed. <" + LinesLoaded
+ "> configuration lines loaded for <" + getSymbolicName() + " > from <"
+ cacheDataFile + ">");
}
/**
* Load the data from the defined Data Source
*
* @throws InitializationException
*/
@Override
public void loadDataFromDB()
throws InitializationException {
String Plan;
int ModelsLoaded = 0;
int IntervalsLoaded = 0;
int DaysLoaded = 0;
String To;
String From;
String Day;
String Model;
String Result;
String Name;
String Value;
// Find the location of the zone configuration file
OpenRate.getOpenRateFrameworkLog().info("Starting Time Model Cache Loading from DB for <" + getSymbolicName() + ">");
// Try to open the DS
JDBCcon = DBUtil.getConnection(cacheDataSourceName);
// Now prepare the statements
prepareStatements();
// *** Day Mappings - Only perform if the statement has been defined ***
if (dayMapDefined) {
// clear the default cache first
DayCache.clear();
// Execute the day mapping query
try {
mrsc = StmtDayMappingSelectQuery.executeQuery();
} catch (SQLException Sex) {
message = "Error performing SQL for retieving day map data in <" + getSymbolicName() + ">. message = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
// loop through the results for the mapping entries
try {
mrsc.beforeFirst();
while (mrsc.next()) {
DaysLoaded++;
Name = mrsc.getString(1);
Value = mrsc.getString(2);
addDay(Name, Value);
}
} catch (SQLException Sex) {
message = "Error performing SQL for retieving day map data in <" + getSymbolicName() + ">. message = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
// Close down stuff
try {
mrsc.close();
StmtDayMappingSelectQuery.close();
} catch (SQLException Sex) {
message = "Error closing day map data result set in <" + getSymbolicName() + ">. message = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
}
// *** Models ***
try {
mrsa = StmtModelSelectQuery.executeQuery();
} catch (SQLException Sex) {
message = "Error performing SQL for retieving time map data in <" + getSymbolicName() + ">. message = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
// loop through the results for the model entries
try {
mrsa.beforeFirst();
while (mrsa.next()) {
IntervalsLoaded++;
Model = mrsa.getString(1);
Day = DayCache.get(mrsa.getString(2));
// There was no mapping
if (Day == null) {
message = "Error reading Map Data for <" + getSymbolicName() + ">. No day map found for day value <" + mrsa.getString(2) + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
From = mrsa.getString(3);
To = mrsa.getString(4);
Result = mrsa.getString(5);
addInterval(Model, Day, From, To, Result);
}
} catch (SQLException Sex) {
message = "SQL Error reading Map Data for <" + getSymbolicName() + ">. Messge = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
// Close down stuff
try {
mrsa.close();
StmtModelSelectQuery.close();
} catch (SQLException Sex) {
message = "Error closing time map data result set in <" + getSymbolicName() + ">. message = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
// *** Mappings ***
try {
mrsb = StmtMappingSelectQuery.executeQuery();
} catch (SQLException Sex) {
message = "Error performing SQL for retieving time model data in <" + getSymbolicName() + ">. message = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
// loop through the results for the mapping entries
try {
mrsb.beforeFirst();
while (mrsb.next()) {
ModelsLoaded++;
Plan = mrsb.getString(1);
Model = mrsb.getString(2);
addModel(Plan, Model);
}
} catch (SQLException Sex) {
message = "SQL Error reading Model Data for <" + getSymbolicName() + ">. Messge = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
// Close down stuff
DBUtil.close(mrsb);
DBUtil.close(StmtMappingSelectQuery);
// Close down the connection
try {
JDBCcon.close();
} catch (SQLException Sex) {
message = "Error closing time model data result set in <" + getSymbolicName() + ">. message = <" + Sex.getMessage() + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
// check that we have complete coverage of the time models
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + IntervalsLoaded + "> Checking Model intervals");
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + IntervalsLoaded + "> Model intervals Loaded");
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + ModelsLoaded + "> Mappings Loaded");
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + DaysLoaded + "> Days Loaded");
OpenRate.getOpenRateFrameworkLog().info("Time Model Data Loading completed from <" + cacheDataSourceName + ">");
}
/**
* Load the data from the defined Data Source Method
*
* @throws InitializationException
*/
@Override
public void loadDataFromMethod()
throws InitializationException {
String Plan;
int ModelsLoaded = 0;
int IntervalsLoaded = 0;
int DaysLoaded = 0;
String To;
String From;
String Day;
String Model;
String Result;
String Name;
String Value;
ArrayList<String> tmpMethodResult;
// Find the location of the zone configuration file
OpenRate.getOpenRateFrameworkLog().info("Starting Time Model Cache Loading from Method for <" + getSymbolicName() + ">");
// Execute the user domain method
Collection<ArrayList<String>> methodLoadResultSet;
if (dayMapDefined) {
methodLoadResultSet = getMethodData(getSymbolicName(), DayCacheMethodName);
if (methodLoadResultSet == null) {
OpenRate.getOpenRateFrameworkLog().debug("No day map data returned by method <" + DayCacheMethodName
+ "> in cache <" + getSymbolicName() + ">");
} else {
Iterator<ArrayList<String>> methodDataToLoadIterator = methodLoadResultSet.iterator();
// clear the default cache first
DayCache.clear();
while (methodDataToLoadIterator.hasNext()) {
tmpMethodResult = methodDataToLoadIterator.next();
DaysLoaded++;
Name = tmpMethodResult.get(0);
Value = tmpMethodResult.get(1);
addDay(Name, Value);
}
}
}
// Now load the model intervals
methodLoadResultSet = getMethodData(getSymbolicName(), MapCacheMethodName);
if (methodLoadResultSet == null) {
OpenRate.getOpenRateFrameworkLog().warning("No model map data returned by method <" + MapCacheMethodName
+ "> in cache <" + getSymbolicName() + ">");
} else {
Iterator<ArrayList<String>> methodDataToLoadIterator = methodLoadResultSet.iterator();
while (methodDataToLoadIterator.hasNext()) {
tmpMethodResult = methodDataToLoadIterator.next();
IntervalsLoaded++;
Model = tmpMethodResult.get(0);
Day = DayCache.get(tmpMethodResult.get(1));
// There was no mapping
if (Day == null) {
message = "Error reading Map Data for <" + getSymbolicName() + ">. No day map found for day value <" + tmpMethodResult.get(1) + ">";
OpenRate.getOpenRateFrameworkLog().fatal(message);
throw new InitializationException(message, getSymbolicName());
}
From = tmpMethodResult.get(2);
To = tmpMethodResult.get(3);
Result = tmpMethodResult.get(4);
addInterval(Model, Day, From, To, Result);
}
}
// Now load the model map
methodLoadResultSet = getMethodData(getSymbolicName(), ModelCacheMethodName);
if (methodLoadResultSet == null) {
OpenRate.getOpenRateFrameworkLog().warning("No model map data returned by method <" + ModelCacheMethodName
+ "> in cache <" + getSymbolicName() + ">");
} else {
Iterator<ArrayList<String>> methodDataToLoadIterator = methodLoadResultSet.iterator();
while (methodDataToLoadIterator.hasNext()) {
tmpMethodResult = methodDataToLoadIterator.next();
ModelsLoaded++;
Plan = tmpMethodResult.get(0);
Model = tmpMethodResult.get(1);
addModel(Plan, Model);
}
}
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + IntervalsLoaded + "> Model intervals Loaded");
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + ModelsLoaded + "> Mappings Loaded");
OpenRate.getOpenRateFrameworkLog().info("Time Model Cache: <" + DaysLoaded + "> Days Loaded");
OpenRate.getOpenRateFrameworkLog().info("Time Model Data Loading completed from <" + cacheDataSourceName + ">");
}
/**
* Clear down the cache contents in the case that we are ordered to reload
*/
@Override
public void clearCacheObjects() {
TimeModelCache.clear();
ModelCache.clear();
if (dayMapDefined) {
// clear it because we have a non-default map to load
DayCache.clear();
}
}
// -----------------------------------------------------------------------------
// ---------------- Start of data base data layer functions --------------------
// -----------------------------------------------------------------------------
/**
* get the select statement(s). Implemented as a separate function so that it
* can be overwritten in implementation classes. By default the cache picks up
* the statement with the name "SelectStatement".
*
* @param ResourceName The name of the resource to load for
* @param CacheName The name of the cache to load for
* @return True if the statements were found, otherwise false
* @throws InitializationException
*/
@Override
protected boolean getDataStatements(String ResourceName, String CacheName) throws InitializationException {
// Get the Select statement
ModelSelectQuery = PropertyUtils.getPropertyUtils().getDataCachePropertyValueDef(ResourceName,
CacheName,
"ModelSelectStatement",
"None");
MappingSelectQuery = PropertyUtils.getPropertyUtils().getDataCachePropertyValueDef(ResourceName,
CacheName,
"MappingSelectStatement",
"None");
DayMappingSelectQuery = PropertyUtils.getPropertyUtils().getDataCachePropertyValueDef(ResourceName,
CacheName,
"DaySelectStatement",
"None");
// if we have a day mapping defined, note it
if (DayMappingSelectQuery.equalsIgnoreCase("None") == false) {
dayMapDefined = true;
}
if (ModelSelectQuery.equals("None") | MappingSelectQuery.equals("None")) {
return false;
} else {
return true;
}
}
/**
* get the data method to use. Implemented as a separate function so that it
* can be overwritten in implementation classes. By default the cache picks up
* the statement with the name "MethodName".
*
* @param ResourceName The name of the resource to load for
* @param CacheName The name of the cache to load for
* @return True if the statements were found, otherwise false
* @throws InitializationException
*/
@Override
protected boolean getDataMethods(String ResourceName, String CacheName) throws InitializationException {
// Get the Select statement
ModelCacheMethodName = PropertyUtils.getPropertyUtils().getDataCachePropertyValueDef(ResourceName,
CacheName,
"ModelMethodName",
"None");
MapCacheMethodName = PropertyUtils.getPropertyUtils().getDataCachePropertyValueDef(ResourceName,
CacheName,
"MapMethodName",
"None");
DayCacheMethodName = PropertyUtils.getPropertyUtils().getDataCachePropertyValueDef(ResourceName,
CacheName,
"DayMethodName",
"None");
// if we have a day mapping defined, note it
if (DayCacheMethodName.equalsIgnoreCase("None") == false) {
dayMapDefined = true;
}
if (ModelCacheMethodName.equals("None") | MapCacheMethodName.equals("None")) {
return false;
} else {
return true;
}
}
/**
* PrepareStatements creates the statements from the SQL expressions so that
* they can be run as needed.
*
* @throws InitializationException
*/
@Override
protected void prepareStatements()
throws InitializationException {
try {
// prepare the SQL for the TestStatement
StmtModelSelectQuery = JDBCcon.prepareStatement(ModelSelectQuery,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
} catch (SQLException ex) {
message = "Error preparing the statement " + ModelSelectQuery;
OpenRate.getOpenRateFrameworkLog().error(message);
throw new InitializationException(message, ex, getSymbolicName());
}
try {
// prepare the SQL for the TestStatement
StmtMappingSelectQuery = JDBCcon.prepareStatement(MappingSelectQuery,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
} catch (SQLException ex) {
message = "Error preparing the statement " + MappingSelectQuery;
OpenRate.getOpenRateFrameworkLog().error(message);
throw new InitializationException(message, ex, getSymbolicName());
}
if (dayMapDefined) {
try {
// prepare the SQL for the TestStatement
StmtDayMappingSelectQuery = JDBCcon.prepareStatement(DayMappingSelectQuery,
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_READ_ONLY);
} catch (SQLException ex) {
message = "Error preparing the statement " + DayMappingSelectQuery;
OpenRate.getOpenRateFrameworkLog().error(message);
throw new InitializationException(message, ex, getSymbolicName());
}
}
}
// -----------------------------------------------------------------------------
// ------------- Start of inherited IEventInterface functions ------------------
// -----------------------------------------------------------------------------
/**
* registerClientManager registers the client module to the ClientManager
* class which manages all the client modules available in this OpenRate
* Application.
*
* registerClientManager registers this class as a client of the ECI listener
* and publishes the commands that the plug in understands. The listener is
* responsible for delivering only these commands to the plug in.
*
* @throws OpenRate.exception.InitializationException
*/
@Override
public void registerClientManager() throws InitializationException {
// Set the client reference and the base services first
super.registerClientManager();
//Register services for this Client
ClientManager.getClientManager().registerClientService(getSymbolicName(), SERVICE_GROUP_COUNT, ClientManager.PARAM_DYNAMIC);
}
/**
* processControlEvent is the method that will be called when an event is
* received for a module that has registered itself as a client of the
* External Control Interface
*
* @param Command - command that is understand by the client module
* @param Init - we are performing initial configuration if true
* @param Parameter - parameter for the command
* @return The result string of the operation
*/
@Override
public String processControlEvent(String Command, boolean Init,
String Parameter) {
int ResultCode = -1;
// Return the number of objects in the cache
if (Command.equalsIgnoreCase(SERVICE_GROUP_COUNT)) {
return Integer.toString(TimeModelCache.size());
}
if (ResultCode == 0) {
OpenRate.getOpenRateFrameworkLog().debug(LogUtil.LogECICacheCommand(getSymbolicName(), Command, Parameter));
return "OK";
} else {
return super.processControlEvent(Command, Init, Parameter);
}
}
}