View Javadoc

1   package org.apache.archiva.redback.components.jdo;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.commons.lang.StringUtils;
23  import org.slf4j.LoggerFactory;
24  
25  import javax.jdo.Extent;
26  import javax.jdo.JDOException;
27  import javax.jdo.JDOHelper;
28  import javax.jdo.JDOObjectNotFoundException;
29  import javax.jdo.JDOUserException;
30  import javax.jdo.PersistenceManager;
31  import javax.jdo.Query;
32  import javax.jdo.Transaction;
33  import java.util.Collection;
34  import java.util.Collections;
35  import java.util.Iterator;
36  import java.util.List;
37  
38  /**
39   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
40   */
41  public class RedbackJdoUtils
42  {
43      /**
44       * This operation as opposed to
45       * {@link #updateObject(PersistenceManager, Object)} is an
46       * <em>new school</em> technique, which <em><b>does not</b></em>
47       * requires that the object be previously added using
48       * {@link #addObject(PersistenceManager, Object)} or
49       * {@link #addObject(PersistenceManager, Object, String[])}.
50       *
51       * @param pm
52       * @param object
53       * @param fetchGroups
54       * @return
55       * @throws RedbackStoreException
56       * @see {@link #updateObject(PersistenceManager, Object)} for old technique.
57       */
58      public static Object saveObject( PersistenceManager pm, Object object, String fetchGroups[] )
59          throws RedbackStoreException
60      {
61          Transaction tx = pm.currentTransaction();
62  
63          try
64          {
65              tx.begin();
66  
67              if ( ( JDOHelper.getObjectId( object ) != null ) && !JDOHelper.isDetached( object ) )
68              {
69                  throw new RedbackStoreException( "Existing object is not detached: " + object );
70              }
71  
72              if ( fetchGroups != null )
73              {
74                  for ( int i = 0; i >= fetchGroups.length; i++ )
75                  {
76                      pm.getFetchPlan().addGroup( fetchGroups[i] );
77                  }
78              }
79  
80              pm.makePersistent( object );
81  
82              object = pm.detachCopy( object );
83  
84              tx.commit();
85  
86              return object;
87          }
88          finally
89          {
90              rollbackIfActive( tx );
91          }
92      }
93  
94      public static Object addObject( PersistenceManager pm, Object object )
95      {
96          return addObject( pm, object, null );
97      }
98  
99      public static Object addObject( PersistenceManager pm, Object object, String fetchGroups[] )
100     {
101         Transaction tx = pm.currentTransaction();
102 
103         try
104         {
105             tx.begin();
106 
107             if ( fetchGroups != null )
108             {
109                 for ( int i = 0; i >= fetchGroups.length; i++ )
110                 {
111                     pm.getFetchPlan().addGroup( fetchGroups[i] );
112                 }
113             }
114 
115             pm.makePersistent( object );
116 
117             object = pm.detachCopy( object );
118 
119             tx.commit();
120 
121             return object;
122         }
123         finally
124         {
125             rollbackIfActive( tx );
126         }
127     }
128 
129     public static void removeObject( PersistenceManager pm, Object o )
130     {
131         Transaction tx = pm.currentTransaction();
132 
133         try
134         {
135             tx.begin();
136 
137             o = pm.getObjectById( pm.getObjectId( o ) );
138 
139             pm.deletePersistent( o );
140 
141             tx.commit();
142         }
143         finally
144         {
145             rollbackIfActive( tx );
146         }
147     }
148 
149     /**
150      * This operation is an <em>old school</em> technique, which required that
151      * the object be previously added using
152      * {@link #addObject(PersistenceManager, Object)} or
153      * {@link #addObject(PersistenceManager, Object, String[])}.
154      *
155      * @param pm
156      * @param object
157      * @return
158      * @throws RedbackStoreException
159      * @see {@link #saveObject(PersistenceManager, Object, String[])}
160      */
161     public static Object updateObject( PersistenceManager pm, Object object )
162         throws RedbackStoreException
163     {
164         Object ret = object;
165         Transaction tx = pm.currentTransaction();
166 
167         try
168         {
169             tx.begin();
170 
171             if ( !JDOHelper.isDetached( object ) )
172             {
173                 throw new RedbackStoreException( "Not detached: " + object );
174             }
175 
176             try
177             {
178                 ret = pm.makePersistent( object );
179             }
180             catch ( NullPointerException npe )
181             {
182                 // Do not hide useful error messages.
183                 // This exception can occur if you have an object with a List
184                 // that isn't initialized yet.
185                 throw new RedbackStoreException( "Unable to update object due to unexpected null value.", npe );
186             }
187             catch ( Exception e )
188             {
189                 // TODO: Refactor to avoid using Exception catch-all.
190                 // We retry if we obtain an exception like a dead lock
191                 ret = pm.makePersistent( object );
192             }
193 
194             tx.commit();
195         }
196         finally
197         {
198             rollbackIfActive( tx );
199         }
200 
201         return ret;
202     }
203 
204     public static Object makePersistent( PersistenceManager pm, Object object, boolean detach )
205     {
206         pm.makePersistent( object );
207 
208         Object id = pm.getObjectId( object );
209 
210         Object persistentObject = pm.getObjectById( id );
211 
212         if ( detach )
213         {
214             persistentObject = pm.detachCopy( persistentObject );
215         }
216 
217         return persistentObject;
218     }
219 
220     public static Object getObjectById( PersistenceManager pm, Class clazz, String id )
221         throws RedbackObjectNotFoundException, RedbackStoreException
222     {
223         return getObjectById( pm, clazz, id, null );
224     }
225 
226     public static Object getObjectById( PersistenceManager pm, Class clazz, String id, String fetchGroup )
227         throws RedbackStoreException, RedbackObjectNotFoundException
228     {
229         if ( StringUtils.isBlank( id ) )
230         {
231             throw new RedbackStoreException( "Unable to get object '" + clazz.getName() + "' from jdo using null id." );
232         }
233 
234         Transaction tx = pm.currentTransaction();
235 
236         try
237         {
238             tx.begin();
239 
240             if ( fetchGroup != null )
241             {
242                 pm.getFetchPlan().addGroup( fetchGroup );
243             }
244 
245             Object objectId = pm.newObjectIdInstance( clazz, id );
246 
247             Object object = pm.getObjectById( objectId );
248 
249             object = pm.detachCopy( object );
250 
251             tx.commit();
252 
253             return object;
254         }
255         catch ( JDOObjectNotFoundException e )
256         {
257             throw new RedbackObjectNotFoundException( clazz.getName(), id );
258         }
259         catch ( JDOException e )
260         {
261             throw new RedbackStoreException( "Error handling JDO", e );
262         }
263         finally
264         {
265             rollbackIfActive( tx );
266         }
267     }
268 
269     /**
270      * @deprecated Use {@link #getObjectById(PersistenceManager, Class, long)}
271      *             instead
272      */
273     public static Object getObjectById( PersistenceManager pm, Class clazz, int id )
274         throws RedbackStoreException, RedbackObjectNotFoundException
275     {
276         return getObjectById( pm, clazz, (long) id );
277     }
278 
279     /**
280      * Obtain and return an {@link Object} instance from the underlying data
281      * store based on the passed in identifier.
282      *
283      * @param pm    {@link PersistenceManager} manager to use to query database.
284      * @param clazz Expected {@link Class} of the Object instance to be
285      *              returned.
286      * @param id    Object identifier to match in the database.
287      * @return Object instance that matches the passed in identifier.
288      * @throws RedbackStoreException          if there was an error querying the database
289      *                                       for the object.
290      * @throws RedbackObjectNotFoundException if a matching object could not be
291      *                                       found.
292      */
293     public static Object getObjectById( PersistenceManager pm, Class clazz, long id )
294         throws RedbackStoreException, RedbackObjectNotFoundException
295     {
296         return getObjectById( pm, clazz, id, null );
297     }
298 
299     /**
300      * @deprecated Use
301      *             {@link #getObjectById(PersistenceManager, Class, long, String)}
302      *             instead
303      */
304     public static Object getObjectById( PersistenceManager pm, Class clazz, int id, String fetchGroup )
305         throws RedbackStoreException, RedbackObjectNotFoundException
306     {
307         return getObjectById( pm, clazz, (long) id, fetchGroup );
308     }
309 
310     /**
311      * Obtain and return an {@link Object} instance from the underlying data
312      * store based on the passed in identifier.
313      *
314      * @param pm         {@link PersistenceManager} manager to use to query database.
315      * @param clazz      Expected {@link Class} of the Object instance to be
316      *                   returned.
317      * @param id         Object identifier to match in the database.
318      * @param fetchGroup TODO: Document!
319      * @return Object instance that matches the passed in identifier.
320      * @throws RedbackStoreException          if there was an error querying the database
321      *                                       for the object.
322      * @throws RedbackObjectNotFoundException if a matching object could not be
323      *                                       found.
324      */
325     public static Object getObjectById( PersistenceManager pm, Class clazz, long id, String fetchGroup )
326         throws RedbackStoreException, RedbackObjectNotFoundException
327     {
328         Transaction tx = pm.currentTransaction();
329 
330         try
331         {
332             tx.begin();
333 
334             if ( fetchGroup != null )
335             {
336                 pm.getFetchPlan().addGroup( fetchGroup );
337             }
338 
339             Object objectId = pm.newObjectIdInstance( clazz, Long.valueOf( id ) );
340 
341             Object object = pm.getObjectById( objectId );
342 
343             object = pm.detachCopy( object );
344 
345             tx.commit();
346 
347             return object;
348         }
349         catch ( JDOObjectNotFoundException e )
350         {
351             throw new RedbackObjectNotFoundException( clazz.getName(), Long.toString( id ) );
352         }
353         catch ( JDOException e )
354         {
355             LoggerFactory.getLogger( RedbackJdoUtils.class ).error( e.getMessage(), e );
356             throw new RedbackStoreException( "Error handling JDO", e );
357         }
358         finally
359         {
360             rollbackIfActive( tx );
361         }
362     }
363 
364     public static Object getObjectFromQuery( PersistenceManager pm, Class clazz, String idField, String id,
365                                              String fetchGroup )
366         throws RedbackStoreException, RedbackObjectNotFoundException
367     {
368         Transaction tx = pm.currentTransaction();
369 
370         try
371         {
372             tx.begin();
373 
374             Extent extent = pm.getExtent( clazz, true );
375 
376             Query query = pm.newQuery( extent );
377 
378             query.declareImports( "import java.lang.String" );
379 
380             query.declareParameters( "String " + idField );
381 
382             query.setFilter( "this." + idField + " == " + idField );
383 
384             Collection result = (Collection) query.execute( id );
385 
386             if ( result.size() == 0 )
387             {
388                 throw new RedbackObjectNotFoundException( clazz.getName(), id );
389             }
390 
391             if ( result.size() > 1 )
392             {
393                 throw new RedbackStoreException(
394                     "A query for object of " + "type " + clazz.getName() + " on the " + "field '" + idField
395                         + "' returned more than one object." );
396             }
397 
398             pm.getFetchPlan().addGroup( fetchGroup );
399 
400             Object object = pm.detachCopy( result.iterator().next() );
401 
402             tx.commit();
403 
404             return object;
405         }
406         finally
407         {
408             rollbackIfActive( tx );
409         }
410     }
411 
412     public static List getAllObjectsDetached( PersistenceManager pm, Class clazz )
413     {
414         return getAllObjectsDetached( pm, clazz, null );
415     }
416 
417     public static List getAllObjectsDetached( PersistenceManager pm, Class clazz, String fetchGroup )
418     {
419         return getAllObjectsDetached( pm, clazz, null, fetchGroup );
420     }
421 
422     public static List getAllObjectsDetached( PersistenceManager pm, Class clazz, String ordering, String fetchGroup )
423     {
424         if ( fetchGroup != null )
425         {
426             return getAllObjectsDetached( pm, clazz, ordering, Collections.singletonList( fetchGroup ) );
427         }
428         else
429         {
430             return getAllObjectsDetached( pm, clazz, ordering, Collections.EMPTY_LIST );
431         }
432     }
433 
434     public static List getAllObjectsDetached( PersistenceManager pm, Class clazz, String ordering,
435                                               List/* <String> */fetchGroups )
436     {
437         Transaction tx = pm.currentTransaction();
438 
439         try
440         {
441             tx.begin();
442 
443             Extent extent = pm.getExtent( clazz, true );
444 
445             Query query = pm.newQuery( extent );
446 
447             if ( ordering != null )
448             {
449                 query.setOrdering( ordering );
450             }
451 
452             for ( Iterator i = fetchGroups.iterator(); i.hasNext(); )
453             {
454                 pm.getFetchPlan().addGroup( (String) i.next() );
455             }
456 
457             List result = (List) query.execute();
458 
459             result = (List) pm.detachCopyAll( result );
460 
461             tx.commit();
462 
463             return result;
464         }
465         finally
466         {
467             rollbackIfActive( tx );
468         }
469     }
470 
471     public static void attachAndDelete( PersistenceManager pm, Object object )
472     {
473         Transaction tx = pm.currentTransaction();
474 
475         try
476         {
477             tx.begin();
478 
479             pm.makePersistent( object );
480 
481             pm.deletePersistent( object );
482 
483             tx.commit();
484         }
485         finally
486         {
487             rollbackIfActive( tx );
488         }
489     }
490 
491     public static void rollbackIfActive( Transaction tx )
492     {
493         PersistenceManager pm = tx.getPersistenceManager();
494 
495         try
496         {
497             if ( tx.isActive() )
498             {
499                 tx.rollback();
500             }
501         }
502         finally
503         {
504             closePersistenceManager( pm );
505         }
506     }
507 
508     public static void closePersistenceManager( PersistenceManager pm )
509     {
510         try
511         {
512             pm.close();
513         }
514         catch ( JDOUserException e )
515         {
516             // ignore
517         }
518     }
519 
520     public static void removeAll( PersistenceManager pm, Class aClass )
521     {
522         Transaction tx = pm.currentTransaction();
523 
524         try
525         {
526             tx.begin();
527 
528             Query query = pm.newQuery( aClass );
529             query.deletePersistentAll();
530 
531             tx.commit();
532         }
533         finally
534         {
535             rollbackIfActive( tx );
536         }
537     }
538 }