/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.ejb.plugins.cmp.jdbc.metadata;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Collection;
import org.w3c.dom.Element;
import org.jboss.deployment.DeploymentException;
import org.jboss.metadata.MetaData;
import org.jboss.metadata.QueryMetaData;
import org.jboss.util.Classes;
import org.jboss.ejb.plugins.cmp.jdbc.JDBCQueryManager;
import org.jboss.logging.Logger;
/**
* JDBCQueryMetaDataFactory constructs a JDBCQueryMetaData object based
* on the query specifiection type.
*
* @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
* @version $Revision: 81030 $
*/
public class JDBCQueryMetaDataFactory
{
private static final Logger log = Logger.getLogger(JDBCQueryMetaDataFactory.class);
private JDBCEntityMetaData entity;
public JDBCQueryMetaDataFactory(JDBCEntityMetaData entity)
{
this.entity = entity;
}
public Map createJDBCQueryMetaData(QueryMetaData queryData)
throws DeploymentException
{
Method[] methods = getQueryMethods(queryData);
Map queries = new HashMap(methods.length);
for(int i = 0; i < methods.length; i++)
{
queries.put(
methods[i],
new JDBCQlQueryMetaData(queryData, methods[i], entity.getQLCompiler(), false)
);
}
return queries;
}
public Map createJDBCQueryMetaData(Element queryElement,
Map defaultValues,
JDBCReadAheadMetaData readAhead) throws DeploymentException
{
// get the query methods
Method[] methods = getQueryMethods(queryElement);
// read-ahead
Element readAheadElement =
MetaData.getOptionalChild(queryElement, "read-ahead");
if(readAheadElement != null)
{
readAhead = new JDBCReadAheadMetaData(readAheadElement, readAhead);
}
Map queries = new HashMap(methods.length);
for(int i = 0; i < methods.length; i++)
{
JDBCQueryMetaData defaultValue =
(JDBCQueryMetaData) defaultValues.get(methods[i]);
if(defaultValue == null && !entity.isCMP1x() && !methods[i].getName().equals("findByPrimaryKey"))
{
//throw new DeploymentException("Unknown query method : " + methods[i]);
log.warn("The query method is not defined in ejb-jar.xml: " + methods[i]);
}
JDBCQueryMetaData jdbcQueryData = createJDBCQueryMetaData(
defaultValue,
queryElement,
methods[i],
readAhead
);
queries.put(methods[i], jdbcQueryData);
}
return queries;
}
public static JDBCQueryMetaData createJDBCQueryMetaData(JDBCQueryMetaData jdbcQueryMetaData,
JDBCReadAheadMetaData readAhead,
Class qlCompiler)
throws DeploymentException
{
// RAW-SQL
if(jdbcQueryMetaData instanceof JDBCRawSqlQueryMetaData)
{
return new JDBCRawSqlQueryMetaData(jdbcQueryMetaData.getMethod(), qlCompiler, false);
}
// JBOSS-QL
if(jdbcQueryMetaData instanceof JDBCJBossQLQueryMetaData)
{
return new JDBCJBossQLQueryMetaData(
(JDBCJBossQLQueryMetaData) jdbcQueryMetaData,
readAhead, qlCompiler, false
);
}
// DYNAMIC-SQL
if(jdbcQueryMetaData instanceof JDBCDynamicQLQueryMetaData)
{
return new JDBCDynamicQLQueryMetaData(
(JDBCDynamicQLQueryMetaData) jdbcQueryMetaData,
readAhead, qlCompiler, false
);
}
// DECLARED-SQL
if(jdbcQueryMetaData instanceof JDBCDeclaredQueryMetaData)
{
return new JDBCDeclaredQueryMetaData(
(JDBCDeclaredQueryMetaData) jdbcQueryMetaData,
readAhead, qlCompiler, false
);
}
// EJB-QL: default
if(jdbcQueryMetaData instanceof JDBCQlQueryMetaData)
{
return new JDBCQlQueryMetaData(
(JDBCQlQueryMetaData) jdbcQueryMetaData,
readAhead, qlCompiler, false
);
}
throw new DeploymentException(
"Error in query specification for method " +
jdbcQueryMetaData.getMethod().getName()
);
}
private JDBCQueryMetaData createJDBCQueryMetaData(JDBCQueryMetaData jdbcQueryMetaData,
Element queryElement,
Method method,
JDBCReadAheadMetaData readAhead)
throws DeploymentException
{
final Class qlCompiler = JDBCQueryManager.getQLCompiler(queryElement, entity);
final boolean isResultTypeMappingLocal = (jdbcQueryMetaData == null ?
false : jdbcQueryMetaData.isResultTypeMappingLocal());
final boolean lazyResultSetLoading = Collection.class.isAssignableFrom(method.getReturnType()) &&
MetaData.getOptionalChildBooleanContent(queryElement, "lazy-resultset-loading");
// RAW-SQL
Element rawSql = MetaData.getOptionalChild(queryElement, "raw-sql");
if(rawSql != null)
{
return new JDBCRawSqlQueryMetaData(method, qlCompiler, lazyResultSetLoading);
}
// JBOSS-QL
Element jbossQL =
MetaData.getOptionalChild(queryElement, "jboss-ql");
if(jbossQL != null)
{
return new JDBCJBossQLQueryMetaData(
isResultTypeMappingLocal,
jbossQL,
method,
readAhead,
qlCompiler,
lazyResultSetLoading
);
}
// DYNAMIC-SQL
Element dynamicQL = MetaData.getOptionalChild(queryElement, "dynamic-ql");
if(dynamicQL != null)
{
return new JDBCDynamicQLQueryMetaData(isResultTypeMappingLocal, method, readAhead, qlCompiler, lazyResultSetLoading);
}
// DECLARED-SQL
Element delcaredSql = MetaData.getOptionalChild(queryElement, "declared-sql");
if(delcaredSql != null)
{
return new JDBCDeclaredQueryMetaData(
isResultTypeMappingLocal,
delcaredSql,
method,
readAhead,
qlCompiler,
lazyResultSetLoading
);
}
// EJB-QL: default
if(jdbcQueryMetaData instanceof JDBCQlQueryMetaData)
{
return new JDBCQlQueryMetaData(
(JDBCQlQueryMetaData) jdbcQueryMetaData,
method,
readAhead
);
}
throw new DeploymentException("Error in query specification for method " + method.getName());
}
private Method[] getQueryMethods(Element queryElement)
throws DeploymentException
{
// query-method sub-element
Element queryMethod = MetaData.getUniqueChild(queryElement, "query-method");
// method name
String methodName =
MetaData.getUniqueChildContent(queryMethod, "method-name");
// method params
ArrayList methodParams = new ArrayList();
Element methodParamsElement =
MetaData.getUniqueChild(queryMethod, "method-params");
Iterator iterator =
MetaData.getChildrenByTagName(methodParamsElement, "method-param");
while(iterator.hasNext())
{
methodParams.add(MetaData.getElementContent((Element) iterator.next()));
}
try
{
Class[] parameters = Classes.convertToJavaClasses(methodParams.iterator(), entity.getClassLoader());
return getQueryMethods(methodName, parameters);
}
catch(ClassNotFoundException cnfe)
{
throw new DeploymentException(cnfe.getMessage());
}
}
private Method[] getQueryMethods(QueryMetaData queryData)
throws DeploymentException
{
String methodName = queryData.getMethodName();
try
{
Class[] parameters = Classes.convertToJavaClasses(queryData.getMethodParams(), entity.getClassLoader());
return getQueryMethods(methodName, parameters);
}
catch(ClassNotFoundException cnfe)
{
throw new DeploymentException(cnfe.getMessage());
}
}
private Method[] getQueryMethods(String methodName,
Class parameters[]) throws DeploymentException
{
// find the query and load the xml
ArrayList methods = new ArrayList(2);
if(methodName.startsWith("ejbSelect"))
{
// bean method
Method method = getQueryMethod(methodName, parameters, entity.getEntityClass());
if(method != null)
{
methods.add(method);
}
}
else
{
// remote home
Class homeClass = entity.getHomeClass();
if(homeClass != null)
{
Method method = getQueryMethod(methodName, parameters, homeClass);
if(method != null)
{
methods.add(method);
}
}
// local home
Class localHomeClass = entity.getLocalHomeClass();
if(localHomeClass != null)
{
Method method = getQueryMethod(methodName, parameters, localHomeClass);
if(method != null)
{
methods.add(method);
}
}
}
if(methods.size() == 0)
{
StringBuffer sb = new StringBuffer(300);
sb.append("Query method not found: ")
.append(methodName).append('(');
for(int i = 0; i < parameters.length; i++)
{
if(i > 0)
{
sb.append(',');
}
sb.append(parameters[i].getName());
}
sb.append(')');
throw new DeploymentException(sb.toString());
}
return (Method[]) methods.toArray(new Method[methods.size()]);
}
private static Method getQueryMethod(String queryName,
Class[] parameters,
Class clazz)
{
try
{
Method method = clazz.getMethod(queryName, parameters);
// is the method abstract?
// (remember interface methods are always abstract)
if(Modifier.isAbstract(method.getModifiers()))
{
return method;
}
}
catch(NoSuchMethodException e)
{
// that's cool
}
return null;
}
}