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.sql.Connection;
   22   import java.sql.SQLException;
   23   import java.util.BitSet;
   24   import java.util.Collection;
   25   import java.util.Iterator;
   26   import java.util.LinkedList;
   27   
   28   import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
   29   import org.apache.openjpa.jdbc.meta.ClassMapping;
   30   import org.apache.openjpa.jdbc.meta.Discriminator;
   31   import org.apache.openjpa.jdbc.meta.FieldMapping;
   32   import org.apache.openjpa.jdbc.meta.Strategy;
   33   import org.apache.openjpa.jdbc.meta.Version;
   34   import org.apache.openjpa.jdbc.sql.DBDictionary;
   35   import org.apache.openjpa.jdbc.sql.RowManager;
   36   import org.apache.openjpa.jdbc.sql.SQLExceptions;
   37   import org.apache.openjpa.kernel.OpenJPAStateManager;
   38   import org.apache.openjpa.kernel.PCState;
   39   import org.apache.openjpa.lib.conf.Configurable;
   40   import org.apache.openjpa.lib.conf.Configuration;
   41   import org.apache.openjpa.util.ImplHelper;
   42   import org.apache.openjpa.util.OpenJPAException;
   43   import org.apache.openjpa.util.OptimisticException;
   44   
   45   /**
   46    * Base update manager with common functionality.
   47    *
   48    * @author Abe White
   49    */
   50   public abstract class AbstractUpdateManager
   51       implements UpdateManager, Configurable {
   52   
   53       protected JDBCConfiguration conf = null;
   54       protected DBDictionary dict = null;
   55   
   56       public void setConfiguration(Configuration conf) {
   57           this.conf = (JDBCConfiguration) conf;
   58           dict = this.conf.getDBDictionaryInstance();
   59       }
   60   
   61       public void startConfiguration() {
   62       }
   63   
   64       public void endConfiguration() {
   65       }
   66   
   67       public Collection flush(Collection states, JDBCStore store) {
   68           Connection conn = store.getConnection();
   69           try {
   70               PreparedStatementManager psMgr = newPreparedStatementManager(store,
   71                   conn);
   72               return flush(states, store, psMgr);
   73           } finally {
   74               try { conn.close(); } catch (SQLException se) {}
   75           }
   76       }
   77   
   78       private Collection flush(Collection states, JDBCStore store,
   79           PreparedStatementManager psMgr) {
   80           // run through all the states and update them as necessary
   81           RowManager rowMgr = newRowManager();
   82           Collection customs = new LinkedList();
   83           Collection exceps = null;
   84           for (Iterator itr = states.iterator(); itr.hasNext();)
   85               exceps = populateRowManager((OpenJPAStateManager) itr.next(),
   86                   rowMgr, store, exceps, customs);
   87   
   88           // flush rows
   89           exceps = flush(rowMgr, psMgr, exceps);
   90   
   91           // now do any custom mappings
   92           for (Iterator itr = customs.iterator(); itr.hasNext();) {
   93               try {
   94                   ((CustomMapping) itr.next()).execute(store);
   95               } catch (SQLException se) {
   96                   exceps = addException(exceps, SQLExceptions.getStore(se, dict));
   97               } catch (OpenJPAException ke) {
   98                   exceps = addException(exceps, ke);
   99               }
  100           }
  101   
  102           // return all exceptions
  103           Collection psExceps = psMgr.getExceptions();
  104           if (exceps == null)
  105               return psExceps;
  106           if (psExceps == null)
  107               return exceps;
  108           exceps.addAll(psExceps);
  109           return exceps;
  110       }
  111   
  112       /**
  113        * Return a new {@link RowManager}.
  114        */
  115       protected abstract RowManager newRowManager();
  116   
  117       /**
  118        * Return a new {@link PreparedStatementManager}.
  119        */
  120       protected abstract PreparedStatementManager newPreparedStatementManager(
  121           JDBCStore store, Connection conn);
  122   
  123       /**
  124        * Flush all rows of the given row manager. Add exceptions to
  125        * <code>exceps</code> (which may start as null) using
  126        * {@link #addException}. Return <code>exceps</code>.
  127        */
  128       protected abstract Collection flush(RowManager rowMgr,
  129           PreparedStatementManager psMgr, Collection exceps);
  130   
  131       /**
  132        * Populate the row manager with rows to be flushed for the given state.
  133        *
  134        * @param exceps exceptions encountered when flushing will be added to
  135        * this list and returned; the list may be null initially
  136        * @param customs buffer custom mappings
  137        * @return the exceptions list
  138        */
  139       protected Collection populateRowManager(OpenJPAStateManager sm,
  140           RowManager rowMgr, JDBCStore store, Collection exceps,
  141           Collection customs) {
  142           try {
  143               BitSet dirty;
  144               if (sm.getPCState() == PCState.PNEW && !sm.isFlushed()) {
  145                   insert(sm, (ClassMapping) sm.getMetaData(), rowMgr, store,
  146                       customs);
  147               } else if (sm.getPCState() == PCState.PNEWFLUSHEDDELETED
  148                   || sm.getPCState() == PCState.PDELETED) {
  149                   delete(sm, (ClassMapping) sm.getMetaData(), rowMgr, store,
  150                       customs);
  151               } else if ((dirty = ImplHelper.getUpdateFields(sm)) != null) {
  152                   update(sm, dirty, (ClassMapping) sm.getMetaData(), rowMgr,
  153                       store, customs);
  154               } else if (sm.isVersionUpdateRequired()) {
  155                   updateIndicators(sm, (ClassMapping) sm.getMetaData(), rowMgr,
  156                       store, customs, true);
  157               } else if (sm.isVersionCheckRequired()) {
  158                   if (!((ClassMapping) sm.getMetaData()).getVersion().
  159                       checkVersion(sm, store, false))
  160                       exceps = addException(exceps, new OptimisticException(sm.
  161                           getManagedInstance()));
  162               }
  163           } catch (SQLException se) {
  164               exceps = addException(exceps, SQLExceptions.getStore(se, dict));
  165           } catch (OpenJPAException ke) {
  166               exceps = addException(exceps, ke);
  167           }
  168           return exceps;
  169       }
  170   
  171       /**
  172        * Add the given exception to the given list, which may start out as null.
  173        */
  174       protected Collection addException(Collection exceps, Exception err) {
  175           if (exceps == null)
  176               exceps = new LinkedList();
  177           exceps.add(err);
  178           return exceps;
  179       }
  180   
  181       /**
  182        * Recursive method to insert the given instance, base class first.
  183        */
  184       protected void insert(OpenJPAStateManager sm, ClassMapping mapping,
  185           RowManager rowMgr, JDBCStore store, Collection customs)
  186           throws SQLException {
  187           Boolean custom = mapping.isCustomInsert(sm, store);
  188           if (!Boolean.FALSE.equals(custom))
  189               mapping.customInsert(sm, store);
  190           if (Boolean.TRUE.equals(custom))
  191               return;
  192   
  193           ClassMapping sup = mapping.getJoinablePCSuperclassMapping();
  194           if (sup != null)
  195               insert(sm, sup, rowMgr, store, customs);
  196   
  197           mapping.insert(sm, store, rowMgr);
  198           FieldMapping[] fields = mapping.getDefinedFieldMappings();
  199           BitSet dirty = sm.getDirty();
  200           for (int i = 0; i < fields.length; i++) {
  201               if (dirty.get(fields[i].getIndex())
  202                   && !bufferCustomInsert(fields[i], sm, store, customs))
  203                   fields[i].insert(sm, store, rowMgr);
  204           }
  205           if (sup == null) {
  206               Version vers = mapping.getVersion();
  207               if (!bufferCustomInsert(vers, sm, store, customs))
  208                   vers.insert(sm, store, rowMgr);
  209               Discriminator dsc = mapping.getDiscriminator();
  210               if (!bufferCustomInsert(dsc, sm, store, customs))
  211                   dsc.insert(sm, store, rowMgr);
  212           }
  213       }
  214   
  215       /**
  216        * If the given mapping uses a custom insert, places a
  217        * {@link CustomMapping} struct for it in the given collection and
  218        * returns true, else returns false.
  219        */
  220       private boolean bufferCustomInsert(Strategy strat, OpenJPAStateManager sm,
  221           JDBCStore store, Collection customs) {
  222           Boolean custom = strat.isCustomInsert(sm, store);
  223           if (!Boolean.FALSE.equals(custom))
  224               customs.add(new CustomMapping(CustomMapping.INSERT, sm, strat));
  225           return Boolean.TRUE.equals(custom);
  226       }
  227   
  228       /**
  229        * Recursive method to delete the given instance, base class last.
  230        */
  231       protected void delete(OpenJPAStateManager sm, ClassMapping mapping,
  232           RowManager rowMgr, JDBCStore store, Collection customs)
  233           throws SQLException {
  234           Boolean custom = mapping.isCustomDelete(sm, store);
  235           if (!Boolean.FALSE.equals(custom))
  236               mapping.customDelete(sm, store);
  237           if (Boolean.TRUE.equals(custom))
  238               return;
  239   
  240           FieldMapping[] fields = mapping.getDefinedFieldMappings();
  241           for (int i = 0; i < fields.length; i++)
  242               if (!bufferCustomDelete(fields[i], sm, store, customs))
  243                   fields[i].delete(sm, store, rowMgr);
  244   
  245           ClassMapping sup = mapping.getJoinablePCSuperclassMapping();
  246           if (sup == null) {
  247               Version vers = mapping.getVersion();
  248               if (!bufferCustomDelete(vers, sm, store, customs))
  249                   vers.delete(sm, store, rowMgr);
  250               Discriminator dsc = mapping.getDiscriminator();
  251               if (!bufferCustomDelete(dsc, sm, store, customs))
  252                   dsc.delete(sm, store, rowMgr);
  253           }
  254           mapping.delete(sm, store, rowMgr);
  255   
  256           if (sup != null)
  257               delete(sm, sup, rowMgr, store, customs);
  258       }
  259   
  260       /**
  261        * @see #bufferCustomInsert
  262        */
  263       private boolean bufferCustomDelete(Strategy strat, OpenJPAStateManager sm,
  264           JDBCStore store, Collection customs) {
  265           Boolean custom = strat.isCustomDelete(sm, store);
  266           if (!Boolean.FALSE.equals(custom))
  267               customs.add(new CustomMapping(CustomMapping.DELETE, sm, strat));
  268           return Boolean.TRUE.equals(custom);
  269       }
  270   
  271       /**
  272        * Recursive method to update the given instance.
  273        */
  274       protected void update(OpenJPAStateManager sm, BitSet dirty,
  275           ClassMapping mapping, RowManager rowMgr, JDBCStore store,
  276           Collection customs) throws SQLException {
  277           Boolean custom = mapping.isCustomUpdate(sm, store);
  278           if (!Boolean.FALSE.equals(custom))
  279               mapping.customUpdate(sm, store);
  280           if (Boolean.TRUE.equals(custom))
  281               return;
  282   
  283           // update all fields before all mappings so that the mappings can
  284           // detect whether any fields in their rows have been modified
  285           FieldMapping[] fields = mapping.getDefinedFieldMappings();
  286           for (int i = 0; i < fields.length; i++) {
  287               if (dirty.get(fields[i].getIndex())
  288                   && !bufferCustomUpdate(fields[i], sm, store, customs))
  289                   fields[i].update(sm, store, rowMgr);
  290           }
  291   
  292           ClassMapping sup = mapping.getJoinablePCSuperclassMapping();
  293           if (sup == null)
  294               updateIndicators(sm, mapping, rowMgr, store, customs, false);
  295           else
  296               update(sm, dirty, sup, rowMgr, store, customs);
  297           mapping.update(sm, store, rowMgr);
  298       }
  299   
  300       /**
  301        * Update version and discriminator indicators.
  302        */
  303       protected void updateIndicators(OpenJPAStateManager sm, ClassMapping mapping,
  304           RowManager rowMgr, JDBCStore store, Collection customs,
  305           boolean versionUpdateOnly) throws SQLException {
  306           while (mapping.getJoinablePCSuperclassMapping() != null)
  307               mapping = mapping.getJoinablePCSuperclassMapping();
  308   
  309           Version vers = mapping.getVersion();
  310           if (!bufferCustomUpdate(vers, sm, store, customs))
  311               vers.update(sm, store, rowMgr);
  312   
  313           if (versionUpdateOnly) {
  314               // if we are only updating the version column, we need to add
  315               // in the primary key select
  316               mapping.update(sm, store, rowMgr);
  317           } else {
  318               // otherwise we need to make sure we update the discriminator too
  319               Discriminator dsc = mapping.getDiscriminator();
  320               if (!bufferCustomUpdate(dsc, sm, store, customs))
  321                   dsc.update(sm, store, rowMgr);
  322           }
  323       }
  324   
  325       /**
  326        * @see #bufferCustomInsert
  327        */
  328       private boolean bufferCustomUpdate(Strategy strat, OpenJPAStateManager sm,
  329           JDBCStore store, Collection customs) {
  330           Boolean custom = strat.isCustomUpdate(sm, store);
  331           if (!Boolean.FALSE.equals(custom))
  332               customs.add(new CustomMapping(CustomMapping.UPDATE, sm, strat));
  333           return Boolean.TRUE.equals(custom);
  334       }
  335   
  336       /**
  337        * Executes customized mapping updates.
  338        */
  339       protected static class CustomMapping {
  340   
  341           public static final int INSERT = 0;
  342           public static final int UPDATE = 1;
  343           public static final int DELETE = 3;
  344   
  345           private final int _action;
  346           private final OpenJPAStateManager _sm;
  347           private final Strategy _strat;
  348   
  349           public CustomMapping(int action, OpenJPAStateManager sm, Strategy strat) {
  350               _action = action;
  351               _sm = sm;
  352               _strat = strat;
  353           }
  354   
  355           public void execute(JDBCStore store) throws SQLException {
  356               switch (_action) {
  357               case INSERT:
  358                   _strat.customInsert(_sm, store);
  359                   break;
  360               case UPDATE:
  361                   _strat.customUpdate(_sm, store);
  362                   break;
  363               case DELETE:
  364                   _strat.customDelete(_sm, store);
  365                   break;
  366               }
  367           }
  368       }
  369   }

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