Home » apache-openjpa-1.1.0-source » org.apache.openjpa.jdbc » kernel » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one
    3    * or more contributor license agreements.  See the NOTICE file
    4    * distributed with this work for additional information
    5    * regarding copyright ownership.  The ASF licenses this file
    6    * to you under the Apache License, Version 2.0 (the
    7    * "License"); you may not use this file except in compliance
    8    * with the License.  You may obtain a copy of the License at
    9    *
   10    * http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    * Unless required by applicable law or agreed to in writing,
   13    * software distributed under the License is distributed on an
   14    * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
   15    * KIND, either express or implied.  See the License for the
   16    * specific language governing permissions and limitations
   17    * under the License.    
   18    */
   19   package org.apache.openjpa.jdbc.kernel;
   20   
   21   import java.io.Serializable;
   22   import java.sql.Connection;
   23   import java.sql.PreparedStatement;
   24   import java.sql.ResultSet;
   25   import java.sql.SQLException;
   26   import java.sql.Types;
   27   import java.util.HashMap;
   28   
   29   import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
   30   import org.apache.openjpa.jdbc.conf.JDBCConfigurationImpl;
   31   import org.apache.openjpa.jdbc.meta.ClassMapping;
   32   import org.apache.openjpa.jdbc.schema.Column;
   33   import org.apache.openjpa.jdbc.schema.PrimaryKey;
   34   import org.apache.openjpa.jdbc.schema.Schema;
   35   import org.apache.openjpa.jdbc.schema.SchemaGroup;
   36   import org.apache.openjpa.jdbc.schema.SchemaTool;
   37   import org.apache.openjpa.jdbc.schema.Schemas;
   38   import org.apache.openjpa.jdbc.schema.Table;
   39   import org.apache.openjpa.jdbc.sql.DBDictionary;
   40   import org.apache.openjpa.jdbc.sql.RowImpl;
   41   import org.apache.openjpa.jdbc.sql.SQLBuffer;
   42   import org.apache.openjpa.jdbc.sql.SQLExceptions;
   43   import org.apache.openjpa.lib.conf.Configurable;
   44   import org.apache.openjpa.lib.conf.Configuration;
   45   import org.apache.openjpa.lib.conf.Configurations;
   46   import org.apache.openjpa.lib.log.Log;
   47   import org.apache.openjpa.lib.util.Localizer;
   48   import org.apache.openjpa.lib.util.Options;
   49   import org.apache.openjpa.meta.JavaTypes;
   50   import org.apache.openjpa.util.InvalidStateException;
   51   import serp.util.Numbers;
   52   import serp.util.Strings;
   53   
   54   ////////////////////////////////////////////////////////////
   55   // NOTE: Do not change property names; see SequenceMetaData
   56   // and SequenceMapping for standard property names.
   57   ////////////////////////////////////////////////////////////
   58   
   59   /**
   60    * {@link JDBCSeq} implementation that uses a database table
   61    * for sequence number generation. This base implementation uses a single
   62    * row for a global sequence number.
   63    *
   64    * @author Abe White
   65    */
   66   public class TableJDBCSeq
   67       extends AbstractJDBCSeq
   68       implements Configurable {
   69   
   70       public static final String ACTION_DROP = "drop";
   71       public static final String ACTION_ADD = "add";
   72       public static final String ACTION_GET = "get";
   73       public static final String ACTION_SET = "set";
   74   
   75       private static final Localizer _loc = Localizer.forPackage
   76           (TableJDBCSeq.class);
   77   
   78       private transient JDBCConfiguration _conf = null;
   79       private transient Log _log = null;
   80       private int _alloc = 50;
   81       private int _intValue = 1;
   82       private final HashMap _stat = new HashMap();
   83   
   84       private String _table = "OPENJPA_SEQUENCE_TABLE";
   85       private String _seqColumnName = "SEQUENCE_VALUE";
   86       private String _pkColumnName = "ID";
   87   
   88       private Column _seqColumn = null;
   89       private Column _pkColumn = null;
   90       private int _schemasIdx = 0;    
   91   
   92       /**
   93        * The sequence table name. Defaults to <code>OPENJPA_SEQUENCE_TABLE</code>.
   94        * By default, the table will be placed in the first schema listed in your
   95        * <code>openjpa.jdbc.Schemas</code> property, or in the default schema if
   96        * the property is not given. If you specify a table name in the form
   97        * <code>&lt;schema&gt;.&lt;table&gt;</code>, then the given schema
   98        * will be used.
   99        */
  100       public String getTable() {
  101           return _table;
  102       }
  103   
  104       /**
  105        * The sequence table name. Defaults to <code>OPENJPA_SEQUENCE_TABLE</code>.
  106        * By default, the table will be placed in the first schema listed in your
  107        * <code>openjpa.jdbc.Schemas</code> property, or in the default schema if
  108        * the property is not given. If you specify a table name in the form
  109        * <code>&lt;schema&gt;.&lt;table&gt;</code>, then the given schema
  110        * will be used.
  111        */
  112       public void setTable(String name) {
  113           _table = name;
  114       }
  115   
  116       /**
  117        * @deprecated Use {@link #setTable}. Retained for
  118        * backwards-compatibility	with auto-configuration.
  119        */
  120       public void setTableName(String name) {
  121           setTable(name);
  122       }
  123   
  124       /**
  125        * The name of the column that holds the sequence value. Defaults
  126        * to <code>SEQUENCE_VALUE</code>.
  127        */
  128       public String getSequenceColumn() {
  129           return _seqColumnName;
  130       }
  131   
  132       /**
  133        * The name of the column that holds the sequence value. Defaults
  134        * to <code>SEQUENCE_VALUE</code>.
  135        */
  136       public void setSequenceColumn(String sequenceColumn) {
  137           _seqColumnName = sequenceColumn;
  138       }
  139   
  140       /**
  141        * The name of the table's primary key column. Defaults to
  142        * <code>ID</code>.
  143        */
  144       public String getPrimaryKeyColumn() {
  145           return _pkColumnName;
  146       }
  147   
  148       /**
  149        * The name of the table's primary key column. Defaults to
  150        * <code>ID</code>.
  151        */
  152       public void setPrimaryKeyColumn(String primaryKeyColumn) {
  153           _pkColumnName = primaryKeyColumn;
  154       }
  155   
  156       /**
  157        * Return the number of sequences to allocate for each update of the
  158        * sequence table. Sequence numbers will be grabbed in blocks of this
  159        * value to reduce the number of transactions that must be performed on
  160        * the sequence table.
  161        */
  162       public int getAllocate() {
  163           return _alloc;
  164       }
  165   
  166       /**
  167        * Return the number of sequences to allocate for each update of the
  168        * sequence table. Sequence numbers will be grabbed in blocks of this
  169        * value to reduce the number of transactions that must be performed on
  170        * the sequence table.
  171        */
  172       public void setAllocate(int alloc) {
  173           _alloc = alloc;
  174       }
  175       
  176       /**
  177        * Return the number as the initial number for the 
  178        * GeneratedValue.TABLE strategy to start with. 
  179        * @return an initial number
  180        */
  181       public int getInitialValue() {        
  182           return _intValue;
  183       }
  184   
  185       /**
  186        * Set the initial number in the table for the GeneratedValue.TABLE
  187        * strategy to use as initial number. 
  188        * @param intValue. The initial number
  189        */
  190       public void setInitialValue(int intValue) {
  191           _intValue = intValue;
  192       }
  193   
  194       /**
  195        * @deprecated Use {@link #setAllocate}. Retained for backwards
  196        * compatibility of auto-configuration.
  197        */
  198       public void setIncrement(int inc) {
  199           setAllocate(inc);
  200       }
  201   
  202       public JDBCConfiguration getConfiguration() {
  203           return _conf;
  204       }
  205   
  206       public void setConfiguration(Configuration conf) {
  207           _conf = (JDBCConfiguration) conf;
  208           _log = _conf.getLog(JDBCConfiguration.LOG_RUNTIME);
  209       }
  210   
  211       public void startConfiguration() {
  212       }
  213   
  214       public void endConfiguration() {
  215           buildTable();
  216       }
  217       
  218   
  219       public void addSchema(ClassMapping mapping, SchemaGroup group) {
  220           // Since the table is created by openjpa internally
  221           // we can create the table for each schema within the PU
  222           // in here.
  223           
  224           Schema[] schemas = group.getSchemas();
  225           for (int i = 0; i < schemas.length; i++) {
  226               String schemaName = Strings.getPackageName(_table);
  227               if (schemaName.length() == 0)
  228                   schemaName = Schemas.getNewTableSchema(_conf);
  229               if (schemaName == null)
  230                   schemaName = schemas[i].getName();
  231   
  232               // create table in this group
  233               Schema schema = group.getSchema(schemaName);
  234               if (schema == null)
  235                   schema = group.addSchema(schemaName);
  236               
  237               schema.importTable(_pkColumn.getTable());
  238               // we need to reset the table name in the column with the
  239               // fully qualified name for matching the table name from the
  240               // Column.
  241               _pkColumn.resetTableName(schemaName + "."
  242                       + _pkColumn.getTableName());
  243               // some databases require to create an index for the sequence table
  244               _conf.getDBDictionaryInstance().createIndexIfNecessary(schema,
  245                       _table, _pkColumn);
  246            
  247           }
  248       }
  249   
  250       protected Object nextInternal(JDBCStore store, ClassMapping mapping)
  251           throws Exception {
  252           // if needed, grab the next handful of ids
  253           Status stat = getStatus(mapping);
  254           if (stat == null)
  255               throw new InvalidStateException(_loc.get("bad-seq-type",
  256                   getClass(), mapping));
  257   
  258           while (true) {
  259               synchronized (stat) {
  260                   // make sure seq is at least 1, since autoassigned ids of 0 can
  261                   // conflict with uninitialized values
  262                   stat.seq = Math.max(stat.seq, 1);
  263                   if (stat.seq < stat.max)
  264                       return Numbers.valueOf(stat.seq++);
  265               }
  266               allocateSequence(store, mapping, stat, _alloc, true);
  267           }
  268       }
  269   
  270       protected Object currentInternal(JDBCStore store, ClassMapping mapping)
  271           throws Exception {
  272           if (current == null) {
  273               Connection conn = getConnection(store);
  274               try {
  275                   long cur = getSequence(mapping, conn);
  276                   if (cur != -1)
  277                       current = Numbers.valueOf(cur);
  278               } finally {
  279                   closeConnection(conn);
  280               }
  281           }
  282           return super.currentInternal(store, mapping);
  283       }
  284   
  285       protected void allocateInternal(int count, JDBCStore store,
  286           ClassMapping mapping)
  287           throws SQLException {
  288           Status stat = getStatus(mapping);
  289           if (stat == null)
  290               return;
  291   
  292           while (true) {
  293               int available;
  294               synchronized (stat) {
  295                   available = (int) (stat.max - stat.seq);
  296                   if (available >= count)
  297                       return;
  298               }
  299               allocateSequence(store, mapping, stat, count - available, false);
  300           }
  301       }
  302   
  303       /**
  304        * Return the appropriate status object for the given class, or null
  305        * if cannot handle the given class. The mapping may be null.
  306        */
  307       protected Status getStatus(ClassMapping mapping) {  
  308           Status status = (Status)_stat.get(mapping);        
  309           if (status == null){ 
  310               status = new Status();
  311               _stat.put(mapping, status);
  312           }
  313           return status;
  314               
  315       }
  316   
  317       /**
  318        * Add the primary key column to the given table and return it.
  319        */
  320       protected Column addPrimaryKeyColumn(Table table) {
  321           DBDictionary dict = _conf.getDBDictionaryInstance();
  322           Column pkColumn = table.addColumn(dict.getValidColumnName
  323               (getPrimaryKeyColumn(), table));
  324           pkColumn.setType(dict.getPreferredType(Types.TINYINT));
  325           pkColumn.setJavaType(JavaTypes.INT);
  326           return pkColumn;
  327       }
  328   
  329       /**
  330        * Return the primary key value for the given class.
  331        */
  332       protected Object getPrimaryKey(ClassMapping mapping) {
  333           return Numbers.valueOf(0);
  334       }
  335   
  336       /**
  337        * Creates the object-level representation of the sequence table.
  338        */
  339       private void buildTable() {
  340           String tableName = Strings.getClassName(_table);
  341           String schemaName = Strings.getPackageName(_table);
  342           if (schemaName.length() == 0)
  343               schemaName = Schemas.getNewTableSchema(_conf);
  344   
  345           SchemaGroup group = new SchemaGroup();
  346           Schema schema = group.addSchema(schemaName);
  347   
  348           Table table = schema.addTable(tableName);
  349           _pkColumn = addPrimaryKeyColumn(table);
  350           PrimaryKey pk = table.addPrimaryKey();
  351           pk.addColumn(_pkColumn);
  352   
  353           DBDictionary dict = _conf.getDBDictionaryInstance();
  354           _seqColumn = table.addColumn(dict.getValidColumnName
  355               (_seqColumnName, table));
  356           _seqColumn.setType(dict.getPreferredType(Types.BIGINT));
  357           _seqColumn.setJavaType(JavaTypes.LONG);
  358       }
  359   
  360       /**
  361        * Updates the max available sequence value.
  362        */
  363       private void allocateSequence(JDBCStore store, ClassMapping mapping,
  364           Status stat, int alloc, boolean updateStatSeq) 
  365           throws SQLException {
  366           Connection conn = getConnection(store);
  367           try { 
  368               if (setSequence(mapping, stat, alloc, updateStatSeq, conn))
  369                   return;
  370           } catch (SQLException se) {
  371               throw SQLExceptions.getStore(_loc.get("bad-seq-up", _table),
  372                   se, _conf.getDBDictionaryInstance());
  373           } finally {
  374               closeConnection(conn);
  375           }
  376           
  377           try {
  378               // possible that we might get errors when inserting if
  379               // another thread/process is inserting same pk at same time
  380               SQLException err = null; 
  381               // ### why does this not call getConnection() / closeConnection()?
  382               conn = _conf.getDataSource2(store.getContext()).getConnection();
  383               try {
  384                   insertSequence(mapping, conn);
  385               } catch (SQLException se) {
  386                   err = se;
  387               } finally {
  388                   try { conn.close(); } catch (SQLException se) {}
  389               }
  390   
  391               // now we should be able to update...
  392               conn = getConnection(store);
  393               try {
  394                   if (!setSequence(mapping, stat, alloc, updateStatSeq, conn))
  395                       throw (err != null) ? err : new SQLException(_loc.get
  396                           ("no-seq-row", mapping, _table).getMessage());
  397               } finally {
  398                   closeConnection(conn);
  399               }
  400           } catch (SQLException se2) {
  401               throw SQLExceptions.getStore(_loc.get("bad-seq-up", _table),
  402                   se2, _conf.getDBDictionaryInstance());
  403           } 
  404       }
  405   
  406       /**
  407        * Inserts the initial sequence information into the database, if any.
  408        */
  409       private void insertSequence(ClassMapping mapping, Connection conn)
  410           throws SQLException {
  411           if (_log.isTraceEnabled())
  412               _log.trace(_loc.get("insert-seq"));
  413   
  414           Object pk = getPrimaryKey(mapping);
  415           if (pk == null)
  416               throw new InvalidStateException(_loc.get("bad-seq-type",
  417                   getClass(), mapping));
  418   
  419           DBDictionary dict = _conf.getDBDictionaryInstance();
  420           String tableName = resolveTableName(mapping, _pkColumn.getTable());
  421           SQLBuffer insert = new SQLBuffer(dict).append("INSERT INTO ").
  422               append(tableName).append(" (").
  423               append(_pkColumn).append(", ").append(_seqColumn).
  424               append(") VALUES (").
  425               appendValue(pk, _pkColumn).append(", ").
  426               appendValue(_intValue, _seqColumn).append(")");
  427           
  428           boolean wasAuto = conn.getAutoCommit();
  429           if (!wasAuto && !suspendInJTA())
  430               conn.setAutoCommit(true);
  431   
  432           PreparedStatement stmnt = null;
  433           try {
  434               stmnt = prepareStatement(conn, insert);
  435               executeUpdate(_conf, conn, stmnt, insert, RowImpl.ACTION_INSERT);
  436           } finally {
  437               if (stmnt != null)
  438                   try { stmnt.close(); } catch (SQLException se) {}
  439               if (!wasAuto && !suspendInJTA())
  440                   conn.setAutoCommit(false);
  441           }
  442       }
  443   
  444       /**
  445        * Return the current sequence value, or -1 if unattainable.
  446        */
  447       protected long getSequence(ClassMapping mapping, Connection conn)
  448           throws SQLException {
  449           if (_log.isTraceEnabled())
  450               _log.trace(_loc.get("get-seq"));
  451   
  452           Object pk = getPrimaryKey(mapping);
  453           if (pk == null)
  454               return -1;
  455   
  456           DBDictionary dict = _conf.getDBDictionaryInstance();
  457           SQLBuffer sel = new SQLBuffer(dict).append(_seqColumn);
  458           SQLBuffer where = new SQLBuffer(dict).append(_pkColumn).append(" = ").
  459               appendValue(pk, _pkColumn);
  460           String tableName = resolveTableName(mapping, _seqColumn.getTable());
  461           SQLBuffer tables = new SQLBuffer(dict).append(tableName);
  462   
  463           SQLBuffer select = dict.toSelect(sel, null, tables, where, null, null,
  464                   null, false, dict.supportsSelectForUpdate, 0, Long.MAX_VALUE,
  465                   false, true);
  466   
  467           PreparedStatement stmnt = prepareStatement(conn, select);
  468           ResultSet rs = null;
  469           try {
  470               rs = executeQuery(_conf, conn, stmnt, select);
  471               return getSequence(rs, dict);
  472           } finally {
  473               if (rs != null)
  474                   try { rs.close(); } catch (SQLException se) {}
  475               if (stmnt != null)    
  476                   try { stmnt.close(); } catch (SQLException se) {}
  477           }
  478       }
  479   
  480       /**
  481        * Grabs the next handful of sequence numbers.
  482        *
  483        * @return true if the sequence was updated, false if no sequence
  484        * row existed for this mapping
  485        */
  486       protected boolean setSequence(ClassMapping mapping, Status stat, int inc,
  487           boolean updateStatSeq, Connection conn)
  488           throws SQLException {
  489           if (_log.isTraceEnabled())
  490               _log.trace(_loc.get("update-seq"));
  491   
  492           Object pk = getPrimaryKey(mapping);
  493           if (pk == null)
  494               throw new InvalidStateException(_loc.get("bad-seq-type",
  495                   getClass(), mapping));
  496   
  497           DBDictionary dict = _conf.getDBDictionaryInstance();        
  498           SQLBuffer where = new SQLBuffer(dict).append(_pkColumn).append(" = ").
  499               appendValue(pk, _pkColumn);
  500   
  501           // loop until we have a successful atomic select/update sequence
  502           long cur = 0;
  503           PreparedStatement stmnt;
  504           ResultSet rs;
  505           SQLBuffer upd;
  506           for (int updates = 0; updates == 0;) {
  507               stmnt = null;
  508               rs = null;
  509               try {
  510                   cur = getSequence(mapping, conn);
  511                   if (cur == -1)
  512                       return false;
  513   
  514                   // update the value
  515                   upd = new SQLBuffer(dict);
  516                   String tableName = resolveTableName(mapping, _seqColumn.getTable());
  517                   upd.append("UPDATE ").append(tableName).
  518                       append(" SET ").append(_seqColumn).append(" = ").
  519                       appendValue(Numbers.valueOf(cur + inc), _seqColumn).
  520                       append(" WHERE ").append(where).append(" AND ").
  521                       append(_seqColumn).append(" = ").
  522                       appendValue(Numbers.valueOf(cur), _seqColumn);
  523   
  524                   stmnt = prepareStatement(conn, upd);
  525                   updates = executeUpdate(_conf, conn, stmnt, upd, RowImpl.ACTION_UPDATE);
  526               } finally {
  527                   if (rs != null) 
  528                       try { rs.close(); } catch (SQLException se) {}
  529                   if (stmnt != null)
  530                       try { stmnt.close(); } catch (SQLException se) {}
  531               }
  532           }
  533   
  534           // setup new sequence range        
  535           synchronized (stat) {
  536               if (updateStatSeq && stat.seq < cur)
  537                   stat.seq = cur;
  538               if (stat.max < cur + inc)
  539                   stat.max = cur + inc;
  540           }
  541           return true;
  542       }
  543       /**
  544        * Resolve a fully qualified table name
  545        * 
  546        * @param class
  547        *            mapping to get the schema name
  548        */
  549       public String resolveTableName(ClassMapping mapping, Table table) {
  550           String sName = mapping.getTable().getSchemaName();
  551           String tableName;
  552           if (sName == null)
  553               tableName = table.getFullName();
  554           else
  555               tableName = sName + "." + table.getName();
  556           return tableName;
  557       }
  558   
  559       /**
  560        * Creates the sequence table in the DB.
  561        */
  562       public void refreshTable()
  563           throws SQLException {
  564           if (_log.isInfoEnabled())
  565               _log.info(_loc.get("make-seq-table"));
  566   
  567           // create the table
  568           SchemaTool tool = new SchemaTool(_conf);
  569           tool.setIgnoreErrors(true);
  570           tool.createTable(_pkColumn.getTable());
  571       }
  572   
  573       /**
  574        * Drops the sequence table in the DB.
  575        */
  576       public void dropTable()
  577           throws SQLException {
  578           if (_log.isInfoEnabled())
  579               _log.info(_loc.get("drop-seq-table"));
  580   
  581           // drop the table
  582           SchemaTool tool = new SchemaTool(_conf);
  583           tool.setIgnoreErrors(true);
  584           tool.dropTable(_pkColumn.getTable());
  585       }
  586   
  587       /////////
  588       // Main
  589       /////////
  590   
  591       /**
  592        * Usage: java org.apache.openjpa.jdbc.schema.TableJDBCSequence [option]*
  593        * -action/-a &lt;add | drop | get | set&gt; [value]
  594        *  Where the following options are recognized.
  595        * <ul>
  596        * <li><i>-properties/-p &lt;properties file or resource&gt;</i>: The
  597        * path or resource name of a OpenJPA properties file containing
  598        * information such as the license key	and connection data as
  599        * outlined in {@link JDBCConfiguration}. Optional.</li>
  600        * <li><i>-&lt;property name&gt; &lt;property value&gt;</i>: All bean
  601        * properties of the OpenJPA {@link JDBCConfiguration} can be set by
  602        * using their	names and supplying a value. For example:
  603        * <code>-licenseKey adslfja83r3lkadf</code></li>
  604        * </ul>
  605        *  The various actions are as follows.
  606        * <ul>
  607        * <li><i>add</i>: Create the sequence table.</li>
  608        * <li><i>drop</i>: Drop the sequence table.</li>
  609        * <li><i>get</i>: Print the current sequence value.</li>
  610        * <li><i>set</i>: Set the sequence value.</li>
  611        * </ul>
  612        */
  613       public static void main(String[] args)
  614           throws Exception {
  615           Options opts = new Options();
  616           final String[] arguments = opts.setFromCmdLine(args);
  617           boolean ret = Configurations.runAgainstAllAnchors(opts,
  618               new Configurations.Runnable() {
  619               public boolean run(Options opts) throws Exception {
  620                   JDBCConfiguration conf = new JDBCConfigurationImpl();
  621                   try {
  622                       return TableJDBCSeq.run(conf, arguments, opts);
  623                   } finally {
  624                       conf.close();
  625                   }
  626               }
  627           });
  628           if (!ret)
  629               System.out.println(_loc.get("seq-usage"));
  630       }
  631   
  632       /**
  633        * Run the tool. Returns false if invalid options were given.
  634        */
  635       public static boolean run(JDBCConfiguration conf, String[] args,
  636           Options opts)
  637           throws Exception {
  638           String action = opts.removeProperty("action", "a", null);
  639           Configurations.populateConfiguration(conf, opts);
  640           return run(conf, args, action);
  641       }
  642   
  643       /**
  644        * Run the tool. Return false if an invalid option was given.
  645        */
  646       public static boolean run(JDBCConfiguration conf, String[] args,
  647           String action)
  648           throws Exception {
  649           if (args.length > 1 || (args.length != 0
  650               && !ACTION_SET.equals(action)))
  651               return false;
  652   
  653           TableJDBCSeq seq = new TableJDBCSeq();
  654           String props = Configurations.getProperties(conf.getSequence());
  655           Configurations.configureInstance(seq, conf, props);
  656   
  657           if (ACTION_DROP.equals(action))
  658               seq.dropTable();
  659           else if (ACTION_ADD.equals(action))
  660               seq.refreshTable();
  661           else if (ACTION_GET.equals(action) || ACTION_SET.equals(action)) {
  662               Connection conn = conf.getDataSource2(null).getConnection();
  663               try {
  664                   long cur = seq.getSequence(null, conn);
  665                   if (ACTION_GET.equals(action))
  666                       System.out.println(cur);
  667                   else {
  668                       long set;
  669                       if (args.length > 0)
  670                           set = Long.parseLong(args[0]);
  671                       else
  672                           set = cur + seq.getAllocate();
  673                       if (set < cur)
  674                           set = cur;
  675                       else {
  676                           Status stat = seq.getStatus(null);
  677                           seq.setSequence(null, stat, (int) (set - cur), true,
  678                               conn);
  679                           set = stat.seq;
  680                       }
  681                       System.err.println(set);
  682                   }
  683               }
  684               catch (NumberFormatException nfe) {
  685                   return false;
  686               } finally {
  687                   try { conn.close(); } catch (SQLException se) {}
  688               }
  689           } else
  690               return false;
  691           return true;
  692       }
  693   
  694       /**
  695        * Helper struct to hold status information.
  696        */
  697       protected static class Status
  698           implements Serializable {
  699   
  700           public long seq = 1L;
  701           public long max = 0L;
  702       }
  703   
  704       /**
  705        * This method is to provide override for non-JDBC or JDBC-like 
  706        * implementation of preparing statement.
  707        */
  708       protected PreparedStatement prepareStatement(Connection conn, SQLBuffer buf)
  709           throws SQLException {
  710           return buf.prepareStatement(conn);
  711       }
  712       
  713       /**
  714        * This method is to provide override for non-JDBC or JDBC-like 
  715        * implementation of executing update.
  716        */
  717       protected int executeUpdate(JDBCConfiguration conf, Connection conn,  
  718           PreparedStatement stmnt, SQLBuffer buf, int opcode) throws SQLException {
  719           return stmnt.executeUpdate();
  720       }
  721       
  722       /**
  723        * This method is to provide override for non-JDBC or JDBC-like 
  724        * implementation of executing query.
  725        */
  726       protected ResultSet executeQuery(JDBCConfiguration conf, Connection conn,
  727           PreparedStatement stmnt, SQLBuffer buf) throws SQLException {
  728           return stmnt.executeQuery();
  729       }
  730       
  731       /**
  732        * This method is to provide override for non-JDBC or JDBC-like 
  733        * implementation of getting sequence from the result set.
  734        */
  735       protected long getSequence(ResultSet rs, DBDictionary dict) throws SQLException {
  736           if (rs == null || !rs.next())
  737               return -1;
  738           return dict.getLong(rs, 1);
  739       }
  740   }

Save This Page
Home » apache-openjpa-1.1.0-source » org.apache.openjpa.jdbc » kernel » [javadoc | source]