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.InvocationTargetException;
026:
027: import java.util.ArrayList;
028: import java.util.Collection;
029: import java.util.Collections;
030: import java.util.Enumeration;
031: import java.util.List;
032:
033: import javax.ejb.FinderException;
034:
035: import org.jboss.ejb.EntityEnterpriseContext;
036: import org.jboss.ejb.GenericEntityObjectFactory;
037: import org.jboss.ejb.plugins.cmp.jdbc.metadata.JDBCReadAheadMetaData;
038: import org.jboss.logging.Logger;
039:
040: /**
041: * CMPStoreManager CustomFindByEntitiesCommand.
042: * Implements bridge for custom implemented finders in container managed entity
043: * beans. These methods are called ejbFindX in the EJB implementation class,
044: * where X can be anything. Such methods are called findX in the Home and/or
045: * the LocalHome interface.
046: *
047: * @see org.jboss.ejb.plugins.cmp.jdbc.JDBCFindEntitiesCommand
048: * @author <a href="mailto:michel.anke@wolmail.nl">Michel de Groot</a>
049: * @author <a href="mailto:john-jboss@freeborg.com">John Freeborg</a>
050: * @version $Revision: 57209 $
051: */
052: public final class JDBCCustomFinderQuery implements JDBCQueryCommand {
053: private final Logger log;
054: private final Method finderMethod;
055: private final JDBCReadAheadMetaData readAheadMetaData;
056: private final ReadAheadCache readAheadCache;
057: private final JDBCStoreManager manager;
058:
059: /**
060: * Constructs a command which can handle multiple entity finders
061: * that are BMP implemented.
062: * @param finderMethod the EJB finder method implementation
063: */
064: public JDBCCustomFinderQuery(JDBCStoreManager manager,
065: Method finderMethod) {
066: this .finderMethod = finderMethod;
067: this .manager = manager;
068:
069: JDBCReadAheadMetaData readAheadMetaData = manager.getMetaData()
070: .getReadAhead();
071: if ((readAheadMetaData != null) && readAheadMetaData.isOnLoad()) {
072: this .readAheadCache = manager.getReadAheadCache();
073: this .readAheadMetaData = readAheadMetaData;
074: } else {
075: this .readAheadCache = null;
076: this .readAheadMetaData = null;
077: }
078:
079: this .log = Logger.getLogger(this .getClass().getName() + "."
080: + manager.getMetaData().getName() + "."
081: + finderMethod.getName());
082:
083: if (log.isDebugEnabled())
084: log
085: .debug("Finder: Custom finder "
086: + finderMethod.getName());
087: }
088:
089: public JDBCStoreManager getSelectManager() {
090: return manager;
091: }
092:
093: public Collection execute(Method unused, Object[] args,
094: EntityEnterpriseContext ctx,
095: GenericEntityObjectFactory factory) throws FinderException {
096: try {
097: // invoke implementation method on ejb instance
098: Object value = finderMethod.invoke(ctx.getInstance(), args);
099:
100: // if expected return type is Collection, return as is
101: // if expected return type is not Collection, wrap value in Collection
102: if (value instanceof Enumeration) {
103: Enumeration e = (Enumeration) value;
104: List result = new ArrayList();
105: while (e.hasMoreElements()) {
106: result.add(e.nextElement());
107: }
108: cacheResults(result);
109: return GenericEntityObjectFactory.UTIL
110: .getEntityCollection(factory, result);
111: } else if (value instanceof Collection) {
112: List result;
113: if (value instanceof List)
114: result = (List) value;
115: else
116: result = new ArrayList((Collection) value);
117: cacheResults(result);
118: return GenericEntityObjectFactory.UTIL
119: .getEntityCollection(factory, result);
120: } else {
121: // Don't bother trying to cache this
122: return Collections.singleton(factory
123: .getEntityEJBObject(value));
124: }
125: } catch (IllegalAccessException e) {
126: log.error("Error invoking custom finder "
127: + finderMethod.getName(), e);
128: throw new FinderException(
129: "Unable to access finder implementation: "
130: + finderMethod.getName());
131: } catch (IllegalArgumentException e) {
132: log.error("Error invoking custom finder "
133: + finderMethod.getName(), e);
134: throw new FinderException("Illegal arguments for finder "
135: + "implementation: " + finderMethod.getName());
136: } catch (InvocationTargetException e) {
137: // Throw the exception if its a FinderException
138: Throwable ex = e.getTargetException();
139: if (ex instanceof FinderException) {
140: throw (FinderException) ex;
141: } else {
142: throw new FinderException(
143: "Errror invoking cutom finder "
144: + finderMethod.getName() + ": " + ex);
145: }
146: }
147: }
148:
149: private void cacheResults(List listOfPKs) {
150: // the on-load read ahead cache strategy is the only one that makes
151: // sense to support for custom finders since all we have is a list of
152: // primary keys.
153: if (readAheadCache != null) {
154: readAheadCache.addFinderResults(listOfPKs,
155: readAheadMetaData);
156: }
157: }
158: }
|