Showing posts with label Java. Show all posts
Showing posts with label Java. Show all posts

Tuesday, July 15, 2014

New ways to do old things

Web Services are a way of life for mobile developers.  I can't really think of a single mobile app I've written that didn't have a backend of some type, even if it's just Google Analytics.

A very common pattern for web services are to setup a basic set of REST based services.  These let the phone update info on the backend very easily.  One of the fastest and easiest Web Servers to use is Google's AppEngine unfortunately rest frameworks are oddly heavy - meaning that the frameworks use lots of jars and extra libraries to do something that seems like it should be simple - and the heavier the framework the more effort is to get it working.

Here is an example of a restful url to list all the frogs on a backend:
http://welikefrogs.com/listAllFrogs
Another way to create that same functionality would be to create a basic url like this:
http://welikefrogs.com/listServlet?frogs=all

The backend code for both  techniques would be very similar.

Jersey is a framework I've used a lot.  It's a great framework for REST and there are lots of benefits to using a REST framework other than URL pattern matching.  The problem is that Google's AppEngine doesn't seem to like Jersey very much.  Oh sure, you can get it working (eventually).  Some people would probably say it's even easy - but it's actually a huge pain in the butt to configure and run the latest version of Jersey on the latest version of AppEngine.

So that brings us to our blog title is there a new way to do the same thing I've been doing for several years now?  Hopefully one that is less painful than trying to get the Jersey framework to function?

Well good news! Apparently Google has a new framework or API called "Cloud EndPoints".  I started playing with them today and so far it's a little frustrating - so I though I'd share some of it with you.  :)

First of all after reading up on the documentation it sounds pretty cool, it looks to lean pretty heavily on Eclipse and the Google Web plugin which is cool - we all love eclipse right?

As you go through the tutorial you see several mentions to the plugin - and then you get to the part where you build a demo application entirely from maven.  That's cool, we like Maven too right? So the tutorial page tells you to issue this maven command:
  1. mvn archetype:generate -Dappengine-version=1.9.6 -Dfilter=com.google.appengine.archetypes:
and that works just fine also.  Well, at least until you import the new project into eclipse so you can code the app.  After you import the project into eclipse you can expect to get several errors about your pom.xml file and your persistence.xml file.

Really?!  What the hell?  This is so unlike Google - things typically just magically work with their frameworks and libraries.

There are about 6 errors in the POM file that all have to do with "Plugin execution not covered by lifecycle configuration" this turns out to be an eclipse or more specifically an M2E plugin (maven 2 eclipse) error.  It has a pretty easy fix here is the documentation on why this error occurs, here is the snippet you need to add to your pom.xml file (it goes inside the tag):

<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
  <lifecycleMappingMetadata>
    <pluginExecutions>
      <pluginExecution>
        <pluginExecutionFilter>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>versions-maven-plugin</artifactId>
          <versionRange>[2.1,)</versionRange>
          <goals>
                            <goal>display-dependency-updates</goal>
                            <goal>display-plugin-updates</goal>
          </goals>
        </pluginExecutionFilter>
        <action>
          <ignore />
        </action>
      </pluginExecution>
      <pluginExecution>
        <pluginExecutionFilter>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
          <versionRange>[2.5,)</versionRange>
          <goals>
                            <goal>resources</goal>
                            <goal>testResources</goal>
          </goals>
        </pluginExecutionFilter>
        <action>
          <ignore />
        </action>
      </pluginExecution> 
    </pluginExecutions>
  </lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>

</pluginManagement>

Keep in mind this fix is just so that eclipse won't complain about your pom file.  It does not affect your build if you're using Jenkins or building on the command line it is ignored, also to be clear the errors only occur in Eclipse - so it's not really a Google error. 

OK, so now our build is working.  now we have to figure out what's going on with the persistence.xml file - when you look at that file all that is in there is one line:

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

Well, that is clearly a problem no xml validator would be happy with that, so add just enough xml to make it happy:


xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" 
    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_2_0.xsd">
<persistence-unit name="dataStore">
   
</persistence-unit>

</persistence>

Keep in mind this is only valid for the XML validation.  Once we get ready to use the data store we will need to fix it the right way.

I'll keep you posted on how the endpoints work out.  It's a tad irritating so far but learning a new way to do something is often frustrating.

Cheers!

-Aaron

Tuesday, April 29, 2008

So, I have a bit of a confession here. I have recently purchased a new Mac Book Pro. It’s about 2 weeks old now and I can’t say the transition has been painless... It’s hard to migrate from working in a almost exclusive windows environment for the last 12 years (My first computer was a mac OS 7). I have to think a lot about how things work now keyboard shortcuts are different... Applications are different I sorely miss my editplus, I love that application. It is one of the few that I actually registered - and highly recommend it to anyone who does any type of file manipulation or scripting...

Anyway, I’ve been working on a super secret project that will eventually evolve into developing an application for the iPhone and to do that type of development then you have to have an Intel PC mac. It is kind of crappy - but I was in the market for a new PC anyway my previous laptop was over 4 years old (still running very well but showing a bit of age). I will say that GlassFish has never run better, and it is truly amazing how much development software it comes with out of the box. I’ve started playing with Objective-C and Cocoa just a bit and they are very cool I can totally understand why a developer would want to use the Cocoa Framework and XCode.

Anyway, I just wanted to get that off of my chest... I’m not a zealot yet - it is just a tool after all but it definitely a powerful system - and a 17“ wide screen is a beautiful thing indeed.



-Aaron

Friday, February 29, 2008

Single Sign on with glassfish

Holy cow check out this little nugget taken from the GlassFish manual:

 

User Authentication for Single Sign-on

The single sign-on feature of the Application Server allows multiple web applications deployed to the same virtual server to share the user authentication state. With single sign-on enabled, users who log in to one web application become implicitly logged into other web applications on the same virtual server that require the same authentication information. Otherwise, users would have to log in separately to each web application whose protected resources they tried to access.

An example application using the single sign-on scenario could be a consolidated airline booking service that searches all airlines and provides links to different airline web sites. Once the user signs on to the consolidated booking service, the user information can be used by each individual airline site without requiring another sign-on.

Single sign-on operates according to the following rules:

  • Single sign-on applies to web applications configured for the same realm and virtual server. The realm is defined by the realm-name element in the web.xml file. For information about virtual servers, see the Sun Java System Application Server Platform Edition 9.0 Administration Guide.
  • As long as users access only unprotected resources in any of the web applications on a virtual server, they are not challenged to authenticate themselves.
  • As soon as a user accesses a protected resource in any web application associated with a virtual server, the user is challenged to authenticate himself or herself, using the login method defined for the web application currently being accessed.
  • Once authenticated, the roles associated with this user are used for access control decisions across all associated web applications, without challenging the user to authenticate to each application individually.
  • When the user logs out of one web application (for example, by invalidating the corresponding session), the user's sessions in all web applications are invalidated. Any subsequent attempt to access a protected resource in any application requires the user to authenticate again.

The single sign-on feature utilizes HTTP cookies to transmit a token that associates each request with the saved user identity, so it can only be used in client environments that support cookies.

To configure single sign-on, set the following properties in the virtual-server element of the domain.xml file:

  • sso-enabled - If false, single sign-on is disabled for this virtual server, and users must authenticate separately to every application on the virtual server. The default is true.
  • sso-max-inactive-seconds - Specifies the time after which a user's single sign-on record becomes eligible for purging if no client activity is received. Since single sign-on applies across several applications on the same virtual server, access to any of the applications keeps the single sign-on record active. The default value is 5 minutes (300 seconds). Higher values provide longer single sign-on persistence for the users at the expense of more memory use on the server.
  • sso-reap-interval-seconds - Specifies the interval between purges of expired single sign-on records. The default value is 60.

Here is an example configuration with all default values:

     
...
<property name="sso-enabled" value="true"/>
<property name="sso-max-inactive-seconds" value="450"/>
<property name="sso-reap-interval-seconds" value="80"/>
</virtual-server>

How sweet is that?


 


-Aaron

Thursday, February 28, 2008

MD5 Encryption Java style

Here is a little nugget you might enjoy how to do some MD5 Encryption with Java pretty easy really.  Mostly taken from this book:

javaSecurityHandbook

 

package test.md5.encrypt;

import java.io.ByteArrayInputStream;
import java.security.DigestInputStream;
import java.security.MessageDigest;

import junit.framework.TestCase;

public class TestMessageDigest extends TestCase {
private static String[] hexDigits = {"0", "1", "2", "3",
"4", "5", "6", "7",
"8", "9", "a", "b",
"c", "d", "e", "f"};
public void testEncrypt(){
MessageDigest md = null;
DigestInputStream dis = null;
String digestedString = null;
try{
md = MessageDigest.getInstance("MD5");
ByteArrayInputStream bis =
new ByteArrayInputStream("password".getBytes());
dis = new DigestInputStream(bis, md);

byte[] bytes = new byte[1024];
dis.read(bytes);
md = dis.getMessageDigest();
dis.close();
byte[] digest= md.digest();

digestedString =byteArrayToString(digest);
System.out.println(digestedString);
} catch (Exception e){
e.printStackTrace();
assertTrue(false);
}
}
private String byteToHexString(byte aByte){
int n = aByte;
if (n < 0) n = 256 + n;
int d1 = n/16;
int d2 = n%16;
return hexDigits[d1] + hexDigits[d2];
}
private String byteArrayToString(byte[] bytes){
String result = "";
for (int a = 0; a < bytes.length; a++){
result += byteToHexString(bytes[a]);
}
return result;
}
}


Not too bad is it?  Thanks to Jamie Jaworski and Paule Perrone for authoring that book (heh, I actually got in on clearance for $15.00) not too shabby...


 


-Aaron

Saturday, February 23, 2008

a wasted week

So, I did say I hated ldap right?  After fighting and fighting with I finally gave in and tried the JDBCRealm with Glassfish's security configuration.

So much nicer.  There is a brilliant post here that explains how to do it.  The only comment I would have is that you can sent the encryption to none instead of MD5 or something else. 

So, yeah I pretty much wasted a week trying to do things the "right" way.  I'm totally digging the JDBC Realm though.  It works just the way you think it should.

 

Cheers!

-Aaron

Thursday, February 21, 2008

Container Managed LDAP

<sigh> will these ldap posts ever end?

So now that I have authentication working, I want to be able to register users now.  So how can I save users easily to my ldap server?  Well I figured there had to be an easy way to get a container managed instance of the server, low and behold I found this post on making a container managed LDAP from a Java Evangelist.

Once you follow all of those instructions, what is the best way to get access to it?  With Spring of course!

It's as simple as injecting this into your bean

<bean id="ldapServer" 
class="org.springframework.jndi.JndiObjectFactoryBean"
lazy-init="default">
<property name="jndiName">
<value>ldap/directory</value>
</property>
<property name="resourceRef">
<value>false</value>
</property>
</bean>


Couldn't be easier. 

Putting it all together

So, now that I have my ldap server working (more or less).  I need to use it to authenticate with, this turned out to be surprisingly easy with GlassFish.  I created a new LDAP Realm like this:

ldapConfig

The "assign group" property was  a bit confusing - basically it is just a value that you map you application to in the web.xml and the sun-web.xml this is an exampl of how it could be done using the webusers as the value of the "assign group" property.

web.xml:

  <security-constraint>
<web-resource-collection>
<web-resource-name>Faces Servlet</web-resource-name>
<url-pattern>/pages/*</url-pattern>
<http-method>GET</http-method>
<http-method>POST</http-method>
</web-resource-collection>
<auth-constraint>
<role-name>AUTHENTICATED</role-name>
</auth-constraint>
</security-constraint>
<login-config>
<auth-method>FORM</auth-method>
<realm-name>LdapRealm</realm-name>
<form-login-config>
<form-login-page>/login.jsp</form-login-page>
<form-error-page>/unprotected/loginError.jsf</form-error-page>
</form-login-config>
</login-config>


sun-web.xml:


	<security-role-mapping>
<role-name>AUTHENTICATED</role-name>
<group-name>webusers</group-name>
</security-role-mapping>


The last bit of magic is the login form:


<form action="j_security_check" method="post">
<table border="0" cellspacing="0" cellpadding="0">
<tr>
<td>
<p>User ID<br/>
<input type="text" name="j_username" value="" size="10"/>
</p>
</td>
</tr>
<tr><td>
<p>Password<br/>
<input type="text" name="j_password" value="" size="10"/>
</p>
</td>
</tr>
<tr>
<td style="padding-bottom: 10px;">
<p>
<input type="submit" value="Log In"/>
</p>
</td>
</tr>
</table>
</form>


And that is how you can authenticate.  Now if you remember I'm using JSF to manage this and that is clearly not a jsf form.  So this is how I decided to make it work (and there are other options) it is not without problems mind you, JSF makes a lot of things better but in so doing messes up a lot of old conventions.


I have decided to work on the assumption that users are going to navigate to my web site by saying http://www.my great web site.com  I have the welcome page in a "protected" area so that by navigating to the welcome page you will get kicked out the the registration screen if you are successful then you get sent to the welcome page which does a jsp:forward to the welcome page through a faces context.  It is overly complicated I think but we have to make sure that the faces context is initialized correctly.

Thursday, February 14, 2008

OpenLDAP

So I'm not a big fan of LDAP of any kind.  It could entirely be out of ignorance I will admit to that.  It seems very out dated when the info you store can be done SOOOO much easier in a database.

 

Having said that it seems all "real" applications have an LDAP server back end.  So, tonight I have decided that this is the night when flyingspheres has a working LDAP server.  Not that I really need one mind you it is really just me for the most part, but to really play with security modules in Java you need to have the container working together with an ldap server.

So here we go...

I will be referencing lots of sites to get this work done.  Mostly cause me not so smart when it come to LDAP...

OpenLDAP comes down from the friendly synaptic manager.  Once you get that installed (very easily mind you) you get a new config directory at /etc/ldap which looks like this:

 

-rw-r--r-- 1 root root  333 2007-04-27 10:19 ldap.conf
drwxr-xr-x 2 root root 4096 2007-12-03 14:05 sasl2
drwxr-xr-x 2 root root 4096 2008-02-08 18:38 schema
-rw------- 1 root root 4340 2008-02-14 21:56 slapd.conf

 


Now, when I installed OpenLDAP I think my server wasn't named very well so if you were to try and connect to me (and I opened a hole in my firewall) you would see the DN of nodomain.  Heh, is that cool or what?


So first order of business how do I change that?


Sprinkled liberally throughout our slapd.conf file is a reference to nodomain.  This is no doubt a problem.  Before we go mucking around it let's back up that file first... 


... ok backup complete.


Now let's go through and change the cn="nodomain" to cn="flyingspheres",cn="com"  (make sure you get them all).


Ok, that's done.


YoLinux points out that the database our ldap server is under the directory attribute.  By default uBuntu put mine here: "/var/lib/ldap".  Common sense says that's where the nodomain database lives so I'm going to move it somewhere else.  if you look in that /var/lib/ldap directory there is a lot of stuff there.  I wonder what it all is... oh well.... so made my new directory and pointed slapd.conf to it.  I'm hoping that when I restart slapd (openLdap) all that stuff will be created in my new directory.  Once the directory is created and slapd points to the correct location it's time for a restart.  (upon restart there was no love.... my directory was empty... maybe that's ok).


So after about 20 minutes of poking around looking through the OpenLdap link things started working.... I can connect there are db files in the directory defined for the db.  I initially created an ldif file with only the admin user and that worked pretty well, although connecting went through anonymous bind only.


 


So, many minutes later (maybe an hour or so).  There is a mildly intuitive relationship between the object classes and attributes to what you are wanting to store in your LDAP.  I'm sure if someone reading this knows what they're doing they're laughing now.  You need to pull in the objectClasses that you want into your LDIF file and then add the attributes you care about (and the ones that are required, hopefully they're the same).



I ran the ldapadd probably 50 times trying to figure out the right combination.


 


Like I said I'm not a real big fan of LDAP...


 


-Aaron

Tuesday, February 12, 2008

Begin Again

So, I'm starting a new project. 

It never ceases to amaze me how difficult java web applications are to setup.  A lot of it is because of all the different frameworks we get to choose from.  This project appears to be going to use Ice Faces (a JSF implementation/extension), Facelets some level of Spring Integration, possibly JPA or Hibernate.

I played around with RichFaces and facelets a few months ago and was able to lean on the JBoss IDE for some of the configuration, but since I'm using Ice Faces this time I don't want all of the extra stuff that comes with the JBoss IDE.

So we get to start from scratch.  The documentation is pretty decent on what needs to be added to the web.xml and faces-config.xml to get facelets working correctly.  But after that where do you start?  I guess the best place is always the beginning so let's code up the index.html page (always a good place to start).

As you know for faces to work you need to be working w/in a faces context so this is a really good places to initialize the faces context let's make a silly little index.jsp page that simply forwards us inside the context:

 

		
<%@ taglib uri="http://java.sun.com/jsf/html" prefix="h" %>
<%@ taglib uri="http://java.sun.com/jsf/core" prefix="f" %>
<html>
<head>
<title>My Title</title>
</head>
<body>
<jsp:forward page="pages/login.jsf" />
</body>
</html>

 


So, that's easy enough.  But, with Facelets we don't want to really be writing jsf or jsp pages.  Clearly we are forwarding to a jsf page though what gives?  We create a url-pattern mapped to a Faces Servlet so any request to our url pattern (*.jsf) get's routed through the faces context.  One last thing we need to make sure our faces.DefaultSuffix is linked to *.xhtml pages.  So our pages/login.jsf page will land on the pages/login.xhtml page.   Remember with JSF it is all about the faces context stay in the context and you will be ok. This is why (IMHO) if you're doing AJAX you really need to use a framework like RichFaces or IceFaces.  You're just asking for death by a million cuts to go any other route.


So I got all my xhtml files created the web.xml and faces-config.xml are all tweaked out and guess what the dang thing didn't work.  I kept getting this error:


 

[#|2008-02-12T23:32:08.192-0600|WARNING|sun-appserver9.1|javax.enterprise.system.stream.err|_ThreadID=12;_ThreadName=httpWorkerThread-4848-0;_RequestID=837d6942-3e34-4c0f-b9de-40c1419d7e40;|
java.lang.UnsupportedOperationException
at com.sun.faces.config.ConfigureListener$InitFacesContext.getViewRoot(ConfigureListener.java:1690)
at com.sun.faces.util.MessageFactory.getMessage(MessageFactory.java:113)
at com.sun.faces.util.MessageUtils.getExceptionMessageString(MessageUtils.java:277)
at com.sun.faces.util.Util.createInstance(Util.java:477)
at com.sun.faces.config.ConfigureListener.configure(ConfigureListener.java:671)
at com.sun.faces.config.ConfigureListener.configure(ConfigureListener.java:503)
at com.sun.faces.config.ConfigureListener.contextInitialized(ConfigureListener.java:402)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4493)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:5150)
at com.sun.enterprise.web.WebModule.start(WebModule.java:308)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:960)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:944)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:671)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1575)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1216)
at com.sun.enterprise.server.WebModuleDeployEventListener.moduleDeployed(WebModuleDeployEventListener.java:169)
at com.sun.enterprise.server.WebModuleDeployEventListener.moduleDeployed(WebModuleDeployEventListener.java:265)
at com.sun.enterprise.admin.event.AdminEventMulticaster.invokeModuleDeployEventListener(AdminEventMulticaster.java:951)
at com.sun.enterprise.admin.event.AdminEventMulticaster.handleModuleDeployEvent(AdminEventMulticaster.java:938)
at com.sun.enterprise.admin.event.AdminEventMulticaster.processEvent(AdminEventMulticaster.java:448)
at com.sun.enterprise.admin.event.AdminEventMulticaster.multicastEvent(AdminEventMulticaster.java:160)

This seems to be a pretty nasty error, all it is really saying is "Hey I somebody is referencing a class I don't know anything about".  This is probably java's biggest criticism happening right here on my laptop.  I think there are a total of 16 jars I needed to get my very simple page to work here.  Don't get me wrong I'm most thankful to the people who wrote them.  But man it is sure a pain to be trying to figure out what you need and what you don't.


I actually opted for the shotgun approach.  I ended up taking a demo app that comes with Ice Faces and pull out all of the jars from the demo and add them to my project.  Not very accurate but it did fix the problem.


That's enough for tonight.  I'll let you know how it goes.


By the way I got the ice faces demo apps running here:



 


-Aaron

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...

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

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...

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

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