Insights on Software Development and Architecture

ErionPC's weblog on software development

JQuery calendar

I like using the Ajax Control Toolkit in the ASP.NET websites I maintain and I had been using a CalendarExtender for a while to pop up a calendar from watermarked textboxes.
I found out that with the new relase of Mozilla Firefox (4.0.1) my ajax calendar stopped working. I didn’t particularly like the fact that it sent postbacks to the server on date-change anyway, so I thought it was time to look for something different, completely client-side and javascript-based.
This is how I discovered Any+Time™. It’s a Date/time picker based on JQuery which I found was easy to integrate in my projects and flexible enough to be customized and extended. The source code is available so it can be adapted to many different contexts.

This is how it looks in its basic form

date picker

It can be adapted to show just the date picker or just the time picker, or both. It also supports localization. The only prerequiste required is the jquery framework, even in its minimal version.

The Date Picker is composed by the following files:

  • anytime.js (main js file)
  • anytimetz.js (optional: to support localization)
  • anytime.css (presentation)

After including the above files and the jquery file in the HTML you can use the following code to bind Date pickers to your textboxes:

function resetDatePickers() {
    $(document.getElementById("<%= this.myTextBox.ClientID %>")).AnyTime_noPicker();
    $(document.getElementById("<%= this.myTextBox.ClientID %>")).AnyTime_picker({ format: "%d/%m/%Y", labelTitle: "Seleziona la data", labelDayOfMonth: "Giorno", labelMonth: "Mese", labelYear: "Anno", dayAbbreviations: ["Dom", "Lun", "Mar", "Mer", "Gio", "Ven", "Sab"], monthAbbreviations: ["Gen", "Feb", "Mar", "Apr", "Mag", "Giu", "Lug", "Ago", "Set", "Ott", "Nov", "Dic"], firstDOW: 1 }).removeAttr("disabled");
}

It would be a good idea to call this function after every page postback (ex. inside the Page_Load method in ASP.NET). After this, a click on this.myTextBox will popup a date picker which will change the Text property on any click, obviously without posting back to the server. In the above example I use the Italian localization.

I have also called the function removeAttr("disabled"), because I want to be able to edit the text of my textbox manually and this isn’t possible unless you call this function. I extended anytime.js so that the date/time entered in the textbox is cleared after a keyboard-del or backspace. This is useful because otherwise there is no other way to clear the textbox if you don’t want to enter anything and you’ve just clicked on it.

Another thing to notice is that I called the function AnyTime_noPicker() before calling AnyTime_picker(). I had to do this because if the page posts back and you try using the datepicker inside an ajax update panel without reloading the page, it doesn’t work anymore because the datepicker object doesn’t get destroyed on a postback which partially updates the page.  AnyTime_noPicker() destroys any existing instances of the date picker and makes it possible to re-bind it to the textbox after a postback. The author was kind enough to help me get to this solution very quickly.

This is what I’ve added to anytime.js to clear the text on Delete.

key: function(event) {
   if ( key == /* ... */ ) { /* ... */ }
   // ....
   // My code
   else if ((key == 8) || (key == 27) || (key == 46)) // backspace, escape or delete
   {
      this.inp[0].value = "";
      this.dismiss(null);
   }
   else
      this.showPkr(null);
   // ....
}

For any further details, refer to the original documentation on http://www.ama3.com/anytime/.

This is my extended version of anytime.js http://erionpc.files.wordpress.com/2011/05/anytime.odt. You need to rename anytime.odt to anytime.js after download (wordpress work around).

Web Service Communicator

Introduction

The purpose of this article is to illustrate the potential of dynamic web service invocation made possible by Reflection.

This approach consists in: downloading the WSDL file at runtime, creating the proxy class, compiling it into an assembly and executing the methods on it.

This allows you to dynamically invoke methods from a web service that aren’t known at build time and potentially build pre-configured routines for message exchange between multiple services.

Background

I had been looking for a couple of days about a way to dynamically invoke a web service without being bound to a prior knowledge of its contract at build-time.

As a result of my research I finally came across http://www.crowsprogramming.com/archives/66, which follows the approach that I’ve explained in the introduction.

I’ve built a simple Windows application which shows the potential of that approach to make web services communicate between them without a compile-time knowledge of their contracts.

Using the code

The sample solution includes two projects:

  • WSCommunicator.SL – Sample service layer
  • WSCommunicator.WinForm – Sample Windows Forms application

The Service layer contains a simple web service which returns some sample data. These are its methods

[WebMethod]
public List<Person> GetAllPersons()

[WebMethod]
public List<string> GetAllPersonsNames()

[WebMethod]
public int GetPersonsAge(string name, string surname)

[WebMethod]
public Address FindPersonsAdress(string name, string surname)

We will use these methods later to see how dynamic message exchange works.

The WinForm project contains one WinForm (“WSCommunicatorForm”) and some classes which are used for the dynamic web service invokation. The most important class is “WSInvoker” which uses System.Reflection to dynamically compile the web service descriptions into packages and call their methods.

This is how it achieves this:

private Assembly BuildAssemblyFromWSDL(Uri webServiceUri)
{
    if (String.IsNullOrEmpty(webServiceUri.ToString()))
        throw new Exception("Web Service Not Found");

    XmlTextReader xmlreader = new XmlTextReader(webServiceUri.ToString() + "?wsdl");

    ServiceDescriptionImporter descriptionImporter = BuildServiceDescriptionImporter(xmlreader);

    return CompileAssembly(descriptionImporter);
}

private ServiceDescriptionImporter BuildServiceDescriptionImporter( XmlTextReader xmlreader )
{
    // make sure xml describes a valid wsdl
    if (!ServiceDescription.CanRead(xmlreader))
        throw new Exception("Invalid Web Service Description");

    // parse wsdl
    ServiceDescription serviceDescription = ServiceDescription.Read(xmlreader);

    // build an importer, that assumes the SOAP protocol, client binding, and generates properties
    ServiceDescriptionImporter descriptionImporter = new ServiceDescriptionImporter();
    descriptionImporter.ProtocolName = "Soap";
    descriptionImporter.AddServiceDescription(serviceDescription, null, null);
    descriptionImporter.Style = ServiceDescriptionImportStyle.Client;
    descriptionImporter.CodeGenerationOptions = System.Xml.Serialization.CodeGenerationOptions.GenerateProperties;

    return descriptionImporter;
}

private Assembly CompileAssembly(ServiceDescriptionImporter descriptionImporter)
{
    // a namespace and compile unit are needed by importer
    CodeNamespace codeNamespace = new CodeNamespace();
    CodeCompileUnit codeUnit = new CodeCompileUnit();

    codeUnit.Namespaces.Add(codeNamespace);

    ServiceDescriptionImportWarnings importWarnings = descriptionImporter.Import(codeNamespace, codeUnit);

    if (importWarnings == 0) // no warnings
    {
        // create a c# compiler
        CodeDomProvider compiler = CodeDomProvider.CreateProvider("CSharp");

        // include the assembly references needed to compile
        string[] references = { "System.Web.Services.dll", "System.Xml.dll" };

        CompilerParameters parameters = new CompilerParameters(references);

        // compile into assembly
        CompilerResults results = compiler.CompileAssemblyFromDom(parameters, codeUnit);

        foreach (CompilerError oops in results.Errors)
        {
            // trap these errors and make them available to exception object
            throw new Exception("Compilation Error Creating Assembly!!\r\n" + oops.ErrorText);
        }

        // all done....
        return results.CompiledAssembly;
    }
    else
    {
        // warnings issued from importers, something wrong with WSDL
        throw new Exception("Invalid WSDL");
    }
}

First a ServiceDescriptionImporter is built by parsing the web service WSDL. This is then compiled into an assembly which is ready to be used. This is how the WSInvoker calls its methods:

public T InvokeMethod<T>( string serviceName, string methodName, params object[] args )
{
    // create an instance of the specified service
    // and invoke the method
    object obj = this.webServiceAssembly.CreateInstance(serviceName);

    Type type = obj.GetType();

    return (T)type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, obj, args);
}

In order to make data visualization possible on the client, an XML serializer (CustomSerializer class) is used which serializes the WS Output and loads a dataset with it, when possible. Here are the serialization-deserialization methods:

public String SerializeObject(Object pObject, Type myType)
{
    try
    {
        String XmlizedString = null;
        MemoryStream memoryStream = new MemoryStream();
        XmlSerializer xs = new XmlSerializer(myType);
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
        xs.Serialize(xmlTextWriter, pObject);
        memoryStream = (MemoryStream)xmlTextWriter.BaseStream;
        XmlizedString = UTF8ByteArrayToString(memoryStream.ToArray());

        XmlizedString = changeInvalidCharacters(XmlizedString);

        return XmlizedString.Substring(1);
    }
    catch (Exception ex) 
    { 
        throw new Exception("Serialization error!\r\n" + ex.Message); 
    }
}

public Object DeserializeObject(String pXmlizedString, Type myType)
{
    try
    {
        XmlSerializer xs = new XmlSerializer(myType);
        MemoryStream memoryStream = new MemoryStream(StringToUTF8ByteArray(pXmlizedString));
        XmlTextWriter xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
        return xs.Deserialize(memoryStream);
    }
    catch (Exception ex)
    {
        throw new Exception("Deserialization error!\r\n" + ex.Message);
    }
}

The CustomSerializer is also used to serialize/deserialize the application configuration file which we’re going to examine further on.

The WSCommunicatorForm class defines the user interface. This is how it looks (click to expand):

user interface

The window is divided in two main parts: the left one contains the input web service configuration, the right one contains the output configuration and the input-output parameter mapping. When a valid web service url is entered into the left top textbox (Input web service) and the corresponding Load button is pressed, the Form calls the BuildAssemblyFromWSDL method of the WSInvoker class, which parsed the web service descriptor and acquires information on its definition and methods. The left part of the form is thus populated with the input web service information. By changing the web method selection, the corresponding return type information is updated to display the details of the currently selected method output.

There is also a textbox in which the input web service method parameters must be written separated by semicolon to allow a correct invocation of the web method.

A click on the left Invoke button invokes the selected method with the specified input parameters and displays the result on the left datagrid. I haven’t worked much on the data visualization aspect, as this is just a test application, but you should be able to see a result for most types of output.

When the result is displayed, the “Available Output Fields” listbox on the right gets populated with the column definitions of the left DataGridView. These items will later be mapped to the output web service input parameters.

If we now digit a valid web service url into the right top textbox (Output web service) and press the corresponding Load button, the right part of the form will be populated with the details of the output web service. This web service can even be the input web service, or any other which is reachable by the client machine. In the illustrated example the output web service is the same as the input one. This is how the window looks now (click to expand):

user interface populated

In order to make the message exchange possible between the two web services we need to configure the input-output mapping correctly. We can do this by using the arrows on the right side which allow us to move into the “Input parameters” listbox the available output fields obtained by the input web service. The parameters can also be moved up and down. The right-most listbox on the mapping section (Input types) contains the input parameter types for the currently selected output web service method. The number and the type of the input parameters must correspond to these types.

Once the mapping is done, we’re ready for the “magic” to happen: Press the right “Invoke” button to pass the input-web-service-output to the output web service method and see its output on the right DataGridView. This is how the window looks now (click to expand):

user interface populated

The application can save/load its configuration from XML. In order to make this simpler and make a creative use of the CustomSerializer I created some data structures in the WSComConfig.cs file as follows:

public struct WSComConfig
{
    public WSConfig wsInputConfig { get; set; }
    public WSConfig wsOutputConfig { get; set; }
}
public struct WSConfig
{
    public string wsAddress { get; set; }
    public string wsName { get; set; }
    public string wsMethod { get; set; }
    public List<string> wsParams { get; set; }
}

The CustomSerializer serializes this into (and deserializes this from):

<?xml version="1.0" encoding="utf-8"?>
<WSComConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsInputConfig>
    <wsAddress>http://localhost:51425/SampleService.asmx</wsAddress>
    <wsName>SampleService</wsName>
    <wsMethod>GetAllPersons</wsMethod>
    <wsParams />
  </wsInputConfig>
  <wsOutputConfig>
    <wsAddress>http://localhost:51425/SampleService.asmx</wsAddress>
    <wsName>SampleService</wsName>
    <wsMethod>FindPersonsAdress</wsMethod>
    <wsParams>
      <string>Name</string>
      <string>Surname</string>
    </wsParams>
  </wsOutputConfig>
</WSComConfig>

This makes configuration loading and saving extremely easy. For this test application, the click handler on the “Load configuration” button automates the input-output configuration and the invocation of the input web service method, but leaves the final Invoke to the user. It obviously takes nothing to automate that too. This illustrates the potential of this approach to create automated web service message exchange routines!

Points of Interest

I learnt a lot through this project about dynamic web service invocation and explored dynamic web service mapping. Although the sample application illustrates communication between only two web services, this concept can be extended to an unlimited number of web services which can be configured to create a business process workflow. I have previously worked on the Java Open ESB and have been fascinated by its technology. This is surely less than 1% complex compared to it, but it makes web service interoperability possible.

Notes

I’d be very happy if someone takes this idea further

Click here to download the sample code from my Live Sky Drive

Click here to view this article on CodeProject.com

A SOA approach to dynamic DOCX-PDF report generation – Part 2

Introduction

Having already achieved automatized MsOffice-independent Docx report generation in a client-server architecture following the approach explained in my previous article “A SOA approach to dynamic DOCX-PDF report generation – part 1″, now we’ll look into automatically printing those docx files into PDF from managed code and transmitting the PDF bytes through HTTP.

The PDF conversion is based on a free BullZip PDF product, which offers a free, full-featured, programmable and very well documented PDF printer that can print any file to PDF, including Docx files.

Needless to say that PDF is probably the most used document exchange format between different platforms, therefore the need to have PDF reports of some kind of data is common to most data-centric applications.

1. Installing the PDF Printer

The first thing to do is to download and install BullZipPdf. It will create a PDF printer in the system and it will include the help file in the installation directory. Read through the help file to learn how to use the Bullzip.PdfWriter namespace.

2. Adding the PDF Conversion to an Existing Visual Studio Solution

First of all, we need to import the package into the solution. As sweet as it can be, we can find the package in the GAC, so just go on Add Reference -> .NET and find BullZip Pdf Writer. This will add the Bullzip.PDFWriter assembly to the solution, which exposes its classes and methods under the Bullzip.PDFWriter namespace. The next thing to do is configuring the PDF printer. This can be achieved through a .ini file, but I’m not going to enter into this, you can read a lot about it in the Bullzip documentation. The printer settings are managed by a class called PdfSettings, whilst the PDF creation methods are in a class called PdfUtils. Everything is ready now, we can already start converting to PDF!

3. Converting to PDF

Here’s what the test application does:

  1. It includes some docx templates with sample data in a templates directory
  2. Generates customized docx reports based on the docx templates and some XML-serialized Business-Logic data whose structure corresponds to the custom XML parts in the docx templates
  3. Saves the docx reports into a temporary directory
  4. Prints the docx reports into PDF
  5. Sends the PDF bytes through HTTP
  6. Destroys the docx and PDF files

This PrintToPdf method loads the printer settings from an “.ini” file, it “reads” a docx file from a temporary directory, creates the PDF file and then destroys the original docx and PDF.

using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
using System.Diagnostics;
using System.ComponentModel;
using System.Configuration;
using System.ServiceModel;
using Bullzip.PdfWriter;

namespace DocxGenerator.SL.WCF
{
    public class PdfMaker
    {
        internal static byte[] PrintToPdf(string appFolder, string tempDocxFileName)
        {
            try
            {
                string tempFolder = appFolder + @"\temp";
                string tempDocxFilePath = tempFolder + @"\" + tempDocxFileName;

                PdfSettings pdfSettings = new PdfSettings();
                pdfSettings.PrinterName = ConfigurationManager.AppSettings["PdfPrinter"];

                string settingsFile = pdfSettings.GetSettingsFilePath(PdfSettingsFileType.Settings);
                pdfSettings.LoadSettings(appFolder + @"\App_Data\printerSettings.ini");
                pdfSettings.SetValue("Output", tempFolder + @"\&lt;docname&gt;.pdf");
                pdfSettings.WriteSettings(settingsFile);

                PdfUtil.PrintFile(tempDocxFilePath, pdfSettings.PrinterName);
                string tempPdfFilePath = tempFolder + @"\Microsoft Word - " + tempDocxFileName + ".pdf";

                bool fileCreated = false;
                while (!fileCreated)
                {
                    fileCreated = PdfUtil.WaitForFile(tempPdfFilePath, 1000);
                }

                byte[] pdfBytes = File.ReadAllBytes(tempPdfFilePath);

                File.Delete(tempDocxFilePath);
                File.Delete(tempPdfFilePath);

                return pdfBytes;
            }
            catch (Exception ex)
            {
                throw new FaultException("WCF ERROR!\r\n" + ex.Message);
            }
        }
    }

Points of Interest

The scope of this article is limited to a mere illustration of what can be achieved through this architecture. With a little bit of head-scratching, you can extend this and make it into a PDF conversion server (did anyone think of a free version Adobe Distiller ???), a scheduled batch printer, an archiving system, etc.
If integrated in the SOA report generation solution mentioned above this permits you to get rid of the docx files and use PDF as the document exchange format.

Have fun!

History

The previous (must-read to understand the SOA integration concepts) article that brought to this: “A SOA approach to dynamic DOCX-PDF report generation – part 1″

Click here to view this article on CodeProject.

Click here to download the test application’s source code.

A SOA approach to automatized DOCX-PDF report generation – part 1

Introduction

With the advent of Ms Office 2007 Open XML formats, the philosophy of Office report generation was deeply changed into making it dettached from Office itself and open to any kind of programming language which is capable of reading compressed archives and manipulating XML. For further reading visit

In this article I’m going to illustrate a SOA approach for generating Docx reports in a distributed environment with the necessity of having Ms Office 2007 installed only on the developer machine (not the production server). The application is composed by the following parts:

  1. An ASP.NET web application
  2. An IIS-hosted WCF service
  3. A business tier
  4. A data access tier
  5. A database

The scope of this article is limited to the top 2 tiers. By using the Open XML SDK (now 2.0) it’s possible to programmatically read and write inside Office Open XML packages – that means reading and writing Office files without using Office COM objects. This approach is very fast, easy, light on resources and STABLE. The WCF service in this application must be able to create Docx reports on the basis of an existing docx template and some db data serialized as XML. Docx files are constructed in a modular way. To be able to appreciate this, you can just rename a docx file changing it’s extension to .zip. To know more about how this archive is organized visit http://msdn.microsoft.com/en-us/library/bb266220%28office.12%29.aspx. The part that we’re interested in is called Custom XML (read http://msdn.microsoft.com/en-us/library/bb608618.aspx). The approach that’s best to follow for manipulating data within a Docx file is binding content controls to custom xml parts.

1. Generating a docx template document

The first thing to do is to build a docx document which defines the layout of the reports by using Word 2007 or above. In this document there are going to be static parts (text-blocks, images and so on) and dynamic parts, which are going to be dependent on the data. At first we build and format the docx file as we expect it to look with dynamic data on it. Then, when we’re happy enough with the way it looks, it’s time to add the content controls. On the Word ribbon we need to go to the Developer tab (if you don’t see it, click here to learn how to activate it). In this tab we can find a few content controls, such as rich text, plain text, image, etc. We now need to replace the fake data that we’ve put into the document with the appropriate content controls.

2. Creating Custom XML parts

Using Word 2007 we’re able to put Content Controls into a docx document, but we’re not able to bind those controls to custom data. In order to do this we need to use another tool called Word 2007 Content Control Toolkit. At this point our docx document doesn’t contain any custom xml parts. We can create these by using WCCT. Open the docx document inside WCCT. On the right panel click on “Create a new Custom XML part”. The custom XML part will be created and we’ll be able to see it from the “Bind view” tab. On the left part of the window we will be able to see references to the content controls that we’ve inserted in the file. Clicking on the “Edit view” of the right panel it’s possible to edit the xml. The xml structure that we need to create has to be valid and needs to correspond to the content controls in the page. For example

<documentData>
<title alias=”Title”>document title</title>
<body alias=”Body”>document body</body>
</documentData>


When we’ve finished creating the xml, it’s always good to get the xml syntax checked by WCCT clicking on the “Check Syntax” button. We’re now ready to go back to the “Bind View”. We will now be able to see the xml nodes we’ve just inserted in a tree-like structure and the fun part is about to begin. We’ll now bind the xml nodes to the content controls, and this is as easy as drag-and-drop. Select one of the nodes on the right panel and drag it on the reference to one of the content controls of the document. Repeat this operation for all of the xml nodes until all the content controls have been bound to data. When you’re done, save the file and click on the preview button to open the document using Word. Notice how the custom xml data has replaced the text inside the content controls.

3. Building the WCF service

The WCF service will replace the custom xml inside the docx template with business logic xml data. Using the Open XML SDK this is actually very easy. Here’s the replaceXML method

private void replaceCustomXML(string docxTemplate, string customXML)
{
try
{
using (WordprocessingDocument wordDoc = WordprocessingDocument.Open(docxTemplate, true))
{
MainDocumentPart mainPart = wordDoc.MainDocumentPart;

mainPart.DeleteParts<CustomXmlPart>(mainPart.CustomXmlParts);

//Add a new customXML part and then add content
CustomXmlPart customXmlPart = mainPart.AddCustomXmlPart(CustomXmlPartType.CustomXml);

//copy the XML into the new part…
using (StreamWriter ts = new StreamWriter(customXmlPart.GetStream()))
ts.Write(customXML);
}
}
catch (Exception ex)
{
throw new FaultException(“Errore WCF!\r\n” + ex.Message);
}
}

Once the docx document is created it will be sent to the client as an array of bytes.

public byte[] GenerateDynamicDocx(string customXML)
{
try
{
HttpServerUtility webServer = HttpContext.Current.Server;

// Copy template.docx in the temp folder to preserve the original copy
string tempFolder = webServer.MapPath(“temp”);
string tempDocxFileName = Guid.NewGuid() + “.docx”;
string tempDocxFilePath = tempFolder + @”\” + tempDocxFileName;
File.Copy(webServer.MapPath(@”App_Data/template.docx”), tempDocxFilePath);

replaceCustomXML(tempDocxFilePath, customXML);

byte[] docxContents = File.ReadAllBytes(tempDocxFilePath);

//Delete the temporary file
File.Delete(tempDocxFilePath);

return docxContents;
}
catch (Exception ex)
{
throw new FaultException(“Errore WCF!\r\n” + ex.Message);
}
}


4. Building the ASP.NET client

The ASP.NET client will have a template.xml file which replicates the structure of the custom XML part in the server’s docx template. Ideally, there would be a web page which automatically generates web controls for inputing data which mirrors the structure of the xml template file. After the data is inputed the web client must compose an xml document which follows the structure of the existing template.xml but replaces the data with those inputed by the user. The xml string is then sent to the WCF service wich returns the bytes of the docx file. These bytes can then either be saved as a docx file on the server or sent directly to the client through HTTP.

Click here to download source code.

Click here to view article on codeproject.com.

Import – Export data into an Oracle 10g database

Being a newbie in Oracle, I’ve often had to look around the web for good documentation on how to import and export data from and into an Oracle Db. I’ve put together all that I’ve found in a 1 page document. I’ve tested the procedure more and more times now and for me it works.

The document is a pdf file in English and Italian.

ASP.NET – Get Client Screen Resolution

No matter ASP.NET offers the “Page.Request.Browser.ScreenPixelsWidth” and “Page.Request.Browser.ScreenPixelsHeight” methods, these don’t help when you need to obtain the client’s screen resolution on the server side. They give false results. I think the best way to do this is through JavaScript. Here’s an example:

C#


<%if (!this.IsPostBack)
{%>
<script language="javascript" type="text/javascript">
var rowURL = window.location.href;
var screenWidth = window.screen.availWidth;
if (rowURL.indexOf("screen_width") == -1)
window.location.href = window.location.href + "?screen_width=" + screenWidth;
</script>
<%}%>

This script just needs to be pasted inside the <body> tag of the page. The script basically checks whether the query string contains the “screen_width” parameter. If it doesn’t, it appends the “screen_width” parameter to the query string and refreshes the page. Server-side, you just need to retreive the value of the “screen_width” Request parameter.

GlassFish and XML serialization – reviewed

I keep finding work arounds to OpenESB-Glassfish bugs by chance. I am currently using;

Product Version: NetBeans IDE 6.1 (Build 200809100101)
Java: 1.6.0_04; Java HotSpot(TM) Client VM 10.0-b19
System: Windows XP version 5.1 running on x86; Cp1252; en_US (nb)

On a previous post I had written that as far as I knew by my experience, GlassFish doesn’t serialize business objects which inherit from other business objects. This is quite limiting in regards to software architecture and I really like using polymorphism.

I had been desperately trying to make my JAX-WS return xml-serialized business objects which I had defined, but without success, until I tried the following. I’ll need to give further details on this to make it clear. These are the business objects that I wanted to be serialized (click on the image to see it bigger).

streamhandler package class diagram

streamhandler package class diagram

My DataBlock objects are specialized into TrackDataBlock and MessageDataBlock and are composed by a DataBlockHeader and a RecordList. DataBlockHeader is specialized into TrackDataBlockHeader and MessageDataBlockHeader. RecordList is composed by a list of Records. A Record is an abstract BO which is made concrete by the types TrackIdRecord, TrackPointRecord, CellSwitchRecord and MessageRecord. The latter one is specialized further by TextMessageRecord. My objective is to have all this structure available as a return type for a JAX-WS -> consequently serialized into xml.

The first thing I did was refactoring all the java classes into the ‘Bean’ form. I then tried serializing a DataBlock, but got the incomprehensible exceptions:

javax.servlet.ServletException: java.lang.reflect.InvocationTargetException
	at com.sun.enterprise.webservice.monitoring.WebServiceTesterServlet.doPost(WebServiceTesterServlet.java:345)
	at com.sun.enterprise.webservice.monitoring.WebServiceTesterServlet.invoke(WebServiceTesterServlet.java:121)
	at com.sun.enterprise.webservice.EjbWebServiceServlet.service(EjbWebServiceServlet.java:140)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:831)
	at com.sun.enterprise.web.AdHocContextValve.invoke(AdHocContextValve.java:114)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:632)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:577)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:571)
	at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:87)
	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:206)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:632)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:577)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:571)
	at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1080)
	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:150)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:632)
	at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:577)
	at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:571)
	at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:1080)
	at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:272)
	at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.invokeAdapter(DefaultProcessorTask.java:637)
	at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.doProcess(DefaultProcessorTask.java:568)
	at com.sun.enterprise.web.connector.grizzly.DefaultProcessorTask.process(DefaultProcessorTask.java:813)
	at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.executeProcessorTask(DefaultReadTask.java:341)
	at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:263)
	at com.sun.enterprise.web.connector.grizzly.DefaultReadTask.doTask(DefaultReadTask.java:214)
	at com.sun.enterprise.web.connector.grizzly.TaskBase.run(TaskBase.java:265)
	at com.sun.enterprise.web.connector.grizzly.ssl.SSLWorkerThread.run(SSLWorkerThread.java:106)
Caused by: java.lang.reflect.InvocationTargetException
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
	at java.lang.reflect.Method.invoke(Method.java:597)
	at com.sun.enterprise.webservice.monitoring.WebServiceTesterServlet.doPost(WebServiceTesterServlet.java:316)
	... 27 more
Caused by: com.sun.xml.ws.encoding.soap.DeserializationException: Failed to read a response: javax.xml.bind.UnmarshalException
 - with linked exception:
[javax.xml.bind.UnmarshalException: Unable to create an instance of ejb.easyict.it.track.Record
 - with linked exception:
[java.lang.InstantiationException]]
	at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:124)
	at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
	at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:118)
	at $Proxy174.testSerializzazioneRecordList(Unknown Source)
	... 32 more
Caused by: javax.xml.bind.UnmarshalException
 - with linked exception:
[javax.xml.bind.UnmarshalException: Unable to create an instance of ejb.easyict.it.track.Record
 - with linked exception:
[java.lang.InstantiationException]]
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:421)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:360)
	at com.sun.xml.bind.v2.runtime.BridgeImpl.unmarshal(BridgeImpl.java:120)
	at com.sun.xml.bind.api.Bridge.unmarshal(Bridge.java:233)
	at com.sun.xml.ws.client.sei.ResponseBuilder$DocLit.readResponse(ResponseBuilder.java:525)
	at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:121)
	... 35 more
Caused by: javax.xml.bind.UnmarshalException: Unable to create an instance of ejb.easyict.it.track.Record
 - with linked exception:
[java.lang.InstantiationException]
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:603)
	at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:244)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:570)
	at com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader.startElement(StructureLoader.java:181)
	at com.sun.xml.bind.v2.runtime.unmarshaller.ProxyLoader.startElement(ProxyLoader.java:55)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:449)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:427)
	at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.handleStartElement(StAXStreamConnector.java:275)
	at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:209)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:358)
	... 39 more
Caused by: javax.xml.bind.UnmarshalException: Unable to create an instance of ejb.easyict.it.track.Record
 - with linked exception:
[java.lang.InstantiationException]
	... 49 more
Caused by: java.lang.InstantiationException
	at sun.reflect.InstantiationExceptionConstructorAccessorImpl.newInstance(InstantiationExceptionConstructorAccessorImpl.java:30)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at com.sun.xml.bind.v2.ClassFactory.create0(ClassFactory.java:123)
	at com.sun.xml.bind.v2.runtime.ClassBeanInfoImpl.createInstance(ClassBeanInfoImpl.java:257)
	at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.createInstance(UnmarshallingContext.java:564)
	... 46 more

Then I declared simple test web methods on my WS which used each of the BOs as return types, starting from the leaves of the above architecture. I found that GlassFish would serialize them with no problems. Then I tried to serialize a generic list of different object types which inherited from the same object (like the different specialized types of Record). I found out that “magically” GlassFish serialized the list!! I then tried the final test -> serializing a DataBlock; it worked out fine!!

At this point I couldn’t help trying to comment out the test methods which used the bottom level BOs as return types and recompile. When I executed the method for serializing a DataBlock, I got the same exceptions as before!! This proved to me that as long as my JAX-WS declared methods which return the bottom level BOs, GlassFish would be happy to serialize even the higher level BOs.

I’d be happy if this helps out someone who’s trying to keep using polymorphism on a JAX-WS.

Happy days! :)

BPEL and Web Service packages

For a few hours I was trying to understand why my simple BPEL process wasn’t working. I was using NetBeans IDE 6.1 (Build 200809100101). My simple BPEL process used two external partner links which were web services exposed by an EJB Module. Looking at the messy exception messages that Glassfish shows it was kind of hard to understand the issue. Everything seamed to be fine, building went smoothly and the deployment on a Composite Application as well, but the test always failed. The test failure wasn’t due to the fact that the contents of the output file and the file whose name contains the timestamp of the moment when the test was executed were different, because both of the files reported an error message (this is in fact a bug in NetBeans). I couldn’t understand why I could never obtain the desired results. Trying different things I found out that if I put the web services which acted like partner links in the BPEL process into different packages in the EJB Module, everything worked fine!! I think this was due to the fact that some of the output types used in the two web services were the same (for example java.lang.Exception) and maybe the BPEL schema importer couldn’t tell between the two. I don’t know, the important thing is that this seems to be yet another bug in the NetBeans platform. I resolved the problem with some simple refactoring, putting the two different web services into two different packages.

Glassfish and XML Serialization

Having worked with the .NET frameworks in Visual Studio, whenever I implemented an ASPNET web service I was used to return generalized collections of my business objects which were declared in nested layers and I never had any problems because the returned values would always be xml-serializations of my classes. However, having to work with GlassFish now I found that serialization isn’t that immediate. After days of looking for documentation on this issue, I discovered that Glassfish doesn’t serialize your objects unless they respect the java-beans structure (private fields, public getters and setters in CamelCase and a no-parameter constructor) and (obviously) they need to implement the java.io.serializable interface. I also found that nested classes can’t be serialized (but maybe I’m wrong).

I’ve written a more recent post on this topic. Click here to view it.

Silverlight and JAX-WS Web Services?

This is a tough one,

for the last two days I’ve been trying to make a Silverlight client consume a Glassfish JAX-WS Web Service, but without any success till a few hours ago. I tried the procedure indicated at “Call a Java EE Web service from Silverlight Client” on the MSDN blogs (the only one I could find) but it didn’t work. That blog post says that the solution is copying an xml file called clientaccesspolicy.xml in the docroot folder of the GlassFish domain where the web service resides. I found that when you add a GlassFish WS web reference to a Silverlight project, Visual Studio (I use the Professional 2008 version) creates a configuration file that gives compilation problems, unless you manually change the “customBinding” to “basicHttpBinding” and manually add the endpoint. When I ran the Silverlight client it launched a CommunicationException due to a “cross-domain configuration error”. I had already copied the clientaccesspolicy.xml file on the docroot folder of my GlassFish domain as indicated on the msdn blog.

Then, after some hours, I had the idea of creating an ASPNET Web Service which acts as a wrapper for my GlassFish WS, but I found out that neither that would work and it would launch the same exception! I started to have strong suspicions that this was a Silverlight bug. I completely erased the existing project which didn’t work and created a new one, adding the web references normally (not manually). In this way it finally worked!

Just out of curiosity I tried adding another web reference to the Silverlight project to my original GlassFish WS, having to change the configuration file manually as before. It not only didn’t work, but it also caused the other (.NET) web service to stop working, even after I had removed it completely and had restored the configuration file to the original state. It’s so ridiculous! Silverlight is good looking, but still not serious enough for interoperability.

Cheers.

Follow

Get every new post delivered to your Inbox.