tag:blogger.com,1999:blog-13734140156861959862024-03-05T01:03:56.446-05:00Another Web Development BlogA collection of tips and best practices for developing great applications using Web Experience Factory and Java EE.Carl Dominguehttp://www.blogger.com/profile/02941990420640564181noreply@blogger.comBlogger57125tag:blogger.com,1999:blog-1373414015686195986.post-51689173725835839512016-12-01T19:36:00.000-05:002016-12-02T14:30:30.365-05:00What is a Java Lambda Expression?A lambda expression is a shortcut notation for an anonymous class implementation of an interface.<br />
<br />
<br />
<h3>
Which Interface? Where is the Type Definition...?</h3>
A lambda expression is used in the context of a target method signature. For example the following method signature<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> public String doSomething(String s, MyInterface mi){...}</span><br />
<br />
could be invoked with the following code using an anonymous class:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> doSomething("hello", new MyInterface(){</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> public void myMethod() { </span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> System.out.println("goodbye");}</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> });</span><br />
<br />
it can also be invoked with the following lambda expression:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> doSomething("hello", ()->{ System.out.println("goodbye");});</span><br />
<br />
<br />
<br />
The target method <b>doSomething</b> is expecting two parameters - a <b>String</b> and an instance of <b>MyInterface</b>. The <b>String</b> value is clearly "hello", but the other is not so obvious. What happens here is the compiler sees that an instance of <b>MyInterface</b> needs to be somehow created from this expression and passed as the second parameter:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> ()->{ System.out.println("goodbye");}</span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
To understand how this takes place we need to look at <b>MyInterface</b><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> interface MyInterface {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> public void myMethod();</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<br />
<br />
<h3>
So what's so special about that interface?</h3>
The key characteristic of this interface is that it contains <i>exactly one method definition</i>. This makes it a functional interface, and it could be annotated with <b>@FunctionalInterface</b> for clarity although this is not necessary. Lamba expressions only work with functional interfaces.<br />
<br />
Since the compiler needs to create an instance of <b>MyInterface</b> which it can pass to <b>doSomething</b>, it needs an implementation of <b>myMethod</b>.<br />
<br />
<br />
<h3>
Where is the compiler going to find an implementation of myMethod?</h3>
This is where the lambda expression comes into the picture. A lambda is a shortened syntax for an anonymous class definition, but since the interface contains only one method definition, the compiler can easily fill in the blanks. The left side of the lambda expression is a placeholder for the interface method signature parameters. Without this left side, the implementation would have no point of reference for these parameters.<br />
<br />
For example if we change the signature to<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> interface MyInterface {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> public void myMethod(int myNum);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Then our lambda would look like this<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> (i)->{ System.out.println("goodbye");}</span><br />
<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
Note that the simple implementation doesn't use the int value (which is ok).<span class="Apple-tab-span" style="white-space: pre;"> </span><br />
<div>
<br /></div>
<div>
<br /></div>
<h3>
Recap</h3>
<div>
Take an anonymous class implementation, strike out the unnecessary syntax which the compiler can figure out because there's only one method in the interface, then add a <span style="color: blue; font-family: "courier new" , "courier" , monospace;"><b>-></b> </span></div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;"> doSomething("hello", <strike>new MyInterface</strike><b style="text-decoration: line-through;">()</b><strike>{</strike></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <strike>public void myMethod</strike>()<b><span style="color: blue;">-></span>{ </b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><b> System.out.println("goodbye");}</b></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> <strike>}</strike>);</span><br />
<br />
What's left is a lambda expression!</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-84784170501621950502015-11-10T18:02:00.001-05:002015-11-10T18:02:53.196-05:00Making HTML readonly Attribute Look Like DisabledA quick entry in case anybody else runs into this scenario. I have a form with some text boxes which need to display as disabled, but the values aren't being submitted with the form. As it turns out, this is native behavior for the 'disabled' attribute.<br />
<br />
The workaround is to use the 'readonly' attribute instead, but the problem with that is it doesn't render with a grayed out background. After fiddling for a while I came up with the following script:<br />
<br />
<br />
<pre>dojo.ready(function(){
dojo.query("[readonly]").forEach(function(node, index, arr){
dojo.attr(node.parentNode,"style", "background-color: #efefef !important");
});
});
</pre>
<br />
Maybe someone else will find this useful.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-12235737976526126252015-04-30T11:10:00.002-04:002015-04-30T11:16:52.967-04:00Adding a Log4j Console to a Web ApplicationThere's a popular open source jsp that allows changing the log4j levels for a web application called <a href="https://gist.github.com/iamkristian/943918">log4jAdmin.jsp</a> that I've been wanting to use for troubleshooting, but using it poses a problem. Typically, deployable artifacts are built by an automated process and are not altered as they make their way through the different environments (development/integration/quality assurance/production). I definitely don't want a log4j administration console finding its way into a production environment as this would allow end users to access it.<br />
<br />
So the ideal situation would be to add the jsp to the application <b>after it has been deployed</b>. I could have the system administrators add the file to the WebSphere installedApps directory, but this isn't recommended (and they would likely not agree to do this anyways).<br />
<br />
A proper alternative is to use WebSphere's deployment process. Instead of updating an application using the default option, look further below on the page:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNL6GFxMViFwvlT0KfFg1zXxYylY57VxH_o6U1akRth55Y9qn4rZsPk0U6dZOuPJiwOCrA3WoDK0-SdJTbslN3alSlgV_oUTAVm1DkX1ud_PgbVE3_t7YaWm0_l7NcGkLeNLjBWBB6z6KD/s1600/$2E91E482AF26E731.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNL6GFxMViFwvlT0KfFg1zXxYylY57VxH_o6U1akRth55Y9qn4rZsPk0U6dZOuPJiwOCrA3WoDK0-SdJTbslN3alSlgV_oUTAVm1DkX1ud_PgbVE3_t7YaWm0_l7NcGkLeNLjBWBB6z6KD/s1600/$2E91E482AF26E731.png" height="320" width="282" /></a></div>
<br />
<br />
The contents of the zip should mirror the exploded folder structure in installedApps. In this case the zip contains a single JSP:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivfSnp3adLVaBXa7P2ki-rItxEnL7QqveTgjB26Uw5bGOZ9-ZuEjcQKU1RWS7qNQqCOfj5DuNm2_gZ4Zqs57bDQ1KomOVAFRcM5ilG9W_SCM5qqocRIrfM3gi8ADkmYDoBXzaoI_66N7mh/s1600/$3F265CEBB5D54D30.bmp" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivfSnp3adLVaBXa7P2ki-rItxEnL7QqveTgjB26Uw5bGOZ9-ZuEjcQKU1RWS7qNQqCOfj5DuNm2_gZ4Zqs57bDQ1KomOVAFRcM5ilG9W_SCM5qqocRIrfM3gi8ADkmYDoBXzaoI_66N7mh/s1600/$3F265CEBB5D54D30.bmp" height="214" width="320" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
Any number of files can be injected into a deployed application using this technique, but in this particular instance I use it to manage Log4j log levels.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-69569558350170081192015-02-26T11:03:00.002-05:002015-02-26T11:09:14.862-05:00Error Running wsadmin.shI've been making extensive use of wsadmin.sh as part of scripted WebSphere application installs to virtual machines, and today a script which I had written a long time ago started to throw the following error:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">com.ibm.websphere.management.exception.AdminException: ADMA0043E: /tmp/app9215861615159415312.ear does not exist for installation.</span><br />
<br />
I didn't find any conclusive solution to the error on the web although some suggested there was a mismatch in the location of the temp folder. I changed the websphere variable (Environment > Websphere variables) from<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">WAS_TEMP_DIR = ${USER_INSTALL_ROOT}/temp</span><br />
<br />
to<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">WAS_TEMP_DIR = /tmp</span><br />
<br />
Restarted the server and the problem went away. I have no idea why this worked before, but I guess it's fixed now.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-35029792563455478702014-07-31T12:32:00.004-04:002014-07-31T13:42:10.061-04:00Error Messages using the WEF JAXB PluginI just resolved an issue related to my plugin for WEF which generates JAXB code for easy conversion to/from IXML and I thought I'd write it up before I forget.<br />
<br />
The error message looks something like this:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">java.lang.ClassCastException: javax.xml.bind.JAXBElement incompatible with com.dsixe.jaxbgen....</span><br />
<pre></pre>
This seems to be caused by a variance in the schema generated by the SQL Call builder where the topmost wrapper element is not annotated as root element by JAXB. The problem is solved by using code which looks like this:
<br />
<pre><span style="font-family: 'Times New Roman'; white-space: normal;">
</span></pre>
<pre><span style="font-family: Courier New, Courier, monospace;">javax.xml.bind.JAXBElement jaxbElement = (javax.xml.bind.JAXBElement)Transform.convertToObject(available, "http://com/dsixe/Roles", com.dsixe.jaxbgen.rolesTransformSchema.RowSetType.class);
com.dsixe.jaxbgen.rolesTransformSchema.RowSetType iAvailable = (com.dsixe.jaxbgen.rolesTransformSchema.RowSetType) jaxbElement.getValue(); </span>
<div style="font-family: 'Times New Roman'; white-space: normal;">
</div>
<div>
<pre><span style="font-family: Times New Roman;"><span style="white-space: normal;">We need to initially cast to <b>JAXBElement</b> and then use <b>getValue()</b> to retrieve the object. One more line of code fixes the problem.</span></span></pre>
</div>
</pre>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-22374655726449870332014-04-18T15:52:00.003-04:002014-04-18T15:52:59.265-04:00Defaulting WEF Builder Input Groups as ExpandedA little used WEF feature is the comments builder input which appears on all builder editors. The input always displays at the very top under the collapsed group header "Properties" along with the builder enable/disable input. The primary reason it is little used is because the "Properties" group is collapsed by default and therefore not immediately visible. This can be easily changed through these steps:<br />
<br />
1) Extract the <b>Base.bdef </b>file from <b>\WebContent\WEB-INF\builders\corebuilders.zip</b><br />
2) Copy the file to <b>\WebContent\WEB-INF\builders\com\bowstreet\core</b><br />
3) Edit the highlighted element from <b>true</b> to <b>false</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjd-QGPBKmdlnw8Xu0pGB2M5goqSItPzj8NBZmLL5sMYVs5GkDZCdKnThITXqAOv74ClF9TcM0pAfYIsqzCgMae1gFoRJDlCSlN0a7xO52eliN-ysgmQqx3W3R5mLu56cjwEK1fCXnhidMo/s1600/builderComment2.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjd-QGPBKmdlnw8Xu0pGB2M5goqSItPzj8NBZmLL5sMYVs5GkDZCdKnThITXqAOv74ClF9TcM0pAfYIsqzCgMae1gFoRJDlCSlN0a7xO52eliN-ysgmQqx3W3R5mLu56cjwEK1fCXnhidMo/s1600/builderComment2.PNG" height="88" width="400" /></a></div>
<span id="goog_380665217"></span><span id="goog_380665218"></span><br />
<br />
Restart your eclipse workspace and the comments builder input should now be visible by default.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7VfZAmHjLEYLujdnghQJbaLgkZeTa5YsgZmxa2grK2_IXECxZ8ESY-7NwUCDlTjuFzh49kBTmJYwHXNVY5GEPxnTNJ7MDSXE4W0lPZdefXFUS1ztbNODzYN_wXQMijZDV7mEnEc1k5ctS/s1600/builderComment.PNG" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh7VfZAmHjLEYLujdnghQJbaLgkZeTa5YsgZmxa2grK2_IXECxZ8ESY-7NwUCDlTjuFzh49kBTmJYwHXNVY5GEPxnTNJ7MDSXE4W0lPZdefXFUS1ztbNODzYN_wXQMijZDV7mEnEc1k5ctS/s1600/builderComment.PNG" height="154" width="640" /></a></div>
<br />
Remember to restart this process when you upgrade to a new version of WEF since this effectively overrides the designer's defaults.<br />
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-13869692659209872542014-03-04T20:29:00.000-05:002014-03-04T20:29:00.196-05:00REST vs SOAPFor some reason people who work in technology seem to have well defined opinions about matters and will often go to great lengths to defend those opinions. Think about the unix vi editor (I dislike), windows vs unix, windows vs apple. These topics will often lead to <a href="http://royal.pingdom.com/2009/09/22/the-holy-tech-flame-wars/" target="_blank">flame wars</a>. Today I'm going to weigh in on web service transports and hope I don't light up a wildfire.<br />
<br />
<h3>
Early Binding vs Late Binding</h3>
I'm a supporter of the SOAP protocol for most cases unless the service is to be consumed by a javascript application. I've been thinking about why it is that I have this preference and I think I know exactly why. It comes down to early (or design time) binding of an external component vs late (or runtime) binding. This concept has been around since the early days of computer science, the idea being that a sub component can declare ahead of time what kind of operation signatures it supports so that these can be confirmed by the compiler. If a piece of code which has been bound at compile time fails at run time then we immediately know there is a conflict in versions. A similar concept is found in strongly typed languages. I can think of a few examples of this:<br />
<ul>
<li>java interfaces</li>
<li>C/C++ header files</li>
<li>WSDL - web service definition language</li>
</ul>
<div>
The bad part of using SOAP is that it requires additional overhead, but in simple cases this is little more that a message envelope.</div>
<div>
<br /></div>
<div>
The other side of the argument is run time binding where we find out about the operation signatures when the code is actually executed. Now this isn't as bad as one thinks because the component owner will always provide details about the shape of the data and what is expected so the consumer that write appropriate code. The bad part of this is that the service provider can change anything at any time without notifying the consumers, resulting in an error when the consumer attempts to invoke an operation. There is a similar concept in weakly typed languages:</div>
<div>
<ul>
<li>javascript</li>
<li>visual basic</li>
<li>assembly language</li>
</ul>
<h3>
How to Choose?</h3>
</div>
<div>
The short answer is that this whole argument is moot if the software is well designed and written. All the valuable business logic should reside in java bean POJOs and then combined with a runtime container such as an <a href="http://en.wikipedia.org/wiki/Enterprise_service_bus" target="_blank">enterprise service bus (ESB)</a> or a <a href="http://en.wikipedia.org/wiki/Service_Component_Architecture" target="_blank">service component architecture (SCA)</a>. The container manages exposing the POJO business logic using any number of transport protocols and can be configured at time of deployment. If an ESB or SCA is not available, then a similar result can be attained by coding a thin delegate using JAX-RS or JAX-WS.</div>
<div>
<br /></div>
<div>
Why do I prefer early binding? I don't like doing emergency production troubleshooting and with early binding I can eliminate one more point of failure.</div>
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-11758783822481310392014-01-21T10:24:00.001-05:002014-01-21T10:24:43.467-05:00Transform IXml with JAXB<br />
This posting simply redirects to an article I've added to IBM's community.<br />
<br />
http://www-10.lotus.com/ldd/pfwiki.nsf/dx/Transform_IXml_with_JAXBUnknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-5933682308444148362013-11-02T12:10:00.001-04:002013-11-02T12:11:28.023-04:00Building Reusable Web ServicesI've worked on many projects for various organizations, both large and small, during my career in IT, and it's sad to say that reusability of web services is something that is very difficult to attain. We all learn about good design and coding practices, and agree that reusability is cornerstone to building great applications, so why do so many organizations get it wrong?<br />
<br />
<h3>
Qualities of a Good Web Service</h3>
Let's start by identifying what can be considered to be traits of a good web service<br />
<ul>
<li>encapsulation of knowledge</li>
<li>fine and coarse grained operations</li>
<li>self documenting</li>
<li>application agnostic</li>
<li>ease of use</li>
</ul>
There are other traits such as security, but these are more technical aspects that are well described through the WS-* specifications. Most concepts are easier explained through an example, and in the context of this article I'll use an automobile's construction process as a guide. If we consider a web service that provides operations to assemble a car, what would that service look like?<br />
<br />
<h4>
Fine and Coarse Grained Operations</h4>
Every good developer understands the advantage of breaking up their code into reusable parts that can be invoked from different sources. Somehow this approach never translates itself into web services. It seems that developers are so focused on reaching the next milestone that they don't take the time to ask a very basic question.<br />
<br />
Can this operation be broken up into useful parts?<br />
<br />
Agile methodology involves delivering functionality with short development cycles, and this makes it easy to forget about the larger context. Developers may be focused on writing a service operation to deliver a car's door, that they don't think how a door is composed of many pieces. What happens if in the next development cycle there's a need for an operation to deliver a door mirror or a window control switch (these are parts of a car's door)? Instead of writing a coarse grained operation that looks like this:<br />
<br />
<pre class="brush:java">CarDoor getCarDoor(){
}
</pre>
<br />
it can be broken up into several fine grained operations<br />
<br />
<pre class="brush:java">DoorMirror getMirror(){
}
DoorSwitch[] getSwitches(){
}
CarDoor getCarDoor(){
CarDoor = getMirror() + getSwitches();
}
</pre>
<br />
<br />
With little additional work, the service is now much more useful and can handle future requests that may not have been anticipated.<br />
<h3>
</h3>
<h4>
Encapsulation of Knowledge</h4>
A big reason organizations decide to develop web services is not only to expose back end systems, but also to encapsulate/hide the complexity of those systems. Software applications have a way of far outliving their original lifespan due to embedded business logic or the cost of rewriting them. A web service can be written that leaks the internal workings of the system it is exposing. <br />
<br />
This is bad. How do these leaks happen?<br />
<br />
Let's take the car example which is manufactured by the fictitious Acme car company. As is the case for most industries, Acme uses an internal vocabulary to describe parts of their cars (I'm making these up):<br />
<ul>
<li>windows are called "clear silica substrate" (or CSS)</li>
<li>door switches are called by their product codes such as D39's</li>
</ul>
Everybody working at Acme knows what that a car door has two D39's and a CSS, but these terms should not be exposed in a service operation. What's more, if the manufacturer of the D39's goes out of business (or the underlying software system is replaced) any references to these terms suddenly don't make sense. Instead of exposing this object:<br />
<br />
<pre class="brush:java">CarDoor {
CSS cssItemNumber;
D39[] switches;
}</pre>
<br />
use something that is agnostic of the underlying system but supports the business objects:<br />
<br />
<pre class="brush:java">CarDoor{
Window windowID;
Switch[] doorSwitchID;
}</pre>
<br />
This approach makes the operations easy to understand, and cuts down on the need to document.<br />
<br />
<br />
<h4>
Self Documenting</h4>
The bane of all software development is documentation. Nobody likes to do it, and when done, it gets misplaced or quickly falls out of date with the implementation. I can write about how developers need to get their act together, but the truth is that it just doesn't happen that way. They can be coaxed into writing a few lines to describe their functions but formal documentation is not realistic. An alternative way to handle this situation is to write a service interface that uses business terms instead of technical ones and exposes explicit, fine grained operations. The following is an example of a poor interface to handle seats in a car:<br />
<br />
<pre class="brush:java">handleSeat(String operation, Seat newSeat, Seat oldSeat, String seatID){
if operation = "add" then ....
if operation = "remove" then ...
if operation = "replace" then ...
}</pre>
<br />
The above operation requires documentation that describes the options for "add", "remove" and "replace". It is impossible that a consumer of the service will be able to guess the values without referring to some documentation (which is probably non existent or out of date). What's more is that because the operation requires a "Seat" object for "add", the consumer also needs to pass one for "remove", even though it is not necessary for that particular operation. A better interface looks like this:<br />
<br />
<pre class="brush:java">addSeat(Seat seat){
}
removeSeat(String seatID){
}
replaceSeat(Seat newSeat, Seat oldSeat){
}</pre>
<br />
Again, just a little more effort makes the service infinitely more usable. A business subject matter expert (SME) should be able to understand the interface.<br />
<br />
<h4>
Application Agnostic</h4>
In summary, don't create services for a specific application, instead code generic operations that can be used by any application. Acme needs a service that supplies wheels for it's latest model, the XJ2000. The immediate thought is to create operation like so:<br />
<br />
<pre class="brush:java">Wheel[] getXJ200Wheels(){
}</pre>
<br />
Six months later management decides that the web service has worked out so well, they want to leverage their investment to provide wheels for an older model, the FRT3000. The FRT3000 is a sport model which has two kinds of wheels, 18 inch alloys as well as 16 inch standard. Unfortunately the existing operation cannot be reused because it doesn't take into consideration that wheels come in different sizes and will have to be rewritten.<br />
<br />
Operations should reflect the business knowledge domain (in this case, the auto industry), not the application's.<br />
<h4>
</h4>
<h4>
Ease of Use</h4>
Here's a common scenario that unfolds when a developer begins to work on a new feature. They look at a document from the design team and are made aware of some existing service operations that should be leveraged to accelerate their work. They pull up the service with a testing tool and attempt to make use of it. If <br />
<ul>
<li>they can't find the WSDL document </li>
<li>the service is not well documented</li>
<li>they can't find the correct parameters to invoke the service operations</li>
<li>the operations are too difficult to understand or are perceived to be inadequate</li>
<li>they have an alternative way to get their work completed </li>
</ul>
they won't use it and will write their own code. The developer is on a tight deadline to deliver and will avoid something that's difficult to use.<br />
<br />
<h3>
So what's the answer?</h3>
A simple guiding principal I try to follow is this - write the service as if it was exposed to the real world instead of some internal team. Would Bob at Universal Motor Co understand my service? The great appeal of a service oriented architecture (SOA) is writing once and reusing throughout the organization, unfortunately the investment doesn't pay off it it is not done right.<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-54642211771584428462013-08-08T17:44:00.000-04:002014-03-11T14:41:32.334-04:00Logging SOAP Requests in WEFSome of my projects make extensive use of the web service call builder and I often need to look at the outgoing SOAP requests when a problem crops up. This is easy by turning on logging in the advanced section of the builder, but doing this on every instance of the builder is tedious.<br />
<br />
<br />
<span style="font-size: large;">JAX-WS SOAP Handler</span><br />
I stumbled on this <a href="http://www-10.lotus.com/ldd/pfwiki.nsf/dx/JAX-WS_Handler_Sample_using_IBM_Web_Experience_Factory" target="_blank">article</a> where Rob Flynn describes a technique to handle SOAP requests from a central point using the <span style="font-family: "Courier New",Courier,monospace;">bowstreet.serviceCall.jaxwsHandler</span> override. I used this approach to add some log4j logging statements, this way I don't have to go into each builder and tweak the input and redeploy, I can just change the <b>log4j.properties</b>. Unbelievably, a google search shows that there are no other references to this override - not even in IBM's documentation. I have to wonder how many other awesome WEF features lay undocumented (ask me about <b>pageprocessors.properties</b>).<br />
<br />
<pre class="brush:java">public class SoapHandler extends BaseJaxWsHandler {
static Logger logger = Logger.getLogger(SoapHandler.class);
/*
* Populate the user's identity into the SOAP request.
*/
public boolean handleOutboundMessage(SOAPMessageContext context) {
// bail if logging not enabled
if (!logger.isInfoEnabled())
return;</pre>
<pre class="brush:java"> logMessage(context);
return true;
}
/**
* Log the SOAP message.
* @param context
*/
private void logMessage(SOAPMessageContext context) {
// bail if logging not enabled
if (!logger.isInfoEnabled())
return;
try {
HashMap hm = (HashMap) context.get(com.ibm.websphere.webservices.Constants.REQUEST_TRANSPORT_PROPERTIES);
Set keys = hm.keySet();
logger.info(">> Start SOAP message log");
logger.info("calling Model=" + getWebappAccess().getModelName());
logger.info(this.getEndPointUrl(context));
for (Object key : keys){
logger.info("HTTP header -> " + key + "=" + hm.get(key));
}
logger.info(context.getMessage().getSOAPPart().getEnvelope());
logger.info(">> End SOAP message log\n");
} catch (SOAPException e) {
// we're just logging, not sure we care that an exception is thrown
}
}
}
</pre>
The parent class <b>BaseJaxWsHandler </b>can be found on Rob's entry mentioned above.
Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-58168789084080766532013-05-31T11:01:00.002-04:002013-05-31T11:01:08.729-04:00Product Codes for IBM SoftwareIn many past instances I've been really confused by the download process for IBM Passport. Searching for the correct download package is like trying to find a needle in a haystack.<br />
<br />
This week I stumbled on a page I had been looking for, here is a link to the product codes for WebSphere Portal 8:<br />
<br />
<span style="-webkit-text-stroke-width: 0px; background-color: white; color: #222222; display: inline !important; float: none; font-family: arial; font-size: x-small; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px;">http://www-10.lotus.com/ldd/portalwiki.nsf/xpDocViewer.xsp?lookupName=IBM WebSphere Portal 8 Product Documentation#action=openDocument&res_title=Electronic_images_wp8&content=pdcontent</span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-18201157278818030312013-04-30T22:28:00.001-04:002013-04-30T22:28:40.920-04:00Using the Localized Resource BuilderLast week I had to use the localized resource builder for localizing an application for one of my clients. After searching a while I did find an <a href="http://www-10.lotus.com/ldd/pfwiki.nsf/dx/ibm-localizing-portlets" target="_blank">article about the topic</a>, and although it didn't meet my needs, it did point me in the right direction.<br />
<br />
<span style="font-size: large;"><span style="font-size: large;">Localize <span style="font-size: large;">with</span></span> the Data Page Builder </span><br />
Here's the scenario - I have a custom HTML page that has descriptive text to be localized. This is easily accomplished by adding a second data page builder (the first is for the data on the page) that points to the variable created by the localized resource builder.<br />
<br />
Here's the HTML I used for page1:<br />
<pre><html>
<head><title>Default Test Page</title></head>
<body>
<div name="contact">
<span name="name_label"/>
<span name="name"></span>
<br>
<span name="phone_label"/>
<span name="phone"></span>
</div>
<span name="btn"/>
</body>
</html>
</pre>
<br />
and here's the default resource bundle:<br />
<pre>button_label=click me
phone_label=Phone number:
name_label=Name:
</pre>
I create a data page builder and point to the variable <b>Variables/LocaleData</b> created by the local resource builder:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkPwAC54p-xn-XuGF97Y8wvXXa6mLCKcbcBbglSPJff2i9DAEfGXcHVxEoOiwZZyPRhoiV5IxC2FE_4rLow10euEXAonB6gNtM98jDTsyyCdHuCm1t7DsCuSlaSc4HRjNY0Ul2dzZzkJrN/s1600/localized_dp.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhkPwAC54p-xn-XuGF97Y8wvXXa6mLCKcbcBbglSPJff2i9DAEfGXcHVxEoOiwZZyPRhoiV5IxC2FE_4rLow10euEXAonB6gNtM98jDTsyyCdHuCm1t7DsCuSlaSc4HRjNY0Ul2dzZzkJrN/s400/localized_dp.png" width="400" /></a></div>
<br />
When I run the model I get this output:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8fALamZ-DLEKxasgCgRL4YP9GOhW8gnQ0cZP4z7OecwchBVA91Uk-ezFbVa_-s6om2abXbPUuMZX5aXSgROZZQ0-1tNNntGTlAxmR-ARR8cTV2YOODubs4f5l5irpHbr0MxpyDKP5skex/s1600/localized_en.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="56" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg8fALamZ-DLEKxasgCgRL4YP9GOhW8gnQ0cZP4z7OecwchBVA91Uk-ezFbVa_-s6om2abXbPUuMZX5aXSgROZZQ0-1tNNntGTlAxmR-ARR8cTV2YOODubs4f5l5irpHbr0MxpyDKP5skex/s200/localized_en.png" width="200" /></a></div>
To test for French language I add a new resource bundle:<br />
<pre>button_label=clique moi
phone_label=Numero de telephone:
name_label=Nom:
</pre>
<br />
and change the language to <b>fr</b>: <br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcn07msCu6ExoFiBKfDQqEMzKOWZRDH8UFHcjQ2VoLBNST1JbqhRHhe9aOXlxMR1nDcrpU8E70ykVwCACBrNoZUSo58tOD-YX_k44RAsqToxhiYlnCnVMzIs4m3ZkjJKQAjf2rphbGDsp7/s1600/localized_rb.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="123" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgcn07msCu6ExoFiBKfDQqEMzKOWZRDH8UFHcjQ2VoLBNST1JbqhRHhe9aOXlxMR1nDcrpU8E70ykVwCACBrNoZUSo58tOD-YX_k44RAsqToxhiYlnCnVMzIs4m3ZkjJKQAjf2rphbGDsp7/s320/localized_rb.png" width="320" /></a></div>
resulting in this output:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfyqyZQLZMouRChz6erTdY9tNpyIQE0gmaReTELqTMoOvg_GGRiJg18t_GQEpIlYg1L8n6S1V8t5gv5uehyksRRGIQKG6O3V_lLFxpDVpjlfGpTbogKypx4akR-h_85SN8MpzNBxOqeSse/s1600/localized_fr.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="48" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfyqyZQLZMouRChz6erTdY9tNpyIQE0gmaReTELqTMoOvg_GGRiJg18t_GQEpIlYg1L8n6S1V8t5gv5uehyksRRGIQKG6O3V_lLFxpDVpjlfGpTbogKypx4akR-h_85SN8MpzNBxOqeSse/s200/localized_fr.png" width="200" /></a></div>
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-34953799056833257792013-04-01T20:13:00.000-04:002013-04-02T13:51:16.850-04:00Deploying WARs With a ScriptI've wanted to figure this out for a long time and yesterday I finally put together a script that updates a WAR to WebSphere. I have WebSphere Portal running locally on my development box and running the following command will use <b>wsadmin</b> to update a freshly built WAR to the server:<br />
<br />
<pre class="brush:java">sudo /opt/IBM/WPS8/WebSphere/wp_profile/bin/wsadmin.sh -conntype SOAP -user wpsadmin -password wpsadmin -c "\$AdminApp update POC_WS_war app {-operation update -contents /home/dsixe/WEF/POC_WS.war}"
</pre>
<br />
It took me a while to find out why my script wasn't working, the <a href="http://www-01.ibm.com/support/docview.wss?uid=swg1PK43076" target="_blank">$AdminApp command requires a \ prefix on non-windows platforms</a>. I initially thought that somebody else would have published a clear example of how to deploy with a script, but I just couldn't find one with repeated google searches (at least none that had the \ prefix).Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-23537341600185777092012-12-31T13:26:00.002-05:002013-01-02T11:14:20.179-05:00Documenting WEF ModelsWeb 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. <br />
<br />
<span style="font-size: large;">Using an Eclipse Plugin to Generate Graphs</span><br />
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.<br />
I recently stumbled on an open source application named <a href="http://graphviz.org/" target="_blank">Graphviz</a>, and when I saw the simplicity of using a <a href="http://en.wikipedia.org/wiki/DOT_language" target="_blank">DOT file</a> to describe a graph, I was able to quickly develop a plugin to inspect a WEF model and produce a graph of it.<br />
<br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaHJQJJXt35_rDXbsfxa4Fp3GgTMJG2XrXB8o7V97DdjM4BQdwSvzRIFJYmrMlKiSZEG2yiBupQprADpQxnAdKw98PaEolfZ5gTmlO64gTX2HDlxHijtSxaCuSSvwAczUuWCeGMzJWpwav/s1600/graph.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="186" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhaHJQJJXt35_rDXbsfxa4Fp3GgTMJG2XrXB8o7V97DdjM4BQdwSvzRIFJYmrMlKiSZEG2yiBupQprADpQxnAdKw98PaEolfZ5gTmlO64gTX2HDlxHijtSxaCuSSvwAczUuWCeGMzJWpwav/s400/graph.png" width="400" /></a></div>
<br />
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 <b>model_4</b> contains an action list builder named <b>alTest</b> that invokes the <b>doSomeOperation</b> operation exposed by the service consumer builder named <b>svcConsumer</b>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdQwF4RCbLH434MR3mjUpkfFkcs2eES7GywAri3Bebflu_XxmuvwkxEdECAAVIYkrQSEGbMvfa1XtrBDquZIA40iPL_VYQBbkeg4mM2uJHZNx1u6WCQfAXoHAE-kxK4rTk57PgsomRiPmd/s1600/Screenshot+at+2012-12-31+12:56:51.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="306" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgdQwF4RCbLH434MR3mjUpkfFkcs2eES7GywAri3Bebflu_XxmuvwkxEdECAAVIYkrQSEGbMvfa1XtrBDquZIA40iPL_VYQBbkeg4mM2uJHZNx1u6WCQfAXoHAE-kxK4rTk57PgsomRiPmd/s400/Screenshot+at+2012-12-31+12:56:51.png" width="400" /></a></div>
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.<br />
After the plugin is installed by <a href="http://www.dsixe.com/eclipse" target="_blank">following these instructions</a>, you will see the following submenu when right clicking on a model.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghjng6yb1rnL2B3Erx29t8w5F2zMI8PbL7zy41TO0mutxE0boXlCi-BcwCzw9MDfH6DlJY3h2Q_dtGwVgCIxiTMN22QWPvPZye05TZ2A7D6DVEBWlmmlo8G7IQCNu-1siExgGXD8ueJs2Y/s1600/menu.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="66" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEghjng6yb1rnL2B3Erx29t8w5F2zMI8PbL7zy41TO0mutxE0boXlCi-BcwCzw9MDfH6DlJY3h2Q_dtGwVgCIxiTMN22QWPvPZye05TZ2A7D6DVEBWlmmlo8G7IQCNu-1siExgGXD8ueJs2Y/s400/menu.png" width="400" /></a></div>
<br />
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.<br />
<br />
If the tool doesn't work for you, then please leave me a message on this blog (or email me).<br />
<br />
<br />
<b>References:</b> Download plugin from http://www.dsixe.com/eclipse Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-1373414015686195986.post-55436062053975248252012-12-04T20:30:00.000-05:002012-12-05T08:48:03.679-05:00Using com.bowstreet.builders.webapp.api.MethodI've been writing some more custom builders recently and had a hard time figuring out how to generate a method with arguments.<br />
<br />
Below is an example:<br />
<br />
<pre class="brush:java"> Method method = new Method(builderCall, genContext);
method.setName("myMethod");
IXml args = null;
try {
args = XmlUtil.parseXml("<top><Argument><Name>msgValue</Name><Type>String</Type></Argument></top>");
} catch (IOException e) {
e.printStackTrace();
}
method.setArguments(args);
StringBuffer sb = new StringBuffer("{ \n");
sb.append(" webAppAccess.getVariables().getVariable(\"myVar\").setValue(msgValue); \n");
sb.append("}");
method.setBody(sb.toString());
method.invokeBuilder();
</pre>
<br />
and here's the code added to the model on regen:<br />
<br />
<pre class="brush:java">/**
* Generated Method [myMethod]
*/
public void myMethod(WebAppAccess webAppAccess, String msgValue)
{
webAppAccess.getVariables().getVariable("myVar").setValue(msgValue);
}
</pre>
I figured out the magic XML for <i>method.setArguments()</i> by looking at the model XML for a standard method builder.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-83331762731795710912012-11-28T21:30:00.000-05:002012-11-28T21:37:08.039-05:00WEF Profiling ExplainedProfiling 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.<br />
<br />
<span style="font-size: large;">Comparing Profiles to Java Code</span><br />
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):<br />
<pre class="brush:java">if (request.getHeader("User-Agent") == "android"){
button.visible = true;
}
</pre>
<br />
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.<br />
<br />
Think of a profile set as a collection of profiles and the selection of a given profile is the result of a conditional statement. <b>That conditional statement is controlled by a selection handler</b>. Let's look at the code above again from this perspective<br />
<pre class="brush:java">if (profileset.selectionHandler.result == "android"){
button.enable = true;
}</pre>
<br />
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.<br />
<br />
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<br />
<pre class="brush:java">if (profileset.selectionHandler.profile.name == "android"){
button.enable = true;
invokeSomeOperation();
}</pre>
<br />
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<br />
<pre class="brush:java">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
}</pre>
<br />
That all seems very obvious if we were using java, but how is it implemented in WEF using profiling?<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNp-vVW3H8ncY2sKVK1FUOF9oq975lvS5rY4KCrHUYIrh92hZt8jLwlX4AXDfMgtjLYELdolNvsZuVxCyaNn62mhQ_aEQhK1rYXzVxg3BFVrJIpZ0VrUJANmj80qzHmJSM60pbD25DUeJo/s1600/blog_profiling2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNp-vVW3H8ncY2sKVK1FUOF9oq975lvS5rY4KCrHUYIrh92hZt8jLwlX4AXDfMgtjLYELdolNvsZuVxCyaNn62mhQ_aEQhK1rYXzVxg3BFVrJIpZ0VrUJANmj80qzHmJSM60pbD25DUeJo/s1600/blog_profiling2.png" /></a></div>
<br />
Here is the detailed profile entry for the button<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkKn-p4q364VoS5kuO25WLJzwwMQm_lyyhdsoPjr50nyPK5S6jfLOCpEdFFlm4vfqnpRj57SuoCvZptk90lPNE7A_U0y-SxS_aeHiht1VSA8QAZFJSenUlE0aCKUQq2yAf-jTTm-8Xx6jr/s1600/blog_profiling1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="425" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkKn-p4q364VoS5kuO25WLJzwwMQm_lyyhdsoPjr50nyPK5S6jfLOCpEdFFlm4vfqnpRj57SuoCvZptk90lPNE7A_U0y-SxS_aeHiht1VSA8QAZFJSenUlE0aCKUQq2yAf-jTTm-8Xx6jr/s640/blog_profiling1.png" width="640" /></a></div>
<br />
Similarly, the action list is profiled<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-KQGh-lPTEAxhch-dyQ8EACVLGprbHB3GmxSYFnpTQS8x0sA52iZI27a86Ogm-O8FzDsoG_vX_Mb6QE2N0YvPQpDdKBOuq-U9FVgjkFCs47HnBBsUSu4lOvzZqmpnXeK9pL3gHqXzQZVM/s1600/blog_profiling4.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-KQGh-lPTEAxhch-dyQ8EACVLGprbHB3GmxSYFnpTQS8x0sA52iZI27a86Ogm-O8FzDsoG_vX_Mb6QE2N0YvPQpDdKBOuq-U9FVgjkFCs47HnBBsUSu4lOvzZqmpnXeK9pL3gHqXzQZVM/s1600/blog_profiling4.png" /></a></div>
<br />
<br />
and below is the detailed profile entry <br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj28vG6ZA7eZVJ-eHNeLuM6c-lOvghxkNON-z5z4SBnCkjZInMvTSGBIgTDppagfb1Ptq1uumGUOoaSkaqO5GdzcWxANA9jshbjwmoFYsRWBqho026YnC2vvf5GxV_1NWgZxUcl_Iaul0r6/s1600/blog_profiling3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj28vG6ZA7eZVJ-eHNeLuM6c-lOvghxkNON-z5z4SBnCkjZInMvTSGBIgTDppagfb1Ptq1uumGUOoaSkaqO5GdzcWxANA9jshbjwmoFYsRWBqho026YnC2vvf5GxV_1NWgZxUcl_Iaul0r6/s1600/blog_profiling3.png" /></a></div>
<br />
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.<br />
<br />
<br />
<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-90793639898127446292012-11-07T22:03:00.000-05:002012-11-08T09:31:26.900-05:00WEF and Custom HTMLWorking 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.<br />
<br />
<span style="font-size: large;">Don't Fight with WEF</span><br />
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:<br />
<br />
1 - Turn off the theme<br />
2 - Don't let the data page builder create the UI<br />
3 - Learn how to exploit page automation<br />
<br />
<span style="font-size: large;">Turn off the Theme</span><br />
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 <i>override.properties</i>.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL6F4t3rL4sz6m2fk_IUTJaOqGyLSbwG1dHGdIEipaOsuk519QeJoSW-S3MHpkz_JQ4IJxG6QLOZZFJS4_Z4o-7fWh5p9mYUMOIpRxWTAv_oDMzvyghqPR5pkcKJooqAForJJ_NK8k5W7m/s1600/override_theme.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjL6F4t3rL4sz6m2fk_IUTJaOqGyLSbwG1dHGdIEipaOsuk519QeJoSW-S3MHpkz_JQ4IJxG6QLOZZFJS4_Z4o-7fWh5p9mYUMOIpRxWTAv_oDMzvyghqPR5pkcKJooqAForJJ_NK8k5W7m/s400/override_theme.png" width="400" /></a></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
The theme is great when using WEF's default user interface, but it just gets in the way of custom HTML.<br />
<br />
<span style="font-size: large;">Dumb Down the Data Page Builder</span><br />
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.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBGpB8e8h838nyZEadDU7BfF2ql9Eqs09F5MfoLbH9bcOXFN7rX3VuPMJ-K02fW5loJR3QFKuCz65mf7ExrdygXl52P28jQ7zvRK-CeyuoYeTzN_m7TQivokyEO4It53OlokqKPKKFRcpe/s1600/dp_low.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="249" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiBGpB8e8h838nyZEadDU7BfF2ql9Eqs09F5MfoLbH9bcOXFN7rX3VuPMJ-K02fW5loJR3QFKuCz65mf7ExrdygXl52P28jQ7zvRK-CeyuoYeTzN_m7TQivokyEO4It53OlokqKPKKFRcpe/s640/dp_low.png" width="640" /></a></div>
In many cases we'll also want to set the page type to <i>view only</i> if we're only displaying data, but this depends on the use case. <br />
<br />
<span style="font-size: large;">Exploit Page Automation</span><br />
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 <i>name</i> attributes to the HTML elements. Whenever page automation finds a value for the <i>name</i> attribute that matches the data specified in the data page variable, it inserts a data value. Take for example the following XML data<br />
<pre><contacts>
<contact>
<name>n1</name>
<phone>p1</phone>
</contact>
<contact>
<name>n2</name>
<phone>p2</phone>
</contact>
</contacts>
</pre>
<br />
We can ask page automation to take this custom HTML<br />
<pre><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></pre>
to produce a user interface, and this is what we see in the browser when we launch the application<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtzJra5O6S0bSfCBqDHEOdMmfaK7yxVgN0x-Zq1cEltvxQIiCXHZyIGVil62XDLTTwKfwOMN9Qr-GGjZ9pVosrP850zfNaK3p5vArxi1RHLAiz575vkl92JfdbQnvmZp5ZHrQTV-KH3Bg1/s1600/custom_ui.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" height="96" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtzJra5O6S0bSfCBqDHEOdMmfaK7yxVgN0x-Zq1cEltvxQIiCXHZyIGVil62XDLTTwKfwOMN9Qr-GGjZ9pVosrP850zfNaK3p5vArxi1RHLAiz575vkl92JfdbQnvmZp5ZHrQTV-KH3Bg1/s640/custom_ui.png" width="640" /></a></div>
<br />
<br />
<br />
<br />
<br />
<br />
This is how page automation sees the HTML <i>name</i> attributes that we added<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizBFGrtlCtaodzUXlcN2TmLYjV9GvpFDOqCyhaeP1VfxVs6XS0Jh0nyvd0tS9QjIaB8iqlqvqBZ8R0xyYJ9BdltJJFQKLtfOvjEWwqDr5U59tAsbC1UZetiTS_BiqGPHpWox7KfOrDgZU-/s1600/custom_html.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="440" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizBFGrtlCtaodzUXlcN2TmLYjV9GvpFDOqCyhaeP1VfxVs6XS0Jh0nyvd0tS9QjIaB8iqlqvqBZ8R0xyYJ9BdltJJFQKLtfOvjEWwqDr5U59tAsbC1UZetiTS_BiqGPHpWox7KfOrDgZU-/s640/custom_html.png" width="640" /></a></div>
<br />
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 <i>Header</i> to the name attribute in the table header rows.<br />
<br />
Also note that the table row identified with the name attribute <i>contact</i> refers to the repeating XML data element <i>contact</i>. Page automation will create a new HTML row for each <i>contact</i> element in our data.<br />
<br />
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.<br />
<br />
More information about manually marking up HTML for page automation can be <a href="http://www-10.lotus.com/ldd/pfwiki.nsf/dx/Writing_Page_Automation_friendly_HTML_and_styles" target="_blank">found here</a>.<br />
<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-6034779733237206752012-07-29T10:38:00.000-04:002013-09-30T18:40:27.571-04:00What's in a Portal URL?I've been working with WebSphere Portal for many years and I always wondered about the format of the URL, but never took the time to track it down. Last week I stumbled on this <a href="http://www.google.com/url?sa=t&rct=j&q=websphere%20url%20mapping%20and%20friendly%20urls&source=web&cd=2&ved=0CFcQFjAB&url=https%3A%2F%2Fwww-10.lotus.com%2Fldd%2Fportalwiki.nsf%2Fxsp%2F.ibmmodres%2Fdomino%2FOpenAttachment%2Fldd%2Fportalwiki.nsf%2F6080F957F38F73F48525765600718D98%2Fattach%2FURL%2520Mapping%2520%26%2520Friendly%2520URLs%2520Leue%252020090303.pdf&ei=G4IWUJ3TE8XE0QHEsoGoCw&usg=AFQjCNFNjS0GP6I84KLwCMt0GpQss31wIg&cad=rja">interesting document</a> that laid it all out.<br />
<br />
The short if it is that the typical URL<br />
<pre class="brush:xml">http://localhost:10039/wps/portal/!ut/p/b0/04_Sj9CPykssy0xPLMnMz0vMAfGjzOKd3R09TMx9DAwsTC0MDTwdPULNzYJdjAxczfXD9aPwKnE0hiowwAEcDfT9fPLT01NT_EtL9Auys9McHRUVAdjo3OY!
</pre>
is an XML representation of the portal page compressed and encoded with a proprietary algorithm. It turns out there are several alternate URL schemes for WPS, but this one is the most common variation that everyone is familiar with.<br />
<br />
No need for me to go into details - the document explains it quite well.<br />
<br />
<br />
<b>EDIT 09/30/2013:</b> Here's a URL that describes REST services which will encode/decode portal URLs:<br />
<br />
http://www-10.lotus.com/ldd/portalwiki.nsf/dx/IBM_WebSphere_Portal_Remote_State_Service_and_Fragment_ServiceUnknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-85513324850140612192012-07-24T19:12:00.000-04:002012-07-24T21:30:58.205-04:00A Lotus Notes Calendar WidgetMost of my blog entries reflect some challenging task that I helped my client complete, this latest one was particularly interesting because there was little documentation to guide us. In fact I'm going to blog about something that I wouldn't recommend to anyone but sometimes there are no easy ways out.<br />
<br />
<span style="font-size: large;">The Requirement for a Calendar</span><br />
My client wanted to expose their user's lotus notes calendar entries into a JSR 286 portlet but we couldn't find any easy out of the box solutions for this. Since I don't know anything (at all) about lotus domino I turned to a resident expert for advice on how to get my hands on the calendar data. We appeared to have two options:<br />
<br />
<ul>
<li>Develop a custom lotus form that would require replicating every user's mailbox</li>
<li>Re-purpose an existing form to suit our needs</li>
</ul>
<br />
After much discussion we decided to pursue the second option since we had little time to roll out the portlet and we didn't want to alter the mailbox database of thousands of users.<br />
<br />
<span style="font-size: large;">Tapping into ReadViewEntries</span><br />
The domino mailbox supports a URL command named ReadViewEntries that can be used to retrieve calendar entries as JSON data. The URL looks something like this<br />
<pre>http://yourbox.com/mailServer/mailbox.nsf/Calendar?ReadViewEntries&outputformat=JSON
</pre>
This request returns calendar entries for a given date range, more details can be found on this <a href="http://www.ibm.com/developerworks/lotus/library/ls-Domino_URL_cheat_sheet/">cheat sheet</a>. Unfortunately we quickly realized that ReadViewEntries is not really designed for retrieving calendar entries formatted the way we needed. I'm not sure about the real purpose of this form, but I had to reverse engineer the results by creating a test sampling of all the different types of calendar entries (anniversary/meeting/reminder/repeated entries....) and then looking at the result set. Below is the javascript that I created to parse out the data feed<br />
<pre class="brush:javascript">function populateCalendarData(viewentries) {
var jqueryData = [];
for ( var x = 0; x < viewentries.viewentry.length; x++) {
var entry = {};
entry.type = "meeting";
var cday = null;
if (viewentries.viewentry[x].entrydata[0].datetime != undefined){
cday = viewentries.viewentry[x].entrydata[0].datetime[0];
}
else {
// repeating item shows up with datetimelist
cday = viewentries.viewentry[x].entrydata[0].datetimelist.datetime[0][0];
}
var sd = cday;
// all day events don't have start dates
if (viewentries.viewentry[x].entrydata[2].datetime != undefined){
sd = viewentries.viewentry[x].entrydata[2].datetime[0];
}
else {
entry.type = "all-day";
}
var ed = sd;
if (viewentries.viewentry[x].entrydata[4].datetime != undefined){
ed = viewentries.viewentry[x].entrydata[4].datetime[0];
}
else {
// appointments don't have end dates
entry.type = "appointment";
}
var startDate = getDate(sd);
var endDate = getDate(ed);
var moderator = "";
var subject = "";
var location = "";
if (viewentries.viewentry[x].entrydata[5].textlist == undefined){
// not a meeting type entry. This could be reminder or appointment
subject = viewentries.viewentry[x].entrydata[5].text[0];
}
else{
// check if a location was provided
if (viewentries.viewentry[x].entrydata[5].textlist.text.length > 2){
subject = viewentries.viewentry[x].entrydata[5].textlist.text[0][0];
location = viewentries.viewentry[x].entrydata[5].textlist.text[1][0];
moderator = viewentries.viewentry[x].entrydata[5].textlist.text[2][0];
}
else {
subject = viewentries.viewentry[x].entrydata[5].textlist.text[0][0];
moderator = viewentries.viewentry[x].entrydata[5].textlist.text[1][0];
}
}
// create jquery calendar entry
entry.date = startDate.getTime().toString();
entry.title = subject;
entry.description = "no description available at this time";
entry.url = "no url";
entry.end = endDate.getTime().toString();
entry.location = location;
jqueryData.push(entry);
}
return jqueryData;
}
</pre>
The result is neatly populated into an array of javascript objects with the following structure
<br />
<pre class="brush:javascript">{"type":"meeting","date":"1343138400000","title":"Project A meeting","description":"no description available at this time","url":"no url","end":"1343142000000","location":"Huddle room 5"}</pre>
This data construct was then fed into a <a href="http://www.vissit.com/projects/eventCalendar/">jquery widget</a> to produce this interface<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs2wFwLkPtowIeOobKGnkF3gwr1UcgpxVfo8UnqFNRvgCy7vh-1H9KsvfE5eSQn863JoA6l_R9j4f4yzt5RK8ionhwO2Vu_M2XgmpGsDy5Wrb0fxao-gz7JDaTumlLCruInItoKeamrAf_/s1600/calendar_blog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjs2wFwLkPtowIeOobKGnkF3gwr1UcgpxVfo8UnqFNRvgCy7vh-1H9KsvfE5eSQn863JoA6l_R9j4f4yzt5RK8ionhwO2Vu_M2XgmpGsDy5Wrb0fxao-gz7JDaTumlLCruInItoKeamrAf_/s320/calendar_blog.png" width="247" /></a></div>
<br />
The result looks pretty good - thanks to Rick Taylor for helping me out with the lotus domino stuff.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-71468426339371916912012-05-02T21:32:00.000-04:002012-05-03T09:33:12.070-04:00Integrating Sametime into PortalI recently worked with a client that wished to integrate Sametime instant messaging into WebSphere Portal. After evaluating the options available, I found that although IBM provides a Sametime portlet, it has one big drawback in that it takes so much space on the screen. User interfaces are already limited by screen size and resolution, it makes sense to use this space well.<br />
<br />
<span style="font-size: large;">Using a Tooltip Dialog</span><br />
Most native instant messaging clients hide their user interfaces until they're needed - either to send a message or to handle an incoming message. The remainder of the time it just provides a status indicator on a tray at the bottom of the screen. This same concept can be applied to a web interface using a dojo tooltip dialog.
Suppose that we've identified a location in the HTML where we want to show the Sametime status:
<br />
<pre><div id="myClient2" onclick="ShowSTClientInFloatingPane()">Show tooltip dialog</div>
</pre>
Now we can programmatically create a sametime.WebClient dojo widget using javascript:
<br />
<pre>var dsixe = {};
var tooltipDialog = null;
dojo.ready(function() {
// Instantiate the sametime client widget
dsixe.ST_Client = new sametime.WebClient({
style : "width:200px;height:300px;border:1px solid black;"
});
dojo.require("dijit.TooltipDialog");
tooltipDialog = new dijit.TooltipDialog({
content : dsixe.ST_Client,
onBlur : function() {
dijit.popup.close(tooltipDialog);
}
});
});
</pre>
and add a script to handle the onClick event that will display the Sametime buddy list:
<br />
<pre>function ShowSTClientInFloatingPane() {
var node = dojo.byId("myClient2");
var coords = dojo.coords("myClient2");
var x = coords.x + 15;
var y = coords.y + (coords.h / 2) + 5;
dijit.popup.open({
popup : tooltipDialog,
x : x,
y : y
});
dsixe.ST_Client.main.initLayout();
}
</pre>
When we put this all together in a proper HTML page, we get something that looks like this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOqLJmASNsxw0g0tjZJ9rpbFzWYitf58pjuJn5nYCY-JkAQaZvFsHbj4AKgUTj289xnN3vrDpOfiGJBk-m4yr6Zp047yDRhq0LUE9XnsZ2haBor9S0UkNP80w08SU-jzma9l_tbbeHMVE/s1600/st-tooltipDialog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOqLJmASNsxw0g0tjZJ9rpbFzWYitf58pjuJn5nYCY-JkAQaZvFsHbj4AKgUTj289xnN3vrDpOfiGJBk-m4yr6Zp047yDRhq0LUE9XnsZ2haBor9S0UkNP80w08SU-jzma9l_tbbeHMVE/s320/st-tooltipDialog.png" width="226" /></a></div>
<span style="font-size: large;">Conclusion</span><br />
Using this technique I was able to provide an instant messaging experience that is familiar to the end user while consuming very little screen space.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-77186241088227112922012-04-09T20:13:00.000-04:002012-04-09T20:13:00.117-04:00Managing CVS Branches with WEFToday 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.<br />
<br />
<span style="font-size: large;">Eclipse and CVS Branches</span><br />
The solution to the problem is documented in this <a href="http://www.eclipse.org/eclipse/platform-cvs/r2.0/cvs-faq.html#browsing_1">eclipse CVS FAQ list</a>, but it's worth mentioning in a WEF blog because we typically don't check in the <i>.project</i> 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.<br />
<br />
Checking in the <i>.project</i> file causes problems when later attempting to check out using the <i>new WEF project wizard</i>. Following the instructions in the FAQ above provides an easy work around.<br />
<br />
Hope someone finds some use in this tidbit of information.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-48342071206666440032012-03-14T22:38:00.000-04:002012-03-18T21:37:38.575-04:00SOA Development Using JavascriptIn the past several months I've been putting some thought into the trends that I see emerging in software development frameworks. Working in the IT industry means that things are always moving and survival requires keeping a close watch on trends. <br />
It looks like application development is quickly moving away from servlets, and towards javascript. After prototyping a pure javascript web application using web services I realized that servlets are an antiquated way of designing applications. This blog entry describes an approach I used that worked well for me.<br />
<br />
<span style="font-size: large;">Overview</span><br />
Here's a diagram from my <a href="http://www.slideshare.net/viragoboy/soa-development-using-javascript" target="_blank">slide deck</a> that describes what I aimed to accomplish<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX9n8_zEJUeJ2QzuS6VfScO2a_CHu9W7f-A3LPuuy8wUYAQlLszoxWeuJEDOaxXujSimKALVvQQd2utkRKjZM3o7bOJ4Oert9L1HnycwQFjzlVMif75eQEP7utBVMDoCFbADrWU-mqDTYp/s1600/soa-js-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="371" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiX9n8_zEJUeJ2QzuS6VfScO2a_CHu9W7f-A3LPuuy8wUYAQlLszoxWeuJEDOaxXujSimKALVvQQd2utkRKjZM3o7bOJ4Oert9L1HnycwQFjzlVMif75eQEP7utBVMDoCFbADrWU-mqDTYp/s640/soa-js-1.png" width="640" /></a></div>
<br />
<br />
Although I used SOAP web services, the design works equally well with REST services. I did find a few frameworks like <a href="http://directwebremoting.org/dwr/index.html" target="_blank">DWR</a>, but these didn't meet my needs since I work in a corporate environment that prefers to not use open source code. Besides, I already had a rich set of in house web services available that I wanted to leverage.<br />
<br />
<span style="font-size: large;">Creating Javascript Objects from XML</span><br />
Since most of code I typically work with is in java, I've been spoiled with all kinds of frameworks and annotations that render things like web services really easy to deal with. Working with javascript means that I need to find similar tools to facilitate unpacking XML into javascript objects much like JAX-WS does for java. I decided to roll my own using dojo class framework and the <a href="http://fast-code.sourceforge.net/" target="_blank">FastCode</a> eclipse code generation plugin.<br />
<br />
The idea is to follow what JAXB does for java in a javascript environment, namely that given some XML I want to have something parse it and hand me a collection of javascript objects - and vice versa from objects to XML. I accomplished this using the FastCode plugin.<br />
<br />
<span style="font-size: large;">Generating Javascript Code from Java Beans</span><br />
I started by coding a dojo class that contained the functions necessary to parse XML to JS and back to XML, then wrapped a FastCode template around it:<br />
<pre class="brush:xml"><template type="Dojo declare class from java bean">
<description>Create a dojo class from a java bean.</description>
<variation></variation>
<class-pattern></class-pattern>
<getter-setter>getter-setter</getter-setter>
<allowed-file-extensions>js</allowed-file-extensions>
<number-required-classes>1</number-required-classes>
<allow-multiple-variation>false</allow-multiple-variation>
<template-body>
<![CDATA[
dojo.provide("${full_class_name}");
dojo.require("com.dsixe._BeanBase");
\n
dojo.declare("${full_class_name}", com.dsixe._BeanBase, {
\n
#foreach ($field in ${fields})
_${field.name} : null, /* ${field.type} */
#end
\n
/*
Copy/paste to save some typing:
new ${full_class_name}({
#foreach ($field in ${fields})
\t ${field.name}: null,
#end
});
*/
constructor : function(args) {
#foreach ($field in ${fields})
this.setValue(args, "${field.name}");
#end
},
\n
/* Useful for creating instance after service call */
createFromXML : function(xmlData, elementName) {
var list = [];
\n
if (elementName == undefined){
elementName = "${class_name}"; this is probably the wrong element name
}
\n
var _list = dojo.query(elementName, xmlData);
for (var x=0; x < _list.length; x++){
var inst = new ${full_class_name}();
var item = _list[x];
#foreach ($field in ${fields})
#if (${field.type.endsWith("[]")})
\n
// Child element contains XML
var o_${field.name} = new QUALIFY_YOUR_PACKAGE_NAME_HERE.${field.type}(); fix this line
var i_${field.name} = o_${field.name}.createFromXML(xmlData, "${field.name}");
inst.${field.setter}(i_${field.name});
\n
#else
inst.${field.setter}(this._getValueXML(item, "${field.name}"));
#end
#end
list.push(inst);
}
return list;
},
\n
/* Useful for updates/inserts on large objects */
createWire : function(elementName){
var wire = new dojox.wire.ml.XmlElement(elementName);
#foreach ($field in ${fields})
#if (${field.type.endsWith("[]")})
\n
// Child element contains XML
var ${field.name}Wire = [];
for (var x=0; x < this._${field.name}.length; x++){
var item = this._${field.name}[x];
${field.name}Wire.push(item.createWire("${field.name}"));
}
wire.setPropertyValue("${field.name}", ${field.name}Wire);
\n
#else
wire.setPropertyValue("${field.name}", this._${field.name});
#end
#end
return wire;
},
\n
#foreach ($field in ${fields})
${field.getter} : function (){
return this._${field.name};
},
${field.setter} : function (arg){
this._${field.name} = arg;
},
\n
#end
});
]]>
</template-body>
</template></pre>
<br />
The java class that I'm using for this blog:<br />
<pre class="brush:java">package com.dsixe.blog;
public class ContactBean {
private String name;
private String phone;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
}
</pre>
<br />
I invoke the plugin using these steps - select template:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibhau_u8RXJkTUF397S-HneQGtUbWGnXdSQEOAcgdJSoqUJixWT1586AGRQnBtKJyiVLg1OV2VVgZVXFTJx-bPz7W0HfDjDpBEjyMLyL-4xsIiJRg5EO_HQDpUtjZjs-7vqNFxmJkmhB9I/s1600/fc-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="177" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEibhau_u8RXJkTUF397S-HneQGtUbWGnXdSQEOAcgdJSoqUJixWT1586AGRQnBtKJyiVLg1OV2VVgZVXFTJx-bPz7W0HfDjDpBEjyMLyL-4xsIiJRg5EO_HQDpUtjZjs-7vqNFxmJkmhB9I/s400/fc-1.png" width="400" /> </a> </div>
<div class="separator" style="clear: both; text-align: center;">
</div>
Choose class:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwarEVIqAvemc0D73SyF-hBHAxx9KoUb0nPepIDMgdLlYQRsh7o5BqKOa01QDnQKzmxMeZ4GhFn_EIkh41_DZKmu-xzf8ERs9qe-B0hT7Kv1PApmtu2BCSqB3OP2WiYX3lT2lW-ffQsOsL/s1600/fc-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="165" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjwarEVIqAvemc0D73SyF-hBHAxx9KoUb0nPepIDMgdLlYQRsh7o5BqKOa01QDnQKzmxMeZ4GhFn_EIkh41_DZKmu-xzf8ERs9qe-B0hT7Kv1PApmtu2BCSqB3OP2WiYX3lT2lW-ffQsOsL/s400/fc-2.png" width="400" /></a></div>
<br />
Pick java fields:<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX89nYJikXbs1LFcVOQQvVa60P1l5swvMnkUfHFLqG8krsfhDIaj8aXnNzxYtmDxPbymXGmgdPKvm_gRy5Pjaqf0YQCg2A5cT7Jq3zDsJbtCDn-sBeRI2cw9FzPuAjbrX-mwXu4nJqgEB8/s1600/fc-3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="203" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgX89nYJikXbs1LFcVOQQvVa60P1l5swvMnkUfHFLqG8krsfhDIaj8aXnNzxYtmDxPbymXGmgdPKvm_gRy5Pjaqf0YQCg2A5cT7Jq3zDsJbtCDn-sBeRI2cw9FzPuAjbrX-mwXu4nJqgEB8/s400/fc-3.png" width="400" /></a></div>
<br />
And voila - a nice dojo class that is very nearly complete:<br />
<pre class="brush:javascript">dojo.provide("com.dsixe.blog.ContactBean");
dojo.require("com.dsixe._BeanBase");
dojo.declare("com.dsixe.blog.ContactBean", com.dsixe._BeanBase, {
_name : null, /* String */
_phone : null, /* String */
/*
Copy/paste to save some typing:
new com.dsixe.blog.ContactBean({
name: null,
phone: null,
});
*/
constructor : function(args) {
this.setValue(args, "name");
this.setValue(args, "phone");
},
/* Useful for creating instance after service call */
createFromXML : function(xmlData, elementName) {
var list = [];
if (elementName == undefined) {
elementName = "ContactBean"; // !! this is probably the wrong element name
}
var _list = dojo.query(elementName, xmlData);
for ( var x = 0; x < _list.length; x++) {
var inst = new com.dsixe.blog.ContactBean();
var item = _list[x];
inst.setName(this._getValueXML(item, "name"));
inst.setPhone(this._getValueXML(item, "phone"));
list.push(inst);
}
return list;
},
/* Useful for updates/inserts on large objects */
createWire : function(elementName) {
var wire = new dojox.wire.ml.XmlElement(elementName);
wire.setPropertyValue("name", this._name);
wire.setPropertyValue("phone", this._phone);
return wire;
},
getName : function() {
return this._name;
},
setName : function(arg) {
this._name = arg;
},
getPhone : function() {
return this._phone;
},
setPhone : function(arg) {
this._phone = arg;
}
});
</pre>
<br />
<span style="font-size: large;">Picking Apart the Generated Dojo Class</span><br />
Let's take a closer look at the code which is almost ready to use, but requires a few tweaks.<br />
The template adds a comment providing an easy way to copy/paste code for a constructor. This seems trivial when there are only two fields, but it can get tiresome when the class contains a dozen or more.<br />
<pre class="brush:javascript"> /*
Copy/paste to save some typing:
new com.dsixe.blog.ContactBean({
name: null,
phone: null,
});
*/
</pre>
The constructor delegates parsing of the fields to the superclass <i>_BeanBase</i>. This allows invoking with a subset of parameters if needed.<br />
<pre class="brush:javascript"> constructor : function(args) {
this.setValue(args, "name");
this.setValue(args, "phone");
},
</pre>
Create from XML is pretty obvious, it provides a way to convert XML to a collection of javascript objects. This code needs to be reviewed to ensure that the element names match the values returned by the service.<br />
<pre class="brush:javascript"> createFromXML : function(xmlData, elementName) {
var list = [];
if (elementName == undefined) {
elementName = "ContactBean"; // !! this is probably the wrong element name
}
var _list = dojo.query(elementName, xmlData);
for ( var x = 0; x < _list.length; x++) {
var inst = new com.dsixe.blog.ContactBean();
var item = _list[x];
inst.setName(this._getValueXML(item, "name"));
inst.setPhone(this._getValueXML(item, "phone"));
list.push(inst);
}
return list;
},</pre>
Create wire will convert a javascript class instance into a <i>dojox.wire.ml.XmlElement</i> object which is needed by the <i>ibm_soap</i> dojo library. If I was using a REST service then I guess I'd have to change this code or add another function to the template.<br />
<pre class="brush:javascript"> createWire : function(elementName) {
var wire = new dojox.wire.ml.XmlElement(elementName);
wire.setPropertyValue("name", this._name);
wire.setPropertyValue("phone", this._phone);
return wire;
},
</pre>
The remainder of the code is standard gettter/setters for the fields. I tried my best to make the code as formal as possible without any kind of javascript magic for a few reasons:<br />
<ul>
<li>javascript can get real messy real fast</li>
<li>this code is intended for use by java developers who aren't javascript experts </li>
</ul>
Could it be <i>better</i>? I'm pretty sure it could, but for its intended use, performance and size aren't really an issue. The best part is that the generated code has no strings attached and can be edited at will.<br />
<br />
<span style="font-size: large;">Using the Generated Code</span><br />
Now that I don't have to get my hands dirty with the XML, I can write some nice clean code against dojo classes. In a nutshell, here's how I invoked a web service operation using ibm_soap:<br />
<pre class="brush:javascript"> wsdlParser = new ibm_soap.util.WsdlParser();
wsdlParser.parse("contacts.wsdl");
// Create reference to service and set the URL
myService = new ibm_soap.rpc.SoapService(wsdlParser.smdObj);
myService.serviceUrl = "/axis2/services/ContactService.ContactInfoPort/";
var params = new dojox.wire.ml.XmlElement("getAllContacts");
var deferred = myService.getAllContacts(params);
deferred.addCallback(function(xmlData) {
var cb = new com.dsixe.blog.ContactBean();
var contacts = cb.createFromXML(xmlData, "contact");
// do something useful with the data
}</pre>
In practice, the code is much shorter if I <a href="http://dsixe-wpf.blogspot.com/2011/05/converting-wsdl-to-javascript-with-web.html">parse the wsdl into javascript</a> upfront. In addition, the service/url is really only defined once in the application. This leaves me with creating the <i>dojox.wire.ml.XmlElement</i> and invoking the service operation.<br />
<br />
Nice! <br />
<br />
Attachments:<br />
<a href="http://dl.dropbox.com/u/455147/DsixE/DsixEBlog_WS.war">DsixEBlog_WS.war</a><br />
<br />
References:<br />
Fast Code eclipse plugin http://fast-code.sourceforge.net/Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-84532653251367896382012-03-12T19:35:00.000-04:002012-03-18T21:39:55.552-04:00Using the Fast Code Eclipse PluginI recently discovered an eclipse plugin that I've been needing since I started coding. On several occasions I started down the path of writing my own but quickly got lost in the world of eclipse and ran out of time. Out of the box, the <a href="http://fast-code.sourceforge.net/">fast code plugin</a> generates many types of code/xml, but the part that I really like is its support for custom templates.<br />
<br />
<span style="font-size: large;">How to Write Your Own Template</span><br />
Here are the steps that I used to create my own template which generates a spring RowMapper for a JdbcDaoSupport class.<br />
<br />
Start with exporting templates using menu <i>Fast Code | Templates | Export Templates</i>:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD6CWKbvK2LD6lJcCQveWPyr0Y0YhSaSi9YYdvnrlFf6U0E7kwXnxsjBBpulJs8GaMDRcRkm8sq8nCLRSrJ9tIfh7mcYKG6yLaX0WdiigGDguSEsItoZ2jC8m77qGQfldSQZ8kLPeGyGz0/s1600/fca-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="120" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhD6CWKbvK2LD6lJcCQveWPyr0Y0YhSaSi9YYdvnrlFf6U0E7kwXnxsjBBpulJs8GaMDRcRkm8sq8nCLRSrJ9tIfh7mcYKG6yLaX0WdiigGDguSEsItoZ2jC8m77qGQfldSQZ8kLPeGyGz0/s640/fca-1.png" width="640" /></a></div>
<br />
Choosing <i>templates-config.xml</i> (or all) creates a new project in my workspace:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLtX5z-zOTGl9GiPBXL4tEfJM-6cY2BhdqA2aIFamVg_A_YF5qJaxHRYAtpPmRqHHfvNikE8wwYhJ2LIxJm-kGSDufgD6WI2OCjKTsoYpqiWFhSTp1S_zZusSVWW01FW9RHYEnc_rbNfEK/s1600/fca-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgLtX5z-zOTGl9GiPBXL4tEfJM-6cY2BhdqA2aIFamVg_A_YF5qJaxHRYAtpPmRqHHfvNikE8wwYhJ2LIxJm-kGSDufgD6WI2OCjKTsoYpqiWFhSTp1S_zZusSVWW01FW9RHYEnc_rbNfEK/s1600/fca-2.png" /></a></div>
Next, I altered the exported <i>templates-config.xml</i> file and added my own custom template:<br />
<pre class="brush:xml"> <template type="Create Spring Detail Mapper">
<description></description>
<variation></variation>
<class-pattern></class-pattern>
<getter-setter>getter-setter</getter-setter>
<allowed-file-extensions>java</allowed-file-extensions>
<number-required-classes>1</number-required-classes>
<allow-multiple-variation>false</allow-multiple-variation>
<template-body>
<![CDATA[
private class ${class_name}Mapper implements RowMapper <${class_name}>{
public ${class_name} mapRow(ResultSet rs, int line) throws SQLException {
${class_name} inst = new ${class_name}();
#foreach ($field in ${fields})
#if (${field.type.endsWith("String")})
inst.${field.setter}(rs.getString(""));
#else
inst.${field.setter}(rs.getInt("")); // type not String, assume int
#end
#end
return inst;
}
}
]]>
</template-body>
</template></pre>
To test the result I import the template back into fast code using menu <i>Fast Code | Templates | Import Templates,</i> then open up a java class that needs the mapper and execute the template using menu <i>Fast Code | Templates | Create New Snippet.</i> Pick my template, class, fields and presto:<br />
<pre class="brush:java"> private class ContactBeanMapper implements RowMapper<ContactBean> {
public ContactBean mapRow(ResultSet rs, int line) throws SQLException {
ContactBean inst = new ContactBean();
inst.setName(rs.getString(""));
inst.setPhone(rs.getString(""));
return inst;
}
}
</pre>
This may not seem like a big deal because I only have two fields in class <i>ContactBean</i>. It really pays off when I have a dozen or more fields.<br />
I did find a few quirks with the plugin - it looks like the custom templates need to be reloaded every time eclipse is restarted, and the import/export mechanism seems to make a service call to localhost so make sure that the eclipse network proxy preference is configured correctly.<br />
<br />
In short - I can create a new template whenever I want to generate some code or configuration file based on the definition of a java class. In another blog post, I use it to generate a javascript clone of a java bean.Unknownnoreply@blogger.com5tag:blogger.com,1999:blog-1373414015686195986.post-54040148018781369802012-03-08T19:25:00.000-05:002012-03-09T13:30:08.546-05:00Debugging Dojo with ChromeAs a web developer I spend many hours working with javascript libraries like dojo. Unfortunately, in many cases the javascript in these libraries is compressed making it very difficult to trace in a debug session.<br />
<br />
<span style="font-size: large;">Chrome is Your New Best Friend</span><br />
Google's chrome developer tools has many bells and whistles, some of which I've only discovered in the last week. One feature that I think is worthy of mention is the <i>pretty print</i> button, tucked away at the bottom of the page in the status bar.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSAsRkYJTAOeJZs5c0F_971_7fXxjD4InQl0V9yn_Zk-qYTsAFtCZZe_8VC270aqELAXXVbJSRvrPRLxbcesiV6dHOOR0xVQPDQ2eX9aE20QrRUdC5i5lb8xi9GEX-o2XJxKznceqb2SqB/s1600/chrome_dojo2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="107" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSAsRkYJTAOeJZs5c0F_971_7fXxjD4InQl0V9yn_Zk-qYTsAFtCZZe_8VC270aqELAXXVbJSRvrPRLxbcesiV6dHOOR0xVQPDQ2eX9aE20QrRUdC5i5lb8xi9GEX-o2XJxKznceqb2SqB/s320/chrome_dojo2.png" width="320" /></a></div>
<br />
Click on the button and dojo.js goes from this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQjlzfQ2s31Q5y-aSnLon_emQIu-CSRIFiBav8e7EHGQxflyug2CZx43JLXcalRz65Qi7R_Flb4G6fiiKzBl_RSbtNF_1eA5JKNymiDUGdUTzCCerwZEKDTzAOnDczUXn2N_Tfqf6a3_8v/s1600/chrome_dojo1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="132" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQjlzfQ2s31Q5y-aSnLon_emQIu-CSRIFiBav8e7EHGQxflyug2CZx43JLXcalRz65Qi7R_Flb4G6fiiKzBl_RSbtNF_1eA5JKNymiDUGdUTzCCerwZEKDTzAOnDczUXn2N_Tfqf6a3_8v/s640/chrome_dojo1.png" width="640" /></a></div>
<br />
to this:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgczc3hYemSJjffO9OiYD-kc1MRUooixB-wkE0m3IGwH3Z0FK1G0q5Cpc0sSFDZmdAhQktenfCO70dlSKQr8RVgnt1qXi8jGRAlyIG5xtwt7cHpZL1dVTtWfD_xnr0Myhx20JFqnq4zkcH6/s1600/chrome_dojo3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="224" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgczc3hYemSJjffO9OiYD-kc1MRUooixB-wkE0m3IGwH3Z0FK1G0q5Cpc0sSFDZmdAhQktenfCO70dlSKQr8RVgnt1qXi8jGRAlyIG5xtwt7cHpZL1dVTtWfD_xnr0Myhx20JFqnq4zkcH6/s640/chrome_dojo3.png" width="640" /></a></div>
<br />
Some of the variables are still compressed, but now the code becomes legible and breakpoints can be added with ease.<br />
<br />
Yes, it also works with JQuery.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-1373414015686195986.post-89378754274649448172012-01-17T18:02:00.000-05:002012-01-17T18:02:33.805-05:00XML to JSON Converter BuilderToday I had the opportunity to use the <em>xml to json converter</em> builder for a project I'm working on and found that the documentation was a little lacking. Searching google for help netted me next to nothing so I figured it was time for a blog entry.<br />
<br />
<span style="font-size: large;">Why is This Not Working?</span><br />
The key to getting this feature working is to understand that the builder on its own doesn't really do anything useful. It just provides a method that must be invoked somewhere else, some code that produces the JSON notation. The <em>callback</em> builder input field is text which is prepended to the output of this method. For example if I have these values<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVbre-G76ZSSr47wlsHul0G9TmZTuhWJkyxSrfYhWORSqSMkWiu3A_twIp6pfGznTPxQ6MgQ1vy5rKpqlf0ZEH8r44qB71xKE3GJ9TSMtwz7w45-8NGhkA9xGkhDCrV8PR4TLq4OnwVg4B/s1600/json_convert1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="225" kba="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhVbre-G76ZSSr47wlsHul0G9TmZTuhWJkyxSrfYhWORSqSMkWiu3A_twIp6pfGznTPxQ6MgQ1vy5rKpqlf0ZEH8r44qB71xKE3GJ9TSMtwz7w45-8NGhkA9xGkhDCrV8PR4TLq4OnwVg4B/s400/json_convert1.png" width="400" /></a></div>
<br />
with the following html in a page builder:<br />
<pre><html>
<head><title>Default Test Page</title></head>
<body>
<script type="text/javascript">
function dumpJson(json){
console.log(json);
}
</script>
<span name="script1"/>
</body>
</html>
</pre>
all that's missing now (and this is important) is a call to the generated method, in my case using a <em>client javascript</em> builder:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoVswwlaVKGZ6IY6jBuEdQ78SnD0e6LXu87D0cZnPNgdkg9gtbYxMjKxvjXEJAyybOyKIF-rA6L3FuTX28O29BqQnaB7CyhxRslC0wFFsT0Jcx81ZaGAmjGC_vdvAeaHYYQGtRLFI7f0HV/s1600/json_convert2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="247" kba="true" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgoVswwlaVKGZ6IY6jBuEdQ78SnD0e6LXu87D0cZnPNgdkg9gtbYxMjKxvjXEJAyybOyKIF-rA6L3FuTX28O29BqQnaB7CyhxRslC0wFFsT0Jcx81ZaGAmjGC_vdvAeaHYYQGtRLFI7f0HV/s400/json_convert2.png" width="400" /></a></div>
The output html looks like this:<br />
<pre><html>
<head>
<title>Default Test Page</title>
</head>
<body>
<script type="text/javascript">
function dumpJson(json){
console.log(json);
}
</script>
<script name="script1" type="text/javascript">dumpJson({"evaluationDetail":{....})</script>
</body>
</html>
</pre>
Hopefully someone will stumble on this blog before they pull their hair out trying to figure out how to use this builder.Unknownnoreply@blogger.com0