/*
Copyright (c) 2003-2009 ITerative Consulting Pty Ltd. All Rights Reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:
o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
o Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the distribution.
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package Express.services;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.ArrayList;
import org.apache.log4j.Logger;
import DisplayProject.binding.beans.ExtendedPropertyChangeSupport;
import DisplayProject.binding.beans.Observable;
import Express.services.interfaces.IBusinessServiceMgr;
import Framework.Array_Of_IntegerData;
import Framework.Array_Of_Object;
import Framework.CloneHelper;
import Framework.Constants;
import Framework.DataValue;
import Framework.GenericException;
import Framework.IntegerData;
import Framework.RuntimeProperties;
/**
* The BusinessClient class is used to select or update BusinessClass objects. Objects of this class interact with objects of the BusinessMgr class, which interact directly with the database server. Together, these classes manage the tables that correspond to BusinessClass objects.
* <p>
* @author ITerative Consulting
* @since 26-Feb-2008
*/
@RuntimeProperties(isDistributed=true, isAnchored=false, isShared=false, isTransactional=false)
@SuppressWarnings("serial")
public class BusinessClient
implements Serializable, Observable
{
// ----------
// Attributes
// ----------
public PropertyChangeSupport qq_Listeners = new ExtendedPropertyChangeSupport(this, true);
private ClientConcurrency concurrency;
private boolean isRevertable;
private IBusinessServiceMgr mgr;
private Trace trace;
// ------------
// Constructors
// ------------
public BusinessClient() {
// Explicitly call the superclass constructor to prevent the implicit call
super();
this.setTrace(new Trace());
this.getTrace().setDefaultServiceID(Constants.SP_ST_EX);
}
// ----------------------
// Accessors and Mutators
// ----------------------
public void setConcurrency(ClientConcurrency concurrency) {
ClientConcurrency oldValue = this.concurrency;
this.concurrency = concurrency;
this.qq_Listeners.firePropertyChange("concurrency", oldValue, this.concurrency);
}
public ClientConcurrency getConcurrency() {
return this.concurrency;
}
//PM:19/05/2008:fixed setting the manager
public void setMgr(IBusinessServiceMgr mgr) {
if (this.mgr != null){
throw new Error( Error.BC_HAS_MGR, "setMgr",this).getException();
}
this.concurrency = mgr.getClientConcurrency();
this.mgr = mgr;
}
public IBusinessServiceMgr getMgr() {
return this.mgr;
}
public void setTrace(Trace trace) {
Trace oldValue = this.trace;
this.trace = trace;
this.qq_Listeners.firePropertyChange("trace", oldValue, this.trace);
}
public Trace getTrace() {
return this.trace;
}
// ------------------
// Virtual attributes
// ------------------
// -------------------------------------------------
// (Virtual) Attribute Revertable
// -------------------------------------------------
public boolean getRevertable() {
return this.qq_getRevertable();
}
public void setRevertable(boolean revertable) {
this.qq_setRevertable(revertable);
}
// -------
// Methods
// -------
public void addPropertyChangeListener(String property, PropertyChangeListener listener) {
qq_Listeners.addPropertyChangeListener(property, listener);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
qq_Listeners.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(String property, PropertyChangeListener listener) {
qq_Listeners.removePropertyChangeListener(property, listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
qq_Listeners.removePropertyChangeListener(listener);
}
/**
* afterSelect<p>
* AfterSelect<br>
* AfterSelect gets executed by the Select method after performing<br>
* the select against the server. The generic method, i.e. this method<br>
* is always empty. You may override this method in the custom class<br>
* to provide implementation for any actions you want performed after<br>
* the select is done.<br>
* <p>
* query<br>
* The query parameter passed to this method is the query parameter<br>
* passed to the Select method.<br>
* <p>
* transactionMode<br>
* The transactionMode parameter passed to this method is the<br>
* transactionMode parameter passed to the Select method.<br>
* <p>
* result<br>
* The result parameter contains the array of BusinessClasses the<br>
* Select method is about to return. Any changes made to it will<br>
* affect the classes actually returned from Select.<br>
* <p>
* @param query Type: BusinessQuery
* @param transactionMode Type: int
* @param result Type: Array_Of_BusinessClass<BusinessClass>
*/
public void afterSelect(BusinessQuery query, int transactionMode, Array_Of_BusinessClass<BusinessClass> result) {
}
/**
* afterUpdate<p>
* AfterUpdate<br>
* AfterUpdate gets executed by the Update method after performing<br>
* the update against the server. The generic method, i.e. this method<br>
* is always empty. You may override this method in the custom class<br>
* to provide implementation for any actions you want performed after<br>
* the update is done.<br>
* <p>
* source<br>
* The source parameter contains the array of BusinessClasses passed<br>
* to the Update method.<br>
* <p>
* transactionMode<br>
* The transactionMode parameter passed to this method is the<br>
* transactionMode parameter passed to the Update method.<br>
* <p>
* @param source Type: Array_Of_BusinessClass<BusinessClass>
* @param transactionMode Type: int
*/
public void afterUpdate(Array_Of_BusinessClass<BusinessClass> source, int transactionMode) {
}
/**
* beforeSelect<p>
* BeforeSelect<br>
* BeforeSelect gets executed by the Select method before performing<br>
* the select against the server. The generic method, i.e. this method<br>
* is always empty. You may override this method in the custom class<br>
* to provide implementation for any actions you want performed before<br>
* the select is done.<br>
* <p>
* query<br>
* The query parameter passed to this method is the query parameter<br>
* passed to the Select method. Any changes made to it will affect<br>
* the query actually performed.<br>
* <p>
* transactionMode<br>
* The transactionMode parameter passed to this method is the<br>
* transactionMode parameter passed to the Select method.<br>
* <p>
* @param query Type: BusinessQuery
* @param transactionMode Type: int
*/
public void beforeSelect(BusinessQuery query, int transactionMode) {
}
/**
* beforeUpdate<p>
* BeforeUpdate<br>
* BeforeUpdate gets executed by the Update method before performing<br>
* the update against the server. The generic method, i.e. this method<br>
* is always empty. You may override this method in the custom class<br>
* to provide implementation for any actions you want performed before<br>
* the update is done.<br>
* <p>
* source<br>
* The source parameter contains the array of BusinessClasses passed<br>
* to the Update method. Any changes made to it will affect the<br>
* classes actually updated by Update.<br>
* <p>
* transactionMode<br>
* The transactionMode parameter passed to this method is the<br>
* transactionMode parameter passed to the Update method.<br>
* <p>
* @param source Type: Array_Of_BusinessClass<BusinessClass>
* @param transactionMode Type: int
*/
public void beforeUpdate(Array_Of_BusinessClass<BusinessClass> source, int transactionMode) {
}
/**
* delete<p>
* Delete<br>
* Use Delete when you want to delete a BusinessClass that was previously<br>
* retrieved with the Select method.<br>
* <p>
* Delete marks this BusinessClass for deletion. This can be done in two<br>
* ways depending on the status of the entity.<br>
* 1) If the entity was originally returned from a manager then the<br>
* Status is set to ST_DELETE and a query is created that will<br>
* delete the entity when the Update method is invoked on the<br>
* manager. Entities in the ST_DELETE state should not be<br>
* removed from their containing array. The update method will do<br>
* that once the query has been processed.<br>
* 2) If the entity was inserted, then it's status will be changed to<br>
* ST_EMPTY and any query associated with the entity will be<br>
* cleared. Entities in the ST_EMPTY state will not be sent to<br>
* the manager when the Update method is invoked.<br>
* <p>
* @param source Type: BusinessClass
*/
public void delete(BusinessClass source) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.EC_DELETE, 1, this, "Delete")) {
Logger.getLogger("task.part.logmgr").info(source.getClass().getSimpleName());
Logger.getLogger("task.part.logmgr").info(".InstanceKey = ");
if (source.getInstanceKey() != null) {
Logger.getLogger("task.part.logmgr").info(source.getInstanceKey().asTextData());
}
Logger.getLogger("task.part.logmgr").info("");
}
if (this.getMgr() == null) {
this.setup();
}
if (source.getInstanceStatus() == BusinessClass.ST_READONLY) {
throw new Error(Error.B_CANT_DELETE, "Delete", this, source, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
else if (source.getInstanceStatus() == BusinessClass.ST_READWRITE || source.getInstanceStatus() == BusinessClass.ST_UPDATE) {
this.logAttr(source, 10000);
source.getUpdateQuery().setOperation(BusinessQuery.OP_DELETE, source.getInstanceKey());
source.setInstanceStatus(BusinessClass.ST_DELETE);
}
else if (source.getInstanceStatus() == BusinessClass.ST_INSERT) {
source.setUpdateQuery(null);
source.setInstanceStatus(BusinessClass.ST_EMPTY);
}
}
/**
* dispose<p>
* Dispose<br>
* The Dispose method is used when the BusinessClient is no longer needed.<br>
* It allows any server side resources to be released.<br>
* <p>
*/
public void dispose() {
if (this.getConcurrency() != null) {
this.getConcurrency().dispose();
}
this.setMgr(null);
}
/**
* endTrans<p>
* <p>
* @param ifActive Type: boolean (Input) (default in Forte: FALSE)
*/
public void endTrans(boolean ifActive) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.EC_ENDTRANS, 1, this, "EndTrans")) {
Logger.getLogger("task.part.logmgr").info("");
}
if (this.getMgr() == null) {
this.setup();
}
this.getConcurrency().endTrans(ifActive);
}
/**
* Same as {@link #endTrans(boolean) with ifActive default of false.
*/
public void endTrans(){
this.endTrans(false);
}
/**
* qq_getRevertable<p>
* Method renamed by jcTOOL from GetRevertable to qq_getRevertable
* because it conflicted with an attribute<p>
* GetRevertable<br>
* The GetRevertable method returns the value of the IsRevertable<br>
* attribute which specifies whether the Revert method may be invoked.<br>
* When IsRevertable is set, then before images of BusinessClasses are<br>
* saved when they are changed by the LogAttr method so the changes<br>
* can be undone by the Revert method.<br>
* <p>
* @return boolean
*/
public boolean qq_getRevertable() {
return this.isRevertable;
}
/**
* logAttr<p>
* LogAttr<br>
* LogAttr is used before you modify an attribute of a BusinessClass.<br>
* LogAttr should be invoked once for each attribute modified before<br>
* invoking the Update. If an attribute is modified more than once<br>
* LogAttr need only be invoked once for that attribute. If the attribute<br>
* logged is NIL then a new one will be instantiated, which can be<br>
* subsequently set either directly or using SetAttr. Note: NewAttr<br>
* should not be invoked after LogAttr as the new attribute won't be<br>
* logged. Only simple attributes can be logged directly. Modifications<br>
* to dependent attributes should be logged on the dependent entities and<br>
* a single LogAttr done on the independent entity with no attr index<br>
* specified.<br>
* <p>
* LogAttr causes a query to be built, or appended to if LogAttr is called<br>
* more than once, that will modify the indicated attribute to the value<br>
* current at the time the Update method is called. If the entity on<br>
* which LogAttr is invoked is in the ST_EMPTY state (i.e. it didn't come<br>
* from the database and hasn't been inserted) then it will be put into<br>
* the ST_INSERT state and the query built will be for inserting the<br>
* entity into the Database with the values logged.<br>
* <p>
* attr<br>
* An index identifying which attribute to log. There is a<br>
* constant for each attribute of the entity. These constants are<br>
* defined in the entity's Query class. If you use the constant<br>
* BusinessQuery.ATTR_SIMPLE then all simple attributes will be logged.<br>
* If attr is not specified the BusinessClass will be put in the<br>
* update state but not attributes will be logged. This is useful<br>
* if it is necessary to perform the LogAttr after the values change.<br>
* <p>
* @param source Type: BusinessClass
* @param attr Type: int (Input) (default in Forte: 10000)
*/
public void logAttr(BusinessClass source, int attr) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.EC_LOGATTR, 1, this, "LogAttr")) {
Logger.getLogger("task.part.logmgr").info(source.getClass().getSimpleName());
Logger.getLogger("task.part.logmgr").info(".InstanceKey = ");
if (source.getInstanceKey() != null) {
Logger.getLogger("task.part.logmgr").info(source.getInstanceKey().asTextData());
}
Logger.getLogger("task.part.logmgr").info(", attr = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(attr));
if (attr > 0 && attr < BusinessQuery.ATTR_FOREIGN) {
Logger.getLogger("task.part.logmgr").info(", value = ");
Logger.getLogger("task.part.logmgr").info(source.getAttr(attr));
}
Logger.getLogger("task.part.logmgr").info("");
}
if (source == null) {
throw new Error(Error.BC_NIL_SOURCE, "LogAttr", this).getException();
}
if (this.getMgr() == null) {
this.setup();
}
//
// Check the state and allocate a new query if needed setting its state as
// appropriate.
//
if (source.getInstanceStatus() == BusinessClass.ST_EMPTY) {
if (source.getUpdateQuery() == null) {
source.setUpdateQuery(source.newQuery());
source.getUpdateQuery().setOperation(BusinessQuery.OP_NONE, (BusinessKey)null);
}
if (attr != BusinessQuery.ATTR_FOREIGN) {
source.getUpdateQuery().setOperation(BusinessQuery.OP_INSERT, (BusinessKey)null);
source.setInstanceStatus(BusinessClass.ST_INSERT);
}
}
else if (source.getInstanceStatus() == BusinessClass.ST_READWRITE) {
if (this.isRevertable || (this.getConcurrency().getConcurrencyMode() == ConcurrencyMgr.CO_OPT_VERIFY)) {
this.saveForRevert(source);
}
else {
source.setUpdateQuery(source.newQuery());
}
source.getUpdateQuery().setOperation(BusinessQuery.OP_UPDATE, source.getInstanceKey());
source.setInstanceStatus(BusinessClass.ST_UPDATE);
}
else if (source.getInstanceStatus() != BusinessClass.ST_UPDATE && source.getInstanceStatus() != BusinessClass.ST_INSERT) {
throw new Error(Error.B_CANT_UPDATE, "LogAttr", this, source, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
if (attr < BusinessQuery.ATTR_SIMPLE) {
throw new Error(Error.B_ILLEGAL_ATTR, "LogAttr", this, source, new IntegerData(attr)).getException();
}
else if (attr == BusinessQuery.ATTR_SIMPLE) {
//
// This means all simple attributes (good for inserts).
//
int n = source.getUpdateQuery().getNumAttrs();
// virtual attr.
for (int i = 1; i <= n; i++) {
this.logAttr(source, i);
}
}
else if (attr < BusinessQuery.ATTR_FOREIGN) {
// 0 < attr < ATTR_FOREIGN is true, which means that it is a regular simple
// attribute. Get it and add a constraint which will modify the value in
// the Database. Note: The constraint on a query for update is used to
// specify the columns to update and their values.
DataValue myValue = null;
myValue = source.getAttr(attr);
if (myValue == null) {
myValue = source.newAttr(attr);
}
//
// If we have logged this attribute before we update the value.
//
if (source.getUpdateQuery().getValues() != null) {
ConstraintNode c = null;
for (int i = 1; i <= source.getUpdateQuery().getValues().getStack().size(); i++) {
c = source.getUpdateQuery().getValues().getStack().get(i-1);
if (c instanceof ConstraintAttr && (((ConstraintAttr)c).getAttr() == attr)) {
((ConstraintValue)(source.getUpdateQuery().getValues().getStack().get(i-1-1))).setValue(myValue);
return;
}
}
}
source.getUpdateQuery().setValue(attr, myValue);
}
//
// For foreign classes we don't do anything more than initialize the query.
// By the time the Update is invoked, LogAttr will been invoked on the foreign
// class's attributes.
//
}
public void logAttr(BusinessClass source) {
this.logAttr(source, 10000);
}
/**
* newKey<p>
* NewKey<br>
* The NewKey method fills in the key attributes of a BusinessClass by<br>
* requesting one from its associated BusinessMgr.<br>
* <p>
* source<br>
* The source parameter holds the BusinessClass which is to get a<br>
* new key.<br>
* <p>
* @param source Type: BusinessClass
*/
public void newKey(BusinessClass source) {
if (this.getMgr() == null) {
this.setup();
}
this.getMgr().newKey(source);
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.EC_NEWKEY, 1, this, "NewKey")) {
Logger.getLogger("task.part.logmgr").info(source.getClass().getSimpleName());
Logger.getLogger("task.part.logmgr").info(".InstanceKey = ");
if (source.getInstanceKey() != null) {
Logger.getLogger("task.part.logmgr").info(source.getInstanceKey().asTextData());
}
}
}
/**
* revert<p>
* Revert<br>
* The Revert method is used to return a set of BusinessClasses previously<br>
* selected with the Select method to their originally selected state<br>
* undoing any changes and the effects of any LogAttr or Delete methods<br>
* upon them.<br>
* The Revert method may only be used if the Revertable attribute is set<br>
* before the first change is made to any selected BusinessClass.<br>
* <p>
* source<br>
* The source parameter specifies which BusinessClasses should be<br>
* reverted.<br>
* <p>
* @param source Type: BusinessClass
*/
@SuppressWarnings("unchecked")
public void revert(ParameterHolder_BusinessClass source) {
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_REVERT, 50, this, "Revert")) {
if (((BusinessClass)source.getObject()) != null) {
Logger.getLogger("task.part.logmgr").info(((BusinessClass)source.getObject()).fillString(1));
}
Logger.getLogger("task.part.logmgr").info("");
}
if (!(this.getRevertable())) {
throw new Error(Error.BC_NOT_REVERTABLE, "Revert", this).getException();
}
else if (((BusinessClass)source.getObject()) != null) {
if ((((BusinessClass)source.getObject()).getInstanceStatus()&(BusinessClass.ST_EMPTY|BusinessClass.ST_INSERT)) > 0) {
source.setObject(null);
}
else if ((((BusinessClass)source.getObject()).getInstanceStatus()&(BusinessClass.ST_UPDATE|BusinessClass.ST_DELETE)) > 0) {
if ((((BusinessClass)source.getObject()).getUpdateQuery() == null) || (((BusinessClass)source.getObject()).getUpdateQuery().getOriginalClass() == null)) {
throw new Error(Error.BC_CANNOT_REVERT, "Revert", this).getException();
}
((BusinessClass)source.getObject()).setInstanceStatus(((BusinessClass)source.getObject()).getUpdateQuery().getOriginalClass().getInstanceStatus());
for (int j = 1; j <= ((BusinessClass)source.getObject()).getUpdateQuery().getNumAttrs(); j++) {
((BusinessClass)source.getObject()).setAttr(j, ((BusinessClass)source.getObject()).getUpdateQuery().getOriginalClass().getAttr(j));
}
Array_Of_BusinessClass<BusinessClass> a = null;
BusinessClass b = null;
for (int attr = BusinessQuery.ATTR_FOREIGN+1; attr <= BusinessQuery.ATTR_FOREIGN+((BusinessClass)source.getObject()).getUpdateQuery().getNumForeignAttrs(); attr++) {
if ((((BusinessClass)source.getObject()).getUpdateQuery().getForeignAttrMult(attr)&BusinessQuery.ASSOC_MULT_ONE_MASK) == 0) {
if (((BusinessClass)source.getObject()).getUpdateQuery().getOriginalClass() == null) {
// ------------------------------
// Parameters for call to GetAttr
// ------------------------------
ParameterHolder_BusinessClass_Array qq_value = new ParameterHolder_BusinessClass_Array();
((BusinessClass)source.getObject()).getAttr(attr, qq_value);
a = (Array_Of_BusinessClass<BusinessClass>)qq_value.getObject();
}
else {
// ------------------------------
// Parameters for call to GetAttr
// ------------------------------
ParameterHolder_BusinessClass_Array qq_value = new ParameterHolder_BusinessClass_Array();
((BusinessClass)source.getObject()).getUpdateQuery().getOriginalClass().getAttr(attr, qq_value);
a = (Array_Of_BusinessClass<BusinessClass>)qq_value.getObject();
((BusinessClass)source.getObject()).setAttr(attr, a);
}
this.revert(a);
}
else {
if (((BusinessClass)source.getObject()).getUpdateQuery().getOriginalClass() == null) {
// ------------------------------
// Parameters for call to GetAttr
// ------------------------------
ParameterHolder_BusinessClass qq_value = new ParameterHolder_BusinessClass();
((BusinessClass)source.getObject()).getAttr(attr, qq_value);
b = (BusinessClass)qq_value.getObject();
}
else {
// ------------------------------
// Parameters for call to GetAttr
// ------------------------------
ParameterHolder_BusinessClass qq_value = new ParameterHolder_BusinessClass();
((BusinessClass)source.getObject()).getUpdateQuery().getOriginalClass().getAttr(attr, qq_value);
b = (BusinessClass)qq_value.getObject();
((BusinessClass)source.getObject()).setAttr(attr, b);
}
// -----------------------------
// Parameters for call to Revert
// -----------------------------
ParameterHolder_BusinessClass qq_source = new ParameterHolder_BusinessClass(b);
this.revert(qq_source);
b = (BusinessClass)qq_source.getObject();
if (b == null) {
((BusinessClass)source.getObject()).setAttr(attr, (BusinessClass)(null));
}
}
}
((BusinessClass)source.getObject()).setUpdateQuery(null);
}
}
}
/**
* revert<p>
* Revert<br>
* The Revert method is used to return a set of BusinessClasses previously<br>
* selected with the Select method to their originally selected state<br>
* undoing any changes and the effects of any LogAttr or Delete methods<br>
* upon them.<br>
* The Revert method may only be used if the Revertable attribute is set<br>
* before the first change is made to any selected BusinessClass.<br>
* <p>
* source<br>
* The source parameter specifies which BusinessClasses should be<br>
* reverted.<br>
* <p>
* @param source Type: Array_Of_BusinessClass<BusinessClass>
*/
public void revert(Array_Of_BusinessClass<BusinessClass> source) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.EC_REVERT, 1, this, "Revert")) {
if (source != null) {
Logger.getLogger("task.part.logmgr").info("array of ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(source.size()));
Logger.getLogger("task.part.logmgr").info(" items");
}
Logger.getLogger("task.part.logmgr").info("");
}
if (source != null && source.size() > 0) {
ArrayList<Integer> listToDelete = new ArrayList<Integer>();
for (int i = source.size(); i >= 1; i--) {
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_REVERT, 50, this, "Revert")) {
Logger.getLogger("task.part.logmgr").info("reverting item ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(i-1));
}
// -----------------------------
// Parameters for call to Revert
// -----------------------------
ParameterHolder_BusinessClass qq_source = new ParameterHolder_BusinessClass(source.get(i-1));
this.revert(qq_source);
source.set(i-1, (BusinessClass)qq_source.getObject());
if (source.get(i - 1) == null) {
listToDelete.add(new Integer(i - 1));
}
}
for (Integer index : listToDelete) {
source.deleteRow(index.intValue());
}
}
}
/**
* saveForRevert<p>
* SaveForRevert<br>
* SaveForRevert is used before you modify a BusinessClass on which you<br>
* later want to do Revert or a LogAttr. SaveForRevert only needs to be<br>
* invoked if you do the LogAttr after the value of the attribute changes.<br>
* If you do the LogAttr before the value changes then you don't ever<br>
* need to do a SaveForRevert.<br>
* <p>
* source<br>
* The source parameter contains the BusinessClass that you later<br>
* want to Revert.<br>
* <p>
* @param source Type: BusinessClass
*/
public void saveForRevert(BusinessClass source) {
if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.EC_SAVEFORREVERT, 1, this, "SaveForRevert")) {
Logger.getLogger("task.part.logmgr").info(source.getClass().getSimpleName());
Logger.getLogger("task.part.logmgr").info(".InstanceKey = ");
if (source.getInstanceKey() != null) {
Logger.getLogger("task.part.logmgr").info(source.getInstanceKey().asTextData());
}
Logger.getLogger("task.part.logmgr").info("");
}
if (source == null) {
throw new Error(Error.BC_NIL_SOURCE, "SaveForRevert", this).getException();
}
//
// Check the state and allocate a new query if needed setting its state as
// appropriate.
//
if ((source.getInstanceStatus()&(BusinessClass.ST_EMPTY|BusinessClass.ST_INSERT)) > 0 || (source.getInstanceStatus() == BusinessClass.ST_UPDATE && source.getUpdateQuery() != null && source.getUpdateQuery().getOriginalClass() != null)) {
//
// Nothing to do!
}
else if (source.getInstanceStatus() == BusinessClass.ST_READWRITE) {
if (source.getUpdateQuery() == null) {
BusinessQuery updateQuery = source.newQuery();
updateQuery.setOriginalClass(CloneHelper.clone(source, false));
source.setUpdateQuery(updateQuery);
DataValue val = null;
for (int i = 1; i <= source.getUpdateQuery().getNumAttrs(); i++) {
val = source.getAttr(i);
if (val != null) {
source.getUpdateQuery().getOriginalClass().setAttr(i, CloneHelper.clone(val, true));
}
}
}
}
else if (source.getInstanceStatus() == BusinessClass.ST_READONLY) {
throw new Error(Error.BC_CANNOT_SAVE, "SaveForRevert", this, source, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
else {
throw new Error(Error.BC_TOO_LATE_TO_SAVEFORREVERT, "SaveForRevert", this, source, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
}
}
/**
* select<p>
* Select<br>
* The Select method processes a query and returns an array containing the<br>
* BusinessClasses it describes.<br>
* <p>
* query<br>
* The query parameter describes what is to be returned by the Select.<br>
* <p>
* transactionMode<br>
* The transactionMode parameter specifies whether a transaction<br>
* should be started before performing the select and whether the<br>
* transaction should be ended after the select. Values for<br>
* transactionMode are any combination of:<br>
* <p>
* ConcurrencyMgr.TR_START (this is the default)<br>
* Start a new transation. The result set returned will be<br>
* recorded as part of the transaction by the ConcurrencyMgr.<br>
* If a transaction is already in progress an exception will be<br>
* raised.<br>
* <p>
* ConcurrencyMgr.TR_CONTINUE<br>
* A transaction is not started, nor ended. If a transaction<br>
* is not already in progress then an exception is raised. This<br>
* mode is overridden if either TR_START or TR_END is specified.<br>
* <p>
* ConcurrencyMgr.TR_END<br>
* The transaction is ended after the select.<br>
* <p>
* Returns<br>
* An Array of BusinessClass that contains the entities selected from<br>
* the database as specified by the query parameter.<br>
* <p>
* @param query Type: BusinessQuery
* @param transactionMode Type: int (Input) (default in Forte: 1)
* @return Array_Of_BusinessClass<BusinessClass>
*/
public Array_Of_BusinessClass<BusinessClass> select(BusinessQuery query, int transactionMode) {
Array_Of_BusinessQuery<BusinessQuery> queries = new Array_Of_BusinessQuery<BusinessQuery>();
Array_Of_BusinessClass<BusinessClass> result = null;
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_SELECT, 1, this, "Select")) {
Logger.getLogger("task.part.logmgr").info("transactionMode = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(transactionMode));
Logger.getLogger("task.part.logmgr").info("");
}
if (this.mgr == null) {
this.setup();
}
queries.add(query);
if (this.trace.getOn() && (transactionMode&ConcurrencyMgr.TR_START) > 0 && (this.trace.test(0, 0, Trace.EC_STARTTRANS, 1, this, "StartTrans"))) {
Logger.getLogger("task.part.logmgr").info("");
}
this.concurrency.beforeOperation(transactionMode);
this.beforeSelect(query, transactionMode);
try {
result = this.mgr.selectQueries(this.concurrency.getClientID(), queries, transactionMode);
}
catch (java.lang.RuntimeException qq_e) {
if (!(qq_e instanceof GenericException)) Logger.getLogger("task.part.logmgr").debug("Translating exception into GenericException", qq_e);
GenericException e = (qq_e instanceof GenericException) ? ((GenericException)qq_e) : new GenericException(qq_e);
this.concurrency.abortOperation(transactionMode, e);
throw e;
}
this.afterSelect(query, transactionMode, result);
if (this.trace.getOn() && (transactionMode&ConcurrencyMgr.TR_END) > 0 && (this.trace.test(0, 0, Trace.EC_ENDTRANS, 1, this, "EndTrans"))) {
Logger.getLogger("task.part.logmgr").info("");
}
this.concurrency.afterOperation(transactionMode);
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_SELECT, 50, this, "Select")) {
Logger.getLogger("task.part.logmgr").info("Returned ");
Logger.getLogger("task.part.logmgr").info(new BusinessClass().fillString(result, 0));
}
return result;
}
/**
* qq_setMgr<p>
* Method renamed by jcTOOL from SetMgr to qq_setMgr
* because it conflicted with an attribute<p>
* SetMgr<br>
* The SetMgr method is used when initializing a new BusinessClass client.<br>
* SetMgr should be invoked once before any other method is invoked on<br>
* the client and passed the specific manager service object for which it<br>
* will be used. SetMgr will save the reference to the manager, retrieve<br>
* and store a client ID which will be used in all communication with the<br>
* manager, and retreive and store the concurrency mode.<br>
* <p>
* mgr<br>
* The mgr parameter is used to pass the service ojbect of the<br>
* BusinessServiceMgr that will be used by this client.<br>
* <p>
* @param mgr Type: IBusinessServiceMgr
*/
public void qq_setMgr(IBusinessServiceMgr mgr) {
if (this.mgr != null) {
throw new Error(Error.BC_HAS_MGR, "SetMgr", this).getException();
}
this.concurrency = mgr.getClientConcurrency();
this.mgr = mgr;
}
/**
* qq_setRevertable<p>
* Method renamed by jcTOOL from SetRevertable to qq_setRevertable
* because it conflicted with an attribute<p>
* SetRevertable<br>
* The SetRevertable method sets the value of the IsRevertable attribute<br>
* which specifies whether the Revert method may be invoked. When<br>
* IsRevertable is set, then before images of BusinessClasses are<br>
* saved when they are changed by the LogAttr method so the changes<br>
* can be undone by the Revert method.<br>
* <p>
* @param revertable Type: boolean
*/
public void qq_setRevertable(boolean revertable) {
this.isRevertable = revertable;
}
/**
* setup<p>
* Setup<br>
* The Setup method is used to initialize the BusinessClient to use the<br>
* generated BusinessMgr.<br>
* <p>
* This method will be overridden by the BusinessClient's generated class.<br>
* <p>
*/
public void setup() {
throw new Error(Error.GEN_UNIMPLEMENTED, "Setup", this).getException();
}
/**
* startTrans<p>
* <p>
* @param ifActive Type: boolean (Input) (default in Forte: TRUE)
*/
public void startTrans(boolean ifActive) {
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_STARTTRANS, 1, this, "StartTrans")) {
Logger.getLogger("task.part.logmgr").info("");
}
if (this.mgr == null) {
this.setup();
}
this.concurrency.startTrans(ifActive);
}
public void startTrans(){
this.startTrans(true);
}
/**
* transActive<p>
* <p>
* @return boolean
*/
public boolean transActive() {
if (this.mgr == null) {
this.setup();
}
return this.concurrency.transActive();
}
/**
* update<p>
* Update<br>
* The Update method takes BusinessClasses previously returned by the<br>
* Select method and sends any querries associated with them to the<br>
* BusinessMgr who will run the querries to update the database to<br>
* reflect changes made to the classes. The BusinessClass array is then<br>
* Reset which builds new keys for any classes that had key fields<br>
* modified, removes classes which were in the ST_EMPTY or ST_DELETE<br>
* states and puts all the classes into the ST_READWRITE (updatable but<br>
* not modified) state.<br>
* <p>
* source<br>
* The source parameter holds the classes to update. It is normally<br>
* the array returned from the Select method.<br>
* <p>
* transactionMode<br>
* The transactionMode parameter specifies whether a transaction<br>
* should be started before performing the update and whether the<br>
* transaction should be ended after the update. Values for<br>
* transactionMode are any combination of:<br>
* <p>
* ConcurrencyMgr.TR_START<br>
* Start a new transation. If a transaction is already in<br>
* progress an exception will be raised.<br>
* <p>
* ConcurrencyMgr.TR_CONTINUE<br>
* A transaction is not started, nor ended. If a transaction<br>
* is not already in progress then an exception is raised. This<br>
* mode is overridden if either TR_START or TR_END is specified.<br>
* <p>
* ConcurrencyMgr.TR_END (this is the default)<br>
* The transaction is ended after the update.<br>
* <p>
* @param source Type: Array_Of_BusinessClass<BusinessClass>
* @param transactionMode Type: int (Input) (default in Forte: 2)
*/
@SuppressWarnings("unchecked")
public void update(Array_Of_BusinessClass<BusinessClass> source, int transactionMode) {
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_UPDATE, 1, this, "Update")) {
Logger.getLogger("task.part.logmgr").info("beginning update, transactionMode = ");
Logger.getLogger("task.part.logmgr").info( Integer.toString(transactionMode));
if (this.trace.test(0, 0, Trace.EC_UPDATE, 100, (Object)null, (String)null)) {
Logger.getLogger("task.part.logmgr").info(", source(before) = ");
Logger.getLogger("task.part.logmgr").info(new BusinessClass().fillString(source, 0));
}
Logger.getLogger("task.part.logmgr").info("");
}
if (this.mgr == null) {
this.setup();
}
if (this.trace.getOn() && (transactionMode&ConcurrencyMgr.TR_START) > 0 && (this.trace.test(0, 0, Trace.EC_STARTTRANS, 1, this, "StartTrans"))) {
Logger.getLogger("task.part.logmgr").info("");
}
this.concurrency.beforeOperation(transactionMode);
this.beforeUpdate(source, transactionMode);
Array_Of_BusinessQuery<BusinessQuery> queries = null;
//
// Cull out all the querries from the BusinessClasses. If a BusinessClass
// has foreign attributes which have querries, then pull out their
// querries and attach them to their parent BusinessClass.
//
Array_Of_Object<Object> origRef = null;
Array_Of_IntegerData<IntegerData> origAttr = null;
Array_Of_BusinessQuery<BusinessQuery> origClasses = null;
try {
if (source != null) {
queries = new Array_Of_BusinessQuery<BusinessQuery>();
if (source != null) {
for (BusinessClass e : source) {
if ((e.getInstanceStatus()&(BusinessClass.ST_INSERT|BusinessClass.ST_UPDATE|BusinessClass.ST_DELETE)) > 0 && e.getUpdateQuery() != null && e.getUpdateQuery().getOperation() != BusinessQuery.OP_NONE) {
//
// This BusinessClass has a query validate it and add it to the list
//
e.validateInstance(this);
queries.add(e.getUpdateQuery());
if (e.getUpdateQuery().sendClassOnUpdate()) {
e.getUpdateQuery().setUpdatedClass(e);
}
//
// If this BusinessClass (e) has any foreign BusinessClasses
// which have querries, hook their querries up to this
// BusinessClass's query.
//
e.getUpdateQuery().connectQueries(e, this);
}
}
}
}
//
// If we have original classes attached to the queries (a copy of the
// class before changes were made -- used by the optimistic concurrency
// mode) then we want to remove any foreign references in the original
// copies so we don't send down an entire object graph. The bad part
// is that we have to remember these references so we can restore them
// in the case of an exception!
//
origClasses = new Array_Of_BusinessQuery<BusinessQuery>();
origAttr = new Array_Of_IntegerData<IntegerData>();
origRef = new Array_Of_Object<Object>();
if (queries != null) {
for (BusinessQuery q : queries) {
if (q.getOriginalClass() != null) {
for (int attr = BusinessQuery.ATTR_FOREIGN+1; attr <= BusinessQuery.ATTR_FOREIGN+q.getNumForeignAttrs(); attr++) {
if ((q.getForeignAttrMult(attr)&BusinessQuery.ASSOC_MULT_ONE_MASK) == 0) {
Array_Of_BusinessClass<BusinessClass> a = null;
// ------------------------------
// Parameters for call to GetAttr
// ------------------------------
ParameterHolder_BusinessClass_Array qq_value = new ParameterHolder_BusinessClass_Array();
q.getOriginalClass().getAttr(attr, qq_value);
a = (Array_Of_BusinessClass<BusinessClass>)qq_value.getObject();
q.getOriginalClass().setAttr(attr, (Array_Of_BusinessClass)(null));
origClasses.add(q);
origAttr.add(new IntegerData(attr));
origRef.add(a);
}
else {
BusinessClass b = null;
// ------------------------------
// Parameters for call to GetAttr
// ------------------------------
ParameterHolder_BusinessClass qq_value = new ParameterHolder_BusinessClass();
q.getOriginalClass().getAttr(attr, qq_value);
b = (BusinessClass)qq_value.getObject();
q.getOriginalClass().setAttr(attr, (BusinessClass)(null));
origClasses.add(q);
origAttr.add(new IntegerData(attr));
origRef.add(b);
}
}
}
}
}
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_UPDATE, 200, (Object)null, (String)null)) {
Logger.getLogger("task.part.logmgr").info("beginning update, OriginalClasses:");
if (queries != null) {
for (BusinessQuery q : queries) {
if (q.getOriginalClass() != null) {
Logger.getLogger("task.part.logmgr").info(q.getOriginalClass().fillString(0));
}
}
}
Logger.getLogger("task.part.logmgr").info("");
}
//
// Send the querries off to the manager
//
this.mgr.updateQueries(this.concurrency.getClientID(), queries, transactionMode);
//
// Now reset the BusinessClass array. New keys will be built for any
// BusinessClasses that had key fields modified, BusinessClasses which
// were in the ST_EMPTY or ST_DELETE state will be removed from the array,
// and all the BusinessClasses will be put into the ST_READWRITE
// (updatable but not modified) state.
//
if (queries.size() > 0) {
source.get(0).reset(source, true);
}
}
catch (Throwable e) {
if (queries != null) {
for (BusinessQuery q : queries) {
q.disconnectQueries();
}
}
if (origClasses != null) {
for (int i = 1; i <= origClasses.size(); i++) {
BusinessQuery q = origClasses.get(i-1);
int attr = origAttr.get(i-1).getValue();
if ((q.getForeignAttrMult(attr)&BusinessQuery.ASSOC_MULT_ONE_MASK) == 0) {
q.getOriginalClass().setAttr(attr, (Array_Of_BusinessClass)(origRef.get(i-1)));
}
else {
q.getOriginalClass().setAttr(attr, (BusinessClass)(origRef.get(i-1)));
}
}
}
this.concurrency.abortOperation(transactionMode, e);
throw (RuntimeException)e;
}
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_UPDATE, 200, (Object)null, (String)null)) {
Logger.getLogger("task.part.logmgr").info("after update, OriginalClasses:");
if (queries != null) {
for (BusinessQuery q : queries) {
if (q.getOriginalClass() != null) {
Logger.getLogger("task.part.logmgr").info(q.getOriginalClass().fillString(0));
}
}
}
Logger.getLogger("task.part.logmgr").info("");
}
this.afterUpdate(source, transactionMode);
if (this.trace.getOn() && (transactionMode&ConcurrencyMgr.TR_END) > 0 && (this.trace.test(0, 0, Trace.EC_ENDTRANS, 1, this, "EndTrans"))) {
Logger.getLogger("task.part.logmgr").info("");
}
this.concurrency.afterOperation(transactionMode);
if (this.trace.getOn() && this.trace.test(0, 0, Trace.EC_UPDATE, 50, this, "Update")) {
Logger.getLogger("task.part.logmgr").info("update complete, source = ");
Logger.getLogger("task.part.logmgr").info(new BusinessClass().fillString(source, 0));
}
}
/**
* Same as {@link #update(Array_Of_BusinessClass, int) with default of ConcurrencyMgr.TR_END.
* @param source
*/
public void update(Array_Of_BusinessClass<BusinessClass> source) {
this.update(source, ConcurrencyMgr.TR_END);
}
} // end class BusinessClient
// c Pass 2 Conversion Time: 3094 milliseconds