package org.jboss.ejb.plugins.cmp.jdbc;
import java.lang.reflect.Method;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.ejb.FinderException;
import org.jboss.deployment.DeploymentException;
import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCAutomaticQueryMetaData;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCQueryMetaData;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCDeclaredQueryMetaData;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCDynamicQLQueryMetaData;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCJBossQLQueryMetaData;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCQlQueryMetaData;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData;
import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData;
import org.jboss.ejb.plugins.cmp.ejbql.Catalog;
import org.jboss.logging.Logger;
import org.jboss.metadata.MetaData;
import org.w3c.dom.Element;
public final class JDBCQueryManager
{
private static final String FIND_BY_PK = "findByPrimaryKey";
private static final String EJB_FIND = "ejbFind";
private static final String FIND_ALL = "findAll";
private static final String FIND_BY = "findBy";
private final Map knownQueries = new HashMap();
private final JDBCStoreManager manager;
public JDBCQueryManager(JDBCStoreManager manager)
{
this.manager = manager;
}
public static final Class getQLCompiler(Element query, JDBCEntityMetaData entity)
throws DeploymentException
{
String compiler = MetaData.getOptionalChildContent(query, "ql-compiler");
Class impl;
if(compiler == null || compiler.trim().length() == 0)
{
impl = entity.getQLCompiler();
}
else
{
try
{
impl = TCLAction.UTIL.getContextClassLoader().loadClass(compiler);
}
catch(ClassNotFoundException e)
{
throw new DeploymentException("Failed to load compiler implementation: " + compiler);
}
}
return impl;
}
public static final QLCompiler getInstance(Class impl, Catalog catalog)
throws DeploymentException
{
if(impl == null)
{
throw new DeploymentException("ql-compiler is not specified.");
}
final Constructor constructor;
try
{
constructor = impl.getConstructor(new Class[]{Catalog.class});
}
catch(NoSuchMethodException e)
{
throw new DeploymentException("Compiler class does not have a constructor which takes " + Catalog.class.getName());
}
try
{
return (QLCompiler)constructor.newInstance(new Object[]{catalog});
}
catch(Exception e)
{
throw new DeploymentException("Failed to create an instance of " + impl.getName() + ": " + e.getMessage(), e);
}
}
public JDBCQueryCommand getQueryCommand(Method queryMethod)
throws FinderException
{
JDBCQueryCommand queryCommand = (JDBCQueryCommand)knownQueries.get(queryMethod);
if(queryCommand == null)
{
throw new FinderException("Unknown query: " + queryMethod);
}
return queryCommand;
}
public void start() throws DeploymentException
{
Logger log = Logger.getLogger(
this.getClass().getName() +
"." +
manager.getMetaData().getName());
JDBCCommandFactory factory = manager.getCommandFactory();
Class homeClass = manager.getContainer().getHomeClass();
Class localHomeClass = manager.getContainer().getLocalHomeClass();
JDBCEntityBridge entity = (JDBCEntityBridge) manager.getEntityBridge();
if(homeClass != null)
{
try
{
Method method = homeClass.getMethod(FIND_BY_PK, new Class[]{entity.getPrimaryKeyClass()});
JDBCQueryMetaData findByPKMD = manager.getMetaData().getQueryMetaDataForMethod(method);
JDBCReadAheadMetaData readAhead = (findByPKMD == null ?
entity.getMetaData().getReadAhead() : findByPKMD.getReadAhead());
JDBCQueryMetaData q = new JDBCAutomaticQueryMetaData(
method,
readAhead,
entity.getMetaData().getQLCompiler(),
false
);
knownQueries.put(method, factory.createFindByPrimaryKeyQuery(q));
if(log.isDebugEnabled())
log.debug("Added findByPrimaryKey query command for home interface");
} catch(NoSuchMethodException e)
{
throw new DeploymentException("Home interface does not have a findByPrimaryKey method");
}
}
if(localHomeClass != null)
{
Method method;
try
{
method = localHomeClass.getMethod(FIND_BY_PK, new Class[] { entity.getPrimaryKeyClass() });
} catch(NoSuchMethodException e)
{
throw new DeploymentException("Local home interface does " +
"not have the method findByPrimaryKey(" +
entity.getPrimaryKeyClass().getName() + ")");
}
JDBCQueryMetaData findByPKMD = manager.getMetaData().getQueryMetaDataForMethod(method);
JDBCReadAheadMetaData readAhead = (findByPKMD == null ?
entity.getMetaData().getReadAhead() : findByPKMD.getReadAhead());
JDBCQueryMetaData q = new JDBCAutomaticQueryMetaData(method, readAhead, entity.getMetaData().getQLCompiler(), false);
knownQueries.put(method, factory.createFindByPrimaryKeyQuery(q));
if(log.isDebugEnabled())
log.debug("Added findByPrimaryKey query command for local home interface");
}
Class ejbClass = manager.getMetaData().getEntityClass();
Method[] customMethods = ejbClass.getMethods();
for (int i = 0; i < customMethods.length; i++)
{
Method m = customMethods[i];
String methodName = m.getName();
if(methodName.startsWith(EJB_FIND))
{
String interfaceName = 'f' + methodName.substring(4);
if(homeClass != null)
{
try
{
Method interfaceMethod = homeClass.getMethod(
interfaceName,
m.getParameterTypes());
knownQueries.put(interfaceMethod, new JDBCCustomFinderQuery(manager, m));
if(log.isDebugEnabled())
log.debug("Added custom finder " + methodName + " on home interface");
} catch(NoSuchMethodException e)
{
}
}
if(localHomeClass != null)
{
try
{
Method interfaceMethod = localHomeClass.getMethod(
interfaceName,
m.getParameterTypes());
knownQueries.put(interfaceMethod, new JDBCCustomFinderQuery(manager, m));
if(log.isDebugEnabled())
log.debug("Added custom finder " + methodName + " on local home interface");
} catch(NoSuchMethodException e)
{
}
}
}
}
Iterator definedFinders = manager.getMetaData().getQueries().iterator();
while(definedFinders.hasNext())
{
JDBCQueryMetaData q = (JDBCQueryMetaData)definedFinders.next();
if(!knownQueries.containsKey(q.getMethod()) )
{
if(q instanceof JDBCJBossQLQueryMetaData)
{
knownQueries.put(q.getMethod(), factory.createJBossQLQuery(q));
} else if(q instanceof JDBCDynamicQLQueryMetaData)
{
knownQueries.put(q.getMethod(), factory.createDynamicQLQuery(q));
} else if(q instanceof JDBCDeclaredQueryMetaData)
{
knownQueries.put(q.getMethod(), factory.createDeclaredSQLQuery(q));
} else if(q instanceof JDBCQlQueryMetaData)
{
knownQueries.put(q.getMethod(), factory.createEJBQLQuery(q));
}
}
}
if(homeClass != null)
{
addAutomaticFinders(manager, homeClass.getMethods(), log);
}
if(localHomeClass != null)
{
addAutomaticFinders(manager, localHomeClass.getMethods(), log);
}
}
public void clear()
{
this.knownQueries.clear();
}
private void addAutomaticFinders(
JDBCStoreManager manager,
Method[] homeMethods,
Logger log)
{
JDBCCommandFactory factory = manager.getCommandFactory();
JDBCEntityBridge entity = (JDBCEntityBridge) manager.getEntityBridge();
for (int i = 0; i < homeMethods.length; i++)
{
Method method = homeMethods[i];
if(!knownQueries.containsKey(method))
{
String name = method.getName();
if(name.equals(FIND_ALL))
{
JDBCQueryMetaData q = new JDBCAutomaticQueryMetaData(
method,
entity.getMetaData().getReadAhead(),
entity.getMetaData().getQLCompiler(), false
);
knownQueries.put(method, factory.createFindAllQuery(q));
}
else if(name.startsWith(FIND_BY) && !name.equals(FIND_BY_PK))
{
try
{
JDBCQueryMetaData q = new JDBCAutomaticQueryMetaData(
method,
entity.getMetaData().getReadAhead(),
entity.getMetaData().getQLCompiler(), false);
knownQueries.put(method, factory.createFindByQuery(q));
} catch (IllegalArgumentException e)
{
log.debug("Could not create the finder " + name +
", because no matching CMP field was found.");
}
}
}
}
}
}