001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins.cmp.jdbc;
023:
024: import java.lang.reflect.Method;
025: import java.lang.reflect.Constructor;
026: import java.util.HashMap;
027: import java.util.Iterator;
028: import java.util.Map;
029: import javax.ejb.FinderException;
030:
031: import org.jboss.deployment.DeploymentException;
032: import org.jboss.ejb.plugins.cmp.jdbc.bridge.JDBCEntityBridge;
033: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCAutomaticQueryMetaData;
034: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCQueryMetaData;
035: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCDeclaredQueryMetaData;
036: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCDynamicQLQueryMetaData;
037: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCJBossQLQueryMetaData;
038: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCQlQueryMetaData;
039: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData;
040: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCEntityMetaData;
041: import org.jboss.ejb.plugins.cmp.ejbql.Catalog;
042: import org.jboss.logging.Logger;
043: import org.jboss.metadata.MetaData;
044: import org.w3c.dom.Element;
045:
046: /**
047: * Maintains a map from a query method to query command.
048: *
049: * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
050: * @author <a href="mailto:rickard.oberg@telkel.com">Rickard �berg</a>
051: * @author <a href="mailto:marc.fleury@telkel.com">Marc Fleury</a>
052: * @author <a href="mailto:shevlandj@kpi.com.au">Joe Shevland</a>
053: * @author <a href="mailto:justin@j-m-f.demon.co.uk">Justin Forder</a>
054: * @author <a href="mailto:alex@jboss.org">Alex Loubyansky</a>
055: * @version $Revision: 57209 $
056: */
057: public final class JDBCQueryManager {
058: private static final String FIND_BY_PK = "findByPrimaryKey";
059: private static final String EJB_FIND = "ejbFind";
060: private static final String FIND_ALL = "findAll";
061: private static final String FIND_BY = "findBy";
062:
063: private final Map knownQueries = new HashMap();
064: private final JDBCStoreManager manager;
065:
066: public JDBCQueryManager(JDBCStoreManager manager) {
067: this .manager = manager;
068: }
069:
070: public static final Class getQLCompiler(Element query,
071: JDBCEntityMetaData entity) throws DeploymentException {
072: String compiler = MetaData.getOptionalChildContent(query,
073: "ql-compiler");
074: Class impl;
075:
076: if (compiler == null || compiler.trim().length() == 0) {
077: impl = entity.getQLCompiler();
078: } else {
079: try {
080: impl = TCLAction.UTIL.getContextClassLoader()
081: .loadClass(compiler);
082: } catch (ClassNotFoundException e) {
083: throw new DeploymentException(
084: "Failed to load compiler implementation: "
085: + compiler);
086: }
087: }
088: return impl;
089: }
090:
091: public static final QLCompiler getInstance(Class impl,
092: Catalog catalog) throws DeploymentException {
093: if (impl == null) {
094: throw new DeploymentException(
095: "ql-compiler is not specified.");
096: }
097:
098: final Constructor constructor;
099: try {
100: constructor = impl
101: .getConstructor(new Class[] { Catalog.class });
102: } catch (NoSuchMethodException e) {
103: throw new DeploymentException(
104: "Compiler class does not have a constructor which takes "
105: + Catalog.class.getName());
106: }
107:
108: try {
109: return (QLCompiler) constructor
110: .newInstance(new Object[] { catalog });
111: } catch (Exception e) {
112: throw new DeploymentException(
113: "Failed to create an instance of " + impl.getName()
114: + ": " + e.getMessage(), e);
115: }
116: }
117:
118: public JDBCQueryCommand getQueryCommand(Method queryMethod)
119: throws FinderException {
120: JDBCQueryCommand queryCommand = (JDBCQueryCommand) knownQueries
121: .get(queryMethod);
122:
123: if (queryCommand == null) {
124: throw new FinderException("Unknown query: " + queryMethod);
125: }
126: return queryCommand;
127: }
128:
129: public void start() throws DeploymentException {
130: Logger log = Logger.getLogger(this .getClass().getName() + "."
131: + manager.getMetaData().getName());
132:
133: JDBCCommandFactory factory = manager.getCommandFactory();
134:
135: Class homeClass = manager.getContainer().getHomeClass();
136: Class localHomeClass = manager.getContainer()
137: .getLocalHomeClass();
138:
139: //
140: // findByPrimaryKey
141: //
142: JDBCEntityBridge entity = (JDBCEntityBridge) manager
143: .getEntityBridge();
144: if (homeClass != null) {
145: try {
146: // try to get the finder method on the home interface
147: Method method = homeClass.getMethod(FIND_BY_PK,
148: new Class[] { entity.getPrimaryKeyClass() });
149:
150: JDBCQueryMetaData findByPKMD = manager.getMetaData()
151: .getQueryMetaDataForMethod(method);
152: JDBCReadAheadMetaData readAhead = (findByPKMD == null ? entity
153: .getMetaData().getReadAhead()
154: : findByPKMD.getReadAhead());
155:
156: // got it add it to known finders
157: JDBCQueryMetaData q = new JDBCAutomaticQueryMetaData(
158: method, readAhead, entity.getMetaData()
159: .getQLCompiler(), false);
160: knownQueries.put(method, factory
161: .createFindByPrimaryKeyQuery(q));
162:
163: if (log.isDebugEnabled())
164: log
165: .debug("Added findByPrimaryKey query command for home interface");
166: } catch (NoSuchMethodException e) {
167: throw new DeploymentException(
168: "Home interface does not have a findByPrimaryKey method");
169: }
170: }
171:
172: if (localHomeClass != null) {
173:
174: Method method;
175: try {
176: // try to get the finder method on the local home interface
177: method = localHomeClass.getMethod(FIND_BY_PK,
178: new Class[] { entity.getPrimaryKeyClass() });
179: } catch (NoSuchMethodException e) {
180: throw new DeploymentException(
181: "Local home interface does "
182: + "not have the method findByPrimaryKey("
183: + entity.getPrimaryKeyClass().getName()
184: + ")");
185: }
186:
187: // got it add it to known finders
188: JDBCQueryMetaData findByPKMD = manager.getMetaData()
189: .getQueryMetaDataForMethod(method);
190: JDBCReadAheadMetaData readAhead = (findByPKMD == null ? entity
191: .getMetaData().getReadAhead()
192: : findByPKMD.getReadAhead());
193: JDBCQueryMetaData q = new JDBCAutomaticQueryMetaData(
194: method, readAhead, entity.getMetaData()
195: .getQLCompiler(), false);
196: knownQueries.put(method, factory
197: .createFindByPrimaryKeyQuery(q));
198:
199: if (log.isDebugEnabled())
200: log
201: .debug("Added findByPrimaryKey query command for local home interface");
202: }
203:
204: //
205: // Custom finders - Overrides defined and automatic finders.
206: //
207: Class ejbClass = manager.getMetaData().getEntityClass();
208:
209: Method[] customMethods = ejbClass.getMethods();
210: for (int i = 0; i < customMethods.length; i++) {
211: Method m = customMethods[i];
212: String methodName = m.getName();
213: if (methodName.startsWith(EJB_FIND)) {
214: String interfaceName = 'f' + methodName.substring(4);
215:
216: if (homeClass != null) {
217: try {
218: // try to get the finder method on the home interface
219: Method interfaceMethod = homeClass.getMethod(
220: interfaceName, m.getParameterTypes());
221:
222: // got it add it to known finders
223: knownQueries.put(interfaceMethod,
224: new JDBCCustomFinderQuery(manager, m));
225:
226: if (log.isDebugEnabled())
227: log
228: .debug("Added custom finder "
229: + methodName
230: + " on home interface");
231: } catch (NoSuchMethodException e) {
232: // this is ok method may not be defined on this interface
233: }
234: }
235:
236: if (localHomeClass != null) {
237: try {
238: // try to get the finder method on the local home interface
239: Method interfaceMethod = localHomeClass
240: .getMethod(interfaceName, m
241: .getParameterTypes());
242:
243: // got it add it to known finders
244: knownQueries.put(interfaceMethod,
245: new JDBCCustomFinderQuery(manager, m));
246:
247: if (log.isDebugEnabled())
248: log.debug("Added custom finder "
249: + methodName
250: + " on local home interface");
251: } catch (NoSuchMethodException e) {
252: // this is ok method may not be defined on this interface
253: }
254: }
255: }
256: }
257:
258: //
259: // Defined finders - Overrides automatic finders.
260: //
261: Iterator definedFinders = manager.getMetaData().getQueries()
262: .iterator();
263: while (definedFinders.hasNext()) {
264: JDBCQueryMetaData q = (JDBCQueryMetaData) definedFinders
265: .next();
266:
267: if (!knownQueries.containsKey(q.getMethod())) {
268: if (q instanceof JDBCJBossQLQueryMetaData) {
269: knownQueries.put(q.getMethod(), factory
270: .createJBossQLQuery(q));
271:
272: } else if (q instanceof JDBCDynamicQLQueryMetaData) {
273: knownQueries.put(q.getMethod(), factory
274: .createDynamicQLQuery(q));
275:
276: } else if (q instanceof JDBCDeclaredQueryMetaData) {
277: knownQueries.put(q.getMethod(), factory
278: .createDeclaredSQLQuery(q));
279:
280: } else if (q instanceof JDBCQlQueryMetaData) {
281: knownQueries.put(q.getMethod(), factory
282: .createEJBQLQuery(q));
283: }
284: }
285: }
286:
287: //
288: // Automatic finders - The last resort
289: //
290: if (homeClass != null) {
291: addAutomaticFinders(manager, homeClass.getMethods(), log);
292: }
293:
294: if (localHomeClass != null) {
295: addAutomaticFinders(manager, localHomeClass.getMethods(),
296: log);
297: }
298: }
299:
300: public void clear() {
301: this .knownQueries.clear();
302: }
303:
304: private void addAutomaticFinders(JDBCStoreManager manager,
305: Method[] homeMethods, Logger log)
306: throws DeploymentException {
307:
308: JDBCCommandFactory factory = manager.getCommandFactory();
309: JDBCEntityBridge entity = (JDBCEntityBridge) manager
310: .getEntityBridge();
311: for (int i = 0; i < homeMethods.length; i++) {
312: Method method = homeMethods[i];
313:
314: if (!knownQueries.containsKey(method)) {
315: String name = method.getName();
316: if (name.equals(FIND_ALL)) {
317: JDBCQueryMetaData q = new JDBCAutomaticQueryMetaData(
318: method,
319: entity.getMetaData().getReadAhead(), entity
320: .getMetaData().getQLCompiler(),
321: false);
322: knownQueries.put(method, factory
323: .createFindAllQuery(q));
324: } else if (name.startsWith(FIND_BY)
325: && !name.equals(FIND_BY_PK)) {
326: try {
327: JDBCQueryMetaData q = new JDBCAutomaticQueryMetaData(
328: method, entity.getMetaData()
329: .getReadAhead(), entity
330: .getMetaData().getQLCompiler(),
331: false);
332: knownQueries.put(method, factory
333: .createFindByQuery(q));
334: } catch (IllegalArgumentException e) {
335: log
336: .debug("Could not create the finder "
337: + name
338: + ", because no matching CMP field was found.");
339: }
340: }
341: }
342: }
343: }
344: }
|