Web Experience Factory is a pretty good tool for rapid development, but its designer lacks automated documentation that can be used to explain an application to a new developer. Models can get extremely complicated, especially when they're assembled by developers who are just starting to use the tool. This article describes how graphs can be generated using eclipse.
Using an Eclipse Plugin to Generate Graphs
I've worked with projects that, in some cases, imported dozens of other models, making it quite challenging to follow a sequence of events. About a year ago I had the idea of generating a graph showing how models are imported into each other, but quickly got lost in the details of graphing within eclipse.
I recently stumbled on an open source application named Graphviz, and when I saw the simplicity of using a DOT file to describe a graph, I was able to quickly develop a plugin to inspect a WEF model and produce a graph of it.
An easy candidate for a graph is tracing how models import other models. The plugin does this by recursively traversing the import builders in each model, producing a graph similar to this example.
Once I figured that out, I was able to add some more to the plugin, producing a graph of service consumer operation calls like the one below. This graph indicates that model_4 contains an action list builder named alTest that invokes the doSomeOperation operation exposed by the service consumer builder named svcConsumer.
The graph of action list calls (builders which invoke action lists) is very similar to the one above, except the target node is an action list instead of a service operation.
After the plugin is installed by following these instructions, you will see the following submenu when right clicking on a model.
Just select the graph you wish to generate and it will appear in an eclipse browser window. Although I developed this tool for my own use, I'm making it available free of charge to anyone.
If the tool doesn't work for you, then please leave me a message on this blog (or email me).
References: Download plugin from http://www.dsixe.com/eclipse
A collection of tips and best practices for developing great applications using Web Experience Factory and Java EE.
Showing posts with label WEF. Show all posts
Showing posts with label WEF. Show all posts
Monday, December 31, 2012
Wednesday, November 28, 2012
WEF Profiling Explained
Profiling is a frequently misunderstood concept in web experience factory. This blog entry describes profiling by comparing it to java code, something that more developers are familiar with.
Comparing Profiles to Java Code
Many people struggle with the concept of profiling and profile sets, but it can be closely compared to a conditional statement in java. Suppose that we have a button that needs to be displayed if the application is accessed from an android device. Coding this using java would look something like this (depending on the framework):
The same can be accomplished with WEF profiling except we don't have any code to work with, only a button builder with inputs. Ideally, we would want to apply the results of profiling to the builder enable input, setting it to true or false which would effectively replicate what the java code above does.
Think of a profile set as a collection of profiles and the selection of a given profile is the result of a conditional statement. That conditional statement is controlled by a selection handler. Let's look at the code above again from this perspective
The profile set selection handler is the engine that controls which profile is selected. In this particular case, we're using the mobile selection handler which contains logic that looks at the HTTP request user agent header to determine which profile is selected. Moving one step further, the selection handler doesn't really return a value like "android" per se, it chooses a profile.
Suppose we not only want to control the visibility of a button, but we also want to execute a call to a service provider operation when the application is accessed from an android device. In java, we would add some logic
For the sake of making this explanation clearer, let's also add some code to handle iPhones as well as a handler for the default case
That all seems very obvious if we were using java, but how is it implemented in WEF using profiling?
Here is the detailed profile entry for the button
Similarly, the action list is profiled
and below is the detailed profile entry
Only one profile in any profile set can be active at one time, and profiling is applied when the user session is first initiated. It is not possible to use two different profiles from the same profile set or switch profiles in the same session.
Comparing Profiles to Java Code
Many people struggle with the concept of profiling and profile sets, but it can be closely compared to a conditional statement in java. Suppose that we have a button that needs to be displayed if the application is accessed from an android device. Coding this using java would look something like this (depending on the framework):
if (request.getHeader("User-Agent") == "android"){ button.visible = true; }
The same can be accomplished with WEF profiling except we don't have any code to work with, only a button builder with inputs. Ideally, we would want to apply the results of profiling to the builder enable input, setting it to true or false which would effectively replicate what the java code above does.
Think of a profile set as a collection of profiles and the selection of a given profile is the result of a conditional statement. That conditional statement is controlled by a selection handler. Let's look at the code above again from this perspective
if (profileset.selectionHandler.result == "android"){ button.enable = true; }
The profile set selection handler is the engine that controls which profile is selected. In this particular case, we're using the mobile selection handler which contains logic that looks at the HTTP request user agent header to determine which profile is selected. Moving one step further, the selection handler doesn't really return a value like "android" per se, it chooses a profile.
Suppose we not only want to control the visibility of a button, but we also want to execute a call to a service provider operation when the application is accessed from an android device. In java, we would add some logic
if (profileset.selectionHandler.profile.name == "android"){ button.enable = true; invokeSomeOperation(); }
For the sake of making this explanation clearer, let's also add some code to handle iPhones as well as a handler for the default case
if (profileset.selectionHandler.profile.name == "android"){ button.enable = true; invokeSomeOperation(); } else if (profileset.selectionHandler.profile.name == "iphone"){ button.enable = false; invokeSomeOperationIPhone(); } else{ button.enable = false; // do nothing }
That all seems very obvious if we were using java, but how is it implemented in WEF using profiling?
Here is the detailed profile entry for the button
Similarly, the action list is profiled
and below is the detailed profile entry
Only one profile in any profile set can be active at one time, and profiling is applied when the user session is first initiated. It is not possible to use two different profiles from the same profile set or switch profiles in the same session.
Labels:
profileset
,
profiling
,
web experience factory
,
WEF
Wednesday, November 7, 2012
WEF and Custom HTML
Working with custom HTML is probably one of the most common patterns I've seen when building an application with web experience factory (WEF). Typically this is a situation where I'm given a really nice HTML stub from a professional web designer and I need to build an application around it.
Don't Fight with WEF
A common mistake I see all the time is a web developer trying to untangle or intercept the code generated by WEF. Don't do it, you're going to lose your mind or create an unmaintainable mess (or both). Here are a few tips that should help:
1 - Turn off the theme
2 - Don't let the data page builder create the UI
3 - Learn how to exploit page automation
Turn off the Theme
There are two ways to accomplish this, adding a theme builder to your model and selecting the individual components, or blanking out the theme file name in the project's override.properties.
The theme is great when using WEF's default user interface, but it just gets in the way of custom HTML.
Dumb Down the Data Page Builder
The data page builder is the heart of page automation in WEF, but sometimes it wants to do too much, and again, gets in the way of custom HTML. We want dumb it down a little by turning off the option to make the UI from data.
In many cases we'll also want to set the page type to view only if we're only displaying data, but this depends on the use case.
Exploit Page Automation
Now that we've turned off some of the noise that we don't need, how do we tell the page automation to place data on our custom HTML? This is easily done by adding our own name attributes to the HTML elements. Whenever page automation finds a value for the name attribute that matches the data specified in the data page variable, it inserts a data value. Take for example the following XML data
We can ask page automation to take this custom HTML
This is how page automation sees the HTML name attributes that we added
You may have noticed that we added sorting capability to the first column, this is standard practice using a data column modifier (DCM) builder. The DCM builder needs to be able to identify the location of the table headers, and since we have custom HTML, we have to do this ourselves by adding a suffix Header to the name attribute in the table header rows.
Also note that the table row identified with the name attribute contact refers to the repeating XML data element contact. Page automation will create a new HTML row for each contact element in our data.
The edit button is there to demonstrate that we can easily add builders that refer to named locations in our HTML, just as if the data page builder had done all the work for us.
More information about manually marking up HTML for page automation can be found here.
Don't Fight with WEF
A common mistake I see all the time is a web developer trying to untangle or intercept the code generated by WEF. Don't do it, you're going to lose your mind or create an unmaintainable mess (or both). Here are a few tips that should help:
1 - Turn off the theme
2 - Don't let the data page builder create the UI
3 - Learn how to exploit page automation
Turn off the Theme
There are two ways to accomplish this, adding a theme builder to your model and selecting the individual components, or blanking out the theme file name in the project's override.properties.
The theme is great when using WEF's default user interface, but it just gets in the way of custom HTML.
Dumb Down the Data Page Builder
The data page builder is the heart of page automation in WEF, but sometimes it wants to do too much, and again, gets in the way of custom HTML. We want dumb it down a little by turning off the option to make the UI from data.
In many cases we'll also want to set the page type to view only if we're only displaying data, but this depends on the use case.
Exploit Page Automation
Now that we've turned off some of the noise that we don't need, how do we tell the page automation to place data on our custom HTML? This is easily done by adding our own name attributes to the HTML elements. Whenever page automation finds a value for the name attribute that matches the data specified in the data page variable, it inserts a data value. Take for example the following XML data
<contacts> <contact> <name>n1</name> <phone>p1</phone> </contact> <contact> <name>n2</name> <phone>p2</phone> </contact> </contacts>
We can ask page automation to take this custom HTML
<html> <head> <title>Default Test Page</title> </head> <body> <table name="contacts" width="50%"> <tr align="center"> <th><span name="nameHeader">Name</span></th> <th>Click to update</th> <th><span name="phoneHeader">Phone</span></th> </tr> <tr name="contact" align="center"> <td><span name="name"></span></td> <td><span name="btn"></span></td> <td><span name="phone"></span></td> </tr> </table> </body> </html>to produce a user interface, and this is what we see in the browser when we launch the application
This is how page automation sees the HTML name attributes that we added
You may have noticed that we added sorting capability to the first column, this is standard practice using a data column modifier (DCM) builder. The DCM builder needs to be able to identify the location of the table headers, and since we have custom HTML, we have to do this ourselves by adding a suffix Header to the name attribute in the table header rows.
Also note that the table row identified with the name attribute contact refers to the repeating XML data element contact. Page automation will create a new HTML row for each contact element in our data.
The edit button is there to demonstrate that we can easily add builders that refer to named locations in our HTML, just as if the data page builder had done all the work for us.
More information about manually marking up HTML for page automation can be found here.
Labels:
custom html
,
page automation
,
table headers
,
WEF
,
WPF
Monday, April 9, 2012
Managing CVS Branches with WEF
Today I finally had the time to resolve a problem I had experienced regarding branches on CVS with web experience factory. Sometimes I want to work with a branch that, for some unknown reason, doesn't show up in eclipse drop down lists. I know it exists, but I have no means to select it.
Eclipse and CVS Branches
The solution to the problem is documented in this eclipse CVS FAQ list, but it's worth mentioning in a WEF blog because we typically don't check in the .project file. As the FAQ explains, eclipse looks at this file to determine which branches are available for a project, so we have to change the CVS configuration to look at another file instead.
Checking in the .project file causes problems when later attempting to check out using the new WEF project wizard. Following the instructions in the FAQ above provides an easy work around.
Hope someone finds some use in this tidbit of information.
Eclipse and CVS Branches
The solution to the problem is documented in this eclipse CVS FAQ list, but it's worth mentioning in a WEF blog because we typically don't check in the .project file. As the FAQ explains, eclipse looks at this file to determine which branches are available for a project, so we have to change the CVS configuration to look at another file instead.
Checking in the .project file causes problems when later attempting to check out using the new WEF project wizard. Following the instructions in the FAQ above provides an easy work around.
Hope someone finds some use in this tidbit of information.
Labels:
CVS branches
,
portlet factory
,
web experience factory
,
WEF
,
WPF
Monday, July 25, 2011
Ajax Busy Indicators in WEF
This is my first posting for websphere portlet factory re-branded as web experience factory. I guess I'll have to get used to WEF, at least it sounds like a word now although not very meaningful.
Looking Under the Hood
I often seem to find myself snooping in code, usually when trying to fix a bug or extend some OOTB functionality to my liking. In this case I had a need to display some busy indicators during an unusually long ajax call, which led me to the javascript that enables ajax in WEF.
The file of interest is WebContent\factory\clientjavascript\ajax\ppr.js and inside it, the following code can be found:
Since directly altering this file is not a good idea, we can instead take the advice in the comment and overload the functions in our own script:
I've used the dojo standby widget which does a great job communicating to the user that something is taking place while disabling part of the UI, preventing unnecessary repeated requests.
Done!
Looking Under the Hood
I often seem to find myself snooping in code, usually when trying to fix a bug or extend some OOTB functionality to my liking. In this case I had a need to display some busy indicators during an unusually long ajax call, which led me to the javascript that enables ajax in WEF.
The file of interest is WebContent\factory\clientjavascript\ajax\ppr.js and inside it, the following code can be found:
// Can overload these to, e.g., show a progress indicator for long operations. startLoad: function() { }, endLoad: function() { },
Since directly altering this file is not a good idea, we can instead take the advice in the comment and overload the functions in our own script:
dojo.require("dojox.widget.Standby"); var standby = new dojox.widget.Standby({ target: "basic2" }); wpf_ppr.startLoad = function(){standby.show()}; wpf_ppr.endLoad = function(){standby.hide()};
I've used the dojo standby widget which does a great job communicating to the user that something is taking place while disabling part of the UI, preventing unnecessary repeated requests.
Done!
Labels:
ajax
,
dojo standby
,
WEF
Tuesday, June 21, 2011
Building a WPF Project with Ant
Generally speaking, I never endorse deploying an application to a production environment unless it has been built from scratch in a clean environment. This means that building a portlet factory WAR from the eclipse IDE is not the way to do a production build, even though it is really convenient.
Building with Ant
Apache ant has been around for a long while now, is an excellent framework for building WAR files and is the tool that WPF uses to build its own WAR files. In older versions of WPF the build process was somewhat lacking, but the team at IBM has really done a great job with the latest release of the product (I think this improved build may have been available in 6.1.5, but we skipped over that and went straight to 7.0).
Below is an example of how I've taken the sample build.xml provided with the product and modified it to pull code from CVS and allow for project specific settings.
The build.properties is mostly unchanged:
Note that I've added a new property CVSTag which is used to identify which label or branch to use with CVS. I've also changed the project.name property to a self descriptive value that will stand out during a build if it is not changed. The intent is that this build.properties file does not contain any project specific values - those will be set elsewhere.
Next, I've taken the sample build.xml and made a few changes to it as well:
Noteworthy, from top to bottom:
Now that I've done some prep work, I can build any WPF project with a short bit of xml saved as MyAwesomeWPFProject.xml:
The heavy lifting here is done with the import of build.xml, which is just like adding everything in that file to my script, but allowing me to override any targets within it. In this case I've added my own propertiesOverride where I can change values that were defined in build.properties and addPackages where I can add any featuresets that my project requires.
Building my project is now as simple as
Piece of Cake
Prior to this, I had my own homebrew build process that I am now glad to throw away. It served me well for the last three years, but this is more robust and I really like the way I can add featuresets.
Building with Ant
Apache ant has been around for a long while now, is an excellent framework for building WAR files and is the tool that WPF uses to build its own WAR files. In older versions of WPF the build process was somewhat lacking, but the team at IBM has really done a great job with the latest release of the product (I think this improved build may have been available in 6.1.5, but we skipped over that and went straight to 7.0).
Below is an example of how I've taken the sample build.xml provided with the product and modified it to pull code from CVS and allow for project specific settings.
The build.properties is mostly unchanged:
CVSTag=HEAD # Build source root directory !NOTE! This value must be an absolute path. buildsrc.location=C:/wsad/GCPS_V7/PF_Build/WPF7/${project.name} # Build temp location. This is where the temporary project will be created for building purposes buildtmp.location=${buildsrc.location}/buildtmp # The root directory for the Portlet Factory files. wpf.artifacts.dir=C:/wsad/GCPS_V7/PF_Build/WPF7 # The output location for the generated war files. builddist.location=${buildsrc.location}/dist # The location of the pbportlet.jar file. This ships with portal c2a.lib.dir=${wpf.artifacts.dir}/WebSphere Portal # The name of the project (used for identifiying war files) project.name=SET PROJECT NAME IN XML BUILD FILE #-- The following properties should not need to be changed under normal circumstances. -- # The root directory of the temp project. This is used by projectDeploy.xml project.location=${buildtmp.location} # The WebContent directory of the project that will be created. This is also used by projectDeploy.xml webcontent.location=${project.location}/WebContent # The output directory for standalone deployment wars. build.deployment.war.builddir=${builddist.location} # The output directory for the portlet wars wpf.portletwar.location=${builddist.location} # The shipping version of Portlet Factory version=7.0.0
Note that I've added a new property CVSTag which is used to identify which label or branch to use with CVS. I've also changed the project.name property to a self descriptive value that will stand out during a build if it is not changed. The intent is that this build.properties file does not contain any project specific values - those will be set elsewhere.
Next, I've taken the sample build.xml and made a few changes to it as well:
<project name="build" default="build4GCPS" basedir="."> <!-- define build script properties. --> <target name="properties" depends="propertiesOverride"> <property file="build.properties" /> </target> <target name="build4GCPS" depends="properties, clean"> <!-- create temp directory structure for building --> <mkdir dir="${builddist.location}" /> <mkdir dir="${buildtmp.location}" /> <cvs package="${project.name}" cvsroot=":pserver:blduser:XXXX@cvserver1:/usr/cvs/projects" tag="${CVSTag}"/> <!-- create temp dir to build on top of --> <copy todir="${buildtmp.location}/.deployment"> <fileset dir="${buildsrc.location}/.deployment"/> </copy> <copy todir="${webcontent.location}"> <fileset dir="${buildsrc.location}/WebContent"/> </copy> <!-- optional task to generate the logs folder in the temp location. Specific war generation tasks will log their data to this directory. --> <mkdir dir="${buildsrc.location}/WebContent/WEB-INF/logs"/> <!-- expand factory image into the webcontent.location --> <ant antfile="${webcontent.location}/projectDeploy.xml" target="expandFactoryImage" > <property name="runtime.image" value="${wpf.artifacts.dir}/Images/factory${version}.zip" /> </ant> <antcall target="addPackages"/> <!-- build source files --> <ant antfile="${webcontent.location}/projectDeploy.xml" target="compile" /> <!-- build 286 portlet war, and give it a new name. --> <ant antfile="${webcontent.location}/projectDeploy.xml" target="buildPortletWar" > <property name="wpf.portletapi.target" value="build286StandardPortletWar"/> <property name="project.name" value="${project.name}"/> </ant> </target> <target name="addPackages"> <fail>Your project ant script is missing a target named "addPackages". This is used to add WPF featuresets.</fail> </target> <target name="propertiesOverride"> <fail>Your project ant script is missing a target named "propertiesOverride".</fail> </target> <!-- clean the project --> <target name="clean" depends="properties"> <delete dir="${buildsrc.location}" /> </target> </project>
Noteworthy, from top to bottom:
- added depends="propertiesOverride" to the properties target.
- added a call to the ant cvs task. This will retrieve any code that was added to source control.
- removed the sample antcall to addFeatureSet and replaced it with a call to my own addPackages.
- finally at the bottom I've added default implementations for the new targets that will cause the build to fail if they're not defined elsewhere.
Now that I've done some prep work, I can build any WPF project with a short bit of xml saved as MyAwesomeWPFProject.xml:
<project name="mainDeployment" default="build4GCPS" basedir="."> <description>Template script for building a portlet factory WAR for deployment</description> <import file="build.xml"/> <target name="propertiesOverride"> <property name="project.name" value="MyAwesomeWPFProject"/> </target> <target name="addPackages"> <ant antfile="${webcontent.location}/projectDeploy.xml" target="addFeatureSet" > <property name="pkg" value="${wpf.artifacts.dir}/Packages/Tutorials.pkg" /> </ant> </target> </project>
The heavy lifting here is done with the import of build.xml, which is just like adding everything in that file to my script, but allowing me to override any targets within it. In this case I've added my own propertiesOverride where I can change values that were defined in build.properties and addPackages where I can add any featuresets that my project requires.
Building my project is now as simple as
ant -f MyAwesomeWPFProject.xmland if I need to build a specific version that has been labeled in CVS, I can provide that label like this
ant -f MyAwesomeWPFProject.xml -DCVSTag=MyLabelwhich will override the value in build.properties.
Piece of Cake
Prior to this, I had my own homebrew build process that I am now glad to throw away. It served me well for the last three years, but this is more robust and I really like the way I can add featuresets.
Labels:
ant
,
build script
,
WEF
Subscribe to:
Posts
(Atom)