View Javadoc

1   package org.apache.jcs.auxiliary.disk.jdbc;
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 java.io.IOException;
23  import java.io.Serializable;
24  import java.sql.Connection;
25  import java.sql.Date;
26  import java.sql.PreparedStatement;
27  import java.sql.ResultSet;
28  import java.sql.SQLException;
29  import java.sql.Statement;
30  import java.util.ArrayList;
31  import java.util.Arrays;
32  import java.util.List;
33  import java.util.Set;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.jcs.auxiliary.AuxiliaryCacheAttributes;
38  import org.apache.jcs.auxiliary.disk.AbstractDiskCache;
39  import org.apache.jcs.engine.CacheConstants;
40  import org.apache.jcs.engine.behavior.ICacheElement;
41  import org.apache.jcs.engine.behavior.IElementSerializer;
42  import org.apache.jcs.engine.stats.StatElement;
43  import org.apache.jcs.engine.stats.behavior.IStatElement;
44  import org.apache.jcs.engine.stats.behavior.IStats;
45  import org.apache.jcs.utils.serialization.StandardSerializer;
46  
47  /***
48   * This is the jdbc disk cache plugin.
49   * <p>
50   * It expects a table created by the following script. The table name is
51   * configurable.
52   * <p>
53   *
54   * <pre>
55   *                       drop TABLE JCS_STORE;
56   *
57   *                       CREATE TABLE JCS_STORE
58   *                       (
59   *                       CACHE_KEY                  VARCHAR(250)          NOT NULL,
60   *                       REGION                     VARCHAR(250)          NOT NULL,
61   *                       ELEMENT                    BLOB,
62   *                       CREATE_TIME                DATE,
63   *                       CREATE_TIME_SECONDS        BIGINT,
64   *                       MAX_LIFE_SECONDS           BIGINT,
65   *                       SYSTEM_EXPIRE_TIME_SECONDS BIGINT,
66   *                       IS_ETERNAL                 CHAR(1),
67   *                       PRIMARY KEY (CACHE_KEY, REGION)
68   *                       );
69   * </pre>
70   *
71   * <p>
72   * The cleanup thread will delete non eternal items where (now - create time) >
73   * max life seconds * 1000
74   * <p>
75   * To speed up the deletion the SYSTEM_EXPIRE_TIME_SECONDS is used instead. It
76   * is recommended that an index be created on this column is you will have over
77   * a million records.
78   * <p>
79   * @author Aaron Smuts
80   */
81  public class JDBCDiskCache
82      extends AbstractDiskCache
83  {
84      private final static Log log = LogFactory.getLog( JDBCDiskCache.class );
85  
86      private static final long serialVersionUID = -7169488308515823492L;
87  
88      private IElementSerializer elementSerializer = new StandardSerializer();
89  
90      private JDBCDiskCacheAttributes jdbcDiskCacheAttributes;
91  
92      private int updateCount = 0;
93  
94      private int getCount = 0;
95  
96      // if count % interval == 0 then log
97      private static final int LOG_INTERVAL = 100;
98  
99      private JDBCDiskCachePoolAccess poolAccess = null;
100 
101     private TableState tableState;
102 
103     /***
104      * Constructs a JDBC Disk Cache for the provided cache attributes. The table
105      * state object is used to mark deletions.
106      * <p>
107      * @param cattr
108      * @param tableState
109      */
110     public JDBCDiskCache( JDBCDiskCacheAttributes cattr, TableState tableState )
111     {
112         super( cattr );
113 
114         this.setTableState( tableState );
115 
116         setJdbcDiskCacheAttributes( cattr );
117 
118         if ( log.isInfoEnabled() )
119         {
120             log.info( "jdbcDiskCacheAttributes = " + getJdbcDiskCacheAttributes() );
121         }
122 
123         /***
124          * This initializes the pool access.
125          */
126         initializePoolAccess( cattr );
127 
128         // Initialization finished successfully, so set alive to true.
129         alive = true;
130     }
131 
132     /***
133      * Registers the driver and creates a poolAccess class.
134      * @param cattr
135      */
136     protected void initializePoolAccess( JDBCDiskCacheAttributes cattr )
137     {
138         try
139         {
140             try
141             {
142                 // org.gjt.mm.mysql.Driver
143                 Class.forName( cattr.getDriverClassName() );
144             }
145             catch ( ClassNotFoundException e )
146             {
147                 log.error( "Couldn't find class for driver [" + cattr.getDriverClassName() + "]", e );
148             }
149 
150             poolAccess = new JDBCDiskCachePoolAccess( cattr.getName() );
151 
152             poolAccess.setupDriver( cattr.getUrl() + cattr.getDatabase(), cattr.getUserName(), cattr.getPassword(),
153                                     cattr.getMaxActive() );
154 
155             poolAccess.logDriverStats();
156         }
157         catch ( Exception e )
158         {
159             log.error( "Problem getting connection.", e );
160         }
161     }
162 
163     /*
164      * (non-Javadoc)
165      * @see org.apache.jcs.auxiliary.disk.AbstractDiskCache#doUpdate(org.apache.jcs.engine.behavior.ICacheElement)
166      */
167     public void doUpdate( ICacheElement ce )
168     {
169         incrementUpdateCount();
170 
171         if ( log.isDebugEnabled() )
172         {
173             log.debug( "updating, ce = " + ce );
174         }
175 
176         Connection con;
177         try
178         {
179             con = poolAccess.getConnection();
180         }
181         catch ( SQLException e )
182         {
183             log.error( "Problem getting conenction.", e );
184             return;
185         }
186 
187         try
188         {
189             // TEST
190             Statement sStatement = null;
191             try
192             {
193                 sStatement = con.createStatement();
194                 alive = true;
195             }
196             catch ( SQLException e )
197             {
198                 log.error( "Problem creating statement.", e );
199                 alive = false;
200             }
201             finally
202             {
203                 try
204                 {
205                     sStatement.close();
206                 }
207                 catch ( SQLException e )
208                 {
209                     log.error( "Problem closing statement.", e );
210                 }
211             }
212 
213             if ( !alive )
214             {
215                 if ( log.isInfoEnabled() )
216                 {
217                     log.info( "Disk is not alive, aborting put." );
218                 }
219                 return;
220             }
221 
222             if ( log.isDebugEnabled() )
223             {
224                 log.debug( "Putting [" + ce.getKey() + "] on disk." );
225             }
226 
227             byte[] element;
228 
229             try
230             {
231                 element = serialize( ce );
232             }
233             catch ( IOException e )
234             {
235                 log.error( "Could not serialize element", e );
236                 return;
237             }
238 
239             boolean exists = false;
240 
241             // First do a query to determine if the element already exists
242             if ( this.getJdbcDiskCacheAttributes().isTestBeforeInsert() )
243             {
244                 exists = doesElementExist( ce );
245             }
246 
247             // If it doesn't exist, insert it, otherwise update
248             if ( !exists )
249             {
250                 try
251                 {
252                     String sqlI = "insert into "
253                         + getJdbcDiskCacheAttributes().getTableName()
254                         + " (CACHE_KEY, REGION, ELEMENT, MAX_LIFE_SECONDS, IS_ETERNAL, CREATE_TIME, CREATE_TIME_SECONDS, SYSTEM_EXPIRE_TIME_SECONDS) "
255                         + " values (?, ?, ?, ?, ?, ?, ?, ?)";
256 
257                     PreparedStatement psInsert = con.prepareStatement( sqlI );
258                     psInsert.setString( 1, (String) ce.getKey() );
259                     psInsert.setString( 2, this.getCacheName() );
260                     psInsert.setBytes( 3, element );
261                     psInsert.setLong( 4, ce.getElementAttributes().getMaxLifeSeconds() );
262                     if ( ce.getElementAttributes().getIsEternal() )
263                     {
264                         psInsert.setString( 5, "T" );
265                     }
266                     else
267                     {
268                         psInsert.setString( 5, "F" );
269                     }
270                     Date createTime = new Date( ce.getElementAttributes().getCreateTime() );
271                     psInsert.setDate( 6, createTime );
272 
273                     long now = System.currentTimeMillis() / 1000;
274                     psInsert.setLong( 7, now );
275 
276                     long expireTime = now + ce.getElementAttributes().getMaxLifeSeconds();
277                     psInsert.setLong( 8, expireTime );
278 
279                     psInsert.execute();
280                     psInsert.close();
281                 }
282                 catch ( SQLException e )
283                 {
284                     if ( e.toString().indexOf( "Violation of unique index" ) != -1
285                         || e.getMessage().indexOf( "Violation of unique index" ) != -1
286                         || e.getMessage().indexOf( "Duplicate entry" ) != -1 )
287                     {
288                         exists = true;
289                     }
290                     else
291                     {
292                         log.error( "Could not insert element", e );
293                     }
294 
295                     // see if it exists, if we didn't already
296                     if ( !exists && !this.getJdbcDiskCacheAttributes().isTestBeforeInsert() )
297                     {
298                         exists = doesElementExist( ce );
299                     }
300                 }
301             }
302 
303             // update if it exists.
304             if ( exists )
305             {
306                 String sqlU = null;
307                 try
308                 {
309                     sqlU = "update " + getJdbcDiskCacheAttributes().getTableName()
310                         + " set ELEMENT  = ?, CREATE_TIME = ?, CREATE_TIME_SECONDS = ?, "
311                         + " SYSTEM_EXPIRE_TIME_SECONDS = ? " + " where CACHE_KEY = ? and REGION = ?";
312                     PreparedStatement psUpdate = con.prepareStatement( sqlU );
313                     psUpdate.setBytes( 1, element );
314 
315                     Date createTime = new Date( ce.getElementAttributes().getCreateTime() );
316                     psUpdate.setDate( 2, createTime );
317 
318                     long now = System.currentTimeMillis() / 1000;
319                     psUpdate.setLong( 3, now );
320 
321                     long expireTime = now + ce.getElementAttributes().getMaxLifeSeconds();
322                     psUpdate.setLong( 4, expireTime );
323 
324                     psUpdate.setString( 5, (String) ce.getKey() );
325                     psUpdate.setString( 6, this.getCacheName() );
326                     psUpdate.execute();
327                     psUpdate.close();
328 
329                     if ( log.isDebugEnabled() )
330                     {
331                         log.debug( "ran update " + sqlU );
332                     }
333                 }
334                 catch ( SQLException e2 )
335                 {
336                     log.error( "e2 sql [" + sqlU + "] Exception: ", e2 );
337                 }
338             }
339         }
340         finally
341         {
342             try
343             {
344                 con.close();
345             }
346             catch ( SQLException e )
347             {
348                 log.error( "Problem closing connection.", e );
349             }
350         }
351 
352         if ( log.isInfoEnabled() )
353         {
354             if ( updateCount % LOG_INTERVAL == 0 )
355             {
356                 // TODO make a log stats method
357                 log.info( "Update Count [" + updateCount + "]" );
358             }
359         }
360     }
361 
362     /***
363      * Does an element exist for this key?
364      * <p>
365      * @param ce
366      * @return boolean
367      */
368     protected boolean doesElementExist( ICacheElement ce )
369     {
370         boolean exists = false;
371 
372         Connection con;
373         try
374         {
375             con = poolAccess.getConnection();
376         }
377         catch ( SQLException e )
378         {
379             log.error( "Problem getting conenction.", e );
380             return exists;
381         }
382 
383         PreparedStatement psSelect = null;
384         try
385         {
386             // don't select the element, since we want this to be fast.
387             String sqlS = "select CACHE_KEY from " + getJdbcDiskCacheAttributes().getTableName()
388                 + " where REGION = ? and CACHE_KEY = ?";
389 
390             psSelect = con.prepareStatement( sqlS );
391             psSelect.setString( 1, this.getCacheName() );
392             psSelect.setString( 2, (String) ce.getKey() );
393 
394             ResultSet rs = psSelect.executeQuery();
395 
396             if ( rs.next() )
397             {
398                 exists = true;
399             }
400 
401             if ( log.isDebugEnabled() )
402             {
403                 log.debug( "[" + ce.getKey() + "] existing status is " + exists );
404             }
405 
406             rs.close();
407         }
408         catch ( SQLException e )
409         {
410             log.error( "Problem looking for item before insert.", e );
411         }
412         finally
413         {
414             try
415             {
416                 if ( psSelect != null )
417                 {
418                     psSelect.close();
419                 }
420                 psSelect.close();
421             }
422             catch ( SQLException e1 )
423             {
424                 log.error( "Problem closing statement.", e1 );
425             }
426 
427             try
428             {
429                 con.close();
430             }
431             catch ( SQLException e )
432             {
433                 log.error( "Problem closing connection.", e );
434             }
435         }
436 
437         return exists;
438     }
439 
440     /***
441      * Queries the database for the value. If it gets a result, the value is
442      * deserialized.
443      * <p>
444      * @see org.apache.jcs.auxiliary.disk.AbstractDiskCache#doGet(java.io.Serializable)
445      */
446     public ICacheElement doGet( Serializable key )
447     {
448         incrementGetCount();
449 
450         if ( log.isDebugEnabled() )
451         {
452             log.debug( "Getting " + key + " from disk" );
453         }
454 
455         if ( !alive )
456         {
457             return null;
458         }
459 
460         ICacheElement obj = null;
461 
462         byte[] data = null;
463         try
464         {
465             // region, key
466             String selectString = "select ELEMENT from " + getJdbcDiskCacheAttributes().getTableName()
467                 + " where REGION = ? and CACHE_KEY = ?";
468 
469             Connection con = poolAccess.getConnection();
470             try
471             {
472                 PreparedStatement psSelect = null;
473                 try
474                 {
475                     psSelect = con.prepareStatement( selectString );
476                     psSelect.setString( 1, this.getCacheName() );
477                     psSelect.setString( 2, key.toString() );
478 
479                     ResultSet rs = psSelect.executeQuery();
480                     try
481                     {
482                         if ( rs.next() )
483                         {
484                             data = rs.getBytes( 1 );
485                         }
486                         if ( data != null )
487                         {
488                             try
489                             {
490                                 // USE THE SERIALIZER
491                                 obj = (ICacheElement) getElementSerializer().deSerialize( data );
492                             }
493                             catch ( IOException ioe )
494                             {
495                                 log.error( ioe );
496                             }
497                             catch ( Exception e )
498                             {
499                                 log.error( "Problem getting item.", e );
500                             }
501                         }
502                     }
503                     finally
504                     {
505                         if ( rs != null )
506                         {
507                             rs.close();
508                         }
509                         rs.close();
510                     }
511                 }
512                 finally
513                 {
514                     if ( psSelect != null )
515                     {
516                         psSelect.close();
517                     }
518                     psSelect.close();
519                 }
520             }
521             finally
522             {
523                 if ( con != null )
524                 {
525                     con.close();
526                 }
527             }
528         }
529         catch ( SQLException sqle )
530         {
531             log.error( sqle );
532         }
533 
534         if ( log.isInfoEnabled() )
535         {
536             if ( getCount % LOG_INTERVAL == 0 )
537             {
538                 // TODO make a log stats method
539                 log.info( "Get Count [" + getCount + "]" );
540             }
541         }
542 
543         return obj;
544     }
545 
546     /***
547      * Returns true if the removal was succesful; or false if there is nothing
548      * to remove. Current implementation always result in a disk orphan.
549      * <p>
550      * @param key
551      * @return boolean
552      */
553     public boolean doRemove( Serializable key )
554     {
555         // remove single item.
556         String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
557             + " where REGION = ? and CACHE_KEY = ?";
558 
559         try
560         {
561             boolean partial = false;
562             if ( key instanceof String && key.toString().endsWith( CacheConstants.NAME_COMPONENT_DELIMITER ) )
563             {
564                 // remove all keys of the same name group.
565                 sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
566                     + " where REGION = ? and CACHE_KEY like ?";
567                 partial = true;
568             }
569             Connection con = poolAccess.getConnection();
570             PreparedStatement psSelect = null;
571             try
572             {
573                 psSelect = con.prepareStatement( sql );
574                 psSelect.setString( 1, this.getCacheName() );
575                 if ( partial )
576                 {
577                     psSelect.setString( 2, key.toString() + "%" );
578                 }
579                 else
580                 {
581                     psSelect.setString( 2, key.toString() );
582                 }
583 
584                 psSelect.executeUpdate( );
585 
586                 alive = true;
587             }
588             catch ( SQLException e )
589             {
590                 log.error( "Problem creating statement. sql [" + sql + "]", e );
591                 alive = false;
592             }
593             finally
594             {
595                 try
596                 {
597                     if ( psSelect != null )
598                     {
599                         psSelect.close();
600                     }
601                     con.close();
602                 }
603                 catch ( SQLException e1 )
604                 {
605                     log.error( "Problem closing statement.", e1 );
606                 }
607             }
608 
609         }
610         catch ( Exception e )
611         {
612             log.error( "Problem updating cache.", e );
613             reset();
614         }
615         return false;
616     }
617 
618     /*** This should remove all elements. */
619     public void doRemoveAll()
620     {
621         // it should never get here formt he abstract dis cache.
622         if ( this.jdbcDiskCacheAttributes.isAllowRemoveAll() )
623         {
624             try
625             {
626                 String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName() + " where REGION = ?";
627                 Connection con = poolAccess.getConnection();
628                 PreparedStatement psDelete = null;
629                 try
630                 {
631                     psDelete = con.prepareStatement( sql );
632                     psDelete.setString( 1, this.getCacheName() );
633                     alive = true;
634                     psDelete.executeUpdate( );
635                 }
636                 catch ( SQLException e )
637                 {
638                     log.error( "Problem creating statement.", e );
639                     alive = false;
640                 }
641                 finally
642                 {
643                     try
644                     {
645                         if ( psDelete != null )
646                         {
647                             psDelete.close();
648                         }
649                         con.close();
650                     }
651                     catch ( SQLException e1 )
652                     {
653                         log.error( "Problem closing statement.", e1 );
654                     }
655                 }
656             }
657             catch ( Exception e )
658             {
659                 log.error( "Problem removing all.", e );
660                 reset();
661             }
662         }
663         else
664         {
665             if ( log.isInfoEnabled() )
666             {
667                 log.info( "RemoveAll was requested but the request was not fulfilled: allowRemoveAll is set to false." );
668             }
669         }
670     }
671 
672     /***
673      * Removed the expired. (now - create time) > max life seconds * 1000
674      * <p>
675      * @return the number deleted
676      */
677     protected int deleteExpired()
678     {
679         int deleted = 0;
680 
681         try
682         {
683             getTableState().setState( TableState.DELETE_RUNNING );
684 
685             long now = System.currentTimeMillis() / 1000;
686 
687             // This is to slow when we push over a million records
688             // String sql = "delete from " +
689             // getJdbcDiskCacheAttributes().getTableName() + " where REGION = '"
690             // + this.getCacheName() + "' and IS_ETERNAL = 'F' and (" + now
691             // + " - CREATE_TIME_SECONDS) > MAX_LIFE_SECONDS";
692 
693             String sql = "delete from " + getJdbcDiskCacheAttributes().getTableName()
694                 + " where IS_ETERNAL = ? and REGION = ? and ? > SYSTEM_EXPIRE_TIME_SECONDS";
695 
696             Connection con = poolAccess.getConnection();
697             PreparedStatement psDelete = null;
698             try
699             {
700                 psDelete = con.prepareStatement( sql );
701                 psDelete.setString( 1, "F" );
702                 psDelete.setString( 2, this.getCacheName() );
703                 psDelete.setLong( 3, now );
704 
705                 alive = true;
706 
707                 deleted = psDelete.executeUpdate( );
708             }
709             catch ( SQLException e )
710             {
711                 log.error( "Problem creating statement.", e );
712                 alive = false;
713             }
714             finally
715             {
716                 try
717                 {
718                     if ( psDelete != null )
719                     {
720                         psDelete.close();
721                     }
722                     con.close();
723                 }
724                 catch ( SQLException e1 )
725                 {
726                     log.error( "Problem closing statement.", e1 );
727                 }
728             }
729         }
730         catch ( Exception e )
731         {
732             log.error( "Problem removing expired elements from the table.", e );
733             reset();
734         }
735         finally
736         {
737             getTableState().setState( TableState.FREE );
738         }
739 
740         return deleted;
741     }
742 
743     /***
744      * Typically this is used to handle errors by last resort, force content
745      * update, or removeall
746      */
747     public void reset()
748     {
749         // nothing
750     }
751 
752     /*** Shuts down the pool */
753     public void doDispose()
754     {
755         try
756         {
757             poolAccess.shutdownDriver();
758         }
759         catch ( Exception e )
760         {
761             log.error( "Problem shutting down.", e );
762         }
763     }
764 
765     /***
766      * Returns the current cache size. Just does a count(*) for the region.
767      * <p>
768      * @return The size value
769      */
770     public int getSize()
771     {
772         int size = 0;
773 
774         // region, key
775         String selectString = "select count(*) from " + getJdbcDiskCacheAttributes().getTableName()
776             + " where REGION = ?";
777 
778         Connection con;
779         try
780         {
781             con = poolAccess.getConnection();
782         }
783         catch ( SQLException e1 )
784         {
785             log.error( "Problem getting conenction.", e1 );
786             return size;
787         }
788         try
789         {
790             PreparedStatement psSelect = null;
791             try
792             {
793                 psSelect = con.prepareStatement( selectString );
794                 psSelect.setString( 1, this.getCacheName() );
795                 ResultSet rs = null;
796 
797                 rs = psSelect.executeQuery();
798                 try
799                 {
800                     if ( rs.next() )
801                     {
802                         size = rs.getInt( 1 );
803                     }
804                 }
805                 finally
806                 {
807                     if ( rs != null )
808                     {
809                         rs.close();
810                     }
811                     rs.close();
812                 }
813             }
814             finally
815             {
816                 if ( psSelect != null )
817                 {
818                     psSelect.close();
819                 }
820                 psSelect.close();
821             }
822         }
823         catch ( SQLException e )
824         {
825             log.error( "Problem getting size.", e );
826         }
827         finally
828         {
829             try
830             {
831                 con.close();
832             }
833             catch ( SQLException e )
834             {
835                 log.error( "Problem closing connection.", e );
836             }
837         }
838         return size;
839     }
840 
841     /***
842      * Returns the serialized form of the given object in a byte array.
843      * <p>
844      * @param obj
845      * @return byte[]
846      * @throws IOException
847      */
848     protected byte[] serialize( Serializable obj )
849         throws IOException
850     {
851         return getElementSerializer().serialize( obj );
852     }
853 
854     /***
855      * @param groupName
856      * @return
857      */
858     public Set getGroupKeys( String groupName )
859     {
860         if ( true )
861         {
862             throw new UnsupportedOperationException( "Groups not implemented." );
863         }
864         return null;
865     }
866 
867     /***
868      * @param elementSerializer
869      *            The elementSerializer to set.
870      */
871     public void setElementSerializer( IElementSerializer elementSerializer )
872     {
873         this.elementSerializer = elementSerializer;
874     }
875 
876     /***
877      * @return Returns the elementSerializer.
878      */
879     public IElementSerializer getElementSerializer()
880     {
881         return elementSerializer;
882     }
883 
884     /*** safely increment */
885     private synchronized void incrementUpdateCount()
886     {
887         updateCount++;
888     }
889 
890     /*** safely increment */
891     private synchronized void incrementGetCount()
892     {
893         getCount++;
894     }
895 
896     /***
897      * @param jdbcDiskCacheAttributes
898      *            The jdbcDiskCacheAttributes to set.
899      */
900     protected void setJdbcDiskCacheAttributes( JDBCDiskCacheAttributes jdbcDiskCacheAttributes )
901     {
902         this.jdbcDiskCacheAttributes = jdbcDiskCacheAttributes;
903     }
904 
905     /***
906      * @return Returns the jdbcDiskCacheAttributes.
907      */
908     protected JDBCDiskCacheAttributes getJdbcDiskCacheAttributes()
909     {
910         return jdbcDiskCacheAttributes;
911     }
912 
913     /***
914      * @return Returns the AuxiliaryCacheAttributes.
915      */
916     public AuxiliaryCacheAttributes getAuxiliaryCacheAttributes()
917     {
918         return this.getJdbcDiskCacheAttributes();
919     }
920 
921     /***
922      * Extends the parent stats.
923      */
924     public IStats getStatistics()
925     {
926         IStats stats = super.getStatistics();
927         stats.setTypeName( "JDBC/Abstract Disk Cache" );
928         stats.getStatElements();
929 
930         ArrayList elems = new ArrayList();
931 
932         IStatElement se = null;
933 
934         se = new StatElement();
935         se.setName( "Update Count" );
936         se.setData( "" + updateCount );
937         elems.add( se );
938 
939         se = new StatElement();
940         se.setName( "Get Count" );
941         se.setData( "" + getCount );
942         elems.add( se );
943 
944         se = new StatElement();
945         se.setName( "Size" );
946         se.setData( "" + getSize() );
947         elems.add( se );
948 
949         se = new StatElement();
950         se.setName( "Active DB Connections" );
951         se.setData( "" + poolAccess.getNumActiveInPool() );
952         elems.add( se );
953 
954         se = new StatElement();
955         se.setName( "Idle DB Connections" );
956         se.setData( "" + poolAccess.getNumIdleInPool() );
957         elems.add( se );
958 
959         se = new StatElement();
960         se.setName( "DB URL" );
961         se.setData( this.jdbcDiskCacheAttributes.getUrl() );
962         elems.add( se );
963 
964         // get the stats from the event queue too
965         // get as array, convert to list, add list to our outer list
966         IStatElement[] eqSEs = stats.getStatElements();
967         List eqL = Arrays.asList( eqSEs );
968         elems.addAll( eqL );
969 
970         // get an array and put them in the Stats object
971         IStatElement[] ses = (IStatElement[]) elems.toArray( new StatElement[0] );
972         stats.setStatElements( ses );
973 
974         return stats;
975     }
976 
977     /***
978      * Returns the name of the table.
979      * <p>
980      * @return the table name or UNDEFINED
981      */
982     protected String getTableName()
983     {
984         String name = "UNDEFINED";
985         if ( this.getJdbcDiskCacheAttributes() != null )
986         {
987             name = this.getJdbcDiskCacheAttributes().getTableName();
988         }
989         return name;
990     }
991 
992     /***
993      * @param tableState The tableState to set.
994      */
995     public void setTableState( TableState tableState )
996     {
997         this.tableState = tableState;
998     }
999 
1000     /***
1001      * @return Returns the tableState.
1002      */
1003     public TableState getTableState()
1004     {
1005         return tableState;
1006     }
1007 
1008     /***
1009      * For debugging.
1010      */
1011     public String toString()
1012     {
1013         return this.getStats();
1014     }
1015 }