VisiBroker for Java Developer’s Guide : Using valuetypes

Using valuetypes
This section explains how to use the valuetype IDL type in VisiBroker.
Understanding valuetypes
The valuetype IDL type is used to pass state data over the wire. A valuetype is best thought of as a struct with inheritance and methods. Valuetypes differ from normal interfaces in that they contain properties to describe the valuetype's state, and contain implementation details beyond that of an interface.
Valuetype IDL code sample
The following IDL code declares a simple valuetype:
module Map {
valuetype Point {
public long x;
public long y;
private string label;
factory create (in long x, in long y, in string z);
void print();
};
};
Valuetypes are always local. They are not registered with the VisiBroker ORB, and require no identity, as their value is their identity. They can not be called remotely.
Concrete valuetypes
Concrete valuetypes contain state data. They extend the expressive power of IDL structs by allowing:
Valuetype derivation
You can derive a concrete valuetype from one other concrete valuetype. However, valuetypes can be derived from multiple other abstract valuetypes.
Sharing semantics
Valuetype instances can be shared by other valuetypes across or within other instances. Other IDL data types such as struct, union, or sequence cannot be shared. Valuetypes that are shared are isomorphic between the sending context and the receiving context.
In addition, when the same valuetype is passed into an operation for two or more arguments, the receiving context receives the same valuetype reference for both arguments.
Null semantics
Null valuetypes can be passed over the wire, unlike IDL data types such as structs, unions, and sequences. For instance, by boxing a struct as a boxed valuetype, you can pass a null value struct. For more information, see “Boxed valuetypes”.
Factories
Factories are methods that can be declared in valuetypes to create valuetypes in a portable way. For more information on Factories, see “Implementing factories”.
Abstract valuetypes
Abstract valuetypes contain only methods and do not have state. They may not be instantiated. Abstract valuetypes are a bundle of operation signatures with a purely local implementation.
For instance, the following IDL defines an abstract valuetype Account that contains no state, but one method, get_name:
abstract valuetype Account{
string get_name();
}
Now, two valuetypes are defined that inherit the get_name method from the abstract valuetype:
valuetype savingsAccount:Account{
private long balance;
}
valuetype checkingAccount:Account{
private long balance;
}
These two valuetypes contain a variable balance, and they inherit the get_name method from the abstract valuetype Account.
Implementing valuetypes
To implement valuetypes in an application, do the following:
1
2
3
4
Implement the Factory class to implement any factory methods defined in IDL.
5
Implement the create_for_unmarshal method.
6
7
Either implement the _add_ref, _remove_ref, and _ref_countvalue methods or derive from CORBA::DefaultValueRefCountBase.
Defining your valuetypes
In the IDL sample (for more information, see “Valuetype IDL code sample”), you define a valuetype named Point that defines a point on a graph. It contains two public variables, the x and y coordinates, one private variable that is the label of the point, the valuetype's factory, and a print method to print the point.
Compiling your IDL file
When you have defined your IDL, compile it using idl2java to create source files. You then modify the source files to implement your valuetypes.
If you compile the IDL shown in “Valuetype IDL code sample”, your output consists of the following files:
Inheriting the valuetype base class
After compiling your IDL, create your implementation of the valuetype. The implementation class will inherit the base class. This class contains the constructor that is called in your ValueFactory, and contains all the variables and methods declared in your IDL.
In the obv\PointImpl.java, the PointImpl class extends the Point class, which is generated from the IDL.
Inheriting the valuetype base class:
public class PointImpl extends Point {
public PointImpl() {}
public PointImpl(int a_x, int a_y, String a_label) {
x = a_x;
y = a_y;
label = a_label;
}
public void print () {
System.out.println("Point is [" + label + ": (" + x + ", " + y + ")]");
}
}
Implementing the Factory class
When you have created an implementation class, implement the Factory for your valuetype.
In the following example, the generated Point_init class contains the create method declared in your IDL. This class extends org.omg.CORBA.portable.ValueFactory . The PointDefaultFactory class implements PointValueFactory as shown in the following example.
public class PointDefaultFactory implements PointValueFactory {
public java.io.Serializable read_value (org.omg.CORBA.portable.InputStream is) {
java.io.Serializable val = new PointImpl(); // Called the implementation
class
// create and initialize value
val = ((org.omg.CORBA_2_3.portable.InputStream)is).read_value(val);
return val;
}
// It is up to the user to implement the valuetype however they want:
public Point create (int x,
int y,
java.lang.String z) {
// IMPLEMENT:
return null;
}
}
PointImpl() is called to create a new valuetype, which is read in from the InputStream by read_value.
You must call read_value or your Factory will not work, and you may not call any other method.
Registering your Factory with the VisiBroker ORB
To register your Factory with the VisiBroker ORB, call ORB.register_value_factory. This is required only if you do not name your factory valuetypenameDefaultFactory. For more information on registering Factories, see “Registering valuetypes”.
Implementing factories
When the VisiBroker ORB receives a valuetype, it must first be demarshaled, and then the appropriate factory for that type must be found in order to create a new instance of that type. Once the instance has been created, the value data is unmarshaled into the instance. The type is identified by the RepositoryID that is passed as part of the invocation. The mapping between the type and the factory is language specific.
VisiBroker version 4.5 or later version will generate the correct signatures for either the JDK 1.3 or JDK 1.4 default value factory method. Existing (version 4.0) generated code is not designed to run under JDK 1.3, unless you modify the default value factory method signature as shown below. If you use your existing code with JDK 1.3 and do not modify default value factory, the code will not compile or will throw a NO_IMPLEMENT exception. Consequently, we recommend that you regenerate your code to generate the correct signatures.
The following code sample shows how you should modify the default value factory method signature to make sure that it compiles under JDK 1.3:
public class PointDefaultFactory implements PointValueFactory {
public java.io.Serializable read_value (
org.omg.CORBA_2_3.portable.InputStream is
) {
java.io.Serializable val = new PointImpl();
// create and initialize value
// It is very important that this call is made.
val = ((org.omg.CORBA_2_3.portable.InputStream)is).read_value(val);
return val;
}
public Point create (int x, int y, java.lang.String z) {
// IMPLEMENT:
return NO_IMPLEMENT;
}
}
Factories and valuetypes
When the VisiBroker ORB receives a valuetype, it will look for that type's factory. It will look for a factory named <valuetype>DefaultFactory. For instance, the Point valuetype's factory is called PointDefaultFactory. If the correct factory doesn't conform to this naming schema (<valuetype>DefaultFactory), you must register the correct factory so the VisiBroker ORB can create an instance of the valuetype.
If the VisiBroker ORB cannot find the correct factory for a given valuetype, a MARSHAL exception is raised, with an identified minor code.
Registering valuetypes
Each language mapping specifies how and when registration occurs. If you created a factory with the <valuetype>DefaultFactory naming convention, this is considered implicitly registering that factory, and you do not need to explicitly register your factory with the VisiBroker ORB.
To register a factory that does not conform to the <valuetype>DefaultFactory naming convention, call register_value_factory. To unregister a factory, call unregister_value_factory on the VisiBroker ORB. You can also lookup a registered valuetype factory by calling lookup_value_factory on the VisiBroker ORB.
Boxed valuetypes
Boxed valuetypes allow you to wrap non-value IDL data types as valuetypes. For example, the following IDL boxed valuetype declaration,
valuetype Label string;
is equivalent to this IDL valuetype declaration:
valuetype Label{
public string name;
}
By boxing other data types as valuetypes, it allows you to use valuetype's null semantics and sharing semantics.
Valueboxes are implemented purely with generated code. No user code is required.
Abstract interfaces
Abstract interfaces allow you to choose at runtime whether the object will be passed by value or by reference.
Abstract interfaces differ from IDL interfaces in the following ways:
Abstract interfaces do not implicitly derive from org.omg.CORBA.Object because they can represent either object references or valuetypes. Valuetypes do not necessarily support common object reference operations. If the abstract interface can be successfully narrowed to an object reference type, you can invoke the operations of org.omg.CORBA.Object .
For example, examine the following abstract interface.
abstract interface ai{
};
interface itp : ai{
};
valuetype vtp supports ai{
};
interface x {
void m(ai aitp);
};
valuetype y {
void op(ai aitp);
};
For the argument to method m:
itp is always passed as an object reference.
vtp is passed as a value.
Custom valuetypes
By declaring a custom valuetype in IDL, you bypass the default marshalling and unmarshalling model and are responsible for encoding and decoding.
custom valuetype customPoint{
public long x;
public long y;
private string label;
factory create(in long x, in long y, in string z);
};
You must implement the marshal and unmarshal methods from the CustomMarshal interface.
When you declare a custom valuetype, the valuetype extends org.omg.CORBA.portable. CustomValue, as opposed to org.omg.CORBA.portable.StreamableValue, as in a regular valuetype. The compiler does not generate read or write methods for your valuetype.
You must implement your own read and write methods by using org.omg.CORBA. portable.DataInputStream and org.omg.CORBA.portable.DataOutputStream to read and write the values, respectively.
Truncatable valuetypes
Truncatable valuetypes allow you to treat an inherited valuetype as its parent.
The following IDL defines a valuetype checkingAccount that is inherited from the base type Account and can be truncated in the receiving object.
valuetype checkingAccount: truncatable Account{
private long balance;
}
This is useful if the receiving context doesn't need the new data members or methods in the derived valuetype, and if the receiving context isn't aware of the derived valuetype. However, any state data from the derived valuetype that isn't in the parent data type will be lost when the valuetype is passed to the receiving context.
Note
You cannot make a custom valuetype truncatable.