/*==========================================================================*\
| $Id: IndependentEOManager.java,v 1.5 2011/12/25 02:24:54 stedwar2 Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2006-2011 Virginia Tech
|
| This file is part of Web-CAT.
|
| Web-CAT is free software; you can redistribute it and/or modify
| it under the terms of the GNU Affero General Public License as published
| by the Free Software Foundation; either version 3 of the License, or
| (at your option) any later version.
|
| Web-CAT is distributed in the hope that it will be useful,
| but WITHOUT ANY WARRANTY; without even the implied warranty of
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
| GNU General Public License for more details.
|
| You should have received a copy of the GNU Affero General Public License
| along with Web-CAT; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package org.webcat.core;
import org.apache.log4j.Logger;
import com.webobjects.eoaccess.EOUtilities;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.eocontrol.EORelationshipManipulation;
import com.webobjects.foundation.NSDictionary;
//-------------------------------------------------------------------------
/**
* This implementation of EOManager provides an independently saveable
* view of an EO's state, where changes can be saved independently of the
* EO's editing context. Make changes as usual, then commit them using
* the {@link #saveChanges()} method. Note that if there are optimistic
* locking conflicts, this class uses a "last write wins" strategy to
* resolve them automatically.
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.5 $, $Date: 2011/12/25 02:24:54 $
*/
public class IndependentEOManager
implements EOManager
{
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Creates a new manager for the given EO. The EO must exist and be
* within an existing editing context, already stored in the database.
* After giving control of an EO to this manager, no other code should
* directly modify the EO's state.
* @param eo the object to manage
*/
public IndependentEOManager(EOEnterpriseObject eo)
{
this(eo.editingContext(), eo, new ECManager());
}
// ----------------------------------------------------------
/**
* Creates a new manager for the given EO. The EO must exist and be
* within an existing editing context, already stored in the database.
* After giving control of an EO to this manager, no other code should
* directly modify the EO's state.
* @param context The editing context used by this manager's client(s)
* @param eo the object to manage
* @param manager the (probably shared) editing context manager to use
* for independent saving of the given eo
*/
public IndependentEOManager(
EOEditingContext context, EOEnterpriseObject eo, ECManager manager)
{
ecm = manager;
setClientContext(context);
mirror = ecm.localize(eo);
}
//~ Public Methods ........................................................
// ----------------------------------------------------------
/**
* Retrieve this object's <code>id</code> value.
* @return the value of the attribute
*/
public Number id()
{
try
{
return (Number)EOUtilities.primaryKeyForObject(
mirror.editingContext(), mirror).objectForKey( "id" );
}
catch (Exception e)
{
return er.extensions.eof.ERXConstant.ZeroInteger;
}
}
// ----------------------------------------------------------
/**
* Gets a local instance of the managed object in the specified editing
* context.
*
* @param ec the editing context
* @return a local instance of the object
*/
public EOEnterpriseObject localInstanceIn(EOEditingContext ec)
{
return EOUtilities.localInstanceOfObject(ec, mirror);
}
// ----------------------------------------------------------
public Object valueForKey(String key)
{
return ECManager.localize(clientContext, mirror.valueForKey(key));
}
// ----------------------------------------------------------
public void takeValueForKey(Object value, String key)
{
mirror.takeValueForKey(ecm.localize(value), key);
}
// ----------------------------------------------------------
public void addObjectToBothSidesOfRelationshipWithKey(
EORelationshipManipulation eo, String key)
{
mirror.addObjectToBothSidesOfRelationshipWithKey(
ecm.localize(eo), key);
}
// ----------------------------------------------------------
public void addObjectToPropertyWithKey(Object eo, String key)
{
mirror.addObjectToPropertyWithKey(ecm.localize(eo), key);
}
// ----------------------------------------------------------
public void removeObjectFromBothSidesOfRelationshipWithKey(
EORelationshipManipulation eo, String key)
{
mirror.removeObjectFromBothSidesOfRelationshipWithKey(
ecm.localize(eo), key);
}
// ----------------------------------------------------------
public void removeObjectFromPropertyWithKey(Object eo, String key)
{
mirror.removeObjectFromPropertyWithKey(ecm.localize(eo), key);
}
// ----------------------------------------------------------
public void refresh()
{
ecm.revert();
ecm.refreshAllObjects();
}
// ----------------------------------------------------------
public void revert()
{
ecm.revert();
}
// ----------------------------------------------------------
/**
* Tries to save any pending changes in the managed EO, returning
* null on success or an appropriate Exception object on failure.
* This method allows the caller to decide what to do when saving
* fails.
* @return The exception that occurred, if saving fails, or null
* on success.
*/
public Exception tryToSaveChanges()
{
return ecm.tryToSaveChanges();
}
// ----------------------------------------------------------
public void saveChanges()
{
// grab the changes, in case there is trouble saving them
@SuppressWarnings("unchecked")
NSDictionary<String, Object> snapshot =
mirror.editingContext().committedSnapshotForObject(mirror);
@SuppressWarnings("unchecked")
NSDictionary<String, Object> changes =
mirror.changesFromSnapshot(snapshot);
boolean changesSaved = false;
// Try ten times
for (int i = 0; !changesSaved && i< 10; i++)
{
EOEnterpriseObject newMirror = ecm.saveChanges(mirror);
changesSaved = (newMirror == mirror);
if (!changesSaved)
{
// then the changes may have failed
mirror = newMirror;
changes = ecm.localize(changes);
mirror.reapplyChangesFromDictionary(changes);
}
}
if (!changesSaved)
{
log.error("Unable to save changes to eo " + mirror);
log.error("Unsaved changes = " + changes,
new Exception("here"));
}
}
// ----------------------------------------------------------
public EOEditingContext clientContext()
{
return clientContext;
}
// ----------------------------------------------------------
public void setClientContext(EOEditingContext newClientContext)
{
clientContext = newClientContext;
}
//~ Instance/static variables .............................................
private ECManager ecm;
private EOEnterpriseObject mirror; // copy of EO in ecm context
private EOEditingContext clientContext;
static Logger log = Logger.getLogger(IndependentEOManager.class);
}