Table of Contents

Modifying Persistent Objects

Retrieving and Modifying Persistent Objects

We have seen a number of examples of how to retrieve named persistent objects from the repository by looking them up in the Facets Naming Service. Changing persistent objects is as simple as making changes to plain old Java objects, with the proviso, that if the changes are to be persistent, they must be made within the scope of a transaction. Only changes that are made within a transaction can be made permanent. Aborting a transaction prior to committing it will reverse all of the changes that were made during the scope of the transaction, and the sessions view of the repository will be updated to reflect any changes that were made by other transactions executing against the repository. Below is a small snippet of code that shows how we retrieve a Game object from the GameManager and then change its name.

Assume a Game class that has at least the following definition:

	public class Game {
	    protected String     name;
	    protected CuHashMap  players;
	    protected Maze       maze;
	
            public Game(String aName,int roomCount) {
                name = aName;
                players = new CuHashMap();
                maze = new Maze(roomCount);
            }
	
            public void setName(String newName) {
                name = newName;
            }
	}

and that the following method is defined on GameManager

	public void changeNameOfGameFromTo(String oldName,String newName) {
            Game  game;
            game = (Game)games.get(oldName);
			
            if (game != null) {
                games.remove(oldName);
                game.setName(newName);
                games.put(newName,game);
            }
	}

Now the following code will retrieve the game with the given name and update it's name, because the collection of games in GameManager is keyed by the name, we also have to remove the old name and replace it with the new one:

	GameManager     manager;
	GsSession       session;
	SessionFactory  factory;
	Context         context;	
	
	//
	// retrieve the singleton SessionFactory instance
	//
	factory = SessionFactory.getInstance();
	if (factory == null) {
		System.err.println("unable to retrieve instance of SessionFactory");
		return;
	}
	
	//
	// now attempt to retrieve a session
	//
	session = null;
	try {
		session = factory.getSession();
	} catch  (Exception exception) {
		System.err.println("exception while retrieving a session");
		exception.printStackTrace();
		return;
	}
	
	//
	// now obtain the GameManager instance and ask it to
	// to change the name of the specified game
	//
	try {
		context = session.getInitialContext();
		manager = (GameManager)context.lookup("GameManager");
		session.begin();
		manager.changeGameNameFromTo(oldName,newName);
		session.commit();
	} catch  (GsTransactionInProgressException inProgress) {
		System.out.println("unable to start a transaction");
		inProgress.printStackTrace();
	} catch  (Exception exception) {
		session.abort();
		System.err.println("unable to commit transaction");
		exception.printStackTrace();
	}
	
	//
	// return the session to the factory
	//
	session.close();
	

Handling Conflicts

In many cases the judicious use of the Cu classes can allow even a massively multi-threaded system to concurrently update what it needs without generating conflicts, but there are some places where the use of a Cu class just does not help. In this case, it may become necessary to lock various objects prior to attempting to update them to either ensure exclusive access or when a situation can not permit a transaction to fail. Facets provides a locking mechanism which allows all of the normal locking semantics at the object level. If you need to lock an object, obtain a reference to the GsLockService by sending the "getLockService" message to a session and then request that the lock service lock the object that you need locked with the appropriate semantics using messages such as "writeLock()" or "readLock()". A useful technique for managing locks, is to use the try-catch-finally mechanism that we used to ensure that sessions were always returned to the factory. It is important not to forget to unlock an object once you have locked it, since any other threads or VMs attempting to lock that objects or update will be unable to do so.

If you use the Cu classes wisely you will find that there is not often a need to lock objects prior to updating them, since it is often quite simple to correctly partition the access to the various objects.

©2005 GemStone Systems, Inc.