Documented by my friend @Amr Gomaa
Entity Object Work:
- - Add transient attributes
with name xxOutput and xxInput of Data Type ‘String’
- - Set xxInput to ‘Mandatory’
(Optional according to the business)
- - Add view Accessor on StpCalendarViewObject using the defined view criteria “StpCalendarLookupCriteria”
- - Default values”
·
For the date input
transient attribute add default value expression using the defined public method
with input parameter “true”: calcXX (true)
For the recalculate
expression condition: select Never
·
For the date output
transient attribute add default value expression using the defined public method
with input parameter “false”: calcXX (false)
For the recalculate
expression condition: select Never
- - Generate EntityImpl class
·
Add the following method
(which is a generic method to generate input/output fields values from DB or
date default value) into your entity Impl :
/**
* calculates the date representation values (gregorian and hijri).
* calculation against database date value and type.
* @param dateAttrIndx the date
presistent attribute index
* @param dateTypeAttrIndx the date type presistent attribute
index
* @param isInputDate true if
the data to be returned is for input date field, false for output date field
* @return
return the requested date.
*/
private String calculateDate(Integer dateAttrIndx,Integer dateTypeAttrIndx,
boolean isInputDate){
String retVal = null;
//for non nul date in database
if(getAttribute(dateAttrIndx) != null){
//create date conversion utility instance with stp_calendar view accessor
DateTypeConversionUtil dtcu = new
DateTypeConversionUtil(getStpCalendarViewAccessor());
//convert date according to database date value and type
dtcu.convertDate((Timestamp)getAttribute(dateAttrIndx),(String)getAttribute(dateTypeAttrIndx));
//check if the date to be returned is the input date or output date
if(isInputDate){
//return input date string
retVal = dtcu.getInputDateString();
}else{
//return output date string
retVal = dtcu.getOutputDateString();
}
}
return retVal;
}
·
Add the following public
method :
public String calcXX(boolean isInputDate){
return calculateDate(TERMDEFINITIONDATE,TERMDEFINITIONDATETYPE,isInputDate);
}
Where the XX represents the
date field name.
·
In the create method of the
entity Impl (after super.create() ) add the following 2 lines of code:
setAttributeInternal([index of transient attribute for date
input],calcXX(true));
setAttributeInternal([index of transient attribute for date
output],calcXX(false));
·
In the setter of date input
attribute (setXXInput) add the following code:
DateTypeConversionUtil dtcu = new
DateTypeConversionUtil(getStpCalendarViewAccessor());
try {
dtcu.convertDate(value);
value = dtcu.getInputDateString();
setXXOutput(dtcu.getOutputDateString());
setXXType(dtcu.getDateType());
setXX (dtcu.getGregorianDate());
} catch (Exception e) {
value = "?" + e.getMessage();
}
Notes:
·
XX : represents the common
name for dates attributes,
e.g. if the main attribute name is “TermDefinitionDate = XX“,
then we have
(setTermDefinitionDate, setTermDefinitionDateInput
,setTermDefinitionDateOutput, setTermDefinitionDateType).
Representing (main date attribute as Timestamp, the input date attribute
string,the converted output date string, main date type “H” or “G”)
respectively.
·
This code to be inserted in
the setter before “setAttributeInternal”
- - Add attribute validation
for the date input transient attribute as following:
·
In the business logic unit
of the entity, override the date input transient attribute.
·
Add “Script expression”
validation to that attribute with the following script:
if(newValue != null)
{
return !newValue.startsWith("?")
}else{
return true
}
·
In the failure handling,
select the failure message from the resource bundle with the following key:
com.ejada.model.entities.rules.common.DateInput_Invalid
·
Finally you will find a
token message defined below, add the following expression to define its
expression:
newValue.substring(1)
View Object Work:
-
Add the input and output
date attributes from entity to the corresponding VO
UI Page:
-
Use the two attributes in
the UI display page (the one for date input “inputText with LabeL and
auto-submit” , date other one for the converted output date “inputText
without label and disabled“).
Notes:
-
Finally Test your work with
, the valid date input with the following constrains:
·
“ddmmyyy” , dd<=31
, mm<=12,
·
No separators are added
between digits.
·
Day and month should be
represented by two digits (01,11, .. etc)
·
Valid Gregorian date after
that exists within Stp_calendar table ranging, or valid hijri date according to
Stp_Calendar table.
- StpCalendarViewObject is a read only view object get date mapping from the table in database.
<ViewObject xmlns="http://xmlns.oracle.com/bc4j" Name="StpCalendarLookup" Version="11.1.2.62.76"
BindingStyle="OracleName" CustomQuery="true" FetchMode="FETCH_AS_NEEDED" PageIterMode="Full" UseGlueCode="false">
<DesignTime>
<Attr Name="_isExpertMode" Value="true"/>
</DesignTime>
<Properties>
<SchemaBasedProperties>
<LABEL ResId="com.ejada.common.queries.StpCalendarLookup_LABEL"/>
</SchemaBasedProperties>
</Properties>
<Variable Name="inputGregorianDate" Kind="viewcriteria" Type="java.sql.Timestamp"/>
<Variable Name="inputHijriYear" Kind="viewcriteria" Type="java.lang.String"/>
<SQLQuery><![CDATA[SELECT STP_CALENDAR.H_YR H_YR, STP_CALENDAR.STRT_G_DT STRT_G_DT, STP_CALENDAR.END_G_DT END_G_DT, STP_CALENDAR.L1 L1, STP_CALENDAR.L2 L2, STP_CALENDAR.L3 L3, STP_CALENDAR.L4 L4, STP_CALENDAR.L5 L5, STP_CALENDAR.L6 L6, STP_CALENDAR.L7 L7, STP_CALENDAR.L8 L8, STP_CALENDAR.L9 L9, STP_CALENDAR.L10 L10, STP_CALENDAR.L11 L11, STP_CALENDAR.L12 L12 FROM STP_CALENDAR]]></SQLQuery>
<ViewAttribute Name="HYr" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="255" Type="java.lang.String" ColumnType="VARCHAR2" AliasName="H_YR" Expression="H_YR" SQLType="VARCHAR">
<DesignTime>
<Attr Name="_DisplaySize" Value="4"/>
</DesignTime>
</ViewAttribute>
<ViewAttribute Name="StrtGDt" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Type="java.sql.Timestamp" ColumnType="DATE" AliasName="STRT_G_DT" Expression="STRT_G_DT" SQLType="DATE"/>
<ViewAttribute Name="EndGDt" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Type="java.sql.Timestamp" ColumnType="DATE" AliasName="END_G_DT" Expression="END_G_DT" SQLType="DATE"/>
<ViewAttribute Name="L1" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L1" Expression="L1" SQLType="INTEGER"/>
<ViewAttribute Name="L2" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L2" Expression="L2" SQLType="INTEGER"/>
<ViewAttribute Name="L3" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L3" Expression="L3" SQLType="INTEGER"/>
<ViewAttribute Name="L4" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L4" Expression="L4" SQLType="INTEGER"/>
<ViewAttribute Name="L5" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L5" Expression="L5" SQLType="INTEGER"/>
<ViewAttribute Name="L6" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L6" Expression="L6" SQLType="INTEGER"/>
<ViewAttribute Name="L7" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L7" Expression="L7" SQLType="INTEGER"/>
<ViewAttribute Name="L8" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L8" Expression="L8" SQLType="INTEGER"/>
<ViewAttribute Name="L9" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L9" Expression="L9" SQLType="INTEGER"/>
<ViewAttribute Name="L10" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L10" Expression="L10" SQLType="INTEGER"/>
<ViewAttribute Name="L11" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L11" Expression="L11" SQLType="INTEGER"/>
<ViewAttribute Name="L12" IsUpdateable="false" IsPersistent="false" PrecisionRule="true" Precision="2" Scale="0" Type="java.lang.Integer" ColumnType="NUMBER" AliasName="L12" Expression="L12" SQLType="INTEGER"/>
<ViewCriteria Name="StpCalendarLookupCriteria" ViewObjectName="com.ejada.common.queries.StpCalendarLookup" Conjunction="AND">
<Properties>
<CustomProperties>
<Property Name="displayOperators" Value="InAdvancedMode"/>
<Property Name="autoExecute" Value="false"/>
<Property Name="allowConjunctionOverride" Value="true"/>
<Property Name="showInList" Value="true"/>
<Property Name="mode" Value="Basic"/>
</CustomProperties>
</Properties>
<ViewCriteriaRow Name="StpCalendarLookupCriteria_row_0" UpperColumns="1">
<ViewCriteriaItem Name="StrtGDt" ViewAttribute="StrtGDt" Operator="ONORBEFORE" Conjunction="AND" Value=":inputGregorianDate" IsBindVarValue="true" Required="Optional"/>
<ViewCriteriaItem Name="StpCalendarLookupCriteria_StpCalendarLookupCriteria_row_0_EndGDt" ViewAttribute="EndGDt" Operator="ONORAFTER" Conjunction="AND" Value=":inputGregorianDate" IsBindVarValue="true" Required="Optional"/>
</ViewCriteriaRow>
<ViewCriteriaRow Name="StpCalendarLookupCriteria_row_1" UpperColumns="1">
<ViewCriteriaItem Name="HYr" ViewAttribute="HYr" Operator="=" Conjunction="AND" Value=":inputHijriYear" IsBindVarValue="true" Required="Optional"/>
</ViewCriteriaRow>
</ViewCriteria>
<ResourceBundle>
<PropertiesBundle PropertiesFile="com.ejada.EjadaGRPServiceBundle"/>
</ResourceBundle>
</ViewObject>
- DateTypeConversionUtil is a class contain code to convert the date between Hijri and Gregorian
import oracle.jbo.RowSet;
import oracle.jbo.domain.Timestamp;
import oracle.jbo.server.ViewRowImpl;
/**
* The <code>DateTypeConversionUtil</code> class validates input date as string input.
* Then it converts the input date from Gregorian to Hijri and vice versa using Stp_Calendar view accessor.
*
* @author Amr Gomaa
*/
public class DateTypeConversionUtil {
/** Integers that represents the input date as array of : year, month and day */
private Integer[] inputDate;
/** Integers that represents the output date as array of : year, month and day */
private Integer[] outputDate;
/** Integers that represents the gregorian start date as array of : year, month and day */
private Integer[] gregorianStartDate;
/** Integers that represents the gregorian end date as array of : year, month and day */
private Integer[] gregorianEndDate;
/** Representing input date type*/
private int dateType;
/** View Accessor on the view object that queries on hijri Calendar database table (Stp_Calendar)*/
private RowSet hijriCalendarViewAccessor;
/** stp_calendar row that represents the input date hijri year.*/
private ViewRowImpl inputDateHijriYear;
/** variable that represents the gregorian date as a timestamp*/
private Timestamp gregorianDate;
/** Constant representing year field index*/
private final int YEAR = 0;
/** Constant representing month field index*/
private final int MONTH = 1;
/** Constant representing day of month field index*/
private final int DAY = 2;
/** Date validation format regex strings, ddmmyyy where:
* dayFormat : 01 --> 31
* monthFormat : 01 --> 12
* yearFormat : any four digits.
*/
/** Constant representing day format string regex*/
private final String dayFormat = "([0][1-9]|[1-2][0-9]|[3][0-1])";
/** Constant representing month format string regex*/
private final String monthFormat = "([0][1-9]|[1][0-2])";
/** Constant representing year format string regex*/
private final String yearFormat = "([0-9]{4})";
/** Constant represneting Gregorian date type */
private final int GREGORIAN_DATE = 3;
/** Constant represneting Hijri date type */
private final int HIJRI_DATE = 4;
/**
* Constructor with input of stp_calendar view accessor for hijri date validation and conversion.
* @param hijriCalendarViewAccessor stp_calendar view accessor
*/
public DateTypeConversionUtil(RowSet hijriCalendarViewAccessor) {
//store the input parameter into internal variable.
this.hijriCalendarViewAccessor = hijriCalendarViewAccessor;
//initialize input date array
this.inputDate = new Integer[3];
}
/**
* Convert input date from one type to another (Hijri to Gregorian and vice versa)
* First validates the input date (Format and value).
* Then convert date.
* @param inputDateStr input date string.
* @return returns true if conversion done successfully, false otherwise
* @throws Exception Throws Exception if input date string validation fails.
*/
public boolean convertDate(String inputDateStr)throws Exception{
boolean retVal = false;
//validate input date formate and value.
retVal = validateInputDate(inputDateStr);
//convert input date into output date if validation passed.
if(retVal){
outputDate = convertInputDateToOutputDate();
}
return retVal;
}
/**
* Converts database gregorian date into hijri date, and store them into input & output dates
* according to date type:
* Date type hijri "H" : input date hijri & output date gregorian
* Date type gregorian "G" : input date gregorian & output date hijri
* @param gregorianDateTs gregorian date from database.
* @param dateTypeStr type of input date saved in database
*/
public void convertDate(Timestamp gregorianDateTs,String dateTypeStr){
try{
inputDateHijriYear = getHijriYearData("inputGregorianDate", gregorianDateTs);
}catch(Exception e){
e.printStackTrace();
}
if(dateTypeStr.trim().contentEquals("H")){
dateType = HIJRI_DATE;
outputDate = parseGregorianDate(gregorianDateTs);
inputDate = convertGregorianToHijri(outputDate);
}else if(dateTypeStr.trim().contentEquals("G")){
dateType = GREGORIAN_DATE;
inputDate = parseGregorianDate(gregorianDateTs);
outputDate = convertGregorianToHijri(inputDate);
}
}
/**
* Validates input date string formate and value
* @param inputDateStr input date string to be checked
* @return returns true if the input date format is ok && the input date is a valid date,
* returns false otherwise.
* @throws Exception Throws Exception if the input date validation fails.
*/
private boolean validateInputDate(String inputDateStr)throws Exception{
boolean retVal = false;
//Validate input date string format
retVal = validateInputDateFormat(inputDateStr);
//check if input date string format is valid
if(retVal){
//Vaidate if input date is a valid date
retVal = validateInputDateValue(inputDateStr);
//check if input date is valid date
}
return retVal;
}
/**
* This mehtod is used to validate the input date string format.
* @param inputDateStr Input date string that to be validated.
* @return returns true if the date format validation pasess, flase otherwise
* @throws Exception Throws Exception if the input date string format is wrong.
*/
private boolean validateInputDateFormat(String inputDateStr)throws Exception{
boolean retVal = false;
// 1.Valiate input date length, should be 8 digits
if(inputDateStr.matches("([0-9]{8})")){
// 2.Validate date format as : ddmmyyyy
if(inputDateStr.matches(dayFormat+monthFormat+yearFormat)){
//date formate validation ok.
retVal = true;
}else{
throw new Exception("Wrong Date Format");
//You can make it return false otherwise
}
}else{
throw new Exception("Wrong Date Format");
//You can make it return false otherwise
}
return retVal;
}
/**
* Parses the input string into dat, month, year variables.
* Checks validity of the input date value (as Hijri or Gregorian).
* @param inputDateStr Input date string that to be validated
* @return returns true if the date value validation pasess, false otherwise
* @throws Exception Throws exception if the input date value is not valid
*/
private boolean validateInputDateValue(String inputDateStr)throws Exception{
boolean retVal = false;
//parse input date string into three integers representing : year, month, day.
parseInputDateElements(inputDateStr);
//parse the type of the input date
parseInputDateType();
//validate input date value if it is within the valid dates as Gregorian or Hijri.
retVal = validateDateValue();
return retVal;
}
/**
* Checks validity of the date value (as Hijri or Gregorian).
* @return returns true if the date value validation pasess, false otherwise
* @throws Exception Throws exception if the date value is not valid
*/
private boolean validateDateValue()throws Exception{
boolean retVal = false;
//check the input date type to be validated if Gregorian or Hijri.
if(dateType == GREGORIAN_DATE){
//validate gregorian date.
retVal = validateGregorianDate();
}else if(dateType == HIJRI_DATE){
//validate hijri date.
retVal = validateHijriDate();
}
return retVal;
}
/**
* this method validates gregorian date with consideration of month length and leap year as following:
* input day should be <= month length where:
* month length = 30 + extendedMonthFlag - februaryFlag
* extendedMonthFlag: this flag is "1" for "31 days" months, and "0" otherwise.
* februaryFlag: for input month 2 (February) --> is "1" for leap year, and "2" for non leap year
* months other than 2 this flag is "0"
* @return returns true if the gregorian date value validation pasess, false otherwise
* @throws Exception Throws exception if the gregorian date value is not valid
*/
private boolean validateGregorianDate()throws Exception{
boolean retVal = false;
//check if input day is not greater than month length.
if(inputDate[DAY] > getGregorianMonthLengh(inputDate[MONTH],inputDate[YEAR])){
throw new Exception("Wrong input date " + inputDate[DAY]+"-" + inputDate[MONTH]+"-" + inputDate[YEAR]);
}else{
//Store the input gregorian date as Timestamp with format "yyyy-mm-dd"
gregorianDate = Timestamp.toTimestamp(getDateTimestampFormat(inputDate));
//get the stp_calendar row representing the input date equivalent hijri year
inputDateHijriYear = getHijriYearData("inputGregorianDate",gregorianDate);
//check if the input gregorian date in valid in stp_calendar.
if(inputDateHijriYear != null){
//gregorian date value validation ok.
retVal = true;
}
}
return retVal;
}
/**
* this method validates hijri date using view accessor that queries on hijri calendar database table.
*
* @return returns true if the hijri date value validation pasess, false otherwise
* @throws Exception Throws exception if the hijri date value is not valid
*/
private boolean validateHijriDate()throws Exception{
boolean retVal = false;
//variable represents input month length
Integer monthLength = 0;
//get the stp_calendar row representing the input date equivalent hijri year
inputDateHijriYear = getHijriYearData("inputHijriYear",inputDate[YEAR].toString());
//get input month length from the retrived stp_calendar row.
monthLength = (Integer)inputDateHijriYear.getAttribute("L"+inputDate[MONTH].toString());
//check if input day is greater than month length as defined in the stp_calendar
if(inputDate[DAY] > monthLength){
//if input day is greater than month length as defined in the stp_calendar, then this is invalid date.
throw new Exception("Wrong input date " + inputDate[DAY]+"-" + inputDate[MONTH]+"-" + inputDate[YEAR]);
}else{
//hijri date value validation ok.
retVal = true;
}
return retVal;
}
/**
* This method is used to parse the input date string into the three representing Integers:
* Year , Month , Day
* @param inputDateStr Input date string that to be parsed
*/
private void parseInputDateElements(String inputDateStr){
//1.Parse day 2 digits (1st & 2nd chars) into inputDate[DAY] variable.
String data = inputDateStr.substring(0, 2);
inputDate[DAY] = Integer.parseInt(data);
//2.Parse Month 2 digits (3rd & 4th chars) into inputDate[MONTH] variable.
data = inputDateStr.substring(2, 4);
inputDate[MONTH] = Integer.parseInt(data);
//3.Parse Year 4 digits (5th to 8th chars) into inputDate[YEAR] variable.
data = inputDateStr.substring(4);
inputDate[YEAR] = Integer.parseInt(data);
}
/**
* This method is used to parse the input date type.
*/
private void parseInputDateType(){
//check the input year against a specific value "1800"
if(inputDate[YEAR] < 1800){
//If the input year < 1800 then it's Hijri date
dateType = HIJRI_DATE;
}else{
//If the input year > 1800 then it's Gregorian date
dateType = GREGORIAN_DATE;
}
}
/**
* Converts the gregorian date from Timestamp type into array of Integers : year, month, day
* @param gregorianTimestamp Gregorian date in Timestamp format
* @return Gregorian date as array of integers : year , month , day.
*/
private Integer[] parseGregorianDate(Timestamp gregorianTimestamp){
//get the date string of the input timestamp
String dateStr = gregorianTimestamp.toString().split("\\s")[0];
//seperate each element of the date in an index of string array.
String[] dateElements = dateStr.split("-");
//initialize array of integers to parse date elements into it
Integer[] date = new Integer[3];
//parse year string into integer array.
date[YEAR] = Integer.parseInt(dateElements[YEAR]);
//parse month string into integer array.
date[MONTH] = Integer.parseInt(dateElements[MONTH]);
//parse day string into integer array.
date[DAY] = Integer.parseInt(dateElements[DAY]);
return date;
}
/**
* Returns date type as string:
* "G" : stands for Gregorian date type.
* "H" : stands for Hijri date type.
* @return date type string.
*/
public String getDateType(){
//initize type to "G" gregorian date type
String dateTypeStr = "G";
//check if date type is Hijri
if(dateType == HIJRI_DATE){
//if date type is Hijri set date type to "H" hijri date type
dateTypeStr = "H";
}
return dateTypeStr;
}
/**
* converts input date into output date of the other type
* i.e. if the input date is Gregorian, then the output date is Hijri and vice versa.
*/
/**
* converts input date into output date of the other type
* i.e. if the input date is Gregorian, then the output date is Hijri and vice versa.
* @return the converted output date.
*/
private Integer[] convertInputDateToOutputDate(){
Integer[] tempOutputDate = null;
//check the input date type
//For gregorian input date type
if(dateType == GREGORIAN_DATE){
//convert gregorian input date into hijri output date
tempOutputDate = convertGregorianToHijri(inputDate);
//For gregorian input date type
}else if(dateType == HIJRI_DATE){
//convert hijri input date into gregorian output date
tempOutputDate = convertHijriToGregorian(inputDate);
}
return tempOutputDate;
}
/**
* converts gregorian input date into hijri output date.
* @param gregorianDate the gregorian date to be converted to hijri date.
* @return hijri date.
*/
private Integer[] convertGregorianToHijri(Integer[] gregorianDate){
Integer[] hijriDate = new Integer[3];
/**
* The following variable holds the total number of days from the start of the input's hijri year
* till the specified input date.
* It is initialized in the follwing way:
* - Add the input date day of month since it represents the days that passed of this month.
* (that number will include the first day of year as well and days of the previous hijri year
* in case of the input date month is the same as the start date month).
* - Subtract the start date day of month since it represents the number of days that are not included
* in this hijri year (that will include subtracting the first day of the year as well which to be
* compensated with the next element "1").
* - Adding "1" to number of days that represents The first day of the year to compensate the subtracted
* day within the start date day of month.
*/
int totalHijriYearDays = gregorianDate[DAY] - gregorianStartDate[DAY] + 1;
/**
* This variable represents a cursor that iterates over the gregorian monthes from the start date month
* till the end date month.
* It is initialized with the start date month.
*/
int nextGregorianMonthCursor = gregorianStartDate[MONTH];
/**
* This variable represents a cursor that iterates over the gregorian years from the start date year.
* It is initialize with the gregorian start date year
*/
int gregorianYearCursor = gregorianStartDate[YEAR];
/**
* This loop iterates over monthes from start month till the input date month to calculate
* total number of days
* The following loop starts with the following condition:
* If the month cursor is pointing to a month that's the same as the input date month
* and the input date year is the same as the start date year, then break.
* Otherwise continute total days calculation.
*/
while(!(nextGregorianMonthCursor == gregorianDate[MONTH] && gregorianYearCursor == gregorianDate[YEAR])){
/**
* Add this month's length (number of days) to the total days to get the remaining total days.
* In the case that the input date month is not the same as the start date month:
* - The addition of start date month length into total days beside the subtracted start date day
* gives the remaining days on the month after the start date day.
*/
totalHijriYearDays = totalHijriYearDays + getGregorianMonthLengh(nextGregorianMonthCursor,gregorianDate[YEAR]);
//Move the cursor to the next month
//check if cursor over month "12" which is the last month of the year.
if(nextGregorianMonthCursor < 12){
//case that the cursor is over a month < 12, then move the cursor to the next month
nextGregorianMonthCursor++;
}else{
//case that the cursor is over the month "12" which is the last month, then move to first
//month of the next year.
nextGregorianMonthCursor = 1;
gregorianYearCursor++;
}
}
/**
* This variable represents a cursor that iterates over the hijri monthes from the first month
* till the end date month.
* It is initialized with the first month.
*/
int nextHijriMonthCursor = 1;
/**
* This loop iterates over hijri monthes as long as the current iteration month's length is < total days
* Then it subtracts the monthes lengths till we get total days <= current cursor month length
* Current cursor is over the output date month, and the remaining total days represents
* the output day of month.
*/
while(totalHijriYearDays > (Integer)inputDateHijriYear.getAttribute("L" + nextHijriMonthCursor)){
//subtract months length from total days to get the remaining days after that month.
totalHijriYearDays = totalHijriYearDays - (Integer)inputDateHijriYear.getAttribute("L" + nextHijriMonthCursor);
//Move cursor to the next month.
nextHijriMonthCursor++;
}
//store the hijri date in the output date array.
//store the hijri year represented by the year in the stp_calendar row.
hijriDate[YEAR] = Integer.parseInt((String)inputDateHijriYear.getAttribute("HYr"));
//store the hijri month represented by the month on which the cursor is.
hijriDate[MONTH] = nextHijriMonthCursor;
//store the hijri day of month represented by the remaining total days.
hijriDate[DAY] = totalHijriYearDays;
return hijriDate;
}
/**
* converts hijri input date into gregorian output date
*/
/**
* converts hijri input date into gregorian output date
* @param hijriDate hijri date to be converted into gregorian date
* @return the gregorian date.
*/
private Integer[] convertHijriToGregorian(Integer[] hijriDate){
Integer[] tempGregorianDate = new Integer[3];
/**
* The following variable holds the total number of days from the start of the input's hijri year
* till the specified input date.
* It is initialized with the input date day of month that represents the number of days passed
* of the input date month.
*/
int totalHijriYearDays = hijriDate[DAY];
/**
* This variable represents a cursor that iterates over the hijri monthes from the first month
* till the input date month.
* It is initialized with the first month.
*/
int nextHijriMonthCursor = 1;
/**
* This loop iterates over hijri monthes as long as the current iteration month is not equal to the
* input date month.
* If the month cursor is pointing to a month that's the same as the input date month, then break.
* Otherwise continute total days calculation.
*/
while(nextHijriMonthCursor != hijriDate[MONTH]){
//add months length to total days to get.
totalHijriYearDays = totalHijriYearDays + (Integer)inputDateHijriYear.getAttribute("L" + nextHijriMonthCursor);
//Move cursor to the next month.
nextHijriMonthCursor++;
}
/**
* This variable represents gregorian day of month.
* It is initialized to get the input gregorian day of month using the total days passed of the year:
* - Add calculated total days to the gregorian start date day of month.
* - Subtract "1" from since the first day of the year is included twice :
* First : by the start date day of month.
* Second : by the total days number.
*
* Notes:
* - If the input date month is the same as the start date month withing the same year, then
* this variable will actually represent the gregorian day of month.
* - If the input date month is different from the start date month or they're not within the same year,
* then the start date month length is subtracted to compensate the added value of the start date
* day of month
*/
int gregorianDayOfMonth = gregorianStartDate[DAY] + totalHijriYearDays - 1;
/**
* This variable represents a cursor that iterates over the gregorian monthes from the start date month
* till the end date month.
* It is initialized with the start date month.
*/
int nextGregorianMonthCursor = gregorianStartDate[MONTH];
/**
* This variable represents a cursor that iterates over the gregorian years from the start date year.
* It is initialize with the gregorian start date year
*/
int gregorianYearCursor = gregorianStartDate[YEAR];
/**
* This loop iterates over gregorian monthes as long as :
* the current iteration month's length is < gregorian day of month.
* Then it subtracts the monthes lengths till we get gregorian day of month <= current cursor month length
* Current cursor is over the output date month, and the remaining gregorian day of month represents
* the output day of month.
*/
while(gregorianDayOfMonth > getGregorianMonthLengh(nextGregorianMonthCursor,hijriDate[YEAR])){
//subtract months length from total days to get the remaining day of month after that month.
gregorianDayOfMonth = gregorianDayOfMonth - getGregorianMonthLengh(nextGregorianMonthCursor,hijriDate[YEAR]);
//Move the cursor to the next month
//check if cursor over month "12" which is the last month of the year.
if(nextGregorianMonthCursor < 12){
//case that the cursor is over a month < 12, then move the cursor to the next month
nextGregorianMonthCursor++;
}else{
//case that the cursor is over the month "12" which is the last month, then move to first
//month of the next year.
nextGregorianMonthCursor = 1;
//move the output date year to the neaxt year.
gregorianYearCursor++;
}
}
//store the hijri date in the output date array.
//store the gregorian year represented by the gregorian year cursor.
tempGregorianDate[YEAR] = gregorianYearCursor;
//store the gregorian month represented by the month on which the cursor is.
tempGregorianDate[MONTH] = nextGregorianMonthCursor;
//store the gregorian day of month represented by the gregorian day of month.
tempGregorianDate[DAY] = gregorianDayOfMonth;
return tempGregorianDate;
}
/**
* returns stp_calendar row that represents the input date equivalent hijri year
* @param bindVarName bind variable parameter to be set in the view accessor criteria.
* @param value the value of the bind variable
* @return stp_calendar row that represents the input date equivalent hijri year
* @throws Exception Throws Exception if there is no representation in stp_calendar for the input date.
*/
private ViewRowImpl getHijriYearData(String bindVarName,Object value)throws Exception{
ViewRowImpl stpRow = null;
//Modify criteria of the view accessor to retrieve Str-Calendar row that represents the input year.
hijriCalendarViewAccessor.setNamedWhereClauseParam(bindVarName, value);
//execute the new query to have the new Rowset
hijriCalendarViewAccessor.executeQuery();
//check if the rowset is not empty,
if(hijriCalendarViewAccessor.hasNext()){
//get the stp_calendar row representing the input year
stpRow= (ViewRowImpl)hijriCalendarViewAccessor.next();
//get gregorian start date as array of integers
gregorianStartDate = parseGregorianDate(new Timestamp((java.sql.Timestamp)stpRow.getAttribute("StrtGDt")));
//get gregorian end date as array of integers
gregorianEndDate = parseGregorianDate(new Timestamp((java.sql.Timestamp)stpRow.getAttribute("EndGDt")));
//If rowset empty, then this hijri year does not exist in stp_calendar (i.e. invalid date)
}else{
throw new Exception("Wrong input date, date out of range");
}
return stpRow;
}
/**
* Returns the calculated length of a given gregorian month in a given year..
* @param month gregorian month
* @param year gregorian year whose month length to be calculated
* @return gregorian month length
*/
private int getGregorianMonthLengh(int month,Integer year){
//this flag is "1" for leap year, and "2" for non leap year
int februaryFlag = 0;
//this flag is "1" for "31 days" months, and "0" for "30 days" months.
int extendedMonthFlag = 0;
//variable represents input month length
int monthLength = 0;
//Case input month is February whose length depends on leap years.
if(month == 2){
//set february flag to "2" as for non leap year.
februaryFlag = 2;
if(year % 4 == 0){
//deacrese february flag by one for leap year to be "1".
februaryFlag--;
}
// Case for months that are 31 days (1,3,5,7,8,10,12)
}else if((month / 2 < 4 && month % 2 != 0 ) || (month / 2 >= 4 && month % 2 == 0 )){
//increase extended month flag to "1"
extendedMonthFlag++;
}
//calculate month length.
//For February non leap year : 30 + 0 - 1 = 28
//For February leap year : 30 + 0 - 2 = 29
//For months (1,3,5,7,8,10,12) : 30 + 1 - 0 = 31
//For months (4,6,9,11) : 30 + 0 - 0 = 30
monthLength = 30 + extendedMonthFlag - februaryFlag;
return monthLength;
}
/**
* Returns string representing the output date in the format "dd-mm-yyy"
* @return output date string in the format "dd-mm-yyyy"
*/
public String getOutputDateString(){
return (outputDate[DAY] + "-" + outputDate[MONTH] + "-" + outputDate[YEAR]);
}
/**
* Returns string representing the input date in the format "dd-mm-yyy"
* @return output date string in the format "dd-mm-yyyy"
*/
public String getInputDateString(){
return (inputDate[DAY] + "-" + inputDate[MONTH] + "-" + inputDate[YEAR]);
}
/**
* Returns the gregorian date of the input date as a Timestamp
* @return the gregorian date of the input date as a Timestamp.
*/
public Timestamp getGregorianDate(){
return gregorianDate;
}
/**
* Returns a formatted string for Timestamp object creation of the input date in gregorian representation.
* @return formatted string for Timestamp object creation
*/
private String getDateTimestampFormat(Integer[] date){
//Temp Variable for creating Timestamp string formatted
//Add year string representation "yyyy"
String tempTimestampFormat = date[YEAR].toString() + "-";
//If month value < 10 (i.e. represented by "1" digit)
if(date[MONTH] < 10){
//Add preceding "0" to the month value to make its representation "2" digits "mm"
tempTimestampFormat = tempTimestampFormat + "0";
}
//Add month value string
tempTimestampFormat = tempTimestampFormat + date[MONTH] + "-";
//If day value < 10 (i.e. represented by "1" digit)
if(date[DAY] < 10){
//Add preceding "0" to the day value to make its representation "2" digits "dd"
tempTimestampFormat = tempTimestampFormat + "0";
}
//Add day value string
tempTimestampFormat = tempTimestampFormat + date[DAY];
//Add time format string with all zeros (not used).
tempTimestampFormat = tempTimestampFormat + " 00:00:00";
return tempTimestampFormat;
}
--
STP_CALENDAR Database Table: Contain mapping between Hijri and Gregorian
TABLE "STP_CALENDAR"
CREATE TABLE "STP_CALENDAR" ("H_YR" VARCHAR2(4) NOT NULL ENABLE, "STRT_G_DT" DATE NOT NULL ENABLE, "END_G_DT" DATE NOT NULL ENABLE, "L1" NUMBER(2, 0) NOT NULL ENABLE, "L2" NUMBER(2, 0) NOT NULL ENABLE, "L3" NUMBER(2, 0) NOT NULL ENABLE, "L4" NUMBER(2, 0) NOT NULL ENABLE, "L5" NUMBER(2, 0) NOT NULL ENABLE, "L6" NUMBER(2, 0) NOT NULL ENABLE, "L7" NUMBER(2, 0) NOT NULL ENABLE, "L8" NUMBER(2, 0) NOT NULL ENABLE, "L9" NUMBER(2, 0) NOT NULL ENABLE, "L10" NUMBER(2, 0) NOT NULL ENABLE, "L11" NUMBER(2, 0) NOT NULL ENABLE, "L12" NUMBER(2, 0) NOT NULL ENABLE)
-
-