Just another (occasional) brain dump on technology and the technology industry...

About Me

My photo
I enjoy wine, laptops, walks, bicycling with the kids and long drives. I am constanly reading. In my heart I am a teacher a salesman and a technologist.

Saturday, August 30, 2008

Introducing the Rolodex

What is a Rolodex?

According to Wikipedia, a "RolodexTM (Rolling Index) is a rotating file device used to store business contact information currently manufactured by Newell Rubbermaid. The Rolodex holds specially shaped index cards; the user writes the contact information for one person or company on each card. Many users avoid the effort of writing by taping the contact's business card directly to the Rolodex index card. Some companies have produced business cards in the shape of Rolodex cards, as a marketing idea.

The Rolodex was invented by Arnold Neustadter in 1958...."

Why is a Rolodex interesting?

A Rolodex makes for a great example of a physical device that can be implemented as software. When one looks at it closely one can easily identify object-oriented principles.



  • Abstraction - a person is a contact.

  • Association (or composition or aggregation) - a person works for an organization, a person has given names and so on.

  • Polymorphism - a contact's string representation will look different depending on whether the contact is a person or an organization.

What goes into a Rolodex?


A Rolodex stores contact information. A contact can have a couple of telephone numbers, email addresses and addresses. A contact may be a person or an organization. A person has given names, a family name, a gender and a birth date. An organization has a name. A person may be associated with an organization. An organization may have many employees.


What can one do with a Rolodex?


You can add, remove, find and edit contacts. You can also add, remove, edit and find telephone numbers, email addresses and addresses for contacts. You my want to update a person or an organization's information from time to time.


Why did I describe the Rolodex?


Because I want to show how to implement a software solution that can take the place of a Rolodex. Over the next couple of weeks I want to show how you will go about implementing the Rolodex mainly using Java technology. I will cover the following topics:



  • Rolodex's interfaces.

  • Persisting Rolodex entities in an XML file using JSE technologies.

  • Persisting Rolodex entities in a relational database via JPA using JSE technologies.

  • Accessing Rolodex functionality as JEE components.

  • Exposing the Rolodex as a Web Service.

  • Exposing the Rolodex via JSF.

  • Exposing the Rolodex via SEAM and,

  • using .NET and web services technologies to expose the Rolodex as a .NET client.

Monday, March 03, 2008

Sun MySQL. Wow!

Half way through January I heard the news that Sun was buying MySQL. I thought is was great news then. I think it is even better news now!

I do a lot of work in the JEE space. Big Blue is pervasive. I have to put up with their technology. It is trash mostly, but sometimes they have a real gem or two in their product stack, like DB2 and MQ. AIX is ok, like it is ok to have any old car instead of walking everywhere. WebSphere is a nasty piece of work.

I really like BEA's product stack. I think that it is excellent in almost all cases. Oracle is the worlds most deployed database and for what reason I do not know. I wonder how that is going to pan out?

I started playing with the Sun Application server 9.0 a while back. I immediately loved it. I still do. In my opinion it is the best AS out there. 9.1 is even better! I also have high regard for MySQL. It looks as if Jonathan Schwartz is doing great things with Sun, I have a good feeling that he will do awesome things with MySQL.

Happy coding...

Friday, February 15, 2008

SOAP With Attachments in Java CAPS, Client

In a previous article I showed how to use SAAJ in Java CAPS to consume SwA messages. This article adds the client side code to generate an appropriate SOAP message and to invoke the "Web Service" in CAPS.

The code is as follows:






01 package tech.axl.s11wa.saaj13.client;
02 
03 
04 import java.io.FileInputStream;
05 import java.io.IOException;
06 import java.net.MalformedURLException;
07 import java.net.URL;
08 import java.util.logging.Level;
09 import java.util.logging.Logger;
10 import javax.xml.soap.AttachmentPart;
11 import javax.xml.soap.MessageFactory;
12 import javax.xml.soap.SOAPConnection;
13 import javax.xml.soap.SOAPConnectionFactory;
14 import javax.xml.soap.SOAPConstants;
15 import javax.xml.soap.SOAPException;
16 import javax.xml.soap.SOAPFactory;
17 import javax.xml.soap.SOAPMessage;
18 
19 
20 public class _Client {
21 
22     public static void main(String[] args) {
23         _Client c_ = new _Client();
24         int helloIndex_ = 1;
25         int worldIndex_ = 1;
26         if (args.length >= 2) {
27             helloIndex_ = Integer.parseInt(args[0]);
28             worldIndex_ = Integer.parseInt(args[1]);
29         }
30         c_.callSOAP11WithAttachmentsEndpoint(helloIndex_, worldIndex_);
31     }
32 
33     private void callSOAP11WithAttachmentsEndpoint(final int helloIndex, final int worldIndex) {
34         try {
35             MessageFactory mf_ = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
36             SOAPMessage message_ = mf_.createMessage(); 
37 
38             //
39             AttachmentPart attachment0_ = message_.createAttachmentPart();
40             attachment0_.setRawContent(new FileInputStream("Hello.txt"), "text/plain");
41             attachment0_.setContentId("hello_in_multiple_languages");
42             message_.addAttachmentPart(attachment0_);
43             AttachmentPart attachment1_ = message_.createAttachmentPart();
44             attachment1_.setRawContent(new FileInputStream("World.txt"), "text/plain");
45             attachment1_.setContentId("world_in_multiple_languages");
46             message_.addAttachmentPart(attachment1_);
47 
48             //
49             SOAPFactory factory_ = SOAPFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
50             message_.getSOAPBody().addBodyElement(factory_.createName(
51                     "helloIndex", "dhpoc", "http://www.discovery.co.za/poc")).setValue(String.valueOf(helloIndex));
52             message_.getSOAPBody().addBodyElement(factory_.createName(
53                     "worldIndex", "dhpoc", "http://www.discovery.co.za/poc")).setValue(String.valueOf(worldIndex));
54 
55             //
56             message_.saveChanges();
57 
58             SOAPConnectionFactory scf_ = SOAPConnectionFactory.newInstance();
59             SOAPConnection c_ = scf_.createConnection();
60             SOAPMessage response_ = c_.call(message_, new URL(
61                     "http://localhost:28280/dpSwAWithSAAJ13_servlet_SwAWithSAAJ13/SwAWithSAAJ13"));
62             if (null != response_) {
63                 response_.writeTo(System.out);
64             } else {
65                 Logger.getLogger(_Client.class.getName()).log(Level.WARNING, "Could not retrieve SOAP response");
66             }
67         } catch (SOAPException ex) {
68             Logger.getLogger(_Client.class.getName()).log(Level.SEVERE, null, ex);
69         } catch (MalformedURLException ex) {
70             Logger.getLogger(_Client.class.getName()).log(Level.SEVERE, null, ex);
71         } catch (IOException ex) {
72             Logger.getLogger(_Client.class.getName()).log(Level.SEVERE, null, ex);
73         }
74     }
75 
76 }




I used tcpmon to redirect the call to the appropriate destination to see the payload on the wire.

Have fun!

Thursday, February 07, 2008

SOAP With Attachments in Java CAPS

I was part of a team that did a Proof of Concept (PoC) to demonstrate the capabilities of Java CAPS at a prospective customer recently. One of the requirements of the PoC was to handle SOAP (1.1) with Attachments (SwA) from within Java CAPS. I searched high and low for an example. I was fortunate enough to find none...

I figured that the SOAP with Attachments API for Java (SAAJ) would be a good place to start. I looked through the API documentation and found that I will need a byte array and the SOAP message's MIME headers to create a SOAP message using SAAJ. All I needed to do was to expose the HTTPServer's processRequest as a JCD.

Here is the implementation:







001 package SOAP_1_u002E_1SOAP_With_Attachments_SAAJ_452723634;
002 
003 
004 import java.io.BufferedInputStream;
005 import java.io.ByteArrayInputStream;
006 import java.io.ByteArrayOutputStream;
007 import java.io.IOException;
008 import java.io.LineNumberReader;
009 import java.io.StringReader;
010 import java.util.Iterator;
011 
012 import javax.xml.soap.AttachmentPart;
013 import javax.xml.soap.MessageFactory;
014 import javax.xml.soap.MimeHeaders;
015 import javax.xml.soap.Name;
016 import javax.xml.soap.SOAPElement;
017 import javax.xml.soap.SOAPException;
018 import javax.xml.soap.SOAPFactory;
019 import javax.xml.soap.SOAPMessage;
020 
021 import org.w3c.dom.Node;
022 
023 import com.stc.codegen.alerter.Alerter;
024 import com.stc.codegen.logger.Logger;
025 import com.stc.codegen.util.CollaborationContext;
026 import com.stc.codegen.util.TypeConverter;
027 import com.stc.connector.otd.httpserveradapter.webservice.WebHeaderList;
028 import com.stc.connector.otd.httpserveradapter.webservice.WebServerApplication;
029 
030 
031 public class jcdSwAWithSAAJ13 {
032     public Logger logger;
033 
034     public Alerter alerter;
035 
036     public CollaborationContext collabContext;
037 
038     public TypeConverter typeConverter;
039 
040     public void processRequest(final WebServerApplication input)
041             throws Throwable {
042         MessageFactory mf_ = MessageFactory.newInstance();
043         SOAPMessage message_ = unmarshalSOAPMessage(input, mf_);
044         int helloIndexValue_ = 0;
045         int worldIndexValue_ = 0;
046         if (null != message_) {
047             helloIndexValue_ = extractIndex("helloIndex", message_);
048             worldIndexValue_ = extractIndex("worldIndex", message_);
049         }
050 
051         String greeting_ = buildGreeting(
052             helloIndexValue_, worldIndexValue_, message_);
053         SOAPMessage response_ = generateResponse(mf_, greeting_);
054         if (null != response_) {
055             sendResponse(response_, input);
056         }
057     }
058 
059     private SOAPMessage unmarshalSOAPMessage(
060             final WebServerApplication input, final MessageFactory factory) {
061         SOAPMessage result_ = null;
062         try {
063             BufferedInputStream bis_ = new BufferedInputStream(
064                 new ByteArrayInputStream(input.getRequest().getByteArray()));
065             MimeHeaders headers_ = extractHeaders(
066                 input.getRequest().getHeaderInfo());
067             result_ = factory.createMessage(headers_, bis_);
068         } catch (Exception e_) {
069             error(e_.getMessage(), e_.getCause());
070         }
071 
072         return result_;
073     }
074 
075     private int extractIndex(
076             final String indexName, final SOAPMessage message) {
077         int result_ = Integer.MIN_VALUE;
078         SOAPElement element_ = extractElement(indexName, message);
079         if (null != element_) {
080             result_ = typeConverter.stringToInt(
081                 element_.getValue(), "#", false, 0);
082         } else {
083             result_ = 1;
084         }
085 
086         return result_;
087     }
088 
089     private String buildGreeting(
090             final int helloIndex, final int worldIndex,
091             final SOAPMessage message) {
092         String result_ = "";
093 
094         Iterator attachments_ = message.getAttachments();
095         int numberOfAttachments_ = 0;
096         String hello_ = "";
097         String world_ = "";
098         while (attachments_.hasNext()) {
099             numberOfAttachments_++;
100             AttachmentPart attachment_ = (AttachmentPart) attachments_.next();
101             if (attachment_.getContentId().equalsIgnoreCase(
102                     "hello_in_multiple_languages")) {
103                 hello_ = extractWord(attachment_, helloIndex);
104             } else if (attachment_.getContentId().equalsIgnoreCase(
105                     "world_in_multiple_languages")) {
106                 world_ = extractWord(attachment_, worldIndex);
107             }
108         }
109 
110         result_ = hello_ + " " + world_ + "!";
111 
112         return result_;
113     }
114 
115     /** Dito */
116     private MimeHeaders extractHeaders(final WebHeaderList headers) {
117         MimeHeaders result_ = new MimeHeaders();
118         int numberOfHeaders_ = headers.countWebHeaderList();
119         for (
120                 int headerIndex_ = 0;
121                 headerIndex_ < numberOfHeaders_;
122                 headerIndex_++) {
123             String headerName_ = headers.getWebHeaderList(
124                 headerIndex_).getName();
125             String[] headerValues_ = headers.getWebHeaderList(
126                 headerIndex_).getValues();
127             for (
128                     int headerValueIndex_ = 0;
129                     headerValueIndex_ < headerValues_.length;
130                     headerValueIndex_++) {
131                 result_.addHeader(
132                     headerName_, headerValues_[headerValueIndex_]);
133             }
134         }
135 
136         return result_;
137     }
138 
139     private SOAPElement extractElement(final String localName,
140             final SOAPMessage message) {
141         SOAPElement element_ = null;
142 
143         try {
144             Iterator elements_ = message.getSOAPBody().getChildElements();
145             while (elements_.hasNext()) {
146                 Node n_ = (Node) elements_.next();
147                 if (n_.getLocalName().equalsIgnoreCase(localName)) {
148                     element_ = (SOAPElement) n_;
149                     break;
150                 }
151             }
152         } catch (Exception e_) {
153             error(e_.getMessage(), e_.getCause());
154         }
155 
156         return element_;
157     }
158 
159     private String extractWord(final AttachmentPart attachment,
160             final int index) {
161         String result_ = "Yebo";
162 
163         try {
164             LineNumberReader reader_ = new LineNumberReader(
165                 new StringReader((String) attachment.getContent()));
166             int escapeHatch_ = 0;
167             while (reader_.getLineNumber() < index) {
168                 result_ = reader_.readLine();
169                 if (escapeHatch_++ > index) {
170                     break;
171                 }
172             }
173         } catch (Exception e_) {
174             error(e_.getMessage(), e_.getCause());
175         }
176 
177         return result_;
178     }
179 
180     private SOAPMessage generateResponse(final MessageFactory factory,
181             final String greeting) {
182         SOAPMessage response_ = null;
183 
184         try {
185             response_ = factory.createMessage();
186             SOAPFactory factory_ = SOAPFactory.newInstance();
187             Name helloWorldName_ = factory_.createName(
188                 "helloWorld", "dhpoc", "http://www.discovery.co.za/poc");
189             response_.getSOAPBody().addBodyElement(helloWorldName_).setValue(
190                 greeting);
191         } catch (SOAPException e_) {
192             error(e_.getMessage(), e_.getCause());
193         }
194 
195         return response_;
196     }
197 
198     private void sendResponse(final SOAPMessage response,
199             final WebServerApplication input) {
200         try {
201             byte[] responseAsBytes_ = convertResponseToBytes(response);
202             if (responseAsBytes_.length > 0) {
203                 input.getResponse().setByteArray(responseAsBytes_);
204                 input.getResponse().setContentType("text/xml");
205                 input.getResponse().setContentLength(
206                     input.getResponse().getByteArray().length);
207                 input.sendResponse();
208             }
209         } catch (Exception e_) {
210             error(e_.getMessage(), e_.getCause());
211         }
212     }
213 
214     private byte[] convertResponseToBytes(final SOAPMessage message) {
215         ByteArrayOutputStream baos_ = new ByteArrayOutputStream();
216         try {
217             message.writeTo(baos_);
218         } catch (SOAPException e_) {
219             error(e_.getMessage(), e_.getCause());
220         } catch (IOException e_) {
221             error(e_.getMessage(), e_.getCause());
222         }
223 
224         return baos_.toByteArray();
225     }
226     private void error(final String message, final Throwable t) {
227         logger.error("::: ::: " + message + " ::: :::", t);
228     }
229 }



unmarshallSOAPMessage on line 59 shows how to reconstruct the incoming SOAP message from the WebApplication's byte array and HeaderList. The rest is fairly obvious. sendResponse on line 198 shows how to pump a newly created SOAP message back over the wire.

That covers SwA server functionality within Java CAPS. I will show the client side code in a next blog.

Tuesday, November 22, 2005

XML to POJO and back. Horses for courses.

One aspect I've looked at in the recent past was the ability to turn POJOs into XML back into POJOs. There are a myriad of utilities out there to do just that. JAXB, Javolution, XMLBeans, XStream, JiBX and many more. Granted, some of the utilities are way smarter than others and offer different levels of functionality. With some you have to write code in your POJO. Others work of XML Schemas, you feed some sort of compiler a schema and it spits out POJOa galore which you then access using factories and such.

Of the utilities I've mentioned before JAXB and XMLBeans are a notable example of the XML Schema to POJO route. I feed a compiler a schema and it spits out POJOs. So if you are given a schema, go fry your brains with one of these tools. Real easy. Because you work from the schema to a Java representation the content and format of the Java classes created from the schema are out of your hands. It means that if you get an ugly, badly designed schema, you'll end up with ugly, non-intuitive Java. In that case you might have to use a second round of transformations like dozering or hand-written Java to Java transformation. You also have to write schema-centric or XML-centric application code. You are constantly remided that there is a document at stake somewhere. Now what can I say about JAXB and XMLBeans - "XML Schema to Java in 60 seconds" I guess...

Jovolution is somewhat different from the other utilities in that it is part of a high-performance, realtime Java library. So you write your Java code first. You can then add your Java to XML serialization and XML to Java deserialization code. It allows you to produce XML that are more element centric or more attribute centric - depending on your mood or your boss' mood. It is relatively easy to use once you've figured it out. Fortunately there is an eclipse plug-in that makes your life a whole lot easier - that is if you use eclipse of course (why wouldn't you). Don't use Javolution if you have a schema somewhere that the XML needs to adhere to, you'll get depressed and stressed and might suffer a nervous breakdown... What will be a nice catch phrase for Javolution - "kickass performance after you've figured it out". The figuring is the hard part...

If you have Java and want to go to XML you can also use XStream. Boy what a pleasure. Easy as pie. Five lines of code. Really, really easy. Did you get that, simple as sneeze! You do not have a great deal of power to configure what your XML will look like but hey, who cares, with this ease of use who wants to specify in great detail what the XML is produce should look like. Ok, so now we've covered the "extremes" if I may say so - schema driven XML to POJO or Java driven POJO to XML code.

JiBX allows you complete control over the mapping of XML to Java (or Java to XML). Its flexibility may come at a price. You can end up with XML and POJOs that at face value does not look the same. You will also have to work with a mapping compiler and such. From a Java point of view it is totally non-intrusive. Nowhere in your Java will you ever know about the underlying XML (except of course in your marshaler, unmarshaler service). It also has nice functionality like having binding specifications of different versions, so if you want to provide XML for Bob, use your Bob mapping and if you want to provide XML for Sue use your Sue mapping. Very nice. What can I say about JiBX - I guess "hard work, great rewards" sums it up best. Oh yeah, forget the schema - unless you want to use some of the tools supplied with JiBX...

Tuesday, October 11, 2005

Engineering in general

I am amazed at what the human mind is capable of conceiving. I am even more amazed that humans are able to do what they think, or want to do. The pyramids were built 2000 BCE, some say 10,000 BCE. Millions of cubic meters of rock, hundreds of millions of tones of rock. Countless laborers. It took hundreds(?) of years to complete - if you do not want to believe Egyptologists that is... If I stand back however, I see that it was not really that complex - yes, yes, I know that it is remarkable that the base layer of each pyramid is as good as absolutely flat and that each building block fits perfectly in place.

If we look at high rise buildings like the Petronas Towers or the Sears Tower or the not-any-more-but-still-awesome World Trade Centre more closely we will know that each one is a miracle on its own. We've grown so used to seeing them go up that our jaws don't drop anymore every time we see it happen. Even the most massive ones are not nearly as heavy as an average sized pyramid. It is essentially many a liter of concrete, many a kilometer of steel and sheet upon sheet of glass. And yet, we are astounded when buildings partially collapse (because of human error). How do we test the new building? Do we fill it up gradually from the bottom to the top and hope that it does not cave in? No. We go right ahead and put thousands of people in a building and know that it will stand!

The most astounding fact is that the technology to build massive buildings is much older that massive buildings itself - we had to wait for the escalator/elevator to be perfected to make sky scrapers practical!

When we see a massive dam like the Hoover, Itaipu or the not-yet-but-soon-to-be Three Gorges, holding back what will be approaching thousands of billions of liters of water what do we think - "Oooh, nice view! Let's go swim!". We do not even think that the dam might break and wash us down the river into a great ocean. We trust its walls.

Massive bridges like the Akashi Kaikyo, Millau Viaduct, Lake Pontchartrain Causeway or even the awe inspiring Firth of Forth that was built in the mid 1800's are common place. How does an engineer test a newly constructed bridge? Will she take her four year old, put him on his bicycle and hope that he reaches the other side? Will she then get in her small car and drive across the bridge and hope to reach the other side? Will she then get a fair sized truck to make the trip and look on in anguish as she prays to all the benevolent forces in the universe to protect the bridge? Will she then gamble with a mini rush hour volume of traffic? No! Cut the ribbon, drive!

We did not even touch on other amazing structures, inventions and consumables that just works. Like petrochemical plants, airliners, tunnels, massive ocean liners, space stations, ocean-bound exploration platforms, domes, busses, rockets, power plants of all sorts, the space shuttle and on and on and on...

What makes all of this possible? Mathematics. Physics. Chemistry - and the understanding and applications thereof. In all the mature engineering disciplines there is a solid foundation of mathematics together with interesting applications of mathematics - thermodynamics, strength of materials, static and dynamic forces and so on.

You also have a clear stratification in skill and ability in the mature engineering disciplines. At the foundation level you'll find pure mathematitians. They figure out stuff - stuff that not even they know the application of. On top of this foundation of pure mathematics you'll find people that can see the application of the clever stuff bubbling from beneath them, we'll call them the engineering scientists. Building on top of the engineering sciences you'll find types that can use all the tools handed up from the lower layer to build predictive models. These are your engineers. At the next level you'll find individuals that can take the models and draw designs, diagrams, schemas and plans and hand it off to other individuals that can correctly interpret the designs and such. At the next level you'll get the types that can say "Ok Bob, do this, that and the other!" - according to the plans etc. And right at the top sits Bob, someone that is relatively unskilled but hard working.

What do we have that even approach this in the software engineering field? Should we be arrogant enough to call software endeavors "engineering"? What are your thoughts? More on this in a later article.