Wednesday, December 05, 2007

Web Services - Spring Style

Ok, so there is the whole debate about EJB's vs.  Web Services, at least at my company - we have a team of Java developers who want to use EJB's (well sort of) and the Architecture team who is pushing portability/compatibility with web services. 

We use IBM's WebSphere here at work which is both good and bad I suppose - recently I was asked to help out with a Proof - Of - Concept application and wanted to leverage some of the services developed on WebSphere but from a non-WebSphere app server.  Guess what...  IBM won't let you access their services unless you are running under their JDK.  What the heck is up with that IBM?   We're wanting to play with some of the cool stuff that EJB 3/JPA and Annotations can give us but IBM doesn't support that in their JDK's so we can't play at all.

So, I'm playing with web services because I want a service that can be portable and compatible with other languages/frameworks - which comes at a bit of a performance hit - I understand - but it would be nice to have some services that could be accessed from other languages - don't get me wrong I love Java but I like to tinker with Python and Ruby as well....

My only complaint with Spring's Web Services is the build process...

I wrote my first Spring web service to authenticate user's against one of our LDAP servers, now I'm getting ready to write another web service from scratch and thought I'd write a tutorial on it as I go through the steps (note: I have adapted all of the code examples from a project I'm developing for another company so if you seen any misnamed xml namespaces, class files - or anything else let me know I'll fix them up for the next person).

Let's call our new web service...."ApplicationServices"

  • First of all create a Web Project however you like to do that (I like Eclipse so I'm going to be creating a new "Dynamic Web Project" with as few faces as possible - no struts, no jsf, nothing, just a plain vanilla servlet project)
  • My application will be running on GlassFish this is what the initial layout looks like:

projectLayout 

  • For my project I need to expose some functionality that was written to be included in another application.  Luckily it can be bundled up in a Jar and included into our project very easily.  Along with that let's go ahead and add all of our other supporting libraries.  Here is a list of every jar I needed to add for the Spring Web Services framework to work (versioning shouldn't be too terribly critical just don't use anything less than the version listed), along with hibernate as well.:
    • spring-ws-core-1.0.2.jar
    • spring-xml-1.02.jar
    • spring.jar
    • commons-logging.jar
    • commons-collections.jar(hibernate)
    • log4j-1.2.15.jar
    • jdom.jar - get this at JDOM
    • WSDL4j.jar
    • cglib-nodep-2.1_3.jar (hibernate)
    • ehcache-1.2.4.jar (hibernate)
    • hibernate3.jar (hibernate, duh)
    • dom4j-1.6.1.jar (hibernate)
  • Now that we have our libs all setup we need to configure our web.xml file.  Basically we need to map the spring webservice servlet class to a url and load up our config file like this:
    • <?xml version="1.0" encoding="UTF-8"?>
      <web-app id="WebApp_ID" version="2.4"
      xmlns="http://java.sun.com/xml/ns/j2ee"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
      <display-name>ApplicationServices</display-name>
      <servlet>
      <servlet-name>services-ws</servlet-name>
      <servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
      </servlet>
      <servlet-mapping>
      <servlet-name>services-ws</servlet-name>
      <url-pattern>*.wsdl</url-pattern>
      </servlet-mapping>
      <welcome-file-list>
      <welcome-file>index.jsp</welcome-file>
      </welcome-file-list>
      </web-app>

    • So, what is going here?  the <servlet> Tag let's our container know we have a servlet (you probably figured that much out) and then gives us a name to map it with and the class that needs to be loaded for it.
    • Next is the servlet mapping which uses the mapping name we just created and maps that to any requests that come in with a URL that ends with *.wsdl
    • Now this is the important part you MUST name your spring file the name of your servlet so for this example our spring file must be named: services-ws-servlet.xml and it must be in your WEB-INF directory (see the picture up above).
    • To be convenient let's load up a welcome file to see if things are working (don't forget to create the index.jsp file in the WebContent root directory - we will be using it to test with.  You can do something simple like "Hello World" if you want.  I never seem to get tired of seeing that one....

  • Let's go ahead and stub out a spring file and see if our application will even load.  Create a new file called services-ws-servlet.xml in the WEB-INF directory you can fill it up with this:

    • <?xml version="1.0" encoding="UTF-8"?>

      <beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
      http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
      http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
      http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd
      http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:util="http://www.springframework.org/schema/util">

      </beans>

    • That should be enough to get us started

  • Go ahead and fire up your container and see if it works.  You shouldn't see any startup exceptions in your logs.  And if you go to the URL of your container probably something like http://localhost:8080/ApplicationServices/index.jsp you should see whatever you content you put in the jsp page - now if you were to jump ahead and go to http://localhost:8080/ApplicationServices/something.wsdl the servlet we configured will load up and you should get a 405 error.
  • If you look at your logs you probably saw an error that said your log4j isn't configured correctly let's throw out a log4j.properties file in our classpath real quick this is the content I typically use:
      log4j.rootLogger=DEBUG, stdout, logfile
      log4j.rootCategory=DEBUG, stdout, logfile

      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      # %d = date
      # %p = priority
      # %c = category (class)
      # %m = message
      # %C = class
      # %M = method name
      log4j.appender.stdout.layout.ConversionPattern=%d %p [%c.%M] - %m %n

      log4j.appender.logfile=org.apache.log4j.RollingFileAppender
      log4j.appender.logfile.File=../logs/applications/applicationServices.log
      log4j.appender.logfile.MaxFileSize=1024KB
      log4j.appender.logfile.MaxBackupIndex=5
      log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
      log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n

      log4j.category.org.hibernate=WARN
      log4j.category.net.sf.ehcache=WARN
      log4j.category.org.apache.axis=WARN
      log4j.category.org.apache.commons.beanutils=WARN
      log4j.category.org.apache.commons.digester=WARN
      log4j.category.org.apache.catalina.session.ManagerBase=WARN
      log4j.category.org.apache.jasper=WARN
      log4j.category.org.springframework=WARN

  • So let's do something interesting....  Spring Web services recommends using the contract first pattern - basically we configure an xml messsage (or conversation) and use that to drive our service creation instead of having our application drive our xml configuration.  This seems a little backwards but it breaks your XML (or WSDL ultimately) from being tightly coupled to the code behind it (which is a good thing).
  • So we need our service to do something... Let's create some XML to help us think about what we're going to do:

    • Let's create an auto process request object that has an instance name
    • And an auto process response that has a statusCode and a messages field my XML looks like this:
      <autoProcessing  xmlns="http://www.flyingspheres.com/tutorial/services">
      <processRequest
      <instanceName>someInstanceName</instanceName>
      </processRequest>

      <processResponse>
      <statusCode></statusCode>
      <messages></messages>
      </processResponse>
      </autoProcessing>

  • We need to turn that into an xsd document that looks like - a little caveat here there is an amusing statement in the spring webservices tutorial "By far the easiest way to create an XSD is to infer it from sample documents.  Any good XML editor or Java IDE offers this functionality" Oddly enough I couldn't figure out how to get Eclispe or Netbeans to do this either - either I don't know how to use the tool (possible) or they aren't decent editors ( you can decide that one yourself).

    • You could definitely hand tool the XSD it isn't that difficult however... since we want to reduce the hand tooling as much as possible go to HitSoftware and load up your xml file and generate your xsd
    • You should get a response that looks like this:
      <?xml version="1.0" encoding="UTF-8" ?>

      <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
      <xs:element name="autoProcessing">
      <xs:complextype>
      <xs:sequence>
      <xs:element ref="processRequest" />
      <xs:element ref="processResponse" />
      </xs:sequence>
      </xs:complextype>
      </xs:element>

      <xs:element name="instanceName">
      <xs:complextype mixed="true" />
      </xs:element>

      <xs:element name="messages" type="xs:string" />

      <xs:element name="processRequest">
      <xs:complextype>
      <xs:sequence>
      <xs:element ref="instanceName" />
      </xs:sequence>
      </xs:complextype>
      </xs:element>

      <xs:element name="processResponse">
      <xs:complextype>
      <xs:sequence>
      <xs:element ref="statusCode" />
      <xs:element ref="messages" />
      </xs:sequence>
      </xs:complextype>
      </xs:element>

      <xs:element name="statusCode" type="xs:string" />

      </xs:schema>

  • That got us pretty close but to get to where we need we need to adjust the xsd just a bit let's change it to look like this, oh and put the saved file in your WEB-INF directory: 
    <?xml version="1.0" encoding="UTF-8" ?>

    <xs:schema targetNamespace="http://service.flyingspheres.com/autoProcessing"
    elementFormDefault="qualified"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:auto="http://service.flyingspheres.com/autoProcessing">
    <xs:element name="autoProcessing">
    <xs:complexType>
    <xs:choice>
    <xs:element ref="auto:processResponse" />
    <xs:element ref="auto:processRequest" />
    </xs:choice>
    </xs:complexType>
    </xs:element>

    <xs:element name="processRequest">
    <xs:complexType>
    <xs:sequence>
    <xs:element ref="auto:instanceName" />
    </xs:sequence>
    </xs:complexType>
    </xs:element>
    <xs:element name="processResponse">
    <xs:complexType>
    <xs:sequence>
    <xs:element ref="auto:messages" />
    <xs:element ref="auto:statusCode" />
    </xs:sequence>
    </xs:complexType>
    </xs:element>
    <xs:element name="instanceName" type="xs:string" />
    <xs:element name="messages" type="xs:string" />
    <xs:element name="statusCode" type="xs:string" />
    </xs:schema>

  • Next we need to flesh out our spring file so that it will do something useful. I highly recommend going out and reading the documentation on the spring web services before you go too far down this path there are a lot of options and a ton of functionality I'm not covering here but you may need to do something very clever that I don't....
  • So this is my spring file:

<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.0.xsd
http://www.springframework.org/schema/lang http://www.springframework.org/schema/lang/spring-lang-2.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:lang="http://www.springframework.org/schema/lang" xmlns:jee="http://www.springframework.org/schema/jee" xmlns:util="http://www.springframework.org/schema/util">
<import resource="persistence_ioc.xml" />
<!-- WSDL Generation Information -->
<bean id="autoProcessing" class="org.springframework.ws.wsdl.wsdl11.DynamicWsdl11Definition">
<property name="builder">
<description>
The builder creates a WSDL from the a schema.
It detects all elements that ends with 'Request', finds corresponding
'Response' messages, and creates an operation based on that.
        </description>
<bean class="org.springframework.ws.wsdl.wsdl11.builder.XsdBasedSoap11Wsdl4jDefinitionBuilder">
<property name="schema" value="/WEB-INF/mySchemaFile.xsd"/>
<property name="portTypeName" value="processing"/>
<property name="locationUri" value="http://localhost:8080/ApplicationServices/"/>
</bean>
</property>
</bean>

<bean id="servicesEndPoint" class="com.flyingspheres.service.endpoints.ServicesEndPoint">
<constructor-arg ref="autoProcessingService"/>
</bean>

<bean id="autoProcessingService" class="com.flyingspheres.service.AutoProcessingService">

</bean>

<bean class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
<property name="mappings">
<props>
<prop key="{http://service.flyingspheres.com/processing}Processing">servicesEndPoint</prop>
</props>
</property>
<property name="interceptors">
<list>
<ref local="loggingInterceptor"/>
<ref local="validatingInterceptor"/>
</list>
</property>
    </bean>
<bean id="loggingInterceptor" class="org.springframework.ws.server.endpoint.interceptor.PayloadLoggingInterceptor">
<description>
This interceptor logs the message payload.
</description>
</bean>
<bean id="validatingInterceptor"
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<description>
This interceptor validates both incoming and outgoing message contents according to the 'echo.xsd' XML
Schema file.
</description>
<property name="schema" value="/WEB-INF/mySchemaFile.xsd"/>
<property name="validateRequest" value="true"/>
<property name="validateResponse" value="true"/>
</bean>
</beans>



    • Details:

      • the autoProcessing bean has defines how the container / client will interact with our service you can access the wsdl by going to the url locationUri/portTypeName.wsdl: http://localhost:8080/ApplicationServices/processing.wsdl obviously this will probably be different for you.
      • servicesEndPoint bean is the entry point for your application, our example uses a constructor arg so that we can control how it is created - this can be done a lot of different ways but this is how the Spring WS tutorial does it so we will follow suit.
      • autoProcessingServices bean is where we will do most of our coding that is what will actually happen
      • The next bean doesn't have a name but is really where the magic happens that kind of maps urls to our endpoints (which ends up calling our service bean).  This line: <prop key="{http://service.flyingspheres.com/processing}processing">servicesEndPoint</prop> is where the url is mapped to our end point
      • Next some interceptors are defined (we'll talk about interceptors and aspects some other day).  For now they're there to do what they look like validation and logging

  • Well if we did everything correctly we should be able to access a wsdl that looks something like this:
    <?xml version="1.0" encoding="UTF-8"?><wsdl:definitions xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:schema="http://service.flyingspheres.com/processing" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" targetNamespace="http://service.flyingspheres.com/processing">
    <wsdl:types>
    <xs:schema xmlns:auto="http://service.flyingspheres.com/processing" xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified" targetNamespace="http://service.flyingspheres.com/processing">
    <xs:element name="autoProcessing">
    <xs:complexType>
    <xs:choice>
    <xs:element ref="auto:processResponse"/>
    <xs:element ref="auto:processRequest"/>
    </xs:choice>
    </xs:complexType>
    </xs:element>

    <xs:element name="processRequest">
    <xs:complexType>
    <xs:sequence>
    <xs:element ref="auto:instanceName"/>
    </xs:sequence>
    </xs:complexType>
    </xs:element>
    <xs:element name="processResponse">
    <xs:complexType>
    <xs:sequence>
    <xs:element ref="auto:messages"/>
    <xs:element ref="auto:statusCode"/>
    </xs:sequence>
    </xs:complexType>
    </xs:element>
    <xs:element name="instanceName" type="xs:string"/>
    <xs:element name="messages" type="xs:string"/>
    <xs:element name="statusCode" type="xs:string"/>
    </xs:schema>
    </wsdl:types>
    <wsdl:message name="processRequest">
    <wsdl:part element="schema:processRequest" name="processRequest">
    </wsdl:part>
    </wsdl:message>
    <wsdl:message name="processResponse">
    <wsdl:part element="schema:processResponse" name="processResponse">
    </wsdl:part>
    </wsdl:message>
    <wsdl:portType name="autoProcessing">
    <wsdl:operation name="process">
    <wsdl:input message="schema:processRequest" name="processRequest">
    </wsdl:input>
    <wsdl:output message="schema:processResponse" name="processResponse">
    </wsdl:output>
    </wsdl:operation>
    </wsdl:portType>
    <wsdl:binding name="autoProcessingBinding" type="schema:autoProcessing">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="process">
    <soap:operation soapAction=""/>
    <wsdl:input name="processRequest">
    <soap:body use="literal"/>
    </wsdl:input>
    <wsdl:output name="processResponse">
    <soap:body use="literal"/>
    </wsdl:output>
    </wsdl:operation>
    </wsdl:binding>
    <wsdl:service name="autoProcessingService">
    <wsdl:port binding="schema:autoProcessingBinding" name="autoProcessingPort">
    <soap:address location="http://localhost:8080/ApplicationServices/"/>
    </wsdl:port>
    </wsdl:service>
    </wsdl:definitions>

  • We can then take this wsdl and drop it into our client and have it generate the necessary files to call our web services.
  • Before we close this tutorial for now let's talk real quick about the ServicesEndPoint class.    So we told spring that we were going to create a class called com.flyingspheres.service.endpoints.ServicesEndPoint that would extend the AbstractJDomPayloadEndpoint class (by telling spring that it would be called from the org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping class that meant we had to extend the AbstractJDomPayloadEndpoint.  Since we also told spring that we would overload the constructor with our serviceBean we need to define that constructor as well as the methods the PayloadEndpoint forces us to implement.  The Spring WS tutorial section 3.6 does a great job explaining what needs to happen in those methods - so I won't cover that here.  For our needs lets put in some logging like this:
    package com.flyingspheres.service.endpoints;

    import org.apache.commons.logging.Log;
    import org.apache.commons.logging.LogFactory;
    import org.jdom.Element;
    import org.springframework.ws.server.endpoint.AbstractJDomPayloadEndpoint;

    import com.flyingspheres.service.AutoProcessingService;

    public class ServicesEndPoint extends AbstractJDomPayloadEndpoint{
    private static final Log LOG = LogFactory.getLog(ServicesEndPoint.class.getName());
    public ServicesEndPoint(AutoProcessingService service){
    LOG.debug("Entering the constructor with a: " + service.getClass().getName());
    }
    protected Element invokeInternal(Element authenticationRequest) throws Exception {
    LOG.debug("Entering the invokeInternal method with a: " + authenticationRequest.getClass().getName());
    return null;
    }
    }

Well that should be enough to get you started...  Read the tutorial and all of the other documentation as well if you have any questions let me know Aaron at flyingspheres dot com


 


Happy coding!

Spring Web Services

First of all let me start by saying I love the Spring Framework.  It makes my job a ton easier - things just work better when you use Spring.  One of the things I love about it the most is that when you download it you have the option to download all of the dependencies which is a very extensive list of libraries that cover just about everything (Aspects, Hibernate, Toplink, Axis, Velocity, 62MB of 3rd party libraries) it is very convenient.

However the Spring WebServices Framework opted to use Maven to manage their dependencies if you were to download maven and try to build it you might get an error that looks like this:

mvnError

I don't really care why, and I don't want to learn Maven right now - I'm sure I will eventually right now I just want it to work - and I need a list of required Jars for my web services to work.....

 

Not a very good experience - if I was not an experienced developer I would probably give up and use something else...

Monday, November 12, 2007

Two Hats

So did you hear the one about 2 hats on a hat rack?

 

The first one said to the other - "You stay here, I'll go on a head."

 

get it go on a head....

Friday, November 09, 2007

H:SelectOneMenu

This is the JSF tag that causes me more frustration than just about any other tag.   Probably documented the worst - probably a relation ship there...

So here is an example of the tag:

 

<h:selectonemenu value="#{selectManager.selectedTheme}">
<a4j:support actionlistener="#{treeManager.filterWorkspaces}"
ajaxsingle="true"
rerender="workspaceTree"
event="onchange">
<f:selectitems value="#{selectManager.themes}">
</h:selectonemenu>

 


Aside from from the a4j:support tag (we'll talk about that later) it is pretty much a text book example. The problem is what happens in the selectManager. 


We have 2 values we are binding to this component one is the #{selectManager.selectedTheme} and the other is #{selectManager.themes}.  If we take a step back and remember what the HTML select/option guys do we can figure out what is going on the selectedTheme variable is going to be one Object that is submitted on the post - the tricky part is that the themes object supposedly can be a List, an Array , a Set but really you just want to use a List.  Everything else just causes problems.


So the data backing the selectOneMenu is kind of important.  The API and documentation says that you need to use SelectItem objects and when you create a new one it takes an Object and a String (there are other constrcutors but this one works good for me)in it's constructor one is the value the other is the label.  Fair enough...


Here is the really important part the Object for the value really needs to be a String.  Now you can go and jump through all kinds of hoops to write converters and modify all your config files but just make the darn thing a String and be done with it.  If you want to put in your fancy objects I wish you the best of luck but keep the complex stuff in your code not the transmission between the jsps and your controllers.


So, the a4j:support part... this is the fancy stuff that is given to us from ajax4jsf library it makes your select component make ajax calls to the bound listener (#{treeManager.filterWorkspaces}) in our case.  It submits to a method that needs to accept an ActionEvent and return nothing.  Once you get into that method it is super easy to get the selected item - notice the selectOneMenu has a bound value #{selectManager.selectedTheme} that value is updated via the DHTML it has nothing to do with AJAX or form submits anytime you change the select list that value is changed... So when you're in your event method all you have to do is ask the FacesContext what the value is something like this:

SelectManager mgr = (SelectManager)FacesContext.getCurrentInstance().getExternalContext().getRequestMap().get("selectManager");
mgr.getSelectedTheme();

 


That's it... Pretty easy huh?


-Aaron

My New Java Shirt

Check out my new Java shirt! You're probably jealous now aren't you.

Thursday, November 08, 2007

Java Server Faces and AJAX

So, to carry on the theme from the previous post I've been playing with JSF quite a bit lately.  I've recently been moved over to the Architecture team and this team isn't so Java savvy.  They do learn quickly they/we are working on a proof of concept application and they opted to do Spring MVC in lieu of Java Server Faces.  Mostly do to the very steep learning curve; they wanted to learn something fairly easy to help meet their delivery dates.  Since they don't have much of any Java experience it was probably a wise choice.

Except for the fact that the development team that they are supposedly leading doesn't use Spring MVC for anything!!!  The dev team is a strict Struts shop until the last project that I did which introduced JSF, which seemed to be a very successful experience, although a rather painful learning curve.

Having said that what exactly does it mean to have a standard if the people that should be defining don't follow it?  <- that is mostly just a complaining kind of question I suppose.

My real question is with all of the web frameworks out there (and that isn't even a comprehensive list, especially if you start looking at various JSF Implementations ) how can you ever decide what should be your company's standard?  A search of JSF at Dice dot com shows 1,605 jobs Struts has 2,318.  I'm sure there is a bit of cross over but that is a significant difference.  Supposedly JSF is the direction the industry is moving towards - in fact IBM is not longer actively supporting Struts on their portal servers, so I guess that must mean something.

So why do enterprise development teams set standards if the technology moves so quickly?  As soon as you set them they're out of date...  So why then?

  • Performance
  • Scalability
  • Stability
  • Development Speed
  • Easily found skill set
  • Licensing
  • Support Structure
  • Long term viability of the technology

I guess that is a decent list - not terribly comprehensive but things to think about when deciding on a standard.  What things would you think about?  What frameworks are standard where you work?

Monday, November 05, 2007

JPA Code Examples

So here are the goodies:

first you need to make your persistence.xml file look kind of like this:

<?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" version="1.0" xsi:schemalocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
<persistence-unit name="TestJPA">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>com.agnostic.software.jpa.entities.Users</class>
<properties>
<property name="hibernate.connection.driver_class" value="org.gjt.mm.mysql.Driver"></property>
<property name="hibernate.connection.url" value="jdbc:mysql://serverName/dbName"></property>
<property name="hibernate.connection.username" value="webUser"></property>
<property name="hibernate.connection.password" value="myPassword"></property>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"></property>
</properties>
</persistence-unit>
</persistence>

 


Notice the properties section and the lack of jta-data-source tag, this will create a problem if you want to use this persistence file to deploy to the app server.


Your Entities won't need to change, they'll work the same. 


Your Junit tests can be configured lots of ways but this is how I did mine:

public class TestUsers extends TestCase {
private EntityManagerFactory emf;
private EntityManager em;
@Override
protected void setUp() throws Exception {
emf = Persistence.createEntityManagerFactory("TestJPA");
em = emf.createEntityManager();
}
public void testRetrieveUsers(){
em.getTransaction().begin();

List<Users> users = null;
try{
Query query = em.createQuery("Select u from Users u");
users = (List<Users>)query.getResultList();
} catch (Exception e){
e.printStackTrace();
}
assertNotNull(users);
for (Users u : users){
System.out.println(u);
}
System.out.println("returning: " + users.size() + " users");
em.close();
emf.close();
}
}

That is it in a nutshell, I'm surprised that this isn't documented somewhere better but here it is for your testing enjoyment... So don't give me any excuses test that code!

Testing JPA

So, I've gotten very comfortable with the whole Spring/Hibernate mashup.  I really can't think of a better way to do database transactions than using hibernate to map the database and Spring to inject the Hibernate sessions into which ever component needs it.  It is simple and it just simply works...

 

One of my favorite things about using Hibernate is the Criteria search capabilities.  Basically it is a very OO way to do simple queries - you can get kind of clever with them but for the most part simple is better.   And in my opinion if you're writing queries that can't be done with Criteria's your data model probably sucks and needs to be re-worked... like that is ever an option.

 

Anyway I've recently joined the Architecture team and I was having a conversation espousing the glory and ease of use of these criteria's when somebody popped their head up over the cube wall and said "Why would you use Criteria's anyway they're not supported by the JPA specification."

 

Which is unfortunately true... for now anyway.

 

So, my last project was with JSF which was delivered successfully but it was extremely painful.  Mostly due to IBM's horrible implementation with their 5.0 portal server - heh, yeah it was even jdk1.3 how cool is that?

 

As that project is closing off I've been thinking on some of the pain points of that my team and I went through.  This contemplation led me to SEAM which led me to EJB3 and JPA.

 

So that's twice that JPA has come up recently so I decided to start poking around and see if I can figure the new specification out.  Indeed I have lost my beloved criteria's and once again an forced to contaminate my java code with SQL like syntax.  I can live without that temporarily anyway as long as I have a robust testing model.  So far the best I've seen is integrating with Spring to do it.  But isn't EJB3 supposed to handle the IOC for me? 

 

So after more searching than their should have been I found this article that takes you to a Sun Tutorial on desktop Java so with just a little bit massaging I can now run Junit test cases with just JPA, very sweet...

Thursday, October 04, 2007

Wednesday, October 03, 2007

Picture I saw on the way to work the other day.

Monday, September 10, 2007

Intention

I have had several blog entries in the past about intentions.  So, excuse me for repeating myself but my thoughts often return to this subject and my misunderstanding of them in the past and present.

For those of you who may read this and not really know me I have an 11 year old boy, a 8 year old girl, and a 3 year old girl as well.  Lately the 11 year old has taken quite an attitude with pretty much everyone but mostly with his oldest sister.

This morning he was exceptionally grouchy about her whistling on the way to the car.  On and off throughout the day I had thought about what I could say that would let him know that the problems that he has with her are mostly in his perspective of reality.  In other words her whistling or crunching on some popcorn loudly maybe rude but are mostly problems because of what he brings to the experience. 

Pema Chodron has a book called "No Time to Lose" that talks about how we should react when people do things that we perceive to hurt (or irritate) us.  The advice in that book is to act as though the people had as much intention or control over themselves as a tree dropping one of it's limb's on our head.  A tree would have no intention of hurting us so it would be silly to be angry  at the tree.

So here I am explaining this to my son in the context of his sister being the tree; her irritating habits are only irritating to him because he chooses to be angry at her.

He then corrects me and proceeds to explain to me that he is trying to get her to stop so that when she is at school she won't behave that way - and then people won't tease or make fun of her the way they did him, and that he gets angry because she ignores his advice.  Her not showing the proper response to his advice is what makes him angry not that she is chewing with her mouth open or whistling...


The conversation was pretty much over at that point.  His intention is sound, he is just not carrying it through properly...

 

... Amazing ...

 

-Aaron

Wednesday, August 15, 2007

Teachers...

So, I realize that I have a different view on things...

I suppose I always have and probably always will.  I'm okay with that, however it does seem to cause the occasional friction or concern that no one else has but me. 

Today someone put in their 2 weeks notice here at work.  Many people were quite happy that he did, not me though.  Admittedly this fellow  is very hard to work with, he does not hesitate to interrupt conversations, refuses to follow the development process we have in place, and doesn't ask for help when he doesn't know what to do. 

However, he really cared about the quality of his work and would argue his point until you were forced to listen, but would eventually concede when/if the case was lost.

We were at odds a lot of times and I think that I'm the only one who had any respect for him at all.  I did (usually) like him as a developer and a person.  

Not that I didn't get frustrated and occasionally angry with him.  I just can't help but think of the Buddhist teaching that tells us to be thankful for the people in our lives that we struggle to get along.  It is through them that we learn compassion, patience and wisdom...

 

So, see you later V. P. I hope your next job treats you better...

-A

Wednesday, August 01, 2007

I always wondered how to do that!

So, have you ever been writing code and new there was a probability an exception was going to get thrown. For whatever reason you want to do something with the stack trace kind of unusual, and you want more than just the exception.getMessage() in fact you want the whole stack trace.

Now I never claimed to be a rocket scientist. Some days I don't even claim to be clever. Today I took the time to figure out how to catch the exception and turn the complete stack trace into a String that you can do whatever you want to with. Here is the snippet I used.

catch (Exception e){
confirmMessageButton.setText("Exit");
OutputStream os = new ByteArrayOutputStream();
PrintWriter writer= new PrintWriter(os);

e.printStackTrace(writer);
writer.flush();
String myMessage = new String(
((ByteArrayOutputStream)os).toByteArray());
//do something with the string
}


So, like I said it's not rocket science but it is something I always wondered how to do.


-Aaron


Monday, July 30, 2007

A dash of ruby

So, I've been playing with ruby on and off now for about 2-3 months.  After going through the pick axe book and a rails book I have pretty much set it down, mostly so I could focus on some Java issues at work. 

After our last release the Java work has settled down and now my interest in Ruby has once again returned, not Rails so much (However, I do think that the Java Community has a lot to learn from Rails though).  So here is the problem I had...

The company that I work for is completely in love with EJBs (2.1).  We use them with Spring so it's not as bad as it might sound.  Anyway to stub out an EJB it takes about an hour.  That is without any methods that actually do something.

So just in the event that you 're working on an application server that doesn't support JEE 5 or higher (I think that is the write acronym - they keep changing) here are the things you need (this is the spring version so there are a few extra interfaces in there to make it more fun):

Server Side Components

  1. The implementation that does something.  This should extend the interface in the client
  2. The EJB that implements the interface in the client and and Spring's AbstractStatelessSessionBean

Client Side Components

  1. The interface that defines what is supposed to happen
  2. The LocalHome interface this guy extends EJBLocalHome and simply has a create() method
  3. The Local interface this guy extends our interface and EJBLocalHome.  Oddly enough he has no methods (spring takes care of it for us).
  4. The Remote  interface he extends EJBObject and has the same method signatures as the interface (unless you don't want them exposed through remote objects)
  5. The RemoteHome interface that extends the EJBHome he has one method method called create()

 

So to hand code all of these things correctly takes me around an hour more or less depending on distractions.  So here is a fancy little ruby script that will prompt you for package names implementation names and a few other things and generate those guys for you.  Of course you will still need to configure the spring files and ejb-jar.xml file as well as whatever custom config files your appserver needs but it was a fun task to do with Ruby.

 

-Aaron

Friday, July 20, 2007

Life is like that I guess

So, my dad is dying...  Ok, so he is technically my step dad but he raised me nonetheless.  Many of my best (or worse attributes) come from him.

Anyway, last year he lost a kidney to cancer.  The one he has left is only working at 50% capacity (so that is 25% over all).   It turns out on top of all that he has a small spot of lung cancer as well...

So, yeah.  He's feeling fine now but we don't know how long that will last.  He is taking treatments for the bladder/kidney cancer several times a week now.  And the doctors are trying to figure out what to do about the lung cancer now.

On the flip side he has a Grand Daughter who is about to get married, his house is paid off, he has his first Grand Son who will bear his name that will be born in a few months...

Life is like that I guess... Really bad things happen at the same time really bad things happen... It's never all bad or all good. 

It reminds me of the Zen story of where this guy is hanging from a vine while a tiger is looking down trying to get him, a poisonous snake is working it's way up to get him, and 2 mice begin to chew the vine.  With death coming from all around some honey starts dripping into the hole and he realizes how great the honey tastes. 

 

Yeah, Life is like that I guess.

 

-Aaron

Tuesday, July 17, 2007

Buddha is as Buddha does

So, I started reading a new book a few weeks ago.  It's called "Buddha is as Buddha Does" by Lama Surya Das.

 

I haven't read any of Lama Surya Das's other books but this one is really great.  However, it is not a fast reader the concepts are really quite deep.  It's one of those books that has to be digested slowly.  I find myself only able to read a couple of pages at a time.  The concepts just sit in my mind and slowly soak in.  Here is a particularly great paragraph (from chapter 1 - Generosity):

"Whenever we consider our inner thoughts about anything, it's crucial to bear in mind that we can change them.  Being visited by negative or selfish thoughts doesn't make us bad people.  It just means we're conditioned human beings.  Nor do we have to be forever at the mercy of these thoughts merely because they occurred to us.  We can cultivate positive thoughts to replace them, thus skillfully and intentionally reconditioning and eventually deconditioning our energy and ourselves.  When the Buddha said, 'We are what we think,' He was asking us to take responsibility for our inner life.  That's the crux of why meditation and awareness cultivation are such vital practices in Buddhism.  They enhance our ability to manage more skillfully our own thoughts and feelings, including our thoughts about generosity -- a truth that, again illustrates how all the paramitas are interrelated and mutually supportive.

It is a great comfort for me to remember throughout the day that the thoughts that arise in my mind are not necessarily a reflection of who and what I am.  Irrational anger can be caught and defused before it explodes.

The teachings of the Buddha give me great hope...

-A

Monday, July 16, 2007

Cool Little JavaScript goodie

Oddly enough one of the best web sites I've been to in a while is my local gas company.  They have this fancy little clock that tells you what time it is, I finally took the time to figure out how they did it.  Here is the short version...

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<TITLE> Clock </TITLE>
<SCRIPT LANGUAGE="JavaScript">
<!--
/* =================================================== */
// Display Date / Time
var ie = /MSIE/.test(navigator.userAgent);
/* =================================================== */
var addEvent;
if (document.addEventListener) {
    addEvent = function(element, type, handler) {
        element.addEventListener(type, handler, null);
    };
} else if (document.attachEvent) {
    addEvent = function(element, type, handler) {
        element.attachEvent("on" + type, handler);
    };
} else {
    addEvent = new Function; // not supported
}
/* =================================================== */
// Display Date / Time
function clock(){
    if (!document.getElementById){ return }
    this.start = function(){
        var self = this;
        this.date = new Date();
        // ===== Set Timezone & Daylight Savings ===========
        var day = this.date.getDay();
        var month = this.date.getMonth() + 1;
        var week = Math.floor((this.date.getDate() - 1) / 7) + 1;
        var dst = Number(month +""+ week +""+ day);
        // daylight savings range
        var start = 327  // March(3): Second(2) Sunday(7) = 327;
        var end = 1117    // November(11): First(1) Sunday(7) = 1117;

        this.offset = (dst > start && dst < end)? -5 : -6;
        this.zone = "CT";
        this.utc = this.date.getTime() + (this.date.getTimezoneOffset() * 60000);
        this.d = new Date(this.utc + (3600000*this.offset));
        // ===== Format Date ===============================
        this.day = this.addZeros(this.d.getDate());
        this.month = this.getMonthName(this.d.getMonth());
        this.yr = this.d.getYear();
        this.year = (this.yr<1000)? (this.yr+=1900) : this.yr;
        self.addSeconds();
        window.setInterval(function() {self.addSeconds();},1000);
    };
    this.addSeconds = function() {
        this.d.setSeconds(this.d.getSeconds() + 1);
        var hours = this.setMeridian(this.d.getHours());
        var minutes = this.addZeros(this.d.getMinutes());
        var seconds = this.addZeros(this.d.getSeconds());
        document.getElementById("dateTime").innerHTML = this.month+" "+this.day+" "+this.year+" "+hours+":"+minutes+":"+seconds+" "+meridian+" "+this.zone;
    };
    this.getMonthName= function(nMonth){
        var months = new Array('Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec');
        return months[nMonth]
    };
    this.setMeridian = function(hours){
        meridian = (hours < 12)? "AM" : "PM";
        return (hours > 12)? hours-12 : (hours==0)? 12 : hours;
    };
    this.addZeros = function(digits){
         return (Number(digits) < 10) ? "0"+digits : digits;
    };
}
addEvent(window,'load',startClock);
function startClock(){
    var theClock = new clock();
    theClock.start();
}
/* =================================================== */
//-->
</SCRIPT>
<STYLE TYPE="text/css" TITLE="">
t body { margin:0px; padding:0px; border:0px; text-align:center; background:#FFF; }
body { margin:0px; padding:0px; border:0px; text-align:center; background:#FFF; }
body * { font-family: Tahoma, Arial, Helvetica, sans-serif; }
#header ul.navitems  { position:absolute; top:8px; left: 165px; z-index:10; margin:0px; padding:0px; list-style-type:none; }
#header ul.navitems li { float:right; font:normal 10px Arial, Helvetica, sans-serif; color:#898688; padding-left:10px; }
#header ul.navitems li.stock { background:transparent url(../images/arrow.gif) no-repeat 0px 0px; padding-right:10px;  }
#header ul.navitems li#dateTime { border-left:1px solid #CCC; margin-left:10px; display:block; width:140px; padding:0px 10px 0px 10px; white-space:nowrap; }
#header ul.navitems li a { position:relative; top:2px }
</STYLE>
</HEAD>

<BODY >
<div id="header">
    <ul class="navitems">
        <li id="dateTime">&nbsp;</li>
    </ul>
</div>
</BODY>
</HTML>

Saturday, July 14, 2007

One More...

Releasing the Cows as told by Thich Naht Hahn

So one day the Buddha was sitting with a number of monks in the woods. They had just finished their mindful lunch and were about to start a Dharma discussion when a farmer came by. He was lost and said: “Dear Venerables did you see my cows passing by here?”, and the Buddha answered “No we have not seen any cows”.

“I have 3 cows, and this morning I don’t know why, all of them have run away. And this year the insects have eaten up all of our crops I think I’m going to die.” The farmer expressed his sufferings and worries.

The Buddha said “Dear friend, we have not seen your cows passing by here, you might try to look in the other direction.” The farmer thanked the Buddha and went away.

The Buddha turned to his monks smiling he looked at them and said “Dear Friends, do you know that you are happy people? Do you know that you are lucky people? You don’t have any cows to lose!”

So the practice here is to identify the cows that you have. The cows that you think you can not be separated from. The cows that you think are essential to your happiness but these cows actually cause you suffering.

Odds and Ends pt 6

And finally....

How far you go in life
Depends on your being
Tender with the young
Compassionate with the aged
Sympathetic with the striving
Tolerant of the weak and the strong

Because someday in life you will have been all of these

-George Washington Carver

Odds And Ends pt 5

A prayer heard from Jack Kornfield

Dear God,
So far today I've done alright. 
I haven't gossiped, lost my temper,
haven't been greedy, nasty, selfish or
over-indulgent.

I'm really glad about that.

But in a few minutes God I'm going to
get out of bed.

And from then on I'm probably going to
need a lot more help.

Thank you.

Odds and Ends pt 4

Traditional Zen Blessing on food

Innumerable labor's brought us this food
we should know how it comes to us

Receiving this offering
we should consider wether our virtue and practice deserve it

Desiring the natural order of mind
we should be free from greed hate and delusion

Odds And Ends pt 3

Let me not pray to be sheltered from dangers
but to be fearless in facing them.

Let me not beg for the stilling of my pain
but for the heart to conquer it.

Let me not look for allies in life's battlefield
but to my own strength.

Let me not crave in anxious fear to be saved
but hope for patience to win my freedom.

- Ancient Buddhist Prayer

Odds and Ends pt 2

As read by Gil Fronsdal

This has to do with a man who was an Abbott of a Zen monastery.
The abbot was a most unusual man, he seemed always to have
a smile in his eyes and a look as if he knew you better than you knew yourself.  He once told this story about himself...

When I was 13 my family would send me up to the mountains around the monastery to collect edible plants to be used for our evening meal.  This foraging trip was the only work that I enjoyed doing otherwise I tried every trick I could to avoid work on my family's farm.  I was still going to school but school had no interest;  for me and my ever present anger was a welcome barrier to learning anything the teacher was teaching.

Occasionally during my foraging trips I would pass by the monastery while the monks were out and about sweeping the leaves from the many paths.  The first time I saw the monks working I was mesmerized in watching them going about their work.

For many months afterwards I would often stop for awhile to watch them sweep.  They went about their work silently and with an efficiency that seemed effortless.  One day a monk walked up to me and asked what I was doing in the mountains.  Immediately I became defensive and scared I resented anyone who tried to get to know me, so instead of answering the question I countered
by asking him what he was doing.  The monk smiled and answered he had been told to sweep and that he was just killing time until he could return to his room for a nap.

As I walked home later in the day I thought about his answer and was glad that he did not seem any different than myself;  when I was required to do anything my heart was never in it and my attitude was that I was passing time until I could be excused taking a nap was certainly preferable.

The next day I passed by the monastery on one of my foraging trips and another monk stopped his sweeping and asked what I was doing.  again I resented the question, it felt like an intrusion, however this time I did not feel as scared, again I deflected the question by asking what he was doing.  He answered that he was doing extra work in hopes of being assigned to the kitchen which was always warm in the winter and always seemed to have one or two extra sweet rice cakes in the cupboard for cooks to nibble on without saying anything I nodded and left to continue my foraging.  The monks answer resonated with me since I too liked to be warm and eating sweet cakes was one of my favorite activities second only to sleeping.

The next time I passed the monastery a third monk asked me the same question.  I was surprised that  I wasn't offensive or resentful of being asked.  However again I deflected the question back to him he explained that he was sweeping as a spiritual discipline to help him overcome his anger.  Later as I walked the mountain trail with my bag of plants I felt a kinship with this monk like me he had
anger but I was perplexed that he would want to overcome it.  For me my anger protected me.  A week later I was again outside the monetary watching the monks sweep.  yet another monk came up to me when he asked me what I was doing I mumbled something about collecting plants I doubt he could hear me my
voice was so faint.  But I did muster up some strength to ask him what he was doing.  he replied that he was beautifying the monastery so that others may be inspired in their work of spiritual transformation before I left him I glanced down the well swept paths and realized that part of the reason I was compelled to
watch the monks sweep was that they seemed to be transforming the paths into something that made me feel peaceful.

The next time I stood outside the monastery watching the monks I was drawn to walk over to a fifth monk and before he could ask me what I was doing I asked him.   He looked at me with kind eyes and after what seemed like a long but quite soft silence he explained that he was sweeping to be of service to all who used the monastery in practicing this way he hoped to find the ultimate peace.  as I left the monastery that day I thought his answer strange because I didn't understand what he meant by service and peace  I certainly couldn't see how these had any value for me. 

The next time I visited the monastery for the last time I had an unfamiliar feeling as I walked up into the mountains.   Just before I reached the monastery I guessed  that i was looking forward to seeing the monks again I felt a warm glow of gladness in anticipation by what I would find.  When I arrived at the monastery I walked right up to the old monk who seemed absorbed by the sweeping.  I inquired what he was doing.   as he answered each of his words washed over me like cleansing water:  me? he said I am not doing anything, my ego was swept away long ago.  There is no I that does anything now the awakened life moves through my body my mind my heart and my mouth no one sweeps there are no paths to sweep and there is no dirt to brush away.  I was stunned by his answer and before I could respond he handed me the broom and walked away. 

I have been here ever since.

Odds and Ends pt 1

I'm cleaning up my hard drive today and found a few interesting things that have been accumulating here is the first one:

I go among trees and sit still
all my stirring becomes quite around me like circles on water
my tasks lie in their places where I left them asleep like cattle

Then what is afraid of me comes and lives awhile in my sight
what it fears in me leaves me and the fear of me leaves it
it sings and I bear it's song

Then what I am afraid of comes I live for a while in it's sight
what I fear in it leaves it and the fear in it leaves me
it sings and I hear it's song

By Wendal Berry

Saturday, July 07, 2007

Web Site vs. Web Application

I went to lunch the other day with one of the VP's where I work.  She had questions about our architecture, specifically why do we have so many licenses for WebSphere Portal; and if there was a relationship between the way we use EJB's.

I suppose that was an opportunity to vent a bit on the fact that our use of EJB's is completely excessive and a horrible idea.  It introduces such a huge level of complexity.

But I didn't.  My biggest concern is the complexity of EJBs and how they are very difficult to support.  However, with the advent of Spring the complexity is significantly reduced.  Troubleshooting can still be very difficult but... it is manageable.

So, I guess with Spring I am learning to at least view EJBs as a valid option in the J2EE architecture (Past experience has proven otherwise).

Another interesting conversation that came out of that lunch was the difference between a website and a web application.  I found a couple of articles supporting our VP's stance.  Funny, I've been working on web applications for close to 10 years and never really thought about the differences...  Maybe that explains why I stink at designing web sites but love architecting and writing applications.

-Aaron

Sunday, July 01, 2007

New stuff has been learned... Old things have become new.

So, all the problem I was working through yesterday have been figured out.  Kind of disappointing in some ways.  Sort of like reading a really good short story.  Great entertainment but so short, hardly worth the effort.

I mentioned, or alluded yesterday that I had been playing around with IDE support trying to get my dtd converted into beans.  One of the places I discovered while pursuing the NetBeans route was the Schema2Beans plug-in.  Although I never got it to work inside of NetBeans I was able to pull out the libraries of the plug-in and invoke them from the command line (and from Eclipse). 

So my big nasty DTD did have some "issues" you could say, that didn't really help anything but with a little help from an XML validator and some creative hacking I got it all working.  It works quite beautifully actually.  The XML generation isn't quite as cool as my decorator but it will work.

The funny thing is as I was writing the test case I recognized the code I had written was almost identical to the way IBM's generated beans work.  So there is a [small] chance in H3ll that the old applications can migrate to this version when IBM finally deprecates their dtd converter.

Not the weekend I should have had but it was a fun little problem that didn't turn out to be that difficult thanks to those fine fellows over at NetBeans.

-Aaron

Saturday, June 30, 2007

New Project == New things to learn

So, I just finished the design for a service (I'll try to keep the names out of this to protect the guilty).  Basically this service plays the middle man between an EJB layer (A) and another EJB layer (B).  We do love our EJB's where I work...

Anyway, EJB Layer B receives XML requests and does magic on them and sends back an answer (or a failure) as XML.  We have the magic DTD and a Schema to help us figure out how to create the right question and how to parse the answer correctly.

As you no doubt know right XML is trivial.  I got a little creative this time and used a decorator pattern to generate the XML, so that was kind of fun... 

Parsing out the XML has been incredibly simple I'm using the Digester library from the jakarta-commons project by apache and the parsing and object instantiation has been a breeze. 

The only problem is that I don't want to have to hand write all of the objects that get populated via the digester.  I initially tried to go the IDE route, I was researching some plugins and found this article it looked pretty promising except I don't have a version of eclipse 3.1 lying around and I can't bring myself to download it.

I have found 3 solutions so far:

  • IBM's XSD-Beans given a DTD or XSD it will auto generate POJO's for you.  But then you are tied to IBM's runtime.   We do run on IBM's WebSphere app server so that's not horrible, but it is kind of yucky.
  • XML Spy from Altova.  This was the easiest by far.  The Enterprise Edition costs $990.00 though, and once the process is done you get your java beans tied to Altova's runtime.   Not so good.
  • Lastly I have tried PlainXML from softAMIS which is a library written on top of JAXB (B for binding).  It eventually worked I did have to do a bit of troubleshooting, no doubt due to my nasty DTD but I did eventually get my java files built.  But they were tied to the PlainXML runtime...

I guess my next steps are to look at JAXB without any wrappers and actually try to figure out what the heck is going on...  All I really want is a set of very simple POJO's that I can initialize out of the digester process, not tied to a specific XML library just simple getters and setters...

<sigh>

Wish me luck.

-Aaron

Saturday, June 23, 2007

First try.

This is the swingset in my backyard.

Begin Again

All I can think of is bad 80's songs to reference... "here I go again....", "round and round".    Like I said all bad references. 

I have been playing with blogging tools on and off now for quite awhile.  I have one blog that is not setup anymore using Roller another using wordpress at FlyingSpheres.org.  Although wordpress is a decent tool - the whole self-management of a blogging web site is enjoyable in some aspects; in other ways it is a huge pain.  Since Google has consumed blogspot I thought I would give it a try again, I had actually forgotten I had this account.

This is being written using the Windows Live Writer that Microsoft has in beta right now.  The previous process I used was to write the posts using Microsoft Word for spell check, pasting it into Edit Plus to get rid of the special characters and then copying and pasting once again.  Very laborious... Hopefully this will be better. 

If it is less painful hopefully there will be regular postings...  We shall see.

-Aaron