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.Collection;
017: import java.util.HashMap;
018: import java.util.Iterator;
019: import java.util.List;
020:
021: import org.rapla.components.util.Assert;
022: import org.rapla.components.util.Tools;
023: import org.rapla.entities.EntityNotFoundException;
024: import org.rapla.entities.storage.RefEntity;
025: import org.rapla.entities.storage.EntityReferencer;
026: import org.rapla.entities.storage.EntityResolver;
027:
028: /** The ReferenceHandler takes care of serializing and deserializing references to Entity objects.
029: <p>
030: The references will be serialized to the ids of the corresponding entity. Deserialization of
031: the ids takes place in the contextualize method. You need to provide an EntityResolver on the Context.
032: </p>
033: <p>
034: The ReferenceHandler support both named and unnamed References. Use the latter one, if you don't need to refer to the particular reference by name and if you want to keep the order of the references.
035:
036: <pre>
037:
038: // put a named reference
039: referenceHandler.put("owner",user);
040:
041: // put unnamed reference
042: Iterator it = resources.iterator();
043: while (it.hasNext())
044: referenceHandler.add(it.next());
045:
046: // returns
047: User referencedUser = referenceHandler.get("owner");
048:
049: // returns both the owner and the resources
050: Itertor references = referenceHandler.getReferences();
051: </pre>
052:
053: </p>
054: @see EntityResolver
055: */
056: public class ReferenceHandler implements EntityReferencer,
057: java.io.Serializable {
058: // Don't forget to increase the serialVersionUID when you change the fields
059: private static final long serialVersionUID = 1;
060:
061: private HashMap map;
062: private ArrayList list;
063: private transient boolean contextualizeCalled;
064:
065: // added for performance reasons
066: private transient boolean referencesUpToDate;
067: private transient List referenceList;
068:
069: /**
070: * @see org.rapla.entities.storage.EntityReferencer#resolveEntities(org.rapla.entities.storage.EntityResolver)
071: */
072: public void resolveEntities(EntityResolver resolver)
073: throws EntityNotFoundException {
074: try {
075: if (map != null) {
076: Iterator it = map.values().iterator();
077: while (it.hasNext()) {
078: ReferenceEntry entry = (ReferenceEntry) it.next();
079: entry.reference = resolver.resolve(entry.id);
080: }
081: }
082: if (list != null) {
083: Iterator it = list.iterator();
084: while (it.hasNext()) {
085: ReferenceEntry entry = (ReferenceEntry) it.next();
086: entry.reference = resolver.resolve(entry.id);
087: }
088: }
089: } catch (EntityNotFoundException ex) {
090: clearReferences();
091: throw ex;
092: }
093: contextualizeCalled = true;
094: referencesUpToDate = false;
095: }
096:
097: /** Use this method if you want to implement deserialization of the object manualy.
098: * You have to add the reference-ids to other entities immediatly after the constructor.
099: * @throws IllegalStateException if contextualize has been called before.
100: */
101: public void addId(Object id) {
102: if (contextualizeCalled)
103: throw new IllegalStateException(
104: "Contextualize has been called before.");
105: if (list == null)
106: list = new ArrayList(3);
107: Assert.notNull(id);
108:
109: ReferenceEntry entry = new ReferenceEntry();
110: entry.id = id;
111: list.add(entry);
112: }
113:
114: /** Use this method if you want to implement deserialization of the object manualy.
115: * You have to add the reference-ids to other entities immediatly after the constructor.
116: * @throws IllegalStateException if contextualize has been called before.
117: */
118: public void putId(String key, Object id) {
119: if (contextualizeCalled)
120: throw new IllegalStateException(
121: "Contextualize has been called before.");
122: if (map == null)
123: map = new HashMap(5);
124:
125: if (id == null) {
126: map.remove(key);
127: return;
128: }
129:
130: ReferenceEntry entry = new ReferenceEntry();
131: entry.id = id;
132: map.put(key, entry);
133: }
134:
135: public boolean removeId(String key) {
136: if (map == null)
137: return false;
138: if (map.remove(key) != null) {
139: referencesUpToDate = false;
140: return true;
141: } else {
142: return false;
143: }
144: }
145:
146: public Object getId(String key) {
147: if (map == null)
148: throw new IllegalStateException("Map is empty.");
149: ReferenceEntry entry = (ReferenceEntry) map.get(key);
150: if (entry != null)
151: return entry.id;
152: throw new IllegalStateException("Key not found." + key);
153: }
154:
155: public void put(String key, Object obj) {
156: if (map == null)
157: map = new HashMap(5);
158: if (obj == null) {
159: map.remove(key);
160: return;
161: }
162:
163: ReferenceEntry entry = new ReferenceEntry();
164: RefEntity entity = (RefEntity) obj;
165: entry.id = entity.getId();
166: entry.reference = entity;
167: map.put(key, entry);
168: referencesUpToDate = false;
169: }
170:
171: public Object get(String key) {
172: if (map == null)
173: return null;
174: ReferenceEntry entry = (ReferenceEntry) map.get(key);
175: if (entry == null)
176: return null;
177: return entry.reference;
178: }
179:
180: public void add(Object obj) {
181: RefEntity entity = (RefEntity) obj;
182: if (isRefering(entity))
183: return;
184: if (list == null)
185: list = new ArrayList(3);
186: ReferenceEntry entry = new ReferenceEntry();
187: entry.id = entity.getId();
188: entry.reference = entity;
189: list.add(entry);
190: referencesUpToDate = false;
191: }
192:
193: public boolean remove(Object obj) {
194: RefEntity entity = (RefEntity) obj;
195: if (!isRefering(entity)) {
196: return false;
197: }
198: if (list != null) {
199: Iterator it = list.iterator();
200: while (it.hasNext()) {
201: ReferenceEntry entry = (ReferenceEntry) it.next();
202: if (entry.reference.equals(obj))
203: it.remove();
204: }
205: }
206: if (map != null) {
207: Iterator it = map.keySet().iterator();
208: while (it.hasNext()) {
209: ReferenceEntry entry = (ReferenceEntry) map.get(it
210: .next());
211: if (entry.reference.equals(obj))
212: it.remove();
213: }
214: }
215: referencesUpToDate = false;
216: return true;
217: }
218:
219: private Collection getReferenceList() {
220: if (referencesUpToDate)
221: return referenceList;
222: referenceList = new ArrayList(5);
223: if (list != null) {
224: Iterator it = list.iterator();
225: while (it.hasNext()) {
226: ReferenceEntry entry = (ReferenceEntry) it.next();
227: if (entry.reference == null)
228: throw new IllegalStateException(
229: "Contextualize was not called. References need to be resolved in context.");
230: referenceList.add(entry.reference);
231: }
232: }
233: if (map != null) {
234: Iterator it = map.keySet().iterator();
235: while (it.hasNext()) {
236: ReferenceEntry entry = (ReferenceEntry) map.get(it
237: .next());
238: if (entry.reference == null)
239: throw new IllegalStateException(
240: "Contextualize was not called. References need to be resolved in context.");
241: referenceList.add(entry.reference);
242: }
243: }
244: referencesUpToDate = true;
245: return referenceList;
246: }
247:
248: public boolean isRefering(RefEntity obj) {
249: if (list == null && map == null)
250: return false;
251: return getReferenceList().contains(obj);
252: }
253:
254: public Iterator getReferences() {
255: if (list == null && map == null)
256: return Tools.EMPTY_ITERATOR;
257: return getReferenceList().iterator();
258: }
259:
260: public Iterator getReferenceKeys() {
261: if (map == null)
262: return Tools.EMPTY_ITERATOR;
263: return map.keySet().iterator();
264: }
265:
266: public void clearReferences() {
267: if (map != null)
268: map.clear();
269: if (list != null)
270: list.clear();
271: referencesUpToDate = false;
272: }
273:
274: public Object clone() {
275: ReferenceHandler clone = new ReferenceHandler();
276: if (map != null)
277: clone.map = (HashMap) map.clone();
278: if (list != null)
279: clone.list = (ArrayList) list.clone();
280: clone.referencesUpToDate = false;
281: return clone;
282: }
283:
284: class ReferenceEntry implements java.io.Serializable {
285: private static final long serialVersionUID = 1;
286: transient RefEntity reference;
287: Object id;
288: }
289:
290: }
|