This project has retired. For details please refer to its Attic page.
JdoAccess xref
View Javadoc

1   package org.apache.maven.archiva.database.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.apache.maven.archiva.database.ArchivaDatabaseException;
24  import org.apache.maven.archiva.database.Constraint;
25  import org.apache.maven.archiva.database.DeclarativeConstraint;
26  import org.apache.maven.archiva.database.ObjectNotFoundException;
27  import org.apache.maven.archiva.database.SimpleConstraint;
28  import org.apache.maven.archiva.database.constraints.AbstractSimpleConstraint;
29  import org.apache.maven.archiva.model.CompoundKey;
30  import org.codehaus.plexus.jdo.JdoFactory;
31  import org.codehaus.plexus.personality.plexus.lifecycle.phase.Initializable;
32  import org.codehaus.plexus.personality.plexus.lifecycle.phase.InitializationException;
33  
34  import java.io.PrintStream;
35  import java.util.ArrayList;
36  import java.util.List;
37  import javax.jdo.Extent;
38  import javax.jdo.JDOException;
39  import javax.jdo.JDOHelper;
40  import javax.jdo.JDOObjectNotFoundException;
41  import javax.jdo.JDOUserException;
42  import javax.jdo.PersistenceManager;
43  import javax.jdo.PersistenceManagerFactory;
44  import javax.jdo.Query;
45  import javax.jdo.Transaction;
46  import javax.jdo.datastore.DataStoreCache;
47  import javax.jdo.listener.InstanceLifecycleEvent;
48  import javax.jdo.listener.InstanceLifecycleListener;
49  import javax.jdo.listener.StoreLifecycleListener;
50  import javax.jdo.spi.Detachable;
51  import javax.jdo.spi.PersistenceCapable;
52  
53  /**
54   * JdoAccess 
55   *
56   * @version $Id: JdoAccess.java 1043850 2010-12-09 07:58:00Z brett $
57   * @plexus.component role="org.apache.maven.archiva.database.jdo.JdoAccess" role-hint="archiva"
58   */
59  public class JdoAccess
60      implements Initializable, InstanceLifecycleListener, StoreLifecycleListener
61  {
62      /**
63       * @plexus.requirement role-hint="archiva"
64       */
65      private JdoFactory jdoFactory;
66  
67      private PersistenceManagerFactory pmf;
68  
69      public void initialize()
70          throws InitializationException
71      {
72          pmf = jdoFactory.getPersistenceManagerFactory();
73  
74          /* Primitive (and failed) attempt at creating the schema on startup.
75           Just to prevent the multiple stack trace warnings on auto-gen of schema.
76           
77           // Create the schema (if needed)
78           URL jdoFileUrls[] = new URL[] { getClass().getResource( "/org/apache/maven/archiva/model/package.jdo" ) };
79  
80           File propsFile = null; // intentional
81           boolean verbose = true;
82  
83           try
84           {
85           String connectionFactoryName = pmf.getConnectionFactoryName();
86           if ( StringUtils.isNotBlank( connectionFactoryName ) && connectionFactoryName.startsWith( "java:comp" ) )
87           {
88           // We have a JNDI datasource!
89           String jndiDatasource = connectionFactoryName;
90           System.setProperty( PMFConfiguration.JDO_DATASTORE_URL_PROPERTY, jndiDatasource );
91           }
92           
93           // TODO: figure out how to get the jdbc driver details from JNDI to pass into SchemaTool.
94  
95           SchemaTool.createSchemaTables( jdoFileUrls, new URL[] {}, propsFile, verbose, null );
96           }
97           catch ( Exception e )
98           {
99           getLogger().error( "Unable to create schema: " + e.getMessage(), e );
100          }
101 
102          pmf.getPersistenceManager();
103          */
104 
105         // Add the lifecycle listener.
106         pmf.addInstanceLifecycleListener( this, null );
107     }
108 
109     public static void dumpObjectState( PrintStream out, Object o )
110     {
111         final String STATE = "[STATE] ";
112         final String INDENT = "        ";
113 
114         if ( o == null )
115         {
116             out.println( STATE + "Object is null." );
117             return;
118         }
119 
120         out.println( STATE + "Object " + o.getClass().getName() );
121 
122         if ( !( o instanceof PersistenceCapable ) )
123         {
124             out.println( INDENT + "is NOT PersistenceCapable (not a jdo object?)" );
125             return;
126         }
127 
128         out.println( INDENT + "is PersistenceCapable." );
129         if ( o instanceof Detachable )
130         {
131             out.println( INDENT + "is Detachable" );
132         }
133 
134         out.println( INDENT + "is new : " + Boolean.toString( JDOHelper.isNew( o ) ) );
135         out.println( INDENT + "is transactional : " + Boolean.toString( JDOHelper.isTransactional( o ) ) );
136         out.println( INDENT + "is deleted : " + Boolean.toString( JDOHelper.isDeleted( o ) ) );
137         out.println( INDENT + "is detached : " + Boolean.toString( JDOHelper.isDetached( o ) ) );
138         out.println( INDENT + "is dirty : " + Boolean.toString( JDOHelper.isDirty( o ) ) );
139         out.println( INDENT + "is persistent : " + Boolean.toString( JDOHelper.isPersistent( o ) ) );
140 
141         out.println( INDENT + "object id : " + JDOHelper.getObjectId( o ) );
142     }
143 
144     public PersistenceManager getPersistenceManager()
145     {
146         PersistenceManager pm = pmf.getPersistenceManager();
147 
148         pm.getFetchPlan().setMaxFetchDepth( -1 );
149 
150         return pm;
151     }
152 
153     public void enableCache( Class<?> clazz )
154     {
155         DataStoreCache cache = pmf.getDataStoreCache();
156         cache.pinAll( clazz, false ); // Pin all objects of type clazz from now on
157     }
158 
159     public Object saveObject( Object object )
160     {
161         return saveObject( object, null );
162     }
163 
164     public Object saveObject( Object object, String[] fetchGroups )
165     {
166         PersistenceManager pm = getPersistenceManager();
167         Transaction tx = pm.currentTransaction();
168 
169         try
170         {
171             tx.begin();
172 
173             if ( ( JDOHelper.getObjectId( object ) != null ) && !JDOHelper.isDetached( object ) )
174             {
175                 // This is a fatal error that means we need to fix our code.
176                 // Leave it as a JDOUserException, it's intentional.
177                 throw new JDOUserException( "Existing object is not detached: " + object, object );
178             }
179 
180             if ( fetchGroups != null )
181             {
182                 for ( int i = 0; i >= fetchGroups.length; i++ )
183                 {
184                     pm.getFetchPlan().addGroup( fetchGroups[i] );
185                 }
186             }
187 
188             pm.makePersistent( object );
189 
190             object = pm.detachCopy( object );
191 
192             tx.commit();
193 
194             return object;
195         }
196         finally
197         {
198             rollbackIfActive( tx );
199         }
200     }
201 
202     public List<?> getAllObjects( Class<?> clazz )
203     {
204         return queryObjects( clazz, null );
205     }
206 
207     public List<?> queryObjects( Class<?> clazz, Constraint constraint )
208     {
209         PersistenceManager pm = getPersistenceManager();
210         Transaction tx = pm.currentTransaction();
211 
212         List<?> result = null;
213 
214         try
215         {
216             tx.begin();
217 
218             if ( constraint != null )
219             {
220                 if ( constraint instanceof DeclarativeConstraint )
221                 {
222                     result = processConstraint( pm, clazz, (DeclarativeConstraint) constraint );
223                 }
224                 else if ( constraint instanceof AbstractSimpleConstraint )
225                 {
226                     result = processConstraint( pm, (SimpleConstraint) constraint );
227                 }
228                 else
229                 {
230                     result = processUnconstrained( pm, clazz );
231                 }
232             }
233             else
234             {
235                 result = processUnconstrained( pm, clazz );
236             }
237 
238             result = (List<?>) pm.detachCopyAll( result );
239 
240             tx.commit();
241         }
242         finally
243         {
244             rollbackIfActive( tx );
245         }
246 
247         return result;
248     }
249 
250     public List<?> queryObjects( SimpleConstraint constraint )
251     {
252         PersistenceManager pm = getPersistenceManager();
253         Transaction tx = pm.currentTransaction();
254 
255         try
256         {
257             tx.begin();
258 
259             List<?> result = processConstraint( pm, constraint );
260 
261             // Only detach if results are known to be persistable.
262             if ( constraint.isResultsPersistable() )
263             {
264                 result = (List<?>) pm.detachCopyAll( result );
265             }
266             else
267             {
268                 List<Object> copiedResults = new ArrayList<Object>();
269                 copiedResults.addAll( result );
270                 result = copiedResults;
271             }
272 
273             tx.commit();
274 
275             return result;
276         }
277         finally
278         {
279             rollbackIfActive( tx );
280         }
281     }
282 
283     private List<?> processUnconstrained( PersistenceManager pm, Class<?> clazz )
284     {
285         Extent extent = pm.getExtent( clazz, true );
286         Query query = pm.newQuery( extent );
287         return (List<?>) query.execute();
288     }
289 
290     private List<?> processConstraint( PersistenceManager pm, SimpleConstraint constraint )
291     {
292         Query query = pm.newQuery( constraint.getSelectSql() );
293 
294         if ( constraint.getResultClass() == null )
295         {
296             throw new IllegalStateException( "Unable to use a SimpleConstraint with a null result class." );
297         }
298 
299         query.setResultClass( constraint.getResultClass() );
300 
301         if ( constraint.getFetchLimits() != null )
302         {
303             pm.getFetchPlan().addGroup( constraint.getFetchLimits() );
304         }
305 
306         List<?> objects;
307         if ( constraint.getParameters() != null )
308         {
309             objects = processParameterizedQuery( query, constraint.getParameters() );
310         }
311         else
312         {
313             objects = (List<?>) query.execute();
314         }
315         return objects;
316     }
317 
318     private List<?> processConstraint( PersistenceManager pm, Class<?> clazz, DeclarativeConstraint constraint )
319     {
320         Extent extent = pm.getExtent( clazz, true );
321         Query query = pm.newQuery( extent );
322 
323         if ( constraint.getFilter() != null )
324         {
325             query.setFilter( constraint.getFilter() );
326         }
327 
328         if ( constraint.getVariables() != null )
329         {
330             query.declareVariables( StringUtils.join( constraint.getVariables(), ";  " ) );
331         }
332 
333         if ( constraint.getSortColumn() != null )
334         {
335             String ordering = constraint.getSortColumn();
336 
337             if ( constraint.getSortDirection() != null )
338             {
339                 ordering += " " + constraint.getSortDirection();
340             }
341 
342             query.setOrdering( ordering );
343         }
344 
345         if ( constraint.getFetchLimits() != null )
346         {
347             pm.getFetchPlan().addGroup( constraint.getFetchLimits() );
348         }
349 
350         if ( constraint.getWhereCondition() != null )
351         {
352             query.setFilter( constraint.getWhereCondition() );
353         }
354 
355         if ( constraint.getDeclaredImports() != null )
356         {
357             query.declareImports( StringUtils.join( constraint.getDeclaredImports(), ", " ) );
358         }
359 
360         if ( constraint.getRange() != null )
361         {
362         	query.setRange( constraint.getRange()[0], constraint.getRange()[1] );
363         }
364 
365         if ( constraint.getDeclaredParameters() != null )
366         {
367             if ( constraint.getParameters() == null )
368             {
369                 throw new JDOException( "Unable to use query, there are declared parameters, "
370                     + "but no parameter objects to use." );
371             }
372 
373             if ( constraint.getParameters().length != constraint.getDeclaredParameters().length )
374             {
375                 throw new JDOException( "Unable to use query, there are <" + constraint.getDeclaredParameters().length
376                     + "> declared parameters, yet there are <" + constraint.getParameters().length
377                     + "> parameter objects to use.  This should be equal." );
378             }
379 
380             query.declareParameters( StringUtils.join( constraint.getDeclaredParameters(), ", " ) );
381 
382             return processParameterizedQuery( query, constraint.getParameters() );
383         }
384         else
385         {
386             return (List<?>) query.execute();
387         }
388     }
389 
390     private List<?> processParameterizedQuery( Query query, Object parameters[] )
391     {
392         switch ( parameters.length )
393         {
394             case 1:
395                 return (List<?>) query.execute( parameters[0] );
396             case 2:
397                 return (List<?>) query.execute( parameters[0], parameters[1] );
398             case 3:
399                 return (List<?>) query.execute( parameters[0], parameters[1], parameters[2] );
400             default:
401                 return (List<?>) query.executeWithArray( parameters );                
402         }
403     }
404 
405     public Object getObjectById( Class<?> clazz, Object id, String fetchGroup )
406         throws ObjectNotFoundException, ArchivaDatabaseException
407     {
408         if ( id == null )
409         {
410             throw new ObjectNotFoundException( "Unable to get object '" + clazz.getName() + "' from jdo using null id." );
411         }
412 
413         PersistenceManager pm = getPersistenceManager();
414         Transaction tx = pm.currentTransaction();
415 
416         try
417         {
418             tx.begin();
419 
420             if ( fetchGroup != null )
421             {
422                 pm.getFetchPlan().addGroup( fetchGroup );
423             }
424 
425             Object objectId = null;
426 
427             if ( id instanceof CompoundKey )
428             {
429                 objectId = pm.newObjectIdInstance( clazz, id.toString() );
430             }
431             else
432             {
433                 objectId = pm.newObjectIdInstance( clazz, id );
434             }
435 
436             Object object = pm.getObjectById( objectId );
437 
438             object = pm.detachCopy( object );
439 
440             tx.commit();
441 
442             return object;
443         }
444         catch ( JDOObjectNotFoundException e )
445         {
446             throw new ObjectNotFoundException( "Unable to find Database Object [" + id + "] of type " + clazz.getName()
447                 + " using " + ( ( fetchGroup == null ) ? "no fetch-group" : "a fetch-group of [" + fetchGroup + "]" ),
448                                                e, id );
449         }
450         catch ( JDOException e )
451         {
452             throw new ArchivaDatabaseException( "Error in JDO during get of Database object id [" + id + "] of type "
453                 + clazz.getName() + " using "
454                 + ( ( fetchGroup == null ) ? "no fetch-group" : "a fetch-group of [" + fetchGroup + "]" ), e );
455         }
456         finally
457         {
458             rollbackIfActive( tx );
459         }
460     }
461 
462     public Object getObjectById( Class<?> clazz, String id, String fetchGroup )
463         throws ObjectNotFoundException, ArchivaDatabaseException
464     {
465         if ( StringUtils.isEmpty( id ) )
466         {
467             throw new ObjectNotFoundException( "Unable to get object '" + clazz.getName()
468                 + "' from jdo using null/empty id." );
469         }
470 
471         return getObjectById( clazz, (Object) id, fetchGroup );
472     }
473 
474     public boolean objectExists( Object object )
475     {
476         return ( JDOHelper.getObjectId( object ) != null );
477     }
478 
479     public boolean objectExistsById( Class<?> clazz, String id )
480         throws ArchivaDatabaseException
481     {
482         try
483         {
484             Object o = getObjectById( clazz, id, null );
485             return ( o != null );
486         }
487         catch ( ObjectNotFoundException e )
488         {
489             return false;
490         }
491     }
492 
493     public void removeObject( Object o )
494         throws ArchivaDatabaseException
495     {
496         if ( o == null )
497         {
498             throw new ArchivaDatabaseException( "Unable to remove null object" );
499         }
500 
501         PersistenceManager pm = getPersistenceManager();
502         Transaction tx = pm.currentTransaction();
503 
504         try
505         {
506             tx.begin();
507 
508             o = pm.getObjectById( pm.getObjectId( o ) );
509 
510             pm.deletePersistent( o );
511 
512             tx.commit();
513         }
514         finally
515         {
516             rollbackIfActive( tx );
517         }
518     }
519 
520     public void rollbackIfActive( Transaction tx )
521     {
522         PersistenceManager pm = tx.getPersistenceManager();
523 
524         try
525         {
526             if ( tx.isActive() )
527             {
528                 tx.rollback();
529             }
530         }
531         finally
532         {
533             closePersistenceManager( pm );
534         }
535     }
536 
537     public void closePersistenceManager( PersistenceManager pm )
538     {
539         try
540         {
541             pm.close();
542         }
543         catch ( JDOUserException e )
544         {
545             // ignore
546         }
547     }
548 
549     public void postDelete( InstanceLifecycleEvent evt )
550     {
551         PersistenceCapable obj = ( (PersistenceCapable) evt.getSource() );
552 
553         if ( obj == null )
554         {
555             // Do not track null objects.
556             // These events are typically a product of an internal lifecycle event.
557             return;
558         }
559     }
560 
561     public void preDelete( InstanceLifecycleEvent evt )
562     {
563         // ignore
564     }
565 
566     public void postStore( InstanceLifecycleEvent evt )
567     {
568         // PersistenceCapable obj = ( (PersistenceCapable) evt.getSource() );
569     }
570 
571     public void preStore( InstanceLifecycleEvent evt )
572     {
573         // ignore
574     }
575 
576     public void removeAll( Class<?> aClass )
577     {
578         PersistenceManager pm = getPersistenceManager();
579         Transaction tx = pm.currentTransaction();
580 
581         try
582         {
583             tx.begin();
584 
585             Query query = pm.newQuery( aClass );
586             query.deletePersistentAll();
587 
588             tx.commit();
589         }
590         finally
591         {
592             rollbackIfActive( tx );
593         }
594     }
595 
596     public JdoFactory getJdoFactory()
597     {
598         return jdoFactory;
599     }
600 
601     public long countObjects( SimpleConstraint constraint )
602     {
603         PersistenceManager pm = getPersistenceManager();
604         Transaction tx = pm.currentTransaction();
605 
606         try
607         {
608             tx.begin();
609 
610             Query query = pm.newQuery( constraint.getCountSql() );
611 
612             if ( constraint.getFetchLimits() != null )
613             {
614                 pm.getFetchPlan().addGroup( constraint.getFetchLimits() );
615             }
616 
617             List<?> objects;
618             if ( constraint.getParameters() != null )
619             {
620                 objects = processParameterizedQuery( query, constraint.getParameters() );
621             }
622             else
623             {
624                 objects = (List<?>) query.execute();
625             }
626 
627             Long result = !objects.isEmpty() ? (Long) objects.get( 0 ) : 0;
628 
629             tx.commit();
630 
631             return result;
632         }
633         finally
634         {
635             rollbackIfActive( tx );
636         }
637     }
638 
639     public long countObjects( Class<?> clazz, DeclarativeConstraint constraint )
640     {
641         PersistenceManager pm = getPersistenceManager();
642         Transaction tx = pm.currentTransaction();
643 
644         Long result = null;
645 
646         try
647         {
648             tx.begin();
649 
650             Extent extent = pm.getExtent( clazz, true );
651             Query query = pm.newQuery( extent );
652 
653             if ( constraint.getFilter() != null )
654             {
655                 query.setFilter( constraint.getFilter() );
656             }
657 
658             if ( constraint.getVariables() != null )
659             {
660                 query.declareVariables( StringUtils.join( constraint.getVariables(), ";  " ) );
661             }
662 
663             if ( constraint.getFetchLimits() != null )
664             {
665                 pm.getFetchPlan().addGroup( constraint.getFetchLimits() );
666             }
667 
668             if ( constraint.getWhereCondition() != null )
669             {
670                 query.setFilter( constraint.getWhereCondition() );
671             }
672 
673             if ( constraint.getDeclaredImports() != null )
674             {
675                 query.declareImports( StringUtils.join( constraint.getDeclaredImports(), ", " ) );
676             }
677 
678             if ( constraint.getRange() != null )
679             {
680                 query.setRange( constraint.getRange()[0], constraint.getRange()[1] );
681             }
682 
683             query.setResult( "count(this)" );
684 
685             if ( constraint.getDeclaredParameters() != null )
686             {
687                 if ( constraint.getParameters() == null )
688                 {
689                     throw new JDOException( "Unable to use query, there are declared parameters, "
690                         + "but no parameter objects to use." );
691                 }
692 
693                 if ( constraint.getParameters().length != constraint.getDeclaredParameters().length )
694                 {
695                     throw new JDOException( "Unable to use query, there are <" + constraint.getDeclaredParameters().length
696                         + "> declared parameters, yet there are <" + constraint.getParameters().length
697                         + "> parameter objects to use.  This should be equal." );
698                 }
699 
700                 query.declareParameters( StringUtils.join( constraint.getDeclaredParameters(), ", " ) );
701 
702                 result = (Long) query.executeWithArray( constraint.getParameters() );
703             }
704             else
705             {
706                 result = (Long) query.execute();
707             }
708             tx.commit();
709         }
710         finally
711         {
712             rollbackIfActive( tx );
713         }
714 
715         return result;
716     }
717 }