/* * BusinessObject * * Copyright (C) 2010 Jaroslav Merxbauer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. * */ package notwa.wom; import java.lang.reflect.Field; import org.apache.log4j.Logger; /** * Abstract class representing a single <code>BusinessObject</code> and providing * a common behavior to be shared by all possible ascendants. * <p><code>BusinessObject</code>s could be maintained simply as regular objects * without no rules attached to them. However, as soon as they are going to be maintained * as a part of <code>BusinessObjectCollection</code> they must obey certain rules: * <ul> * <li>They must be context aware, which means that they must have <code>Context</code> * withing they live</li> * <li>They will be <code>attach</code>ed to the collection and they then cannost perform * freely certain operations</li> * <ul></p> * * @author Tomas Studnicka * @author Jaroslav Mexbauer */ public abstract class BusinessObject { /** * The <code>BusinessObjectCollection</code> we are attached to. */ protected BusinessObjectCollection attachedBOC; /** * The original version of this <code>BusinessObject</code> which could be * picked up and replaced with the current state by calling the {@link #rollback()}. */ protected BusinessObject originalVersion; /** * The current <code>Context</code> we are living within. This <code>Context</code> * keeps all the <code>BusinessObjects</code> related to our literal context. */ protected Context currentContext; /** * The flag indicating that the content of this <code>BusinessObject</code> have * been updated. * * <p>Please note that this flag has sense only as soon as this <code>BusinessObject</code> * is attached ({@link #attach(notwa.wom.BusinessObjectCollection)}) to the * closed ({@link BusinessObjectCollection#closed}) <code>BusinessObjectCollection</code>. * </p> */ protected boolean updated; /** * The flag indicating that this <code>BusinessObject</code> have been marked * for deletion. * * <p>Please note that this flag has sense only as soon as this <code>BusinessObject</code> * is attached ({@link #attach(notwa.wom.BusinessObjectCollection)}) to the * closed ({@link BusinessObjectCollection#closed}) <code>BusinessObjectCollection</code>. * </p> */ protected boolean deleted; /** * The flag indicating that this <code>BusinessObject</code> has been newly * added to the attached <code>BusinessObjectCollection</code>. * * <p>Please note that this flag has sense only as soon as this <code>BusinessObject</code> * is attached ({@link #attach(notwa.wom.BusinessObjectCollection)}) to the * closed ({@link BusinessObjectCollection#closed}) <code>BusinessObjectCollection</code>. * </p> */ protected boolean inserted; protected Logger log; /** * The sole constructor making sure that all members are set to their default * values. */ public BusinessObject() { this.log = Logger.getLogger(this.getClass()); this.deleted = false; this.inserted = false; this.updated = false; this.currentContext = null; this.originalVersion = null; } /** * Attach Business object to <code>BusinessObjectCollection</code>. * <p>As soon as the <code>BusinessObject</code> is attached certain behavior * is restricted and this <code>BusinessObject</code> is well recognized as * and part of its collection.</p> * <p>It also helps to hold the bidirectional information of who is keeping * who and who is being kept by who.</p> * * @param boc The attached <code>BusinessObjectCollection</code>. */ public void attach(BusinessObjectCollection boc) { this.attachedBOC = boc; try { this.originalVersion = (BusinessObject) this.clone(); } catch (CloneNotSupportedException ex) { log.debug("", ex); } } /** * Detach <code>BusinessObject</code> from <code>BusinessObjectCollection</code>. * <p>As soon as the <code>BusinessObject</code> is detached, its connection * with the attached <code>BusinessObjectCollection</code> would become too lose * and therefore it is removed from it.</p> */ public void detach() { this.attachedBOC.remove(this); this.attachedBOC = null; } /** * Check if <code>BusinessObject</code> is attached to <Code>BusinessObjectCollection</code>. * * @return <code>true</code> if this <code>BusinessObject</code> is attached * to any <code>BusinessObjectCollection</code>. */ public boolean isAttached() { return (attachedBOC != null); } /** * Rewrites all user changes with original version */ public void rollback() { Class<?> c = this.getClass(); Class<?> o = originalVersion.getClass(); for (Field field : c.getDeclaredFields()) { try { field.setAccessible(true); Field ovField = o.getDeclaredField(field.getName()); ovField.setAccessible(true); field.set(this, ovField.get(originalVersion)); } catch (Exception ex) { log.debug("", ex); } } } /** * Saves all user changes to original version and clears the inserted flag. */ public void commit() { this.originalVersion = null; try { this.originalVersion = (BusinessObject) this.clone(); } catch (CloneNotSupportedException ex) { log.debug("", ex); } this.setInserted(false); } /** * Sets the current <code>Context<code> which represents the actual <code>context</code> * within this business is going to live. * * @param currentContext The actual <code>Context<code> to be registered with. */ public abstract void registerWithContext(Context currentContext); /** * Gets the <code>Context</code> representing the actuall context within this * business object has been created. * <p>Only <code>BusinessObject</code>s within the same context could relate * with each other</p> * * @return The current context. */ public Context getCurrentContext() { return currentContext; } /** * Checks whether this <code>BusinessObject</code> wasn't already marked as * deleted which could draw some restriction to certain oprations which is * working with it. * <p>The physical representation in the <code>BusinessObjectCollection</code> * is going to be removed as soon as the <code>commit</code> method is invoked * usualy by the <code>DataAccessLayer.</code></p> * * @return <code>true</code> if this <code>BusinessObject</code> has been already * marked for deletion, <code>false</code> otherwise */ public boolean isDeleted() { return deleted; } /** * Marks this <code>BusinessObject</code> for deletion which could draw some * impact to certain oprations which is working with it. * * <p>The physical representation in the <code>BusinessObjectCollection</code> * is going to be removed as soon as the <code>commit</code> method is invoked * usualy by the <code>DataAccessLayer</code>.</p> * * @param deleted Indicating whether this <code>BusinessObject</code> will * be marked for deletion or not. */ public void setDeleted(boolean deleted) { this.deleted = deleted; } /** * Checks wheter this <code>BusinessObject</code> is marked as inserted in the * already closed <code>BusinessObjectCollection</code> which means that this * object doesn't already have a representation in the database. * * <p>This mark is going to be removed as soon as the <code>BusinessObjectCollection</code> * invokes the <code>commit</code> method usualy by the <code>DataAccessLayer</code>.</p> * * @return <code>true</code> if this <code>BusinessObject</code> is marked as * inserted, <code>false</code> otherwise. */ public boolean isInserted() { return inserted; } /** * Marks this <code>BusinessObject</code> as inserted to the already closed * <code>BusinessObjectCollection</code> which means that this object doesn't * already have a representation in the database. * * <p>This mark is going to be removed as soon as the <code>BusinessObjectCollection</code> * invokes the <code>commit</code> method usualy by the <code>DataAccessLayer</code>.</p> * * @param inserted Indicating whether this <code>BusinessObject</code> will * be marked as inserted or not. */ public void setInserted(boolean inserted) { this.inserted = inserted; } /** * Gets whether this <code>BusinessObject</code> has been updated since it has * become a member of a <code>BusinessObjectCollection</code>. * This flag is removed as soon as the {@link #commit()} method is called to * facticaly save the updated information. * * @return <code>true</code> if this <code>BusinessObject</code> has been updated, * <code>false</code> otherwise. */ public boolean isUpdated() { return updated; } /** * Sets whether this <code>BusinessObject</code> has been updated since it has * become a member of a <code>BusinessObjectCollection</code>. * This flag is removed as soon as the {@link #commit()} method is called to * facticaly save the updated information. * * @param updated <code>true</code> if this <code>BusinessObject</code> has * been updated, <code>false</code> otherwise. */ public void setUpdated(boolean updated) { this.updated = updated; } /** * Gets whether the queried <code>BusinessObject</code> is uniqely indentified. * This means whether it has it's id. If not, it is up to the * <code>BusinessObjectCollection</code> to acquire it. * * @return <code>true</code> if the item has not-null or non-zero id, <code>false</code * otherwise. */ public abstract boolean hasUniqeIdentifier(); /** * Sets the uniqe identifier of the concrete implementation of this * <Code>BusinessObject</code>. * * @param value The uniqe identifier. */ public abstract void setUniqeIdentifier(int value); /** * Gets the uniqe identifier of the concrete implementation of this * <Code>BusinessObject</code>. * * @return The uniqe identifier. */ public abstract int getUniqeIdentifier(); }