package com.gpc.client.pointofsale.invoice.sync.process; import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.lang.reflect.Array; import java.math.BigDecimal; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Vector; import net.sf.json.JSON; import net.sf.json.JSONObject; import net.sf.json.JSONSerializer; import net.sf.json.JsonConfig; import net.sf.json.util.PropertyFilter; import org.apache.commons.beanutils.DynaBean; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpStatus; import org.apache.commons.httpclient.methods.EntityEnclosingMethod; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.util.EncodingUtil; import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.gpc.backofficecommon.constants.schema.Sch_Cart; import com.gpc.client.common.ClientApplicationContext; import com.gpc.client.common.ClientPropConstants; import com.gpc.client.pointofsale.invoice.line.InvoiceLineBL; import com.gpc.common.Profile; import com.gpc.common.SystemConfig; import com.gpc.common.TsoCurrentUser; import com.gpc.common.constants.refvalues.RefInvoiceNoteType; import com.gpc.common.util.CommonUtil; import com.gpc.common.util.ServerInfoHelper; import com.gpc.valueobjects.catalog.VehicleVO; import com.gpc.valueobjects.common.IDValuePairVO; import com.gpc.valueobjects.customer.CustomerVO; import com.gpc.valueobjects.invoice.InvoiceVO; import com.gpc.valueobjects.invoice.line.BaseLineItemVO; import com.gpc.valueobjects.invoice.line.FulfillmentNoteVO; import com.gpc.valueobjects.invoice.line.FulfillmentVO; import com.gpc.valueobjects.invoice.line.InvoiceLineItemVO; import com.gpc.valueobjects.invoice.line.InvoiceNoteVO; import com.gpc.valueobjects.invoice.line.KitLineItemVO; /** * Abstract class to provide a base for all cart related activities. * */ public abstract class BaseCartProcess { protected static final String LINE_ITEM_TYPE_LINE = "Line"; protected static final String LINE_ITEM_TYPE_NOTE = "Note"; private static String CREATE_CART_URN = "/taap/cartmanagement/createCart"; private static String READ_CART_URN = "/taap/cartmanagement/readCart"; private static String ADD_TO_CART_URN = "/taap/cartmanagement/addToCart"; private static String EDIT_CART_URN = "/taap/cartmanagement/editCart"; private static String REMOVE_FROM_CART_URN = "/taap/cartmanagement/removeFromCart"; private static String REFRESH_CART_URN = "/taap/cartmanagement/refreshCart"; private static String ERASE_CART_URN = "/taap/cartmanagement/eraseCart"; protected static String CREATE_CART_URL = ""; protected static String READ_CART_URL = ""; protected static String ADD_TO_CART_URL = ""; protected static String EDIT_CART_URL = ""; protected static String REMOVE_FROM_CART_URL = ""; protected static String REFRESH_CART_URL = ""; protected static String ERASE_CART_URL = ""; protected static int id = 0; protected static final Object mutex = new Object(); private static final Map connectionProperties = new HashMap(); /* * Json config for json attributes. We don't want fields with empty values to * get generated. */ private static final JsonConfig config = new JsonConfig(); static final Logger logger = Logger.getLogger(BaseCartProcess.class); static { config.setJsonPropertyFilter(new PropertyFilter() { public boolean apply(Object source, String name, Object value) { boolean exclude = value == null || value.equals("") || (value instanceof String && ((String)value).trim().length() <= 0); if(!exclude){ if(value.getClass().isArray()){ exclude = Array.getLength(value) <= 0; } if(value instanceof List){ exclude = ((List)value).size() <= 0; } if(value instanceof Map){ final Collection values = ((Map)value).values(); final Iterator iterator = values.iterator(); while(iterator.hasNext()){ exclude = apply(source, name, iterator.next()); if(!exclude){ break; } } } } return exclude; } }); final Properties properties = ClientApplicationContext.getInstance().getSystemConfig().getSystemConfiguration(SystemConfig.APPLICATION); CREATE_CART_URN = properties.getProperty(ClientPropConstants.CREATE_CART_URN, CREATE_CART_URN); READ_CART_URN = properties.getProperty(ClientPropConstants.READ_CART_URN, READ_CART_URN); ADD_TO_CART_URN = properties.getProperty(ClientPropConstants.ADD_TO_CART_URN, ADD_TO_CART_URN); EDIT_CART_URN = properties.getProperty(ClientPropConstants.EDIT_CART_URN, EDIT_CART_URN); REMOVE_FROM_CART_URN = properties.getProperty(ClientPropConstants.REMOVE_FROM_CART_URN, REMOVE_FROM_CART_URN); REFRESH_CART_URN = properties.getProperty(ClientPropConstants.REFRESH_CART_URN, REFRESH_CART_URN); ERASE_CART_URN = properties.getProperty(ClientPropConstants.ERASE_CART_URN, ERASE_CART_URN); final String ipAddress = ServerInfoHelper.getServerInfo().getHost(); CREATE_CART_URL = "http://"+ipAddress+":18080"+CREATE_CART_URN; READ_CART_URL = "http://"+ipAddress+":18080"+READ_CART_URN; ADD_TO_CART_URL = "http://"+ipAddress+":18080"+ADD_TO_CART_URN; EDIT_CART_URL = "http://"+ipAddress+":18080"+EDIT_CART_URN; REMOVE_FROM_CART_URL = "http://"+ipAddress+":18080"+REMOVE_FROM_CART_URN; REFRESH_CART_URL = "http://"+ipAddress+":18080"+REFRESH_CART_URN; ERASE_CART_URL = "http://"+ipAddress+":18080"+ERASE_CART_URN; try{ connectionProperties.put(ClientPropConstants.CART_SERVICE_CONNECTION_TIMEOUT, Integer.valueOf(properties.getProperty(ClientPropConstants.CART_SERVICE_CONNECTION_TIMEOUT, "100"))); connectionProperties.put(ClientPropConstants.CART_SERVICE_REQUEST_TIMEOUT, Integer.valueOf(properties.getProperty(ClientPropConstants.CART_SERVICE_REQUEST_TIMEOUT, "200"))); } catch(NumberFormatException nfe){ connectionProperties.put(ClientPropConstants.CART_SERVICE_CONNECTION_TIMEOUT,new Integer(100)); connectionProperties.put(ClientPropConstants.CART_SERVICE_REQUEST_TIMEOUT, new Integer(200)); } } private int retryCounter = 0; /** * Base method for generating request. This method contains common request attributes. * * @param invoiceVO * @param lineItem * @param customerVO * @return */ protected Map prepareRequest(final InvoiceVO invoiceVO, final InvoiceLineItemVO lineItem, final CustomerVO customerVO){ final TsoCurrentUser user = ClientApplicationContext.getClientApplicationContext().getCurrentUser(); final Map request = new HashMap(); request.put(Sch_Cart.CORRELATION_ID, CommonUtil.getUniqueID(Profile.POINT_OF_SALE_CLIENT, invoiceVO.getLOC(), invoiceVO.getCountermanEmployeeID())); request.put(Sch_Cart.SESSION_ID, invoiceVO.getSessionID()); request.put(Sch_Cart.SOURCE_SYSTEM, "TAMS"); request.put(Sch_Cart.EMPLOYEE_NUMBER, user.getEmployeeNum()); return request; } /** * A new method to implement the request containing individual line. * * @param invoiceLineItem * @return */ protected Map populateLineItem(InvoiceLineItemVO invoiceLineItem){ final Map lineItemMap = new HashMap(); if(invoiceLineItem instanceof BaseLineItemVO){ final BaseLineItemVO lineItem = (BaseLineItemVO)invoiceLineItem; lineItemMap.put(Sch_Cart.CI_TYPE, LINE_ITEM_TYPE_LINE); lineItemMap.put(Sch_Cart.CI_LINE_ITEM_ID, lineItem.getId()); lineItemMap.put(Sch_Cart.CI_EXTERNAL_IDENTIFIER, lineItem.getExternalIdentifier()); lineItemMap.put(Sch_Cart.CI_LINE, lineItem.getLineAbbr()); lineItemMap.put(Sch_Cart.CI_PART_NUMBER, lineItem.getPartNum()); lineItemMap.put(Sch_Cart.CI_VERSION, lineItem.getVersion()); } else if(invoiceLineItem instanceof InvoiceNoteVO){ final InvoiceNoteVO noteLineItem = (InvoiceNoteVO)invoiceLineItem; String invoiceNoteText = noteLineItem.getText(); lineItemMap.put(Sch_Cart.CI_TYPE, LINE_ITEM_TYPE_NOTE); lineItemMap.put(Sch_Cart.CI_LINE_ITEM_ID, noteLineItem.getId()); //Special Sale Item if(noteLineItem.getRefInvoiceNoteTyepID().intValue() == RefInvoiceNoteType.SALE_MESSAGE) { ClientApplicationContext clientApplication = ClientApplicationContext.getClientApplicationContext(); String storeLanguageCd = clientApplication.getProfile(Profile.POINT_OF_SALE_CLIENT, clientApplication.getLocation()) .getStoreProfile().getRefLanguageCd(); invoiceNoteText = clientApplication.getRefTableDAO().getInvoiceNoteText(noteLineItem .getRefInvoiceNoteTyepID(), storeLanguageCd); } lineItemMap.put(Sch_Cart.CI_EXTERNAL_IDENTIFIER, noteLineItem.getExternalIdentifier()); lineItemMap.put(Sch_Cart.CI_VALUE, invoiceNoteText); lineItemMap.put(Sch_Cart.CI_VERSION, noteLineItem.getVersion()); } return lineItemMap; } /** * @param invoiceVO * @return */ protected List populateAllLines(final InvoiceVO invoiceVO){ final List cartItems = new ArrayList(); final Vector lines = invoiceVO.getLineItems(); if(lines != null){ for(int index = 0; index < lines.size(); index++){ cartItems.add(populateLineItem((InvoiceLineItemVO)lines.get(index))); } } return cartItems; } /** * API for accessing cart in server. This method can be used by processes which just * need InvoiceVO. * * @param invoiceVO * @return * @throws Exception */ public InvoiceVO execute(final InvoiceVO invoiceVO) throws Exception{ return execute(invoiceVO, null); } /** * API for accessing cart in server. This method can be used by processes which do not * depend on single line item. e.g. creating cart, refreshing cart. * * @param invoiceVO * @param customerVO * @return An InvoiceVO which will contain all the attributes received from server. * @throws Exception */ public InvoiceVO execute(final InvoiceVO invoiceVO, final CustomerVO customerVO) throws Exception{ return execute(invoiceVO, null, customerVO); } /** * API for accessing cart in server. This method can be used by processes which need to * work on a single line item. e.g. adding to cart, editing a cart and removing from cart. * * @param invoiceVO * @param lineItem * @param customerVO * @return An InvoiceVO which will contain all the attributes received from server. * @throws Exception */ public InvoiceVO execute(final InvoiceVO invoiceVO, final InvoiceLineItemVO lineItem, final CustomerVO customerVO) throws Exception{ preProcess(invoiceVO, lineItem); String res = execute(prepareRequest(invoiceVO, lineItem, customerVO), connectionProperties); final DynaBean completeResponse = (DynaBean)JSONSerializer.toJava( (JSON)JSONSerializer.toJSON(res, config), config); final InvoiceVO newInvoice = populateResponse(invoiceVO, lineItem, customerVO, completeResponse); postProcess(newInvoice, invoiceVO, lineItem); return newInvoice; } /** * Child classes can override this method to modify data to be sent out. * * @param invoiceVO * @param lineItem */ protected void preProcess(InvoiceVO invoiceVO, InvoiceLineItemVO lineItem) {} /** * Child classes can override this method to perform work after POS receives response from * server. * * @param newInvoice * @param existingInvoice * @param lineItem */ protected void postProcess(InvoiceVO newInvoice, InvoiceVO existingInvoice, final InvoiceLineItemVO lineItem) {} /** * Execute the HttpMethod. * * @param request * @return * @throws Exception */ protected String execute(final Map request, final Map properties) throws Exception{ String response = ""; final HttpClient client = new HttpClient(); client.getHttpConnectionManager().getParams().setConnectionTimeout( ((Integer)properties.get(ClientPropConstants.CART_SERVICE_CONNECTION_TIMEOUT)).intValue()); client.getHttpConnectionManager().getParams().setSoTimeout( ((Integer)properties.get(ClientPropConstants.CART_SERVICE_REQUEST_TIMEOUT)).intValue()); final EntityEnclosingMethod method = getHttpMethod(); method.setRequestHeader("content-type", "application/json; charset=UTF-8"); final JSONObject jsonObject = JSONObject.fromObject(request, config); String req = jsonObject.toString(); logger.info(method.getPath() + " request:" + req); method.setRequestBody(req); InputStream in = null; ByteArrayOutputStream out = null; int thisRetryNumberIs = 0; try{ final int status = client.executeMethod(method); if(status == HttpStatus.SC_OK){ in = method.getResponseBodyAsStream(); out = new ByteArrayOutputStream(); byte[] buffer = new byte[4096]; int len; while ((len = in.read(buffer)) > 0) { out.write(buffer, 0, len); } final byte[] rawdata = out.toByteArray(); if(rawdata != null){ response = EncodingUtil.getString(rawdata, method.getResponseCharSet()); } /* * If its a successful call, then we assign the max retry number to thisRetryNumberIs * so that retry logic does not kick off. */ thisRetryNumberIs = getMaxRetryCount(); } else { throw new Exception("HttpStatus is not 200 OK. It is "+status); } }catch(Exception exception){ thisRetryNumberIs = getRetryCount(); /* * We don't want to throw error till retry mechanism gives up. */ if(thisRetryNumberIs >= getMaxRetryCount()){ throw exception; } logger.error(exception.getMessage(), exception); } finally{ method.releaseConnection(); if(in != null){ in.close(); } if(out != null){ out.close(); } if(thisRetryNumberIs < getMaxRetryCount()){ final Map newConnectionProperties = new HashMap(); /* * Each time we do a retry, we want to give it more chance to succeed than the * last one. That is why we increase the timeouts by number of retry. * e.g if initial timeouts are 500 and 1000 milis. Next time they will be set to * 1000 & 2000 respectively. */ newConnectionProperties.put(ClientPropConstants.CART_SERVICE_CONNECTION_TIMEOUT, new Integer((thisRetryNumberIs + 1) * ((Integer)connectionProperties.get( ClientPropConstants.CART_SERVICE_CONNECTION_TIMEOUT)).intValue())); newConnectionProperties.put(ClientPropConstants.CART_SERVICE_REQUEST_TIMEOUT, new Integer((thisRetryNumberIs + 1) * ((Integer)connectionProperties.get( ClientPropConstants.CART_SERVICE_REQUEST_TIMEOUT)).intValue())); response = execute(request, newConnectionProperties); } } logger.info(method.getPath() + " response:" + response); return response; } /** * Abstract method for getting the service URL. Implementing class needs to * populate the URL to be used. * * @return */ protected abstract String getURL(); /** * @return */ protected EntityEnclosingMethod getHttpMethod(){ return new PostMethod(getURL()); } /** * Populate an InvoiceVO from the response. * * @param invoiceVO * @param invoiceLineItem * @param customerVO * @param completeResponse * @return * @throws Exception */ protected InvoiceVO populateResponse(final InvoiceVO invoiceVO, final InvoiceLineItemVO invoiceLineItem, final CustomerVO customerVO, final DynaBean completeResponse) throws Exception{ final DynaBean tracking = (DynaBean)get(completeResponse, Sch_Cart.TRACKING); final Boolean isSuccess = (Boolean)get(tracking, Sch_Cart.TRACKING_IS_SUCCESS); /* * The failure scenario needs to be revisited again. We may need little discussion with architect * as well to come up with a decent failure mechanism. Right now we are just throwing an exception. */ if(!isSuccess.booleanValue()){ throw new Exception("There is some problem with cart syncing process. Please contact support."); } final InvoiceVO newInvoice = new InvoiceVO(); final DynaBean response = (DynaBean)get(completeResponse, Sch_Cart.RESPONSE); final List linesToProcess = new ArrayList(); final DynaBean cart = (DynaBean)get(response, Sch_Cart.R_CART); newInvoice.setVersion((Integer)get(cart, Sch_Cart.R_CART_VERSION)); final DynaBean customer = (DynaBean)get(cart, Sch_Cart.R_CART_CUSTOMER); if(customer != null){ newInvoice.setCustomerName((String)get(customer, Sch_Cart.R_CART_CUSTOMER_CUSTOMER_NAME)); } final List lines = (List)get(cart, Sch_Cart.R_CART_ITEMS); if(lines != null){ for(int index = 0; index < lines.size(); index++){ final DynaBean lineItem = (DynaBean)lines.get(index); final String type = (String)get(lineItem, Sch_Cart.R_CI_TYPE); final Integer id = (Integer)get(lineItem, Sch_Cart.R_CI_LINE_ITEM_ID); Integer generatedBySequence = (Integer)get(lineItem, Sch_Cart.R_CI_GENERATED_BY_LINE_ITEM_ID); final Object version = get(lineItem, Sch_Cart.R_CI_VERSION); final String externalIdentifier = (String)get(lineItem, Sch_Cart.R_CI_EXTERNAL_IDENTIFIER); final Boolean markedForDeletion = (Boolean)get(lineItem, Sch_Cart.R_CI_MARKED_FOR_DELETION); if(type.equals(LINE_ITEM_TYPE_LINE)){ final BaseLineItemVO baseLineItemVO = new BaseLineItemVO(); baseLineItemVO.setId(id); if(generatedBySequence != null) { baseLineItemVO.setGeneratedBySequence(generatedBySequence); } baseLineItemVO.setExternalIdentifier(externalIdentifier); baseLineItemVO.setMarkedForDeletion(markedForDeletion == null ? new Boolean(false) : markedForDeletion); baseLineItemVO.setPartNum((String)get(lineItem, Sch_Cart.R_CI_PART_NUMBER)); baseLineItemVO.setLineAbbr((String)get(lineItem, Sch_Cart.R_CI_LINE)); baseLineItemVO.setSpecialOrder((String)get(lineItem, Sch_Cart.CI_FULFILLMENT_TYPE)); baseLineItemVO.setPartDescription((String)get(lineItem, Sch_Cart.R_CI_PART_DESCRIPTION)); baseLineItemVO.setQuantityBilled(new BigDecimal(get(lineItem, Sch_Cart.R_CI_BILLED_QTY).toString())); baseLineItemVO.setTokenId((String)get(lineItem, Sch_Cart.R_CI_PPSE_TOKEN_ID)); final Object unitPrice = get(lineItem, Sch_Cart.CI_UNIT_PRICE); if(unitPrice != null){ baseLineItemVO.setUnitPrice(new BigDecimal(unitPrice.toString())); } final Object stockCheck = get(lineItem, "stockCheck"); if(stockCheck != null){ baseLineItemVO.setStockCheck(new Boolean(stockCheck.toString()).booleanValue()); } final DynaBean vehicleIdentification = (DynaBean)get(lineItem, Sch_Cart.R_CI_VEHICLE_IDENTIFICATION); if(vehicleIdentification != null){ final DynaBean makeAndModel = (DynaBean)get(vehicleIdentification, Sch_Cart.R_CI_VI_MAKE_AND_MODEL); if(makeAndModel != null){ baseLineItemVO.setVehicleMake((String)get(makeAndModel, Sch_Cart.R_CI_VI_MAM_MAKE)); baseLineItemVO.setVehicleModel((String)get(makeAndModel, Sch_Cart.R_CI_VI_MAM_MODEL)); final Object year = get(makeAndModel, Sch_Cart.R_CI_VI_MAM_YEAR); if(year != null){ baseLineItemVO.setVehicleYear(new Short(year.toString())); } final VehicleVO vehicleVo = new VehicleVO(); if(baseLineItemVO.getVehicleYear() != null) { vehicleVo.setYear(baseLineItemVO.getVehicleYear().intValue()); } if(!StringUtils.isEmpty(baseLineItemVO.getVehicleMake())) { final IDValuePairVO vehicleMake = new IDValuePairVO(); vehicleMake.setID(new Integer("0")); vehicleMake.setValue(baseLineItemVO.getVehicleMake()); vehicleVo.setMake(vehicleMake); } if(!StringUtils.isEmpty(baseLineItemVO.getVehicleModel())) { final IDValuePairVO vehicleModel = new IDValuePairVO(); vehicleModel.setID(new Integer(0)); vehicleModel.setValue(baseLineItemVO.getVehicleModel()); vehicleVo.setModel(vehicleModel); } baseLineItemVO.setVehicleVO(vehicleVo); } final String catalogNotes = (String)get(vehicleIdentification, Sch_Cart.R_CI_VI_CATALOG_NOTES); if(!StringUtils.isEmpty(catalogNotes)){ baseLineItemVO.setPartNote(new String[]{catalogNotes}); } final List additionalCodes = (List)get(vehicleIdentification, Sch_Cart.R_CI_VI_VEHICLE_ADDITIONAL_CODES); if(additionalCodes != null){ final StringBuffer sb = new StringBuffer(); for(int additionalCodeIndex = 0; additionalCodeIndex < additionalCodes.size(); additionalCodeIndex++){ sb.append(additionalCodes.get(additionalCodeIndex)); if(additionalCodeIndex < (additionalCodes.size() - 1)){ sb.append(" "); } } if(!StringUtils.isBlank(sb.toString())){ baseLineItemVO.setVehicleAdditionalInfo(sb.toString()); } } } baseLineItemVO.setVersion(new Integer(version.toString())); final List childs = (List)get(lineItem, Sch_Cart.R_CI_CHILDS); if(childs != null){ final List components = new ArrayList(); for(int childIndex = 0; childIndex < childs.size(); childIndex++){ final DynaBean child = (DynaBean)childs.get(childIndex); final String childType = (String)get(child, Sch_Cart.R_CI_TYPE); if(LINE_ITEM_TYPE_LINE.equals(childType)){ final KitLineItemVO component = new KitLineItemVO(); component.setPartNum((String)get(child, Sch_Cart.R_CI_PART_NUMBER)); component.setExpandedPartNum(component.getPartNum()); component.setLineAbbr((String)get(child, Sch_Cart.R_CI_LINE)); component.setPartDescription((String)get(child, Sch_Cart.R_CI_PART_DESCRIPTION)); component.setQuantityBilled(new BigDecimal(get(child, Sch_Cart.R_CI_BILLED_QTY).toString())); component.setRequiredQuantity(component.getQuantityBilled().divide(baseLineItemVO.getQuantityBilled(), BigDecimal.ROUND_UNNECESSARY)); components.add(component); } else if(LINE_ITEM_TYPE_NOTE.equals(childType)){ final FulfillmentNoteVO note = new FulfillmentNoteVO(); note.setText((String)get(child, Sch_Cart.R_CI_VALUE)); List fulfillments = baseLineItemVO.getFulfillments(); if(fulfillments == null){ fulfillments = new ArrayList(); baseLineItemVO.setFulfillments(fulfillments); } final FulfillmentVO fulfillment = new FulfillmentVO(); List fulfillmentItems = fulfillment.getFulfillmentItems(); if(fulfillmentItems == null){ fulfillmentItems = new ArrayList(); fulfillment.setFulfillmentItems(fulfillmentItems); } fulfillmentItems.add(note); fulfillments.add(fulfillment); } } baseLineItemVO.setVirtualKit(components.size() > 0); baseLineItemVO.setComponents(components); if (baseLineItemVO.isVirtualKit()){ InvoiceLineBL.logKitMismatchIfAny(baseLineItemVO,customerVO); } } linesToProcess.add(baseLineItemVO); } else if(type.equals(LINE_ITEM_TYPE_NOTE)){ final InvoiceNoteVO invoiceNoteVO = new InvoiceNoteVO(); invoiceNoteVO.setId(id); invoiceNoteVO.setExternalIdentifier(externalIdentifier); invoiceNoteVO.setMarkedForDeletion(markedForDeletion == null ? new Boolean(false) : markedForDeletion); invoiceNoteVO.setText((String)get(lineItem, Sch_Cart.R_CI_VALUE)); invoiceNoteVO.setVersion(new Integer(version.toString())); if(generatedBySequence != null) { invoiceNoteVO.setGeneratedBySequence(generatedBySequence); } linesToProcess.add(invoiceNoteVO); } } } newInvoice.setLineItems(new Vector(linesToProcess)); return newInvoice; } /** * Just an utility method for getting the value of the property from DynaBean. * If property isn't found in the DynaBean, API throws an exception. We are * catching it and returning back null in that case. * * @param bean * @param property * @return */ private Object get(final DynaBean bean, final String property){ try{ return PropertyUtils.getProperty(bean, property); }catch(Exception exception){ return null; } } /** * This method cause side effects. So we need to be careful while invoking this method. * Each time we call it, it increments the retryCounter variable by one. We have marked it * as protected, so that child processes can override this method to have their own behavior. * * @return */ protected int getRetryCount(){ retryCounter = retryCounter + 1; return retryCounter; } /** * This method returns the maximum number of time retry mechanism runs. Default value is 3. We have marked it * as protected, so that child processes can override this method to have their own behavior. * * @return */ protected int getMaxRetryCount(){ return 3; } }