GPF Dev Weblogic Domain Structure epblnx50d AHCluster – 3GB gpfNode7gpfNode8 ENTCluster – 3GB gpfNode9gpfNode10 CSLCluster – 3GB gpfNode5gpfNode6 REFCluster – 3GB gpfNode3gpfNode4 GPFCluster – 4GB gpfNode1gpfNode2 Admin Server SQL Server eqpfsqtpdv01.nam.nsroot.net:2431 AccountsDataSubLedgerInstrumentRefDataMarketData Sybase epbdb1d.ny.ssmb.com:4100 PBOnline Container-Level Data Sources AHDatasource SubLedgerFinderXADataSource SubLedgerXADatasource ReferenceDatasource MarketDatasource ProductProcessorDS epblnx51d 11 Processes needed for whole deployement.
AHFinderServiceImplAHFinderProxyImp AHDAOManager AHCacheAspect PfclientAcctDAO PffundAcctDAO PfsubAcctDAO PfgroupAcctDAO PfrefCodesAcctDAO …. 45 in total Database Save() Delete() Merge() attachClean() attachDirty() findById() …… Core Business Logic and Data Access Classes AHManagerServiceImplAHManagerProxyImpl clientAcctRegionfundAcctRegion subAcctRegiongroupAcctRegion
ESF (Enterprise Service Framework) Stack Container4.0.jar Esf_config.xml GPFServices.jar GPFServices Application Mule1.4.1.jar Container4.0.jar Esf_config.xml AHGui.jar AHGui Application Mule1.4.1.jar Axis:ServletAxis:JMS
Data Bus AHGUI AHFinderServiceFacade.execWSMethod() ESFClient.send() AH_esf_config_client.xmlESFAxisConnector AH DB GPFServices EMS Server
Common Accounts Getters PfAccount getCSLSubAccount() PfAccount[] getPfClientAccountsByAcronym() PfAccount[] getPfFundAccountsByAcronym() PfAccount[] getPfSubAccountsByProductProcessor() in total Pfgroup getPfGroupByPfGrpId() in total Abstract entities based only on cached data PfAccount getAccountHierarchyByPfId() ClientSummary[] getAllClientSummary() FundSummary[] getAllFundSummary() GroupSummary[] getAllGroupSummary() SubAcctSummary[] getAllSubAcctSummary() Data not cached by Gemfire PfacctAddress getPfacctAddress() PfacctAddress[] getPfacctAddresses() PfrefCodes[] getAllPfrefCodes() Pfexception[] getPfexceptions() True if specified entity exist in cache or DB Boolean isValidClientAcct() Boolean isValidFundAcct() Boolean isValidSubAcct() Boolean isValidSubAcctById() Boolean isValidSubAcctByRootIdAndPortfolioId() Clear caches and Reload From Database void refreshCache() Hibernate Save, children entities will also be saved. E.g. SubAcctEQRef PfAccount updateClientAccount(PfclientAcct clientAccount) PfAccount updateFundAccount(PffundAcct fundAccount) PfAccount updateSubAccount(PfsubAcct subAccounts) Hibernate Save, children entities will NOT be saved, e.g. childrenAccounts PfAccount updateAccount(PfAccount account) Pfgroup addGroup(Pfgroup pfgroup) Pfgroup updateGroup(Pfgroup pfgroup) Integer deleteGroup(Integer pfGrpId, Integer version) Changing Hierarchy Structure, ActionXXX stored procedures Handled PfAccount addClientAccount(AddClient addClient) Integer deleteClientAccount(DeleteClient deleteClient) PfAccount mergeClientAccount(MergeClient mergeClient) PfAccount addFundAccount(AddFund addFund) Integer deleteFundAccount(DeleteFund deleteFund) PfAccount mergeFundAccount(MergeFund mergeFund) PfAccount addSubAccount(AddSubAcct addSubAccount) Integer deleteSubAccount(DeleteSubAcct deleteSubAccount) PfAccount updateParentAccount(UpdateParent updateParent) Convert CITI data to PF data, UpdDDIXXX stored procedures handled PfAccount[] setPFFundAcctFromDDI(Integer citiId) PfAccount[] setPFSubAcctFromDDI(Integer citiId) Finder Service Functions Manager Service Functions
Cache Handling – CacheAspect Aspects Defined in AHServiceContext.xml Spring Advice Types Before advice: Executes before a method enters execution. After returning advice: Executed after a method completes normally. After throwing advice: Executed if a method exits by throwing an exception. After (finally) advice: Executed regardless of the means by which a method exits. Around advice: Perform custom behavior before and after the method invocation. Objective When reading data, use cache instead of database When writing data, update cache as necessary
public PfAccount getPfClientAcctByAcronymFromCache(ProceedingJoinPoint joinPoint) { try { Object[] args = joinPoint.getArgs(); PfAccount pfAccount = null; String queryString = "SELECT * FROM /root/ClientAccount r " + "WHERE r.pfclientAcct.pfClientAcronym = “ + "'" + args[0] + "'"; Query query = cacheManager.getQueryService().newQuery(queryString); SelectResults results = (SelectResults) query.execute(); Iterator iter = sr.iterator(); if (iter.hasNext()) { pfAccount = (PfAccount) iter.next(); } if (null == pfAccount) { pfAccount = (PfAccount) joinPoint.proceed(); if (pfAccount != null) { Region region = cacheManager.getRegion("root/ClientAccount"); region.put(pfAccount.getPfId(), pfAccount); AhEventPublisher ahEventPublisher = new AhEventPublisher(); ahEventPublisher.publish(pfAccount); ahEventPublisher.close(); } } else { pfAccount.setPfChildAccounts(new PfAccount[0]); pfAccount.setPfIndirectChildAccounts(new PfAccount[0]); } return pfAccount; } catch (Throwable t) { AHExceptionUtil.throwAHException(t); } Sample Read Data From Cache Gemfire query to find data, similar to Hibernate Publish cached data changes to JMS queue If no data found in cache, proceed to AHFinderService to try getting it from database Nullify children references to Shrink the size of return object
Mule Data Flow Supported Transports Axis BPM CXF EJB File FTP HTTP HTTPS IMAP JDBC Jetty JMS Multicast POP3 RMI Servlet SMTP SOAP STDIO TCP UDP VM WebSphere MQ XMPP
Challenges PfAccount PfClientAccountPfFundAccountPfSubAccount PfAccount SSL HandShaking Exception (certificate file) NoSuchElementException vo object unmatched) Update function doesnot return updated result PfGroup AHGUI Data & Function
ESF Service Config Elements Connectors Esf : JmsConnector Esf : AxisConnector Mule : VMConnector Interceptor-Stack Esf : LoggingInterceptor Esf : TimerInterceptor Esf_config_deploy.xml Transformers mule : ObjectToXML mule : JMSMessageToObject mule : ObjectToJMSMessage Mule : ByteArrayToSerializable Ah : AHTransformer Services Ah : AHFinderService inbound : axis:servlet://AHFinderService inbound : axis:jms://gpf_ AHFinderService.request Ah : AHManagerService inbound : axis:servlet://AHManagerService inbound : axis:jms://gpf_ AHManagerService.request Mule : BridgeComponent inbound : vm://ahJmsProxy outbound : axis:jms://gpf_ Equity.AHNotificationReceiver.request?method=receiveAHEvent outbound : axis:jms://gpf_ IPB.AHNotificationReceiver.request?method=receiveAHEvent Exception Strategy AHDefaultConnectorExceptionStrategy Profiles Threading Profile Pooling Profile Queue Profile
ESF Service Config Structure <property name="allowedMethods" value="getVersionResult,getPfClientAccounts,getPfFundAccounts,getPfSubAccounts,,getAllSubAcctSummary..." />
AHService Config Files Overview
Utility Classes UIDGenerator – A 24 character-length unique string generator, based on System.currentTimeMillis(), host IP address, and java.security.SecureRandom(“SHA1PRN”). It’s used by AHEventPublished to assign event id. Also used by AhJmsTopicMsgPublisher to set service call id. AHSizeAgent – Make rough calculation of memory consumption size for those stored in cache. Was used by AHCacheAspect getAccountsFromCache(), getAccountHierarchyByID(). Not in use right now. AHContextListener – Registered in web.xml as a listener class. Upon context initilization being finished, it calls AHStartupLoader to load data from database into cach. It also pass the ESF config file to ESFXMLConfigurationBuilder to initilize the ESF framework components. AHDefaultConnectorExceptionStrategy – An extension class to org.mule.impl.DefaultExceptionStrategy, in its defaultHandler(Throwable t) method, it simply output the error message via Log4J, its declared as the exception strategy for JMS connection in esf_config_deploy.xml AHEventPublisher – It’s frequently used AHCacheAspect during most cache data change situations. The method publish(Serializable) convert a cached object (e.g. PfClientAcct) into AHEvent object. The AHEvent object is then dispatched through ESFClient to “vm://ahJmsProxy”. A BridgeComponent declared in esf_config_deploy.xml then resend it to citi.eqpb.ny.pbapps.gpf_ Equity.AHNotificationReceiver via Axis JMS channel
The Others Performance Most functions running 2-3 times longer than typical hibernate implementation If service guanrentees that data consistency between Gemfire cache and database why should we get the data from service? Function Flexibility What if we only want part of the result object? What if we need complex searching logic? Data Integrity Does the service always know what’s been changed? Are the interfaces thread safe? Maintain Effort Why so many files need to be changed when we only want to add a single attribute to vo object? Be able to run it in local, for easier coding and debug.