|
|
Want to know more about Packt's Article Network? Interested in contributing your article ideas? Please visit our FAQ for more information. See More BROWSE
All Titles WordPress Web Services SOA BPEL Web Graphics & Video Web Development RAW Portugues, Espanol, Italiano, French PHP/MySQL Oracle Open Source Networking & Telephony Moodle Microsoft & .NET Linux Servers jQuery Joomla! JBoss Java e-Learning e-Commerce Dynamics Drupal CRM Cookbook Content Management Beginner Guides Architecture and Analysis AJAX Future Titles Recently Published Titles |
Apache OFBiz Service Engine: Part 1
Defining a ServiceWe first need to define a service. Our first service will be named learningFirstService. In the folder ${component:learning}, create a new folder called servicedef. In that folder, create a new file called services.xml and enter into it this: <?xml version="1.0" encoding="UTF-8" ?> In the file ${component:learning}ofbiz-component.xml, add after the last <entity-resource> element this: <service-resource type="model" loader="main" location="service def/services.xml"/> That tells our component learning to look for service definitions in the file ${component:learning}servicedefservices.xml. It is important to note that all service definitions are loaded at startup; therefore any changes to any of the service definition files will require a restart! Creating the Java Code for the ServiceIn the package org.ofbiz.learning.learning, create a new class called LearningServices with one static method learningFirstService: package org.ofbiz.learning.learning; Services must return a map. This map must contain at least one entry. This entry must have the key responseMessage (see org.ofbiz.service.ModelService.RESPONSE_MESSAGE), having a value of one of the following:
By using ServiceUtil.returnSuccess() to construct the minimal return map, we do not need to bother adding the responseMessage key and value pair. Another entry that is often used is that with the key successMessage (ModelService.SUCCESS_MESSAGE). By doing ServiceUtil.returnSuccess("Some message"), we will get a return map with entry successMessage of value "Some message". Again, ServiceUtil insulates us from having to learn the convention in key names. Testing Our First ServiceStop OFBiz, recompile our learning component and restart OFBiz so that the modified ofbiz-component.xml and the new services.xml can be loaded. In ${component:learning}widgetlearningLearningScreens.xml, insert a new Screen Widget: <screen name="TestFirstService"> In the file ${component:learning}widgetlearningLearningForms.xml, insert a new Form Widget: <form name="TestingServices" type="single" target="${formTarget}">Notice how the formTarget field is being set in the screen and used in the form. For now don't worry about the Full Name label we are setting from the screen. Our service will eventually set that. In the file ${webapp:learning}WEB-INFcontroller.xml, insert a new request map: <request-map uri="TestFirstService"> The control servlet currently has no way of knowing how to handle an event of type service, so in controller.xml we must add a new handler element immediately under the other <handler> elements: <handler name="service" type="request" class="org.ofbiz.webapp.event.ServiceEventHandler"/> We will cover service-multi services later. Finally add a new view map: <view-map name="TestFirstService" type="screen" Fire to webapp learning an http OFBiz request TestFirstService, and see that we have successfully invoked our first service:
Service ParametersJust like Java methods, OFBiz services can have input and output parameters and just like Java methods, the parameter types must be declared. Input Parameters (IN)Our first service is defined with two parameters: <attribute name="firstName" type="String" mode="IN" optional="true"/> Any parameters sent to the service by the end-user as form parameters, but not in the services list of declared input parameters, will be dropped. Other parameters are converted to a Map by the framework and passed into our static method as the second parameter. Add a new method handleInputParamaters to our LearningServices class. public static Map handleParameters(DispatchContext dctx, Map context){We can now make our service definition invoke this method instead of the learningFirstService method by opening our services.xml file and replacing: <service name="learningFirstService" engine="java" with: <service name="learningFirstService" engine="java" Once again shutdown, recompile, and restart OFBiz. Enter for fields First Name, Last Name, and Planet Id values Some, Name, and Earth, respectively. Submit and notice that only the first two parameters went through to the service. Parameter planetId was dropped silently as it was not declared in the service definition.
Modify the service learningFirstService in the file ${component:learning}servicedefservices.xml, and add below the second parameter a third one like this: <attribute name="planetId" type="String" mode="IN" optional="true"/> Restart OFBiz and submit the same values for the three form fields, and see all three parameters go through to the service.
Apache OFBiz Development: The Beginner's Tutorial
Output Parameters (OUT)Just like Java methods have return values (although Java methods can have only one typed return value), services can be declared with output parameters. When invoked as events from the controller, parameters will be silently dropped if they are not declared in our service's definition. Add this to our service definition: <attribute name="fullName" type="String" mode="OUT" optional="true"/> And in the method handleParameters in org.ofbiz.learning.learning.LearningServices replace: Map resultMap = ServiceUtil.returnSuccess(message); with Map resultMap = ServiceUtil.returnSuccess(message); We have now added the fullName parameter to the resultMap. To see this in action we need to create a new screen widget in LearningScreens.xml: <screen name="TestFirstServiceOutput"> Add the request-map to the controller.xml file: <request-map uri="TestFirstServiceOutput"> and finally the view-map: <view-map name="TestFirstServiceOutput" type="screen" Stop OFBiz, rebuild our Learning Component and restart, fire an OFBiz http request TestFirstServiceOutput to webapp learning. Submit your first and last names and planet and notice that now the fullName parameter has been populated.
Two Way Parameters (INOUT)A service may change the value of an input parameter and we may need a calling service to be aware of this change. To save us declaring the same parameter twice, with a mode for IN and a mode for OUT, we may use the mode INOUT. <attribute name="fullName" type="String" mode="INOUT" optional="true"/> Special Unchecked ParametersThere are a few special cases where IN/OUT parameters can exist even though the service definition does not declare them. They are:
The parameters responseMessage, errorMessage, errorMessageList, successMessage and successMessageList are necessary placeholders for feedback messages. They must be allowed through all validation checks. The parameter userLogin is often required for authentication and permissions checks. The parameter locale is needed just about everywhere in OFBiz. For locale-specificity in certain operations like retrieving template feedback messages, or like formatting numbers and currency figures. Optional and Compulsory ParametersThe Service Engine checks the validity of the input and the output to ensure that what is coming into the service and is leaving adheres to the service definition. If the optional attribute is set to false and an expected parameter is missing, then the validation will fail and the service will return an error. This transaction will now be marked for rollback, meaning any changes to the database made during this transaction will never be committed. This could include any changes made to the database by calling services. For example: <attribute name="fullName" type="String" mode="INOUT" optional="false"/> Here the parameter fullName must be passed into the service and the service must also add this parameter to the resultMap and pass it out or validation will fail and an error will be thrown. Try changing all of the optional flags on our newly created service to false. After a restart we should see:
The DispatchContextWe have already seen how parameters are passed into our Java method as a Map. Just as the userLogin object of type GenericValue and the locale object of type Locale were added as attributes to the request for the Java events, both are now automatically added to this context map when the service is invoked in this way. The first parameter, the DispatchContext, contains the remaining tools we need to access the database, or to invoke other services. From our Java code we can get access to the following handy objects like this: GenericValue userLogin = (GenericValue)context.get("userLogin");For a full list of objects that are available from the DispatchContext, take a look through the code in org.ofbiz.service.DispatchContext. The service engine is in no way reliant on there being HTTPServletRequest or HTTPServletResponse objects available. Because of this we are able to invoke services outside of the web environment and they can be invoked remotely or scheduled to run "offline". Service Security and Access ControlSecurity-related programming in services is exactly like that in events. In the class org.ofbiz.learning.learning.LearningServices, create a new static method serviceWithAuth: public static Map serviceWithAuth(DispatchContext dctx, Map context){ Ensure that the correct imports have been added to the class: import java.util.Map; In the file ${component:learning}servicedefservices.xml, add a new service definition: <service name="learningServiceWithAuth" engine="java" In the file ${webapp:learning}WEB-INFcontroller.xml, add a new request map: <request-map uri="TestServiceWithAuth"> Rebuild and restart and then fire to webapp learning an http OFBiz request TestServiceWithAuth, login with username allowed password ofbiz, and see the welcome message displayed:
Logging in with username denied password zibfo will show an error message. Thanks to the request-map's response element named error having a value of login, we are returned back to the login screen:
SummaryIn this article we have looked at:
In the next part, we will look at Calling services from Java code, Implementing Service Interfaces, Synchronous and asynchronous services, Using the Service Engine tools, and ECAs: Event Condition Actions. Apache OFBiz Development: The Beginner's Tutorial
About the AuthorsJonathon Wong Jong Hann is an avid puzzle solver. He is constantly in search of new problems to take apart. He has dabbled in Rubik's Cubes, maze navigation algorithms, and various other logical and mechanical puzzles. He had taken apart OFBiz within a month for a client who wanted to evaluate it. Having mapped out the architectural structure of OFBiz, he also embarked on documenting the functional and ERP-specific aspects of OFBiz. Within the following six months, he had completed three small-scale projects with OFBiz. He is currently using OFBiz in almost every new project, leveraging OFBiz's advantage for rapid prototyping and development. He first delved into Java some 10 years ago. He has since specialized in clean programming structures, design patterns, and parallel computing. Since then, he also picked up the hobby of reverse engineering various open source software to equip his employers and himself with new technologies. Jonathon has also worked for clients who needed to take apart legacy systems to make corrections. Rupert Howell, while developing Java applications for the UK's Office for National Statistics, stumbled upon Open For Business and has been working with the framework ever since. Since early 2003, Rupert has been a consultant to some of the UK's largest OFBiz implementations and has helped some major retailers successfully migrate their entire ERP systems to OFBiz. Rupert holds a Master's degree in Mechanical Engineering and is a Director of Provolve Ltd, a company specializing in OFBiz-based solutions. For more information see the Provolve website at www.provolve.com Books from Packt |
|
| ||||||||