Hi Paolo,

You will find the related documentation in the final Release of ULC 6.1
which will be available very soon.
(Unfortunately, it did not make it into the Milestone Release...)
In the following I just quote from Section 4.4 fot the upcoming Extension
Guide
document (see below).

Greetings,

Daniel

--------------------------------------------

As explained in Section 3.4.4 the ULC serialization infrastructure is in
charge of marshalling objects from the client to the server side and vice
versa. ULC supports a set of standard types, whose instances it can marshall
right away. However, sometimes it might be useful to marshall instances of
additional custom classes.
In this section we briefly demonstrate how to extend ULC serialization
infrastructure such that instances of custom classes can be marshalled.
The ULC serialization infrastructure is capable of changing the class type
of an object, which is serialized and afterwards deserialized. This feature
is necessary for some ULC classes, but it is unlikely to be used for custom
classes. Therefore, our example focuses on the case where the type of a
serialized object does not change during marshalling.
Suppose you want to marshall complex numbers, i.e., corresponding numbers
should be instances of the following class sample.ComplexNumber:

package sample;
import java.io.Serializable;

public class ComplexNumber implements Serializable {
    private final double fRealPart;
    private final double fImaginaryPart;

    public ComplexNumber(double realPart, double imaginaryPart) {
        fRealPart = realPart;
        fImaginaryPart = imaginaryPart;
    }

    public double getRealPart() {
        return fRealPart;
    }

    public double getImaginaryPart() {
        return fImaginaryPart;
    }

    // Add complex number arithmetic operations here...
}

ComplexNumber implements the standard Java serialization interface
java.io.Serializable. This is not strictly necessary because, as mentioned
in Section 3.4.4, ULC does not rely on Java's standard object serialization,
since the latter approach might incur performance and security problems.
However, it is still recommended to implement java.io.Serializable.
The next step is to provide an additional class, a so-called coder class,
which tells the ULC serialization infrastructure, how it must serialize and
deserialize a complex number. An instance of a coder class is simply called
a coder. A coder class must implement the interface
com.ulcjava.base.shared.IULCStreamCoder with the following three methods:
·       String getPeerClassName() returns the name of the class, of which ULC
creates an instance, when a marshalled object is deserialized. If the object
should not change its type during marshalling then this name is simply the
fully qualified class name of the serialized object itself.
If the marshalled object should change its type, then the returned name is
the fully qualified class name of the object after deserialization.
ULC writes the class name returned by getPeerClassName() as a string to the
stream before serializing the actual data of the respective object. The
written class name is used at deserialization time in order to determine the
coder for reading the data from the stream and therefore correctly
deserializing the object.
·       writeObject(IULCObjectOutput out, Object object) is in charge of
serializing the object, which is passed in as object. The implementation of
writeObject() must write all information from object, which is relevant for
marshalling, to the stream out. For this purpose, the interface
IULCObjectOutput offers methods to write primitive elements of object to the
stream, e.g. writeBoolean(boolean), writeInt(int), writeDouble(double) and
so on.
Moreover, IULCObjectOutput offers the method IULCObjectOutput
.writeObject(Object), which allows for serializing objects contained in
object to the stream. By standard, IULCObjectOutput.writeObject() is capable
of writing array structures, strings and the null value as contained objects
to the stream. If the object passed in to IULCObjectOutput.writeObject() is
not an array or a string or null, then the ULC serialization infrastructure
tries to find a coder for that object and applies the coder's writeObject()
method to it. Therefore, it is necessary that a related coder is implemented
and registered at the ULC serialization infrastructure. (The registration of
a coder will be discussed below.)
According to the previous paragraph, writing an object with contained
objects is a recursive process which involves coders associated with each of
the participating objects, which are being serialized. If there is cyclic
reference of objects to be serialized, then this recursive process will
cause an infinite loop, which results in a runtime exception. Besides, if
ULC cannot find a coder for a participating object, then it also throws a
runtime exception.
·       Object readObject(IULCObjectInput in) is in charge of deserializing an
object from the input stream in. The method readObject() must read the
serialized data in the same order from the in, as the data has been written
to the corresponding output stream before via writeObject(IULCObjectOutput,
Object). ULC invokes readObject() on a coder, which is associated with the
class name as given by getPeerClassName() at serialization time of the
marshalled object (see description of getPeerClassName() from above). By
contract, readObject() must return an instance of the class, whose name was
given by getPeerClassName() at serialization time.
To obtain data from the stream in, IULCObjectInput offers methods to read
primitive data, e.g. readBoolean(boolean), readInt(int), readDouble(int) and
so on. In addition, the method readObject() allows for reading of contained
objects, which were written to the stream via IULCObjectOutput.writeObject()
at serialization time. In short, the process of reading data from the input
stream is complementary to the above explained write process.
Given this background knowledge, the implementation of the coder class for
ComplexNumber, is straight-forward:

package sample;
import com.ulcjava.base.shared.IULCObjectInput;
import com.ulcjava.base.shared.IULCObjectOutput;
import com.ulcjava.base.shared.IULCStreamCoder;

import java.io.IOException;

public class ComplexNumberCoder implements IULCStreamCoder {
    // Since the type of a complex number does not change during
serialization
    // the peer class name is simply sample.ComplexNumber.
    public String getPeerClassName() {
        return ComplexNumber.class.getName();
    }

    public void writeObject(IULCObjectOutput out, Object data) {
        ComplexNumber c = (ComplexNumber)data;
        // Write the contained data: the real part and the imaginary part.
        out.writeDouble(c.getRealPart());
        out.writeDouble(c.getImaginaryPart());
    }

    public Object readObject(IULCObjectInput in) throws IOException {
        // Read the data from the stream: first the real part, then the
        // imaginary part, and return a corresponding deserialized complex
        // number object of type sample.ComplexNumber.
        return new ComplexNumber(in.readDouble(), in.readDouble());
    }
}

To make use of the new coder class, related coders must be registered at the
ULC serialization infrastructure. This must be done at both ends of the
communication line, namely at the client and the server side. The first step
for registration is to subclass the two standard classes, which provide a
coder registry. The subclasses must add entries for the complex number
coder.
For the client side, subclass DefaultClientCoderRegistryProvider in the
following way:

package sample;
import
com.ulcjava.base.client.streamcoder.DefaultClientCoderRegistryProvider;
import com.ulcjava.base.shared.CoderRegistry;

public class MyClientCoderRegistryProvider extends
    // Extend the client-side default coder registry provider.
    DefaultClientCoderRegistryProvider {
    // Override the method which initializes the registry.
    protected void initializeRegistry(CoderRegistry registry) {
        // Ensure that the standard client-side coders get
        // registered by invoking the super method.
        super.initializeRegistry(registry);
        // Register the new coder for ComplexNumber.
        registry.registerCoder(ComplexNumber.class, new
ComplexNumberCoder());
    }
}

For the server side, subclass DefaultServerCoderRegistryProvider in a
similar way:

package sample;
import
com.ulcjava.base.server.streamcoder.DefaultServerCoderRegistryProvider;
import com.ulcjava.base.shared.CoderRegistry;

public class MyServerCoderRegistryProvider extends
    // Extend the server-side default coder registry provider.
    DefaultServerCoderRegistryProvider {
    // Override the method which initializes the registry.
    protected void initializeRegistry(CoderRegistry registry) {
        // Ensure that the standard server-side coders get
        // registered by invoking the super method.
        super.initializeRegistry(registry);
        // Register the new coder for ComplexNumber.
        registry.registerCoder(ComplexNumber.class, new
ComplexNumberCoder());
    }
}

In addition, please ensure that ULC now makes use of the new coder registry
provider classes instead of the extended default classes. For this reason
ULC must be supplied with the class names of the new coder registry provider
classes on the client and the server side. How and where this information is
passed in to ULC, depends on the deployment types of the client and server
part of ULC. In the following, the server-side deployment as a Servlet and
the client-side deployment as an Applet and a JNLP application is discussed.
(For other details on deployment scenarios see the ULC Deployment Guide.)
With respect to a Servlet deployment, the name of the server-side coder
registry provider class must be added in the parameter section of the
web.xml file associated with the ULC application. The following code is a
typical extract of a related web.xml file. The extract defines the
parameters for a ULC application Servlet with a server-side application
class named sample.MyULCApplication. (The latter is expected to implement
com.ulcjava.base.application.IApplication.)

<servlet>
    <servlet-name>MyULCApplication</servlet-name>
    <servlet-class>
        com.ulcjava.container.servlet.server.ServletContainerAdapter
    </servlet-class>
    <init-param>
        <param-name>application-class</param-name>
        <param-value>sample.MyULCApplication</param-value>
    </init-param>
    <init-param>
        <param-name>log-level</param-name>
        <param-value>WARNING</param-value>
    </init-param>
    <init-param>
        <param-name>server-coder-registry-provider</param-name>
        <param-value>sample.MyServerCoderRegistryProvider</param-value>
    </init-param>
</servlet>

The interesting part of the extract is the last parameter section, which
defines the parameter server-coder-registry-provider and associates it with
the value sample.MyServerCoderRegistryProvider. This part instructs ULC not
to use the default coder registry provider on the server side but a custom
one, whose class name is given by the above extract.
To specify the client-side coder registry provider for an Applet deployment,
add a parameter entry in the HTML page's Applet tag section, which
references the corresponding ULC Applet. For the example from above, the
additional parameter entry looks as follows:

<PARAM name="client-coder-registry-provider"
       value="sample.MyClientCoderRegistryProvider">

In the case of a JNLP deployment, the same parameter must be defined in the
application descriptor section (application-desc) of the ULC-related JNLP
file. E.g., the application descriptor for the example from above might look
as follows:

<application-desc
    main-class="com.ulcjava.environment.jnlp.client.DefaultJnlpLauncher">
    <argument>url-string=$$context/myapplication.ulc</argument>
    <argument>keep-alive-interval=900</argument>
    <argument>log-level=WARNING</argument>
    <argument>client-coder-registry-provider=
              sample.MyClientCoderRegistryProvider</argument>
</application-desc>

Since the complex number class ComplexNumber and the related coder class
ComplexNumberCoder are needed on both the client and server side, they must
be accessible at both sides (e.g., by adding them to the corresponding jar
files). The class MyClientCoderRegistryProvider needs to become accessible
at the client (only) and MyServerCoderRegistryProvider needs to become
accessible at the server (only).

-----Original Message-----
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED] Behalf Of Paolo Scaffardi
Sent: Freitag, 12. Mai 2006 08:51
To: [email protected]
Subject: [ULC-developer] ULC 6.1 milestone: how to adding a new coder?


I created a new coder, but i dont know how to set my new server coder
registry provider when i deploy my app using the servlet container.

On the client side, inside my jnlp launcher i instanced a new connector
like this:

IConnector connector = new ServletConnector(
                new CookieRequestPropertyStore(url),
                url,
                keepAliveInterval,
                null,
                "myEnhancedClientCoderRegistryProvider"
              );

On the server side i tried adding this init parameter:

<init-param>
        <param-name>server-coder-registry-provider</param-name>
<param-value>myEnhancedServerCoderRegistryProvider</param-value>
</init-param>

But it seems the ServletContainerAdapterHelper dont like it a returns a
nullpointerexception when the clients tries connecting to it.

What's my fault?

Best regards,
Paolo Scaffardi
GFP Lab s.r.l.
http://www.gfplab.com
_______________________________________________
ULC-developer mailing list
[email protected]
http://lists.canoo.com/mailman/listinfo/ulc-developer

_______________________________________________
ULC-developer mailing list
[email protected]
http://lists.canoo.com/mailman/listinfo/ulc-developer

Reply via email to