001: /**********************************************************************
002: Copyright (c) 2006 Andy Jefferson and others. All rights reserved.
003: Licensed under the Apache License, Version 2.0 (the "License");
004: you may not use this file except in compliance with the License.
005: You may obtain a copy of the License at
006:
007: http://www.apache.org/licenses/LICENSE-2.0
008:
009: Unless required by applicable law or agreed to in writing, software
010: distributed under the License is distributed on an "AS IS" BASIS,
011: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: See the License for the specific language governing permissions and
013: limitations under the License.
014:
015: Contributors:
016: ...
017: **********************************************************************/package org.jpox.jdo;
018:
019: import java.sql.SQLException;
020: import java.util.Collection;
021:
022: import javax.jdo.JDODataStoreException;
023: import javax.jdo.JDOException;
024: import javax.jdo.JDOFatalDataStoreException;
025: import javax.jdo.JDOFatalInternalException;
026: import javax.jdo.JDOFatalUserException;
027: import javax.jdo.JDOHelper;
028: import javax.jdo.JDOObjectNotFoundException;
029: import javax.jdo.JDOOptimisticVerificationException;
030: import javax.jdo.JDOUnsupportedOptionException;
031: import javax.jdo.JDOUserException;
032: import javax.jdo.PersistenceManager;
033: import javax.jdo.PersistenceManagerFactory;
034: import javax.jdo.spi.PersistenceCapable;
035: import javax.transaction.xa.XAException;
036:
037: import org.jpox.StateManager;
038: import org.jpox.exceptions.ClassNotPersistableException;
039: import org.jpox.exceptions.JPOXDataStoreException;
040: import org.jpox.exceptions.JPOXException;
041: import org.jpox.exceptions.JPOXObjectNotFoundException;
042: import org.jpox.exceptions.JPOXOptimisticException;
043: import org.jpox.exceptions.JPOXUnsupportedOptionException;
044: import org.jpox.exceptions.JPOXUserException;
045: import org.jpox.exceptions.NoPersistenceInformationException;
046: import org.jpox.jdo.exceptions.ClassNotPersistenceCapableException;
047: import org.jpox.metadata.ClassMetaData;
048: import org.jpox.metadata.MetaDataManager;
049: import org.jpox.state.StateManagerFactory;
050: import org.jpox.util.Localiser;
051:
052: /**
053: * Helper for persistence operations with JPOX.
054: * Extends JDOHelper so that people can use JPOXHelper if they wish.
055: *
056: * @version $Revision: 1.17 $
057: */
058: public class JPOXJDOHelper extends JDOHelper {
059: /** Localisation utility for output messages */
060: protected static final Localiser LOCALISER = Localiser
061: .getInstance("org.jpox.Localisation");
062:
063: // ------------------------------ Class MetaData --------------------------------
064:
065: /**
066: * Accessor for the JPOX MetaData for the specified class
067: * @param pmf PersistenceManager factory
068: * @param cls The class
069: * @return The MetaData for the class
070: */
071: public static ClassMetaData getMetaDataForClass(
072: PersistenceManagerFactory pmf, Class cls) {
073: if (pmf == null || cls == null) {
074: return null;
075: }
076: if (!(pmf instanceof AbstractPersistenceManagerFactory)) {
077: return null;
078: }
079:
080: AbstractPersistenceManagerFactory jpoxPMF = (AbstractPersistenceManagerFactory) pmf;
081: MetaDataManager mdmgr = jpoxPMF.getOMFContext()
082: .getMetaDataManager();
083: return (ClassMetaData) mdmgr.getMetaDataForClass(cls, jpoxPMF
084: .getOMFContext().getClassLoaderResolver(null));
085: }
086:
087: /**
088: * Accessor for the names of the classes that have MetaData for this PMF.
089: * @param pmf The PMF
090: * @return The class names
091: */
092: public static String[] getClassesWithMetaData(
093: PersistenceManagerFactory pmf) {
094: if (pmf == null
095: || !(pmf instanceof AbstractPersistenceManagerFactory)) {
096: return null;
097: }
098:
099: AbstractPersistenceManagerFactory jpoxPMF = (AbstractPersistenceManagerFactory) pmf;
100: Collection classes = jpoxPMF.getOMFContext()
101: .getMetaDataManager().getClassesWithMetaData();
102: return (String[]) classes.toArray(new String[classes.size()]);
103: }
104:
105: // ------------------------------ Object Lifecycle --------------------------------
106:
107: /**
108: * Convenience method to return a string of the state of an object.
109: * Will return things like "detached-dirty", "persistent-clean", etc
110: * TODO Remove this when JDOHelper has getObjectState() method returning ObjectState enum.
111: * @param obj The object
112: * @return The state
113: */
114: public static String getObjectStateAsString(Object obj) {
115: if (obj == null) {
116: return null;
117: }
118:
119: if (isDetached(obj) && isDirty(obj)) {
120: return "detached-dirty";
121: } else if (isDetached(obj) && !isDirty(obj)) {
122: return "detached-clean";
123: } else if (isPersistent(obj) && isDirty(obj) && !isNew(obj)
124: && isTransactional(obj) && !isDeleted(obj)) {
125: return "persistent-dirty";
126: } else if (isPersistent(obj) && !isNew(obj) && !isDirty(obj)
127: && isTransactional(obj) && !isDeleted(obj)) {
128: return "persistent-clean";
129: } else if (isPersistent(obj) && isNew(obj) && isDirty(obj)
130: && isTransactional(obj) && !isDeleted(obj)) {
131: return "persistent-new";
132: } else if (isPersistent(obj) && isNew(obj) && isDirty(obj)
133: && isTransactional(obj) && isDeleted(obj)) {
134: return "persistent-new-deleted";
135: } else if (isPersistent(obj) && !isNew(obj) && isDirty(obj)
136: && isTransactional(obj) && isDeleted(obj)) {
137: return "persistent-deleted";
138: } else if (isPersistent(obj) && !isNew(obj) && !isDirty(obj)
139: && !isDeleted(obj) && !isTransactional(obj)) {
140: return "hollow / persistent-nontransactional";
141: } else if (isPersistent(obj) && !isNew(obj) && isDirty(obj)
142: && !isDeleted(obj) && !isTransactional(obj)) {
143: return "persistent-nontransactional-dirty";
144: } else if (!isPersistent(obj) && !isNew(obj) && isDirty(obj)
145: && isTransactional(obj) && !isDeleted(obj)) {
146: return "transient-dirty";
147: } else if (!isPersistent(obj) && !isNew(obj) && !isDirty(obj)
148: && isTransactional(obj) && !isDeleted(obj)) {
149: return "transient-clean";
150: } else if (!isPersistent(obj) && !isNew(obj) && !isDirty(obj)
151: && !isTransactional(obj) && !isDeleted(obj)) {
152: return "transient-clean";
153: }
154:
155: return "transient";
156: }
157:
158: /**
159: * Method to return the names of all fields that are currently dirty in the
160: * passed detached object.
161: * TODO Try to remove the need for the PM. We currently use it to generate the temporary StateManager
162: * @param obj The PersistenceCapable (detached)
163: * @param pm PersistenceManager to use
164: * @return Names of the fields that are dirty
165: * @throws JPOXUserException Thrown if the object is not detached
166: */
167: public static String[] getDetachedObjectDirtyFields(Object obj,
168: PersistenceManager pm) {
169: if (obj == null) {
170: return null;
171: }
172: if (!isDetached(obj)) {
173: throw new JPOXUserException(LOCALISER.msg("010008"));
174: }
175:
176: // Create a StateManager to give us a means of extracting the detached info
177: PersistenceCapable pc = (PersistenceCapable) obj;
178: org.jpox.ObjectManager thePM = ((AbstractPersistenceManager) pm)
179: .getObjectManager();
180: StateManager sm = StateManagerFactory
181: .newStateManagerForDetached(thePM, pc, getObjectId(pc),
182: null);
183: pc.jdoReplaceStateManager((javax.jdo.spi.StateManager) sm); // Assign this StateManager to our detached object
184: sm.retrieveDetachState(sm);
185: String[] dirtyFieldNames = sm.getDirtyFieldNames();
186: pc.jdoReplaceStateManager(null); // Remove the StateManager from our detached object
187:
188: return dirtyFieldNames;
189: }
190:
191: /**
192: * Method to return the names of all fields that are currently loaded in the
193: * passed detached object.
194: * TODO Try to remove the need for the PM. We currently use it to generate the temporary StateManager
195: * @param obj The PersistenceCapable (detached)
196: * @param pm PersistenceManager to use
197: * @return Names of the fields that are loaded
198: * @throws JPOXUserException Thrown if the object is not detached
199: */
200: public static String[] getDetachedObjectLoadedFields(Object obj,
201: PersistenceManager pm) {
202: if (obj == null) {
203: return null;
204: }
205: if (!isDetached(obj)) {
206: throw new JPOXUserException(LOCALISER.msg("010008"));
207: }
208:
209: // Create a StateManager to give us a means of extracting the detached info
210: PersistenceCapable pc = (PersistenceCapable) obj;
211: org.jpox.ObjectManager thePM = ((AbstractPersistenceManager) pm)
212: .getObjectManager();
213: StateManager sm = StateManagerFactory
214: .newStateManagerForDetached(thePM, pc, getObjectId(pc),
215: null);
216: pc.jdoReplaceStateManager((javax.jdo.spi.StateManager) sm); // Assign this StateManager to our detached object
217: sm.retrieveDetachState(sm);
218: String[] loadedFieldNames = sm.getLoadedFieldNames();
219: pc.jdoReplaceStateManager(null); // Remove the StateManager from our detached object
220:
221: return loadedFieldNames;
222: }
223:
224: // ------------------------------ Convenience --------------------------------
225:
226: /**
227: * Convenience method to convert a JPOX exception into a JDO exception.
228: * If the incoming exception has a "failed object" then create the new exception with
229: * a failed object. Otherwise if the incoming exception has nested exceptions then
230: * create this exception with those nested exceptions. Else create this exception with
231: * the incoming exception as its nested exception.
232: * @param jpe JPOXException
233: * @return The JDOException
234: */
235: public static JDOException getJDOExceptionForJPOXException(
236: JPOXException jpe) {
237: // Specific exceptions first
238: if (jpe instanceof ClassNotPersistableException) {
239: return new ClassNotPersistenceCapableException(jpe
240: .getMessage(), jpe);
241: } else if (jpe instanceof NoPersistenceInformationException) {
242: return new org.jpox.jdo.exceptions.NoPersistenceInformationException(
243: jpe.getMessage(), jpe);
244: } else if (jpe instanceof JPOXUnsupportedOptionException) {
245: return new JDOUnsupportedOptionException(jpe.getMessage(),
246: jpe);
247: } else if (jpe instanceof JPOXDataStoreException) {
248: if (jpe.isFatal()) {
249: //sadly JDOFatalDataStoreException dont allow nested exceptions and failed objects together
250: if (jpe.getFailedObject() != null) {
251: return new JDOFatalDataStoreException(jpe
252: .getMessage(), jpe.getFailedObject());
253: } else if (jpe.getNestedExceptions() != null) {
254: return new JDOFatalDataStoreException(jpe
255: .getMessage(), jpe.getNestedExceptions());
256: } else {
257: return new JDOFatalDataStoreException(jpe
258: .getMessage(), jpe);
259: }
260: } else {
261: if (jpe.getNestedExceptions() != null) {
262: if (jpe.getFailedObject() != null) {
263: return new JDODataStoreException(jpe
264: .getMessage(), jpe
265: .getNestedExceptions(), jpe
266: .getFailedObject());
267: }
268: return new JDODataStoreException(jpe.getMessage(),
269: jpe.getNestedExceptions());
270: } else if (jpe.getFailedObject() != null) {
271: return new JDODataStoreException(jpe.getMessage(),
272: jpe.getFailedObject());
273: } else {
274: return new JDODataStoreException(jpe.getMessage(),
275: jpe);
276: }
277: }
278: } else if (jpe instanceof JPOXObjectNotFoundException) {
279: //sadly JDOObjectNotFoundException dont allow nested exceptions and failed objects together
280: if (jpe.getFailedObject() != null) {
281: return new JDOObjectNotFoundException(jpe.getMessage(),
282: jpe.getFailedObject());
283: } else if (jpe.getNestedExceptions() != null) {
284: return new JDOObjectNotFoundException(jpe.getMessage(),
285: jpe.getNestedExceptions());
286: } else {
287: return new JDOFatalDataStoreException(jpe.getMessage(),
288: jpe);
289: }
290: } else if (jpe instanceof JPOXUserException) {
291: if (jpe.isFatal()) {
292: if (jpe.getNestedExceptions() != null) {
293: if (jpe.getFailedObject() != null) {
294: return new JDOFatalUserException(jpe
295: .getMessage(), jpe
296: .getNestedExceptions(), jpe
297: .getFailedObject());
298: }
299: return new JDOFatalUserException(jpe.getMessage(),
300: jpe.getNestedExceptions());
301: } else if (jpe.getFailedObject() != null) {
302: return new JDOFatalUserException(jpe.getMessage(),
303: jpe.getFailedObject());
304: } else {
305: return new JDOFatalUserException(jpe.getMessage(),
306: jpe);
307: }
308: } else {
309: if (jpe.getNestedExceptions() != null) {
310: if (jpe.getFailedObject() != null) {
311: return new JDOUserException(jpe.getMessage(),
312: jpe.getNestedExceptions(), jpe
313: .getFailedObject());
314: }
315: return new JDOUserException(jpe.getMessage(), jpe
316: .getNestedExceptions());
317: } else if (jpe.getFailedObject() != null) {
318: return new JDOUserException(jpe.getMessage(), jpe
319: .getFailedObject());
320: } else {
321: return new JDOUserException(jpe.getMessage(), jpe);
322: }
323: }
324: } else if (jpe instanceof JPOXOptimisticException) {
325: //sadly JDOOptimisticVerificationException dont allow nested exceptions and failed objects together
326: if (jpe.getFailedObject() != null) {
327: return new JDOOptimisticVerificationException(jpe
328: .getMessage(), jpe.getFailedObject());
329: } else if (jpe.getNestedExceptions() != null) {
330: return new JDOOptimisticVerificationException(jpe
331: .getMessage(), jpe.getNestedExceptions());
332: } else {
333: return new JDOOptimisticVerificationException(jpe
334: .getMessage(), jpe);
335: }
336: } else if (jpe instanceof org.jpox.transaction.HeuristicRollbackException
337: && jpe.getNestedExceptions().length == 1
338: && jpe.getNestedExceptions()[0].getCause() instanceof SQLException) {
339: // if there was a single failure in the transaction, we want to properly propagate the
340: // single nested SQLException that was the cause of the failure, so application code
341: // can decide on what to do with it
342: return new JDODataStoreException(jpe.getMessage(),
343: ((XAException) jpe.getNestedExceptions()[0])
344: .getCause());
345: } else {
346: if (jpe.isFatal()) {
347: if (jpe.getNestedExceptions() != null) {
348: return new JDOFatalInternalException(jpe
349: .getMessage(), jpe.getNestedExceptions());
350: } else {
351: return new JDOFatalInternalException(jpe
352: .getMessage(), jpe);
353: }
354: } else if (jpe.getNestedExceptions() != null) {
355: return new JDOException(jpe.getMessage(), jpe
356: .getNestedExceptions());
357: } else {
358: return new JDOException(jpe.getMessage(), jpe);
359: }
360: }
361: }
362: }
|