Source Code Cross Referenced for SQLCache.java in  » RSS-RDF » Jena-2.5.5 » com » hp » hpl » jena » db » impl » 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 » RSS RDF » Jena 2.5.5 » com.hp.hpl.jena.db.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *  (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
003:         *  All rights reserved.
004:         *
005:         */
006:
007:        //=======================================================================
008:        // Package
009:        package com.hp.hpl.jena.db.impl;
010:
011:        //=======================================================================
012:        // Imports
013:        import java.sql.*;
014:        import java.util.*;
015:        import java.io.*;
016:
017:        import com.hp.hpl.jena.db.*;
018:        import com.hp.hpl.jena.shared.JenaException;
019:        import com.hp.hpl.jena.util.CollectionFactory;
020:
021:        import org.apache.commons.logging.Log;
022:        import org.apache.commons.logging.LogFactory;
023:
024:        //=======================================================================
025:        /**
026:         * Stores a set of sql statements loaded from a resource file.
027:         * Caches prepared versions of the statements for a given db connection.
028:         * <p>
029:         * The resource file is located on the classpath and has the format:
030:         * <pre>
031:         * # comment at start of line
032:         * operationName1
033:         * sql code line 1
034:         * ...
035:         * sql code last line
036:         *
037:         * operationName2
038:         * ...
039:         * </pre>
040:         * where the blank lines delimit one sql block from the next.
041:         * <p>The sql code is typically a single SQL statement but some operations,
042:         * specifically database initialization and cleanup may require a variable number
043:         * of statments. To cater for this terminate each statement in those groups with
044:         * the string ";;". Note that a single ";" is not used because these compound
045:         * statements are often stored procedure definitions which end to have ";" line
046:         * terminators!
047:         *
048:         * @author <a href="mailto:der@hplb.hpl.hp.com">Dave Reynolds</a>.  Updated by hkuno to support GraphRDB.
049:         * @version $Revision: 1.18 $ on $Date: 2008/01/02 12:08:23 $
050:         */
051:
052:        public class SQLCache {
053:
054:            //=======================================================================
055:            // Variables
056:
057:            /** Set of sql statements indexed by operation name. */
058:            protected Properties m_sql;
059:
060:            /** Cache of prepared versions of the statements. Each map entry is a list
061:             *  of copies of the prepared statement for multi-threaded apps. */
062:            protected Map m_preparedStatements = CollectionFactory
063:                    .createHashedMap();
064:
065:            /** Track which cached, prepared statements are in use and the corresponding
066:             *  list to which the statement should be returned. */
067:            protected Map m_cachedStmtInUse = CollectionFactory
068:                    .createHashedMap();
069:
070:            /** the packaged jdbc connection to the database itself. */
071:            protected IDBConnection m_connection;
072:
073:            /** Maximum number of pre-prepared statements to keep for each operator. */
074:            protected static final int MAX_PS_CACHE = 4;
075:
076:            /** Set to true to enable cache of pre-prepared statements. */
077:            protected boolean CACHE_PREPARED_STATEMENTS = true;
078:
079:            static protected Log logger = LogFactory.getLog(SQLCache.class);
080:
081:            //=======================================================================
082:            // Public interface
083:
084:            /**
085:             * Constructor. Creates a new cache sql statements for interfacing to
086:             * a specific database.
087:             * @param sqlFile the name of the file of sql statements to load, this is
088:             * loaded from the classpath.
089:             * @param defaultOps Properties table which provides the default
090:             * sql statements, any definitions of a given operation in the loaded file
091:             * will override the default.
092:             * @param connection the jdbc connection to the database itself
093:             * @param idType the sql string to use for id types (substitutes for $id in files)
094:             */
095:            public SQLCache(String sqlFile, Properties defaultOps,
096:                    IDBConnection connection, String idType) throws IOException {
097:                m_sql = loadSQLFile(sqlFile, defaultOps, idType);
098:                m_connection = connection;
099:            }
100:
101:            /**
102:             * Set to true to enable cache of pre-prepared statements.
103:             */
104:            public void setCachePreparedStatements(boolean state) {
105:                CACHE_PREPARED_STATEMENTS = state;
106:            }
107:
108:            /**
109:             * Return true if cache of pre-prepared statements is enabled.
110:             */
111:            public boolean getCachePreparedStatements() {
112:                return CACHE_PREPARED_STATEMENTS;
113:            }
114:
115:            /**
116:             * Flush the cache of all currently prepared statements.
117:             */
118:            public void flushPreparedStatementCache() throws RDFRDBException {
119:                try {
120:                    Iterator it = m_preparedStatements.values().iterator();
121:                    while (it.hasNext()) {
122:                        Iterator psit = ((List) it.next()).iterator();
123:                        while (psit.hasNext()) {
124:                            ((PreparedStatement) psit.next()).close();
125:                        }
126:                    }
127:                } catch (SQLException e) {
128:                    throw new RDFRDBException("Problem flushing PS cache", e);
129:                } finally {
130:                    m_preparedStatements = CollectionFactory.createHashedMap();
131:                    m_cachedStmtInUse = CollectionFactory.createHashedMap();
132:                }
133:            }
134:
135:            /**
136:             * Return the associated jdbc connection.
137:             */
138:            public Connection getConnection() throws SQLException {
139:                return m_connection.getConnection();
140:            }
141:
142:            /**
143:             * Set the associated jdbc connection.
144:             */
145:            public void setConnection(IDBConnection connection) {
146:                m_connection = connection;
147:            }
148:
149:            /**
150:             * Return the raw SQL statement corresponding to the named operation.
151:             */
152:            public String getSQLStatement(String opname) throws SQLException {
153:                return getSQLStatement(opname, (String[]) null);
154:            }
155:
156:            /**
157:             * Return the raw SQL statement corresponding to the named operation.
158:             * Substitute the ${a} attribute macro for the current attribute number.
159:             */
160:            public String getSQLStatement(String opname, String[] attr)
161:                    throws SQLException {
162:                String cmd = m_sql.getProperty(opname);
163:                if (cmd == null) {
164:                    if (opname.startsWith("*")) {
165:                        cmd = genSQLStatement(opname);
166:                        m_sql.setProperty(opname, cmd);
167:                    } else {
168:                        logger.error("Unable to find SQL for operation: "
169:                                + opname);
170:                        throw new SQLException(
171:                                "Unable to find SQL for operation: " + opname);
172:                    }
173:                }
174:                int attrCnt = (attr == null) ? 0 : attr.length;
175:                if (attrCnt > 0)
176:                    cmd = substitute(cmd, "${a}", attr[0]);
177:                if (attrCnt > 1)
178:                    cmd = substitute(cmd, "${b}", attr[1]);
179:                if (attrCnt > 2)
180:                    cmd = substitute(cmd, "${c}", attr[2]);
181:                if (attrCnt > 3)
182:                    throw new JenaException("Too many arguments");
183:
184:                return cmd;
185:            }
186:
187:            public String getSQLStatement(String opname, String attr)
188:                    throws SQLException {
189:                String[] param = { attr };
190:                return getSQLStatement(opname, param);
191:            }
192:
193:            /**
194:             * Return the raw SQL statement corresponding to the named operation.
195:             * Attribute version - substitute the ${a} attribute macro for
196:             * the current attribute number.
197:             */
198:            public String getSQLStatement(String opname, String attrA,
199:                    String attrB) throws SQLException {
200:                String[] param = { attrA, attrB };
201:                return getSQLStatement(opname, param);
202:            }
203:
204:            /**
205:             * Return a set of raw SQL statements corresponding to the named operation.
206:             * This is used for compound operations where more than one SQL command is needed to
207:             * implement the operation (e.g. database formating and clean up). The
208:             * individual statements should be separated by double-semicolons at the end of the line.
209:             * <p>Needs refactoring to clarify what operations are and are not compound but for now
210:             * it is assumed the caller knows which is correct. Compound statements are not called
211:             * repeatedly so don't currently cache the parsed statement set.
212:             */
213:            public Collection getSQLStatementGroup(String opname)
214:                    throws SQLException {
215:                String statementSrc = m_sql.getProperty(opname);
216:                if (statementSrc == null) {
217:                    throw new SQLException("Unable to find SQL for operation: "
218:                            + opname);
219:                }
220:                int start = 0;
221:                int split = 0;
222:                List statements = new LinkedList();
223:                while (split != -1) {
224:                    split = statementSrc.indexOf(";;\n", start);
225:                    String statement = null;
226:                    if (split == -1) {
227:                        statement = statementSrc.substring(start);
228:                    } else {
229:                        statement = statementSrc.substring(start, split);
230:                        start = split + 2;
231:                    }
232:                    if (!statement.trim().equals(""))
233:                        statements.add(statement);
234:                }
235:                return statements;
236:            }
237:
238:            /**
239:             * Return a prepared SQL statement corresponding to the named operation.
240:             * The statement should either be closed after use or returned to the
241:             * prepared statement pool using {@link #returnPreparedSQLStatement returnPreparedSQLStatement}
242:             * 
243:             * <p>Only works for single statements, not compound statements.
244:             * @param con the jdbc connection to use for preparing statements
245:             * @param opname the name of the sql operation to locate
246:             * @return a prepared SQL statement appropriate for the JDBC connection
247:             * used when this SQLCache was constructed or null if there is no such
248:             * operation or no such connection
249:             * 
250:             * 
251:             */
252:
253:            public synchronized PreparedStatement getPreparedSQLStatement(
254:                    String opname, String[] attr) throws SQLException {
255:                /* TODO extended calling format or statement format to support different
256:                 * result sets and conconcurrency modes.
257:                 */
258:                PreparedStatement ps = null;
259:                if (m_connection == null || opname == null)
260:                    return null;
261:                int attrCnt = (attr == null) ? 0 : attr.length;
262:                String aop = opname;
263:                if (attrCnt > 0)
264:                    aop = concatOpName(aop, attr[0]);
265:                if (attrCnt > 1)
266:                    aop = concatOpName(aop, attr[1]);
267:                if (attrCnt > 2)
268:                    aop = concatOpName(aop, attr[2]);
269:                if (attrCnt > 3)
270:                    throw new JenaException("Too many arguments");
271:
272:                List psl = (List) m_preparedStatements.get(aop);
273:                // OVERRIDE: added proper PreparedStatement removal.
274:                if (psl != null && !psl.isEmpty()) {
275:                    ps = (PreparedStatement) psl.remove(0);
276:                    try {
277:                        ps.clearParameters();
278:                    } catch (SQLException e) {
279:                        ps.close();
280:                    }
281:                }
282:                if (ps == null) {
283:                    String sql = getSQLStatement(opname, attr);
284:                    if (sql == null) {
285:                        throw new SQLException("No SQL defined for operation: "
286:                                + opname);
287:                    }
288:                    if (psl == null && CACHE_PREPARED_STATEMENTS) {
289:                        psl = new LinkedList();
290:                        m_preparedStatements.put(aop, psl);
291:                    }
292:                    ps = doPrepareSQLStatement(sql);
293:                }
294:                if (CACHE_PREPARED_STATEMENTS)
295:                    m_cachedStmtInUse.put(ps, psl);
296:                return ps;
297:            }
298:
299:            /**
300:             * Prepare a SQL statement for the given statement string.
301:             *  
302:             * <p>Only works for single statements, not compound statements.
303:             * @param stmt the sql statement to prepare.
304:             * @return a prepared SQL statement appropriate for the JDBC connection
305:             * used when this SQLCache was constructed or null if there is no such
306:             * connection.
307:             */
308:
309:            private synchronized PreparedStatement doPrepareSQLStatement(
310:                    String sql) throws SQLException {
311:                if (m_connection == null)
312:                    return null;
313:                return getConnection().prepareStatement(sql);
314:            }
315:
316:            /**
317:             * Return a prepared SQL statement for the given statement string.
318:             * The statement should either be closed after use.
319:             *  
320:             * <p>Only works for single statements, not compound statements.
321:             * @param stmt the sql statement to prepare.
322:             * @return a prepared SQL statement appropriate for the JDBC connection
323:             * used when this SQLCache was constructed or null if there is no such
324:             * connection.
325:             */
326:
327:            public synchronized PreparedStatement prepareSQLStatement(String sql)
328:                    throws SQLException {
329:                if (m_connection == null)
330:                    return null;
331:                return doPrepareSQLStatement(sql);
332:            }
333:
334:            public synchronized PreparedStatement getPreparedSQLStatement(
335:                    String opname) throws SQLException {
336:                return getPreparedSQLStatement(opname, (String[]) null);
337:            }
338:
339:            /**
340:             * Variant on {@link #getPreparedSQLStatement getPreparedSQLStatement} which
341:             * accesses the attribute variant correspond to the given attribute suffix.
342:             */
343:            public synchronized PreparedStatement getPreparedSQLStatement(
344:                    String opname, String attr) throws SQLException {
345:                String[] param = { attr };
346:                return getPreparedSQLStatement(opname, param);
347:            }
348:
349:            /**
350:             * Variant on {@link #getPreparedSQLStatement getPreparedSQLStatement} which
351:             * access the attribute variant correspond to the given attribute suffix.
352:             */
353:            public synchronized PreparedStatement getPreparedSQLStatement(
354:                    String opname, String attrA, String attrB)
355:                    throws SQLException {
356:                String[] param = { attrA, attrB };
357:                return getPreparedSQLStatement(opname, param);
358:            }
359:
360:            /**
361:             * Return a prepared statement to the statement pool for reuse by
362:             * another caller. Any close problems logged rather than raising exception
363:             * so that iterator close() operations can be silent so that they can meet
364:             * the ClosableIterator signature.
365:             */
366:            public synchronized void returnPreparedSQLStatement(
367:                    PreparedStatement ps) {
368:                if (!CACHE_PREPARED_STATEMENTS) {
369:                    try {
370:                        ps.close();
371:                    } catch (SQLException e) {
372:                        logger.warn("Problem discarded prepared statement", e);
373:                    }
374:                    return;
375:                }
376:                List psl = (List) m_cachedStmtInUse.get(ps);
377:                if (psl != null) {
378:                    if (psl.size() >= MAX_PS_CACHE) {
379:                        try {
380:                            ps.close();
381:                        } catch (SQLException e) {
382:                            logger.warn("Problem discarded prepared statement",
383:                                    e);
384:                        }
385:                    } else {
386:                        psl.add(ps);
387:                    }
388:                    m_cachedStmtInUse.remove(ps);
389:                } else {
390:                    throw new JenaException(
391:                            "Attempt to return unused prepared statement");
392:                }
393:            }
394:
395:            /**
396:             * Execute a named pre-prepared SQL query statement taking a set of arguments and return
397:             * a set of results as an iterator (probably a subclass of ResultSetIterator. Returns null
398:             * if they query is an update (as opposed to an empty iterator for a true query which happens
399:             * to return no answers).
400:             * <p>
401:             * Not sure this is a good design. Reducing this to a general interface leads to lots of clunky
402:             * wrapping and unwrapping of primitive types, coercions and lack of compile-time type checking.
403:             * On the other hand letting the clients do this themselves with direct jdbc calls leaves us up
404:             * to the mercy of the client to correctly use returnPreparedSQLStatement and on average seems
405:             * to lead to more duplication of boiler plate code. Currently the client can chose either approach.
406:             * <p>
407:             * The calling arguments are passed in as an array.
408:             */
409:            public ResultSetIterator runSQLQuery(String opname, Object[] args)
410:                    throws SQLException {
411:                PreparedStatement ps = getPreparedSQLStatement(opname);
412:                if (args != null) {
413:                    for (int i = 0; i < args.length; i++) {
414:                        ps.setObject(i + 1, args[i]);
415:                    }
416:                }
417:                return executeSQL(ps, opname, new ResultSetIterator());
418:            }
419:
420:            /**
421:             * Variant on {@link #runSQLQuery} which
422:             * access the attribute variant correspond to the given attribute suffix.
423:             */
424:            public ResultSetIterator runSQLQuery(String opname, String attr,
425:                    Object[] args) throws SQLException {
426:                String aop = concatOpName(opname, attr);
427:                PreparedStatement ps = getPreparedSQLStatement(aop);
428:
429:                if (args != null) {
430:                    for (int i = 0; i < args.length; i++) {
431:                        ps.setObject(i + 1, args[i]);
432:                    }
433:                }
434:                return executeSQL(ps, aop, new ResultSetIterator());
435:            }
436:
437:            /**
438:             * Variant on {@link #runSQLQuery} which
439:             * access the attribute variant correspond to the given attribute suffix.
440:             */
441:            public ResultSetIterator runSQLQuery(String opname, String attrA,
442:                    String attrB, Object[] args) throws SQLException {
443:                String aop = concatOpName(opname, attrA, attrB);
444:                PreparedStatement ps = getPreparedSQLStatement(aop);
445:
446:                if (args != null) {
447:                    for (int i = 0; i < args.length; i++) {
448:                        ps.setObject(i + 1, args[i]);
449:                    }
450:                }
451:                return executeSQL(ps, aop, new ResultSetIterator());
452:            }
453:
454:            /**
455:             * Execute a named pre-prepared SQL update statement taking a set of arguments and returning
456:             * the update count.
457:             */
458:            public int runSQLUpdate(String opname, Object[] args)
459:                    throws SQLException {
460:                PreparedStatement ps = getPreparedSQLStatement(opname);
461:                if (args != null) {
462:                    for (int i = 0; i < args.length; i++) {
463:                        ps.setObject(i + 1, args[i]);
464:                    }
465:                }
466:                int result = ps.executeUpdate();
467:                returnPreparedSQLStatement(ps);
468:                return result;
469:            }
470:
471:            /**
472:             * Variant on {@link #runSQLUpdate} which
473:             * access the attribute variant correspond to the given attribute suffix.
474:             */
475:            public int runSQLUpdate(String opname, String attrA, Object[] args)
476:                    throws SQLException {
477:                String aop = concatOpName(opname, attrA);
478:                PreparedStatement ps = getPreparedSQLStatement(aop);
479:                if (args != null) {
480:                    for (int i = 0; i < args.length; i++) {
481:                        ps.setObject(i + 1, args[i]);
482:                    }
483:                }
484:                int result = ps.executeUpdate();
485:                returnPreparedSQLStatement(ps);
486:                return result;
487:            }
488:
489:            /**
490:             * Variant on {@link #runSQLUpdate} which
491:             * access the attribute variant correspond to the given attribute suffix.
492:             */
493:            public int runSQLUpdate(String opname, String attrA, String attrB,
494:                    Object[] args) throws SQLException {
495:                String aop = concatOpName(opname, attrA, attrB);
496:                PreparedStatement ps = getPreparedSQLStatement(aop);
497:                if (args != null) {
498:                    for (int i = 0; i < args.length; i++) {
499:                        ps.setObject(i + 1, args[i]);
500:                    }
501:                }
502:                int result = ps.executeUpdate();
503:                returnPreparedSQLStatement(ps);
504:                return result;
505:            }
506:
507:            /**
508:             * Execute a named pre-prepared SQL query statement taking a set of arguments and return
509:             * a set of results as an iterator (probably a subclass of ResultSetIterator. Returns null
510:             * if they query is an update (as opposed to an empty iterator for a true query which happens
511:             * to return no answers).
512:             * <p>
513:             * Not sure this is a good design. Reducing this to a general interface leads to lots of clunky
514:             * wrapping and unwrapping of primitive types, coercions and lack of compile-time type checking.
515:             * On the other hand letting the clients do this themselves with direct jdbc calls leaves us up
516:             * to the mercy of the client to correctly use returnPreparedSQLStatement and on average seems
517:             * to lead to more duplication of boiler plate code. Currently the client can chose either approach.
518:             * <p>
519:             * @param opname the name of the SQL operation to perform
520:             * @param args the arguments to pass to the SQL operation as an array of Objects
521:             * @param iterator the iterator to use to return the results
522:             */
523:            public ResultSetIterator runSQLQuery(String opname, Object[] args,
524:                    ResultSetIterator iterator) throws SQLException {
525:                PreparedStatement ps = getPreparedSQLStatement(opname);
526:                if (args != null) {
527:                    for (int i = 0; i < args.length; i++) {
528:                        ps.setObject(i + 1, args[i]);
529:                    }
530:                }
531:                return executeSQL(ps, opname, iterator);
532:            }
533:
534:            /**
535:             * Variant on {@link #runSQLQuery} which
536:             * access the attribute variant correspond to the given attribute suffix.
537:             */
538:            public ResultSetIterator runSQLQuery(String opname, String attrA,
539:                    Object[] args, ResultSetIterator iterator)
540:                    throws SQLException {
541:                String aop = concatOpName(opname, attrA);
542:                PreparedStatement ps = getPreparedSQLStatement(aop);
543:                if (args != null) {
544:                    for (int i = 0; i < args.length; i++) {
545:                        ps.setObject(i + 1, args[i]);
546:                    }
547:                }
548:
549:                return executeSQL(ps, aop, iterator);
550:            }
551:
552:            /**
553:             * Variant on {@link #runSQLQuery} which
554:             * access the attribute variant correspond to the given attribute suffix.
555:             */
556:            public ResultSetIterator runSQLQuery(String opname, String attrA,
557:                    String attrB, Object[] args, ResultSetIterator iterator)
558:                    throws SQLException {
559:                String aop = concatOpName(opname, attrA, attrB);
560:                PreparedStatement ps = getPreparedSQLStatement(aop);
561:                if (args != null) {
562:                    for (int i = 0; i < args.length; i++) {
563:                        ps.setObject(i + 1, args[i]);
564:                    }
565:                }
566:
567:                return executeSQL(ps, aop, iterator);
568:            }
569:
570:            /**
571:             * Run a group of sql statements - normally used for db formating and clean up.
572:             * All statements are executed even if one raises an error then the error is
573:             * reported at the end.
574:             * 
575:             * Attribute version -- substitute the ${a} attribute macro
576:             * for the current attribute 
577:             */
578:            public void runSQLGroup(String opname, String[] attr)
579:                    throws SQLException {
580:                String op = null;
581:                SQLException eignore = null;
582:                String operror = null;
583:                java.sql.Statement sql = getConnection().createStatement();
584:                Iterator ops = getSQLStatementGroup(opname).iterator();
585:                int attrCnt = attr == null ? 0 : attr.length;
586:                if (attrCnt > 6)
587:                    throw new RDFRDBException("Too many parameters");
588:                while (ops.hasNext()) {
589:                    op = (String) ops.next();
590:                    if (attrCnt > 0)
591:                        op = substitute(op, "${a}", attr[0]);
592:                    if (attrCnt > 1)
593:                        op = substitute(op, "${b}", attr[1]);
594:                    if (attrCnt > 2)
595:                        op = substitute(op, "${c}", attr[2]);
596:                    if (attrCnt > 3)
597:                        op = substitute(op, "${d}", attr[3]);
598:                    if (attrCnt > 4)
599:                        op = substitute(op, "${e}", attr[4]);
600:                    if (attrCnt > 5)
601:                        op = substitute(op, "${f}", attr[5]);
602:                    try {
603:                        sql.execute(op);
604:                    } catch (SQLException e) {
605:                        // This is debugging legacy, exception is still reported at the end
606:                        // System.out.println("Exec failure: " + op + ": " + e);
607:                        operror = op;
608:                        eignore = e;
609:                    }
610:                }
611:                sql.close();
612:                if (eignore != null) {
613:                    // operror records the failed operator, mostly internal debugging use
614:                    throw eignore;
615:                }
616:            }
617:
618:            /**
619:             * Run a group of sql statements - normally used for db formating and clean up.
620:             * All statements are executed even if one raises an error then the error is
621:             * reported at the end.
622:             */
623:            public void runSQLGroup(String opname) throws SQLException {
624:                runSQLGroup(opname, (String[]) null);
625:            }
626:
627:            /**
628:             * Run a group of sql statements - normally used for db formating and clean up.
629:             * All statements are executed even if one raises an error then the error is
630:             * reported at the end.
631:             * 
632:             * Attribute version -- substitute the ${a} attribute macro
633:             * for the current attribute 
634:             */
635:            public void runSQLGroup(String opname, String attr)
636:                    throws SQLException {
637:                String[] param = { attr };
638:                runSQLGroup(opname, param);
639:            }
640:
641:            /**
642:             * Run a group of sql statements - normally used for db formating and clean up.
643:             * All statements are executed even if one raises an error then the error is
644:             * reported at the end.
645:             * 
646:             * Attribute version -- substitute the ${a} attribute macro
647:             * for the current attribute 
648:             */
649:            public void runSQLGroup(String opname, String attrA, String attrB)
650:                    throws SQLException {
651:                String[] param = { attrA, attrB };
652:                runSQLGroup(opname, param);
653:            }
654:
655:            /**
656:             * Close all prepared statements
657:             */
658:            public void close() throws SQLException {
659:                Iterator it = m_preparedStatements.values().iterator();
660:                while (it.hasNext()) {
661:                    List psl = (List) it.next();
662:                    Iterator itl = psl.iterator();
663:                    while (itl.hasNext()) {
664:                        PreparedStatement ps = (PreparedStatement) itl.next();
665:                        ps.close();
666:                    }
667:                    it.remove();
668:                }
669:                it = m_cachedStmtInUse.values().iterator();
670:                while (it.hasNext()) {
671:                    it.remove();
672:                }
673:            }
674:
675:            /**
676:             * Load in a defined set of sql statements - see class comment for format.
677:             * The loaded file is return as a Property table. This call is static
678:             * to support the loading of a default sql mapping.
679:             * @param sqlFile the name of the file of sql statements to load, this is
680:             * loaded from the classpath.
681:             * @param defaultOps a Properties table of default sql definitions.
682:             * @param idType the sql string to use for id types (substitutes for $id in files)
683:             */
684:            public static Properties loadSQLFile(String sqlFile,
685:                    Properties defaultOps, String idType) throws IOException {
686:                Properties sqlTable = new Properties(defaultOps);
687:                BufferedReader src = openResourceFile(sqlFile);
688:                String line = null;
689:                while ((line = src.readLine()) != null) {
690:                    if (line.startsWith("#")) {
691:                        continue; // Comment line so skip it
692:                    }
693:                    String opName = line.trim();
694:                    StringBuffer sql = new StringBuffer();
695:                    while (true) {
696:                        line = src.readLine();
697:                        if (line == null || line.trim().equals("")) {
698:                            // Blank line terminates sql block
699:                            sqlTable.setProperty(opName, sql.toString());
700:                            break;
701:                        } else if (line.startsWith("#")) {
702:                            continue;
703:                        } else {
704:                            sql
705:                                    .append(substitute(line.trim(), "${id}",
706:                                            idType));
707:                            sql.append("\n");
708:                        }
709:                    }
710:                    if (line == null)
711:                        break; // Check if read to end of file
712:                }
713:                return sqlTable;
714:            }
715:
716:            /** Helper function calculate op name given substitutions */
717:            public static String concatOpName(String opName, String attr) {
718:                return (opName + attr);
719:            }
720:
721:            /** Helper function calculate op name given substitutions */
722:            public static String concatOpName(String opName, String attrA,
723:                    String attrB) {
724:                return (opName + attrA + attrB);
725:            }
726:
727:            /** Helper function substitute all occurances of macro with subs */
728:            public static String substitute(String line, String macro,
729:                    String subs) {
730:                int loc = line.indexOf(macro);
731:                if (loc != -1) {
732:                    return line.substring(0, loc)
733:                            + subs
734:                            + substitute(line.substring(loc + macro.length()),
735:                                    macro, subs);
736:                } else {
737:                    return line;
738:                }
739:            }
740:
741:            //=======================================================================
742:            // Internal support
743:
744:            /**
745:             * Accessor. Returns the Properties table which maps operation names to
746:             * the plain text sql statements. This is using internally in the constructor.
747:             */
748:            protected Properties getSQLTable() {
749:                return m_sql;
750:            }
751:
752:            /**
753:             * Open a resource file for reading. The file is found on the classpath.
754:             */
755:            public static BufferedReader openResourceFile(String filename)
756:                    throws IOException {
757:                InputStream is = SQLCache.class.getClassLoader()
758:                        .getResourceAsStream(filename);
759:                if (is == null)
760:                    throw new IOException("Can't open resource " + filename);
761:                return new BufferedReader(new InputStreamReader(is, "US-ASCII"));
762:            }
763:
764:            /**
765:             * Execute the given statement, return null if the statement appears to be
766:             * just an update or return an iterator for the result set if the statement appears
767:             * to be a query
768:             */
769:            protected ResultSetIterator executeSQL(PreparedStatement ps,
770:                    String opname, ResultSetIterator iterator)
771:                    throws SQLException {
772:                if (ps.execute()) {
773:                    ResultSet rs = ps.getResultSet();
774:                    iterator.reset(rs, ps, this , opname);
775:                    return iterator;
776:                } else {
777:                    returnPreparedSQLStatement(ps);
778:                    return null;
779:                }
780:            }
781:
782:            /**
783:             * Return dynamically generated SQL for the specified operation.
784:             * @param opname the command to generate; must start with "*", the opname and then op params.
785:             * @return the generated command as a String.
786:             */
787:
788:            protected String genSQLStatement(String opname) throws SQLException {
789:                /* for testing. for now, we only generate one operation, findReif,
790:                 * to find reified statements from a triple match pattern.
791:                 */
792:                String sql = "";
793:                boolean badop = false;
794:                if (opname.startsWith("*")) {
795:                    // a space separate the operation name from its parameters.
796:                    int delim = opname.indexOf(' ');
797:                    String op = opname.substring(1, delim);
798:                    String args = opname.substring(delim + 1);
799:                    if (op.equals("findReif")) {
800:                        sql = genSQLStmtFindReif(op, args);
801:                    } else
802:                        badop = true;
803:                } else
804:                    badop = true;
805:                if (badop) {
806:                    logger.error("Unable to generate SQL for operation: "
807:                            + opname);
808:                    throw new JenaException(
809:                            "Unable to generate SQL for operation: " + opname);
810:                }
811:                return sql;
812:            }
813:
814:            /**
815:             * Return generate SQL for finding reified statements from a triple pattern.
816:             * @param op the command to generate. should be findReif.
817:             * @param args a string describing which command to generate. 
818:             * it has the form [N][PS|PP|PO|PT][O[C]] where N means to search
819:             * for the statement URI; Px means to search for reified subjects, properties,
820:             * objects or types; O means to search for reified objects; OC means the object
821:             * value is rdf:Statement.
822:             */
823:
824:            protected String genSQLStmtFindReif(String op, String args)
825:                    throws SQLException {
826:                /* for a reified triple pattern <S,P,O>, there are 8 cases.
827:                 * 1. <-,-,->	this means retrieve all reified triples. args="".
828:                 * 2. <S,-,->	retrieve all reified triples for this subject. args="N".
829:                 * 3. <S,-,O>	retrieve all reified triples for this subject and
830:                 * 				object value. args="NO" or "NOC".
831:                 * 4. <-,-,O>	retrieve all reified triples with this object value.
832:                 * 				args="O" or "OC"
833:                 * 5. <-,P,->	retrieve all reified triples with this property. args="Px".
834:                 * 				property must be either rdf:subject, rdf:predicate,
835:                 * 				rdf:object, rdf:type.
836:                 * 6. <-,P,O>	retrieve all reified triples with this property and object
837:                 * 				value. args="PxO" or "PxOC".
838:                 * 7. <S,P,->	retrieve all reified triples with this subject and property.
839:                 * 				args="NPx".
840:                 * 8. <S,P,O>	retrieve all reified triples with this subject, property and
841:                 * 				object value. args="NPxO" or "NPxOC".
842:                 */
843:
844:                String stmtStr = getSQLStatement("selectReified");
845:                String qual = "";
846:                IRDBDriver driver = m_connection.getDriver();
847:
848:                if (args.equals("")) {
849:                    // case 1 <-,-,->  nothing to do.
850:                } else {
851:                    int ix = 0;
852:                    boolean hasSubj = false;
853:                    boolean hasProp = false;
854:                    boolean hasObj = false;
855:                    boolean objIsStmt = false;
856:                    char reifProp = ' ';
857:                    int argLen = args.length();
858:
859:                    if (args.charAt(ix) == 'N') {
860:                        hasSubj = true;
861:                        ix++;
862:                    }
863:                    hasProp = (ix < argLen) && (args.charAt(ix) == 'P');
864:                    if (hasProp && (ix < argLen)) {
865:                        ix++;
866:                        reifProp = args.charAt(ix++);
867:                    }
868:                    hasObj = (ix < argLen) && (args.charAt(ix) == 'O');
869:                    if (hasObj) {
870:                        ix++;
871:                        objIsStmt = (ix < argLen) && (args.charAt(ix) == 'C');
872:                    }
873:                    if (!hasProp) {
874:                        if (hasSubj) {
875:                            // cases 2 and 3
876:                            qual += driver.genSQLReifQualStmt();
877:                            if (hasObj) {
878:                                // case 3 above
879:                                qual += " AND "
880:                                        + driver
881:                                                .genSQLReifQualAnyObj(objIsStmt);
882:                            }
883:                        } else {
884:                            // case 4 above
885:                            qual += driver.genSQLReifQualAnyObj(objIsStmt);
886:                        }
887:                    } else {
888:                        // have a reified property
889:                        if (hasSubj)
890:                            qual += driver.genSQLReifQualStmt() + " AND ";
891:                        qual += driver.genSQLReifQualObj(reifProp, hasObj);
892:                    }
893:                    stmtStr += " AND " + qual;
894:                }
895:                return stmtStr;
896:            }
897:
898:        }
899:
900:        /*
901:         *  (c) Copyright 2002, 2003, 2004, 2005, 2006, 2007, 2008 Hewlett-Packard Development Company, LP
902:         *  All rights reserved.
903:         *
904:         * Redistribution and use in source and binary forms, with or without
905:         * modification, are permitted provided that the following conditions
906:         * are met:
907:         * 1. Redistributions of source code must retain the above copyright
908:         *    notice, this list of conditions and the following disclaimer.
909:         * 2. Redistributions in binary form must reproduce the above copyright
910:         *    notice, this list of conditions and the following disclaimer in the
911:         *    documentation and/or other materials provided with the distribution.
912:         * 3. The name of the author may not be used to endorse or promote products
913:         *    derived from this software without specific prior written permission.
914:
915:         * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
916:         * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
917:         * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
918:         * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
919:         * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
920:         * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
921:         * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
922:         * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
923:         * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
924:         * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
925:         */
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.