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.metadata;
023:
024: import java.lang.reflect.Method;
025: import java.lang.reflect.Modifier;
026: import java.util.ArrayList;
027: import java.util.HashMap;
028: import java.util.Iterator;
029: import java.util.Map;
030: import java.util.Collection;
031:
032: import org.w3c.dom.Element;
033:
034: import org.jboss.deployment.DeploymentException;
035: import org.jboss.metadata.MetaData;
036: import org.jboss.metadata.QueryMetaData;
037: import org.jboss.util.Classes;
038: import org.jboss.ejb.plugins.cmp.jdbc.JDBCQueryManager;
039: import org.jboss.logging.Logger;
040:
041: /**
042: * JDBCQueryMetaDataFactory constructs a JDBCQueryMetaData object based
043: * on the query specifiection type.
044: *
045: * @author <a href="mailto:dain@daingroup.com">Dain Sundstrom</a>
046: * @version $Revision: 57209 $
047: */
048: public class JDBCQueryMetaDataFactory {
049: private static final Logger log = Logger
050: .getLogger(JDBCQueryMetaDataFactory.class);
051:
052: private JDBCEntityMetaData entity;
053:
054: public JDBCQueryMetaDataFactory(JDBCEntityMetaData entity) {
055: this .entity = entity;
056: }
057:
058: public Map createJDBCQueryMetaData(QueryMetaData queryData)
059: throws DeploymentException {
060:
061: Method[] methods = getQueryMethods(queryData);
062: Map queries = new HashMap(methods.length);
063: for (int i = 0; i < methods.length; i++) {
064: queries.put(methods[i], new JDBCQlQueryMetaData(queryData,
065: methods[i], entity.getQLCompiler(), false));
066: }
067: return queries;
068: }
069:
070: public Map createJDBCQueryMetaData(Element queryElement,
071: Map defaultValues, JDBCReadAheadMetaData readAhead)
072: throws DeploymentException {
073:
074: // get the query methods
075: Method[] methods = getQueryMethods(queryElement);
076:
077: // read-ahead
078: Element readAheadElement = MetaData.getOptionalChild(
079: queryElement, "read-ahead");
080: if (readAheadElement != null) {
081: readAhead = new JDBCReadAheadMetaData(readAheadElement,
082: readAhead);
083: }
084:
085: Map queries = new HashMap(methods.length);
086: for (int i = 0; i < methods.length; i++) {
087: JDBCQueryMetaData defaultValue = (JDBCQueryMetaData) defaultValues
088: .get(methods[i]);
089:
090: if (defaultValue == null && !entity.isCMP1x()
091: && !methods[i].getName().equals("findByPrimaryKey")) {
092: //throw new DeploymentException("Unknown query method : " + methods[i]);
093: log
094: .warn("The query method is not defined in ejb-jar.xml: "
095: + methods[i]);
096: }
097:
098: JDBCQueryMetaData jdbcQueryData = createJDBCQueryMetaData(
099: defaultValue, queryElement, methods[i], readAhead);
100:
101: queries.put(methods[i], jdbcQueryData);
102: }
103: return queries;
104: }
105:
106: public static JDBCQueryMetaData createJDBCQueryMetaData(
107: JDBCQueryMetaData jdbcQueryMetaData,
108: JDBCReadAheadMetaData readAhead, Class qlCompiler)
109: throws DeploymentException {
110:
111: // RAW-SQL
112: if (jdbcQueryMetaData instanceof JDBCRawSqlQueryMetaData) {
113: return new JDBCRawSqlQueryMetaData(jdbcQueryMetaData
114: .getMethod(), qlCompiler, false);
115: }
116:
117: // JBOSS-QL
118: if (jdbcQueryMetaData instanceof JDBCJBossQLQueryMetaData) {
119: return new JDBCJBossQLQueryMetaData(
120: (JDBCJBossQLQueryMetaData) jdbcQueryMetaData,
121: readAhead, qlCompiler, false);
122: }
123:
124: // DYNAMIC-SQL
125: if (jdbcQueryMetaData instanceof JDBCDynamicQLQueryMetaData) {
126: return new JDBCDynamicQLQueryMetaData(
127: (JDBCDynamicQLQueryMetaData) jdbcQueryMetaData,
128: readAhead, qlCompiler, false);
129: }
130:
131: // DECLARED-SQL
132: if (jdbcQueryMetaData instanceof JDBCDeclaredQueryMetaData) {
133: return new JDBCDeclaredQueryMetaData(
134: (JDBCDeclaredQueryMetaData) jdbcQueryMetaData,
135: readAhead, qlCompiler, false);
136: }
137:
138: // EJB-QL: default
139: if (jdbcQueryMetaData instanceof JDBCQlQueryMetaData) {
140: return new JDBCQlQueryMetaData(
141: (JDBCQlQueryMetaData) jdbcQueryMetaData, readAhead,
142: qlCompiler, false);
143: }
144:
145: throw new DeploymentException(
146: "Error in query specification for method "
147: + jdbcQueryMetaData.getMethod().getName());
148: }
149:
150: private JDBCQueryMetaData createJDBCQueryMetaData(
151: JDBCQueryMetaData jdbcQueryMetaData, Element queryElement,
152: Method method, JDBCReadAheadMetaData readAhead)
153: throws DeploymentException {
154: final Class qlCompiler = JDBCQueryManager.getQLCompiler(
155: queryElement, entity);
156: final boolean isResultTypeMappingLocal = (jdbcQueryMetaData == null ? false
157: : jdbcQueryMetaData.isResultTypeMappingLocal());
158:
159: final boolean lazyResultSetLoading = Collection.class
160: .isAssignableFrom(method.getReturnType())
161: && MetaData.getOptionalChildBooleanContent(
162: queryElement, "lazy-resultset-loading");
163:
164: // RAW-SQL
165: Element rawSql = MetaData.getOptionalChild(queryElement,
166: "raw-sql");
167: if (rawSql != null) {
168: return new JDBCRawSqlQueryMetaData(method, qlCompiler,
169: lazyResultSetLoading);
170: }
171:
172: // JBOSS-QL
173: Element jbossQL = MetaData.getOptionalChild(queryElement,
174: "jboss-ql");
175: if (jbossQL != null) {
176: return new JDBCJBossQLQueryMetaData(
177: isResultTypeMappingLocal, jbossQL, method,
178: readAhead, qlCompiler, lazyResultSetLoading);
179: }
180:
181: // DYNAMIC-SQL
182: Element dynamicQL = MetaData.getOptionalChild(queryElement,
183: "dynamic-ql");
184: if (dynamicQL != null) {
185: return new JDBCDynamicQLQueryMetaData(
186: isResultTypeMappingLocal, method, readAhead,
187: qlCompiler, lazyResultSetLoading);
188: }
189:
190: // DECLARED-SQL
191: Element delcaredSql = MetaData.getOptionalChild(queryElement,
192: "declared-sql");
193: if (delcaredSql != null) {
194: return new JDBCDeclaredQueryMetaData(
195: isResultTypeMappingLocal, delcaredSql, method,
196: readAhead, qlCompiler, lazyResultSetLoading);
197: }
198:
199: // EJB-QL: default
200: if (jdbcQueryMetaData instanceof JDBCQlQueryMetaData) {
201: return new JDBCQlQueryMetaData(
202: (JDBCQlQueryMetaData) jdbcQueryMetaData, method,
203: readAhead);
204: }
205:
206: throw new DeploymentException(
207: "Error in query specification for method "
208: + method.getName());
209: }
210:
211: private Method[] getQueryMethods(Element queryElement)
212: throws DeploymentException {
213: // query-method sub-element
214: Element queryMethod = MetaData.getUniqueChild(queryElement,
215: "query-method");
216:
217: // method name
218: String methodName = MetaData.getUniqueChildContent(queryMethod,
219: "method-name");
220:
221: // method params
222: ArrayList methodParams = new ArrayList();
223: Element methodParamsElement = MetaData.getUniqueChild(
224: queryMethod, "method-params");
225: Iterator iterator = MetaData.getChildrenByTagName(
226: methodParamsElement, "method-param");
227: while (iterator.hasNext()) {
228: methodParams.add(MetaData
229: .getElementContent((Element) iterator.next()));
230: }
231:
232: try {
233: Class[] parameters = Classes.convertToJavaClasses(
234: methodParams.iterator(), entity.getClassLoader());
235:
236: return getQueryMethods(methodName, parameters);
237: } catch (ClassNotFoundException cnfe) {
238: throw new DeploymentException(cnfe.getMessage());
239: }
240:
241: }
242:
243: private Method[] getQueryMethods(QueryMetaData queryData)
244: throws DeploymentException {
245: String methodName = queryData.getMethodName();
246:
247: try {
248: Class[] parameters = Classes.convertToJavaClasses(queryData
249: .getMethodParams(), entity.getClassLoader());
250:
251: return getQueryMethods(methodName, parameters);
252: } catch (ClassNotFoundException cnfe) {
253: throw new DeploymentException(cnfe.getMessage());
254: }
255: }
256:
257: private Method[] getQueryMethods(String methodName,
258: Class parameters[]) throws DeploymentException {
259:
260: // find the query and load the xml
261: ArrayList methods = new ArrayList(2);
262: if (methodName.startsWith("ejbSelect")) {
263: // bean method
264: Method method = getQueryMethod(methodName, parameters,
265: entity.getEntityClass());
266: if (method != null) {
267: methods.add(method);
268: }
269: } else {
270: // remote home
271: Class homeClass = entity.getHomeClass();
272: if (homeClass != null) {
273: Method method = getQueryMethod(methodName, parameters,
274: homeClass);
275: if (method != null) {
276: methods.add(method);
277: }
278: }
279: // local home
280: Class localHomeClass = entity.getLocalHomeClass();
281: if (localHomeClass != null) {
282: Method method = getQueryMethod(methodName, parameters,
283: localHomeClass);
284: if (method != null) {
285: methods.add(method);
286: }
287: }
288: }
289:
290: if (methods.size() == 0) {
291: StringBuffer sb = new StringBuffer(300);
292: sb.append("Query method not found: ").append(methodName)
293: .append('(');
294: for (int i = 0; i < parameters.length; i++) {
295: if (i > 0) {
296: sb.append(',');
297: }
298: sb.append(parameters[i].getName());
299: }
300: sb.append(')');
301: throw new DeploymentException(sb.toString());
302: }
303: return (Method[]) methods.toArray(new Method[methods.size()]);
304: }
305:
306: private static Method getQueryMethod(String queryName,
307: Class[] parameters, Class clazz) {
308:
309: try {
310: Method method = clazz.getMethod(queryName, parameters);
311:
312: // is the method abstract?
313: // (remember interface methods are always abstract)
314: if (Modifier.isAbstract(method.getModifiers())) {
315: return method;
316: }
317: } catch (NoSuchMethodException e) {
318: // that's cool
319: }
320: return null;
321: }
322:
323: }
|