Using User-Defined Data Types


Using User -Defined Data Types

Sometimes your Web service might require the use of classes, in parameters or return values, that are user defined ”in other words, not built into the Java language or WebLogic Server. If your back-end component(s) that uses these user-defined types is already written, chances are your UDT Java classes are also already written. In most cases, the WebLogic ServiceGen task should be able to examine these UDTs and generate the following for you:

  • XML Schema for the UDT, in the <types> section of the Web service deployment descriptor file, web-services .xml

  • Serializer and deserializer classes for the UDT

  • Type-mapping elements in web-services.xml , which map UDTs to their serializer/deserializer classes

These are all necessary items in the make-up of a WebLogic Web service. The good news is that if your UDT conforms to the following rules, WebLogic Server should be able to successfully generate them for you:

  • Define a default, public, zero-argument constructor.

  • For each instance variable, define public setter and getter methods , set Xxx() and get Xxx() , respectively, where Xxx is the name of the instance variable. This is a JavaBean characteristic.

  • If any of your UDT instance variables are themselves UDTs, make sure you also have these UDTs defined.

Otherwise, you need to manually create these items. The following sections describe how this can be done.

Specifying XML Schema for UDTs

You need to decide how your user-defined type will look in the XML representation. For instance, what element names and tag structure will be used? Which elements are required, and which ones are optional? How many times can a particular element occur? The XML representation you define will be used in the XML SOAP request and possibly in the SOAP response.

You define how your UDT will "look" in XML using the precise language of XML Schemas. Learning how to author XML Schemas is not a trivial task and is certainly beyond the scope of this book. We can, however, show a sample schema definition for a typical UDT, Employee , as defined in Listing 30.4. (Note that the Employee class conforms to the rules presented in the preceding section.)

Listing 30.4 Sample User-Defined Type Employee
 public class Employee { private String fullname; private int id; public Employee() {} // Create a default employee // set/get methods for each variable for JavaBean compliance public setFullname(String name) { fullname = name; } public getFullname() { return fullname ; public setId(int serialNo) { id = serialNo; } public getId() { return id; } } 

A possible XML representation for an instance of Employee might be

 
 <employee> <fullname>Christy Anne Go</fullname> <id>98345</id> </employee> 

Now you must codify the rules indicating how to convert an instance ”in fact, any instance ”of Employee into the preceding XML format. What you need is a meta language to describe a grammar for what are valid XML sequences that represent a correct Employee instance. That is exactly what an XML Schema is. A possible schema for Employee is shown in Listing 30.5.

Listing 30.5 A Sample XML Schema for a User-Defined Type
 <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:stns="java:examples.webservices" attributeFormDefault="qualified" elementFormDefault="qualified" targetNamespace="java:examples. webservices "> <xsd:complexType name="Employee"> <xsd:sequence> <xsd:element name="fullname" type="xsd:string" maxOccurs="1" minOccurs="1"> </xsd:element> <xsd:element name="id" type="xsd:int" maxOccurs="1" minOccurs="1"> </xsd:element> </xsd:sequence> </xsd:complexType> </xsd:schema> 

This schema declares the following:

  • Element complexType defines a user-defined type called Employee .

  • Element sequence lists the members of Employee and indicates that each member must occur in the order shown.

  • Element element defines a member, called fullname , of type string . The fullname member must occur exactly once, to be a valid Employee instance. The same applies to the other members.

Note

Go to http://www.w3.org/TR/xmlschema-0/ for more information on the XML Schema notation definition.


Defining Types in web-services.xml

After you write the XML Schema for your UDT, you must add it to the <types> section of web-services.xml , as shown in the following code:

 
 <types> <!-- One user-defined type --> <xsd:schema... > : </xsd:schema> <!--Another user-defined type --> <xsd:schema... > : </xsd:schema> </types> 

You can define multiple UDTs within a schema section, but all UDTs in a schema section will share the same target namespace.

Exactly when is an XML Schema actually used by the container because, in a sense, a UDT's type schema is already codified in its serializer class? The answer is: The schema is not used when a service call is made and fulfilled. It is used only in generating a service's WSDL file. However, a UDT schema is still required regardless of whether you do or do not need the WSDL file.

Writing Serializers and Deserializers

A serializer converts a Java object to XML representation, and a deserializer converts an XML document to a Java object. The characteristics of WebLogic/JAX-RPC serializers are as follows :

  • You write one class that contains a serialize and a deserialize method (with prescribed signatures, of course).

  • The class must extend weblogic.webservice.encoding.AbstractCodec .

  • The naming convention (optional) for a serializer class is udt-name Codec.java , where udt-name is the user-defined class name.

  • Because the WebLogic Web service runtime knows each UDT's serializer class (from type mappings in web-services.xml ), the serialize and deserialize methods are automatically called at the appropriate times. The only exception to this rule occurs when a serializer class must also serialize an embedded UDT. In this case, it is the enclosing UDT that invokes its member UDT's serializer class, not the WebLogic container.

Now look at a sample serializer class for the Employee user-defined type, as shown in Listing 30.6.

Listing 30.6 Sample Serializer Class for the Employee User-Defined Type
 package examples.newTypes; import weblogic.webservice.encoding.AbstractCodec; import weblogic.xml.schema.binding.DeserializationContext; import weblogic.xml.schema.binding.DeserializationException; import weblogic.xml.schema.binding.Deserializer; import weblogic.xml.schema.binding.SerializationContext; import weblogic.xml.schema.binding.SerializationException; import weblogic.xml.schema.binding.Serializer; import weblogic.xml.stream.Attribute; import weblogic.xml.stream.CharacterData; import weblogic.xml.stream.ElementFactory; import weblogic.xml.stream.EndElement; import weblogic.xml.stream.StartElement; import weblogic.xml.stream.XMLEvent; import weblogic.xml.stream.XMLInputStream; import weblogic.xml.stream.XMLName; import weblogic.xml.stream.XMLOutputStream; import weblogic.xml.stream.XMLStreamException; public final class EmployeeCodec extends weblogic.webservice.encoding.AbstractCodec { public void serialize(Object obj, XMLName name, XMLOutputStream writer, SerializationContext context) throws SerializationException { Employee emp = (Employee) obj; try { //outer start element <Employee> writer.add(ElementFactory.createStartElement(name)); //employee name element writer.add(ElementFactory.createStartElement("fullname")); writer.add(ElementFactory.createCharacterData(emp.getName())); writer.add(ElementFactory.createEndElement("fullname")); //employee id element writer.add(ElementFactory.createStartElement("id")); String id_string = Integer.toString(emp.getId()); writer.add(ElementFactory.createCharacterData(id_string)); writer.add(ElementFactory.createEndElement("id")); //outer end element </Employee> writer.add(ElementFactory.createEndElement(name)); } catch(XMLStreamException xse) { throw new SerializationException("stream error", xse); } } public Object deserialize(XMLName name, XMLInputStream reader, DeserializationContext context) throws DeserializationException { // extract the desired information out of reader, consuming the // entire element representing the type, // construct your object, and return it. Employee employee = new Employee(); try { if (reader.skip(name, XMLEvent.START_ELEMENT)) { StartElement top = (StartElement)reader.next(); //next start element should be the employee name if (reader.skip(XMLEvent.START_ELEMENT)) { StartElement emp_name = (StartElement)reader.next(); //assume that the next element is our name character data CharacterData cdata = (CharacterData) reader.next(); employee.setName(cdata.getContent()); } else { throw new DeserializationException("employee name not found"); } //next start element should be the employee id if (reader.skip(XMLEvent.START_ELEMENT)) { StartElement emp_id = (StartElement)reader.next(); //assume that the next element is our id character data CharacterData cdata = (CharacterData) reader.next(); employee.setId(Integer.parseInt(cdata.getContent())); } else { throw new DeserializationException("employee id not found"); } //we must consume our entire element to leave the stream in a //good state for any other deserializer if (reader.skip(name, XMLEvent.END_ELEMENT)) { XMLEvent end = reader. next (); } else { throw new DeserializationException("expected end element not found"); } } else { throw new DeserializationException("expected start element not found"); } } catch (XMLStreamException xse) { throw new DeserializationException("stream error", xse); } return employee; } 

The following is the serialize method signature:

 
 public void serialize(Object obj, XMLName name, XMLOutputStream writer, SerializationContext context) throws SerializationException 

The following are the parameters:

  • Object is the Java object to be converted to XML.

  • XMLName is the top-level element name of the resulting XML.

  • XMLOutputStream is a writer in the WebLogic XML streaming API, and is the place where the converted XML elements will be written.

  • SerializationContext is used for maintaining context across embedded serialize calls. For example, if your UDT contains a member UDT2 , you will need to call UDT2 's serialize method and pass this same SerializationContext onward. Do not in any way change this object.

Now look at the deserializer method signature:

 
 public Object deserialize(XMLName name, XMLInputStream reader, DeserializationContext context) throws DeserializationException 

The following are the parameters:

  • XMLName is the top-level element name of the XML code to be converted.

  • XMLInputStream is a reader in the WebLogic XML streaming API. The XML you want to convert is contained here.

  • DeserializationContext is used for maintaining context across embedded deserialize calls. For example, if a complexType contains a member complexType2 , you need to call complexType2 's deserialize method and pass this same DeserializationContext onward. Do not in any way change this object.

When you're converting an embedded user-defined type, there is no way to look up its serializer/deserializer class. You just need to hard-code any embedded serializer class invocations.

Defining Type Mappings in web-services.xml

The last step in this process is to state which serializer/deserializer class should be called for each user-defined type. If WebLogic Server is generating your serializer class, its type mapping will also be generated for you. Otherwise, you need to add a type-mapping section to web-services.xml , as illustrated in Figure 30.12. The <type-mapping> element starts this section and encompasses one or more <type-mapping-entry> subelements, as shown in Listing 30.7.

Listing 30.7 Type-Mapping Entry for User-Defined Type Employee
 <type-mapping> <type-mapping-entry class-name="examples.ws.Employee" xmlns:p1="java:examples.webservices" type="p1:Employee" serializer="examples.ws.EmployeeCodec" deserializer="examples.ws.EmployeeCodec" > </type-mapping-entry> </type-mapping> 

The following are the parameters:

  • class-name is the fully-qualified Java class of the user-defined type.

  • type points to the XML Schema that describes the user-defined type. Note that the Employee type needs to be namespace qualified; hence, a namespace definition in the preceding line is necessary (unless it is in the default namespace of the web-services.xml file). This namespace definition value must match the one used in the XML Schema definition, shown in Listing 30.5.

  • serializer is the fully qualified Java class which contains a serialize method that converts data from Java to XML.

  • deserializer is the fully qualified Java class which contains a deserializer method that converts data from XML to Java objects.

You can specify multiple type-mapping entries, one for each of your user-defined classes. WebLogic Server presumes that your serializer class produces the correct Java object or XML document. It cannot verify correctness of your custom-created serializer class at build or deploy time.

Also, ServiceGen will not copy your custom serializer/deserializer classes into the ear file, and if you specify an input type mapping file, it will assume that there is no need to generate serializer/deserializer classes for the types that are already mapped.



BEA WebLogic Platform 7
BEA WebLogic Platform 7
ISBN: 0789727129
EAN: 2147483647
Year: 2003
Pages: 360

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net