Arch2Arch Tab BEA.com

James Bayer's Blog

James Bayer James Bayer's Homepage
James Bayer is a Senior Systems Engineer covering enterprise customers in and around the Chicago area. James started out as a Java consultant and architect where he experienced the technology shift toward SOA. Now he helps customers solve business problems by applying BEA technology solutions.

Using X.509 Certificates for Identity Propagation with Web Service Security

Posted by jbayer on April 29, 2008 at 11:11 AM | Permalink | Comments (1)

One of my customers is considering a web services interface for exchanging information with their clients.  Security is a very important consideration in their design, so they are considering using best practices for authentication, integrity and confidentiality.  In this post I'll explain some detail around my experiences setting up a simple prototype using Web Service Security hands-on.

Introduction

Currently they plan on using HTTPS for the transport, but SSL may be terminated by SSL hardware accelerators before it reaches the application server, so transport level security is not enough in this instance, we'll also need some message level security.  The newer WS-Security 1.1 specification is available in the latest releases of WebLogic Server, but WS-Security 1.0 has maximum interoperability with other web services stacks.  So it you are not in control of web service stack's that your clients are using, it's best to use the older standard.  SAML, Username, and X.509 Token Profiles can be used for authentication.  In this instance since certificates are already required for SSL, it will be straightforward to also use them to authenticate identity.  This is a similar use-case to a previous dev2dev article posted on securing web services in WLS 9.2, but in this case we are going to use the X.509 certificates for the identity propagation instead of Username Token.  The formal name for this is the OASIS WS-Security X.509 Token Profile.  The identity in the certificate will map to an LDAP user.

Note that WebLogic Server ships with examples that perform User-name Token authentication located at <BEA_HOME>\wlserver_10.0\samples\server\examples\src\examples\webservices\wss1.1

I was not able to find a X.509 Token Profile example, so I wrote it up here and hopefully you can benefit from my experiences by getting this running and understand the steps in under an hour.

Client Diagram

ws-secClient

Server-side Diagram

ws-secServer

Basic Steps

  • Client Certificate Setup (10 minutes)
  • Server Configuration (20 minutes)
  • Server-side JWS Programming (15 minutes)
  • Client-side Web Service Programming (15 minutes)
  • Client Certificate Setup

    First, set up a java key store and certificate identifying a user that we can map to an LDAP user.  In this example I use only the CN attribute.  This CN attribute will map to a user in WebLogic's embedded LDAP, but you can use another enterprise LDAP (Active Directory, eDirectory, OpenLDAP) just as easily.  We will use self-signed certificates in this simple example, but in production I would highly encourage you to use certificates issued by a Certificate Authority.

    keytool -genkey -v -keyalg RSA -sigalg SHA1withRSA -keystore D:/bea102/wlserver_10.0/samples/domains/wl_server/keystores/Identity.jks -alias testalias -keysize 1024 -keypass weblogic -storepass weblogic -dname CN=secuser'

    Now we need to export the pubic key to a .pem file so we can import it on the server side.

    keytool -export -alias testalias -file testalias.pem -sigalg SHA1withRSA -keystore D:/bea102/wlserver_10.0/samples/domains/wl_server/keystores/Identity.jks -storepass weblogic -rfc

     

    Server Configuration

    Some administrative configuration is required in the console to load the certificate into the trusted certificate chain and to tell the web services security stack to do identity propagation when X.509 tokens are found.

    WebLogic ships with a DemoTrust keystore that can be used for testing purposes.  Again, for production domains, you would want to not use the DemoTrust keystore, but it works well for prototyping the configuration steps.  Here is how I imported the certificate into the keystore.

    keytool -v -import -trustcacerts -alias testalias -file testalias.pem -keystore D:/bea102/wlserver_10.0/server/lib/DemoTrust.jks -keypass DemoTrustKeyStorePassPhrase -noprompt

    Web Service Security Configuration for the domain is also required.  Follow the console configuration instructions here.  Then follow the instructions here to configure the identity propagation with a Token Handler.  Note that one of the steps will specify that we are using the CN attribute to map to the user name in LDAP.

    If you have not already done so, create a user.

    users [2]

    Server-side JWS Programming

    In order to require authentication on a web service, you need only specify a policy via an annotation in the JWS file.  WLS ships with a policy inside the weblogic.jar file known as Auth.xml (as well as Sign.xml and Encrypt.xml which are explained in the earlier article I mentioned).  Here is a simple JWS file that shows how to attach that policy.  This will require all users calling the time operation to be authenticated.  Use the context object to retrieve the identity principal used to validate that we are indeed using an authenticated user.

    package com.bea.sample.webservice; 
    
    import java.util.Date; 
    
    import javax.jws.WebMethod;
    import javax.jws.WebService; 
    
    import weblogic.jws.Context;
    import weblogic.jws.Policies;
    import weblogic.jws.Policy;
    import weblogic.wsee.jws.JwsContext; 
    
    @WebService
    public class Auth { 
    
        @Context
          private JwsContext ctx;
          @WebMethod
          @Policies({
            @Policy(uri = "policy:Auth.xml", direction=Policy.Direction.inbound )})
        public String time() 
        {
            return "User " + ctx.getCallerPrincipal() + " " + (new Date().toString());
        }
    }

    Client-side JAX-RPC Programming

    The normal way to generate JAX-RPC clients provided by BEA is to use clientgen.  In this case we need to add a special parameter generatePolicyMethods="true" to indicate that policy is being used and generate extra methods on the stubs that are created.  Here is the snippet from the build.xml file for ant that generates the client code.

    <target name="run-clientgen" depends="clean">
       <taskdef name="clientgen" classname="weblogic.wsee.tools.anttasks.ClientGenTask" classpathref="compile.classpath" />
    
       <mkdir dir="${build.dir}"/>
    
       <clientgen
          wsdl="${wsdl.dir}/${project.name}.wsdl"
          packageName="${client.package.prefix}.security.http.x509certbst.standalone.stub"
          destDir="${build.dir}"
          generatePolicyMethods="true"
       />
    
       <javac
          srcdir="${build.dir}"
          destdir="${build.dir}"
          source="1.5"
       >
          <include name="test/**/*.java"/>
          <classpath>
             <path refid="compile.classpath"/>
          </classpath>
       </javac>
    
       <delete file="${lib.dir}/${client.jar.name}Client.jar"/>
       <mkdir dir="${lib.dir}"/>
    
       <jar destfile="${lib.dir}/${client.jar.name}Client.jar">
          <fileset dir="${build.dir}">
             <include name="**/*.*"/>
             <exclude name="**/*.java"/>
          </fileset>
       </jar>
    </target>

    The JAX-RPC client code specifies the policy that indicates which certificate to use for x509 identity propagation.  It is different from just using the policy attached to the WSDL on the server-side because we need to give some guidance to the web service stack on the client as to how to embed the identity.  Notice how we specify the CN=secuser in the TokenIssuer element.  I have not included the policy element to sign the body to lower the overhead of the web service invocation.  It is a trade-off of additional security versus performance.

    <wsp:Policy wsu:Id="WSSEX509CertificateTokenPolicy.xml"
      xmlns:wsp="http://schemas.xmlsoap.org/ws/2004/09/policy"
      xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
      xmlns:wssp="http://www.bea.com/wls90/security/policy"
    >
       <wssp:Identity>
          <wssp:SupportedTokens>
             <wssp:SecurityToken TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3"/>
          </wssp:SupportedTokens>
       </wssp:Identity>
       <wssp:Integrity xmlns:wls="http://www.bea.com/wls90/security/policy/wsee#part">
          <wssp:SignatureAlgorithm URI="http://www.w3.org/2000/09/xmldsig#rsa-sha1"/>
          <wssp:CanonicalizationAlgorithm URI="http://www.w3.org/2001/10/xml-exc-c14n#"/>
          <wssp:Target>
             <wssp:DigestAlgorithm URI="http://www.w3.org/2000/09/xmldsig#sha1"/>
             <wssp:MessageParts Dialect="http://www.bea.com/wls90/security/policy/wsee#part"
             >wls:SecurityHeader(wsu:Timestamp)</wssp:MessageParts>
          </wssp:Target>
          <wssp:SupportedTokens>
             <wssp:SecurityToken IncludeInMessage="true" TokenType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-x509-token-profile-1.0#X509v3">
                <wssp:TokenIssuer>CN=secuser</wssp:TokenIssuer>
             </wssp:SecurityToken>
          </wssp:SupportedTokens>
       </wssp:Integrity>
       <wssp:MessageAge Age="300"/>
    </wsp:Policy>

    Inside the Client.java file that makes use of the generated JAX-RPC classes from clientgen, simply specify the policy file in the constructor for the port.

    AuthService_Impl service = new AuthService_Impl();
    
    Auth port = service.getAuthSoapPort(
        Thread.currentThread().getContextClassLoader().getResourceAsStream(_properties.getProperty("helloworld.http.x509certbst.WSPolicyFile")),
        true,
        false
    );

    There is also some special code required to set up reading from the keystore.  I've commented out some code that illustrates how we would inject a Username token if we were using that approach instead.

    List<CredentialProvider> credProviders = new ArrayList<CredentialProvider>();
    
    CredentialProvider cp = new ClientBSTCredentialProvider(
        _properties.getProperty("helloworld.http.x509certbst.IdentityKeyStore"),
        _properties.getProperty("helloworld.http.x509certbst.IdentityKeyStorePassword"),
        _properties.getProperty("helloworld.http.x509certbst.IdentityKeyAlias"),
        _properties.getProperty("helloworld.http.x509certbst.IdentityKeyPassword")
    );
    
    credProviders.add(cp);        
    
    /*
    CredentialProvider cp = new ClientUNTCredentialProvider(
            _properties.getProperty("helloworld.http.passwordunt.username").getBytes(),
            _properties.getProperty("helloworld.http.passwordunt.password").getBytes()
        );
    credProviders.add(cp);
    */
    authStub._setProperty(
        WSSecurityContext.CREDENTIAL_PROVIDER_LIST,
        credProviders
    );
    
    authStub._setProperty(
        WSSecurityContext.TRUST_MANAGER,
        new TrustManager()
        {
            public boolean certificateCallback(X509Certificate[] chain, int validateErr)
            {
                return true;
            }
        }
    );

    When you run the client, you should see output like this if everything is working correctly.

    [Client.Client()]: Attempting to load .properties file from JAXRPCClients.properties
    [Client.Client(String)]: JAXRPCClients.properties was loaded successfully.
    [Client.time()]: response.getStringParameter()=User secuser Mon Apr 28 17:26:26 CDT 2008
    [Client.example()]: Elapsed milliseconds: 1141

    If you encounter problems, then you can enable verbose debugging on both the client and server side by specifying the JVM argument -Dweblogic.wsee.verbose=* which will output to the standard out all the details over the web service requests and responses.

    I have attached my Eclipse-based Workshop Studio projects from the WebLogic Portal 10.2 download to the site if you would like to try it out yourself.  You may have to adjust some of the project settings to adjust the location of webservicesclient.jar and add the weblogic.jar to the ant classpath to generate the client.  Hopefully my experiences with this simple prototype will benefit you.



    Playing with Workshop and the Dojo Ajax Framework

    Posted by jbayer on March 23, 2008 at 3:04 PM | Permalink | Comments (2)

    I have been Inspired by the recent article by Gary Horen called "Ajax programming with BEA Workshop" and the numerous blogs from Skip Sauls that have touched on JSON and Firefox plug-ins like Firebug and YSlow.  I decided to try using what I perceive to be the most popular javascript framework, Dojo, to solve a relatively simple requirement from one of my customers to populate the options of a select drop-down based on the selection of another drop-down without refreshing the page.  For example, the options in the City drop-down will be populated based on the user's selection of an option in the State drop-down.  Here's a look at the finished example.

    state

    The State drop-down is the only one available, the City and the Submit button are disabled.

    stateSelect

    This is not a normal html select, it is a Dijit FilteringSelect that has enhanced capabilities, such as type-ahead, and the user selects a state.

    selectCity [2]

    Once a state is selected, the list of cities is populated and is now enabled.

    submit

    Once a user selects a city, the submit button is now enabled.  This has all happened without a screen refresh and provides a better user experience.

    The Tools

    1. BEA Workshop 10.2
    2. Aptana Studio - Set of javascript plug-ins for Eclipse that among other things help with Javascript debugging
    3. Firefox 2
    4. Firebug - Great Firefox plug-in for debugging client side issues
    5. Dojo 1.0.2

    Getting Started

    The Workshop 10.2 projects used for this example (minus Dojo) are available here.  Import the projects, extract Dojo 1.0.2 to the WebContent folder of the DynamicSelectWEB project and deploy the DynamicSelectEAR project to a server to get it up and running.  This includes a city / state web service in the CitiesStatesWEB project that returns the city and state information.  The ServiceControl in the DyanmicSelectWEB project is assuming that web service is deployed to localhost and port 7001, so make sure to adjust that if your server settings are different.

    I could have tried using IceFaces, an Ajax-enabled JSF framework, but I think it's important to get the fundamentals down before adding additional layers of complexity.  So my first recommendation is to start simple with plain HTML and JSON files.  Once you get the basics going, then add in the dynamic pieces (JSPs, etc).

    The Dojo documentation has some excellent basic examples in the "Book of Dojo 1.0".  After reading the of the form basics, particularly the FilteringSelect example, I figured out the basic framework.  Each FilteringSelect object has an attribute called a "store" that is responsible for holding data for the options.  You can populate the store programmaticly in javascript, by invoking a URL that returns JSON, etc.  The example uses a static states.txt file that shows what the JSON looks like and I use that as a basis for my purposes.  It is easy to take the JSON response and create a new dojo.data.ItemFileReadStore and set the "store" value of the FilteringSelect to that new value without any complex parsing.  I use the same json.jsp for populating both the cities and the states; and the action code in the pageflow just populates some lists for that jsp that can be reused to populate any select-based Dojo element.

    Here's a look at how easy Dojo makes it to wire up events to javascript functions.  This onLoad function gets called when the page loads via some javascript on the body tag.  The "states", "cities", and "myButton" references are the id's of the DOM objects.  "onChange" and "onClick" are the names of the events to register.   "onchange_states", "onchange_cities", and "button_click" are the names of javascript functions to call respectively when those events occur.

    function onLoad() {
      var states = dijit.byId("states");
      dojo.connect(states, "onChange", "onchange_states");
      
      var cities = dijit.byId("cities");
      dojo.connect(cities, "onChange", "onchange_cities");
      
      var button = dijit.byId("myButton");
      dojo.connect(button, "onClick", "button_click");
    }

    Since Workshop has very nice Apache Beehive pageflow tooling, I just prototyped using that framework.  Below is a look at my site-map.  You can see how I started with a test.html file.  Once I got that working, then I migrated the code over to the index.jsp and added in the dynamic elements.  Each drop-down onChange calls a different pageflow action, that return dynamic JSON.  You can see that in the getCities action, I'm passing the entire form.  This way I can pull out the value of the selected state and only return the cities for that state.

    pageflow [2]

    Gotchas

    Take note of this css code that the FilteringSelect requires to display properly.  I had to use this approach instead of the @import example used on the Dojo site due to an issue in one of the Eclipse plug-ins that caused a hang consistently.

    <link rel="stylesheet" type="text/css" href="dojo-release-1.0.2/dijit/themes/tundra/tundra.css" />

    I decided to submit the form with a post when the state is selected since that is most likely how you would do more complex forms.  Here's what that function looks like.

    function populate_cities()
    {
      var ajaxReq = {
              form: dojo.byId("myForm"),
              url: "getCities.do",
              handleAs:"json-comment-filtered",
              load: function(response){
                      dijit.byId('cities').store = new dojo.data.ItemFileReadStore({data:response});  
              },
              error: function(data){
                      alert("Holy Bomb Box, Batman!  An error occurred: " + data);
              },
              timeout: 2000
              };
      //dojo.xhrGet(ajaxReq);  //Servlet get argement with doGet
      dojo.xhrPost(ajaxReq);  //Servlet get argement with doPost
    }

    I found that Dojo does this with a multi-part submission by default, so an extra annotation is necessary on the Pageflow to allow multi-part.

    @Jpf.Controller(simpleActions = { @Jpf.SimpleAction(name = "begin", path = "index.jsp") }, multipartHandler=Jpf.MultipartHandler.memory )
    public class Controller extends PageFlowController {

    Conclusion

    The Firebug plug-in is invaluable for debugging purposes.  I found the Javascript debugging and the ability to look at the XHR request/response values to be particularly helpful.  My example still has debugging turned on and to use this on a high-traffic site I would recommend turning that off and using some javascript compression.  Check out Skip's recent post for more detail on that.  If you have had a better experience using a different javascript framework like prototype, DWR, IceFaces, etc please leave a comment.  Overall Ajax programming is made easier with these frameworks and tools, but they are not quite as mature as what server-side java developers are used to, but they are getting there fast.

    I had some ambitious plans to create a Workshop facet to add Dojo support to Dynamic Web projects, however that's going to be for another time.  Check out Konstantin's presentation if you have curiosity about how to do that.



    Scala Development with Eclipse and WebLogic

    Posted by jbayer on February 6, 2008 at 6:57 PM | Permalink | Comments (3)

    At the end of my previous post about the hype/buzz for alternative programming languages I promised an entry on my experimenting with Scala in WebLogic.  I have only spent a few hours of weekend time playing around, so I can't say much yet, but I'll document some of my first impressions and experiences in this post.  This is not meant to be a post on learning Scala,  For that I recommend an excellent podcast from Bill Venners that goes into great detail about Scala and why you might use it.  I highly recommend it, it is well-worth the listen.  If you prefer reading, then start with The busy Java developer's guide to Scala: Functional programming for the object oriented.  This is a post that documents my experience of using Scala with tooling and an application server familiar to java developers, namely Eclipse and WebLogic Server.

    Prequisites

    1. Download Eclipse 3.3 / WTP 2.0.1.  I used wtp-all-in-one-sdk-R-2.0.1.  Workshop 10.0/10.1 are still based on Eclipse 3.2, so they won't work with the Scala Plugin for Eclipse, which requires 3.3.
    2. In order to easily deploy code to WLS, use Eclipse Update to install WebLogic Server Tools, I used version 1.1.2 from update site https://dev2devclub.bea.com/updates/wls-tools/europa/
    3. Use Eclipse Update to install the Scala Plugin for Eclipse.  I used version 2.6.5 from update site http://www.scala-lang.org/downloads/scala-plugin/

    Obligatory HelloWorld

    After restarting Eclipse because of the new plug-ins, I didn't have to set any paths to configure the Scala Plugin as the set of 5 scala plugins installed include the Scala SDK.  Simply follow the instructions at the bottom of the Scala Plugin for Eclipse page to create your first HelloWorld application to make sure that everything is wired up correctly.  I did not encounter a single snag with HelloWorld at all and my console printed "HelloWorld" in no time flat.

    ScalaHelloWorld

    Interoperability with Java

    The scalac compiler takes .scala files and builds .class files that have a dependency on the scala-library.jar.  Go check out the bin directory in the Resource perspective and see for yourself.  Therefore, the only thing you need to invoke and run them from java is to have the .class files and the scala-library.jar on your classpath.  The converse is also true; Scala objects can just as easily invoke java objects by including them on the scala classpath.

    Now this is where the developer experience is not quite ideal with respect to the packaging scala artifacts to be used easily in Dynamic Web Projects for iterative development with WebLogic Server.  First of all, I could not find a non-custom way of exporting the Scala .class files into a jar file.  In order to package up my Scala Project into a jar with the IDE I had to:

    Right click on the project -> Export... -> General -> Archive File -> and select appropriate values as shown in multiple places.

    ScalaJarExport

    Is this really that big of a deal?  Well, it depends on how you use your IDE to develop.  In the normal process of doing Java web development in the IDE, I find it convenient to have a project with Java code, say a Utility project, which is automatically included in your Dynamic Web Project's classpath and packaged up in the EAR as a jar when I do an export or a deployment.  It doesn't appear that such a nice arrangement is possible using the default tooling.  Of course you can always create a custom ant builder yourself and attach this to your project's build activity, but there is some work involved.  Certainly this will be addressed as the Scala Plugin for Eclipse matures.

    Trying out some various alternatives, I was able to modify the .project xml file for the Scala project and add a Java nature and a java builder so that both .java source and .scala source were compiled into the same bin directory.  This seemed a little fragile and the build order had to be just right in order for both sets of .class files to be in the bin directory after the build.  I suspect that when the build order was reversed that the bin directory was being cleaned by one of the builders.  Here is the .project file if you feel like taking this approach.

    <?xml version="1.0" encoding="UTF-8"?>
    <projectDescription>
        <name>ScalaExamples</name>
        <comment></comment>
        <projects>
        </projects>
        <buildSpec>
            <buildCommand>
                <name>org.eclipse.jdt.core.javabuilder</name>
                <arguments>
                </arguments>
            </buildCommand>
            <buildCommand>
                <name>ch.epfl.lamp.sdt.core.scalabuilder</name>
                <arguments>
                </arguments>
            </buildCommand>
        </buildSpec>
        <natures>
            <nature>ch.epfl.lamp.sdt.core.scalanature</nature>
            <nature>org.eclipse.jdt.core.javanature</nature>
        </natures>
    </projectDescription>
    

     

    Mix Scala with a Dynamic Web Application

    After deciding not to spend more time on the packaging issues I moved on to another basic concept, simply calling a Scala object from a JSP.  In this case there is a suitable example addressbook.scala on the Scala site that spits out an addressbook in Xhtml.  This example also showcases one of the Scala languages handy features of native XML support.  Check out the source.  In order to invoke this quickly from a JSP, I moved it to a package called examples and created a new function named toXhtml to the AddressBook class to return the Xhtml string since the example was meant to be called from a main method and needed the function to be callable from the JSP.

    def toXhtml(): String = page.toString
    

    Here is the index.jsp

    <%@page import="examples.addressbook"%>
    <%= addressbook.toXhtml() %>

    The steps are:

    1. Package the addressbook classes in a jar and place into WEB-INF/lib
    2. Copy the scala-library.jar into WEB-INF/lib (get this from the Scala SDK or from your plugin, mine is here: D:\eclipse3.3\eclipse\plugins\ch.epfl.lamp.sdt.compiler_2.6.9.RC412860\lib)
    3. Create the JSP
    4. Deploy to a server and invoke the jsp

    Here is the end result:

    scalaAddressbook

    Summary

    There is nothing really WebLogic Server specific to this, I could have just as easily deployed this to Tomcat., or WebLogic Event Server.  The point is that Scala actually is fairly easy to integrate into both tools and runtimes that most java developers will already be familiar with.  If you have thoughts on Scala, better integration with java IDE's, etc, drop a comment.



    Paparazzi for Programming Languages

    Posted by jbayer on February 3, 2008 at 10:33 PM | Permalink | Comments (4)

    Have you noticed that there is a growing buzz about alternative programming languages in the blogosphere and online technical journals?  Is this simply just US-Weekly for technology selling the latest Brangelina gossip that will be forgotten next week or is there really a coming revolution to get out in front of or even catch up with?

    The Old Standbys

    PHP and Perl have been popular Internet languages for some time and there is a history of using these languages in conjunction with the WebLogic Server (See WLS information about PHP, ColdFusion, and CGI).   Even JavaScript  / ECMAScript is getting integrated into the JVM in Java 6.

    The New Popular Kids

    Lately a newer set of languages have been getting all the attention in both the Java world and the .NET world.  Of course you've heard about Ruby and Ruby on Rails unless you've been under a rock.  Java has responded with it's own scripting language, Groovy and rails like framework called Grails.  Presumably Groovy and Grails would be more applicable to enterprise developers because of Java roots and higher likelihood of being accessible to Java developers to learn quickly.  Secondly, because Groovy is interoperable with existing java code, it can run on your corporate application server standard, which is of the utmost importance for enterprise adoption.  There is also JRuby; so you can mix Java and Ruby and not have to give up WLS container provided services and all of those plentiful java API's you have lying around from existing applications, frameworks, and packaged applications.  Not to be left-out, functional programming fans have also have a reason to get excited with Scala and F#, which combine elements of OO languages with functional principles.  Even ERLang is getting some hype. 

    Why all the buzz and what to do about it?

    The rationale to use these alternate languages seems to vary, but the most substantive reasons seem to center around brevity, clarity (see the Fibonacci examples), and that they are better for taking advantage of concurrent programming on the growing number of multi-core architectures.  So as an enterprise Java developer and WebLogic Server user how are you to know which of these technologies is the most relevant?  In my humble opinion, it's too early to declare definitive winners.  I don't think that brevity alone can be responsible for a seismic shift.  I am personally more swayed by the multi-core / concurrent programming arguments, but I don't feel the urgency immediately.  I think these are technologies to monitor and dip your toe in, but not necessarily to dive all the way in unless you have an edge case that is in the sweet spot in one of the languages.

    I am definitely bullish on the value of the application server and the rock-solid foundation provided by WebLogic Server.  I feel that the new languages that will have the best synergy with existing Java assets will have the highest likelihood of success.  I've spent a limited amount of time playing with Scala this weekend and deployed an example in WLS.  Look for my write-up on this in an upcoming entry if you want to hear about my experiences.  If you have an opinion on future programming language adoption in the enterprise, please leave a comment.



    Workshop, JPA, and DataSources

    Posted by jbayer on January 25, 2008 at 11:35 PM | Permalink | Comments (2)

    One of my customers is evaluating JPA as a persistence framework for a new project and using Workshop 10.1 for development and WebLogic Server 10.0 MP1 for a target runtime.  They had some trouble figuring out how to configure JPA to use WebLogic managed DataSources instead of using a direct OpenJPA managed connection.  In this entry, I'll illustrate how to specify JNDI DataSources in persistence.xml.

    Default behavior is direct connection

    In Workshop 10.1, when you right click on a table in DbXplorer and select "Generate JPA Mapping...", and target a Web project with JPA facets, Workshop will add the connection information from DbXplorer to the persistence.xml file that uses the direction connection method.  Here's an example of the output for one class called Supplier.  Notice that the direct connection is used and the password is embedded in the file.  This might be ok for development, but this might raise some eyebrows if left unchecked for production.

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
        version="1.0">
        <persistence-unit name="pu">
            <class>com.test.supplier.jpa.Supplier</class>
            <properties>
                <property name="openjpa.TransactionMode" value="local"/>
                <property name="openjpa.ConnectionDriverName" value="oracle.jdbc.driver.OracleDriver"/>
                <property name="openjpa.ConnectionURL" value="jdbc:oracle:thin:@localhost:1521:XE"/>
                <property name="openjpa.ConnectionUserName" value="weblogic"/>
                <property name="openjpa.ConnectionPassword" value="weblogic"/>
                <property name="openjpa.jdbc.Schema" value="WEBLOGIC"/>
            </properties>
        </persistence-unit>
    </persistence>

    Best practice - use container managed DataSources

    Instead of managing all of database connections separately in each application, it is a best practice to use container managed DataSources that are shared among applications.  Here are two data-sources I have configured in the WLS console.

    datasources

    Using DataSources also has the added benefit of not requiring developers to have access to the database attributes, specifically the password.  It turns out that the Workshop 10.1 JPA plug-in does not directly support specifying the JNDI name of the WebLogic DataSource in the GUI.  Looking at the persistence XSD file or trying a code-completion in the persistence.xml file will show you that the persistent-unit element has a child element named jta-data-source that can be used for specifying the JNDI name.  In fact, there is a second element as well, non-jta-data-source, which is also required if you want transactions to work properly with XA compliant DataSources.  The OpenJPA documentation user-guide does an excellent job explaining this.

    Watch your step

    This is where I got tripped up.  Unfortunately, there is a bug in Eclipse WTP which prevents the XML Validator from working properly in Web projects.  Therefore, unless you are careful, you can accidentally place the DataSource elements in the incorrect place.  Code-completion still works in the xml document, but it does not prevent you from making a mistake.  In my case, I put the jta-data-source element after the class element.  This results in an error at runtime such as: persistence.xml [Location: Line: 8, C: 20]: org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'jta-data-source'. One of '{"http://java.sun.com/xml/ns/persistence":class, "http://java.sun.com/xml/ns/persistence":exclude-unlisted-classes, "http://java.sun.com/xml/ns/persistence":properties}' is expected.

    Once I put the data-source elements in the valid location, everything worked great at runtime (thank you Pinaki!).  Here is an example of a persistence.xml file that uses the two DataSources correctly and complies with the XSD.

    <?xml version="1.0" encoding="UTF-8"?>
    <persistence xmlns="http://java.sun.com/xml/ns/persistence"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
        version="1.0">
        <persistence-unit name="pu">
            <jta-data-source>OracleXADataSource</jta-data-source>
            <non-jta-data-source>OracleDataSource</non-jta-data-source>
            <class>com.test.supplier.jpa.Supplier</class>
            <properties>
                <property name="openjpa.jdbc.DBDictionary" value="oracle(DriverVendor=oracle)" />
            </properties>
        </persistence-unit>
    </persistence>
    
    

    Conclusion

    Hopefully the JPA tooling in Workshop will incorporate the JNDI data-source connection in a future release and incorporate a fix for validating xml files in Web projects.  For more JPA blog entries, I highly encourage Pinaki's blog.  He's got lots of great JPA stuff.



    Hermes JMS - Open Source JMS Console

    Posted by jbayer on January 2, 2008 at 2:55 PM | Permalink | Comments (3)

    The WebLogic Server Administration Console provides the ability to monitor and view JMS messages from 9.x onwards.  However it is a web-based tool that is optimized for configuration, not monitoring and development testing.  Looking at the contents of multiple messages requires multiple screen refreshes and it can not do some advanced JMS activities like copy messages from one queue to another very easily.  Hermes JMS is a handy open source project hosted by Sourceforge and built by Colin Crist that can be used to monitor, inspect, and interact with JMS Queues, Topics, and Messages.  Here's how Colin describes it on the website:

    HermesJMS is an extensible console that helps you interact with JMS providers making it easy to browse or search queues and topics, copy messages around and delete them. It fully integrates with JNDI letting you discover administered objects stored, create JMS sessions from the connection factories and use any destinations found. Many providers include a plugin that uses the native API to do non-JMS things like getting queue depths (and other statistics) or finding queue and topic names.

    It works with many of the popular JMS providers such as Active MQ, Arjuna MQ, Tibco EMS, Fiorano MQ, JBoss MQ, JORAM, OpenJMS, Oracle, Pramati, SAP, SeeBeyond ICAN, SeeBeyond JCAPS, Sonic MQ, WebLogic JMS, WebMethods, and WebSphere MQ. This post will explain how to get Hermes installed and configured for use with WebLogic JMS.  If you would like to see the setup with WebLogic as a web recording, go here, otherwise read on for the step-by-step. 

    If you work in the financial vertical, Hermes also has some capabilities with FIX messages that are worth checking out.

    Quick setup

    To install, get the installer from sourceforge and run “java –jar hermes-installer-1.12.jar” in the directory where you have placed the installer jar.

    1. Open the <HERMES_HOME>/bin/hermes.bat or hermes.sh in your favorite editor. Add the path to your WLS JVM at the beginning of the file right after the REM comments.  Note: When I tested with the WLS 10.3 Tech Preview, I had to use the Java 6 JVM that shipped with the tech preview, so if you run into issues in the "discovery" phase, be sure to use the same JVM with Hermes as the WLS JVM you want to connect to.

    set PATH=D:\bea922\jdk150_10\jre\bin
    set JAVA_HOME=D:\bea922\jdk150_10\jre

    1. Launch Hermes by calling the hermes.bat
    2. Right click on “sessions” and select “new -> New session…”.
    3. On the resulting prompt, go to the “providers” tab at the bottom and add a “group” called “weblogic92” and a “library” specifying your path to weblogic.jar. Select “Don’t Scan” when prompted.

    clip_image002

    1. No go back to the “Sessions” tab. Enter a name for the session, in this case “examplesQCF”. In the “Connection Factory” section, select “weblogic92” for the loader (you may have to save and then edit the session to see the provider you just configured in the drop down for loader). Then select “BEA WebLogic” for the “Plug In” dropdown. Then add the properties as in the image below select “OK”.

    clip_image004

    1. Right click on the newly created “examplesQCF” session and select Discover. It should find all of the available destinations and list them under the examplesQCF session.

    clip_image006

    1. If you right click on the exampleQueue node under the session and select “Browse”, you should be able to see the contents of the queue. I have populated my exampleQueue with 3 messages. The first of which has a message payload of “Test Message”. Notice the headers are also displayed.

    clip_image008

    Hermes can monitor multiple queues at once, auto-refresh, use selectors, delete messages, etc. Check out the user guide at http://www.hermesjms.com for more information and tutorials.



    Using Workshop 10.1 with WebLogic Server 10.0 MP1

    Posted by jbayer on December 15, 2007 at 10:50 AM | Permalink | Comments (3)

    Background

    Workshop for WebLogic 10.1 ships with WebLogic Server 10.0 GA bundled in the installer.  Since that time BEA has released Maintenance Pack 1 for WLS 10.0.  So when one of my customers was getting started with developing on WebLogic Server 10.0, I recommended that they start with Server 10.0 MP1 because it has about 7 months worth of bug fixes that the 10.0 GA bits don't have.  Now this customer also wanted to take advantage of all of the great features that first showed up in Workshop 10.1, such as JSF, JPA, Hibernate, Struts, Spring, Beehive tooling all nicely assembled in Eclipse.  After talking with Workshop product management, I realized that there are no plans to update the Workshop 10.1 installer to include the WebLogic Server 10.0 MP1 bits.  You can still use Workshop 10.1 to deploy to Server 10.0 MP1, but there are some caveats.

    Expectation:  I should just be able to update the WebLogic Server 10.0 GA instance to MP1 by using SmartUpdate.  Theoretically yes, but not in this case.  The WebLogic Server 10.0 GA bits that are included with the default Workshop 10.1 installation are there just to support Workshop and are not able to be upgraded because Workshop 10.1 has not been updated itself for MP1.

    Disclaimer:  Note that this configuration (deploying from Workshop 10.1 to Server 10.0 MP1) has not been explicitly tested by our support teams.  I've found most use-cases work just fine.  I've noted several gotchas below, but be aware that this has not gone through an extensive QA.

    The installation steps

    Workshop 10.1 Installer

    Choose the "complete" installation.

    *Updated 12/21/07* Do not choose the custom installation!  Choose "Complete".  It turns out that Workshop 10.1 does have dependences on the Server 10.0 GA bits, so it's best to leave the defaults selected and install both Workshop 10.1 and Server 10.0 GA into the same BEA Home.  You can still install Server 10.0 MP1 into a different BEA Home without its Workshop 10.0 MP1 components as I show further below.  One of the things that will not work if Workshop 10.1 is installed without Server 10.0 GA in its BEA Home is deploying an application with EJBs to WebLogic Server from Workshop.  Reference CR356168 with BEA Support if you encounter troubles in this regard.

    complete

     

    Now install Server 10.0 MP1 into a new BEA_HOME directory.

    Select the custom installation, and make sure you install into a separate BEA_HOME directory from Workshop 10.1.

    server1

    Deselect the Workshop 10.0 components if you do not plan on using Workshop 10.0 MP1, but it doesn't harm anything other than take up disk space if you leave it selected.

    server2

    Post-installation Configuration

    At this point, I recommend changing the default JVM that Workshop will use to be the more recent Sun JDK that ships with Server 10 MP1.  I'll address this later, but it follows from the infamous serialVersionUID bug that has been around in the Sun JVM for awhile.  Open Workshop's ini file (mine is D:\Workshop10.1\workshop_10.1\workshop4WP\workshop4WP.ini) and point it to the updated JDK.

    Before:

    -vm D:/Workshop10.1/jdk150_06/jre/bin/javaw.exe

    etc, etc.

    After:

    -vm D:/bea100MP1/jdk150_11/jre/bin/javaw.exe

    etc, etc.

    Now you'll have both Workshop 10.1 and Server 10 MP1 installed on your machine, the next step is to configure Workshop 10.1 so that it is aware of the Server 10 runtime.  Go ahead and open a workspace and select Window->Preferences...->Server->Installed Runtimes.  Delete the existing 10.0 GA runtime and add the runtime for WebLogic Server 10 MP1.  Normally I wouldn't have to do this step, but since we installed Workshop and Server separately we have to tell Workshop where to find Server and where the correct library modules are located.

    runtime

    After we set that we should see that WebLogic->J2EE Libraries is now populated with the 10.0 MP1 libraries:

    Note:  If you did not delete the 10.0 GA runtime, you'll see multiple copies of the libraries.  They are actually unique, which you can tell by highlighting one, clicking the edit button and noting that the implementation version is different, even though the specification version is the same.

    libraries

    Now we're all set to develop and deploy as normal.  If you forgot to switch your JVM to the version that ships with WLS 10 MP1, which is jdk150_11, you will probably encounter the serialVersionUID error when you work with Beehive Service Controls.  Here is a a look at what that stack might look like, so you know to switch the JVM, delete your types-jar file from WEB-INF/lib, rebuild your controls in Workshop and then redeploy if you encounter it.

    <Dec 14, 2007 1:26:32 PM CST> <Error> <com.bea.control.servicecontrol.util.memento.ServiceClassMementoUtil> <BEA-000000>

    <com.bea.control.servicecontrol.util.memento.ServiceClassMementoUtil: Could not load the ServiceClassMemento from the following resource file:

    control/EchoServiceControlServiceClassMemento.ser.

    This is probably due to a versioning issue and if the developer was astute when they made the change then this should not be the reason. Another

    possibility is that this resource has become corrupt. The good news is a rebuild of your app should fix it. Throwable: java.io.InvalidClassException: javax.xml.namespace.QName; local class incompatible: stream classdesc serialVersionUID =

    4418622981026545151, local class serialVersionUID = -9120448754896609940 Stack Trace: java.io.InvalidClassException: javax.xml.namespace.QName; local class incompatible: stream classdesc serialVersionUID =

    4418622981026545151, local class serialVersionUID = -9120448754896609940 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:546)



    Using LDAP as a user-store for WebLogic Administrators

    Posted by jbayer on December 13, 2007 at 1:51 PM | Permalink | Comments (0)

    One of my customers that has hundreds of WLS instances recently asked me about moving towards a centralized model for managing WebLogic Administrators.  Currently they use the file-based out-of-the-box embedded LDAP that ships with WebLogic Server as an Administrator store.  This is great for getting started quickly, but it means that each instance has it's own local user store for Administrators.  Therefore, when one of their Administrators leaves the company they have to go to each server and change the Administrator password.  Now that can be a headache!  I have previously posted on how to set up WebLogic Server for use with OpenLDAP so that LDAP users can be used for authentication for web apps, etc.  In this post, I'll discuss how to extend that to WebLogic Administration, so that centralized administration of WebLogic Administrators can be enabled via external LDAP.

    Review the documentation for Authentication Providers

    E-docs has some great detail on how to configure more than one Authentication Provider and how to configure LDAP Authentication Providers, and specifically addresses the case in which LDAP is the only Authentication Provider.  One thing that is important to highlight if you go down the path of only having LDAP as the sole Authentication Provider is that it introduces a point of failure into your WebLogic Servers, meaning that if your WLS instances get network partitioned from your LDAP server(s) or your LDAP server(s) goes down, your WLS instances will not boot.  You can partially guard against this by configuring LDAP fail-over, but to keep the flexibility, you may want to keep the Default Authenticator around for emergencies and keep that user/password isolated to a master Administrator.  There are two ways to enable someone to be a WebLogic Administrator:

    1. Add the user to the Administrators group in LDAP (which is included in the Admin global role by default)
    2. Add the user to the Admin global role (you can do this by group, explicit user, etc)

    As it is mentioned in the docs, your LDAP may already use the Administrators group for another purpose, or you may not want to put users in that group and give them Administrator access to all the domains in your environment.  In this case, the 2nd method allows you to be much more granular and even put users in groups that might correlate to their business unit.  So I could have an HRWebLogicAdmins group in LDAP for the Human Resources department, and when I create the domains for that department, make sure I add that group to the Admin Global Role.  If that approach is taken, users may be able to use their normal LDAP user and credentials instead of a special Administrative account that is shared because their personal user has group membership to HRWebLogicAdmins.  This provides you with an additional level of auditing since you are not using shared Administrator accounts.

    Configure your base domain

    Let's put this into practice.  First let's assume were starting from scratch with no domains at all.  We'll configure LDAP with it and confirm that we can have Administrators in LDAP, then create a domain template with LDAP preconfigured so that new domains don't have to do this LDAP setup at all.  I'm going to use WLS 10 MP1 for this, but the steps should be similar in other versions of WLS.  I'm using the same OpenLDAP configuration that I discussed in my previous post, so refer to that for more detail on this setup if you need it.

    1. Create a domain - D:\bea100MP1\wlserver_10.0\common\bin\config.cmd (sh)
    2. Keep the defaults, which will have weblogic/weblogic as your Administrator.
    3. Start the AdminServer and login with weblogic/weblogic.at http://localhost:7001/console
    4. Click the "Lock & Edit" button in the console and optionally then click the "Record" button if you are in WLS 10 or higher and want to record the WLST script
    5. Add the OpenLDAP Authenticator to your realm (remember to set the control flag of both Authenticators to OPTIONAL or SUFFICENT)
    6. Review the Admin role mapping to see that it maps to the users/groups you want.  In this example, I'm assuming that the using the Adminstrators group in LDAP is okay.

    Roles [2]

    Here is the default mapping for all users in the Admin role.  Notice that it includes all of the users in the Adminstrators group by default.  This is where I could add other groups.  Be aware that role changes you make are stored as XACML and have to be imported/exported.

    groupMapping

    Now click "Activate Changes" and notice the name of the WLST script if you did a recording and the notice that we need to restart the server for the changes to take affect since we modified the security subsystem.  At this point we can shut the server down.

    Now let's review my LDAP configuration.  Using JXplorer I can both view and edit my OpenLDAP configuration.  Here are the settings that work with the LDAP config from my previous post:  Note that the password is "secret".

    jxplorer

    Note that I added an Administrators group and added the jbayer user as a member of that group.  To add a group, just right click on "groups" and select "New" and go through the prompts.

    Explorer

    Ok, now I should be able to boot WLS with the jbayer user and login to the console as an Administrator.  Let's try both.  First I need to update the boot.properties file that is located in the domain's <Server_Name>/security directory.  In my case, that is:  D:\bea100MP1\user_projects\domains\open_ldap_domain3\servers\AdminServer\security

    Opening the file shows you that the username and password are encrypted, so now we need to replace the {3DES} encrypted values with plain text ones for my jbayer user.  The next time WLS boots, it will re-encrypt these values.  Note that we can also find out the domains encrypted values ourselves by using the encryption utility:

    D:\bea100MP1\user_projects\domains\open_ldap_domain3\bin>setDomainEnv.cmd
    
    D:\bea100MP1\user_projects\domains\open_ldap_domain3>java weblogic.security.Encrypt jbayer
    {3DES}yunUy+yVmfY=
    
    D:\bea100MP1\user_projects\domains\open_ldap_domain3>java weblogic.security.Encrypt weblogic
    {3DES}PmZxnuL1akG6MzWSRo/g3w==
    
    Now we can boot the domain.  If there is a problem, you'll see a stack trace that mentions the security sub-system, you'll probably have to change the boot.properties file back to the original values, weblogic/weblogic if you didn't change the defaults and see if you messed up anywhere.
     
    If there is no problem and the server goes to a RUNNING state, then we have booted the server as jbayer, which is in the Admin role because that user is in the Administrators group in OpenLDAP.  Now try logging into the console and that should work as well.  Here is my screen-shot showing the successful jbayer user login as Administrator to the console.
    jbayer [2]

    Make it repeatable with WLST or a Domain Template

    Doing all of this configuration each time you want to setup a new domain can monotonous and prone to typing mistakes.  This is where using WLST or domain templates can come in very handy.  First let's review the .py file that was created during our WLST recording as we created the OpenLDAP Authenticator.  Mine was saved to my domain's base directory with the name Script1197502551016.py.  For more on WLST see my intro to WLST post and the command reference for documentation on WLST commands.

    cd('/SecurityConfiguration/open_ldap_domain/Realms/myrealm')
    cmo.createAuthenticationProvider('openLdapAuthenticator', 'weblogic.security.providers.authentication.OpenLDAPAuthenticator')
    
    cd('/SecurityConfiguration/open_ldap_domain/Realms/myrealm/AuthenticationProviders/openLdapAuthenticator')
    cmo.setGroupBaseDN('ou=groups, dc=bea, dc=com')
    cmo.setStaticGroupObjectClass('groupOfNames')
    cmo.setUserBaseDN('ou=people, dc=bea, dc=com')
    cmo.setUserObjectClass('inetOrgPerson')
    cmo.setPrincipal('cn=Manager,dc=bea,dc=com')
    setEncrypted('Credential', 'Credential_1197503008359', 'D:/bea100MP1/user_projects/domains/open_ldap_domain/Script1197502551016Config', 'D:/bea100MP1/user_projects/domains/open_ldap_domain/Script1197502551016Secret')
    cmo.setStaticGroupDNsfromMemberDNFilter('(&(member=%M)(objectclass=groupOfNames))')
    cmo.setUserFromNameFilter('(&(cn=%u)(objectclass=inetOrgPerson))')
    cmo.setGroupFromNameFilter('(&(cn=%g)(objectclass=groupOfNames))')
    cmo.setControlFlag('SUFFICIENT')
    
    cd('/SecurityConfiguration/open_ldap_domain/Realms/myrealm/AuthenticationProviders/DefaultAuthenticator')
    cmo.setControlFlag('SUFFICIENT')
    
    activate()
    

    I could simply use a script like this to configure my new domains to have LDAP support after they have been created.  However, I can go one step further and use the domain that has already been configured for LDAP and create a domain template using the Domain Template Builder D:\bea100MP1\wlserver_10.0\common\bin\config_builder.cmd.  Now when I create new Domains using the Config Wizard and base it off that template, authentication to OpenLDAP will be pre-configured.  Just launch the Domain Template Wizard, point it at the domain and follow all of the defaults.  I can even configure the Admin Role here to include other groups.

    One Last Gotcha

    One big gotcha that I encountered is that the new domains that I created based off that template still had the OpenLDAP password for the manager user set to the encrypted value of the first domain in the config.xml file in the new domain's config directory.  Each domain has a unique way of encrypting it's passwords so the encrypted values cannot be exchanged between domains.  I've highlighted the incorrect value below in the credential-encrypted element.  Make sure you replace that value with new domains correct {3DES} value that you can retrieve with technique illustrated earlier: java weblogic.security.Encrypt password.  I'm investigating whether this is working as designed or not as I expected the Config Wizard to take care of that for me. 

    <sec:authentication-provider xsi:type="wls:open-ldap-authenticatorType">
      <sec:name>openLdapAuthenticator</sec:name>
      <sec:control-flag>SUFFICIENT</sec:control-flag>
      <wls:propagate-cause-for-login-exception>false</wls:propagate-cause-for-login-exception>
      <wls:user-object-class>inetOrgPerson</wls:user-object-class>
      <wls:principal>cn=Manager,dc=bea,dc=com</wls:principal>
      <wls:user-base-dn>ou=people, dc=bea, dc=com</wls:user-base-dn>
      <wls:credential-encrypted>{3DES}68bCeqro3EA=</wls:credential-encrypted>
      <wls:user-from-name-filter>(&amp;(cn=%u)(objectclass=inetOrgPerson))</wls:user-from-name-filter>
      <wls:group-base-dn>ou=groups, dc=bea, dc=com</wls:group-base-dn>
      <wls:group-from-name-filter>(&amp;(cn=%g)(objectclass=groupOfNames))</wls:group-from-name-filter>
      <wls:static-group-object-class>groupOfNames</wls:static-group-object-class>
      <wls:static-group-dns-from-member-dn-filter>(&amp;(member=%M)(objectclass=groupOfNames))</wls:static-group-dns-from-member-dn-filter>
    </sec:authentication-provider>
    

    Hopefully this illustrates how LDAP can provide a way to manage WebLogic Administration in a way that is more scalable than having individual user stores in embedded LDAP when many WLS instances are involved.



    Asynchronous Servlet Article Extras - Push Events

    Posted by jbayer on December 5, 2007 at 9:34 AM | Permalink | Comments (1)

    I just finished reading Francesco Marchioni's article entitled Using Asynchronous Servlets to Deal with Hung Threads and thought that I could add some information for those that want to explore this functionality more and see a working example of a chat room built with AJAX.  This is really about implementing virtual push event to web clients.  Starting with WLS 10, there is an out-of-the-box example that ships with WebLogic Server that illustrates using the Abstract Asynchronous Servlet to build a chat room.  In effect, it uses AJAX to create an event push (via a long poll).  So now when a client sends a message to the chat room, all the clients receive the message virtually instantly without constantly polling the server for new messages.  This technique has come to be known as Comet in AJAX terminology.  To read the details of the example, just go to <BEA_HOME>/wlserver_10.0/samples/server/docs/core/index.html and expand the tree as shown below.  To run it, just follow the directions which are very straight-forward.

    ChatExample

    Also check the javadoc for the AbstractAsynchrounousServlet to get more information about the API.

    One neat thing to do is to run the example with both Firefox and IE at the same time and see messages sent by the IE client show up immediately in the Firefox client.  I have the Firebug plug-in installed and you can see how the XmlHttpRequest (XHR) is waiting for new chat messages to come in.  If no new messages arrive in 20 seconds, the AbstractAsynchServlet times out the request.  Then the client issues a new XHR and starts the process again.

    firefoxWithFirebug

    I've seen some fairly neat examples and demos built with the AbstractAsynchronousServlet in WebLogic Portal such as a dash-board portlet that sends out messages and alerts.  So if you have use-cases that would benefit from having events virtually pushed to web clients, consider using this approach as it is very effective and does not tie up threads on the server.



    WebLogic Scheduling - A polling approach to implement a DB event generator for ALSB

    Posted by jbayer on November 1, 2007 at 9:58 AM | Permalink | Comments (0)

    Scheduling tasks for Java environments seem to come up fairly often.  Often times cron or Windows's Scheduled Tasks might be used, but that's not necessarily ideal if your application servers are spread across multiple machines because your scheduling mechanism could now have a single point of failure on that particular OS instance.  In this post, I'll review a customer situation that is well-suited for a scheduled polling solution and discuss the various options that I researched in WebLogic to implement it.

    The Use Case - A Database Event Generator

    One of my customers recently purchased AquaLogic Service Bus (ALSB) and AquaLogic Data Services Platform (ALDSP).  One of their main use cases is to be able to monitor database tables for new records.  This particular customer has an aversion to database triggers, which is probably the most common solution to this type of problem.  Therefore, we need to rely on something external to the database to detect these events.  Unfortunately, this is not an out-of-the-box feature of either ALSB or ALDSP today, although it is a feature of WebLogic Integration (WLI).  One of the options for WLI's event generator is to use a query-based polling approach, which executes a select statement that returns new records, publishes the events, and updates each record to indicate it has been processed.  It does this on a schedule.  I thought that a similar approach could be implemented fairly easily in a regular J2EE application.  For example, a session bean method called on a regular basis that we could deploy to the ALSB server since it has WLS underneath the covers. 

    Timer Options in WebLogic Server

    So the question now becomes, what mechanism can be used to schedule the invocation of the session bean on a regular basis?  A key requirement is that the solution should work well in a clustered environment such that it will fail-over to another server in a cluster, yet doesn't redundantly execute on each server in the cluster.  I searched around and came up with several options for scheduling with timers in WebLogic.

    1. EJB 2.1 Timer Service
    2. Workshop Timer Control
    3. CommonJ Timer Manager

    EJB 2.1 Timer Service

    The EJB 2.1 Timer Service is supported in WLS 9.2 and WLS 10 and initially seemed like a good solution since it is a J2EE standard.  However, upon a little more investigation I ruled it out mainly because the timer object cannot be migrated from server to server.  Of course, it can take advantage of Whole Server Migration, but that is not currently implemented at this customer, and it has additional infrastructure requirements, such as a SAN, that add complexity.  Additionally, the Timer Service is not supported with WebLogic Clustering.  There are 2 possible compromises mentioned in the documentation, but neither one of those is ideal.

    Workshop Timer Control

    This mechanism is covered very well with a nice tutorial in the documentation and is very easy to develop.  However, this approach is also not designed to operate in a cluster with support for fail-over to another managed server.  Furthermore, using web-services may not be optimal with respect to reliability for once and only once messaging.

    CommonJ Timer Manager

    The CommonJ Timer and Work Manager specification was jointly developed between BEA and IBM to address the limitations of Threads and Timers when used in a managed container.  See the main page for the specification on dev2dev or review the documentation for additional detail and examples.  The WebLogic Job Scheduler functionality is specifically designed to work in a clustered environment and therefore, provides a solution that meets the main requirements.

    A Simple Prototype

    For this post, I'll discuss a simple prototype that I created that works well in a single-server environment.  Some of the details of how the Job Scheduler works will prevent this approach from being used without modification in a clustered environment, but I'll save those details for a subsequent posting.

    Event Generator Components

    StartupServlet and web.xml

    The init() method registers the TimerListener with the TimerManager that is configured web.xml, which also tells this servlet to start up automatically when the application starts.  The web.xml also has some other configuration components such as the sql to execute, how often to check for new rows, the max to process at one time etc.  By putting these details in web.xml, I can easily use a Deployment Plan to change these values later without changing my code.   The Here's how easy it is to create the TimerManager in web.xml:

       <resource-ref>
                <res-