Home » apache-openjpa-1.1.0-source » org.apache.openjpa » 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.kernel;
   20   
   21   import java.io.Serializable;
   22   import java.util.ArrayList;
   23   import java.util.Collection;
   24   import java.util.HashSet;
   25   import java.util.Iterator;
   26   import java.util.List;
   27   import java.util.Map;
   28   import java.util.Set;
   29   
   30   import org.apache.commons.collections.map.LinkedMap;
   31   import org.apache.openjpa.conf.OpenJPAConfiguration;
   32   import org.apache.openjpa.kernel.exps.AbstractExpressionVisitor;
   33   import org.apache.openjpa.kernel.exps.AggregateListener;
   34   import org.apache.openjpa.kernel.exps.Constant;
   35   import org.apache.openjpa.kernel.exps.ExpressionFactory;
   36   import org.apache.openjpa.kernel.exps.ExpressionParser;
   37   import org.apache.openjpa.kernel.exps.FilterListener;
   38   import org.apache.openjpa.kernel.exps.InMemoryExpressionFactory;
   39   import org.apache.openjpa.kernel.exps.Path;
   40   import org.apache.openjpa.kernel.exps.QueryExpressions;
   41   import org.apache.openjpa.kernel.exps.Resolver;
   42   import org.apache.openjpa.kernel.exps.StringContains;
   43   import org.apache.openjpa.kernel.exps.Val;
   44   import org.apache.openjpa.kernel.exps.Value;
   45   import org.apache.openjpa.kernel.exps.WildcardMatch;
   46   import org.apache.openjpa.lib.rop.ListResultObjectProvider;
   47   import org.apache.openjpa.lib.rop.RangeResultObjectProvider;
   48   import org.apache.openjpa.lib.rop.ResultObjectProvider;
   49   import org.apache.openjpa.lib.util.Localizer;
   50   import org.apache.openjpa.meta.ClassMetaData;
   51   import org.apache.openjpa.meta.FieldMetaData;
   52   import org.apache.openjpa.meta.JavaTypes;
   53   import org.apache.openjpa.util.ImplHelper;
   54   import org.apache.openjpa.util.InvalidStateException;
   55   import org.apache.openjpa.util.UnsupportedException;
   56   import org.apache.openjpa.util.UserException;
   57   
   58   /**
   59    * Implementation of an expression-based query, which can handle
   60    * String-based query expressions such as JPQL and JDOQL.
   61    * This implementation is suitable for in-memory operation.
   62    * Override the following methods to also support datastore operation:
   63    * <ul>
   64    * <li>Override {@link #supportsDataStoreExecution} to return
   65    * <code>true</code>.</li>
   66    * <li>Override {@link #executeQuery}, {@link #executeDelete}, and
   67    * {@link #executeUpdate} to execute the query against the data store.
   68    * Keep in mind that the parameters passed to this method might be in use
   69    * by several threads in different query instances. Thus components like
   70    * the expression factory must either be thread safe, or this method must
   71    * synchronize on them.</li>
   72    * <li>Override {@link #getDataStoreActions} to return a representation of
   73    * the actions that will be taken on the data store. For use in visual
   74    * tools.</li>
   75    * <li>Override {@link #getExpressionFactory} to return a factory for creating
   76    * expressions in the datastore's language. The factory must be cachable.</li>
   77    * </ul>
   78    *
   79    * @author Abe White
   80    */
   81   public class ExpressionStoreQuery
   82       extends AbstractStoreQuery {
   83   
   84       private static final Localizer _loc = Localizer.forPackage
   85           (ExpressionStoreQuery.class);
   86   
   87       // maintain support for a couple of deprecated extensions
   88       private static final FilterListener[] _listeners = new FilterListener[]{
   89           new StringContains(), new WildcardMatch(),
   90       };
   91   
   92       private final ExpressionParser _parser;
   93       private transient Object _parsed;
   94   
   95       /**
   96        * Construct a query with a parser for the language.
   97        */
   98       public ExpressionStoreQuery(ExpressionParser parser) {
   99           _parser = parser;
  100       }
  101   
  102       /**
  103        * Resolver used in parsing.
  104        */
  105       public Resolver getResolver() {
  106           return new Resolver() {
  107               public Class classForName(String name, String[] imports) {
  108                   return ctx.classForName(name, imports);
  109               }
  110   
  111               public FilterListener getFilterListener(String tag) {
  112                   return ctx.getFilterListener(tag);
  113               }
  114   
  115               public AggregateListener getAggregateListener(String tag) {
  116                   return ctx.getAggregateListener(tag);
  117               }
  118   
  119               public OpenJPAConfiguration getConfiguration() {
  120                   return ctx.getStoreContext().getConfiguration();
  121               }
  122   
  123               public QueryContext getQueryContext() {
  124                   return ctx;
  125               }
  126           };
  127       }
  128   
  129       /**
  130        * Allow direct setting of parsed state for facades that do parsing.
  131        * The facade should call this method twice: once with the query string,
  132        * and again with the parsed state.
  133        */
  134       public boolean setQuery(Object query) {
  135           _parsed = query;
  136           return true;
  137       }
  138   
  139       public FilterListener getFilterListener(String tag) {
  140           for (int i = 0; i < _listeners.length; i++)
  141               if (_listeners[i].getTag().equals(tag))
  142                   return _listeners[i];
  143           return null;
  144       }
  145   
  146       public Object newCompilation() {
  147           if (_parsed != null)
  148               return _parsed;
  149           return _parser.parse(ctx.getQueryString(), this);
  150       }
  151   
  152       public void populateFromCompilation(Object comp) {
  153           _parser.populate(comp, this);
  154       }
  155   
  156       public void invalidateCompilation() {
  157           _parsed = null;
  158       }
  159   
  160       public boolean supportsInMemoryExecution() {
  161           return true;
  162       }
  163   
  164       public Executor newInMemoryExecutor(ClassMetaData meta, boolean subs) {
  165           return new InMemoryExecutor(this, meta, subs, _parser,
  166               ctx.getCompilation());
  167       }
  168   
  169       public Executor newDataStoreExecutor(ClassMetaData meta, boolean subs) {
  170           return new DataStoreExecutor(this, meta, subs, _parser,
  171               ctx.getCompilation());
  172       }
  173   
  174       ////////////////////////
  175       // Methods for Override
  176       ////////////////////////
  177   
  178       /**
  179        * Execute the given expression against the given candidate extent.
  180        *
  181        * @param ex current executor
  182        * @param base the base type the query should match
  183        * @param types the independent candidate types
  184        * @param subclasses true if subclasses should be included in the results
  185        * @param facts the expression factory used to build the query for
  186        * each base type
  187        * @param parsed the parsed query values
  188        * @param params parameter values, or empty array
  189        * @param range result range
  190        * @return a provider for matching objects
  191        */
  192       protected ResultObjectProvider executeQuery(Executor ex,
  193           ClassMetaData base, ClassMetaData[] types, boolean subclasses,
  194           ExpressionFactory[] facts, QueryExpressions[] parsed, Object[] params,
  195           Range range) {
  196           throw new UnsupportedException();
  197       }
  198   
  199       /**
  200        * Execute the given expression against the given candidate extent
  201        * and delete the instances.
  202        *
  203        * @param ex current executor
  204        * @param base the base type the query should match
  205        * @param types the independent candidate types
  206        * @param subclasses true if subclasses should be included in the results
  207        * @param facts the expression factory used to build the query for
  208        * each base type
  209        * @param parsed the parsed query values
  210        * @param params parameter values, or empty array
  211        * @return a number indicating the number of instances deleted,
  212        * or null to execute the delete in memory
  213        */
  214       protected Number executeDelete(Executor ex, ClassMetaData base,
  215           ClassMetaData[] types, boolean subclasses, ExpressionFactory[] facts,
  216           QueryExpressions[] parsed, Object[] params) {
  217           return null;
  218       }
  219   
  220       /**
  221        * Execute the given expression against the given candidate extent
  222        * and updates the instances.
  223        *
  224        * @param ex current executor
  225        * @param base the base type the query should match
  226        * @param types the independent candidate types
  227        * @param subclasses true if subclasses should be included in the results
  228        * @param facts the expression factory used to build the query for
  229        * each base type
  230        * @param parsed the parsed query values
  231        * @param params parameter values, or empty array
  232        * @return a number indicating the number of instances updated,
  233        * or null to execute the update in memory.
  234        */
  235       protected Number executeUpdate(Executor ex, ClassMetaData base,
  236           ClassMetaData[] types, boolean subclasses, ExpressionFactory[] facts,
  237           QueryExpressions[] parsed, Object[] params) {
  238           return null;
  239       }
  240   
  241       /**
  242        * Return the commands that will be sent to the datastore in order
  243        * to execute the query, typically in the database's native language.
  244        *
  245        * @param base the base type the query should match
  246        * @param types the independent candidate types
  247        * @param subclasses true if subclasses should be included in the results
  248        * @param facts the expression factory used to build the query for
  249        * each base type
  250        * @param parsed the parsed query values
  251        * @param params parameter values, or empty array
  252        * @param range result range
  253        * @return a textual description of the query to execute
  254        */
  255       protected String[] getDataStoreActions(ClassMetaData base,
  256           ClassMetaData[] types, boolean subclasses, ExpressionFactory[] facts,
  257           QueryExpressions[] parsed, Object[] params, Range range) {
  258           return StoreQuery.EMPTY_STRINGS;
  259       }
  260   
  261       /**
  262        * Return the assignable types for the given metadata whose expression
  263        * trees must be compiled independently.
  264        */
  265       protected ClassMetaData[] getIndependentExpressionCandidates
  266           (ClassMetaData type, boolean subclasses) {
  267           return new ClassMetaData[]{ type };
  268       }
  269   
  270       /**
  271        * Return an {@link ExpressionFactory} to use to create an expression to
  272        * be executed against an extent. Each factory will be used to compile
  273        * one filter only. The factory must be cachable.
  274        */
  275       protected ExpressionFactory getExpressionFactory(ClassMetaData type) {
  276           throw new UnsupportedException();
  277       }
  278   
  279       /**
  280        * Provides support for queries that hold query information
  281        * in a {@link QueryExpressions} instance.
  282        *
  283        * @author Marc Prud'hommeaux
  284        */
  285       public static abstract class AbstractExpressionExecutor
  286           extends AbstractExecutor
  287           implements Executor {
  288   
  289           /**
  290            * Return the parsed query expressions for our candidate types.
  291            */
  292           protected abstract QueryExpressions[] getQueryExpressions();
  293   
  294           /**
  295            * Return the query expressions for one candidate type, or die if none.
  296            */
  297           private QueryExpressions assertQueryExpression() {
  298               QueryExpressions[] exp = getQueryExpressions();
  299               if (exp == null || exp.length < 1)
  300                   throw new InvalidStateException(_loc.get("no-expressions"));
  301   
  302               return exp[0];
  303           }
  304   
  305           /**
  306            * Throw proper exception if given value is a collection/map/array.
  307            */
  308           protected void assertNotContainer(Value val, StoreQuery q) {
  309               // variables represent container elements, not the container itself
  310               if (val.isVariable())
  311                   return;
  312   
  313               Class type;
  314               if (val instanceof Path) {
  315                   FieldMetaData fmd = ((Path) val).last();
  316                   type = (fmd == null) ? val.getType() : fmd.getDeclaredType();
  317               } else
  318                   type = val.getType();
  319   
  320               switch (JavaTypes.getTypeCode(type)) {
  321                   case JavaTypes.ARRAY:
  322                   case JavaTypes.COLLECTION:
  323                   case JavaTypes.MAP:
  324                       throw new UserException(_loc.get("container-projection",
  325                           q.getContext().getQueryString()));
  326               }
  327           }
  328   
  329           public final void validate(StoreQuery q) {
  330               QueryExpressions exps = assertQueryExpression();    
  331               ValidateGroupingExpressionVisitor.validate(q.getContext(), exps); 
  332           }
  333   
  334           public void getRange(StoreQuery q, Object[] params, Range range) {
  335               QueryExpressions exps = assertQueryExpression();
  336               if (exps.range.length == 0)
  337                   return;
  338   
  339               if (exps.range.length == 2 
  340                   && exps.range[0] instanceof Constant
  341                   && exps.range[1] instanceof Constant) {
  342                   try {
  343                       range.start = ((Number) ((Constant) exps.range[0]).
  344                           getValue(params)).longValue();
  345                       range.end = ((Number) ((Constant) exps.range[1]).
  346                           getValue(params)).longValue();
  347                       return;
  348                   } catch (ClassCastException cce) {
  349                       // fall through to exception below
  350                   } catch (NullPointerException npe) {
  351                       // fall through to exception below
  352                   }
  353               }
  354               throw new UserException(_loc.get("only-range-constants",
  355                   q.getContext().getQueryString()));
  356           }
  357   
  358           public final Class getResultClass(StoreQuery q) {
  359               return assertQueryExpression().resultClass;
  360           }
  361   
  362           public final boolean[] getAscending(StoreQuery q) {
  363               return assertQueryExpression().ascending;
  364           }
  365   
  366           public final String getAlias(StoreQuery q) {
  367               return assertQueryExpression().alias;
  368           }
  369   
  370           public final String[] getProjectionAliases(StoreQuery q) {
  371               return assertQueryExpression().projectionAliases;
  372           }
  373   
  374           public final int getOperation(StoreQuery q) {
  375               return assertQueryExpression().operation;
  376           }
  377   
  378           public final boolean isAggregate(StoreQuery q) {
  379               return assertQueryExpression().isAggregate();
  380           }
  381   
  382           public final boolean hasGrouping(StoreQuery q) {
  383               return assertQueryExpression().grouping.length > 0;
  384           }
  385   
  386           public final LinkedMap getParameterTypes(StoreQuery q) {
  387               return assertQueryExpression().parameterTypes;
  388           }
  389   
  390           public final Map getUpdates(StoreQuery q) {
  391               return assertQueryExpression().updates;
  392           }
  393   
  394           public final ClassMetaData[] getAccessPathMetaDatas(StoreQuery q) {
  395               QueryExpressions[] exps = getQueryExpressions();
  396               if (exps.length == 1)
  397                   return exps[0].accessPath;
  398   
  399               List metas = null;
  400               for (int i = 0; i < exps.length; i++)
  401                   metas = Filters.addAccessPathMetaDatas(metas,
  402                       exps[i].accessPath);
  403               if (metas == null)
  404                   return StoreQuery.EMPTY_METAS;
  405               return (ClassMetaData[]) metas.toArray
  406                   (new ClassMetaData[metas.size()]);
  407           }
  408   
  409           public boolean isPacking(StoreQuery q) {
  410               return false;
  411           }
  412   
  413           /**
  414            * Throws an exception if select or having clauses contain 
  415            * non-aggregate, non-grouped paths.
  416            */
  417           private static class ValidateGroupingExpressionVisitor 
  418               extends AbstractExpressionVisitor {
  419   
  420               private final QueryContext _ctx;
  421               private boolean _grouping = false;
  422               private Set _grouped = null;
  423               private Value _agg = null;
  424   
  425               /**
  426                * Throw proper exception if query does not meet validation.
  427                */
  428               public static void validate(QueryContext ctx, 
  429                   QueryExpressions exps) {
  430                   if (exps.grouping.length == 0)
  431                       return;
  432   
  433                   ValidateGroupingExpressionVisitor visitor = 
  434                       new ValidateGroupingExpressionVisitor(ctx);
  435                   visitor._grouping = true;
  436                   for (int i = 0; i < exps.grouping.length; i++)
  437                       exps.grouping[i].acceptVisit(visitor);
  438                   visitor._grouping = false;
  439                   if (exps.having != null)
  440                       exps.having.acceptVisit(visitor);
  441                   for (int i = 0; i < exps.projections.length; i++)
  442                       exps.projections[i].acceptVisit(visitor);
  443               }
  444   
  445               public ValidateGroupingExpressionVisitor(QueryContext ctx) {
  446                   _ctx = ctx;
  447               }
  448   
  449               public void enter(Value val) {
  450                   if (_grouping) {
  451                       if (val instanceof Path) {
  452                           if (_grouped == null)
  453                               _grouped = new HashSet();
  454                           _grouped.add(val);
  455                       }
  456                   } else if (_agg == null) {
  457                       if (val.isAggregate()) 
  458                           _agg = val;
  459                       else if (val instanceof Path 
  460                           && (_grouped == null || !_grouped.contains(val))) {
  461                           throw new UserException(_loc.get("bad-grouping",
  462                               _ctx.getCandidateType(), _ctx.getQueryString())); 
  463                       }
  464                   }
  465               }
  466   
  467               public void exit(Value val) {
  468                   if (val == _agg)
  469                       _agg = null;
  470               }
  471           }
  472       }
  473   
  474       /**
  475        * Runs the expression query in memory.
  476        */
  477       private static class InMemoryExecutor
  478           extends AbstractExpressionExecutor
  479           implements Executor, Serializable {
  480   
  481           private final ClassMetaData _meta;
  482           private final boolean _subs;
  483           private final InMemoryExpressionFactory _factory;
  484           private final QueryExpressions[] _exps;
  485           private final Class[] _projTypes;
  486   
  487           public InMemoryExecutor(ExpressionStoreQuery q,
  488               ClassMetaData candidate, boolean subclasses,
  489               ExpressionParser parser, Object parsed) {
  490               _meta = candidate;
  491               _subs = subclasses;
  492               _factory = new InMemoryExpressionFactory();
  493   
  494               _exps = new QueryExpressions[] {
  495                   parser.eval(parsed, q, _factory, _meta)
  496               };
  497               if (_exps[0].projections.length == 0)
  498                   _projTypes = StoreQuery.EMPTY_CLASSES;
  499               else {
  500                   AssertNoVariablesExpressionVisitor novars = new
  501                       AssertNoVariablesExpressionVisitor(q.getContext());
  502                   _projTypes = new Class[_exps[0].projections.length];
  503                   for (int i = 0; i < _exps[0].projections.length; i++) {
  504                       _projTypes[i] = _exps[0].projections[i].getType();
  505                       assertNotContainer(_exps[0].projections[i], q);
  506                       _exps[0].projections[i].acceptVisit(novars);
  507                   }
  508                   for (int i = 0; i < _exps[0].grouping.length; i++)
  509                       _exps[0].grouping[i].acceptVisit(novars);
  510               }
  511           }
  512   
  513           protected QueryExpressions[] getQueryExpressions() {
  514               return _exps;
  515           }
  516   
  517           public ResultObjectProvider executeQuery(StoreQuery q,
  518               Object[] params, Range range) {
  519               // execute in memory for candidate collection;
  520               // also execute in memory for transactional extents
  521               Collection coll = q.getContext().getCandidateCollection();
  522               Iterator itr;
  523               if (coll != null)
  524                   itr = coll.iterator();
  525               else
  526                   itr = q.getContext().getStoreContext().
  527                       extentIterator(_meta.getDescribedType(), _subs,
  528                           q.getContext().getFetchConfiguration(),
  529                           q.getContext().getIgnoreChanges());
  530   
  531               // find matching objects
  532               List results = new ArrayList();
  533               StoreContext ctx = q.getContext().getStoreContext();
  534               try {
  535                   Object obj;
  536                   while (itr.hasNext()) {
  537                       obj = itr.next();
  538                       if (_factory.matches(_exps[0], _meta, _subs, obj, ctx,
  539                           params))
  540                           results.add(obj);
  541                   }
  542               }
  543               finally {
  544                   ImplHelper.close(itr);
  545               }
  546   
  547               // group results
  548               results = _factory.group(_exps[0], results, ctx, params);
  549   
  550               // apply having to filter groups
  551               if (_exps[0].having != null) {
  552                   List matches = new ArrayList(results.size());
  553                   Collection c;
  554                   itr = results.iterator();
  555                   while (itr.hasNext()) {
  556                       c = (Collection) itr.next();
  557                       if (_factory.matches(_exps[0], c, ctx, params))
  558                           matches.add(c);
  559                   }
  560                   results = matches;
  561               }
  562   
  563               // apply projections, order results, and filter duplicates
  564               results = _factory.project(_exps[0], results, ctx, params);
  565               results = _factory.order(_exps[0], results, ctx, params);
  566               results = _factory.distinct(_exps[0], coll == null, results);
  567   
  568               ResultObjectProvider rop = new ListResultObjectProvider(results);
  569               if (range.start != 0 || range.end != Long.MAX_VALUE)
  570                   rop = new RangeResultObjectProvider(rop, range.start,range.end);
  571               return rop;
  572           }
  573   
  574           public String[] getDataStoreActions(StoreQuery q, Object[] params,
  575               Range range) {
  576               // in memory queries have no datastore actions to perform
  577               return StoreQuery.EMPTY_STRINGS;
  578           }
  579   
  580           public Object getOrderingValue(StoreQuery q, Object[] params,
  581               Object resultObject, int orderIndex) {
  582               // if this is a projection, then we have to order on something
  583               // we selected
  584               if (_exps[0].projections.length > 0) {
  585                   String ordering = _exps[0].orderingClauses[orderIndex];
  586                   for (int i = 0; i < _exps[0].projectionClauses.length; i++)
  587                       if (ordering.equals(_exps[0].projectionClauses[i]))
  588                           return ((Object[]) resultObject)[i];
  589   
  590                   throw new InvalidStateException(_loc.get
  591                       ("merged-order-with-result", q.getContext().getLanguage(),
  592                           q.getContext().getQueryString(), ordering));
  593               }
  594   
  595               // use the parsed ordering expression to extract the ordering value
  596               Val val = (Val) _exps[0].ordering[orderIndex];
  597               return val.evaluate(resultObject, resultObject, q.getContext().
  598                   getStoreContext(), params);
  599           }
  600   
  601           public Class[] getProjectionTypes(StoreQuery q) {
  602               return _projTypes;
  603           }
  604   
  605           /**
  606            * Throws an exception if a variable is found.
  607            */
  608           private static class AssertNoVariablesExpressionVisitor 
  609               extends AbstractExpressionVisitor {
  610   
  611               private final QueryContext _ctx;
  612   
  613               public AssertNoVariablesExpressionVisitor(QueryContext ctx) {
  614                   _ctx = ctx;
  615               }
  616   
  617               public void enter(Value val) {
  618                   if (!val.isVariable())
  619                       return;
  620                   throw new UnsupportedException(_loc.get("inmem-agg-proj-var", 
  621                       _ctx.getCandidateType(), _ctx.getQueryString()));
  622               }
  623           }
  624       }
  625   
  626       /**
  627        * The DataStoreExecutor executes the query against the
  628        * implementation's overridden {@link #executeQuery} method.
  629        *
  630        * @author Marc Prud'hommeaux
  631        */
  632       public static class DataStoreExecutor
  633           extends AbstractExpressionExecutor
  634           implements Executor, Serializable {
  635   
  636           private ClassMetaData _meta;
  637           private ClassMetaData[] _metas;
  638           private boolean _subs;
  639           private ExpressionParser _parser;
  640           private ExpressionFactory[] _facts;
  641           private QueryExpressions[] _exps;
  642           private Class[] _projTypes;
  643           private Value[] _inMemOrdering;
  644   
  645           public DataStoreExecutor(ExpressionStoreQuery q,
  646               ClassMetaData meta, boolean subclasses,
  647               ExpressionParser parser, Object parsed) {
  648               _metas = q.getIndependentExpressionCandidates(meta, subclasses);
  649               if (_metas.length == 0)
  650                   throw new UserException(_loc.get("query-unmapped", meta));
  651               _meta = meta;
  652               _subs = subclasses;
  653               _parser = parser;
  654   
  655               _facts = new ExpressionFactory[_metas.length];
  656               for (int i = 0; i < _facts.length; i++)
  657                   _facts[i] = q.getExpressionFactory(_metas[i]);
  658   
  659               _exps = new QueryExpressions[_metas.length];
  660               for (int i = 0; i < _exps.length; i++)
  661                   _exps[i] = parser.eval(parsed, q, _facts[i], _metas[i]);
  662   
  663               if (_exps[0].projections.length == 0)
  664                   _projTypes = StoreQuery.EMPTY_CLASSES;
  665               else {
  666                   _projTypes = new Class[_exps[0].projections.length];
  667                   for (int i = 0; i < _exps[0].projections.length; i++) {
  668                       assertNotContainer(_exps[0].projections[i], q);
  669                       _projTypes[i] = _exps[0].projections[i].getType();
  670                   }
  671               }
  672           }
  673   
  674           protected QueryExpressions[] getQueryExpressions() {
  675               return _exps;
  676           }
  677   
  678           public ResultObjectProvider executeQuery(StoreQuery q,
  679               Object[] params, Range range) {
  680               range.lrs &= !isAggregate(q) && !hasGrouping(q);
  681               return ((ExpressionStoreQuery) q).executeQuery(this, _meta, _metas,
  682                   _subs, _facts, _exps, params, range);
  683           }
  684   
  685           public Number executeDelete(StoreQuery q, Object[] params) {
  686               Number num = ((ExpressionStoreQuery) q).executeDelete(this, _meta,
  687                   _metas, _subs, _facts, _exps, params);
  688               if (num == null)
  689                   return q.getContext().deleteInMemory(q, this, params);
  690               return num;
  691           }
  692   
  693           public Number executeUpdate(StoreQuery q, Object[] params) {
  694               Number num = ((ExpressionStoreQuery) q).executeUpdate(this, _meta,
  695                   _metas, _subs, _facts, _exps, params);
  696               if (num == null)
  697                   return q.getContext().updateInMemory(q, this, params);
  698               return num;
  699           }
  700   
  701           public String[] getDataStoreActions(StoreQuery q, Object[] params,
  702               Range range) {
  703               return ((ExpressionStoreQuery) q).getDataStoreActions(_meta,
  704                   _metas, _subs, _facts, _exps, params, range);
  705           }
  706   
  707           public Object getOrderingValue(StoreQuery q, Object[] params,
  708               Object resultObject, int orderIndex) {
  709               // if this is a projection, then we have to order on something
  710               // we selected
  711               if (_exps[0].projections.length > 0) {
  712                   String ordering = _exps[0].orderingClauses[orderIndex];
  713                   for (int i = 0; i < _exps[0].projectionClauses.length; i++)
  714                       if (ordering.equals(_exps[0].projectionClauses[i]))
  715                           return ((Object[]) resultObject)[i];
  716   
  717                   throw new InvalidStateException(_loc.get
  718                       ("merged-order-with-result", q.getContext().getLanguage(),
  719                           q.getContext().getQueryString(), ordering));
  720               }
  721   
  722               // need to parse orderings?
  723               synchronized (this) {
  724                   if (_inMemOrdering == null) {
  725                       ExpressionFactory factory = new InMemoryExpressionFactory();
  726                       _inMemOrdering = _parser.eval(_exps[0].orderingClauses,
  727                           (ExpressionStoreQuery) q, factory, _meta);
  728                   }
  729                   if (_inMemOrdering == null)
  730                       _inMemOrdering = _exps[0].ordering;
  731               }
  732   
  733               // use the parsed ordering expression to extract the ordering value
  734               Val val = (Val) _inMemOrdering[orderIndex];
  735               return val.evaluate(resultObject, resultObject,
  736                   q.getContext().getStoreContext(), params);
  737           }
  738   
  739           public Class[] getProjectionTypes(StoreQuery q) {
  740               return _projTypes;
  741   		}
  742   	}
  743   }

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