Home » apache-openjpa-1.1.0-source » org.apache.openjpa.lib » rop » [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.lib.rop;
   20   
   21   import java.util.Comparator;
   22   
   23   import org.apache.commons.lang.exception.NestableRuntimeException;
   24   
   25   /**
   26    * A result object provider that merges multiple result object provider
   27    * delegates. Support exists for maintaining ordering of the internally held
   28    * results, provided that each of the individual results is itself ordered.
   29    *
   30    * @author Abe White
   31    * @author Marc Prud'hommeaux
   32    */
   33   public class MergedResultObjectProvider implements ResultObjectProvider {
   34   
   35       private static final byte UNOPENED = 0;
   36       private static final byte OPENED = 1;
   37       private static final byte VALUE = 2;
   38       private static final byte DONE = 3;
   39   
   40       private final ResultObjectProvider[] _rops;
   41       private final Comparator _comp;
   42       private final byte[] _status;
   43       private Object[] _values;
   44       private Object[] _orderValues;
   45       private Object _cur = null;
   46       private int _size = -1;
   47   
   48       /**
   49        * Constructor. Provide delegates.
   50        */
   51       public MergedResultObjectProvider(ResultObjectProvider[] rops) {
   52           this(rops, null);
   53       }
   54   
   55       /**
   56        * Constructor. Provide delegates and optional comparator.
   57        */
   58       public MergedResultObjectProvider(ResultObjectProvider[] rops,
   59           Comparator comp) {
   60           _rops = rops;
   61           _comp = comp;
   62           _status = new byte[rops.length];
   63           _values = (comp == null) ? null : new Object[rops.length];
   64           _orderValues = (comp == null) ? null : new Object[rops.length];
   65       }
   66   
   67       public boolean supportsRandomAccess() {
   68           return false;
   69       }
   70   
   71       public void open() throws Exception {
   72           // if we have a comparator, then open all; else open first
   73           int len = (_comp != null) ? _rops.length : 1;
   74           for (int i = 0; i < len; i++) {
   75               _rops[i].open();
   76               _status[i] = OPENED;
   77           }
   78       }
   79   
   80       public boolean absolute(int pos) throws Exception {
   81           throw new UnsupportedOperationException();
   82       }
   83   
   84       public int size() throws Exception {
   85           if (_size != -1)
   86               return _size;
   87   
   88           // have to open all to get sizes
   89           for (int i = 0; i < _status.length; i++) {
   90               if (_status[i] == UNOPENED) {
   91                   _rops[i].open();
   92                   _status[i] = OPENED;
   93               }
   94           }
   95   
   96           int total = 0;
   97           int size;
   98           for (int i = 0; i < _rops.length; i++) {
   99               size = _rops[i].size();
  100               if (size == Integer.MAX_VALUE) {
  101                   total = size;
  102                   break;
  103               }
  104               total += size;
  105           }
  106           _size = total;
  107           return _size;
  108       }
  109   
  110       public void reset() throws Exception {
  111           for (int i = 0; i < _rops.length; i++)
  112               if (_status[i] != UNOPENED)
  113                   _rops[i].reset();
  114           clear();
  115       }
  116   
  117       public void close() throws Exception {
  118           Exception err = null;
  119           for (int i = 0; i < _rops.length; i++) {
  120               try {
  121                   if (_status[i] != UNOPENED)
  122                       _rops[i].close();
  123               } catch (Exception e) {
  124                   if (err == null)
  125                       err = e;
  126               }
  127           }
  128   
  129           clear();
  130           if (err != null)
  131               throw err;
  132       }
  133   
  134       private void clear() {
  135           _cur = null;
  136           for (int i = 0; i < _rops.length; i++) {
  137               _status[i] = OPENED;
  138               if (_values != null)
  139                   _values[i] = null;
  140               if (_orderValues != null)
  141                   _orderValues[i] = null;
  142           }
  143       }
  144   
  145       public void handleCheckedException(Exception e) {
  146           if (_rops.length == 0)
  147               throw new NestableRuntimeException(e);
  148           _rops[0].handleCheckedException(e);
  149       }
  150   
  151       public boolean next() throws Exception {
  152           // initialize all rops with the latest values
  153           boolean hasValue = false;
  154           for (int i = 0; i < _status.length; i++) {
  155               switch (_status[i]) {
  156                   case UNOPENED:
  157                       // this will only ever be the case if we aren't ordering
  158                       _rops[i].open();
  159                       _status[i] = OPENED;
  160                       // no break
  161                   case OPENED:
  162                       // if this rop has a value, cache it; if we're not ordering,
  163                       // then that's the value to return
  164                       if (_rops[i].next()) {
  165                           if (_comp == null) {
  166                               _cur = _rops[i].getResultObject();
  167                               return true;
  168                           } else {
  169                               hasValue = true;
  170                               _status[i] = VALUE;
  171                               _values[i] = _rops[i].getResultObject();
  172                               _orderValues[i] = getOrderingValue(_values[i],
  173                                   i, _rops[i]);
  174                           }
  175                       } else
  176                           _status[i] = DONE;
  177                       break;
  178                   case VALUE:
  179                       // we only use this state when ordering
  180                       hasValue = true;
  181                       break;
  182               }
  183           }
  184   
  185           // if we get to this point without a comparator, it means none
  186           // of our rops have any more values
  187           if (_comp == null || !hasValue)
  188               return false;
  189   
  190           // for all the rops with values, find the 'least' one according to
  191           // the comparator
  192           int least = -1;
  193           Object orderVal = null;
  194           for (int i = 0; i < _orderValues.length; i++) {
  195               if (_status[i] != VALUE)
  196                   continue;
  197               if (least == -1 || _comp.compare(_orderValues[i], orderVal) < 0) {
  198                   least = i;
  199                   orderVal = _orderValues[i];
  200               }
  201           }
  202   
  203           // assign the least value to the current one, and clear the cached
  204           // value for that rop so that we know to get the next value for
  205           // the next comparison
  206           _cur = _values[least];
  207           _values[least] = null;
  208           _orderValues[least] = null;
  209           _status[least] = OPENED;
  210           return true;
  211       }
  212   
  213       public Object getResultObject() throws Exception {
  214           return _cur;
  215       }
  216   
  217       /**
  218        * Return the value to use for ordering on the given result value. Returns
  219        * the result value by default.
  220        *
  221        * @param val the result value
  222        * @param idx the index of the result object provider in the array
  223        * given on construction that produced the result value
  224        * @param rop the result object provider that produced the result value
  225        */
  226       protected Object getOrderingValue(Object val, int idx,
  227           ResultObjectProvider rop) {
  228           return val;
  229       }
  230   }

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