Package org.xorm.query

Source Code of org.xorm.query.CodeQuery

/*
    $Header: /cvsroot/xorm/xorm/src/org/xorm/query/CodeQuery.java,v 1.8 2004/03/23 23:37:49 seifertd Exp $

    This file is part of XORM.

    XORM is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    XORM is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with XORM; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package org.xorm.query;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;

import javax.jdo.Extent;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;

/**
* Implementation of JDO query interface that
* executes Java code that follows a particular pattern.
*/
public class CodeQuery implements Query {
    public static final String LANGUAGE = "org.xorm.query.CodeQuery";

    private Class queryClass;
    private PersistenceManager mgr;
    private Field[] variables;
    private Object candidates;

    public static Query parseCodeQuery(PersistenceManager mgr, Class clazz) {
  Query q = null;
  CodeParser cp = null;
  try {
      cp = new CodeParser(clazz);
      q = mgr.newQuery(clazz, cp.getFilter());
      String variables = cp.getVariables();
      if (variables != null) {
    q.declareVariables(variables);
      }
      String parameters = cp.getParameters();
      if (parameters != null) {
    q.declareParameters(parameters);
      }
  } catch (Throwable e) {
      // Code could not be turned into JDOQL.
      q = new CodeQuery(mgr, clazz);
  }
  return q;
    }

    public CodeQuery(PersistenceManager mgr, Class queryClass) {
  this.mgr = mgr;
  this.queryClass = queryClass;

  // Introspect to find variables
  variables = queryClass.getDeclaredFields();
    }

    // Query interface methods
    public PersistenceManager getPersistenceManager() {
  return mgr;
    }
    public void setClass(Class clazz) {
  this.queryClass = clazz;
    }
    public void setCandidates(Extent extent) {
  this.candidates = extent;
    }
    public void setCandidates(Collection collection) {
  this.candidates = collection;
    }
    private Iterator getCandidates() {
  if (candidates == null) {
      // do it by class
      return mgr.getExtent(queryClass, false).iterator();
  } else if (candidates instanceof Collection) {
      return ((Collection) candidates).iterator();
  }
  else return ((Extent) candidates).iterator();
    }

    public void setFilter(String filter) { }
    public void declareImports(String imports) { }
    public void declareParameters(String parameters) { }
    public void declareVariables(String variables) { }
    public void setOrdering(String ordering) { }
    public void setIgnoreCache(boolean ignoreCache) { }
    public boolean getIgnoreCache() { return false; }
    public void compile() { }
    public void close(Object results) { }
    public void closeAll() { }

    public Object execute() {
  return executeWithArray(new Object[0]);
    }

    public Object execute(Object param) {
  return executeWithArray(new Object[] { param });
    }

    public Object execute(Object param0, Object param1) {
  return executeWithArray(new Object[] { param0, param1 });
    }

    public Object execute(Object param0, Object param1, Object param2) {
  return executeWithArray(new Object[] { param0, param1, param2 });
    }

    public Object executeWithMap(Map map) {
  // TODO
  throw new UnsupportedOperationException();
    }

    public Object executeWithArray(Object[] params) {
  // Ensure that there is an open transaction
  boolean internalTransaction = !mgr.currentTransaction().isActive();
  if (internalTransaction) mgr.currentTransaction().begin();

  // Determine parameter types
  Class[] paramTypes = new Class [params.length];
  for (int i = 0; i < params.length; i++) {
      paramTypes[i] = params[i] == null ? null : params[i].getClass();
  }

  // Find correct evaluate method using introspection... can't use getDeclaredMethod, it
    // is too restrictive if any of the parameter types are interfaces or base classes and the
    // actual parameter value is a class that implements or extends it.  So we must resort to walking
    // a list of declared methods and checking if the parameter types are compatible using isAssignableFrom
    Method[] allMethods = queryClass.getDeclaredMethods()// TODO: Use getMethods if super classes should be checked
  Method evaluate = null;
    for (int i = 0; i < allMethods.length; ++i) {
        Method toCheck = allMethods[i];

        // Not interested unless it is an evaluate(...) method ...
        if (!"evaluate".equals(toCheck.getName())) {
            continue;
        }

        // Check number of params in the method
        Class[] evalParams = toCheck.getParameterTypes();
        if (evalParams.length != paramTypes.length) {
            // method has different number of parameters, it can't match
            continue;
        }

        // check the parameter types against the method params and see if the method
        // is compatible.  THis loop will take the first method that matches, so
        // the possibility remains that a "better" match exists ... how does the JVM
        // resolve such issues, would be nice to implement an algorithm here that
        // does a similar thing as the JVM when it resolves a "virtual" (to borrow
        // C++ parlance) method call.
        boolean isCompatible = true;
        for (int j = 0; j < evalParams.length; ++j) {
            if (!evalParams[j].isAssignableFrom(paramTypes[j])) {
                isCompatible = false;
                break;
            }
        }
        if (isCompatible) {
            evaluate = toCheck;
            break;
        }
    }

    /* DAS: The below won't work if the paramTypes include subclasses or implementations
  Method evaluate = null;
  try {
      evaluate = queryClass.getDeclaredMethod("evaluate", paramTypes);
  } catch (NoSuchMethodException e) {
      e.printStackTrace();
  } catch (SecurityException e) {
      e.printStackTrace();
  }
    */

  Collection results;
  if (Comparable.class.isAssignableFrom(queryClass)) {
      results = new TreeSet();
  } else {
      results = new ArrayList();
  }

    if (evaluate != null) {
        // Put in a mapping such for queryClass
        Iterator candidates = getCandidates();
        // How many variables?
        Object[] current = new Object[variables.length];
        List allVars = new ArrayList();
        for (int i = 0; i < variables.length; i++) {
            // Get all instances of variable type and add Collection to list.
            allVars.add(mgr.newQuery(variables[i].getType()).execute());
        }

        // Now test all permutations of variables with each candidate
        while (candidates.hasNext()) {
            Object candidate = candidates.next();

            // Now execute for each permutation...
            if (recurse(current, 0, allVars.iterator(), candidate, evaluate, params)) {
            results.add(candidate);
            }
        } // for each candidate
    }
    if (internalTransaction) mgr.currentTransaction().commit();
  return Collections.unmodifiableCollection(results);
    } // executeImpl

    /** Returns true if candidate passes. */
    private boolean recurse(Object[] current, int index, Iterator it, Object candidate, Method evaluate, Object[] params) {
  if (!it.hasNext()) {
      // All variables are set
      return execute2(current, candidate, evaluate, params);
  }
  Collection cc = (Collection) it.next();
  Iterator ccIt = cc.iterator();
  while (ccIt.hasNext()) {
      current[index] = ccIt.next();
      if (recurse(current, index + 1, it, candidate, evaluate, params)) {
    // Break out if candidate passed
    return true;
      }
  }
  return false;
    }

    /** Returns true if candidate passes. */
    private boolean execute2(Object[] variables, Object candidate, Method evaluate, Object[] params) {
  for (int i = 0; i < variables.length; i++) {
      Field field = this.variables[i];
      try {
    field.set(candidate, variables[i]);
      } catch (IllegalAccessException e) {
    e.printStackTrace();
      }
  }

  // Now try to evaluate
  try {
      return (((Boolean) evaluate.invoke(candidate, params)).booleanValue());
  } catch (InvocationTargetException e) {
      e.printStackTrace(); // FOR NOW
      // assume false, e.g. on NullPointerException
  } catch (IllegalAccessException e) {
      e.printStackTrace();
  }
  return false;
    } // boolean execute2()

    public String toString() { return queryClass.toString(); }
} // class CodeQuery
TOP

Related Classes of org.xorm.query.CodeQuery

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.