Contents
When information from pages is submitted, it is received by a server Controller. Which controller receives the information depends on the action that was fired and the application navigation that is defined within the Studio. Within these controllers, you can use the submitted information, perform additional business logic, access databases, call remote services, etc. You can also define how to return any information back to the browser and which page should be used to display the returned information.
You can access controllers from using the right-click context menu on the Application Map tab or the Open Controller Rules link on the right hand panel of the Application Map when a Controller has been selected. For Java controllers, ensure the Java option is selected on the right hand panel.
Receiving calls from other applications on the server
Each Action Link that is painted on the Application Map tab is available for invocation over HTTP. The action request will be processed, together with any supplied parameters and forwarded to the linked Controller for further processing. The invocations can be via URL, basic HTTP or SOAP.
Java Controllers are identified by the Java option setting, against the Controller Details within the WebMaker Application Map screen.
WebMaker generates a Java Class using the Controller name specified in the Application Map.
Managing Controller Source Code
You can organise the source code for Java Controllers by using the Java Code Location and Package Name entries under Application Defaults - Advanced Options on the right hand panel of the Application Map.
Controller Architecture
Before we start to explore the contents of Java Controllers, it is worth recapping on some of the relevant components within the WebMaker Runtime architecture. The diagram below provides a high-level view of this architecture, focusing on the data bindings and the flow of incoming and outgoing information between client (Browser) and server.
WebMaker provides the ability to bind the data within a web page in two directions. When information is submitted from the browser, an arbitrary XML document structure can be populated with the information contained within the submitted XHTML form. When a page is sent to the browser, another arbitrary XML document structure on the server can be used to bind XML fields to HTML fields on the web page. This bi-directional binding can be performed graphically within the WebMaker Page Design - Bindings tab. Controllers on the server handle the requests and also compose the response structures that are then transformed by WebMaker to produce the HTML response to the Browser.
Java Controllers provide the ability to write Java code to perform the desired tasks on the server. What you do here is dependent on your application scenario, technology standards and architecture.
The information between the client and server is bound for you. Therefore, by the time you receive the information it will be in the following format:
<?xml version="1.0" encoding="UTF-8"?>
<mvc:eForm xmlns="http://www.hyfinity.com/xplatform" xmlns:mvc="http://www.hyfinity.com/mvc" xmlns:xg="http://www.hyfinity.com/xgate">
<mvc:Control>
<Page xmlns="http://www.hyfinity.com/mvc">ContactDetails.xsl</Page>
<Controller xmlns="http://www.hyfinity.com/mvc">mvc-Contacts-JGetContactsList-Controller</Controller>
<action xmlns="http://www.hyfinity.com/mvc">getJContactDetails</action>
<unbound_param xmlns="http://www.hyfinity.com/mvc">value</unbound_param>
</mvc:Control>
<mvc:Data>
<GetContactRequest Successful="" Version="" xmlns="http://www.hyfinity.com/schemas/tutorial" xmlns:demo="http://www.hyfinity.com/schemas">
<Contact>
<ContactId>10346</ContactId>
</Contact>
</GetContactRequest>
</mvc:Data>
</mvc:eForm>
The response format will be the same and the complete wrapped document is transformed to produce the response pages, as defined within WebMaker. Please remember that any submitted elements that failed to bind will be placed under the Control/unbound_param element. Let's now return to an example Java Controller generated by WebMaker:
package com.hyfinity.controller.Java;
import com.hyfinity.utils.xml.XDocument;
import com.hyfinity.xplatform.JController;
import Java.util.Map;
import Java.io.File;
public class JGetContactsList extends JController
{
/**
* Process the request for this controller, and return the response data needed
* to display the next screen.
* @param data The bound XML data submitted from the browser.
* @param control A name to value mapping of all the other (non bound) parameters submitted.
* @param action The name of the action called from the browser.
* @return The XML data needed to show the next screen.
*/
public XDocument handleRequest(XDocument data, Map control, String action)
{
/* Set the name of the next page to display. This is the same name as specified in the Application Map tab. */
setNextPage("ContactDetails");
/* Perform processing of your choice to compose the response document. This may include calls to other
* web services, databases, etc. In this scenario, a response fragment from the Contact web service is
* being parsed from the file system to create the Data element within the WebMaker wrapper. See the tutorials
* for more background information on the contacts web services.
*/
XDocument contactDetails = new XDocument(new File("c:\\myjprojects\\example\\GetContactResponse.xml"));
/* Return the response data, which will be wrapped for us to produce the full message format that will
* be transformed to produce the next screen.
*/
return contactDetails;
}
}
Within each Java Controller, it is the handleRequest method that needs to be implemented to perform the required functionality. The above code fragment is simply loading in some data from a file, and returning it.
Important Note: The data incoming parameter contains the XML contents contained within the first element found within the eForm/Data element in the request message. This would be the GetContactRequest
information in the above example message. The XDocument object provides a wrapper around a standard W3C DOM, providing some convenience functions. Please refer to the Java-doc for more details.
The control map provides a read-only view of the unbound parameters submitted from the page, that were therefore placed into the eForm/Control section of the XML message. This maps the parameter names to their values and, within the example message above, would just contain the unbound_param
entry.
The final parameter contains the name of the action that was invoked from the page. This will be one of the names defined against the links on the Application Map canvas.
When complete, the method needs to return the details required to display the next page. These details need to be in XML format and will be placed within the eForm/Data element of the full wrapped XML message returned from the controller.
The following is an example response message, prepared to be sent back to the browser. This response message should resemble the same structure that was used for the Page Display Bindings within the WebMaker Page Design screen. You should also indicate the next page information in order to enable WebMaker to identify the transform to apply to the response message to produce the next page. The JController super class provides a helper method to do this, along with other useful functions. Please see the Java-doc for more details.
In this scenario, a response fragment from the Contact web service is being parsed from the file system to create the Data element within the WebMaker wrapper. You can perform processing of your choice to compose the response document. This may include calls to other web services, databases, etc.
<?xml version="1.0" encoding="UTF-8"?>
<eForm xmlns="http://www.hyfinity.com/xplatform" xmlns:mvc="http://www.hyfinity.com/mvc" xmlns:xg="http://www.hyfinity.com/xgate">
<Control>
<is_script_enabled xmlns="http://www.hyfinity.com/mvc">true</is_script_enabled>
<Page xmlns="http://www.hyfinity.com/mvc">ContactDetails.xsl</Page>
<Controller xmlns="http://www.hyfinity.com/mvc">mvc-Contacts-JGetContactsList-Controller</Controller>
<action xmlns="http://www.hyfinity.com/mvc">getJContactDetails</action>
</Control>
<Data>
<GetContactResponse Successful="true" Version="1-0" xmlns="http://www.hyfinity.com/schemas/tutorial">
<Contact ContactId="10346">
<IdentificationDetails>
<Title>Mrs</Title>
<Forename>Catherine Anne</Forename>
<Surname>Franks</Surname>
<DateOfBirth>1968-01-02</DateOfBirth>
<Gender>Indeterminate</Gender>
<HomeAddress>
<HouseNameNo>564a</HouseNameNo>
<Street>Pellington Road</Street>
<Locality/>
<Town>Chester</Town>
<CountyArea/>
<Postcode/>
<Country/>
</HomeAddress>
</IdentificationDetails>
<PersonalDetails>
<MaritalStatus>d</MaritalStatus>
<NumberOfDependants/>
<CarRegistration/>
<Notes/>
<OtherInformation/>
</PersonalDetails>
<BusinessDetails>
<OrganisationName>Burchell</OrganisationName>
<NationalInsuranceNumber/>
<TaxReference/>
<Salary/>
<PaymentFrequency>W</PaymentFrequency>
<OtherInformation/>
</BusinessDetails>
<ContactNumbers>
<EmailAddresses>
<EmailAddress Preferred="yes" Use="home">
<Email>cathy.franks@example.com</Email>
</EmailAddress>
<EmailAddress Preferred="no" Use="work">
<Email>catherine.franks@hyfinity.com</Email>
</EmailAddress>
<EmailAddress Preferred="no" Use="">
<Email/>
</EmailAddress>
</EmailAddresses>
<TelephoneNumbers>
<TelephoneNumber Preferred="yes" Use="work">
<TelCountryCode>44</TelCountryCode>
<TelNationalNumber>121 456 7890</TelNationalNumber>
</TelephoneNumber>
<TelephoneNumber Preferred="no" Use="work">
<TelCountryCode>44</TelCountryCode>
<TelNationalNumber>121 456 5432</TelNationalNumber>
</TelephoneNumber>
<TelephoneNumber Preferred="no" Use="">
<TelCountryCode/>
<TelNationalNumber/>
</TelephoneNumber>
</TelephoneNumbers>
<FaxNumbers>
<FaxNumber Preferred="no" Use="">
<FaxCountryCode/>
<FaxNationalNumber/>
</FaxNumber>
<FaxNumber Preferred="no" Use="">
<FaxCountryCode/>
<FaxNationalNumber/>
</FaxNumber>
<FaxNumber Preferred="no" Use="">
<FaxCountryCode/>
<FaxNationalNumber/>
</FaxNumber>
</FaxNumbers>
</ContactNumbers>
</Contact>
</GetContactResponse>
</Data>
</eForm>
Compiling and Running Java Controllers
You can use the in-built WebMaker Editor or a Java Development tool of your choice to author and compile the Java classes for each controller. You will need to ensure that the WebMaker xplatform.jar file is on your classpath for the code to compile successfully. This jar is located within the {Installer Location}\design\tomcat-design\common\lib directory of a standard WebMaker installation.
Once compiled, you can place the class within the J2EE container deployment path. For the default WebMaker installation and sample projects, this will reside in the directory {Installer Location}\users\{user name}\{workspace name}\mvc\{project name}\webapp\WEB-INF\classes. Please remember to use the full named package structure. Alternatively, you can place your compiled classes within a JAR file in the jars directory, as you would with any other Java web application ...\WEB-INF\lib.
Java docs
You can use the following link to access the JController Java doc. From here you can see more details for the XDocument
and other helper classes.
If your Java code is placed in the correct location, you should be able to use the Run Test action in the WebMaker Studio, which will deploy the Java into the Test environment. You can use the Debugger to check execution details via the View Debugger tab. This will also show details of any errors, including the inability to locate the controller or inability to execute the controller, etc.
XGate is a WebMaker server component that handles requests from the browser, performs data-bindings and forwards requests to server controllers. XGate also sends responses back to the browser. In both directions, XGate has the ability to use plug-ins to intercept and alter behaviour based on your custom code.
XGate can also act as a gateway to remote service invocations, including calls to SOAP and REST services. (Requires XML Controllers).
XGate Configuration
The XGate configuration details reside in the deployment descriptor file of the Web application.
If {webapps_location}
is the web application deployment area of the Web server, the XML deployment descriptor of a {myapp}
application can be found under {webapps_location}/{myapp}/WEB-INF/web.xml
.
An example web.xml file is shown below:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>
<servlet>
<servlet-name>xgate</servlet-name>
<servlet-class>com.hyfinity.xgate.HTTP2Java</servlet-class>
<init-param>
<param-name>morphyc</param-name>
<!-- Sets the Morphyc configuration file to use for this application -->
<param-value>c:/jprogramfiles/hyfinity/runtime/morphyc/helloworld_morphyc.xml</param-value>
</init-param>
<load-on-startup>10</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>xgate</servlet-name>
<!-- Set all incoming requests to be handled by XGate.
For an MVC application the mapping would be '*.do' to not pick up CSS, image, etc requests-->
<url-pattern>/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>30</session-timeout>
</session-config>
</web-app>
XGate also accepts a second configuration file stored in {webapps_location}/{myapp}/doc/xgate.xml
. This file is optional. If omitted, all the settings this file could contain default to 'false'. If defined, this file can be accessed via the WebMaker Application Map screen, using the Include Local Files option in the Application Details section.
An example of this configuration file is below.
<?xml version="1.0" encoding="UTF-8"?>
<xgate xmlns:xg="http://www.hyfinity.com/xgate" xmlns:xfact="http://www.hyfinity.com/xfactory">
<product>mvc</product>
<plug-ins>
<!--Turn on SXForms processing for binding HTTP Parameters into XML structure -->
<sxforms mark_unbound="true" delete_bound="true">true</sxforms>
<!--Ensure HTML output is returned to the browser -->
<ensure_html_response>true</ensure_html_response>
<!--Output the XHTML 1.0 Transitional Doctype-->
<output_doctype doctype_system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd" doctype_public="-//W3C//DTD XHTML 1.0 Transitional//EN">true</output_doctype>
<!-- disable pre processing of soap requests
If this is enabled, then a transform can be applied to incoming SOAP requests to format them for
processing as standard HTML parameter based requests.-->
<soap_preprocessing>false</soap_preprocessing>
<!-- If true, automatically set the Language control field based on the user's locale -->
<set_locale>false</set_locale>
<!-- Enables file upload support for this application. The two attributes are optional, and not provided by default.-->
<file_upload upload_dir="c:\temp\uploads" plugin_class="com.example.MyFileUploadPlugin">true</file_upload>
<!-- Define any custom plug-ins required -->
<custom_plugins>
<custom_plugin name="My Plug-in" runtime_instance="com.test.MyPlugin" priority="10"/>
</custom_plugins>
</plug-ins>
</xgate>
This file provides control over a number of in-built features and the ability to define your own custom plug-ins. These plug-ins reside between the browser and server and allow interception and inspection of the data received from the browser, and the response being sent back to the browser. For example, a plug-in could be used to enforce custom security checks before allowing access to the controllers. See the next section for more details on writing custom plug-ins.
Both of these configuration files are automatically set up when applications are published from the WebMaker Studio. You can change these files and place copies within the relevant locations under the webapp
directory for your project in the repository. This ensures your changed files will be reused for future test and publish operations.
XGate also makes use of other configuration files that are located within the doc directory within particular webapp structures, but these files should be managed automatically by the WebMaker Studio.
You can learn more about XGate plug-ins on the WebMaker Forum. Search for "xgate".
Adding Custom Plug-ins
Custom plug-ins allow you to write your own Java code to augment the standard functionality provided by the XGate Servlet.
Each custom plug-in needs to implement the com.hyfinity.xgate.XGatePlugin interface, the JavaDoc for which is available here. This interface defines two methods that require implementation, processInput
and processOutput
. The first will be called on each incoming request to give you the option to manipulate the request before it is passed to server controllers for processing, whereas the second will be called with the response received from server controllers (usually HTML content) to perform any final manipulation before the response is returned to the browser.
You can define as many custom plug-ins as you need by listing each one as a custom_plugin element in the xgate.xml file as shown below.
<xgate>
...
<plug-ins>
...
<custom_plugins>
<custom_plugin name="my plug-in" priority="10" runtime_instance="com.company.MyPlugin"/>
<custom_plugin name="custom plug-in 2" priority="70" runtime_instance="com.company.MyPlugin2"/>
</custom_plugins>
</plug-ins>
</xgate>
The name attribute provides a friendly name for the plug-in that is output to the Debugger logs, the runtime_instance attribute provides the classname for your plug-in, and the priority configures the order in which the plug-ins will execute. Plug-ins with a lower priority number will be called first. All the in-built plug-ins that handle the data binding process, etc., have a fixed priority of 50. Therefore, if you add your custom plug-in with a priority less that this, the message it receives will generally be a flat list of parameters sent from the browser, whereas if you use a priority value over 50, the message will look like the structured XML you see in the various binding screens.
If you need to return non-HTML content (e.g. to return a PDF file), you can do this from the processOutput
method. You need to output your content to the response object directly, and then set the output document to null (output.setDocument(null)) to prevent XGate from attempting to return the normal content.
Once you have written your plug-in you will need to ensure it is compiled successfully and available to your deployed/published application. One way to do this is to place your compiled classes/jar within the WEB-INF directory under the webapp directory for your project in the repository. All the jars needed to compile your code can be found in the <install_dir>/design/tomcat-design/common/lib directory.
When you are trying to debug custom plug-ins, it is useful to switch the logging level to debug via the Test Settings menu option. You will then be able use the Debugger to see the state of the message before and after calling each plug-in. This is normally suppressed for applications during development.
For additional details on testing, debugging and publishing your applications, please see the following sections:
You can create pages that make asynchronous calls to server Controllers, refreshing only parts of a full page. In order to achieve this, you need to add a partial page. You can use icons on the right-hand-side of the Page Thumbnails strip on the Page Design tab or the palette on the left-hand-side of the Application Map tab. The design of partial pages is very similar to normal page design, whereby you can access server controller functionality, perform automatic bindings and also use schema-driven data sources to accelerate page design.
Some of the key differences between full and partial pages include:
In almost all cases, partial pages will be linked to from full pages. The partial pages represent a part of the full page.
Each partial page has an integrated server controller because a partial page requires a call to something to enable a refresh of the part of the full page that it is dealing with. You can access the controller details from the right hand panel of the Application Map screen when a Partial Page is selected on the central canvas. The rest of the development process is very similar to the process for developing full pages.
You may notice that the partial page previews do not show the main page that they are called from. They simply show the partial page content.
In order to make an asynchronous call to the server from a partial page, you have to use the AJAX submission option within the Events tab of the Page Design screen. Against this submission type, you will notice the need to provide a Target Group as well as a Source Type. The target group represents the area of the screen that will be refreshed with the response from the server. You should ensure that you have a suitable container group to receive the response of the AJAX Submission. The palette contains some default containers that have been preconfigured e.g. Partial Page Container
. You will also notice a Source Type option. This allows you to submit a part of the full page as the request data, or the full page if this is more appropriate depending on the data required by the Partial Page.
WebMaker allows you to decompose large applications into multiple projects. This provides a more manageable application specification and can aid better understanding during development and maintenance. This section details the options available to integrate these multiple projects to produce a single application.
Each project within WebMaker has its own set of assets and can communicate with other projects.
There are scenarios when two or more projects may wish to 'communicate' with each other. These scenarios typically fall into two categories:
Call Remote Page - A screen in one project contains a button (or other event) that shows a screen from another project.
Call Remote Controller - A controller in one project wishes to call a controller in another project.
Important Note: A key requirement for integrating multiple projects is that all the action names (Action links on the Application Map) used across your projects must be unique. One way to achieve this is to simply add a project-specific prefix to the action names for example.
Considerations for Test Settings
Blueprint Specification part - The Test Settings screen (representing the underlying Morphyc.xml file) represents the control file for an application and lists all projects within the same application context. Multiple projects can be configured to save their deployment configuration information into the same morphyc file. Assuming one of the projects acts as the master/parent project, this can be done by selecting the Test Settings - Location Details from the menu for a 'child' project, and updating the value for the Test Settings File Location and the Test Web Server Location to the values from the 'parent' project, before hitting the Save button. To populate the changed settings for the 'child' project into the 'parent' project, you need to perform a Run Test to setup the necessary runtime test environment details.
This needs to be repeated for each 'child' project to ensure they are successfully referenced in the same morphyc configuration file in the 'parent' project. This is a one off process. Once the correct entries has been placed in the required morphyc file via Test Settings, they will be maintained in future.
Call Remote Page
Once the Test Settings steps have been completed, the running 'parent' project should contain all the included projects, and it becomes possible to make calls between pages in different project as if they were in the same project. To check the setup, go to the Test Settings screen for the 'parent' project and view the Projects in this Environment. You should see the 'parent' project and all the 'child' projects that are referenced.
You can then use the Action name that you want to call (in the target project) as the URL that is called from the source page, whether this be through form or ajax submission or just a standard anchor link. WebMaker currently does not list the actions of a second project using the Form Submission action type within the Page Design screen. Instead, you should select the Enter action name option and then type in the action name manually.
Call Remote Controller
In order to achieve the second type of project interaction, you need to create what is known as an Inter-Project Proxy. These are controllers that work in a very similar way to Web Service Proxies, but rather than representing remote external service URLs, inter-project proxies are used to represent a controller in another project. In the (source) project that wishes to call the controller in the second (target) project you need to create an 'empty' controller, which will act as the proxy to the real controller within the target project. As far as the first project is concerned, this new 'empty' controller will appear the real controller in the second project, and can be called directly as required. At runtime, any calls to Inter-Project Proxy controllers will actually be handled by the real controller in the second project.
In order to achieve this, the 'empty' (no rules processing) Proxy Controller needs to be set-up correctly. This can be achieved by opening the Project Settings tab and clicking on the Runtime Patterns tab. Typically, click on the Model layer to set-up a Remote Proxy Controller. Type in the New Filename for the reference to the Controller you want to call e.g. {RemoteControllerName_Proxy}
and click on the Clone Pattern button. This will display a further screen that allows you to select the Base Pattern to be used - In this case the Remote_Service_Proxy.xml
file. Finally, click on the Clone Pattern button to create the Controller.
Once this is done, open the Test Settings and select the Agent Types menu option. Click on the Agent Id for the Controller just created, and then change its Agent Type to the Inter Project Proxy
option and enter the Target Agent Id as the full Agent Id of the Controller in the target project. This will appear something like mvc-{project}-{pattern}-{agent}
. Note: This value can be seen in the Debugger logs of the 'target' project.
Finally, Click on the Change Agent Type to commit the change.
Inter-Project Proxies versus Web Service Proxies
Please Note: Use of Inter Project proxies requires that the deployment settings mentioned above are completed to ensure both projects are running within the same application server and in the same Java Virtual Machine (JVM). If you need to communicate between projects that are running on different machines, then you should deploy the 'empty' controller as a Web Service Proxy
using the http service
option, and the target controller should be deployed as a Web Service
. This will allow you to treat the proxy controller as if it was the Agent in the target project and call it directly, even though in reality it is deployed to a separate machine and will be accessed via HTTP.
Rendering Pages in Remote Projects
The details above explained how you can call an action in another project by adjusting the event definition for the relevant trigger button. This works fine when you know at design time that you will always be navigating to another project, but what about the situation where you need to decide on the server which page (from multiple projects) to render? When you are dealing with a single project, you can make these decisions on the server by changing the value of the Page
control field in the bindings message structure. But when you want to render a page in a second project it is a bit more complicated. To do this, you will need to create an inter-project proxy to the 'view' controller of the 'target' project. Then, when you need to render the page from the second project, you need to adjust the Page control value, and then call this view proxy to tell the target project to render the correct page. It is important to note however that when this is done, the HTML information returned from the target 'view' controller will still flow back through the controller in the 'controller' and 'view' layers of the current project before being returned to the browser. The rules within the local controller may need to be adjusted to alter the data structure if required.
Binding Considerations When Calling Pages in Remote Projects
You are able to provide different binding structures for each action submission from a page. A WebMaker Project does not know about actions you may wish to call in external projects. You will therefore not see actions in such external projects within the Bindings tab. As a result, actions to external projects will simply submit data that will have no bindings and resort the default binding structure, ending up in the Control section of the bindings document, instead of the formData section.
The best approach to ensure your submission data is structured, even when such data is submitted to remote projects, is to set the required bindings structure for one of the actions. Then set the Set bindings and structure based on another action? option in the Advanced Bindings Mode section for ALL other actions and use the settings for the base action defined earlier. This triggers WebMaker to use the same binding structure for all actions, even for actions it does not know about, such as those being called in remote projects.
WebMaker enables translations, post development. This can be achieved by setting up translation files, which map information on the various pages to their translations in the required language and locale. WebMaker attempts to locate translation files for locales first and, if not present, will then attempt to access general translation files for the language (e.g. if the en-GB
) translation file is not available, then WebMaker will seek to process file en
). If the translation file is not present then the originally developed content for the page will be displayed.
The first step is to create a web application based on one of the languages you need to support, ideally the most commonly used language. Then add language/locale specific XML translation files for each language, to apply new
labels, group names, tool-tips and drop-down list options for the additional languages.
For full details on how to set this up, please refer to the Forum entry - How do I set-up Multi-Lingual Forms for Languages and Locales? .