Home » apache-openjpa-1.1.0-source » org.apache.openjpa » persistence » [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.persistence;
   20   
   21   import java.io.Serializable;
   22   import java.lang.reflect.Method;
   23   import java.util.ArrayList;
   24   import java.util.Calendar;
   25   import java.util.Collection;
   26   import java.util.Collections;
   27   import java.util.Date;
   28   import java.util.HashMap;
   29   import java.util.Iterator;
   30   import java.util.List;
   31   import java.util.Map;
   32   import java.util.Set;
   33   import javax.persistence.FlushModeType;
   34   import javax.persistence.Query;
   35   import javax.persistence.TemporalType;
   36   
   37   import org.apache.commons.collections.map.LinkedMap;
   38   import org.apache.openjpa.enhance.Reflection;
   39   import org.apache.openjpa.kernel.DelegatingQuery;
   40   import org.apache.openjpa.kernel.DelegatingResultList;
   41   import org.apache.openjpa.kernel.Filters;
   42   import org.apache.openjpa.kernel.QueryOperations;
   43   import org.apache.openjpa.kernel.exps.AggregateListener;
   44   import org.apache.openjpa.kernel.exps.FilterListener;
   45   import org.apache.openjpa.lib.rop.ResultList;
   46   import org.apache.openjpa.lib.util.Localizer;
   47   import org.apache.openjpa.util.ImplHelper;
   48   import org.apache.openjpa.util.RuntimeExceptionTranslator;
   49   
   50   /**
   51    * Implementation of {@link Query} interface.
   52    *
   53    * @author Marc Prud'hommeaux
   54    * @author Abe White
   55    * @nojavadoc
   56    */
   57   public class QueryImpl
   58       implements OpenJPAQuerySPI, Serializable {
   59   
   60       private static final Object[] EMPTY_ARRAY = new Object[0];
   61   
   62       private static final Localizer _loc = Localizer.forPackage
   63           (QueryImpl.class);
   64   
   65       private final DelegatingQuery _query;
   66       private transient EntityManagerImpl _em;
   67       private transient FetchPlan _fetch;
   68   
   69       private Map _named;
   70       private List _positional;
   71   
   72       /**
   73        * Constructor; supply factory and delegate.
   74        */
   75       public QueryImpl(EntityManagerImpl em, RuntimeExceptionTranslator ret,
   76           org.apache.openjpa.kernel.Query query) {
   77           _em = em;
   78           _query = new DelegatingQuery(query, ret);
   79       }
   80   
   81       /**
   82        * Delegate.
   83        */
   84       public org.apache.openjpa.kernel.Query getDelegate() {
   85           return _query.getDelegate();
   86       }
   87   
   88       public OpenJPAEntityManager getEntityManager() {
   89           return _em;
   90       }
   91   
   92       public String getLanguage() {
   93           return _query.getLanguage();
   94       }
   95   
   96       public QueryOperationType getOperation() {
   97           return QueryOperationType.fromKernelConstant(_query.getOperation());
   98       }
   99   
  100       public FetchPlan getFetchPlan() {
  101           _em.assertNotCloseInvoked();
  102           _query.assertNotSerialized();
  103           _query.lock();
  104           try {
  105               if (_fetch == null)
  106                   _fetch = ((EntityManagerFactoryImpl) _em.
  107                       getEntityManagerFactory()).toFetchPlan(_query.getBroker(),
  108                       _query.getFetchConfiguration());
  109               return _fetch;
  110           } finally {
  111               _query.unlock();
  112           }
  113       }
  114   
  115       public String getQueryString() {
  116           return _query.getQueryString();
  117       }
  118   
  119       public boolean getIgnoreChanges() {
  120           return _query.getIgnoreChanges();
  121       }
  122   
  123       public OpenJPAQuery setIgnoreChanges(boolean ignore) {
  124           _em.assertNotCloseInvoked();
  125           _query.setIgnoreChanges(ignore);
  126           return this;
  127       }
  128   
  129       public OpenJPAQuery addFilterListener(FilterListener listener) {
  130           _em.assertNotCloseInvoked();
  131           _query.addFilterListener(listener);
  132           return this;
  133       }
  134   
  135       public OpenJPAQuery removeFilterListener(FilterListener listener) {
  136           _em.assertNotCloseInvoked();
  137           _query.removeFilterListener(listener);
  138           return this;
  139       }
  140   
  141       public OpenJPAQuery addAggregateListener(AggregateListener listener) {
  142           _em.assertNotCloseInvoked();
  143           _query.addAggregateListener(listener);
  144           return this;
  145       }
  146   
  147       public OpenJPAQuery removeAggregateListener(AggregateListener listener) {
  148           _em.assertNotCloseInvoked();
  149           _query.removeAggregateListener(listener);
  150           return this;
  151       }
  152   
  153       public Collection getCandidateCollection() {
  154           return _query.getCandidateCollection();
  155       }
  156   
  157       public OpenJPAQuery setCandidateCollection(Collection coll) {
  158           _em.assertNotCloseInvoked();
  159           _query.setCandidateCollection(coll);
  160           return this;
  161       }
  162   
  163       public Class getResultClass() {
  164           Class res = _query.getResultType();
  165           if (res != null)
  166               return res;
  167           return _query.getCandidateType();
  168       }
  169   
  170       public OpenJPAQuery setResultClass(Class cls) {
  171           _em.assertNotCloseInvoked();
  172           if (ImplHelper.isManagedType(_em.getConfiguration(), cls))
  173               _query.setCandidateType(cls, true);
  174           else
  175               _query.setResultType(cls);
  176           return this;
  177       }
  178   
  179       public boolean hasSubclasses() {
  180           return _query.hasSubclasses();
  181       }
  182   
  183       public OpenJPAQuery setSubclasses(boolean subs) {
  184           _em.assertNotCloseInvoked();
  185           Class cls = _query.getCandidateType();
  186           _query.setCandidateExtent(_query.getBroker().newExtent(cls, subs));
  187           return this;
  188       }
  189   
  190       public int getFirstResult() {
  191           return asInt(_query.getStartRange());
  192       }
  193   
  194       public OpenJPAQuery setFirstResult(int startPosition) {
  195           _em.assertNotCloseInvoked();
  196           long end;
  197           if (_query.getEndRange() == Long.MAX_VALUE)
  198               end = Long.MAX_VALUE;
  199           else
  200               end = startPosition +
  201                   (_query.getEndRange() - _query.getStartRange());
  202           _query.setRange(startPosition, end);
  203           return this;
  204       }
  205   
  206       public int getMaxResults() {
  207           return asInt(_query.getEndRange() - _query.getStartRange());
  208       }
  209   
  210       public OpenJPAQuery setMaxResults(int max) {
  211           _em.assertNotCloseInvoked();
  212           long start = _query.getStartRange();
  213           if (max == Integer.MAX_VALUE)
  214               _query.setRange(start, Long.MAX_VALUE);
  215           else
  216               _query.setRange(start, start + max);
  217           return this;
  218       }
  219   
  220       public OpenJPAQuery compile() {
  221           _em.assertNotCloseInvoked();
  222           _query.compile();
  223           return this;
  224       }
  225   
  226       private Object execute() {
  227           if (_query.getOperation() != QueryOperations.OP_SELECT)
  228               throw new InvalidStateException(_loc.get("not-select-query",
  229                   _query.getQueryString()), null, null, false);
  230   
  231           validateParameters();
  232   
  233           // handle which types of parameters we are using, if any
  234           if (_positional != null)
  235               return _query.execute(_positional.toArray());
  236           if (_named != null)
  237               return _query.execute(_named);
  238           return _query.execute();
  239       }
  240   
  241       /**
  242        * Validate that the types of the parameters are correct.
  243        */
  244       private void validateParameters() {
  245           if (_positional != null) {
  246               LinkedMap types = _query.getParameterTypes();
  247               for (int i = 0,
  248                   size = Math.min(_positional.size(), types.size());
  249                   i < size; i++)
  250                   validateParameter(String.valueOf(i),
  251                       (Class) types.getValue(i), _positional.get(i));
  252           } else if (_named != null) {
  253               Map types = _query.getParameterTypes();
  254               for (Iterator i = _named.entrySet().iterator(); i.hasNext();) {
  255                   Map.Entry entry = (Map.Entry) i.next();
  256                   String name = (String) entry.getKey();
  257                   validateParameter(name, (Class) types.get(name),
  258                       entry.getValue());
  259               }
  260           }
  261       }
  262   
  263       private void validateParameter(String paramDesc, Class type, Object param) {
  264           // null parameters are allowed, so are not validated
  265           if (param == null || type == null)
  266               return;
  267   
  268           // check the parameter against the wrapped type
  269           if (!Filters.wrap(type).isInstance(param))
  270               throw new ArgumentException(_loc.get("bad-param-type",
  271                   paramDesc, param.getClass().getName(), type.getName()),
  272                   null, null, false);
  273       }
  274   
  275       public List getResultList() {
  276           _em.assertNotCloseInvoked();
  277           Object ob = execute();
  278           if (ob instanceof List) {
  279               List ret = (List) ob;
  280               if (ret instanceof ResultList)
  281                   return new DelegatingResultList((ResultList) ret,
  282                       PersistenceExceptions.getRollbackTranslator(_em));
  283               else
  284                   return ret;
  285           }
  286   
  287           return Collections.singletonList(ob);
  288       }
  289   
  290       /**
  291        * Execute a query that returns a single result.
  292        */
  293       public Object getSingleResult() {
  294           _em.assertNotCloseInvoked();
  295           // temporarily set query to unique so that a single result is validated
  296           // and returned; unset again in case the user executes query again
  297           // via getResultList
  298           _query.setUnique(true);
  299           try {
  300               return execute();
  301           } finally {
  302               _query.setUnique(false);
  303           }
  304       }
  305   
  306       public int executeUpdate() {
  307           _em.assertNotCloseInvoked();
  308           if (_query.getOperation() == QueryOperations.OP_DELETE) {
  309               // handle which types of parameters we are using, if any
  310               if (_positional != null)
  311                   return asInt(_query.deleteAll(_positional.toArray()));
  312               if (_named != null)
  313                   return asInt(_query.deleteAll(_named));
  314               return asInt(_query.deleteAll());
  315           }
  316           if (_query.getOperation() == QueryOperations.OP_UPDATE) {
  317               // handle which types of parameters we are using, if any
  318               if (_positional != null)
  319                   return asInt(_query.updateAll(_positional.toArray()));
  320               if (_named != null)
  321                   return asInt(_query.updateAll(_named));
  322               return asInt(_query.updateAll());
  323           }
  324           throw new InvalidStateException(_loc.get("not-update-delete-query",
  325               _query.getQueryString()), null, null, false);
  326       }
  327   
  328       /**
  329        * Cast the specified long down to an int, first checking for overflow.
  330        */
  331       private static int asInt(long l) {
  332           if (l > Integer.MAX_VALUE)
  333               return Integer.MAX_VALUE;
  334           if (l < Integer.MIN_VALUE) // unlikely, but we might as well check
  335               return Integer.MIN_VALUE;
  336           return (int) l;
  337       }
  338   
  339       public FlushModeType getFlushMode() {
  340           return EntityManagerImpl.fromFlushBeforeQueries(_query.
  341               getFetchConfiguration().getFlushBeforeQueries());
  342       }
  343   
  344       public OpenJPAQuery setFlushMode(FlushModeType flushMode) {
  345           _em.assertNotCloseInvoked();
  346           _query.getFetchConfiguration().setFlushBeforeQueries
  347               (EntityManagerImpl.toFlushBeforeQueries(flushMode));
  348           return this;
  349       }
  350   
  351       public OpenJPAQuery setHint(String key, Object value) {
  352           _em.assertNotCloseInvoked();
  353           if (key == null || !key.startsWith("openjpa."))
  354               return this;
  355           String k = key.substring("openjpa.".length());
  356   
  357           try {
  358               if ("Subclasses".equals(k)) {
  359                   if (value instanceof String)
  360                       value = Boolean.valueOf((String) value);
  361                   setSubclasses(((Boolean) value).booleanValue());
  362               } else if ("FilterListener".equals(k))
  363                   addFilterListener(Filters.hintToFilterListener(value,
  364                       _query.getBroker().getClassLoader()));
  365               else if ("FilterListeners".equals(k)) {
  366                   FilterListener[] arr = Filters.hintToFilterListeners(value,
  367                       _query.getBroker().getClassLoader());
  368                   for (int i = 0; i < arr.length; i++)
  369                       addFilterListener(arr[i]);
  370               } else if ("AggregateListener".equals(k))
  371                   addAggregateListener(Filters.hintToAggregateListener(value,
  372                       _query.getBroker().getClassLoader()));
  373               else if ("FilterListeners".equals(k)) {
  374                   AggregateListener[] arr = Filters.hintToAggregateListeners
  375                       (value, _query.getBroker().getClassLoader());
  376                   for (int i = 0; i < arr.length; i++)
  377                       addAggregateListener(arr[i]);
  378               } else if (k.startsWith("FetchPlan.")) {
  379                   k = k.substring("FetchPlan.".length());
  380                   hintToSetter(getFetchPlan(), k, value);
  381               } else if (k.startsWith("hint.")) {
  382                   if ("hint.OptimizeResultCount".equals(k)) {
  383                       if (value instanceof String) {
  384                           try {
  385                               value = new Integer((String) value);
  386                           } catch (NumberFormatException nfe) {
  387                           }
  388                       }
  389                       if (!(value instanceof Number) 
  390                           || ((Number) value).intValue() < 0)
  391                           throw new ArgumentException(_loc.get
  392                               ("bad-query-hint-value", key, value), null, null, 
  393                               false);
  394                   }
  395                   _query.getFetchConfiguration().setHint(key, value);
  396               }
  397               else
  398                   throw new ArgumentException(_loc.get("bad-query-hint", key),
  399                       null, null, false);
  400               return this;
  401           } catch (Exception e) {
  402               throw PersistenceExceptions.toPersistenceException(e);
  403           }
  404       }
  405   
  406       private void hintToSetter(FetchPlan fetchPlan, String k, Object value) {
  407           if (fetchPlan == null || k == null)
  408               return;
  409   
  410           Method setter = Reflection.findSetter(fetchPlan.getClass(), k, true);
  411           Class paramType = setter.getParameterTypes()[0];
  412           if (Enum.class.isAssignableFrom(paramType) && value instanceof String)
  413               value = Enum.valueOf(paramType, (String) value);
  414           
  415           Filters.hintToSetter(fetchPlan, k, value);
  416       }
  417   
  418       public OpenJPAQuery setParameter(int position, Calendar value,
  419           TemporalType t) {
  420           return setParameter(position, value);
  421       }
  422   
  423       public OpenJPAQuery setParameter(int position, Date value,
  424           TemporalType type) {
  425           return setParameter(position, value);
  426       }
  427   
  428       public OpenJPAQuery setParameter(int position, Object value) {
  429           _query.assertOpen();
  430           _em.assertNotCloseInvoked();
  431           _query.lock();
  432           try {
  433               // not allowed to mix positional and named parameters (EDR2 3.6.4)
  434               if (_named != null)
  435                   throw new InvalidStateException(_loc.get
  436                       ("no-pos-named-params-mix", _query.getQueryString()),
  437                       null, null, false);
  438   
  439               if (position < 1)
  440                   throw new InvalidStateException(_loc.get
  441                       ("illegal-index", position), null, null, false);
  442   
  443               if (_positional == null)
  444                   _positional = new ArrayList();
  445   
  446               // make sure it is at least the requested size
  447               while (_positional.size() < position)
  448                   _positional.add(null);
  449   
  450               // note that we add it to position - 1, since setPosition
  451               // starts at 1, while List starts at 0
  452               _positional.set(position - 1, value);
  453               return this;
  454           } finally {
  455               _query.unlock();
  456           }
  457       }
  458   
  459       public OpenJPAQuery setParameter(String name, Calendar value,
  460           TemporalType t) {
  461           return setParameter(name, value);
  462       }
  463   
  464       public OpenJPAQuery setParameter(String name, Date value,
  465           TemporalType type) {
  466           return setParameter(name, value);
  467       }
  468   
  469       public OpenJPAQuery setParameter(String name, Object value) {
  470           _query.assertOpen();
  471           _em.assertNotCloseInvoked();
  472           _query.lock();
  473           try {
  474               // not allowed to mix positional and named parameters (EDR2 3.6.4)
  475               if (_positional != null)
  476                   throw new InvalidStateException(_loc.get
  477                       ("no-pos-named-params-mix", _query.getQueryString()),
  478                       null, null, false);
  479   
  480               if (_named == null)
  481                   _named = new HashMap();
  482               _named.put(name, value);
  483               return this;
  484           } finally {
  485               _query.unlock();
  486           }
  487       }
  488   
  489       public boolean hasPositionalParameters() {
  490           return _positional != null;
  491       }
  492   
  493       public Object[] getPositionalParameters() {
  494           _query.lock();
  495           try {
  496               return (_positional == null) ? EMPTY_ARRAY : _positional.toArray();
  497           } finally {
  498               _query.unlock();
  499           }
  500       }
  501   
  502       public OpenJPAQuery setParameters(Object... params) {
  503           _query.assertOpen();
  504           _em.assertNotCloseInvoked();
  505           _query.lock();
  506           try {
  507               _positional = null;
  508               _named = null;
  509               if (params != null)
  510                   for (int i = 0; i < params.length; i++)
  511                       setParameter(i + 1, params[i]);
  512               return this;
  513           } finally {
  514               _query.unlock();
  515           }
  516       }
  517   
  518       public Map getNamedParameters() {
  519           _query.lock();
  520           try {
  521               return (_named == null) ? Collections.EMPTY_MAP
  522                   : Collections.unmodifiableMap(_named);
  523           } finally {
  524               _query.unlock();
  525           }
  526       }
  527   
  528       public OpenJPAQuery setParameters(Map params) {
  529           _query.assertOpen();
  530           _em.assertNotCloseInvoked();
  531           _query.lock();
  532           try {
  533               _positional = null;
  534               _named = null;
  535               if (params != null)
  536                   for (Map.Entry e : (Set<Map.Entry>) params.entrySet())
  537                       setParameter((String) e.getKey(), e.getValue());
  538               return this;
  539           } finally {
  540               _query.unlock();
  541           }
  542       }
  543   
  544       public OpenJPAQuery closeAll() {
  545           _query.closeAll();
  546           return this;
  547       }
  548   
  549       public String[] getDataStoreActions(Map params) {
  550           return _query.getDataStoreActions(params);
  551       }
  552   
  553       public int hashCode() {
  554           return _query.hashCode();
  555       }
  556   
  557       public boolean equals(Object other) {
  558           if (other == this)
  559               return true;
  560           if (!(other instanceof QueryImpl))
  561               return false;
  562           return _query.equals(((QueryImpl) other)._query);
  563   	}
  564   }

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