Speedo Tutorial - Additional 2

 FinalLogo.jpg
 FinalLogo.jpg
  1. Object model
  2. Step 6 : attach/detach
  3. Step 7 : fetch plan

Back to the Speedo tutorial home page


    In this chapter, we will learn to use advanced jdo features such as the attach/detach and the fetch plan.

Object model

    Step 6 deals with the attach/detach feature. The attach/detach feature provides a way for an application to identify persistent instances, obtain copies of these persistent     instances, modify the detached instances either in the same JVM or in a different JVM, apply the changes to the same or different PersistenceManager, and commit the     changes.

    Step 7 deals with the fetch plan. The fetch plan feature enables to define particular loaded states for an object graph. It specifies fields to be loaded for all of the instances     in the graph.

    To illustrate both features, we use the following object model:
   

A Book is identified by its title. A Book has an author and an editor.
An author is identified by his name.
An Editor is identified by his name and has an address.
The PK of an Address is composed of its street and its zip code (we use an AddressId class).


The source code of the java classes is located in the org.objectweb.speedo.tutorial.pobjects.additional.detach package.


Let's have a look at the detach.jdo file :

<!DOCTYPE jdo PUBLIC "-//Sun Microsystems, Inc.//DTD Java Data Objects Metadata 1.0//EN"
"jdo.dtd">
<jdo>
<package name="org.objectweb.speedo.pobjects.tutorial.additional.detach">

<class name="Author" identity-type="application" detachable="true"> 1
<extension vendor-name="speedo" key="sql-name" value="T_ADDITIONAL_AUTHOR"/>
<field name="name" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="NAME"/>
</field>
</class>

<class name="Address" identity-type="application" objectid-class="org.objectweb.speedo.pobjects.tutorial.additional.detach.AddressId" detachable="true">
<extension vendor-name="speedo" key="sql-name" value="T_ADDITIONAL_ADDRESS"/>
<field name="street" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="STREET"/>
</field>
<field name="zipCode" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="ZIP"/>
</field>
<field name="city">
<extension vendor-name="speedo" key="sql-name" value="CITY"/>
</field>
</class>

<class name="Editor" identity-type="application" detachable="true">
<extension vendor-name="speedo" key="sql-name" value="T_ADDITIONAL_EDITOR"/>
<field name="name" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="NAME"/>
</field>
<field name="address">
<extension vendor-name="speedo" key="target-foreign-keys" value="STREET:A_STREET,ZIP:A_ZIP"/>
</field>
</class>

<class name="Book" identity-type="application" detachable="true">
<extension vendor-name="speedo" key="sql-name" value="T_ADDITIONAL_BOOK"/>
<field name="title" primary-key="true">
<extension vendor-name="speedo" key="sql-name" value="TITLE"/>
</field>
<field name="author" default-fetch-group="false">
<extension vendor-name="speedo" key="target-foreign-keys" value="NAME:AUTHOR_NAME"/>
</field>
<field name="editor" default-fetch-group="false">
<extension vendor-name="speedo" key="target-foreign-keys" value="NAME:EDITOR_NAME"/>
</field>
<field name="year">
<extension vendor-name="speedo" key="sql-name" value="YEAR"/>
</field>
<fetch-group name="onlyAuthor"> |
<field name="author"/> |
</fetch-group> |
<fetch-group name="editorName"> | 2
<fetch-group name="default"/> |
<field name="editor.name"/> |
</fetch-group> |
</class>

</package>
</jdo>  
    1 To perform a detach on instances of a class, the class has to be marked as detachable.
   
    2 A fetch group is defined at the class level:

    Within Speedo, four fetch groups are predefined:

  1. default:
  2.             The default group is based on the "default-fetch-group" attribute value of the field definition. It is composed of all the fields defined as belonging to the default fetch group in the jdo file.
                 The default group can be redefined as a normal fetch group by the user in the jdo files.
  3. values:
  4.             The values group is composed of all fields that are included in the default group by default (primitive fields, String, etc...).
                 As the default group, the values group can also be redefined by the user in the jdo files.
  5. none:
  6.             The none group contains only primary key fields.
  7. all:
  8.             The all group contains all fields in the class.
    You can define your own fetchgroups as done for the "onlyAuthor" and "editorName" fetchgroups.
    Speedo loads automatically all the primitive fields: there is no need to define these fields as being part of a fetchgroup.
    Fetchgroups are useful for reference fields.
    For instance, with the onlyAuthor fetchgroup, when a Book is loaded, the fields title, author and year are loaded. The field editor is not loaded. For the field author, as no fetchgroup is             defined for the Author class, the default fetchgroup is taken into account: the fields street, zipcode and city are loaded.
    With the editorName fetchgroup, when a Book is loaded, the fields title, year and editor are loaded, the field author is not. For the field editor, only the name field is loaded, the address         field is not loaded.  
    Fetchgroups are activated via the fetch plan belonging to the persistence manager used.
    For more information about fetchgroups have a look at the fetchgroup section of the user manual.

    Top


Step 6: attach/detach

   In this step, we are going to detach persistent objects from the application, modify and re-attach them.

   In the detachObject method, we create a book with its author and its editor, make it persistent and detach it. We get a detached copy of the persistent object that can be    used in a different JVM. Note that the detach operation can be performed inside or outside a transaction:

/**
* detach persistent objects
*/
public static void detachObject(PersistenceManager pm){
Author author = new Author("Henry Miller");
Address address = new Address("Coronation Street", "811XBA", "Manchester");
Editor editor = new Editor("Grasset", address);
Book book = new Book("Tropic of Capricorn", author, editor, 1939);

//make the book persistent
pm.currentTransaction().begin();
System.out.println( "make persistent the book " + book.toString());
pm.makePersistent(book);
pm.currentTransaction().commit();

//detach the book
Book copyOfBook = (Book) pm.detachCopy(book);
System.out.println("The detached version of the book is as follows:\n " + copyOfBook.toString());
}

   In the attachObject method, we make a book persistent, detach it, modify the detached copy and re-attach this changed copy. The changed copy is made persistent on        the datastore:
   
/**
* detach persistent object
* modify it
* then re-attach it
*/
public static void attachObject(PersistenceManager pm){
Author author = new Author("Hubert Selby Jr");
Address address = new Address("Sharrow Street", "911ZB2", "Sheffield");
Editor editor = new Editor("Folio", address);
Book book = new Book("The willow tree", author, editor, 1999);

//make the book persistent
pm.currentTransaction().begin();
System.out.println( "make persistent the book " + book.toString());
pm.makePersistent(book);
pm.currentTransaction().commit();

//detach the book
Book copyOfBook = (Book) pm.detachCopy(book);
System.out.println("The detached version of the book is as follows:\n " + copyOfBook.toString());

//modify the book
copyOfBook.setYear(2012);
copyOfBook.getEditor().getAddress().setCity("New York");
System.out.println( "Copy of the book " + copyOfBook.toString());

//attach the book
pm.currentTransaction().begin();
Book attachedBook = (Book) pm.attachCopy(copyOfBook,false);
pm.currentTransaction().commit();
System.out.println("The attached version of the book is as follows:\n " + attachedBook.toString());
}
    To launch the step 6:
   You can view the results of the detach method in your database via the DatabaseManager (see Tutorial Environment): table T_ADDITIONAL_BOOK:



    Top


Step 7: fetch plan

   In this step, we are going to detach persistent objects from the application activating the predefined fetch groups and the ones defined in the detach.jdo.

   In the usePredefinedFetchGroups, we:
/**
* Detach objects with the predefined fetchgroups:
* default
* all
*/
public static void usePredefinedFetchGroups(PersistenceManager pm){
//get the pm fetch plan
FetchPlan fp = pm.getFetchPlan();

//create a book
Author author = new Author("William S. Burroughs");
Address address = new Address("Fenton Street", "931ZR2", "Leeds");
Editor editor = new Editor("Mille et Une Nuits", address);
Book book = new Book("The Yage Letters", author, editor, 1955);

//make the book persistent
pm.currentTransaction().begin();
System.out.println( "make persistent the book " + book.toString());
pm.makePersistent(book);
pm.currentTransaction().commit();

//detach the book --> "default" fetch group
//fields title and year are loaded
// fields editor and author are not loaded
Book defaultBook = (Book) pm.detachCopy(book);
System.out.println( "With the default fetchgroup:");
try{
System.out.println( "Title can be accessed: " + defaultBook.getTitle());
System.out.println( "Year can be accessed: " + defaultBook.getYear());
System.out.println( "Author should not be accessed: " + defaultBook.getAuthor().toString());
System.out.println( "Editor should not be accessed: " + defaultBook.getEditor().toString());
}
catch(Exception e){
if(e instanceof JDODetachedFieldAccessException && e.getMessage().indexOf("author") != -1)
System.out.println( "Correct exception caught: " + e.getMessage());
else
System.out.println( "Error: " + e);
}

//detach the book --> "all" fetch group
//all fields are loaded
fp.addGroup("all").removeGroup("default");
Book allBook = (Book) pm.detachCopy(book);
System.out.println( "With the all fetchgroup:");
try{
System.out.println( "Title can be accessed: " + allBook.getTitle());
System.out.println( "Year can be accessed: " + allBook.getYear());
System.out.println( "Author can be accessed: " + allBook.getAuthor().toString());
System.out.println( "Editor can be accessed: " + allBook.getEditor().toString());
}
catch(Exception e){
System.out.println( "Error: " + e);
}
}
     The execution of this method gives these results:
   
[java] make persistent the book The Yage Letters, author=[William S.Burroughs], editor=[Mille et Une Nuits, address=[Fenton Street, 931ZR2,Leeds]], 1955
 

[java] With the default fetchgroup:
[java] Title can be accessed: The Yage Letters
[java] Year can be accessed: 1955
[java] Correct exception caught: Field author cannot be accessed: not loaded when the object has been detached

[java] With the all fetchgroup:
[java] Title can be accessed: The Yage Letters
[java] Year can be accessed: 1955
[java] Author can be accessed: William S. Burroughs
[java] Editor can be accessed: Mille et Une Nuits, address=[Fenton Street, 931ZR2, Leeds]
   

    In the useDefinedFetchGroups, we:
/**
* Detach objects with user-defined fetchgroups (see the detach.jdo file)
*/
public static void useDefinedFetchGroups(PersistenceManager pm){
//get the pm fetch plan
FetchPlan fp = pm.getFetchPlan();

//create a book
Author author = new Author("John Fante");
Address address = new Address("South Street", "211ZL2", "York");
Editor editor = new Editor("Plon", address);
Book book = new Book("Bandini", author, editor, 1938);

//make the book persistent
pm.currentTransaction().begin();
System.out.println( "make persistent the book " + book.toString());
pm.makePersistent(book);
pm.currentTransaction().commit();

//detach the book --> "onlyAuthor" fetch group
//fields title year and author are loaded
// fields editor is not loaded
fp.addGroup("onlyAuthor").removeGroup("default");
Book onlyAuthorBook = (Book) pm.detachCopy(book);
System.out.println( "With the onlyAuthor fetchgroup:");
try{
System.out.println( "Title can be accessed: " + onlyAuthorBook.getTitle());
System.out.println( "Year can be accessed: " + onlyAuthorBook.getYear());
System.out.println( "Author can be accessed: " + onlyAuthorBook.getAuthor().toString());
System.out.println( "Editor should not be accessed: " + onlyAuthorBook.getEditor().toString());
}
catch(Exception e){
if(e instanceof JDODetachedFieldAccessException && e.getMessage().indexOf("editor") != -1)
System.out.println( "Correct exception caught: " + e.getMessage());
else
System.out.println( "Error: " + e);
}

//detach the book --> "editorName" fetch group
//fields title, year, editor.name are loaded
//fields author, editor.address are not loaded
fp.addGroup("editorName").removeGroup("onlyAuthor");
Book editorNameBook = (Book) pm.detachCopy(book);
System.out.println( "With the editorName fetchgroup:");
try{
System.out.println( "Title can be accessed: " + editorNameBook.getTitle());
System.out.println( "Year can be accessed: " + editorNameBook.getYear());
System.out.println( "Editor name can be accessed: " + editorNameBook.getEditor().getName());
System.out.println( "Editor address should not be accessed: " + editorNameBook.getEditor().getAddress().toString());
System.out.println( "Author should not be accessed: " + editorNameBook.getAuthor().toString());
}
catch(Exception e){
if(e instanceof JDODetachedFieldAccessException && e.getMessage().indexOf("address") != -1)
System.out.println( "Correct exception caught: " + e.getMessage());
else
System.out.println( "Error: " + e);
}
}
    The execution of the method gives these results:
   
[java] make persistent the book Bandini, author=[John Fante], editor=[Plon, address=[South Street, 211ZL2, York]], 1938

[java] With the onlyAuthor fetchgroup:
[java] Title can be accessed: Bandini
[java] Year can be accessed: 1938
[java] Author can be accessed: John Fante
[java] Correct exception caught: Field editor cannot be accessed: not loaded when the object has been detached

[java] With the editorName fetchgroup:
[java] Title can be accessed: Bandini
[java] Year can be accessed: 1938
[java] Editor name can be accessed: Plon
[java] Correct exception caught: Field address cannot be accessed: not loaded when the object has been detached
    To launch the step 7:
   You can view the results of the fetchPlan method in your database via the DatabaseManager (see Tutorial Environment): table T_ADDITIONAL_BOOK:



    Top

Step BackFollowing step