Source Code Cross Referenced for JdbcControlImpl.java in  » Library » Apache-beehive-1.0.2-src » org » apache » beehive » controls » system » jdbc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache beehive 1.0.2 src » org.apache.beehive.controls.system.jdbc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *     http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         *
017:         * $Header:$
018:         */
019:        package org.apache.beehive.controls.system.jdbc;
020:
021:        import java.lang.reflect.Method;
022:        import java.sql.CallableStatement;
023:        import java.sql.Connection;
024:        import java.sql.DatabaseMetaData;
025:        import java.sql.DriverManager;
026:        import java.sql.PreparedStatement;
027:        import java.sql.ResultSet;
028:        import java.sql.SQLException;
029:        import java.util.Calendar;
030:        import java.util.HashMap;
031:        import java.util.Iterator;
032:        import java.util.Map;
033:        import java.util.Properties;
034:        import java.util.Vector;
035:        import javax.naming.NamingException;
036:        import javax.naming.Context;
037:        import javax.sql.DataSource;
038:
039:        import org.apache.beehive.controls.api.ControlException;
040:        import org.apache.beehive.controls.api.bean.ControlImplementation;
041:        import org.apache.beehive.controls.api.bean.Extensible;
042:        import org.apache.beehive.controls.api.context.ControlBeanContext;
043:        import org.apache.beehive.controls.api.context.ResourceContext;
044:        import org.apache.beehive.controls.api.context.ResourceContext.ResourceEvents;
045:        import org.apache.beehive.controls.api.events.EventHandler;
046:        import org.apache.beehive.controls.system.jdbc.parser.SqlParser;
047:        import org.apache.beehive.controls.system.jdbc.parser.SqlStatement;
048:        import org.apache.commons.logging.Log;
049:        import org.apache.commons.logging.LogFactory;
050:
051:        /**
052:         * The implementation class for the database controller.
053:         */
054:        @ControlImplementation
055:        public class JdbcControlImpl implements  JdbcControl, Extensible,
056:                java.io.Serializable {
057:
058:            //
059:            // contexts provided by the beehive controls runtime
060:            //
061:            @org.apache.beehive.controls.api.context.Context
062:            protected ControlBeanContext _context;
063:            @org.apache.beehive.controls.api.context.Context
064:            protected ResourceContext _resourceContext;
065:
066:            protected transient Connection _connection;
067:            protected transient ConnectionDataSource _connectionDataSource;
068:            protected transient DataSource _dataSource;
069:            protected transient ConnectionDriver _connectionDriver;
070:
071:            private Calendar _cal;
072:            private transient Vector<PreparedStatement> _resources;
073:
074:            private static final String EMPTY_STRING = "";
075:            private static final Log LOGGER = LogFactory
076:                    .getLog(JdbcControlImpl.class);
077:            private static final ResultSetMapper DEFAULT_MAPPER = new DefaultObjectResultSetMapper();
078:            private static final SqlParser _sqlParser = new SqlParser();
079:
080:            protected static final HashMap<Class, ResultSetMapper> _resultMappers = new HashMap<Class, ResultSetMapper>();
081:            protected static Class<?> _xmlObjectClass;
082:
083:            //
084:            // initialize the result mapper table
085:            //
086:            static {
087:                _resultMappers.put(ResultSet.class,
088:                        new DefaultResultSetMapper());
089:                _resultMappers.put(Iterator.class,
090:                        new DefaultIteratorResultSetMapper());
091:
092:                try {
093:                    _xmlObjectClass = Class
094:                            .forName("org.apache.xmlbeans.XmlObject");
095:                    _resultMappers.put(_xmlObjectClass,
096:                            new DefaultXmlObjectResultSetMapper());
097:                } catch (ClassNotFoundException e) {
098:                    // noop: OK if not found, just can't support mapping to an XmlObject
099:                }
100:            }
101:
102:            /**
103:             * Constructor
104:             */
105:            public JdbcControlImpl() {
106:            }
107:
108:            /**
109:             * Invoked by the controls runtime when a new instance of this class is aquired by the runtime
110:             */
111:            @EventHandler(field="_resourceContext",eventSet=ResourceEvents.class,eventName="onAcquire")
112:            public void onAquire() {
113:
114:                if (LOGGER.isDebugEnabled()) {
115:                    LOGGER.debug("Enter: onAquire()");
116:                }
117:
118:                try {
119:                    getConnection();
120:                } catch (SQLException se) {
121:                    throw new ControlException(
122:                            "SQL Exception while attempting to connect to database.",
123:                            se);
124:                }
125:            }
126:
127:            /**
128:             * Invoked by the controls runtime when an instance of this class is released by the runtime
129:             */
130:            @EventHandler(field="_resourceContext",eventSet=ResourceContext.ResourceEvents.class,eventName="onRelease")
131:            public void onRelease() {
132:
133:                if (LOGGER.isDebugEnabled()) {
134:                    LOGGER.debug("Enter: onRelease()");
135:                }
136:
137:                for (PreparedStatement ps : getResources()) {
138:                    try {
139:                        ps.close();
140:                    } catch (SQLException sqe) {
141:                    }
142:                }
143:                getResources().clear();
144:
145:                if (_connection != null) {
146:                    try {
147:                        _connection.close();
148:                    } catch (SQLException e) {
149:                        throw new ControlException(
150:                                "SQL Exception while attempting to close database connection.",
151:                                e);
152:                    }
153:                }
154:
155:                _connection = null;
156:                _connectionDataSource = null;
157:                _connectionDriver = null;
158:            }
159:
160:            /**
161:             * Returns a database connection to the server associated with the control.
162:             * The connection type is specified by a ConnectionDataSource or ConnectionDriver annotation on the control class
163:             * which extends this control.
164:             * <p/>
165:             * It is typically not necessary to call this method when using the control.
166:             */
167:            public Connection getConnection() throws SQLException {
168:
169:                if (_connection == null) {
170:
171:                    _connectionDataSource = _context
172:                            .getControlPropertySet(ConnectionDataSource.class);
173:                    _connectionDriver = _context
174:                            .getControlPropertySet(ConnectionDriver.class);
175:                    final ConnectionOptions connectionOptions = _context
176:                            .getControlPropertySet(ConnectionOptions.class);
177:
178:                    if (_connectionDataSource != null
179:                            && _connectionDataSource.jndiName() != null) {
180:                        _connection = getConnectionFromDataSource(
181:                                _connectionDataSource.jndiName(),
182:                                _connectionDataSource.jndiContextFactory());
183:
184:                    } else if (_connectionDriver != null
185:                            && _connectionDriver.databaseDriverClass() != null) {
186:                        _connection = getConnectionFromDriverManager(
187:                                _connectionDriver.databaseDriverClass(),
188:                                _connectionDriver.databaseURL(),
189:                                _connectionDriver.userName(), _connectionDriver
190:                                        .password(), _connectionDriver
191:                                        .properties());
192:                    } else {
193:                        throw new ControlException("no @\'"
194:                                + ConnectionDataSource.class.getName()
195:                                + "\' or \'" + ConnectionDriver.class.getName()
196:                                + "\' property found.");
197:                    }
198:
199:                    //
200:                    // set any specifed connection options
201:                    //
202:                    if (connectionOptions != null) {
203:
204:                        if (_connection.isReadOnly() != connectionOptions
205:                                .readOnly()) {
206:                            _connection.setReadOnly(connectionOptions
207:                                    .readOnly());
208:                        }
209:
210:                        DatabaseMetaData dbMetadata = _connection.getMetaData();
211:
212:                        final HoldabilityType holdability = connectionOptions
213:                                .resultSetHoldability();
214:                        if (holdability != HoldabilityType.DRIVER_DEFAULT) {
215:                            if (dbMetadata
216:                                    .supportsResultSetHoldability(holdability
217:                                            .getHoldability())) {
218:                                _connection.setHoldability(holdability
219:                                        .getHoldability());
220:                            } else {
221:                                throw new ControlException(
222:                                        "Database does not support ResultSet holdability type: "
223:                                                + holdability.toString());
224:                            }
225:                        }
226:
227:                        setTypeMappers(connectionOptions.typeMappers());
228:                    }
229:                }
230:
231:                return _connection;
232:            }
233:
234:            /**
235:             * Called by the Controls runtime to handle calls to methods of an extensible control.
236:             *
237:             * @param method The extended operation that was called.
238:             * @param args   Parameters of the operation.
239:             * @return The value that should be returned by the operation.
240:             * @throws Throwable any exception declared on the extended operation may be
241:             *                   thrown.  If a checked exception is thrown from the implementation that is not declared
242:             *                   on the original interface, it will be wrapped in a ControlException.
243:             */
244:            public Object invoke(Method method, Object[] args) throws Throwable {
245:
246:                if (LOGGER.isDebugEnabled()) {
247:                    LOGGER.debug("Enter: invoke()");
248:                }
249:                assert _connection.isClosed() == false : "invoke(): JDBC Connection has been closed!!!!";
250:                return execPreparedStatement(method, args);
251:            }
252:
253:            /**
254:             * Sets the {@link Calendar} used when working with time/date types
255:             */
256:            public void setDataSourceCalendar(Calendar cal) {
257:                _cal = (Calendar) cal.clone();
258:            }
259:
260:            /**
261:             * Returns the {@link Calendar} used when working with time/date types.
262:             *
263:             * @return the {@link Calendar} to use with this {@link DataSource}
264:             */
265:            public Calendar getDataSourceCalendar() {
266:                return _cal;
267:            }
268:
269:            // /////////////////////////////////////////// Protected Methods ////////////////////////////////////////////
270:
271:            /**
272:             * Create and exec a {@link PreparedStatement}
273:             *
274:             * @param method the method to invoke
275:             * @param args the method's arguments
276:             * @return the return value from the {@link PreparedStatement}
277:             * @throws Throwable any exception that occurs; the caller should handle these appropriately
278:             */
279:            protected Object execPreparedStatement(Method method, Object[] args)
280:                    throws Throwable {
281:
282:                final SQL methodSQL = (SQL) _context.getMethodPropertySet(
283:                        method, SQL.class);
284:                if (methodSQL == null || methodSQL.statement() == null) {
285:                    throw new ControlException("Method " + method.getName()
286:                            + " is missing @SQL annotation");
287:                }
288:
289:                setTypeMappers(methodSQL.typeMappersOverride());
290:
291:                //
292:                // build the statement and execute it
293:                //
294:
295:                PreparedStatement ps = null;
296:                try {
297:                    Class returnType = method.getReturnType();
298:
299:                    SqlStatement sqlStatement = _sqlParser.parse(methodSQL
300:                            .statement());
301:                    ps = sqlStatement.createPreparedStatement(_context,
302:                            _connection, _cal, method, args);
303:
304:                    if (LOGGER.isInfoEnabled()) {
305:                        LOGGER.info("PreparedStatement: "
306:                                + sqlStatement.createPreparedStatementString(
307:                                        _context, _connection, method, args));
308:                    }
309:
310:                    //
311:                    // special processing for batch updates
312:                    //
313:                    if (sqlStatement.isBatchUpdate()) {
314:                        return ps.executeBatch();
315:                    }
316:
317:                    //
318:                    // execute the statement
319:                    //
320:                    boolean hasResults = ps.execute();
321:
322:                    //
323:                    // callable statement processing
324:                    //
325:                    if (sqlStatement.isCallableStatement()) {
326:                        SQLParameter[] params = (SQLParameter[]) args[0];
327:                        for (int i = 0; i < params.length; i++) {
328:                            if (params[i].dir != SQLParameter.IN) {
329:                                params[i].value = ((CallableStatement) ps)
330:                                        .getObject(i + 1);
331:                            }
332:                        }
333:                        return null;
334:                    }
335:
336:                    //
337:                    // process returned data
338:                    //
339:                    ResultSet rs = null;
340:                    int updateCount = ps.getUpdateCount();
341:
342:                    if (hasResults) {
343:                        rs = ps.getResultSet();
344:                    }
345:
346:                    if (sqlStatement.getsGeneratedKeys()) {
347:                        rs = ps.getGeneratedKeys();
348:                        hasResults = true;
349:                    }
350:
351:                    if (!hasResults && updateCount > -1) {
352:                        boolean moreResults = ps.getMoreResults();
353:                        int tempUpdateCount = ps.getUpdateCount();
354:
355:                        while ((moreResults && rs == null)
356:                                || tempUpdateCount > -1) {
357:                            if (moreResults) {
358:                                rs = ps.getResultSet();
359:                                hasResults = true;
360:                                moreResults = false;
361:                                tempUpdateCount = -1;
362:                            } else {
363:                                moreResults = ps.getMoreResults();
364:                                tempUpdateCount = ps.getUpdateCount();
365:                            }
366:                        }
367:                    }
368:
369:                    Object returnObject = null;
370:                    if (hasResults) {
371:
372:                        //
373:                        // if a result set mapper was specified in the methods annotation, use it
374:                        // otherwise find the mapper for the return type in the hashmap
375:                        //
376:                        final Class resultSetMapperClass = methodSQL
377:                                .resultSetMapper();
378:                        final ResultSetMapper rsm;
379:                        if (!UndefinedResultSetMapper.class
380:                                .isAssignableFrom(resultSetMapperClass)) {
381:                            if (ResultSetMapper.class
382:                                    .isAssignableFrom(resultSetMapperClass)) {
383:                                rsm = (ResultSetMapper) resultSetMapperClass
384:                                        .newInstance();
385:                            } else {
386:                                throw new ControlException(
387:                                        "Result set mappers must be subclasses of ResultSetMapper.class!");
388:                            }
389:                        } else {
390:                            if (_resultMappers.containsKey(returnType)) {
391:                                rsm = _resultMappers.get(returnType);
392:                            } else {
393:                                if (_xmlObjectClass != null
394:                                        && _xmlObjectClass
395:                                                .isAssignableFrom(returnType)) {
396:                                    rsm = _resultMappers.get(_xmlObjectClass);
397:                                } else {
398:                                    rsm = DEFAULT_MAPPER;
399:                                }
400:                            }
401:                        }
402:
403:                        returnObject = rsm.mapToResultType(_context, method,
404:                                rs, _cal);
405:                        if (rsm.canCloseResultSet() == false) {
406:                            getResources().add(ps);
407:                        }
408:
409:                        //
410:                        // empty ResultSet
411:                        //
412:                    } else {
413:                        if (returnType.equals(Void.TYPE)) {
414:                            returnObject = null;
415:                        } else if (returnType.equals(Integer.TYPE)) {
416:                            returnObject = new Integer(updateCount);
417:                        } else if (!sqlStatement.isCallableStatement()) {
418:                            throw new ControlException("Method "
419:                                    + method.getName()
420:                                    + "is DML but does not return void or int");
421:                        }
422:                    }
423:                    return returnObject;
424:
425:                } finally {
426:                    // Keep statements open that have in-use result sets
427:                    if (ps != null && !getResources().contains(ps)) {
428:                        ps.close();
429:                    }
430:                }
431:            }
432:
433:            // /////////////////////////////////////////// Private Methods ////////////////////////////////////////////
434:
435:            /**
436:             * Get a connection from a DataSource.
437:             *
438:             * @param jndiName    Specifed in the subclasse's ConnectionDataSource annotation
439:             * @param jndiFactory Specified in the subclasse's ConnectionDataSource Annotation.
440:             * @return null if a connection cannot be established
441:             * @throws SQLException
442:             */
443:            private Connection getConnectionFromDataSource(String jndiName,
444:                    Class<? extends JdbcControl.JndiContextFactory> jndiFactory)
445:                    throws SQLException {
446:
447:                Connection con = null;
448:                try {
449:                    JndiContextFactory jf = (JndiContextFactory) jndiFactory
450:                            .newInstance();
451:                    Context jndiContext = jf.getContext();
452:                    _dataSource = (DataSource) jndiContext.lookup(jndiName);
453:                    con = _dataSource.getConnection();
454:                } catch (IllegalAccessException iae) {
455:                    throw new ControlException("IllegalAccessException:", iae);
456:                } catch (InstantiationException ie) {
457:                    throw new ControlException("InstantiationException:", ie);
458:                } catch (NamingException ne) {
459:                    throw new ControlException("NamingException:", ne);
460:                }
461:                return con;
462:            }
463:
464:            /**
465:             * Get a JDBC connection from the DriverManager.
466:             *
467:             * @param dbDriverClassName Specified in the subclasse's ConnectionDriver annotation.
468:             * @param dbUrlStr          Specified in the subclasse's ConnectionDriver annotation.
469:             * @param userName          Specified in the subclasse's ConnectionDriver annotation.
470:             * @param password          Specified in the subclasse's ConnectionDriver annotation.
471:             * @return null if a connection cannot be established.
472:             * @throws SQLException
473:             */
474:            private Connection getConnectionFromDriverManager(
475:                    String dbDriverClassName, String dbUrlStr, String userName,
476:                    String password, String propertiesString)
477:                    throws SQLException {
478:
479:                Connection con = null;
480:                try {
481:                    Class.forName(dbDriverClassName);
482:                    if (!EMPTY_STRING.equals(userName)) {
483:                        con = DriverManager.getConnection(dbUrlStr, userName,
484:                                password);
485:                    } else if (!EMPTY_STRING.equals(propertiesString)) {
486:                        Properties props = parseProperties(propertiesString);
487:                        if (props == null) {
488:                            throw new ControlException(
489:                                    "Invalid properties annotation value: "
490:                                            + propertiesString);
491:                        }
492:                        con = DriverManager.getConnection(dbUrlStr, props);
493:                    } else {
494:                        con = DriverManager.getConnection(dbUrlStr);
495:                    }
496:                } catch (ClassNotFoundException e) {
497:                    throw new ControlException(
498:                            "Database driver class not found!", e);
499:                }
500:                return con;
501:            }
502:
503:            /**
504:             * Get the Vector of Statements which we need to keep open.
505:             * @return Vector of PreparedStatement
506:             */
507:            private Vector<PreparedStatement> getResources() {
508:                if (_resources == null) {
509:                    _resources = new Vector<PreparedStatement>();
510:                }
511:                return _resources;
512:            }
513:
514:            /**
515:             * Parse the propertiesString into a Properties object.  The string must have the format of:
516:             * propertyName=propertyValue;propertyName=propertyValue;...
517:             *
518:             * @param propertiesString
519:             * @return A Properties instance or null if parse fails
520:             */
521:            private Properties parseProperties(String propertiesString) {
522:                Properties properties = null;
523:                String[] propPairs = propertiesString.split(";");
524:                if (propPairs.length > 0) {
525:                    properties = new Properties();
526:                    for (String propPair : propPairs) {
527:                        int eq = propPair.indexOf('=');
528:                        assert eq > -1 : "Invalid properties syntax: "
529:                                + propertiesString;
530:                        properties.put(propPair.substring(0, eq), propPair
531:                                .substring(eq + 1, propPair.length()));
532:                    }
533:                }
534:                return properties;
535:            }
536:
537:            /**
538:             * Set any custom type mappers specifed in the annotation for the connection.  Used for mapping SQL UDTs to
539:             * java classes.
540:             *
541:             * @param typeMappers An array of TypeMapper.
542:             */
543:            private void setTypeMappers(TypeMapper[] typeMappers)
544:                    throws SQLException {
545:
546:                if (typeMappers.length > 0) {
547:                    Map<String, Class<?>> mappers = _connection.getTypeMap();
548:                    for (TypeMapper t : typeMappers) {
549:                        mappers.put(t.UDTName(), t.mapperClass());
550:                    }
551:                    _connection.setTypeMap(mappers);
552:                }
553:            }
554:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.