On technology...

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, November 08, 2008

Downloaded Refcardz from DZone

I just downloaded some Refcardz from DZone. I am impressed. Very impressed.

Friday, September 19, 2008

Rolodex - Interface Based Programming

What is an interface?

An interface is a promise. A naked interface cannot do anything. It states, in black and white, what it will do for you. Don't count on it to remember anything, it suffers from acute memory loss. It knows nothing about "the state of affairs".

What is it not?

An interface does not have any way of telling you how it will come good on its promise - for that you need an implementation. It is just a promise. For example, if you go to an insurance company and sign up to be a customer they promise to replace or repair the stuff you insured. You need to pay up every month of course. The promise does not state HOW they will replace or repair your stuff. Once you need the insurance company to deliver on its promise you will probably call them up and they will tell you what to do - the how bit becomes clear... The company has rules and regulations to deliver on their promise. You don't care what those are, you know that they will deliver on their promise because of your interface (or contract).

Why use interfaces?

Interface based programming has become very popular because of Inversion of Control (AKA Dependency Injection) frameworks. There are may. Google it. There are some frameworks that sucked at appropriate use of interfaces, like J2EE, thankfully we have been rescued by JEE5. The nice thing about interfaces(IoC/DI frameworks) is that you get to split the promise and the delivery mechanism (the implementation). You get to pick the implementation that suits you best, just as long as it delivers on the promise made by the interface.

If you encounter an interface that says it will make the moon disappear and David Copperfield and the US Military decided to implement it you can know for certain that the implementation will be very different!

Monday, September 15, 2008

The KreditInform "Web Service" and I

I did a little work with the KreditInform "web service" during the last month or so. How did I find working with it? Here is a short list:
  • Ease of use - not very easy, documentation sucks.
  • Standards compliant - they call it a web service, which it is in the loosest terms. It is not WS-I compliant. I went to see a developer. There are no plans to change the current implementation to be WS-I compliant.
  • Did I get it to work? Yes.
  • Was it easy and intuitive. No way - be prepared to suffer!

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_ = (AttachmentPartattachments_.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_ = (Nodeelements_.next();
147                 if (n_.getLocalName().equalsIgnoreCase(localName)) {
148                     element_ = (SOAPElementn_;
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((Stringattachment.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.