A Managed Object is defined using annotation. Managed Objects provide:
shared memory persistence
location transparent distributed access
optionally highly available replication
Managed Objects can only be manipulated in an ActiveSpaces® Transactions transaction. See Chapter 4, Transactions for more details on transactions.
Here is an example of a Managed Object that is persisted in shared memory.
Example 5.1. Managed object
// $Revision: 1.1.2.1 $ package com.kabira.snippets.managedobjects; import com.kabira.platform.annotation.*; /** * Defining a managed object * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = A * </ul> */ @Managed public class Manage { /** * Name is stored in shared memory */ public String name; }
No additional annotation is required for a managed object to be distributed or highly available.
The @Managed
annotation is defined in
Example 5.2, “@Managed annotation” along with its usage.
Example 5.2. @Managed annotation
package com.kabira.platform.annotation; import java.lang.annotation.*; /** * Marks a class as being a Managed Object - a shared memory * backed class. Any class that extends a Managed class is * also considered Managed. */ @Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Managed { /** * Set the allocation space reserved for this object. Default is 0, * which causes the system to calculate a default size. */ long allocationSpaceBytes() default 0; /** * Dynamically allocate/deallocate the transaction lock memory for * this object, whenever it is locked in a transaction. * This will save approximately 112 bytes per object, when the * object is not locked. * The default is false, which causes the system to allocate the * lock memory once at object create time, and increases performance * by simplifying the work that the system needs to do whenever * the object is locked and unlocked. */ boolean dynamicLockMemory() default false; } // // Using the @Managed annotation // @Managed class Managed { ... }
The @Managed
annotation is inherited by
sub-types. It is legal, but not required to specify
@Managed
on sub-types.
The supported types for fields in Managed Objects are:
Primitive Java types (int
,
long
, char
, etc.).
Primitive wrapper classes (Integer
,
Long
, Character
, etc.)
java.lang.String
Enumerations
Managed objects
Non-managed objects (See the section called “Non-managed object fields”)
Fields can be arrays of these types also.
Non-managed objects can be stored in a Managed Object field if the
field is annotated with a @ByReference
or a
@ByValue
annotation.
A managed object field annotated with the
@ByReference
annotation can store the handle to a
non-managed object. A managed object field annotated with
@ByReference
is called a by-reference
field. Example 5.3, “@ByReference annotation” shows
the @ByReference
annotation definition and its
use.
Example 5.3. @ByReference annotation
package com.kabira.platform.annotation; /** * Marks a field of a non-Managed object type for inclusion in a Managed class, * using copy-by-reference. This allows a Managed type to safely maintain a * reference to process-local resources. */ @Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ByReference { } // // Using the @ByReference annotation // class NotManaged { ... } @Managed class Managed { @ByReference NotManaged notManaged; }
By-reference fields only store local JVM handles to
non-managed objects. The object state is stored in the JVM heap.
Because of this, the stored objects are invalid on other JVMs. This
implies that non-managed objects stored in a by-reference field are
only visible in the JVM in which the field was set and they are also
not replicated when they are contained by a partitioned object.
By-reference fields are also not maintained across JVM
shutdown.
It is legal to store different non-managed objects in the same by-reference field in different JVMs on the same, or different nodes. If a by-reference field is never set on a JVM, null is returned when the field is accessed on that JVM.
Transaction locks are taken on the managed object when a by-reference field is accessed. However, no transaction locks are taken on the non-managed object.
See the section called “Managed object life cycle” for details on garbage collection for objects stored in by-reference fields.
A managed object field annotated with the
@ByValue
annotation stores the state of a
non-managed serializable object. A managed
object field annotated with @ByValue
is called a
by-value field. Example 5.4, “@ByValue annotation” shows the
@ByValue
annotation definition and its use. It is
an error to attempt to store a non-serializable object in a by-value
field.
Example 5.4. @ByValue annotation
package com.kabira.platform.annotation; /** * Marks a Serializable field for inclusion in a Managed class, * using copy-by-value. This allows a Managed type to easily maintain * a state for a non-Managed type that can be used across VMs and nodes. */ @Documented @Inherited @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface ByValue { } // // Using the @ByValue annotation // class Serializable implements java.io.Serializable { ... } @Managed class Managed { @ByValue Serializable serializable; }
By-value fields store the serialized state of a
non-managed object. Setting a by-value field performs a copy-in of the
state of the non-managed object. Getting a by-value field performs a
copy-out of the state of the non-managed object.
Non-managed objects stored in by-value fields are accessible in any JVM that has access to the containing managed object. The non-managed object is also replicated and is maintained across JVM shutdowns.
Transaction locks are taken on the managed object when a by-value field is accessed. However, no transaction locks are taken on the non-managed object.
Storing a non-managed object in a by-value field has no impact on when the object is garbage collected because only the object state is stored in the field, not a reference to the object itself.
The following audit rules are enforced on the
@ByReference
and @ByValue
annotations at class load time.
the annotations cannot be combined on a single field.
they cannot be specified on a static field.
they cannot be specified on an otherwise legal managed
object field type, e.g. Primitive types, Date
,
String
, etc.
Example 5.5, “Using non-managed object fields” shows the
use of the @ByReference
and
@ByValue
annotations to store non-managed objects
in a managed object field.
Example 5.5. Using non-managed object fields
// $Revision: 1.1.2.3 $ package com.kabira.snippets.managedobjects; import com.kabira.platform.Transaction; import com.kabira.platform.Transaction.Rollback; import com.kabira.platform.annotation.ByReference; import com.kabira.platform.annotation.ByValue; import com.kabira.platform.annotation.Managed; // // A storeByValue Java object // class StoreByValue implements java.io.Serializable { private static final long serialVersionUID = 1L; final String value = "serializable"; } // // A storeByReference heap object // class StoreByReference { final String value = "local"; } // // A managed object containing a by-value and a by-reference non-managed object // @Managed class Container { @ByValue StoreByValue storeByValue; @ByReference StoreByReference storeByReference; } /** * Non-managed objects in managed object fields * <p> * <h2> Target Nodes</h2> * <ul> * <li> <b>domainnode</b> = A </li> * </ul> */ public class NonManagedFields { public static void main(String[] args) { new Transaction("Non-managed object fields") { @Override protected void run() throws Rollback { Container container = new Container(); StoreByReference storeByReference = new StoreByReference(); StoreByValue storeByValue = new StoreByValue(); // // Store a non-managed object by-reference // container.storeByReference = storeByReference; StoreByReference afterByReference = container.storeByReference; System.out.println("INFO: by-reference before - " + storeByReference.toString()); System.out.println("INFO: by-reference after - " + afterByReference.toString()); // // Store a non-managed object by-value // container.storeByValue = storeByValue; StoreByValue afterByValue = container.storeByValue; System.out.println("INFO: by-value before - " + storeByValue.toString()); System.out.println("INFO: by-value after - " + afterByValue.toString()); } }.execute(); } }
When this snippet is run it outputs the following (annotation added):
// // Notice that the object handles are identical. This is because // by-reference fields return the same object when accessed // [A] INFO: by-reference before - com.kabira.snippets.managedobjects.StoreByReference@40363068 [A] INFO: by-reference after - com.kabira.snippets.managedobjects.StoreByReference@40363068 // // Notice that the object handle is different. This is because // of the serialization copy-in/copy-out for by-value fields // [A] INFO: by-value before - com.kabira.snippets.managedobjects.StoreByValue@600dac21 [A] INFO: by-value after - com.kabira.snippets.managedobjects.StoreByValue@767a9224
Static fields are stored locally per JVM, they are not stored in shared memory. This means that the values of static fields are different per JVM. Static field values are also not marshaled to remote nodes for distributed objects.
Example 5.6. Static fields in a managed object
// $Revision: 1.1.2.1 $ package com.kabira.snippets.managedobjects; import com.kabira.platform.annotation.Managed; /** * Static fields in a managed object */ @Managed class StaticFields { // // Store counter in non-transactional JVM local memory // private static class Data { static int counter = 0; } /** * Return local JVM counter * @return Counter value */ int getCounter() { return Data.counter; } /** * Increment local JVM counter */ void incrementCounter() { Data.counter++; } }
Managed Objects have the following restrictions:
they cannot have any static
fields
(static final
fields are allowed).
finalize
cannot be implemented.
cannot extend a non-managed class that contains non-static fields, a non-managed class with only static final fields can be extended.
all fields must be a supported type.
fields cannot use the transient
modifier.
cannot define a serialPersistentFields
field.
all array fields must be of a supported type.
cannot implement the java.io.Externalizable
interface.
@Managed
cannot be specified on
interfaces.
@Managed
cannot be used on classes that
extend
or
Enum
Throwable
.
A @Managed
class can be defined as an inner
class only if it is marked static
. The following
class is legal:
class Outer { @Managed public static class Inner {...} }
the size of a string field is limited by the maximum supported
shared memory allocation size. This size may be found by finding the
Largest supported allocation size
in the
Statistics allocator summary display.
the number of elements in an array field of primitive types is limited by the maximum supported shared memory allocation size divided by the number of bytes in the primitive type.
the number of elements in an array of strings field is limited by the maximum supported shared memory allocation size divided by 32.
the number of elements in an array of arrays field is limited by the maximum supported shared memory allocation size divided by 84.
the number of elements in an array of Managed Object fields is limited by the maximum supported shared memory allocation size divided by 24.
Managed Object restrictions are audited when the class is loaded.
If any Managed Objects in a class fail audit a
java.lang.ClassNotFoundException
is thrown and the
class fails to load.
Managed Objects being accessed remotely (distributed Managed Objects) have these additional restrictions on their method signatures:
return values must be one of the supported types (see the section called “Supported field types”), or a serializable object.
method parameters must be one of the supported types (see the section called “Supported field types”), or serializable object.
the elements of arrays used for method parameters must be one of the supported types (see the section called “Supported field types”), or a serializable object.
the elements of arrays used for method return values must be one of the supported types (see the section called “Supported field types”), or a serializable object.
If a method signature does not support distribution because one
of the method signature restrictions is violated, the class will load
with a warning message. If the method is called on a remote object a
java.lang.UnsupportedOperationException
is thrown
when the method is executed.
In addition, non-managed object method parameters cannot be
null, this includes auto-box types, String
,
Date
, and serializable
objects. Passing a null non-managed object parameter causes a
java.lang.IllegalArgumentException
to be thrown
when the method is called.