Upgrade utility

The upgrade utility is used to generate an upgrade plan based on a detailed analysis of class changes. The generated upgrade plan is used to deploy the upgraded class files. A complete reference for the upgrade utility can be found in the section called “Upgrade utility”. Example 8.2, “Initial class definition” shows a simple Person class definition.

Example 8.2. Initial class definition

package com.kabira.snippets.upgrade;

import com.kabira.platform.annotation.Managed;

@Managed
public class Person
{
    Person()
    {
        name = "Patti Smith";
        age = 64;
    }
    String  name;
    short   age;
}

Example 8.3, “Updated class definition” shows an updated Person class with these changes:

The new Person class was also updated to implement Serializable, ObjectMismatchTrigger, and to add a serialVersionUID as described in the section called “Changing a class”.

Example 8.3. Updated class definition

//     $Revision: 1.1.2.1 $
package com.kabira.snippets.upgrade;

import com.kabira.platform.ManagedObjectStreamClass;
import com.kabira.platform.ObjectMismatchTrigger;
import com.kabira.platform.annotation.Managed;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamField;
import java.io.Serializable;


/*
//
//   Original class
//
@Managed
public class Person
{
    Person()
    {
        name = "Patti Smith";
        age = 64;
    }
    String  name;
    short   age;
}
 */

//
//  New parent type
//
@Managed
class Animal
{
    Animal()
    {
        type = "Human";
    }
    String type;
}

//
//   Updated class definition
//
public class Person extends Animal
    implements Serializable, ObjectMismatchTrigger
{
    Person()
    {
        first = "Patti";
        last = "Smith";
        age = 64;
    }

    @Override
    public void writeObjectToStream(
        ManagedObjectStreamClass remoteClassDescriptor,
        ObjectOutputStream out) throws IOException
    {
        System.out.println("writeObjectToStream: "
            + remoteClassDescriptor.getName());

        //
        //  Output old and new version numbers
        //
        System.out.println("\tOld Class Version: "
            + remoteClassDescriptor.getSerialVersionUID());
        System.out.println("\tNew Class Version: " + serialVersionUID);

        //
        //  Write fields to old version of class using ManagedObjectStreamClass
        //
        for (ObjectStreamField f : remoteClassDescriptor.getFields())
        {
            //
            //  If name field, concatenate first and last name in new version
            //
            if (f.getName().equals("name"))
            {
                System.out.println("\t\tname field: " + first + " " + last);
                out.writeObject(first + " " + last);
            }
            //
            //  If age field, map to short.  This may truncate the age of
            //  _very_ old people
            //
            else if (f.getName().equals("age"))
            {
                System.out.println("\t\tage field: " + age);
                short oldAge = age.shortValue();
                out.writeShort(oldAge);
            }
        }
    }

    @Override
    public void readObjectFromStream(
        ManagedObjectStreamClass remoteClassDescriptor,
        ObjectInputStream in) throws IOException
    {
        System.out.println("readObjectFromStream: "
            + remoteClassDescriptor.getName());

        //
        //  Output old and new version numbers
        //
        System.out.println("\tOld Class Version: "
            + remoteClassDescriptor.getSerialVersionUID());
        System.out.println("\tNew Class Version: " + serialVersionUID);

        //
        //  Read fields from the old version of the class using 
        //  ObjectInputStreamGetField to access the fields
        //
        try
        {
            ObjectInputStream.GetField fields = in.readFields();

            //
            //  Get name field
            //
            String name = (String) fields.get("name", "");

            System.out.println("\t\tname: " + name);
            String[] values = name.split(" ");
            first = values[0];
            last = values[1];

            //
            //  Get age field
            //
            Short previousAge = fields.get("age", (short)0);
            age = previousAge.intValue();
            System.out.println("\t\tage: " + age);
        }
        catch (ClassNotFoundException ex)
        {
            System.out.println("ERROR: " + ex.getMessage());
        }
        
        //
        //  Initialize new parent field
        //
        this.type = "Human";
    }
    private static final long serialVersionUID = 1L;
    String first;
    String last;
    Integer age;
}

Running the upgrade utility on the old and new Person classes generates this output:

java -jar upgrade.jar current=original replacement=dist
1427 classes processed in 0.088 seconds.

Possible problems:
==================

com.kabira.snippets.upgrade.Animal
    Not found in the current JAR files. If this is a 
    new class, this is not a problem. If this is not a 
    new class, the class cannot be found in the current 
    JAR files and must be provided.


Changed classes:
================

Name: com.kabira.snippets.upgrade.Person
Current serialVerisonUID: Not Set
Replacement serialVersionUID: 1
Mismatch handling: Application
Transparent changes:
    Removed field name.
    Added field last.
    Added field first.
Non-transparent changes: 
    Inheritance modified.
    Type of field age changed.

Generated upgrade file: upgrade.111122

The possible problems section indicates that the com.kabira.snippets.upgrade.Animal class was not found in the previous version. This is expected because this is a new class. The upgrade utility reports this as a possible problem because it cannot differentiate between a new class, or one that was not provided in the current JAR files.