Package org.apache.openjpa.persistence

Source Code of org.apache.openjpa.persistence.QueryImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied.  See the License for the
* specific language governing permissions and limitations
* under the License.   
*/
package org.apache.openjpa.persistence;

import static org.apache.openjpa.kernel.QueryLanguages.LANG_PREPARED_SQL;

import java.io.Serializable;
import java.sql.Time;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.locks.ReentrantLock;

import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Parameter;
import javax.persistence.Query;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.ParameterExpression;

import org.apache.openjpa.conf.Compatibility;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.kernel.Broker;
import org.apache.openjpa.kernel.DelegatingQuery;
import org.apache.openjpa.kernel.DelegatingResultList;
import org.apache.openjpa.kernel.DistinctResultList;
import org.apache.openjpa.kernel.FetchConfiguration;
import org.apache.openjpa.kernel.Filters;
import org.apache.openjpa.kernel.PreparedQuery;
import org.apache.openjpa.kernel.PreparedQueryCache;
import org.apache.openjpa.kernel.QueryHints;
import org.apache.openjpa.kernel.QueryLanguages;
import org.apache.openjpa.kernel.QueryOperations;
import org.apache.openjpa.kernel.QueryStatistics;
import org.apache.openjpa.kernel.exps.AggregateListener;
import org.apache.openjpa.kernel.exps.FilterListener;
import org.apache.openjpa.kernel.jpql.JPQLParser;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.rop.ResultList;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.OrderedMap;
import org.apache.openjpa.meta.QueryMetaData;
import org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.RuntimeExceptionTranslator;
import org.apache.openjpa.util.UserException;


/**
* Implementation of {@link Query} interface.
*
* @author Marc Prud'hommeaux
* @author Abe White
* @nojavadoc
*/
@SuppressWarnings("serial")
public class QueryImpl<X> extends AbstractQuery<X> implements Serializable {

    private static final Localizer _loc = Localizer.forPackage(QueryImpl.class);
  private transient FetchPlan _fetch;

  private String _id;
    private transient ReentrantLock _lock = null;
  private HintHandler _hintHandler;
    private DelegatingQuery _query;
  /**
   * Constructor; supply factory exception translator and delegate.
   *
   * @param em  The EntityManager which created this query
   * @param ret Exception translator for this query
   * @param query The underlying "kernel" query.
   */
    public QueryImpl(EntityManagerImpl em, RuntimeExceptionTranslator ret, org.apache.openjpa.kernel.Query query,
        QueryMetaData qmd) {
        super(qmd, em);
        _query = new DelegatingQuery(query, ret);
        _lock = new ReentrantLock();
        if(query.getLanguage() == QueryLanguages.LANG_SQL) {
            _convertPositionalParams = false;
        }
        else {
            Compatibility compat  = query.getStoreContext().getConfiguration().getCompatibilityInstance();
            _convertPositionalParams = compat.getConvertPositionalParametersToNamed();   
        }
       
    }

  /**
   * Constructor; supply factory and delegate.
   *
   * @deprecated
   */
    public QueryImpl(EntityManagerImpl em, RuntimeExceptionTranslator ret, org.apache.openjpa.kernel.Query query) {
        this(em, ret, query, null);
    }
 
    /**
     * Constructor; supply factory and delegate.
     *
     * @deprecated
     */
    public QueryImpl(EntityManagerImpl em, org.apache.openjpa.kernel.Query query) {
        this(em, null, query, null);
   

  /**
   * Delegate.
   */
  public org.apache.openjpa.kernel.Query getDelegate() {
    return _query.getDelegate();
  }

  public OpenJPAEntityManager getEntityManager() {
    return _em;
  }

  public String getLanguage() {
    return _query.getLanguage();
  }

  public QueryOperationType getOperation() {
        return QueryOperationType.fromKernelConstant(_query.getOperation());
  }

  public FetchPlan getFetchPlan() {
    _em.assertNotCloseInvoked();
    _query.assertNotSerialized();
    _query.lock();
    try {
      if (_fetch == null)
                _fetch = ((EntityManagerFactoryImpl) _em
                        .getEntityManagerFactory()).toFetchPlan(_query
                        .getBroker(), _query.getFetchConfiguration());
      return _fetch;
    } finally {
      _query.unlock();
    }
  }

  public String getQueryString() {
    String result = _query.getQueryString();
    return result != null ? result : _id;
  }

  public boolean getIgnoreChanges() {
    return _query.getIgnoreChanges();
  }

  public OpenJPAQuery<X> setIgnoreChanges(boolean ignore) {
    _em.assertNotCloseInvoked();
    _query.setIgnoreChanges(ignore);
    return this;
  }

  public OpenJPAQuery<X> addFilterListener(FilterListener listener) {
    _em.assertNotCloseInvoked();
    _query.addFilterListener(listener);
    return this;
  }

  public OpenJPAQuery<X> removeFilterListener(FilterListener listener) {
    _em.assertNotCloseInvoked();
    _query.removeFilterListener(listener);
    return this;
  }

  public OpenJPAQuery<X> addAggregateListener(AggregateListener listener) {
    _em.assertNotCloseInvoked();
    _query.addAggregateListener(listener);
    return this;
  }

    public OpenJPAQuery<X> removeAggregateListener(AggregateListener listener) {
    _em.assertNotCloseInvoked();
    _query.removeAggregateListener(listener);
    return this;
  }

  public Collection<?> getCandidateCollection() {
    return _query.getCandidateCollection();
  }

  public OpenJPAQuery<X> setCandidateCollection(Collection coll) {
    _em.assertNotCloseInvoked();
    _query.setCandidateCollection(coll);
    return this;
  }

  public Class getResultClass() {
    Class res = _query.getResultType();
    if (res != null)
      return res;
    return _query.getCandidateType();
  }

  public OpenJPAQuery<X> setResultClass(Class cls) {
    _em.assertNotCloseInvoked();
    if (ImplHelper.isManagedType(_em.getConfiguration(), cls))
      _query.setCandidateType(cls, true);
    else
      _query.setResultType(cls);
    return this;
  }

  public boolean hasSubclasses() {
    return _query.hasSubclasses();
  }

  public OpenJPAQuery<X> setSubclasses(boolean subs) {
    _em.assertNotCloseInvoked();
    Class<?> cls = _query.getCandidateType();
        _query.setCandidateExtent(_query.getBroker().newExtent(cls, subs));
    return this;
  }

  public int getFirstResult() {
    return asInt(_query.getStartRange());
  }

  public OpenJPAQuery<X> setFirstResult(int startPosition) {
    _em.assertNotCloseInvoked();
    long end;
    if (_query.getEndRange() == Long.MAX_VALUE)
      end = Long.MAX_VALUE;
    else
      end = startPosition
                    + (_query.getEndRange() - _query.getStartRange());
    _query.setRange(startPosition, end);
    return this;
  }

  public int getMaxResults() {
    return asInt(_query.getEndRange() - _query.getStartRange());
  }

  public OpenJPAQuery<X> setMaxResults(int max) {
    _em.assertNotCloseInvoked();
    long start = _query.getStartRange();
    if (max == Integer.MAX_VALUE)
      _query.setRange(start, Long.MAX_VALUE);
    else
      _query.setRange(start, start + max);
    return this;
  }
 
  public OpenJPAQuery<X> compile() {
    _em.assertNotCloseInvoked();
    _query.compile();
    return this;
  }
 
  private Object execute() {
        if (!isNative() && _query.getOperation() != QueryOperations.OP_SELECT)
            throw new InvalidStateException(_loc.get("not-select-query", getQueryString()), null, null, false);
    try {
        lock();
            Map params = getParameterValues();
            boolean registered = preExecute(params);
            Object result = _query.execute(params);
            if (registered) {
                postExecute(result);
            }
            return result;
    } catch (LockTimeoutException e) {
        throw new QueryTimeoutException(e.getMessage(), new Throwable[]{e}, this);
    } finally {
        unlock();
    }
  }
 
  public List getResultList() {
    _em.assertNotCloseInvoked();
    boolean queryFetchPlanUsed = pushQueryFetchPlan();
    try {
        Object ob = execute();
        if (ob instanceof List) {
          List ret = (List) ob;
          if (ret instanceof ResultList) {
              RuntimeExceptionTranslator trans = PersistenceExceptions.getRollbackTranslator(_em);
              if (_query.isDistinct()) {
                  return new DistinctResultList((ResultList) ret, trans);
              } else {
                  return new DelegatingResultList((ResultList) ret, trans);
              }
          } else {
            return ret;
          }
        }
        return Collections.singletonList(ob);
    } finally {
      popQueryFetchPlan(queryFetchPlanUsed);
    }
  }

  /**
   * Execute a query that returns a single result.
   */
  public X getSingleResult() {
    _em.assertNotCloseInvoked();
        setHint(QueryHints.HINT_RESULT_COUNT, 1); // for DB2 optimization
    boolean queryFetchPlanUsed = pushQueryFetchPlan();
    try {
        List result = getResultList();
        if (result == null || result.isEmpty())
                throw new NoResultException(_loc.get("no-result", getQueryString())
                        .getMessage());
        if (result.size() > 1)
                throw new NonUniqueResultException(_loc.get("non-unique-result",
                        getQueryString(), result.size()).getMessage());
        try {
            return (X)result.get(0);
        } catch (Exception e) {
                throw new NoResultException(_loc.get("no-result", getQueryString())
                    .getMessage());
        }
    } finally {
      popQueryFetchPlan(queryFetchPlanUsed);
    }
  }

  private boolean pushQueryFetchPlan() {
    boolean fcPushed = false;
    if (_fetch != null && _hintHandler != null) {
      switch (_fetch.getReadLockMode()) {
      case PESSIMISTIC_READ:
      case PESSIMISTIC_WRITE:
      case PESSIMISTIC_FORCE_INCREMENT:
        // push query fetch plan to em if pessisimistic lock and any
        // hints are set
        _em.pushFetchPlan(((FetchPlanImpl)_fetch).getDelegate());
        fcPushed = true;
      }
    }
    return fcPushed;
  }

  private void popQueryFetchPlan(boolean queryFetchPlanUsed) {
    if (queryFetchPlanUsed) {
      _em.popFetchPlan();
    }
  }

  public int executeUpdate() {
    _em.assertNotCloseInvoked();
        Map<?,?> paramValues = getParameterValues();
    if (_query.getOperation() == QueryOperations.OP_DELETE) {
       return asInt(paramValues.isEmpty() ? _query.deleteAll() : _query.deleteAll(paramValues));
    }
    if (_query.getOperation() == QueryOperations.OP_UPDATE) {
         return asInt(paramValues.isEmpty() ? _query.updateAll() : _query.updateAll(paramValues));
    }
        throw new InvalidStateException(_loc.get("not-update-delete-query", getQueryString()), null, null, false);
  }

  /**
   * Cast the specified long down to an int, first checking for overflow.
   */
  private static int asInt(long l) {
    if (l > Integer.MAX_VALUE)
      return Integer.MAX_VALUE;
        if (l < Integer.MIN_VALUE) // unlikely, but we might as well check
      return Integer.MIN_VALUE;
    return (int) l;
  }

  public FlushModeType getFlushMode() {
    return EntityManagerImpl.fromFlushBeforeQueries(_query
                .getFetchConfiguration().getFlushBeforeQueries());
  }

  public OpenJPAQuery<X> setFlushMode(FlushModeType flushMode) {
    _em.assertNotCloseInvoked();
    _query.getFetchConfiguration().setFlushBeforeQueries(
                EntityManagerImpl.toFlushBeforeQueries(flushMode));
    return this;
  }

  /**
   * Asserts that this query is a JPQL or Criteria Query.
   */
  void assertJPQLOrCriteriaQuery() {
        String language = getLanguage();
        if (JPQLParser.LANG_JPQL.equals(language)
         || QueryLanguages.LANG_PREPARED_SQL.equals(language)
         || CriteriaBuilderImpl.LANG_CRITERIA.equals(language)) {
            return;
        } else {
            throw new IllegalStateException(_loc.get("not-jpql-or-criteria-query").getMessage());
        }
  }

  public OpenJPAQuery<X> closeAll() {
    _query.closeAll();
    return this;
  }

  public String[] getDataStoreActions(Map params) {
    return _query.getDataStoreActions(params);
  }

    public LockModeType getLockMode() {
        assertJPQLOrCriteriaQuery();
        return getFetchPlan().getReadLockMode();
    }

    /**
     * Sets lock mode on the given query.
     * If the target query has been prepared and cached, then ignores the cached version.
     * @see #ignorePreparedQuery()
     */
    public TypedQuery<X> setLockMode(LockModeType lockMode) {
        String language = getLanguage();
        if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
            ignorePreparedQuery();
        }
        assertJPQLOrCriteriaQuery();
       getFetchPlan().setReadLockMode(lockMode);
       return this;
    }

  public int hashCode() {
        return (_query == null) ? 0 : _query.hashCode();
  }

  public boolean equals(Object other) {
    if (other == this)
      return true;
        if ((other == null) || (other.getClass() != this.getClass()))
            return false;
        if (_query == null)
            return false;
    return _query.equals(((QueryImpl) other)._query);
  }

  /**
   * Get all the active hints and their values.
   *
   */
    //TODO: JPA 2.0 Hints that are not set to FetchConfiguration
    public Map<String, Object> getHints() {
        if (_hintHandler == null)
            return Collections.emptyMap();
        return _hintHandler.getHints();
    }

    public OpenJPAQuery<X> setHint(String key, Object value) {
        _em.assertNotCloseInvoked();
        if (_hintHandler == null) {
            _hintHandler = new HintHandler(this);
        }
        _hintHandler.setHint(key, value);
        return this;
    }

    public Set<String> getSupportedHints() {
        if (_hintHandler == null) {
            _hintHandler = new HintHandler(this);
        }
        return _hintHandler.getSupportedHints();
    }

    /**
     * Unwraps this receiver to an instance of the given class, if possible.
     *
     * @exception if the given class is null, generic <code>Object.class</code> or a class
     * that is not wrapped by this receiver. 
     *
     * @since 2.0.0
     */
    public <T> T unwrap(Class<T> cls) {
        Object[] delegates = new Object[]{_query.getInnermostDelegate(), _query.getDelegate(), _query, this};
        for (Object o : delegates) {
            if (cls != null && cls != Object.class && cls.isInstance(o))
                return (T)o;
        }
        // Set this transaction to rollback only (as per spec) here because the raised exception
        // does not go through normal exception translation pathways
        RuntimeException ex = new PersistenceException(_loc.get("unwrap-query-invalid", cls).toString(), null,
                this, false);
        if (_em.isActive())
            _em.setRollbackOnly(ex);
        throw ex;
    }

   
    // =======================================================================
    // Prepared Query Cache related methods
    // =======================================================================
   
    /**
     * Invoked before a query is executed.
     * If this receiver is cached as a {@linkplain PreparedQuery prepared query}
     * then re-parameterizes the given user parameters. The given map is cleared
     * and re-parameterized values are filled in.
     *
     * @param params user supplied parameter key-values. Always supply a
     * non-null map even if the user has not specified any parameter, because
     * the same map will to be populated by re-parameterization.
     *
     * @return true if this invocation caused the query being registered in the
     * cache.
     */
    private boolean preExecute(Map params) {
        PreparedQueryCache cache = _em.getPreparedQueryCache();
        if (cache == null) {
            return false;
        }
        FetchConfiguration fetch = _query.getFetchConfiguration();
        if (fetch.getReadLockLevel() != 0) {
            if (cache.get(_id) != null) {
                ignorePreparedQuery();
            }
            return false;
        }
       
        // Determine if the query has NULL parameters.  If so, then do not use a PreparedQuery from the cache
        for (Object val : params.values()) {
            if (val == null) {
                ignorePreparedQuery();
                return false;
            }
        }
       
        Boolean registered = cache.register(_id, _query, fetch);
        boolean alreadyCached = (registered == null);
        String lang = _query.getLanguage();
        QueryStatistics<String> stats = cache.getStatistics();
        if (alreadyCached && LANG_PREPARED_SQL.equals(lang)) {
            PreparedQuery pq = _em.getPreparedQuery(_id);
            if (pq.isInitialized()) {
                try {
                    Map rep = pq.reparametrize(params, _em.getBroker());
                    params.clear();
                    params.putAll(rep);
                } catch (UserException ue) {
                    invalidatePreparedQuery();
                    Log log = _em.getConfiguration().getLog(OpenJPAConfiguration.LOG_RUNTIME);
                    if (log.isWarnEnabled())
                        log.warn(ue.getMessage());
                    return false;
                }
            }
            stats.recordExecution(pq.getOriginalQuery());
        } else {
            stats.recordExecution(getQueryString());
        }
        return registered == Boolean.TRUE;
    }
   
    /**
     * Initialize the registered Prepared Query from the given opaque object.
     *
     * @param result an opaque object representing execution result of a query
     *
     * @return true if the prepared query can be initialized.
     */
    private boolean postExecute(Object result) {
        PreparedQueryCache cache = _em.getPreparedQueryCache();
        if (cache == null) {
            return false;
        }
        return cache.initialize(_id, result) != null;
    }
   
    /**
     * Remove this query from PreparedQueryCache.
     */
    boolean invalidatePreparedQuery() {
        PreparedQueryCache cache = _em.getPreparedQueryCache();
        if (cache == null)
            return false;
        ignorePreparedQuery();
        return cache.invalidate(_id);
    }
   
    /**
     * Ignores this query from PreparedQueryCache by recreating the original
     * query if it has been cached.
     */
    void ignorePreparedQuery() {
        PreparedQuery cached = _em.getPreparedQuery(_id);
        if (cached == null)
            return;
        Broker broker = _em.getBroker();
        // Critical assumption: Only JPQL queries are cached and more
        // importantly, the identifier of the prepared query is the original
        // JPQL String
        String JPQL = JPQLParser.LANG_JPQL;
        String jpql = _id;
       
        org.apache.openjpa.kernel.Query newQuery = broker.newQuery(JPQL, jpql);
        newQuery.getFetchConfiguration().copy(_query.getFetchConfiguration());
        newQuery.compile();
        _query = new DelegatingQuery(newQuery, _em.getExceptionTranslator());
    }
   
    // package protected
    QueryImpl setId(String id) {
        _id = id;
        return this;
    }
    // ================ End of Prepared Query related methods =====================
   
    protected void lock() {
        if (_lock != null)
            _lock.lock();
    }

    protected void unlock() {
        if (_lock != null)
            _lock.unlock();
    }

    @Override
    protected void assertOpen() {
        _query.assertOpen();
    }

    @Override
    public OrderedMap<Object, Class<?>> getParamTypes() {
        return _query.getOrderedParameterTypes();
    }

    public String toString() {
        String result = _query.getQueryString();
        return result != null ? result : _id;
    }
}
TOP

Related Classes of org.apache.openjpa.persistence.QueryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.