370 likes | 740 Views
SOA for the Payroll/Personnel System. Web services that inquire or update the EDB. Presentation Overview.
E N D
SOA for the Payroll/Personnel System Web services that inquire or update the EDB
Presentation Overview • New capabilities available in CICS have made it possible to expose the existing CICS programs that underlie current EDB Entry/Update screens as Web Services. This provides an opportunity to reinvigorate data presentation and entry by writing new web applications that require only a Web Browser on the user’s PC. Numerous improvements in the user interface are possible as a result • Today’s presentation is in two parts • Part I - describes the design of the new CICS hosted Web Services that support web applications under development • Part II - describes the design of new JAVA web applications • Important concepts • A WSDL is a Web Service Description Language file. Each Web Service must have a WSDL that defines the input and output of the service • CICS Web Services are implemented using SOAP encoded XML over HTTP • In PPS there are two types of data element numbers • Scalar value – has one value assigned to the DEN • Repeating value – has a list of occurrence key/value pairs assigned to the DEN
EDB Inquiry / Update Web Service Design Goals • Provide authentication of end users via existing userid / password signon process • Reuse existing PPS EDB UPDATE CICS programs for • DB2 database access • value / range edit process • Consistency edit process • ARSM and $PPSFUNC authorization process • Enable creation of Web Applications that do not use SQL • Minimize the need to change the Web Services when new data elements are added to the EDB • Provide authentication of requesting Web Application Server by the Web Service providing CICS region to support point to point security
Provide authentication of end users via existing RACF userid and password signon - <q0:s010_input> <q0:s010_user_id>paypxp</q0:s010_user_id> <q0:s010_password>secret</q0:s010_password> <q0:s010_new_password /> </q0:s010_input> • A Web Service hosted by each campus PPS CICS region checks users id and password entered by the end user • If the userid / password are valid a token is created and saved in storage in the CICS region – the user is then ‘logged on’ to a specific region • The logged on user’s id can be fetched from storage with the token - <s010_output> <s010_user_token_out>0810595977</s010_user_token_out> <s010_return_code>0000</s010_return_code> </s010_output>
Use existing CICS DB2 database access - <q0:PS006INPUT> <q0:webserv_user_token_in>0810595977</q0:webserv_user_token_in> <q0:ps006_request_code /> <q0:ps006_action_code /> <q0:ps006_input_employee_id>000000001</q0:ps006_input_employee_id> - <q0:ps006_input_element_array> - <q0:ps006_input_element_entry> <q0:ps006_input_data_elem_no>0108</q0:ps006_input_data_elem_no> <q0:ps006_input_occur_key /> <q0:ps006_input_value>M</q0:ps006_input_value> </q0:ps006_input_element_entry> </q0:ps006_input_element_array> </q0:PS006INPUT> - <PS001OUT xmlns="http://www.PS001O.com/schemas/PS001OInterface"> <ps001_return_cd>0000</ps001_return_cd> - <ps001_return_entry> <ps001_return_data_elem_no>0001</ps001_return_data_elem_no> <ps001_return_occur_key>010020</ps001_return_occur_key> <ps001_return_value>2006-03-16</ps001_return_value> <ps001_return_data_type>D</ps001_return_data_type> <ps001_return_de_num_sw /> </ps001_return_entry> …. - <ps001_return_entry> <ps001_return_data_elem_no>0105</ps001_return_data_elem_no> <ps001_return_occur_key /> <ps001_return_value>PRESIDENT,EXEC</ps001_return_value> <ps001_return_data_type>A</ps001_return_data_type> <ps001_return_de_num_sw /> </ps001_return_entry> …. - <ps001_return_entry> <ps001_return_data_elem_no>6000</ps001_return_data_elem_no> <ps001_return_occur_key>008U</ps001_return_occur_key> <ps001_return_value>22,000.00</ps001_return_value> <ps001_return_data_type>N</ps001_return_data_type> <ps001_return_de_num_sw /> • PPEDBFET for inquiry • PPEDBUPD for update - <PS006OUTPUT xmlns="http://www.PS006O.com/schemas/PS006OInterface"> <ps006_return_code>0000</ps006_return_code> <ps006_msg_number>U0007</ps006_msg_number> <ps006_msg_text>U0007Updateprocess complete</ps006_msg_text> <ps006_output_employee_id>000000001</ps006_output_employee_id> - <ps006_output_element_array> - <ps006_output_element_entry> <ps006_output_data_elem_no>0108</ps006_output_data_elem_no> <ps006_output_occur_key /> <ps006_output_value>M</ps006_output_value> <ps006_data_elem_status>0</ps006_data_elem_status> </ps006_output_element_entry> </ps006_output_element_array> <ps006_output_conedit_array /> </PS006OUTPUT> - <q0:PS001IN> <q0:ps001_req_emp_id>000000001</q0:ps001_req_emp_id> <q0:webserv_user_token_in>0810595977</q0:webserv_user_token_in> </q0:PS001IN>
Use existing CICS value / range edit process • PPVREDO - <q0:PS015INPUT> <q0:webserv_user_token_in>0810595977</q0:webserv_user_token_in> <q0:s015i_request_code>1</q0:s015i_request_code> - <q0:s015i_element_array> - <q0:s015i_element_item> <q0:s015i_elem_number>1171</q0:s015i_elem_number> <q0:s015i_entered_data>22</q0:s015i_entered_data> <q0:s015i_related_data /> </q0:s015i_element_item> - <q0:s015i_element_item> <q0:s015i_elem_number>1171</q0:s015i_elem_number> <q0:s015i_entered_data>15</q0:s015i_entered_data> <q0:s015i_related_data /> </q0:s015i_element_item> </q0:s015i_element_array> </q0:PS015INPUT> - <PS015OUTPUT xmlns="http://www.PS015O.com/schemas/PS015OInterface"> <s015o_return_code>00001</s015o_return_code> <s015o_return_msg>Element errors encountered</s015o_return_msg> - <s015o_element_array> - <s015o_element_item> <s015o_elem_number>1171</s015o_elem_number> <s015o_entered_data>22</s015o_entered_data> <s015o_edb_data /> <s015o_screen_data>22</s015o_screen_data> <s015o_elem_status_code>1</s015o_elem_status_code> </s015o_element_item> - <s015o_element_item> <s015o_elem_number>1171</s015o_elem_number> <s015o_entered_data>15</s015o_entered_data> <s015o_edb_data>15</s015o_edb_data> <s015o_screen_data>15</s015o_screen_data> <s015o_elem_status_code>0</s015o_elem_status_code> </s015o_element_item> </s015o_element_array> </PS015OUTPUT>
Use existing CICS conedit process ===== Examples of the type of changes needed in UCROUTER ======== ************************************************************** * INCLUDE WEB SERVICE EXTERNAL ************************************************************** 01 CPWSWEBS-WEB-INFO EXTERNAL. COPY CPWSWEBS. **************************************************************** * FOR A WEB SERVICE CALL, IDENTIFY AN INITIAL CALL THROUGH * THE CPWSWEBS EXTERNAL RATHER THAN EIBCALEN **************************************************************** IF CPWSWEBS-WEB-CALL IF CPWSWEBS-WEB-INITIAL-CALL PERFORM 0200-SETUP ELSE PERFORM 0300-ITERATION END-IF ELSE IF EIBCALEN = ZERO PERFORM 0200-SETUP ELSE PERFORM 0300-ITERATION END-IF *************************************************************** * DON'T ISSUE CICS RETURN FOR A WEB SERVICE CALL. MUST GO * BACK TO CALLING PROGRAM. *************************************************************** IF CPWSWEBS-WEB-CALL GOBACK ELSE EXEC CICS RETURN END-EXEC END-IF • UCROUTER Minor changes to UCROUTER allow reuse of existing EDB update process.
Use existing CICS ARSM and $PPSFUNC authorization process • UCPPPEDB • UCFNAUTH Call from Web Services to check ARSM rules Call from Web Services to check $PPSFUNC RACF resources
Enable creation of Web Applications that do not use SQL • Existing CICS screen handling programs provide Entry / Update access to the EDB without SQL • Web Applications using PPS Web Services provide Entry / Update access to the EDB without SQL Eliminates vulnerability of Web Applications to SQL injection Design increases reusability of the Web Application since it is decoupled from the datastore
Minimize the need to change the Web Services when new data elements are added to the EDB • Identify data by data element number/occurrence key • Using data element number/occurrence key to identify data makes using the Web Service harder • The following changes will be reflected in web services without the need to change them: • new data element added to the EDB • changes to value range edits made via the DET table • changes to the conedit process made via the DET, PGT, RTD
Provide authentication of requesting Web Application Server • An X.509 digital certificate identifying the client server is required by all Web Services hosted by PPS CICS regions to support client authentication during the SSL handshake
Consuming PPS Web Services Services in Java From XML to Business Domain Objects
XML to Domain Objects • Focus of this talk • SOAP message to Employee object • Where the rubber meets the road
Technology Stack: Glassfish Metro • Sun’s WS implementation • Current state-of-the-art • Performance improvements over others • Cleaner generated code
Steps from XML to Domain Objects • WSDL import tool • Binding Customizations • Domain Interface/Adapter Strategy • Domain-Level Marshalling
Step One: Generate Client Code • wsimport • WS tool included in Metro & J6SE • WSDL to framework classes • Handles XML manipulation & connection code • Schema bindings • Complex types map to classes • Elements to properties
PS001: EDB Employee Fetch <complexTypename="PS001IN"> <sequence> <elementform="qualified"name="ps001_req_emp_id"> <annotation> <appinfosource="http://www.wsadie.com/appinfo"> <initialValuekind="SPACE"/> </appinfo> </annotation> <simpleType> <restrictionbase="string"> <maxLengthvalue="9"/> </restriction> </simpleType> </element> […] </sequence> </complexType>
Generated Code public class PS001IN { [….] /** * Gets the value of the ps001ReqEmpId property. * * @return * possible object is * {@link String } * */ public String getPs001ReqEmpId() { return ps001ReqEmpId; }
Step Two: Customization Bindings • ”getPs001ReqEmpId” may not be our first choice for naming • wsimport supports customized bindings • Use standard JAX-WS and JAXB bindings • Use XPath to find type/element to affect
Typical Customizations • Package name • Class names • Method names • Enumerations • Especially useful when service sends status codes • Javadoc on generated classes
Example: PS001 JAXB bindings <jaxb:bindings schemaLocation="file:PS001.wsdl#types?schema1" node="/xs:schema/xs:complexType[@name='PS001IN']"> <jaxb:class name="PS001Input"> <jaxb:javadoc> Wrapper around input values to service. </jaxb:javadoc> </jaxb:class> </jaxb:bindings> <jaxb:bindings schemaLocation="file:PS001.wsdl#types?schema1" node="//xs:element[@name='ps001_req_emp_id']"> <jaxb:property name="employeeId"> <jaxb:javadoc> Identifies the employee for whom all non-initial EDB data elements should be returned. </jaxb:javadoc> </jaxb:property> </jaxb:bindings>
Example: Result public class PS001Input implements Serializable { [....] /** * * Identifies the employee for whom all non-initial EDB data elements should be returned. * * * @return * possible object is * {@link String } * */ public String getEmployeeId() { return employeeId; }
Client Operation Becomes Simple EmpDataService ps001EmplFinder = new PS001Service().getPS001Port(); PS001Input inputPayload = new PS001Input(); inputPayload.setEmployeeId( TEST_EMP_ID ); inputPayload.setUserToken( token ); PS001Output employeeData = ps001EmplFinder.getEmpData(inputPayload);
A Good Start But Not Enough • PS001 for example returns an unbounded array of data element number/occurrence key/value elements • Would be nice to convert this data into domain object • Employee with named fields • For example, name, last action, list of appointments
Step Three, First Half: Employee Interface • Business domain representation • Named field for each data element • Append DEN for reference • public String getName0105(); • Reusable business object • Question: how do we bridge the gap from web service return data to these fields?
Step Three, Second Half: Adapter Strategy • Mediates between client code and domain object • Responsible for parsing WS return payload /** *ProvidesanadapterlayerbetweentherawPS010returndataandan<code>EDBEmployee</code>type. * *@authorshunter * */ publicinterface EDBEmployeeAdapter { /** *Transformtherawservicedataintoanemployeeobjectwithnamedfieldsforeachdataelement. *@paramps001OutputPayloadthefullsetofdataelement/valuestringsreturnedbytheservice *@returnanemployeeobject. */ public EDBEmployee parseEmployee( PS001Output ps001OutputPayload );
Implementation Strategy • Adapter Impl puts all returned values into one of two maps • Scalar values • DEN => value • Repeating • DEN => list of occurrence key/value pairs
Map-Backed Employee Impl • Implement each named field getter with access to map • Scalar: public String getArmdFrcesSrvc0344() { returnscalarDataElemValues.get( "0344" ); } Repeating: public String getAdditionalTax6011G() { String value = null; Map<String,String> occurrences = repeatingDataElemsAsMaps.get( "6000" ); if( occurrences != null ){ value = occurrences.get( "011G" ); } return value; }
Help with Special Datasets • Complex repeating sets of data elements • Leave Accrual • Appointments and distributions • Adapter parses these into data structures available in the Emp obj public List<IAppointment> getAppointmentList();
Leave Accrual Data 8024/ LV PER01 BYPASS / 8030/ LV PER02 BYPASS / 8023/ LV PER01 CYC TP / 8029/ LV PER02 CYC TP / 8022/ LV PER01 END DT / 8028/ LV PER02 END DT / 8104/ LV PER01 HR CD1 / 8132/ LV PER02 HR CD1 / 8111/ LV PER01 HR CD2 / 8139/ LV PER02 HR CD2 / 8118/ LV PER01 HR CD3 / 8146/ LV PER02 HR CD3 / 8125/ LV PER01 HR CD4 / 8153/ LV PER02 HR CD4 / 8101/ LV PER01 KEY1 / 8129/ LV PER02 KEY1 / 8108/ LV PER01 KEY2 / 8136/ LV PER02 KEY2 / 8115/ LV PER01 KEY3 / 8143/ LV PER02 KEY3 / 8122/ LV PER01 KEY4 / 8150/ LV PER02 KEY4 / 8027/ LV PER01 LOST P / 8033/ LV PER02 LOST P / 8026/ LV PER01 LOST S / 8032/ LV PER02 LOST S / 8025/ LV PER01 LOST V / 8031/ LV PER02 LOST V / 8107/ LV PER01 P ACR1 / 8135/ LV PER02 P ACR1 / 8114/ LV PER01 P ACR2 / 8142/ LV PER02 P ACR2 / 8121/ LV PER01 P ACR3 / 8149/ LV PER02 P ACR3 / 8128/ LV PER01 P ACR4 / 8156/ LV PER02 P ACR4 / 8102/ LV PER01 PLAN1 / 8130/ LV PER02 PLAN1 / 8109/ LV PER01 PLAN2 / 8137/ LV PER02 PLAN2 / 8116/ LV PER01 PLAN3 / 8144/ LV PER02 PLAN3 / 8123/ LV PER01 PLAN4 / 8151/ LV PER02 PLAN4 / 8106/ LV PER01 S ACR1 / 8134/ LV PER02 S ACR1 / 8113/ LV PER01 S ACR2 / 8141/ LV PER02 S ACR2 / 8120/ LV PER01 S ACR3 / 8148/ LV PER02 S ACR3 / 8127/ LV PER01 S ACR4 / 8155/ LV PER02 S ACR4 / 8103/ LV PER01 TWRD1 / 8131/ LV PER02 TWRD1 / 8110/ LV PER01 TWRD2 / 8138/ LV PER02 TWRD2 / 8117/ LV PER01 TWRD3 / 8145/ LV PER02 TWRD3 / 8124/ LV PER01 TWRD4 / 8152/ LV PER02 TWRD4 / 8105/ LV PER01 V ACR1 / 8133/ LV PER02 V ACR1 / 8112/ LV PER01 V ACR2 / 8140/ LV PER02 V ACR2 / 8119/ LV PER01 V ACR3 / 8147/ LV PER02 V ACR3 / 8126/ LV PER01 V ACR4 / 8154/ LV PER02 V ACR4 /
Step Four: Application-Level Marshalling • Strictly speaking marshalling means • Java datatypes => XML • We need domain object => Java WS client objects • Client expectssimple key/value pair objects • DEN => “[some string value]”
Update Service Input Client public void setPs006InputDataElemNo(String value) { this.ps006InputDataElemNo = value; } public void setPs006InputOccurKey(String value) { this.ps006InputOccurKey = value; } public void setPs006InputValue(String value) { this.ps006InputValue = value; }
Domain Object into Client Framework Class • Iterate on key sets for each map • Scalar • Repeating • Pull each stored value/list, add to service input object
Conclusions • Exposing mainframe logic/data a great thing • Current java WS tools ease development • Autogenerate clients that are easy to use • Further programming strategies needed • Bridge gap from client objects to domain objects