001: /*--------------------------------------------------------------------------*
002: | Copyright (C) 2006 Gereon Fassbender, Christopher Kohlhaas |
003: | |
004: | This program is free software; you can redistribute it and/or modify |
005: | it under the terms of the GNU General Public License as published by the |
006: | Free Software Foundation. A copy of the license has been included with |
007: | these distribution in the COPYING file, if not go to www.fsf.org |
008: | |
009: | As a special exception, you are granted the permissions to link this |
010: | program with every library, which license fulfills the Open Source |
011: | Definition as published by the Open Source Initiative (OSI). |
012: *--------------------------------------------------------------------------*/
013: package org.rapla.entities.storage.internal;
014:
015: import java.util.ArrayList;
016: import java.util.Iterator;
017:
018: import org.rapla.components.util.Assert;
019: import org.rapla.entities.Entity;
020: import org.rapla.entities.EntityNotFoundException;
021: import org.rapla.entities.ReadOnlyException;
022: import org.rapla.entities.User;
023: import org.rapla.entities.storage.EntityReferencer;
024: import org.rapla.entities.storage.EntityResolver;
025: import org.rapla.entities.storage.Mementable;
026: import org.rapla.entities.storage.RefEntity;
027:
028: /** Base-class for all Rapla Entity-Implementations. Provides services
029: * for deep cloning and serialization of references. {@link ReferenceHandler}
030: */
031:
032: public abstract class SimpleEntity implements RefEntity,
033: EntityReferencer, java.io.Serializable {
034: // Don't forget to increase the serialVersionUID when you change the fields
035: private static final long serialVersionUID = 2;
036: private SimpleIdentifier id;
037: private long version = 0;
038:
039: ReferenceHandler subEntityHandler = new ReferenceHandler();
040: ReferenceHandler referenceHandler = new ReferenceHandler();
041:
042: transient boolean readOnly = false;
043:
044: public SimpleEntity() {
045:
046: }
047:
048: public void checkWritable() {
049: if (readOnly)
050: throw new ReadOnlyException(this );
051: }
052:
053: public boolean isPersistant() {
054: return isReadOnly();
055: }
056:
057: public void resolveEntities(EntityResolver resolver)
058: throws EntityNotFoundException {
059: referenceHandler.resolveEntities(resolver);
060: subEntityHandler.resolveEntities(resolver);
061: }
062:
063: public void setReadOnly(boolean enable) {
064: this .readOnly = enable;
065: Iterator it = getSubEntityHandler().getReferences();
066: while (it.hasNext()) {
067: ((SimpleEntity) it.next()).setReadOnly(enable);
068: }
069: }
070:
071: public boolean isReadOnly() {
072: return readOnly;
073: }
074:
075: public User getOwner() {
076: return (User) referenceHandler.get("owner");
077: }
078:
079: public void setOwner(User owner) {
080: referenceHandler.put("owner", owner);
081: }
082:
083: public User getLastChangedBy() {
084: return (User) referenceHandler.get("last_changed_by");
085: }
086:
087: public void setLastChangedBy(User user) {
088: referenceHandler.put("last_changed_by", user);
089: }
090:
091: protected boolean isSubEntity(RefEntity obj) {
092: return subEntityHandler.isRefering(obj);
093: }
094:
095: protected void addEntity(RefEntity entity) {
096: subEntityHandler.add(entity);
097: }
098:
099: public ReferenceHandler getReferenceHandler() {
100: return referenceHandler;
101: }
102:
103: public ReferenceHandler getSubEntityHandler() {
104: return subEntityHandler;
105: }
106:
107: protected void removeEntity(RefEntity entity) {
108: subEntityHandler.isRefering(entity);
109: subEntityHandler.remove(entity);
110: }
111:
112: /** sets the identifier for an object. The identifier should be
113: * unique accross all entities (not only accross the entities of a
114: * the same type). Once set, the identifier for an object should
115: * not change. The identifier is necessary to store the relationsships
116: * between enties.
117: * @see SimpleIdentifier
118: */
119:
120: public void setId(Object id) {
121: this .id = (SimpleIdentifier) id;
122: }
123:
124: /** @return the identifier of the object.
125: * @see SimpleIdentifier
126: */
127: final public Object getId() {
128: return id;
129: }
130:
131: final public boolean isIdentical(Entity ob2) {
132: return equals(ob2);
133: }
134:
135: /** two Entities are equal if they are identical.
136: * @see #isIdentical
137: */
138: final public boolean equals(Object o) {
139: if (!(o instanceof SimpleEntity)) {
140: return false;
141: }
142: SimpleEntity e2 = (SimpleEntity) o;
143: if (e2 == null)
144: return false;
145: SimpleIdentifier id2 = e2.id;
146: if (id2 == null || id == null)
147: return e2 == this ;
148: return (id2.key == id.key && id2.type == id.type);
149:
150: }
151:
152: /** The hashcode of the id-object will be returned.
153: * @return the hashcode of the id.
154: * @throws IllegalStateException if no id is set.
155: */
156: public int hashCode() {
157: if (id != null) {
158: return id.hashCode();
159: } else {
160: throw new IllegalStateException(
161: "Id not set for type '"
162: + getRaplaType()
163: + "'. You must set an Id before you can use the hashCode method.");
164: }
165: }
166:
167: public void setVersion(long version) {
168: this .version = version;
169: }
170:
171: public long getVersion() {
172: return version;
173: }
174:
175: public Iterator getSubEntities() {
176: return getSubEntityHandler().getReferences();
177: }
178:
179: public Iterator getReferences() {
180: return getReferenceHandler().getReferences();
181: }
182:
183: public boolean isRefering(RefEntity entity) {
184: return getReferenceHandler().isRefering(entity);
185: }
186:
187: public boolean isParentEntity(RefEntity object) {
188: return getSubEntityHandler().isRefering(object);
189: }
190:
191: static private void copy(SimpleEntity source, SimpleEntity dest,
192: boolean deepCopy) {
193: Assert.isTrue(source != dest, "can't copy the same object");
194:
195: dest.referenceHandler = (ReferenceHandler) source.referenceHandler
196: .clone();
197:
198: ArrayList newEntities = new ArrayList();
199: Iterator it = source.getSubEntityHandler().getReferences();
200: if (deepCopy) {
201: while (it.hasNext()) {
202: Mementable entity = (Mementable) it.next();
203: Mementable oldEntity = (Mementable) dest
204: .findEntity((RefEntity) entity);
205: if (oldEntity != null) {
206: oldEntity.copy(entity);
207: newEntities.add(oldEntity);
208: } else {
209: newEntities.add(entity.deepClone());
210: }
211: }
212: } else {
213: while (it.hasNext()) {
214: Mementable entity = (Mementable) it.next();
215: Mementable oldEntity = (Mementable) dest
216: .findEntity((RefEntity) entity);
217: if (oldEntity != null) {
218: newEntities.add(oldEntity);
219: } else {
220: newEntities.add(entity);
221: }
222: }
223: }
224: dest.getSubEntityHandler().clearReferences();
225: it = newEntities.iterator();
226: while (it.hasNext()) {
227: RefEntity entity = (RefEntity) it.next();
228: dest.addEntity(entity);
229: }
230: // In a copy operation the target/destination object should always be writable
231: dest.readOnly = false;
232: dest.setVersion(source.getVersion());
233: }
234:
235: /** find the sub-entity that has the same id as the passed copy. Returns null, if the entity was not found. */
236: public Object findEntity(RefEntity copy) {
237: Iterator it = getSubEntities();
238: while (it.hasNext()) {
239: RefEntity entity = (RefEntity) it.next();
240: if (entity.equals(copy)) {
241: return entity;
242: }
243: }
244: return null;
245: }
246:
247: /** copies the references from the entity to this */
248: protected void copy(SimpleEntity entity) {
249: copy(entity, this , false);
250: }
251:
252: protected void deepClone(SimpleEntity clone) {
253: clone.setId(id);
254: copy(this , clone, true);
255: }
256:
257: protected void clone(SimpleEntity clone) {
258: clone.setId(id);
259: copy(this , clone, false);
260: }
261:
262: abstract public Object clone();
263:
264: public String toString() {
265: if (id != null)
266: return id.toString();
267: return "no id for " + super.toString();
268: }
269: }
|