Defining a managed object

A Managed Object is defined using annotation. Managed Objects provide:

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.

@Managed annotation

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.

Supported field types

The supported types for fields in Managed Objects are:

Fields can be arrays of these types also.

Non-managed object fields

Non-managed objects can be stored in a Managed Object field if the field is annotated with a @ByReference or a @ByValue annotation.

By-Reference Fields

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.

By-Value 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.

Audit rules

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.

Using non-managed object fields

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

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++;
    }
}


Restrictions

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 Enum or 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.

    Maximum allocation size

    Figure 5.1. Maximum allocation size


  • 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.

Distributed method signature restrictions

Managed Objects being accessed remotely (distributed Managed Objects) have these additional restrictions on their method signatures:

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.