You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@beehive.apache.org by ek...@apache.org on 2005/05/09 22:18:03 UTC
svn commit: r169351 [5/12] - in /incubator/beehive/trunk/system-controls: ./
ant/ external/ external/commons/ external/ejb/ external/jms/ src/ src/ejb/
src/ejb/org/ src/ejb/org/apache/ src/ejb/org/apache/beehive/
src/ejb/org/apache/beehive/controls/
src/ejb/org/apache/beehive/controls/system/
src/ejb/org/apache/beehive/controls/system/ejb/ src/ejb/schema/ src/jdbc/
src/jdbc/org/ src/jdbc/org/apache/ src/jdbc/org/apache/beehive/
src/jdbc/org/apache/beehive/controls/
src/jdbc/org/apache/beehive/controls/system/
src/jdbc/org/apache/beehive/controls/system/jdbc/
src/jdbc/org/apache/beehive/controls/system/jdbc/parser/ src/jms/
src/jms/org/ src/jms/org/apache/ src/jms/org/apache/beehive/
src/jms/org/apache/beehive/controls/
src/jms/org/apache/beehive/controls/system/
src/jms/org/apache/beehive/controls/system/jms/
src/jms/org/apache/beehive/controls/system/jms/impl/
src/jms/org/apache/beehive/controls/system/jndi/
src/jms/org/apache/beehive/controls/system/jndi/impl/ src/webservice/
src/webservice/org/ src/webservice/org/apache/
src/webservice/org/apache/beehive/
src/webservice/org/apache/beehive/controls/
src/webservice/org/apache/beehive/controls/system/
src/webservice/org/apache/beehive/controls/system/webservice/
src/webservice/org/apache/beehive/controls/system/webservice/generator/
src/webservice/org/apache/beehive/controls/system/webservice/jaxrpc/
src/webservice/org/apache/beehive/controls/system/webservice/utils/ test/
test/ant/ test/conf/ test/src/ test/src/jdbc/ test/src/jdbc/controls/
test/src/jdbc/controls/org/ test/src/jdbc/controls/org/apache/
test/src/jdbc/controls/org/apache/beehive/
test/src/jdbc/controls/org/apache/beehive/controls/
test/src/jdbc/controls/org/apache/beehive/controls/system/
test/src/jdbc/controls/org/apache/beehive/controls/system/jdbc/
test/src/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/
test/src/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/dbconnection/
test/src/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/errors/
test/src/jdbc/controls/org/apache/beehive/controls/system/jdbc/test/results/
test/src/jdbc/controls/schemas/ test/src/jdbc/controls/schemas/badusers/
test/src/jdbc/controls/schemas/users/ test/src/jdbc/jdbc-container/
test/src/jdbc/jdbc-container/application/ test/src/jdbc/jdbc-container/src/
test/src/jdbc/jdbc-container/src/org/
test/src/jdbc/jdbc-container/src/org/apache/
test/src/jdbc/jdbc-container/src/org/apache/beehive/
test/src/jdbc/jdbc-container/src/org/apache/beehive/controls/
test/src/jdbc/jdbc-container/src/org/apache/beehive/controls/system/
test/src/jdbc/jdbc-container/src/org/apache/beehive/controls/system/jdbc/
test/src/jdbc/jdbc-container/src/org/apache/beehive/controls/system/jdbc/containertest/
test/src/jdbc/jdbc-container/webapp/
test/src/jdbc/jdbc-container/webapp/WEB-INF/
test/src/jdbc/jdbc-container/webapp/conf/
test/src/jdbc/jdbc-container/webapp/conf/Catalina/
test/src/jdbc/jdbc-container/webapp/conf/Catalina/localhost/
test/src/jdbc/junitTests/ test/src/jdbc/junitTests/org/
test/src/jdbc/junitTests/org/apache/
test/src/jdbc/junitTests/org/apache/beehive/
test/src/jdbc/junitTests/org/apache/beehive/controls/
test/src/jdbc/junitTests/org/apache/beehive/controls/system/
test/src/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/
test/src/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/
test/src/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/dbconnection/
test/src/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/errors/
test/src/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/results/
test/src/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/sqlparser/
test/src/jdbc/junitTests/org/apache/beehive/controls/system/jdbc/units/utils/
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/JdbcControlChecker.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/JdbcControlChecker.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/JdbcControlChecker.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/JdbcControlChecker.java Mon May 9 13:17:58 2005
@@ -0,0 +1,298 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import com.sun.mirror.apt.AnnotationProcessorEnvironment;
+import com.sun.mirror.declaration.Declaration;
+import com.sun.mirror.declaration.FieldDeclaration;
+import com.sun.mirror.declaration.MethodDeclaration;
+import com.sun.mirror.declaration.TypeDeclaration;
+import com.sun.mirror.type.ArrayType;
+import com.sun.mirror.type.DeclaredType;
+import com.sun.mirror.type.InterfaceType;
+import com.sun.mirror.type.MirroredTypeException;
+import com.sun.mirror.type.PrimitiveType;
+import com.sun.mirror.type.TypeMirror;
+import com.sun.mirror.type.VoidType;
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.bean.ControlChecker;
+import org.apache.beehive.controls.system.jdbc.parser.ParameterChecker;
+import org.apache.beehive.controls.system.jdbc.parser.SqlParser;
+import org.apache.beehive.controls.system.jdbc.parser.SqlStatement;
+
+import java.util.Collection;
+import java.sql.SQLException;
+
+/**
+ * Annotation checker for the JdbcControl. Invoked at compile time by the controls framework.
+ */
+public class JdbcControlChecker implements ControlChecker {
+
+ /**
+ * Invoked by the control build-time infrastructure to process a declaration of
+ * a control extension (ie, an interface annotated with @ControlExtension), or
+ * a field instance of a control type.
+ */
+ public void check(Declaration decl, AnnotationProcessorEnvironment env) {
+
+ if (decl instanceof TypeDeclaration) {
+
+ //
+ // Check class annotations
+ //
+ checkConnectionDataSource((TypeDeclaration) decl, env);
+ checkConnectionDriver((TypeDeclaration) decl, env);
+ checkConnectionOptions((TypeDeclaration) decl, env);
+
+ //
+ // Check method annotations
+ //
+ Collection<? extends MethodDeclaration> methods = ((TypeDeclaration) decl).getMethods();
+ for (MethodDeclaration method : methods) {
+ checkSQL(method, env);
+
+ }
+ } else if (decl instanceof FieldDeclaration) {
+
+ //
+ // NOOP
+ //
+ } else {
+
+ //
+ // NOOP
+ //
+ }
+ }
+
+ /**
+ * Check the ConnectionDataSource annotation.
+ *
+ * @param decl
+ * @param env
+ */
+ private void checkConnectionDataSource(TypeDeclaration decl, AnnotationProcessorEnvironment env) {
+ final JdbcControl.ConnectionDataSource cds =
+ decl.getAnnotation(JdbcControl.ConnectionDataSource.class);
+ if (cds == null) {
+ return;
+ }
+
+ //
+ // NOOP
+ //
+ }
+
+ /**
+ * Check the ConnectionDriver annotation.
+ *
+ * @param decl
+ * @param env
+ */
+ private void checkConnectionDriver(TypeDeclaration decl, AnnotationProcessorEnvironment env) {
+ final JdbcControl.ConnectionDriver cd = decl.getAnnotation(JdbcControl.ConnectionDriver.class);
+ if (cd == null) {
+ return;
+ }
+
+ //
+ // NOOP
+ //
+ }
+
+ /**
+ * Check the ConnectionOptions annotation.
+ *
+ * @param decl
+ * @param env
+ */
+ private void checkConnectionOptions(TypeDeclaration decl, AnnotationProcessorEnvironment env) {
+ final JdbcControl.ConnectionOptions co = decl.getAnnotation(JdbcControl.ConnectionOptions.class);
+ if (co == null) {
+ return;
+ }
+
+ //
+ // NOOP
+ //
+ }
+
+ /**
+ * Check the SQL method annotation. Lots to check here, stop checking as soon as an error is found.
+ *
+ * @param method
+ * @param env
+ */
+ private void checkSQL(MethodDeclaration method, AnnotationProcessorEnvironment env) {
+
+ final JdbcControl.SQL methodSQL = method.getAnnotation(JdbcControl.SQL.class);
+ if (methodSQL == null) {
+ return;
+ }
+
+ //
+ // check for empty SQL statement member
+ //
+ if (methodSQL.statement() == null || methodSQL.statement().length() == 0) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " contains an empty statement member.");
+ return;
+ }
+
+ //
+ // Make sure maxrows is not set to some negative number other than -1
+ //
+ int maxRows = methodSQL.maxRows();
+ if (maxRows < JdbcControl.MAXROWS_ALL) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " maxRows set to invalid value: " + maxRows);
+ return;
+ }
+
+ //
+ // Make sure maxArrayLength is not set to some negative number
+ //
+ int arrayMax = methodSQL.arrayMaxLength();
+ if (arrayMax < 1) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " arrayMaxLength set to invalid value (must be greater than 0): "
+ + arrayMax);
+ return;
+ }
+
+
+ //
+ //
+ // parse the SQL
+ //
+ //
+ SqlParser _p = new SqlParser();
+ SqlStatement _statement = null;
+ try {
+ _statement = _p.parse(methodSQL.statement());
+ } catch (ControlException ce) {
+ env.getMessager().printError(method.getPosition(), "Error parsing SQL statment on method: " + method.getSimpleName() + ": " + ce.toString());
+ return;
+ }
+
+ //
+ // Check that the any statement element params (delimited by '{' and '}' can be
+ // matched to method parameter names. NOTE: This check is only valid on non-compiled files,
+ // once compiled to a class file method parameter names are replaced with 'arg0', 'arg1', etc.
+ // and cannot be used for this check.
+ //
+ try {
+ ParameterChecker.checkReflectionParameters(_statement, method);
+ } catch (ControlException e) {
+ env.getMessager().printError(method.getPosition(), e.getMessage());
+ return;
+ }
+
+ //
+ // check for case of generatedKeyColumns being set, when getGeneratedKeys is not set to true
+ //
+ final boolean getGeneratedKeys = methodSQL.getGeneratedKeys();
+ final String[] generatedKeyColumnNames = methodSQL.generatedKeyColumnNames();
+ final int[] generatedKeyIndexes = methodSQL.generatedKeyColumnIndexes();
+ if (getGeneratedKeys == false && (generatedKeyColumnNames.length != 0 || generatedKeyIndexes.length != 0)) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " getGeneratedKeys must be set to true in order to specify generatedKeyColumnNames or generatedKeyColumnIndexes.");
+ return;
+ }
+
+ //
+ // check that both generatedKeyColumnNames and generatedKeyColumnIndexes are not set
+ if (generatedKeyColumnNames.length > 0 && generatedKeyIndexes.length > 0) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " only one of generatedKeyColumnNames or generatedKeyColumnIndexes may be set in the method annotation.");
+
+ return;
+ }
+
+ //
+ // batch update methods must return int[]
+ //
+ final boolean batchUpdate = methodSQL.batchUpdate();
+ final TypeMirror returnType = method.getReturnType();
+ if (batchUpdate) {
+ if (returnType instanceof ArrayType == true) {
+ final TypeMirror aType = ((ArrayType) returnType).getComponentType();
+ if (aType instanceof PrimitiveType == false || ((PrimitiveType) aType).getKind() != PrimitiveType.Kind.INT) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " if batchUpdate is set to true, method must return void or an array of integers.");
+ return;
+ }
+ } else if (returnType instanceof VoidType == false) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " if batchUpdate is set to true, method must return void or an array of integers.");
+
+ return;
+ }
+
+ }
+
+ //
+ // iterator type check match
+ //
+ if (returnType instanceof InterfaceType) {
+ String iName = ((InterfaceType) returnType).getDeclaration().getQualifiedName();
+ if ("java.util.Iterator".equals(iName)) {
+ String iteratorClassName = null;
+ try {
+ // this should always except
+ methodSQL.iteratorElementType();
+ } catch (MirroredTypeException mte) {
+ iteratorClassName = mte.getQualifiedName();
+ }
+
+ if ("org.apache.beehive.controls.system.jdbc.JdbcControl.UndefinedIteratorType".equals(iteratorClassName)) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " iteratorElementType must be specified if method returns an Iterator.");
+ return;
+
+ }
+ }
+ }
+
+ //
+ // scrollable result set check
+ //
+ final JdbcControl.ScrollType scrollable = methodSQL.scrollableResultSet();
+ switch (scrollable) {
+ case SCROLL_INSENSITIVE:
+ case SCROLL_SENSITIVE:
+ case SCROLL_INSENSITIVE_UPDATABLE:
+ case SCROLL_SENSITIVE_UPDATABLE:
+ case FORWARD_ONLY_UPDATABLE:
+ String typeName = null;
+ if (returnType instanceof DeclaredType) {
+ typeName = ((DeclaredType) returnType).getDeclaration().getQualifiedName();
+ }
+
+ if (typeName == null || "java.sql.ResultSet".equals(typeName) == false) {
+ env.getMessager().printError(method.getPosition(), "@SQL annotation on method: " + method.getSimpleName()
+ + " element scrollableResultSet specified but method does not return a ResultSet.");
+ break;
+ }
+ case FORWARD_ONLY:
+ default:
+ break;
+ }
+ } // checkSQL
+}
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.jcs
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.jcs?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.jcs (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/JdbcControlImpl.jcs Mon May 9 13:17:58 2005
@@ -0,0 +1,490 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.bean.ControlImplementation;
+import org.apache.beehive.controls.api.bean.Extensible;
+import org.apache.beehive.controls.api.context.ControlBeanContext;
+import org.apache.beehive.controls.api.context.ResourceContext;
+import org.apache.beehive.controls.api.context.ResourceContext.ResourceEvents;
+import org.apache.beehive.controls.api.events.EventHandler;
+import org.apache.log4j.Logger;
+import org.apache.beehive.controls.system.jdbc.parser.SqlParser;
+import org.apache.beehive.controls.system.jdbc.parser.SqlStatement;
+
+import javax.naming.NamingException;
+import javax.naming.Context;
+import javax.sql.DataSource;
+import java.lang.reflect.Method;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Vector;
+
+/**
+ * The implementation class for the database controller.
+ */
+@ControlImplementation
+public class JdbcControlImpl implements JdbcControl, Extensible, java.io.Serializable {
+
+ //
+ // contexts provided by the beehive controls runtime
+ //
+ @org.apache.beehive.controls.api.context.Context
+ protected ControlBeanContext _context;
+ @org.apache.beehive.controls.api.context.Context
+ protected ResourceContext _resourceContext;
+
+ protected transient Connection _connection;
+ protected transient ConnectionDataSource _connectionDataSource;
+ protected transient DataSource _dataSource;
+ protected transient ConnectionDriver _connectionDriver;
+
+ private transient Calendar _cal;
+ private transient Vector<PreparedStatement> _resources = new Vector<PreparedStatement>();
+
+ private static final String EMPTY_STRING = "";
+ private static final Logger logger = Logger.getLogger(JdbcControlImpl.class);
+ private static final ResultSetMapper DEFAULT_MAPPER = new DefaultObjectResultSetMapper();
+ private static final SqlParser _sqlParser = new SqlParser();
+
+ protected static final HashMap<Class, ResultSetMapper> _resultMappers = new HashMap<Class, ResultSetMapper>();
+ protected static Class<?> _xmlObjectClass;
+
+ //
+ // initialize the result mapper table
+ //
+ static {
+ _resultMappers.put(ResultSet.class, new DefaultResultSetMapper());
+ _resultMappers.put(Iterator.class, new DefaultIteratorResultSetMapper());
+
+ try {
+ _xmlObjectClass = Class.forName("org.apache.xmlbeans.XmlObject");
+ _resultMappers.put(_xmlObjectClass, new DefaultXmlObjectResultSetMapper());
+ } catch (ClassNotFoundException e) {
+ // noop: OK if not found, just can't support mapping to an XmlObject
+ }
+ }
+
+ /**
+ * Constructor
+ */
+ public JdbcControlImpl() { }
+
+ /**
+ * Invoked by the controls runtime when a new instance of this class is aquired by the runtime
+ */
+ @EventHandler(field = "_resourceContext", eventSet = ResourceEvents.class, eventName = "onAcquire")
+ public void onAquire() {
+ try {
+ getConnection();
+ } catch (SQLException se) {
+ throw new ControlException("SQL Exception while attempting to connect to database.", se);
+ }
+ }
+
+ /**
+ * Invoked by the controls runtime when an instance of this class is released by the runtime
+ */
+ @EventHandler(field = "_resourceContext", eventSet = ResourceContext.ResourceEvents.class, eventName = "onRelease")
+ public void onRelease() {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("onRelease() invoked.");
+ }
+
+ for (PreparedStatement ps : _resources) {
+ try {
+ ps.close();
+ } catch (SQLException sqe) {
+ }
+ }
+ _resources.clear();
+
+ if (_connection != null) {
+ try {
+ _connection.close();
+ } catch (SQLException e) {
+ throw new ControlException("SQL Exception while attempting to close database connection.", e);
+ }
+ }
+
+ _connection = null;
+ _connectionDataSource = null;
+ _connectionDriver = null;
+ }
+
+ /**
+ * Returns a database connection to the server associated with the control.
+ * The connection type is specified by a ConnectionDataSource or ConnectionDriver annotation on the control class
+ * which extends this control.
+ * <p/>
+ * It is typically not necessary to call this method when using the control.
+ */
+ public Connection getConnection() throws SQLException {
+
+ if (_connection == null) {
+
+ _connectionDataSource = _context.getControlPropertySet(ConnectionDataSource.class);
+ _connectionDriver = _context.getControlPropertySet(ConnectionDriver.class);
+ final ConnectionOptions connectionOptions = _context.getControlPropertySet(ConnectionOptions.class);
+
+ if (_connectionDataSource != null && _connectionDataSource.jndiName() != null) {
+ _connection = getConnectionFromDataSource(_connectionDataSource.jndiName(),
+ _connectionDataSource.jndiContextFactory());
+
+ } else if (_connectionDriver != null && _connectionDriver.databaseDriverClass() != null) {
+ _connection = getConnectionFromDriverManager(_connectionDriver.databaseDriverClass(),
+ _connectionDriver.databaseURL(),
+ _connectionDriver.userName(),
+ _connectionDriver.password(),
+ _connectionDriver.properties());
+ } else {
+ throw new ControlException("no @\'" + ConnectionDataSource.class.getName()
+ + "\' or \'" + ConnectionDriver.class.getName() + "\' property found.");
+ }
+
+ //
+ // set any specifed connection options
+ //
+ if (connectionOptions != null) {
+
+ if (_connection.isReadOnly() != connectionOptions.readOnly()) {
+ _connection.setReadOnly(connectionOptions.readOnly());
+ }
+
+ DatabaseMetaData dbMetadata = _connection.getMetaData();
+
+ final HoldabilityType holdability = connectionOptions.resultSetHoldability();
+ if (holdability != HoldabilityType.DRIVER_DEFAULT) {
+ if (dbMetadata.supportsResultSetHoldability(holdability.getHoldability())) {
+ _connection.setHoldability(holdability.getHoldability());
+ } else {
+ throw new ControlException("Database does not support ResultSet holdability type: "
+ + holdability.toString());
+ }
+ }
+
+ setTypeMappers(connectionOptions.typeMappers());
+ }
+ }
+
+ return _connection;
+ }
+
+
+ /**
+ * Called by the Controls runtime to handle calls to methods of an extensible control.
+ *
+ * @param method The extended operation that was called.
+ * @param args Parameters of the operation.
+ * @return The value that should be returned by the operation.
+ * @throws Throwable any exception declared on the extended operation may be
+ * thrown. If a checked exception is thrown from the implementation that is not declared
+ * on the original interface, it will be wrapped in a ControlException.
+ */
+ public Object invoke(Method method, Object[] args) throws Throwable {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("Enter: invoke()");
+ }
+ assert _connection.isClosed() == false : "invoke(): JDBC Connection has been closed!!!!";
+ return execPreparedStatement(method, args);
+ }
+
+ /**
+ * Sets the calendar used when working with time/date types
+ */
+ public void setDataSourceCalendar(Calendar cal) {
+ _cal = (Calendar) cal.clone();
+ }
+
+ /**
+ * Returns the calendar used when working with time/date types.
+ *
+ * @return
+ */
+ public Calendar getDataSourceCalendar() {
+ return _cal;
+ }
+
+
+// /////////////////////////////////////////// Protected Methods ////////////////////////////////////////////
+
+
+ /**
+ * Create and exec the query
+ *
+ * @param method
+ * @param args
+ * @return
+ * @throws Throwable
+ */
+ protected Object execPreparedStatement(Method method, Object[] args)
+ throws Throwable {
+
+ final SQL methodSQL = (SQL) _context.getMethodPropertySet(method, SQL.class);
+ if (methodSQL == null || methodSQL.statement() == null) {
+ throw new ControlException("Method " + method.getName() + " is missing @SQL annotation");
+ }
+
+ setTypeMappers(methodSQL.typeMappersOverride());
+
+ //
+ // build the statement and execute it
+ //
+
+ PreparedStatement ps = null;
+ try {
+ Class returnType = method.getReturnType();
+
+ SqlStatement sqlStatement = _sqlParser.parse(methodSQL.statement());
+ ps = sqlStatement.createPreparedStatement(_context, _connection, _cal, method, args);
+
+ if (logger.isInfoEnabled()) {
+ logger.info("PreparedStatement: "
+ + sqlStatement.createPreparedStatementString(_context, _connection, method, args));
+ }
+
+ //
+ // special processing for batch updates
+ //
+ if (sqlStatement.isBatchUpdate()) {
+ return ps.executeBatch();
+ }
+
+ //
+ // execute the statement
+ //
+ boolean hasResults = ps.execute();
+
+
+ //
+ // callable statement processing
+ //
+ if (sqlStatement.isCallableStatement()) {
+ SQLParameter[] params = (SQLParameter[]) args[0];
+ for (int i = 0; i < params.length; i++) {
+ if (params[i].dir != SQLParameter.IN) {
+ params[i].value = ((CallableStatement) ps).getObject(i + 1);
+ }
+ }
+ return null;
+ }
+
+
+ //
+ // process returned data
+ //
+ ResultSet rs = null;
+ int updateCount = ps.getUpdateCount();
+
+ if (hasResults) {
+ rs = ps.getResultSet();
+ }
+
+ if (sqlStatement.getsGeneratedKeys()) {
+ rs = ps.getGeneratedKeys();
+ hasResults = true;
+ }
+
+ if (!hasResults && updateCount > -1) {
+ boolean moreResults = ps.getMoreResults();
+ int tempUpdateCount = ps.getUpdateCount();
+
+ while ((moreResults && rs == null) || tempUpdateCount > -1) {
+ if (moreResults) {
+ rs = ps.getResultSet();
+ hasResults = true;
+ moreResults = false;
+ tempUpdateCount = -1;
+ } else {
+ moreResults = ps.getMoreResults();
+ tempUpdateCount = ps.getUpdateCount();
+ }
+ }
+ }
+
+ Object returnObject = null;
+ if (hasResults) {
+
+ //
+ // if a result set mapper was specified in the methods annotation, use it
+ // otherwise find the mapper for the return type in the hashmap
+ //
+ final Class resultSetMapperClass = methodSQL.resultSetMapper();
+ final ResultSetMapper rsm;
+ if (!UndefinedResultSetMapper.class.isAssignableFrom(resultSetMapperClass)) {
+ if (ResultSetMapper.class.isAssignableFrom(resultSetMapperClass)) {
+ rsm = (ResultSetMapper) resultSetMapperClass.newInstance();
+ } else {
+ throw new ControlException("Result set mappers must be subclasses of ResultSetMapper.class!");
+ }
+ } else {
+ if (_resultMappers.containsKey(returnType)) {
+ rsm = _resultMappers.get(returnType);
+ } else {
+ if (_xmlObjectClass != null && _xmlObjectClass.isAssignableFrom(returnType)) {
+ rsm = _resultMappers.get(_xmlObjectClass);
+ } else {
+ rsm = DEFAULT_MAPPER;
+ }
+ }
+ }
+
+ returnObject = rsm.mapToResultType(_context, method, rs, _cal);
+ if (rsm.canCloseResultSet() == false) {
+ _resources.add(ps);
+ }
+
+ //
+ // empty ResultSet
+ //
+ } else {
+ if (returnType.equals(Void.TYPE)) {
+ returnObject = null;
+ } else if (returnType.equals(Integer.TYPE)) {
+ returnObject = new Integer(updateCount);
+ } else if (!sqlStatement.isCallableStatement()) {
+ throw new ControlException("Method " + method.getName() + "is DML but does not return void or int");
+ }
+ }
+ return returnObject;
+
+ } finally {
+ // Keep statements open that have in-use result sets
+ if (ps != null && !_resources.contains(ps)) {
+ ps.close();
+ }
+ }
+ }
+
+// /////////////////////////////////////////// Private Methods ////////////////////////////////////////////
+
+ /**
+ * Get a connection from a DataSource.
+ *
+ * @param jndiName Specifed in the subclasse's ConnectionDataSource annotation
+ * @param jndiFactory Specified in the subclasse's ConnectionDataSource Annotation.
+ * @return null if a connection cannot be established
+ * @throws SQLException
+ */
+ private Connection getConnectionFromDataSource(String jndiName,
+ Class<? extends JdbcControl.JndiContextFactory> jndiFactory)
+ throws SQLException
+ {
+
+ Connection con = null;
+ try {
+ JndiContextFactory jf = (JndiContextFactory) jndiFactory.newInstance();
+ Context jndiContext = jf.getContext();
+ _dataSource = (DataSource) jndiContext.lookup(jndiName);
+ con = _dataSource.getConnection();
+ } catch (IllegalAccessException iae) {
+ throw new ControlException("IllegalAccessException:", iae);
+ } catch (InstantiationException ie) {
+ throw new ControlException("InstantiationException:", ie);
+ } catch (NamingException ne) {
+ throw new ControlException("NamingException:", ne);
+ }
+ return con;
+ }
+
+ /**
+ * Get a JDBC connection from the DriverManager.
+ *
+ * @param dbDriverClassName Specified in the subclasse's ConnectionDriver annotation.
+ * @param dbUrlStr Specified in the subclasse's ConnectionDriver annotation.
+ * @param userName Specified in the subclasse's ConnectionDriver annotation.
+ * @param password Specified in the subclasse's ConnectionDriver annotation.
+ * @return null if a connection cannot be established.
+ * @throws SQLException
+ */
+ private Connection getConnectionFromDriverManager(String dbDriverClassName, String dbUrlStr,
+ String userName, String password, String propertiesString)
+ throws SQLException
+ {
+
+ Connection con = null;
+ try {
+ Class.forName(dbDriverClassName);
+ if (!EMPTY_STRING.equals(userName)) {
+ con = DriverManager.getConnection(dbUrlStr, userName, password);
+ } else if (!EMPTY_STRING.equals(propertiesString)) {
+ Properties props = parseProperties(propertiesString);
+ if (props == null) {
+ throw new ControlException("Invalid properties annotation value: " + propertiesString);
+ }
+ con = DriverManager.getConnection(dbUrlStr, props);
+ } else {
+ con = DriverManager.getConnection(dbUrlStr);
+ }
+ } catch (ClassNotFoundException e) {
+ throw new ControlException("Database driver class not found!", e);
+ }
+ return con;
+ }
+
+ /**
+ * Parse the propertiesString into a Properties object. The string must have the format of:
+ * propertyName=propertyValue;propertyName=propertyValue;...
+ *
+ * @param propertiesString
+ * @return A Properties instance or null if parse fails
+ */
+ private Properties parseProperties(String propertiesString) {
+ Properties properties = null;
+ String[] propPairs = propertiesString.split(";");
+ if (propPairs.length > 0) {
+ properties = new Properties();
+ for (String propPair : propPairs) {
+ int eq = propPair.indexOf('=');
+ assert eq > -1 : "Invalid properties syntax: " + propertiesString;
+ properties.put(propPair.substring(0, eq), propPair.substring(eq + 1, propPair.length()));
+ }
+ }
+ return properties;
+ }
+
+ /**
+ * Set any custom type mappers specifed in the annotation for the connection. Used for mapping SQL UDTs to
+ * java classes.
+ *
+ * @param typeMappers An array of TypeMapper.
+ */
+ private void setTypeMappers(TypeMapper[] typeMappers) throws SQLException {
+
+ if (typeMappers.length > 0) {
+ Map<String, Class<?>> mappers = _connection.getTypeMap();
+ for (TypeMapper t : typeMappers) {
+ mappers.put(t.UDTName(), t.mapperClass());
+ }
+ _connection.setTypeMap(mappers);
+ }
+ }
+}
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetHashMap.java Mon May 9 13:17:58 2005
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.HashMap;
+
+/**
+ * The ResultSetHashMap class extends a standard HashMap and
+ * populates it with data derived from a JDBC ResultSet.
+ * <p/>
+ * Note: the keys are treated case-insensitively, and therefore requests
+ * made on the map are case-insensitive. Any direct access to the keys
+ * will yield uppercase keys.
+ * <p/>
+ * Note: only the row associated with the current cursor position
+ * is used.
+ */
+public class ResultSetHashMap extends HashMap<String, Object> {
+
+ ResultSetHashMap() {
+ super();
+ }
+
+ ResultSetHashMap(int size) {
+ super(size);
+ }
+
+ /**
+ * This constructor is optimized for being called in a loop.
+ * Preserve the upper case column list for performance.
+ */
+ ResultSetHashMap(ResultSet rs, String[] keys) throws SQLException {
+ super();
+ assert keys.length == rs.getMetaData().getColumnCount() + 1;
+
+ for (int i = 1; i < keys.length; i++) {
+ assert keys[i].equals(keys[i].toUpperCase());
+ super.put(keys[i], rs.getObject(i));
+ }
+ }
+
+
+ ResultSetHashMap(ResultSet rs) throws SQLException {
+ super();
+ ResultSetMetaData md = rs.getMetaData();
+ for (int i = 1; i <= md.getColumnCount(); i++) {
+ super.put(md.getColumnName(i).toUpperCase(), rs.getObject(i));
+ }
+ }
+
+
+ public boolean containsKey(String key) {
+ return super.containsKey(key.toUpperCase());
+ }
+
+
+ public Object get(String key) {
+ return super.get(key.toUpperCase());
+ }
+
+
+ public Object put(String key, Object value) {
+ return super.put(key.toUpperCase(), value);
+ }
+
+
+ public Object remove(String key) {
+ return super.remove(key.toUpperCase());
+ }
+}
+
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetIterator.java Mon May 9 13:17:58 2005
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+import org.apache.beehive.controls.api.context.ControlBeanContext;
+
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.NoSuchElementException;
+
+/**
+ * Used by DefaultIteratorResultSetMapper for mapping a ResultSet to an Iterator type.
+ */
+public class ResultSetIterator implements java.util.Iterator {
+
+ private final Class _returnClass;
+ private final ResultSet _rs;
+ private final RowMapper _rowMapper;
+
+ private boolean _primed = false;
+
+ /**
+ * Create a new ResultSetIterator.
+ * @param context A ControlBeanContext.
+ * @param method The annotated method.
+ * @param rs The ResultSet to map.
+ * @param cal A Calendar instance for mapping date/time values.
+ */
+ ResultSetIterator(ControlBeanContext context, Method method, ResultSet rs, Calendar cal) {
+ _rs = rs;
+
+ JdbcControl.SQL methodSQL = (JdbcControl.SQL) context.getMethodPropertySet(method, JdbcControl.SQL.class);
+ _returnClass = methodSQL.iteratorElementType();
+
+ if (_returnClass == null) {
+ throw new ControlException("Invalid return class declared for Iterator:" + _returnClass.getName());
+ }
+
+ _rowMapper = RowMapperFactory.getRowMapper(rs, _returnClass, cal);
+ }
+
+ /**
+ * Does this iterater have more elements?
+ * @return true if there is another element
+ */
+ public boolean hasNext() {
+ if (_primed) {
+ return true;
+ }
+
+ try {
+ _primed = _rs.next();
+ } catch (SQLException sqle) {
+ return false;
+ }
+ return _primed;
+ }
+
+ /**
+ * Get the next element in the iteration.
+ * @return The next element in the iteration.
+ */
+ public Object next() {
+ try {
+ if (!_primed) {
+ _primed = _rs.next();
+ if (!_primed) {
+ throw new NoSuchElementException();
+ }
+ }
+ // reset upon consumption
+ _primed = false;
+ return _rowMapper.mapRowToReturnType();
+ } catch (SQLException e) {
+ // Since Iterator interface is locked, all we can do
+ // is put the real exception inside an expected one.
+ NoSuchElementException xNoSuch = new NoSuchElementException("ResultSet exception: " + e);
+ xNoSuch.initCause(e);
+ throw xNoSuch;
+ }
+ }
+
+ /**
+ * Remove is currently not supported.
+ */
+ public void remove() {
+ throw new UnsupportedOperationException("remove not supported");
+ }
+}
+
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/ResultSetMapper.java Mon May 9 13:17:58 2005
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.context.ControlBeanContext;
+
+import java.lang.reflect.Method;
+import java.sql.ResultSet;
+import java.util.Calendar;
+
+/**
+ * Extend this class to create new ResultSet mappers. The extended class will be invoked by the JdbcController
+ * when it is time to map a ResultSet to a method's return type.
+ *
+ * ResultSet mappers are specified on a per method basis using the SQL annotation's resultSetMapper field.
+ */
+public abstract class ResultSetMapper {
+
+ /**
+ * Map a ResultSet to an object type
+ *
+ * @param context A ControlBeanContext instance, see Beehive controls javadoc for additional information
+ * @param m Method assoicated with this call.
+ * @param resultSet Result set to map.
+ * @param cal A Calendar instance for time/date value resolution.
+ * @return The Object resulting from the ResultSet
+ */
+ public abstract Object mapToResultType(ControlBeanContext context, Method m, ResultSet resultSet, Calendar cal);
+
+ /**
+ * Can the ResultSet which this mapper uses be closed by the Jdbc control?
+ * @return true if the ResultSet can be closed by the JdbcControl
+ */
+ public boolean canCloseResultSet() { return true; }
+}
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowMapper.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowMapper.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowMapper.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowMapper.java Mon May 9 13:17:58 2005
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.regex.Pattern;
+import java.util.regex.Matcher;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+
+/**
+ * Abstract base class for all row mappers.
+ *
+ * RowMappers are used to map the contents of a row in a ResultSet to the return type of an annotated method.
+ * Supported RowMapper types include: HashMap, Map, Object, XmlObject. When a ResultSetMapper is ready to
+ * map a ResultSet row to an object, it requests a RowMapper for the return type of the method from the
+ * RowMapperFactory.
+ *
+ */
+public abstract class RowMapper {
+
+ private static final String SETTER_NAME_REGEX = "^(set)([A-Z_]\\w*+)";
+ protected static final TypeMappingsFactory _tmf = TypeMappingsFactory.getInstance();
+ protected static final Pattern _setterRegex = Pattern.compile(SETTER_NAME_REGEX);
+
+ /** ResultSet to map. */
+ protected final ResultSet _resultSet;
+
+ /** Calendar instance for date/time mappings. */
+ protected final Calendar _cal;
+
+ /** Class to map ResultSet Rows to. */
+ protected final Class<?> _returnTypeClass;
+
+ /**
+ * Create a new RowMapper for the specified ResultSet and return type Class.
+ * @param resultSet ResultSet to map
+ * @param returnTypeClass Class to map ResultSet rows to.
+ * @param cal Calendar instance for date/time values.
+ */
+ protected RowMapper(ResultSet resultSet, Class<?> returnTypeClass, Calendar cal) {
+ _resultSet = resultSet;
+ _returnTypeClass = returnTypeClass;
+ _cal = cal;
+ }
+
+ /**
+ * Map a ResultSet row to the return type class
+ * @return An instance of class.
+ */
+ public abstract Object mapRowToReturnType();
+
+
+ /**
+ * Build a String array of column names from the ResultSet.
+ * @return A String array containing the column names contained within the ResultSet.
+ * @throws SQLException on error
+ */
+ protected String[] getKeysFromResultSet() throws SQLException {
+
+ String[] keys;
+ final ResultSetMetaData md = _resultSet.getMetaData();
+ final int columnCount = md.getColumnCount();
+
+ keys = new String[columnCount + 1];
+ for (int i = 1; i <= columnCount; i++) {
+ keys[i] = md.getColumnName(i).toUpperCase();
+ }
+ return keys;
+ }
+
+ /**
+ * Determine if the given method is a java bean setter method.
+ * @param method Method to check
+ * @return True if the method is a setter method.
+ */
+ protected boolean isSetterMethod(Method method) {
+ Matcher matcher = _setterRegex.matcher(method.getName());
+ if (matcher.matches()) {
+
+ if (Modifier.isStatic(method.getModifiers())) return false;
+ if (!Modifier.isPublic(method.getModifiers())) return false;
+ if (!Void.TYPE.equals(method.getReturnType())) return false;
+
+ // method parameter checks
+ Class[] params = method.getParameterTypes();
+ if (params.length != 1) return false;
+ if (TypeMappingsFactory.TYPE_UNKNOWN == _tmf.getTypeId(params[0])) return false;
+
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Extract a column value from the ResultSet and return it as resultType.
+ *
+ * @param index The column index of the value to extract from the ResultSet.
+ * @param resultType The return type. Defined in TypeMappingsFactory.
+ * @return The extracted value
+ * @throws java.sql.SQLException on error.
+ */
+ protected Object extractColumnValue(int index, int resultType) throws SQLException {
+
+ switch (resultType) {
+ case TypeMappingsFactory.TYPE_INT:
+ return new Integer(_resultSet.getInt(index));
+ case TypeMappingsFactory.TYPE_LONG:
+ return new Long(_resultSet.getLong(index));
+ case TypeMappingsFactory.TYPE_FLOAT:
+ return new Float(_resultSet.getFloat(index));
+ case TypeMappingsFactory.TYPE_DOUBLE:
+ return new Double(_resultSet.getDouble(index));
+ case TypeMappingsFactory.TYPE_BYTE:
+ return new Byte(_resultSet.getByte(index));
+ case TypeMappingsFactory.TYPE_SHORT:
+ return new Short(_resultSet.getShort(index));
+ case TypeMappingsFactory.TYPE_BOOLEAN:
+ return _resultSet.getBoolean(index) ? Boolean.TRUE : Boolean.FALSE;
+ case TypeMappingsFactory.TYPE_INT_OBJ:
+ {
+ int i = _resultSet.getInt(index);
+ return _resultSet.wasNull() ? null : new Integer(i);
+ }
+ case TypeMappingsFactory.TYPE_LONG_OBJ:
+ {
+ long i = _resultSet.getLong(index);
+ return _resultSet.wasNull() ? null : new Long(i);
+ }
+ case TypeMappingsFactory.TYPE_FLOAT_OBJ:
+ {
+ float i = _resultSet.getFloat(index);
+ return _resultSet.wasNull() ? null : new Float(i);
+ }
+ case TypeMappingsFactory.TYPE_DOUBLE_OBJ:
+ {
+ double i = _resultSet.getDouble(index);
+ return _resultSet.wasNull() ? null : new Double(i);
+ }
+ case TypeMappingsFactory.TYPE_BYTE_OBJ:
+ {
+ byte i = _resultSet.getByte(index);
+ return _resultSet.wasNull() ? null : new Byte(i);
+ }
+ case TypeMappingsFactory.TYPE_SHORT_OBJ:
+ {
+ short i = _resultSet.getShort(index);
+ return _resultSet.wasNull() ? null : new Short(i);
+ }
+ case TypeMappingsFactory.TYPE_BOOLEAN_OBJ:
+ {
+ boolean i = _resultSet.getBoolean(index);
+ return _resultSet.wasNull() ? null : (i ? Boolean.TRUE : Boolean.FALSE);
+ }
+ case TypeMappingsFactory.TYPE_STRING:
+ case TypeMappingsFactory.TYPE_XMLBEAN_ENUM:
+ return _resultSet.getString(index);
+ case TypeMappingsFactory.TYPE_BIG_DECIMAL:
+ return _resultSet.getBigDecimal(index);
+ case TypeMappingsFactory.TYPE_BYTES:
+ return _resultSet.getBytes(index);
+ case TypeMappingsFactory.TYPE_TIMESTAMP:
+ {
+ if (null == _cal)
+ return _resultSet.getTimestamp(index);
+ else
+ return _resultSet.getTimestamp(index, _cal);
+ }
+ case TypeMappingsFactory.TYPE_TIME:
+ {
+ if (null == _cal)
+ return _resultSet.getTime(index);
+ else
+ return _resultSet.getTime(index, _cal);
+ }
+ case TypeMappingsFactory.TYPE_SQLDATE:
+ {
+ if (null == _cal)
+ return _resultSet.getDate(index);
+ else
+ return _resultSet.getDate(index, _cal);
+ }
+ case TypeMappingsFactory.TYPE_DATE:
+ {
+ // convert explicity to java.util.Date
+ // 12918 | knex does not return java.sql.Date properly from web service
+ java.sql.Timestamp ts = (null == _cal) ? _resultSet.getTimestamp(index) : _resultSet.getTimestamp(index, _cal);
+ if (null == ts)
+ return null;
+ return new java.util.Date(ts.getTime());
+ }
+ case TypeMappingsFactory.TYPE_CALENDAR:
+ {
+ java.sql.Timestamp ts = (null == _cal) ? _resultSet.getTimestamp(index) : _resultSet.getTimestamp(index, _cal);
+ if (null == ts)
+ return null;
+ Calendar c = (null == _cal) ? Calendar.getInstance() : (Calendar) _cal.clone();
+ c.setTimeInMillis(ts.getTime());
+ return c;
+ }
+ case TypeMappingsFactory.TYPE_REF:
+ return _resultSet.getRef(index);
+ case TypeMappingsFactory.TYPE_BLOB:
+ return _resultSet.getBlob(index);
+ case TypeMappingsFactory.TYPE_CLOB:
+ return _resultSet.getClob(index);
+ case TypeMappingsFactory.TYPE_ARRAY:
+ return _resultSet.getArray(index);
+ case TypeMappingsFactory.TYPE_READER:
+ case TypeMappingsFactory.TYPE_STREAM:
+ throw new ControlException("streaming return types are not supported by the JdbcControl; use ResultSet instead");
+ case TypeMappingsFactory.TYPE_STRUCT:
+ case TypeMappingsFactory.TYPE_UNKNOWN:
+ // JAVA_TYPE (could be any), or REF
+ return _resultSet.getObject(index);
+ default:
+ throw new ControlException("internal error: unknown type ID: " + Integer.toString(resultType));
+ }
+ }
+}
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowMapperFactory.java Mon May 9 13:17:58 2005
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.sql.ResultSet;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Factory for creating row mappers.
+ * <p/>
+ * Row mapper types supported by this factory include: HashMap, Map, Object, XmlObject. The factory determines the
+ * proper row mapper to use by checking its List of RowMappers against the type of mapping requested. When performing
+ * the lookup, the factory attempts to find the most specific type match. If a match can't be found the most general
+ * type of RowMapper is returned, RowToObjectMapper.
+ */
+public final class RowMapperFactory {
+
+ private static final HashMap<Class, Class<? extends RowMapper>> _rowMappings
+ = new HashMap<Class, Class<? extends RowMapper>>();
+
+ private static Class<? extends RowMapper> DEFAULT_OBJ_ROWMAPPING = RowToObjectMapper.class;
+
+ private static Class XMLOBJ_CLASS = null;
+ private static Class<? extends RowMapper> DEFAULT_XMLOBJ_ROWMAPPING = null;
+ private final static Class[] _params = {ResultSet.class, Class.class, Calendar.class};
+
+ static {
+
+ _rowMappings.put(HashMap.class, RowToHashMapMapper.class);
+ _rowMappings.put(Map.class, RowToMapMapper.class);
+
+ try {
+ XMLOBJ_CLASS = Class.forName("org.apache.xmlbeans.XmlObject");
+ DEFAULT_XMLOBJ_ROWMAPPING = RowToXmlObjectMapper.class;
+ } catch (ClassNotFoundException e) {
+ // NOOP if apache xml beans not present
+ }
+ }
+
+ /**
+ * Get a RowMapper instance which knows how to map a ResultSet row to the given return type.
+ *
+ * @param rs The ResultSet to map.
+ * @param returnTypeClass The class to map a ResultSet row to.
+ * @param cal Calendar instance for mapping date/time values.
+ * @return A RowMapper instance.
+ */
+ public static RowMapper getRowMapper(ResultSet rs, Class returnTypeClass, Calendar cal) {
+
+ Class<? extends RowMapper> rm = _rowMappings.get(returnTypeClass);
+ if (rm != null) {
+ return getMapper(rm, rs, returnTypeClass, cal);
+ }
+
+ //
+ // if we made it to here, check if the default XMLObject Mapper can be used,
+ // otherwise use the default object mapper
+ //
+ if (XMLOBJ_CLASS != null && XMLOBJ_CLASS.isAssignableFrom(returnTypeClass)) {
+ return getMapper(DEFAULT_XMLOBJ_ROWMAPPING, rs, returnTypeClass, cal);
+ } else {
+ return getMapper(DEFAULT_OBJ_ROWMAPPING, rs, returnTypeClass, cal);
+ }
+ }
+
+ /**
+ * Add a new row mapper to the list of available row mappers. The getRowMapper method traverses the
+ * list of mappers from beginning to end, checking to see if a mapper can handle the specified
+ * returnTypeClass. There is a default mapper which is used if a match cannot be found in the list.
+ *
+ * @param returnTypeClass Class which this mapper maps a row to.
+ * @param rowMapperClass The row mapper class.
+ */
+ public static void addRowMapping(Class returnTypeClass, Class<? extends RowMapper> rowMapperClass) {
+ _rowMappings.put(returnTypeClass, rowMapperClass);
+ }
+
+ /**
+ * Replace a row mapping.
+ *
+ * @param returnTypeClass Class which this mapper maps a row to.
+ * @param rowMapperClass The row mapper class.
+ * @return if the mapper was replaced, false mapper for returnTypeClass was not found, no action taken.
+ */
+ public static Class<? extends RowMapper> replaceRowMapping(Class returnTypeClass, Class<? extends RowMapper> rowMapperClass) {
+ return _rowMappings.put(returnTypeClass, rowMapperClass);
+ }
+
+ /**
+ * remove the row mapping for the specified class type.
+ *
+ * @param returnTypeClass
+ * @return the RowMapper class which was removed, null if returnTypeClass did not match any of the registered
+ * row mappers.
+ */
+ public static Class<? extends RowMapper> removeRowMapping(Class returnTypeClass) {
+ return _rowMappings.remove(returnTypeClass);
+ }
+
+ /**
+ * Sets the rowmapper for Object.class
+ *
+ * @param rowMapperClass
+ */
+ public static Class <? extends RowMapper> setDefaultRowMapping(Class<? extends RowMapper> rowMapperClass) {
+ Class<? extends RowMapper> ret = DEFAULT_OBJ_ROWMAPPING;
+ DEFAULT_OBJ_ROWMAPPING = rowMapperClass;
+ return ret;
+ }
+
+ /**
+ * Sets the rowmapper for XmlObject.class
+ *
+ * @param rowMapperClass
+ */
+ public static Class<? extends RowMapper> setDefaultXmlRowMapping(Class mapToClass, Class<? extends RowMapper> rowMapperClass) {
+ Class<? extends RowMapper> ret = DEFAULT_XMLOBJ_ROWMAPPING;
+ DEFAULT_XMLOBJ_ROWMAPPING = rowMapperClass;
+ XMLOBJ_CLASS = mapToClass;
+ return ret;
+ }
+
+ /**
+ * Create an instance of the RowMapper class.
+ *
+ * @param rowMapper
+ * @param rs ResultSet we are mapping from.
+ * @param returnType Class to map rows to.
+ * @param cal Calendar instance for date/time values.
+ * @return A RowMapper instance.
+ */
+ private static RowMapper getMapper(Class<? extends RowMapper> rowMapper, ResultSet rs, Class returnType, Calendar cal)
+ {
+ Constructor c = null;
+ try {
+ c = rowMapper.getDeclaredConstructor(_params);
+ return (RowMapper) c.newInstance(new Object[]{rs, returnType, cal});
+ } catch (NoSuchMethodException e) {
+ throw new ControlException("Failure creating new instance of RowMapper, " + e.toString(), e);
+ } catch (InstantiationException e) {
+ throw new ControlException("Failure creating new instance of RowMapper, " + e.toString(), e);
+ } catch (IllegalAccessException e) {
+ throw new ControlException("Failure creating new instance of RowMapper, " + e.toString(), e);
+ } catch (InvocationTargetException e) {
+ throw new ControlException("Failure creating new instance of RowMapper, " + e.getCause().toString(), e);
+ }
+ }
+}
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToHashMapMapper.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToHashMapMapper.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToHashMapMapper.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToHashMapMapper.java Mon May 9 13:17:58 2005
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Calendar;
+
+/**
+ * Map a ResultSet row to a java.util.HashMap object
+ */
+public final class RowToHashMapMapper extends RowMapper {
+
+ private final String[] _keys;
+
+
+ /**
+ * Create a new RowToHashMapMapper.
+ * @param resultSet ResultSet to map
+ * @param returnTypeClass Class to map to.
+ * @param cal Calendar instance for date/time mappings.
+ */
+ RowToHashMapMapper(ResultSet resultSet, Class returnTypeClass, Calendar cal) {
+ super(resultSet, returnTypeClass, cal);
+ try {
+ _keys = getKeysFromResultSet();
+ } catch (SQLException sql) {
+ throw new ControlException("RowToHashMapMapper: SQLException: " + sql.getMessage(), sql);
+ }
+ }
+
+ /**
+ * Do the mapping.
+ * @return A ResultSetHashMap object.
+ * @throws ControlException on error.
+ */
+ public Object mapRowToReturnType() {
+ try {
+ return new ResultSetHashMap(_resultSet, _keys);
+ } catch (SQLException e) {
+ throw new ControlException("Exception creating HashMap return type: ", e);
+ }
+ }
+}
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToMapMapper.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToMapMapper.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToMapMapper.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToMapMapper.java Mon May 9 13:17:58 2005
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.Calendar;
+
+/**
+ * Map a ResultSet row to a java.util.Map object.
+ */
+public final class RowToMapMapper extends RowMapper {
+
+ private final String[] _keys;
+
+ /**
+ * Create a new RowToMapMapper.
+ * @param resultSet ResultSet to map
+ * @param returnTypeClass Class to map to.
+ * @param cal Calendar instance for date/time mappings.
+ */
+ RowToMapMapper(ResultSet resultSet, Class returnTypeClass, Calendar cal) {
+ super(resultSet, returnTypeClass, cal);
+ try {
+ _keys = getKeysFromResultSet();
+ } catch (SQLException e) {
+ throw new ControlException("RowToMapMapper: SQLException: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Do the mapping.
+ * @return A Map.
+ * @throws ControlException on error.
+ */
+ public Object mapRowToReturnType() {
+ try {
+ return Collections.unmodifiableMap(new ResultSetHashMap(_resultSet, _keys));
+ } catch (SQLException e) {
+ throw new ControlException("Exception while creating ResultSetHashMap.", e);
+ }
+ }
+}
Added: incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToObjectMapper.java
URL: http://svn.apache.org/viewcvs/incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToObjectMapper.java?rev=169351&view=auto
==============================================================================
--- incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToObjectMapper.java (added)
+++ incubator/beehive/trunk/system-controls/src/jdbc/org/apache/beehive/controls/system/jdbc/RowToObjectMapper.java Mon May 9 13:17:58 2005
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * $Header:$
+ */
+
+package org.apache.beehive.controls.system.jdbc;
+
+import org.apache.beehive.controls.api.ControlException;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.util.Calendar;
+import java.util.HashMap;
+
+/**
+ * Map a ResultSet row to an Object. This mapper uses Java reflection to perform the mapping. The Class being mapped
+ * to must have setter methods which match the ResultSet column names. For example, if a column in the ResultSet
+ * named USERID, the object must have a setter method named setUserid(). If a setter method cannot be class fields
+ * are also checked, the same naming conventions applies, USERID -> userid.
+ */
+public class RowToObjectMapper extends RowMapper {
+
+ private final int _columnCount;
+
+ private AccessibleObject[] _fields;
+ private int[] _fieldTypes;
+
+ private final Object[] _args = new Object[1];
+
+ /**
+ * Create a new RowToObjectMapper.
+ *
+ * @param resultSet ResultSet to map
+ * @param returnTypeClass Class to map to.
+ * @param cal Calendar instance for date/time mappings.
+ */
+ RowToObjectMapper(ResultSet resultSet, Class returnTypeClass, Calendar cal) {
+ super(resultSet, returnTypeClass, cal);
+
+ _fields = null;
+
+ try {
+ _columnCount = resultSet.getMetaData().getColumnCount();
+ } catch (SQLException e) {
+ throw new ControlException("RowToObjectMapper: SQLException: " + e.getMessage(), e);
+ }
+ }
+
+ /**
+ * Do the mapping.
+ *
+ * @return An object instance.
+ */
+ public Object mapRowToReturnType() {
+
+ Object resultObject = null;
+
+ // if the ResultSet only contains a single column we may be able to map directly
+ // to the return type -- if so we don't need to build any structures to support
+ // mapping
+ if (_columnCount == 1) {
+
+ final int typeId = _tmf.getTypeId(_returnTypeClass);
+
+ try {
+ if (typeId != TypeMappingsFactory.TYPE_UNKNOWN) {
+ return extractColumnValue(1, typeId);
+ } else {
+ // we still might want a single value (i.e. java.util.Date)
+ Object val = extractColumnValue(1, typeId);
+ if (_returnTypeClass.isAssignableFrom(val.getClass())) {
+ return val;
+ }
+ }
+ } catch (SQLException e) {
+ throw new ControlException(e.getMessage(), e);
+ }
+ }
+
+ if (_fields == null) {
+ try {
+ getFieldMappings();
+ } catch (SQLException e) {
+ throw new ControlException(e.getMessage(), e);
+ }
+ }
+
+ try {
+ resultObject = _returnTypeClass.newInstance();
+ } catch (InstantiationException e) {
+ throw new ControlException("InstantiationException when trying to create instance of : "
+ + _returnTypeClass.getName(), e);
+ } catch (IllegalAccessException e) {
+ throw new ControlException("IllegalAccessException when trying to create instance of : "
+ + _returnTypeClass.getName(), e);
+ }
+
+ for (int i = 1; i < _fields.length; i++) {
+ AccessibleObject f = _fields[i];
+ Object resultValue = null;
+
+ try {
+ resultValue = extractColumnValue(i, _fieldTypes[i]);
+ if (f instanceof Field) {
+ ((Field) f).set(resultObject, resultValue);
+ } else {
+ _args[0] = resultValue;
+ ((Method) f).invoke(resultObject, _args);
+ }
+ } catch (SQLException e) {
+ throw new ControlException(e.getMessage(), e);
+ } catch (IllegalArgumentException iae) {
+
+ try {
+ ResultSetMetaData md = _resultSet.getMetaData();
+ if (f instanceof Field) {
+ throw new ControlException("The declared Java type for field " + ((Field) f).getName()
+ + ((Field) f).getType().toString()
+ + " is incompatible with the SQL format of column " + md.getColumnName(i).toString()
+ + md.getColumnTypeName(i).toString()
+ + " which returns objects of type " + resultValue.getClass().getName());
+ } else {
+ throw new ControlException("The declared Java type for method " + ((Method) f).getName()
+ + ((Method) f).getParameterTypes()[0].toString()
+ + " is incompatible with the SQL format of column " + md.getColumnName(i).toString()
+ + md.getColumnTypeName(i).toString()
+ + " which returns objects of type " + resultValue.getClass().getName());
+ }
+ } catch (SQLException e) {
+ throw new ControlException(e.getMessage(), e);
+ }
+
+ } catch (IllegalAccessException e) {
+ if (f instanceof Field) {
+ throw new ControlException("IllegalAccessException when trying to access field " + ((Field) f).getName(), e);
+ } else {
+ throw new ControlException("IllegalAccessException when trying to access method " + ((Method) f).getName(), e);
+ }
+ } catch (InvocationTargetException e) {
+ if (f instanceof Field) {
+ throw new ControlException("InvocationTargetException when trying to access field " + ((Field) f).getName(), e);
+ } else {
+ throw new ControlException("InvocationTargetException when trying to access method " + ((Method) f).getName(), e);
+ }
+ }
+ }
+ return resultObject;
+ }
+
+ /**
+ * Build the structures necessary to do the mapping
+ *
+ * @throws SQLException on error.
+ */
+ protected void getFieldMappings()
+ throws SQLException {
+
+ final String[] keys = getKeysFromResultSet();
+
+ //
+ // find fields or setters for return class
+ //
+ HashMap<String, AccessibleObject> mapFields = new HashMap<String, AccessibleObject>(_columnCount * 2);
+ for (int i = 1; i <= _columnCount; i++) {
+ mapFields.put(keys[i], null);
+ }
+
+ // public methods
+ Method[] classMethods = _returnTypeClass.getMethods();
+ for (Method m : classMethods) {
+
+ if (isSetterMethod(m)) {
+ final String fieldName = m.getName().substring(3).toUpperCase();
+ if (mapFields.containsKey(fieldName)) {
+
+ // check for overloads
+ Object field = mapFields.get(fieldName);
+ if (field == null) {
+ mapFields.put(fieldName, m);
+ } else {
+ throw new ControlException("Unable to choose between overloaded methods " + m.getName()
+ + " on the " + _returnTypeClass.getName() + " class. Mapping is done using "
+ + "a case insensitive comparision of SQL ResultSet columns to field "
+ + "names and public setter methods on the return class.");
+ }
+ }
+ }
+ }
+
+ // fix for 8813: include inherited and non-public fields
+ for (Class clazz = _returnTypeClass; clazz != null && clazz != Object.class; clazz = clazz.getSuperclass()) {
+ Field[] classFields = clazz.getDeclaredFields();
+ for (Field f : classFields) {
+ if (Modifier.isStatic(f.getModifiers())) continue;
+ if (!Modifier.isPublic(f.getModifiers())) continue;
+ String fieldName = f.getName().toUpperCase();
+ if (!mapFields.containsKey(fieldName)) continue;
+
+ Object field = mapFields.get(fieldName);
+ if (field == null) {
+ mapFields.put(fieldName, f);
+ }
+ }
+ }
+
+ // finally actually init the fields array
+ _fields = new AccessibleObject[_columnCount + 1];
+ _fieldTypes = new int[_columnCount + 1];
+
+ for (int i = 1; i < _fields.length; i++) {
+ AccessibleObject f = mapFields.get(keys[i]);
+ if (f == null) {
+ throw new ControlException("Unable to map the SQL column " + keys[i]
+ + " to a field on the " + _returnTypeClass.getName() +
+ " class. Mapping is done using a case insensitive comparision of SQL ResultSet "
+ + "columns to field names and public setter methods on the return class.");
+ }
+
+ _fields[i] = f;
+ if (f instanceof Field) {
+ _fieldTypes[i] = _tmf.getTypeId(((Field) f).getType());
+ } else {
+ _fieldTypes[i] = _tmf.getTypeId(((Method) f).getParameterTypes()[0]);
+ }
+ }
+ }
+}