001: package org.apache.ojb.odmg;
002:
003: /* Copyright 2002-2005 The Apache Software Foundation
004: *
005: * Licensed under the Apache License, Version 2.0 (the "License");
006: * you may not use this file except in compliance with the License.
007: * You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: import java.io.Serializable;
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.Map;
022:
023: import org.apache.commons.lang.SerializationUtils;
024: import org.apache.ojb.broker.Identity;
025: import org.apache.ojb.broker.PersistenceBroker;
026: import org.apache.ojb.broker.PersistenceBrokerException;
027: import org.apache.ojb.broker.core.proxy.ProxyHelper;
028: import org.apache.ojb.broker.metadata.ClassDescriptor;
029: import org.apache.ojb.broker.util.ObjectModification;
030: import org.apache.ojb.broker.util.logging.Logger;
031: import org.apache.ojb.broker.util.logging.LoggerFactory;
032: import org.odmg.ClassNotPersistenceCapableException;
033: import org.odmg.ObjectNameNotFoundException;
034: import org.odmg.ObjectNameNotUniqueException;
035: import org.odmg.Transaction;
036:
037: /**
038: * ODMG NamedRoots implementation.
039: * this implementation stores the (name, Identity) pairs in
040: * a database table.
041: * therefore the NamedRootsMap underlies the same transaction management
042: * as all other persistent objects
043: *
044: * @author Thomas Mahler
045: * @version $Id: NamedRootsMap.java,v 1.12.2.5 2005/12/21 22:29:21 tomdz Exp $
046: */
047: public class NamedRootsMap {
048: private Logger log = LoggerFactory.getLogger(NamedRootsMap.class);
049: private TransactionImpl tx;
050: private HashMap tempBindings;
051: private Map deletionMap;
052: private Map insertMap;
053:
054: NamedRootsMap(TransactionImpl tx) {
055: this .tx = tx;
056: this .tempBindings = new HashMap();
057: }
058:
059: private void addForDeletion(NamedEntry entry) {
060: if (deletionMap == null) {
061: deletionMap = new HashMap();
062: }
063: deletionMap.put(entry.getName(), entry);
064: }
065:
066: private void addForInsert(NamedEntry entry) {
067: if (insertMap == null) {
068: insertMap = new HashMap();
069: }
070: insertMap.put(entry.getName(), entry);
071: if (deletionMap != null)
072: deletionMap.remove(entry.getName());
073: }
074:
075: /**
076: * Have to be performed after the "normal" objects be written
077: * to DB and before method {@link #performInsert()}.
078: */
079: public void performDeletion() {
080: if (deletionMap == null)
081: return;
082: else {
083: PersistenceBroker broker = tx.getBroker();
084: Iterator it = deletionMap.values().iterator();
085: while (it.hasNext()) {
086: NamedEntry namedEntry = (NamedEntry) it.next();
087: broker.delete(namedEntry);
088: }
089: }
090: }
091:
092: /**
093: * Have to be performed after the "normal" objects be written
094: * to DB and after method {@link #performDeletion()}.
095: */
096: public void performInsert() {
097: if (insertMap == null)
098: return;
099: else {
100: PersistenceBroker broker = tx.getBroker();
101: Iterator it = insertMap.values().iterator();
102: while (it.hasNext()) {
103: NamedEntry namedEntry = (NamedEntry) it.next();
104: namedEntry.prepareForStore(broker);
105: broker.store(namedEntry, ObjectModification.INSERT);
106: }
107: }
108: }
109:
110: public void afterWriteCleanup() {
111: if (deletionMap != null)
112: deletionMap.clear();
113: if (insertMap != null)
114: insertMap.clear();
115: }
116:
117: private void localBind(String key, NamedEntry entry)
118: throws ObjectNameNotUniqueException {
119: if (tempBindings.containsKey(key)) {
120: throw new ObjectNameNotUniqueException(
121: "Object key already in use, the key '" + key
122: + "' is not unique");
123: } else {
124: tempBindings.put(key, entry);
125: }
126: }
127:
128: private void localUnbind(String key) {
129: tempBindings.remove(key);
130: }
131:
132: private NamedEntry localLookup(String key) {
133: return (NamedEntry) tempBindings.get(key);
134: }
135:
136: /**
137: * Return a named object associated with the specified key.
138: */
139: Object lookup(String key) throws ObjectNameNotFoundException {
140: Object result = null;
141: NamedEntry entry = localLookup(key);
142: // can't find local bound object
143: if (entry == null) {
144: try {
145: PersistenceBroker broker = tx.getBroker();
146: // build Identity to lookup entry
147: Identity oid = broker.serviceIdentity().buildIdentity(
148: NamedEntry.class, key);
149: entry = (NamedEntry) broker.getObjectByIdentity(oid);
150: } catch (Exception e) {
151: log.error("Can't materialize bound object for key '"
152: + key + "'", e);
153: }
154: }
155: if (entry == null) {
156: log.info("No object found for key '" + key + "'");
157: } else {
158: Object obj = entry.getObject();
159: // found a persistent capable object associated with that key
160: if (obj instanceof Identity) {
161: Identity objectIdentity = (Identity) obj;
162: result = tx.getBroker().getObjectByIdentity(
163: objectIdentity);
164: // lock the persistance capable object
165: RuntimeObject rt = new RuntimeObject(result,
166: objectIdentity, tx, false);
167: tx.lockAndRegister(rt, Transaction.READ, tx
168: .getRegistrationList());
169: } else {
170: // nothing else to do
171: result = obj;
172: }
173: }
174: if (result == null)
175: throw new ObjectNameNotFoundException(
176: "Can't find named object for name '" + key + "'");
177: return result;
178: }
179:
180: /**
181: * Remove a named object
182: */
183: void unbind(String key) {
184: NamedEntry entry = new NamedEntry(key, null, false);
185: localUnbind(key);
186: addForDeletion(entry);
187: }
188:
189: public void bind(Object object, String name)
190: throws ObjectNameNotUniqueException {
191: boolean useIdentity = true;
192: PersistenceBroker broker = tx.getBroker();
193: ClassDescriptor cld = null;
194: try {
195: cld = broker.getClassDescriptor(ProxyHelper
196: .getRealClass(object));
197: } catch (PersistenceBrokerException e) {
198: }
199:
200: // if null a non-persistent capable object was specified
201: if (cld == null) {
202: useIdentity = false;
203: if (!(object instanceof Serializable)) {
204: throw new ClassNotPersistenceCapableException(
205: "Can't bind named object, because it's not Serializable. Name="
206: + name + ", object=" + object);
207: }
208: } else {
209: RuntimeObject rt = new RuntimeObject(object, tx);
210: // if the object is already persistet, check for read
211: // lock to make sure
212: // that the used object is a valid version
213: // else persist the specified named object
214: if (!rt.isNew()) {
215: tx.lockAndRegister(rt, Transaction.READ, tx
216: .getRegistrationList());
217: } else {
218: tx.makePersistent(rt);
219: }
220: }
221: NamedEntry oldEntry = localLookup(name);
222: if (oldEntry == null) {
223: Identity oid = broker.serviceIdentity().buildIdentity(
224: NamedEntry.class, name);
225: oldEntry = (NamedEntry) broker.getObjectByIdentity(oid);
226: }
227: if (oldEntry != null) {
228: throw new ObjectNameNotUniqueException(
229: "The name of the specified named object already exist, name="
230: + name);
231: }
232:
233: NamedEntry entry = new NamedEntry(name, object, useIdentity);
234: addForInsert(entry);
235: localBind(name, entry);
236: }
237:
238: //==============================================
239: // inner class
240: //==============================================
241: /**
242: * represents an entry to the named roots table.
243: * maps names (Strings) to OJB Identities
244: */
245: public static final class NamedEntry implements Serializable {
246: static final long serialVersionUID = 6179717896336300342L;
247: /**
248: * the name under which an object is registered in the NamedRoots Map
249: */
250: private String name;
251: /**
252: * the serialized Identity representing the named Object
253: */
254: private byte[] oid;
255:
256: private transient Object object;
257: private transient boolean useIdentity;
258:
259: public NamedEntry() {
260: }
261:
262: NamedEntry(final String aName, final Object object,
263: final boolean useIdentity) {
264: this .name = aName;
265: this .object = object;
266: this .useIdentity = useIdentity;
267: }
268:
269: /**
270: * This has to be called before this object will be persistet.
271: */
272: public void prepareForStore(PersistenceBroker broker) {
273: if (object != null) {
274: if (useIdentity) {
275: Identity oid = broker.serviceIdentity()
276: .buildIdentity(object);
277: this .oid = SerializationUtils.serialize(oid);
278: } else {
279: this .oid = SerializationUtils
280: .serialize((Serializable) object);
281: }
282: }
283: }
284:
285: public String getName() {
286: return name;
287: }
288:
289: public void setName(String name) {
290: this .name = name;
291: }
292:
293: public byte[] getOid() {
294: return oid;
295: }
296:
297: public void setOid(byte[] oid) {
298: this .oid = oid;
299: }
300:
301: Object getObject() {
302: if (object != null) {
303: return object;
304: } else {
305: return oid != null ? SerializationUtils
306: .deserialize(oid) : null;
307: }
308: }
309: }
310: }
|