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;
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
{
Method[] methods = getQueryMethods(queryElement);
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)
{
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
{
if(jdbcQueryMetaData instanceof JDBCRawSqlQueryMetaData)
{
return new JDBCRawSqlQueryMetaData(jdbcQueryMetaData.getMethod(), qlCompiler, false);
}
if(jdbcQueryMetaData instanceof JDBCJBossQLQueryMetaData)
{
return new JDBCJBossQLQueryMetaData(
(JDBCJBossQLQueryMetaData) jdbcQueryMetaData,
readAhead, qlCompiler, false
);
}
if(jdbcQueryMetaData instanceof JDBCDynamicQLQueryMetaData)
{
return new JDBCDynamicQLQueryMetaData(
(JDBCDynamicQLQueryMetaData) jdbcQueryMetaData,
readAhead, qlCompiler, false
);
}
if(jdbcQueryMetaData instanceof JDBCDeclaredQueryMetaData)
{
return new JDBCDeclaredQueryMetaData(
(JDBCDeclaredQueryMetaData) jdbcQueryMetaData,
readAhead, qlCompiler, false
);
}
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");
Element rawSql = MetaData.getOptionalChild(queryElement, "raw-sql");
if(rawSql != null)
{
return new JDBCRawSqlQueryMetaData(method, qlCompiler, lazyResultSetLoading);
}
Element jbossQL =
MetaData.getOptionalChild(queryElement, "jboss-ql");
if(jbossQL != null)
{
return new JDBCJBossQLQueryMetaData(
isResultTypeMappingLocal,
jbossQL,
method,
readAhead,
qlCompiler,
lazyResultSetLoading
);
}
Element dynamicQL = MetaData.getOptionalChild(queryElement, "dynamic-ql");
if(dynamicQL != null)
{
return new JDBCDynamicQLQueryMetaData(isResultTypeMappingLocal, method, readAhead, qlCompiler, lazyResultSetLoading);
}
Element delcaredSql = MetaData.getOptionalChild(queryElement, "declared-sql");
if(delcaredSql != null)
{
return new JDBCDeclaredQueryMetaData(
isResultTypeMappingLocal,
delcaredSql,
method,
readAhead,
qlCompiler,
lazyResultSetLoading
);
}
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
{
Element queryMethod = MetaData.getUniqueChild(queryElement, "query-method");
String methodName =
MetaData.getUniqueChildContent(queryMethod, "method-name");
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
{
ArrayList methods = new ArrayList(2);
if(methodName.startsWith("ejbSelect"))
{
Method method = getQueryMethod(methodName, parameters, entity.getEntityClass());
if(method != null)
{
methods.add(method);
}
}
else
{
Class homeClass = entity.getHomeClass();
if(homeClass != null)
{
Method method = getQueryMethod(methodName, parameters, homeClass);
if(method != null)
{
methods.add(method);
}
}
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);
if(Modifier.isAbstract(method.getModifiers()))
{
return method;
}
}
catch(NoSuchMethodException e)
{
}
return null;
}
}