/**
*
*/
package com.cin.service;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Logger;
import javax.jms.JMSException;
import javax.jms.ObjectMessage;
import javax.jms.Queue;
import javax.jms.QueueConnection;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueSender;
import javax.jms.QueueSession;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import com.cin.constants.ApplicationConstants;
import com.cin.dto.EmploymentStatusDTO;
import com.cin.dto.GenericRequest;
import com.cin.dto.GenericResponse;
import com.cin.dto.IndustryDTO;
import com.cin.dto.InsurencePolicyDTO;
import com.cin.dto.InvitationDTO;
import com.cin.dto.OccupationDTO;
import com.cin.dto.SearchDTO;
import com.cin.dto.StateAbbvDTO;
import com.cin.dto.StatisticsDTO;
import com.cin.dto.UserDTO;
import com.cin.dto.ZipDTO;
import com.cin.ejb.transactionejb.TransactionRemote;
import com.cin.ejb.transactionejb.UserFactory;
import com.cin.exceptions.InvalidInputValueException;
import com.cin.exceptions.MissingInformationException;
import com.cin.exceptions.MissingInputValueException;
import com.cin.exceptions.PersistenceException;
import com.cin.exceptions.PurchaseException;
import com.cin.exceptions.UserNotFoundException;
import com.cin.filters.CustomFilter;
import com.cin.jndi.lookup.EJBLookup;
import com.cin.translators.DataTranslator;
public class CensusInsuranceService {
private static Logger aLog = Logger.getLogger("com.cin.service");
private static TransactionRemote aRemote;
private static UserFactory userFactory;
private static HashMap<String,List<UserDTO>> incomeMap = new HashMap<String,List<UserDTO>>();
ScoreCache scoreCache = ScoreCache.getInstance();
static {
try {
aRemote = EJBLookup.getInstance().getTransactionEJB();
userFactory = EJBLookup.getInstance().getUserFactory();
} catch (Exception pException) {
// TODO: is it good to catch the exception if you can't handle it?
// should this be in constructor?
aLog.severe("Error in Transaction EJB lookup: "
+ pException.getMessage() + "\n");
}
}
/**
* This method is to retrieve the user record based on his/her ssn. The
* method will retrieve the user record and set it back to the parameter.
* This flow will be called from across applications when the user dto
* object is not materialized or retrieving for the user/agent display.
*/
public UserDTO retrieveUserRecord(UserDTO pDTO) throws UserNotFoundException{
return retrieveUserRecord(pDTO.getSsn());
}
public UserDTO retrieveUserRecord(int ssn) throws UserNotFoundException{
UserDTO userFound = userFactory.findUserBySsn(ssn);
if( userFound == null ){
throw new UserNotFoundException("User with ssn "+ssn+" was not found.");
}
return userFound;
}
/**
* Updates information on user. Does not update job nor migration info.
*
* @see changeUserResidence()
* @see changeUserEmployment()
*/
public UserDTO updateUserInfo(UserDTO user) throws UserNotFoundException {
userFactory.updateUserDetail(user);
if (user.getEducation() != null) {
userFactory.updateUserEducation(user);
}
if (user.getInvestmentDetails() != null) {
userFactory.updateUserInvestment(user);
}
if (user.getYouth() != null) {
userFactory.updateUserYouth(user);
}
UserDTO newUser = retrieveUserRecord(user.getSsn());
this.userRecordModified(newUser);
return newUser;
}
public UserDTO changeUserResidence(UserDTO user) {
throw new UnsupportedOperationException();
}
/** Updates job and employment status info */
public UserDTO changeUserEmployment(UserDTO user) {
throw new UnsupportedOperationException();
}
public List<UserDTO> retrieveUserRecordbyZip(String pZipCode)
throws InvalidInputValueException {
if (pZipCode.trim().equals("") || pZipCode.equals("0")) {
throw new MissingInputValueException("Zip code was not provided.");
}
SearchDTO aDTO = new SearchDTO();
aDTO.setZipCode(Integer.parseInt(pZipCode));
List<UserDTO> users = userFactory.findUsersBySearchCriteria(aDTO);
// Check the zip after retrieving users. This way, if zip is invalid, but a user
// has such a zip, the user will be returned.
if( users.size() == 0 ){
if( ! aRemote.zipCodeExists(pZipCode) ){
throw new InvalidInputValueException("Zip code is not valid.");
}
}
return users;
}
public void calculateScoreForUsers(Collection<UserDTO> theUsers)
throws MissingInformationException, InvalidInputValueException {
if (theUsers == null) {
throw new NullPointerException("List of users is missing.");
}
for (UserDTO aDTO : theUsers) {
this.calculateScoreForUser(aDTO);
}
}
private void tryCalculateScoreForUsers(Collection<UserDTO> users){
for( UserDTO user : users){
try{
calculateScoreForUser(user);
} catch (MissingInformationException e) {
// do nothing
} catch (InvalidInputValueException e) {
// do nothing
}
}
}
public void calculateScoreForUser(UserDTO pDTO) throws MissingInformationException, InvalidInputValueException {
synchronized (scoreCache) {
if (scoreCache.hasUser(pDTO.getSsn())) {
aLog.finer("Cache hit.");
int score = scoreCache.getScore(pDTO.getSsn());
pDTO.setScore(score);
} else {
aLog.finer("Cache miss.");
try {
// the code was instrumented to demonstrate deadlock
Thread.sleep(1000);
} catch (InterruptedException e) {
aLog.warning("Interupted sleeping");
}
UserDTO tmpUser = retrieveUserRecord(pDTO);
int score = getScoreForUserFromDb(tmpUser);
pDTO.setScore(score);
tmpUser.setScore(score);
scoreCache.addUser(tmpUser);
}
}
}
private int getScoreForUserFromDb(UserDTO pDTO) throws MissingInformationException, InvalidInputValueException {
UserDTO user = retrieveUserRecord(pDTO);
int aScore = 0;
if (user.getJobDetails() != null && user.getJobDetails().getWorkClass().equalsIgnoreCase(
ApplicationConstants.FEDERAL_GOVT_EMP)) {
return 100;
}
List<UserDTO> theUsers = null;
if(user.getZipCode() == null || user.getZipCode().equals("")) {
throw new MissingInformationException("User's zip code is not known");
}
String zipCode = user.getZipCode();
if(incomeMap.containsKey(zipCode)) {
theUsers = incomeMap.get(zipCode);
}
else {
theUsers = this.retrieveUserRecordbyZip(zipCode);
if(theUsers != null && !theUsers.isEmpty()) {
incomeMap.put(zipCode, theUsers);
}
}
int aNumCount = 0;
for (UserDTO aDTO : theUsers) {
if (user.getIncome() >= aDTO.getIncome()) {
aNumCount++;
}
}
// TODO what if theUsers.size() == 0; it shouldn't happen... but
if(theUsers.size() > 0) {
float aUserPercentile = (float) aNumCount / (float) theUsers.size();
aScore = Math.round(100 * aUserPercentile);
}
if (user.getSex().equalsIgnoreCase("F")) {
aScore = aScore + ((5 / 100) * aScore);
}
if (user.getJobDetails() != null && !user.getJobDetails().isUnionMember()
&& aScore < ApplicationConstants.THRESHOLD_VALUE) {
int aOccStab = 0;
int indStab = 0;
OccupationDTO occStaticData = this.findOccupationStabilityValue(
user.getJobDetails().getOccupationCode());
if(occStaticData != null) {
aOccStab = occStaticData.getStability();
}
IndustryDTO indStaticData = this.findIndustryStabilityValue(
user.getJobDetails().getIndustryCode());
if(indStaticData != null) {
indStab = indStaticData.getStability();
}
Double aUserStability = Math.sqrt(new Double(aOccStab
* indStab))
* new Double(10);
if (aUserStability > 0 && aUserStability < 10) {
return 0;
} else if (aUserStability > 10 && aUserStability < 60) {
aScore = (int) (aScore * (aUserStability / 80));
if (user.getEducation() != null &&
( user.getEducation().isDoctorate()
|| user.getEducation().isMasters()
|| user.getEducation().isProfesssional()) ) {
aScore = aScore + (aScore * (20 / 100));
}
} else if (aUserStability > 60 && aUserStability < 100) {
aScore = (int) (aScore * (aUserStability / 100));
if (user.getEducation() != null &&
( user.getEducation().isBachelors()
|| user.getEducation().isDoctorate()
|| user.getEducation().isMasters()
|| user.getEducation().isProfesssional()) ) {
aScore = aScore + (aScore * (12 / 100));
}
}
}
/**
* TODO based on capital gains. change @arunsanjay
*/
// check other details
if(user.getIncome() > 0) {
int aPayPercentage = (user.incomeFromPay() / user.getIncome()) * 100;
if ((100 - aPayPercentage) > aPayPercentage) {
aScore = aScore - (aScore * (10 / 100));
}
if (user.isSingle()) {
aScore = aScore + (aScore * (10 / 100));
}
if (user.getAge() >= 65 && user.getIncome() < 5000) {
aScore = 0;
}
}
// return score
if (aScore > 0) {
return aScore;
} else {
return 0;
}
}
private void userRecordModified(UserDTO user) {
synchronized (scoreCache) {
if (user.getZipCode() != null) {
scoreCache.clearByZip(user.getZipCode());
} else {
scoreCache.clear(user.getSsn());
}
}
}
public int calculateQuoteForPolicy(InsurencePolicyDTO policy)
throws MissingInformationException, InvalidInputValueException {
try{
UserDTO user = retrieveUserRecord(policy.getUserSSN());
if( policy.getDeductibles() < 0 ){
throw new InvalidInputValueException("Deductibles can't be negative.");
}
if( policy.getPropertyName() == null || policy.getPropertyName().equals("")){
throw new MissingInputValueException("Property name is missing.");
}
if( policy.getPropertyValue() <= 0 ){
throw new InvalidInputValueException("Property value must be positive.");
}
double quote = (policy.getPropertyValue() - policy.getDeductibles()) * 0.1;
if (policy.getDeductibles() > policy.getPropertyValue() * 0.2) {
quote *= 0.90;
} else if (policy.getDeductibles() > policy.getPropertyValue() * 0.1) {
quote *= 0.95;
}
calculateScoreForUser(user);
if (user.getScore() >= 90) {
quote *= 0.90;
} else if (10 <= user.getScore() && user.getScore() <= 75) {
double ration = 2.0 - user.getScore() / 100.0;
quote = quote * ration;
} else if (user.getScore() < 10) {
quote = 2 * quote;
}
if( quote < 1 ){
quote = 1;
}
return Math.round((float) quote);
} catch (UserNotFoundException e) {
throw new UserNotFoundException("Client of this insurence policy was not found in system.");
}
}
public OccupationDTO findOccupationStabilityValue(int pOccupationCode) {
return aRemote.findStabilityForOccupationCode(pOccupationCode);
}
public IndustryDTO findIndustryStabilityValue(int pIndustryCode) {
return aRemote.findStabilityForIndustryCode(pIndustryCode);
}
public List<UserDTO> findUsersByCode(int pIndCode, int pOccCode) {
// TODO: error checking - check if the codes are valid
return userFactory.findUsersByCode(pIndCode, pOccCode);
}
public GenericResponse retrieveUserBySearchCriteria(GenericRequest pRequest)
throws InvalidInputValueException {
List<UserDTO> theUserDetails = new ArrayList<UserDTO>();
SearchDTO aSearchDTO = new SearchDTO();
CustomFilter aFilter = new CustomFilter();
GenericResponse aResponse = new GenericResponse();
aSearchDTO = pRequest.getSearchDTO();
if (aSearchDTO != null) {
theUserDetails = userFactory.findUsersBySearchCriteria(aSearchDTO);
tryCalculateScoreForUsers(theUserDetails);
pRequest.setUserList(theUserDetails);
}
aFilter.filterUsers(theUserDetails, aSearchDTO);
if (theUserDetails != null && !theUserDetails.isEmpty()) {
aResponse.setUserList(theUserDetails);
aResponse.setResponseStatus(true);
}
return aResponse;
}
public InvitationDTO sendInvitation(InvitationDTO invitation, InsurencePolicyDTO samplePolicy)
throws UserNotFoundException, InvalidInputValueException {
// check policy object
if (samplePolicy != null) {
if (samplePolicy.getDeductibles() < 0) {
throw new InvalidInputValueException(
"Deductibles can't be negative.");
}
if (samplePolicy.getPropertyName() == null) {
throw new MissingInputValueException(
"Property name must be specified.");
}
if (samplePolicy.getQuote() <= 0) {
throw new InvalidInputValueException("Quote must be positive.");
}
if (samplePolicy.getUserSSN() != invitation.getCustomer().getSsn()) {
throw new IllegalArgumentException(
"SSN on invitation and sample policy are different.");
}
}
// check if customer exists
if (invitation.getCustomer() == null) {
throw new IllegalArgumentException(
"Invitation must include customer.");
}
UserDTO customer;
try{
customer = retrieveUserRecord(invitation.getCustomer());
}catch(UserNotFoundException e){
throw new UserNotFoundException(
"Customer with ssn "+ invitation.getCustomer().getSsn()+" cannot be found.");
}
// check if agent exists
if (invitation.getAgent() == null) {
throw new IllegalArgumentException("Invitation must include agent.");
}
UserDTO agent;
try{
agent = retrieveUserRecord(invitation.getAgent());
} catch(UserNotFoundException e){
throw new UserNotFoundException(
"Agent with ssn " + invitation.getAgent().getSsn() + " cannot be found.");
}
// record & send invitation
// TODO: no invitation is actually mailed.
InvitationDTO sentInvitation = null;
sentInvitation = new InvitationDTO(0, agent, customer, new Date());
sentInvitation = aRemote.addInvitation(sentInvitation);
return sentInvitation;
}
/**
* @param policy
* Policy that is requested to be purchased
* @return Policy that was purchased.
*/
public InsurencePolicyDTO purchasePolicy(InsurencePolicyDTO policy)
throws PurchaseException, InvalidInputValueException, MissingInformationException {
// verify all data of the policy
UserDTO user;
try{
user = retrieveUserRecord(policy.getUserSSN());
}catch(UserNotFoundException e){
throw new UserNotFoundException("Customer on the policy is not registered.");
}
calculateScoreForUser(user);
if (user.getScore() <= 0) {
throw new PurchaseException("Customer is not eligible for policy.");
}
int newQuote = calculateQuoteForPolicy(policy);
if (newQuote != policy.getQuote()) {
throw new InvalidInputValueException("Quota on the policy is not correct.");
}
if (policy.getPropertyName() == null || policy.getPropertyName().equals("")) {
throw new MissingInputValueException("Policy must include property name.");
}
if (policy.getPropertyValue() <= 0) {
throw new InvalidInputValueException(
"Policy must include valid property value.");
}
if (policy.getDeductibles() < 0) {
throw new InvalidInputValueException("Deductibles can't be negative.");
}
if (policy.getStartDate() != null) {
throw new PurchaseException("New policy can't include start date.");
}
if (policy.getEndDate() != null) {
throw new PurchaseException("New policy can't include end date.");
}
// compensate agent
try {
sendPurchaseMessage(policy);
} catch (Exception ex) {
ex.printStackTrace();
}
// accept policy
policy.setStartDate(new Date());
return policy;
}
private void sendPurchaseMessage(InsurencePolicyDTO policy)
throws NamingException, JMSException {
InitialContext context = new InitialContext();
final Queue queue = (Queue) context.lookup("jms/PurchaseQueue");
final QueueConnectionFactory factory = (QueueConnectionFactory) context
.lookup("jms/QueueConnectionFactory");
final QueueConnection connection = factory.createQueueConnection();
final QueueSession session = connection.createQueueSession(false,
QueueSession.AUTO_ACKNOWLEDGE);
ObjectMessage message = session.createObjectMessage();
message.setObject(policy);
QueueSender sender = session.createSender(queue);
sender.send(message);
}
public void calculateUnemployementForState(String stateName) {
// int aZip = pRequest.getSearchDTO().getZipCode();
int employed = 0, unemployed = 0;
List<ZipDTO> theZipDetails = userFactory.findZipForState(stateName);
// for each zip get the user details
for (ZipDTO aDTO : theZipDetails) {
// aDTO.getZip();
List<UserDTO> theUserDetails = userFactory.findUserForZip(Integer
.parseInt(aDTO.getZip()));
for (UserDTO bDTO : theUserDetails) {
EmploymentStatusDTO employmentStatusDTO = bDTO
.getEmploymentStatus();
if (employmentStatusDTO.getEmploymentStatus().equals(
"unemployed")) {
unemployed++;
}
if (employmentStatusDTO.getEmploymentStatus().equals("pt")) {
employed++;
}
if (employmentStatusDTO.getEmploymentStatus().equals(
"full-time")) {
employed++;
}
}
// TODO: this is not finished
int unemploymentRate;
unemploymentRate = (unemployed / (employed + unemployed) * 100);
}
}
public void recommendUser(UserDTO pUser) {
// TODO: this is not finished
UserDTO user = userFactory.findUserBySsn(pUser.getSsn());
if(user.getJobDetails() != null) {
int occCode = user.getJobDetails().getOccupationCode();
int indCode = user.getJobDetails().getIndustryCode();
}
}
// below function updates user's job, migration and employmentstat details
public UserDTO updateMiscInfo(UserDTO user) throws UserNotFoundException{
if( user.getJobDetails() != null )
{
userFactory.updateUserJob(user);
}
if( user.getMigration() != null )
{
userFactory.updateUserMigration(user);
}
return userFactory.findUserBySsn(user.getSsn());
}
public UserDTO createAUser(GenericRequest greq)
{
UserDTO theUser = new UserDTO ();
theUser = userFactory.addUser(greq.getUser());
return theUser ;
}
public void removeAUser(GenericRequest greq)
{
userFactory.deleteUser(greq.getUser());
}
public UserDTO checkUserExistence(GenericRequest pRequest) {
// TODO: this can't be right
UserDTO uDto = new UserDTO();
DataTranslator aTranslator = new DataTranslator();
if ((uDto = userFactory.findUserBySsn(pRequest.getUser().getSsn())) == null)
{ System.out.println("Failed to authenticate: SSN not found");
return null ;
}
System.out.println("User authenticated!");
return uDto ;
}
public UserDTO calculateLikelinessFactor(UserDTO pUser) throws MissingInformationException,PersistenceException {
UserDTO user = userFactory.findUserBySsn(pUser.getSsn());
StatisticsService aStatsService = new StatisticsService();
StatisticsDTO aUserStateStats = new StatisticsDTO();
if(user.getZipCode() == null || user.getZipCode().trim().length() > 0) {
throw new MissingInformationException("Location information is missing for user.Update the info and calculate the factor");
}
if(user.getJobDetails() != null) {
ZipDTO zip = aRemote.findStateForZip(Integer.parseInt(user.getZipCode()));
if(zip != null) {
aUserStateStats.setState(zip.getState());
}
aUserStateStats.setIndustryCode(user.getJobDetails().getIndustryCode());
aUserStateStats.setOccCode(user.getJobDetails().getOccupationCode());
}
GenericResponse aResponse = aStatsService.calculateWeeklyWage(aUserStateStats);
int userStateAvgWage = 0;
int numOfStates = 0;
if(aResponse != null && aResponse.getStatistics() != null
&& aResponse.isResponseStatus()) {
userStateAvgWage = aResponse.getStatistics().getAvgWeekWage();
}
List<StateAbbvDTO> theStates = aRemote.findAllStates();
StatisticsDTO otherStatesStats = new StatisticsDTO();
for(StateAbbvDTO aState : theStates) {
String aStateName = aState.getAbbv();
otherStatesStats.setIndustryCode(user.getJobDetails().getIndustryCode());
otherStatesStats.setOccCode(user.getJobDetails().getOccupationCode());
otherStatesStats.setState(aStateName);
aResponse = aStatsService.calculateWeeklyWage(aUserStateStats);
if(aResponse != null && aResponse.getStatistics() != null
&& aResponse.isResponseStatus()) {
if(userStateAvgWage < aResponse.getStatistics().getAvgWeekWage()) {
numOfStates++;
}
}
int aPercentage = 0;
if(theStates.size() > 0)
aPercentage = (numOfStates/theStates.size())*100;
if(aPercentage > ApplicationConstants.ACCEPTABLE_LIMIT_PERCENTAGE) {
user.setLikelinessFactor(true);
}
}
return user;
}
}