All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.persistence.queries.MethodBaseQueryRedirector Maven / Gradle / Ivy

There is a newer version: 4.0.2
Show newest version
/*
 * Copyright (c) 1998, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.queries;

import java.lang.reflect.*;
import java.security.AccessController;

import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.sessions.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.internal.security.PrivilegedMethodInvoker;
import org.eclipse.persistence.internal.sessions.AbstractRecord;

/**
 * 

Purpose: * Allows a class to be a QueryRedirector without implementing * {@link QueryRedirector QueryRedirector}. * *

Description: * Normally to define a Redirector a Class must implement QueryRedirector and * the required {@link QueryRedirector#invokeQuery QueryRedirector.invokeQuery(DatabaseQuery, Record, Session)}. *

* To maintain transparency it is possible to instead only define a static * method that takes the same arguments as invokeQuery. *

* An instance of MethodBaseQueryRedirector can be constructed, taking the name of that static * method and the Class in which it is defined as parameters. *

* Whenever invokeQuery is called on this instance reflection will * automatically be used to invoke the custom method instead. *

* Advantages: *

    *
  • The Redirector class and method name can be specified dynamically. *
  • The class containing the invokeQuery method does not need to implement * QueryRedirector. *
  • The invokeQuery method can have any name. *
  • The invokeQuery method can alternatively be defined to accept only * Session session and Vector arguments as parameters. *
* Disadvantages: *
    *
  • An extra step is added as the real invokeQuery method is called * dynamically. *
*

Example: *

 * // First create a named query, define a redirector for it, and add the query
 * // to the query manager.
 * ReadObjectQuery query = new ReadObjectQuery(Employee.class);
 * query.setName("findEmployeeByAnEmployee");
 * query.addArgument("employee");
 *
 * MethodBaseQueryRedirector redirector = new
 * MethodBaseQueryRedirector(QueryRedirectorTest.class, "findEmployeeByAnEmployee");
 * query.setRedirector(redirector);
 * ClassDescriptor descriptor = getSession().getDescriptor(query.getReferenceClass());
 * descriptor.getQueryManager().addQuery(query.getName(), query);
 *
 * // Now execute the query by name, passing in an Employee as an argument.
 * Vector arguments = new Vector();
 * arguments.addElement(employee);
 * objectFromDatabase =
 * getSession().executeQuery("findEmployeeByAnEmployee", Employee.class, arguments);
 *
 * // Note this Class does not implement QueryRedirector or method invokeQuery.
 * public class QueryRedirectorTest {
 * public static Object findEmployeeByAnEmployee(DatabaseQuery query, Record arguments, Session session) {
 * ((ReadObjectQuery) query).setSelectionObject(arguments.get("employee"));
 * return session.executeQuery(query);
 * }
 * }

* * @see QueryRedirector * @author James Sutherland * @since TOPLink/Java 3.0 */ public class MethodBaseQueryRedirector implements QueryRedirector { protected Class methodClass; protected String methodClassName; protected String methodName; protected transient Method method; /** * PUBLIC: * Returns a new query redirector. */ public MethodBaseQueryRedirector() { } /** * PUBLIC: * Returns a new query redirector based on the static method in methodClass. */ public MethodBaseQueryRedirector(Class methodClass, String methodName) { this.methodClass = methodClass; this.methodName = methodName; } /** * INTERNAL: * Returns the static method. */ protected Method getMethod() { return method; } /** * PUBLIC: * Returns the class to execute the static method on. */ public Class getMethodClass() { return methodClass; } /** * INTERNAL: * Returns the class to execute the static method on. */ public String getMethodClassName() { if ((methodClassName == null) && (methodClass != null)) { methodClassName = methodClass.getName(); } return methodClassName; } /** * PUBLIC: * Returns the name of the static method. * This method must be public, static and have argument of DatabaseQuery, Vector, Session. * @see #setMethodName */ public String getMethodName() { return methodName; } /** * INTERNAL: * Set the method. */ protected void initializeMethod(DatabaseQuery query) throws QueryException { if ((getMethodName() == null) || (getMethodClass() == null)) { throw QueryException.redirectionClassOrMethodNotSet(query); } // Must check 3 possible argument sets for backward compatibility. // The DatabaseQuery, Record, Session should be used, check last the throw correct exception. // Check Session, Vector. Class[] arguments = new Class[2]; arguments[0] = ClassConstants.SessionsSession_Class; arguments[1] = ClassConstants.Vector_class; try { setMethod(Helper.getDeclaredMethod(getMethodClass(), getMethodName(), arguments)); } catch (Exception ignore) { // Check DatabaseQuery, Record, Session. arguments = new Class[3]; arguments[0] = ClassConstants.DatabaseQuery_Class; arguments[1] = ClassConstants.Record_Class; arguments[2] = ClassConstants.SessionsSession_Class; try { setMethod(Helper.getDeclaredMethod(getMethodClass(), getMethodName(), arguments)); } catch (Exception ignoreAgain) { // Check DatabaseQuery, Record, Session. arguments = new Class[3]; arguments[0] = ClassConstants.DatabaseQuery_Class; arguments[1] = ClassConstants.Record_Class; arguments[2] = ClassConstants.SessionsSession_Class; try { setMethod(Helper.getDeclaredMethod(getMethodClass(), getMethodName(), arguments)); } catch (Exception exception) { throw QueryException.redirectionMethodNotDefinedCorrectly(getMethodClass(), getMethodName(), exception, query); } } } // Ensure the method is static. if (!Modifier.isStatic(getMethod().getModifiers())) { throw QueryException.redirectionMethodNotDefinedCorrectly(getMethodClass(), getMethodName(), null, query); } } /** * INTERNAL: * Call the static method to execute the query. */ public Object invokeQuery(DatabaseQuery query, org.eclipse.persistence.sessions.Record arguments, Session session) { if (getMethod() == null) { initializeMethod(query); } // To different methods type are supported for backward compatibility. // Check method types to call with correct arguments. Object result = null; if (getMethod().getParameterTypes().length == 3) { Object[] argumentArray = new Object[3]; argumentArray[0] = query; argumentArray[1] = arguments; argumentArray[2] = session; try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ result = AccessController.doPrivileged(new PrivilegedMethodInvoker(getMethod(), null, argumentArray)); }else{ result = PrivilegedAccessHelper.invokeMethod(getMethod(), null, argumentArray); } } catch (Exception exception) { throw QueryException.redirectionMethodError(exception, query); } } else { Object[] argumentArray = new Object[2]; argumentArray[0] = session; argumentArray[1] = ((AbstractRecord)arguments).getValues(); try { if (PrivilegedAccessHelper.shouldUsePrivilegedAccess()){ result = AccessController.doPrivileged(new PrivilegedMethodInvoker(getMethod(), null, argumentArray)); }else{ result = PrivilegedAccessHelper.invokeMethod(getMethod(), null, argumentArray); } } catch (Exception exception) { throw QueryException.redirectionMethodError(exception, query); } } return result; } /** * INTERNAL: * Sets the static method. */ protected void setMethod(Method newMethod) { method = newMethod; } /** * PUBLIC: * Sets the class to execute the static method on. */ public void setMethodClass(Class newMethodClass) { methodClass = newMethodClass; } /** * INTERNAL: * Sets the class to execute the static method on. */ public void setMethodClassName(String newMethodClassName) { methodClassName = newMethodClassName; } /** * PUBLIC: * Sets the name of the static method.

* This method must be public, static and have arguments of DatabaseQuery, Record, and Session. *

* The DatabaseQuery argument is the query that is currently being executed. *

* The Record will contain the Argument names added to the Query through addArgument(Sting) or, in the case * of an Object query, the object attribute field names. These names will * reference the argument values passed into the query, or in the case of an * Object Query the values from the object. *

* The session argument is the session that the query is currently being executed on. *

* Alternatively the method can take only (Session session, Vector arguments) * as parameters. */ public void setMethodName(String newMethodName) { methodName = newMethodName; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy