Source Code Cross Referenced for BaseDbDoubleStorage.java in  » ERP-CRM-Financial » sakai » org » sakaiproject » util » 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 » ERP CRM Financial » sakai » org.sakaiproject.util 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /**********************************************************************************
0002:         * $URL: https://source.sakaiproject.org/svn/db/tags/sakai_2-4-1/db-util/storage/src/java/org/sakaiproject/util/BaseDbDoubleStorage.java $
0003:         * $Id: BaseDbDoubleStorage.java 7084 2006-03-28 00:27:56Z ggolden@umich.edu $
0004:         ***********************************************************************************
0005:         *
0006:         * Copyright (c) 2005, 2006 The Sakai Foundation.
0007:         * 
0008:         * Licensed under the Educational Community License, Version 1.0 (the "License"); 
0009:         * you may not use this file except in compliance with the License. 
0010:         * You may obtain a copy of the License at
0011:         * 
0012:         *      http://www.opensource.org/licenses/ecl1.php
0013:         * 
0014:         * Unless required by applicable law or agreed to in writing, software 
0015:         * distributed under the License is distributed on an "AS IS" BASIS, 
0016:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
0017:         * See the License for the specific language governing permissions and 
0018:         * limitations under the License.
0019:         *
0020:         **********************************************************************************/package org.sakaiproject.util;
0021:
0022:        import java.sql.Connection;
0023:        import java.sql.ResultSet;
0024:        import java.sql.SQLException;
0025:        import java.util.Hashtable;
0026:        import java.util.Iterator;
0027:        import java.util.List;
0028:        import java.util.Stack;
0029:        import java.util.Vector;
0030:
0031:        import org.apache.commons.logging.Log;
0032:        import org.apache.commons.logging.LogFactory;
0033:        import org.sakaiproject.db.api.SqlReader;
0034:        import org.sakaiproject.db.api.SqlService;
0035:        import org.sakaiproject.entity.api.Edit;
0036:        import org.sakaiproject.entity.api.Entity;
0037:        import org.sakaiproject.entity.api.ResourceProperties;
0038:        import org.sakaiproject.event.cover.UsageSessionService;
0039:        import org.sakaiproject.time.api.Time;
0040:        import org.sakaiproject.time.cover.TimeService;
0041:        import org.w3c.dom.Document;
0042:        import org.w3c.dom.Element;
0043:
0044:        /**
0045:         * <p>
0046:         * BaseDbDoubleStorage is a class that stores Resources (of some type) in a database, <br />
0047:         * provides locked access, and generally implements a services "storage" class. The <br />
0048:         * service's storage class can extend this to provide covers to turn Resource and <br />
0049:         * Edit into something more type specific to the service.
0050:         * </p>
0051:         * <p>
0052:         * Note: the methods here are all "id" based, with the following assumptions:
0053:         * <ul>
0054:         * <li>just the Resource Id field is enough to distinguish one Resource from another (or, for resource, the container's id and the resource id).</li>
0055:         * <li>a resource's reference is based on no more than the resource id, for containers </li>
0056:         * <li>and no more than resource and container id for resources</li>
0057:         * <li>a resource's id and container id cannot change</li>
0058:         * </ul>
0059:         * </p>
0060:         * <br />
0061:         * In order to handle Unicode characters properly, the SQL statements executed by this class should not embed Unicode characters into the SQL statement text; <br />
0062:         * rather, Unicode values should be inserted as fields in a PreparedStatement. Databases handle Unicode better in fields.
0063:         * </p>
0064:         */
0065:        public class BaseDbDoubleStorage {
0066:            /** Our logger. */
0067:            private static Log M_log = LogFactory
0068:                    .getLog(BaseDbDoubleStorage.class);
0069:
0070:            /** Table name for container records. */
0071:            protected String m_containerTableName = null;
0072:
0073:            /** The field in the table that holds the container id. */
0074:            protected String m_containerTableIdField = null;
0075:
0076:            /** Table name for resource records. */
0077:            protected String m_resourceTableName = null;
0078:
0079:            /** The field in the resource table that holds the resource id. */
0080:            protected String m_resourceTableIdField = null;
0081:
0082:            /** The field in the resource table that holds the container id. */
0083:            protected String m_resourceTableContainerIdField = null;
0084:
0085:            /** The additional field names in the resource table that go between the two ids and the xml. */
0086:            protected String[] m_resourceTableOtherFields = null;
0087:
0088:            /** The field name in the resource table for ordering. */
0089:            protected String m_resourceTableOrderField = null;
0090:
0091:            /** The xml tag name for the element holding each actual resource entry. */
0092:            protected String m_resourceEntryTagName = null;
0093:
0094:            /** The xml tag name for the element holding each actual container entry. */
0095:            protected String m_containerEntryTagName = null;
0096:
0097:            /** The field in the record that has the user id of the resource owner. */
0098:            protected String m_resourceTableOwnerField = null;
0099:
0100:            /** The field in the record that has the draft indicator ('0' for no, '1' for yes). */
0101:            protected String m_resourceTableDraftField = null;
0102:
0103:            /** The field in the record that has the pubview indicator ('0' for no, '1' for yes). */
0104:            protected String m_resourceTablePubViewField = null;
0105:
0106:            /** If true, we do our locks in the remote database. */
0107:            protected boolean m_locksAreInDb = true;
0108:
0109:            /** If true, we do our locks in the remove database using a separate locking table. */
0110:            protected boolean m_locksAreInTable = true;
0111:
0112:            /** The StorageUser to callback for new Resource and Edit objects. */
0113:            protected StorageUser m_user = null;
0114:
0115:            /**
0116:             * Locks, keyed by reference, holding Connections (or, if locks are done locally, holding an Edit). Note: keying by reference allows botu container and resource locks to be stored, the reference distinguishes them.
0117:             */
0118:            protected Hashtable m_locks = null;
0119:
0120:            /** For container, the extra field is (no longer used) NEXT_ID */
0121:            protected static final String[] M_containerExtraFields = { "NEXT_ID" };
0122:
0123:            /** Injected (by constructor) SqlService. */
0124:            protected SqlService m_sql = null;
0125:
0126:            /**
0127:             * Construct.
0128:             * 
0129:             * @param containerTableName
0130:             *        Table name for containers.
0131:             * @param containerTableIdField
0132:             *        The field in the container table that holds the id.
0133:             * @param resourceTableName
0134:             *        Table name for resources.
0135:             * @param resourceTableIdField
0136:             *        The field in the resource table that holds the id.
0137:             * @param resourceTableContainerIdField
0138:             *        The field in the resource table that holds the container id.
0139:             * @param resourceTableOrderField
0140:             *        The field in the resource table that is used for ordering results.
0141:             * @param resourceTableOtherFields
0142:             *        The other fields in the resource table (between the two id fields and the xml field).
0143:             * @param locksInDb
0144:             *        If true, we do our locks in the remote database, otherwise we do them here.
0145:             * @param containerEntryName
0146:             *        The xml tag name for the element holding each actual container entry.
0147:             * @param resourceEntryName
0148:             *        The xml tag name for the element holding each actual resource entry.
0149:             * @param user
0150:             *        The StorageUser class to call back for creation of Resource and Edit objects.
0151:             * @param sqlService
0152:             *        The SqlService.
0153:             */
0154:            public BaseDbDoubleStorage(String containerTableName,
0155:                    String containerTableIdField, String resourceTableName,
0156:                    String resourceTableIdField,
0157:                    String resourceTableContainerIdField,
0158:                    String resourceTableOrderField,
0159:                    String resourceTableOwnerField,
0160:                    String resourceTableDraftField,
0161:                    String resourceTablePubViewField,
0162:                    String[] resourceTableOtherFields, boolean locksInDb,
0163:                    String containerEntryName, String resourceEntryName,
0164:                    StorageUser user, SqlService sqlService) {
0165:                m_containerTableName = containerTableName;
0166:                m_containerTableIdField = containerTableIdField;
0167:                m_resourceTableName = resourceTableName;
0168:                m_resourceTableIdField = resourceTableIdField;
0169:                m_resourceTableContainerIdField = resourceTableContainerIdField;
0170:                m_resourceTableOrderField = resourceTableOrderField;
0171:                m_resourceTableOtherFields = resourceTableOtherFields;
0172:                m_locksAreInDb = locksInDb;
0173:                m_containerEntryTagName = containerEntryName;
0174:                m_resourceEntryTagName = resourceEntryName;
0175:                m_resourceTableOwnerField = resourceTableOwnerField;
0176:                m_resourceTableDraftField = resourceTableDraftField;
0177:                m_resourceTablePubViewField = resourceTablePubViewField;
0178:                m_user = user;
0179:                m_sql = sqlService;
0180:            }
0181:
0182:            /**
0183:             * Open and be ready to read / write.
0184:             */
0185:            public void open() {
0186:                // setup for locks
0187:                m_locks = new Hashtable();
0188:            }
0189:
0190:            /**
0191:             * Close.
0192:             */
0193:            public void close() {
0194:                if (!m_locks.isEmpty()) {
0195:                    M_log.warn("close(): locks remain!");
0196:                    // %%%
0197:                }
0198:                m_locks.clear();
0199:                m_locks = null;
0200:            }
0201:
0202:            /**
0203:             * Read one Container Resource from xml
0204:             * 
0205:             * @param xml
0206:             *        An string containing the xml which describes the Container resource.
0207:             * @return The Container Resource object created from the xml.
0208:             */
0209:            protected Entity readContainer(String xml) {
0210:                try {
0211:                    // read the xml
0212:                    Document doc = Xml.readDocumentFromString(xml);
0213:
0214:                    // verify the root element
0215:                    Element root = doc.getDocumentElement();
0216:                    if (!root.getTagName().equals(m_containerEntryTagName)) {
0217:                        M_log.warn("readContainer(): not = "
0218:                                + m_containerEntryTagName + " : "
0219:                                + root.getTagName());
0220:                        return null;
0221:                    }
0222:
0223:                    // re-create a resource
0224:                    Entity entry = m_user.newContainer(root);
0225:
0226:                    return entry;
0227:                } catch (Exception e) {
0228:                    M_log.debug("readContainer(): ", e);
0229:                    return null;
0230:                }
0231:            }
0232:
0233:            /**
0234:             * Check if a Container by this id exists.
0235:             * 
0236:             * @param ref
0237:             *        The container reference.
0238:             * @return true if a Container by this id exists, false if not.
0239:             */
0240:            public boolean checkContainer(String ref) {
0241:                // just see if the record exists
0242:                String sql = "select " + m_containerTableIdField + "  from "
0243:                        + m_containerTableName + " where ( "
0244:                        + m_containerTableIdField + " = ? )";
0245:                Object[] fields = new Object[1];
0246:                fields[0] = ref;
0247:                List ids = m_sql.dbRead(sql, fields, null);
0248:                return (!ids.isEmpty());
0249:            }
0250:
0251:            /**
0252:             * Get the Container with this id, or null if not found.
0253:             * 
0254:             * @param ref
0255:             *        The container reference.
0256:             * @return The Container with this id, or null if not found.
0257:             */
0258:            public Entity getContainer(String ref) {
0259:                Entity entry = null;
0260:
0261:                // get the user from the db
0262:                String sql = "select XML from " + m_containerTableName
0263:                        + " where ( " + m_containerTableIdField + " = ? )";
0264:                Object[] fields = new Object[1];
0265:                fields[0] = ref;
0266:
0267:                List xml = m_sql.dbRead(sql, fields, null);
0268:                if (!xml.isEmpty()) {
0269:                    // create the Resource from the db xml
0270:                    entry = readContainer((String) xml.get(0));
0271:                }
0272:
0273:                return entry;
0274:            }
0275:
0276:            /**
0277:             * Get all Containers.
0278:             * 
0279:             * @return The list (Resource) of all Containers.
0280:             */
0281:            public List getAllContainers() {
0282:                List all = new Vector();
0283:
0284:                // read all users from the db
0285:                String sql = "select XML from " + m_containerTableName;
0286:                // %%% order by...
0287:                List xml = m_sql.dbRead(sql);
0288:
0289:                // process all result xml into user objects
0290:                if (!xml.isEmpty()) {
0291:                    for (int i = 0; i < xml.size(); i++) {
0292:                        Entity entry = readContainer((String) xml.get(i));
0293:                        if (entry != null)
0294:                            all.add(entry);
0295:                    }
0296:                }
0297:
0298:                return all;
0299:            }
0300:
0301:            /**
0302:             * Add a new Container with this id.
0303:             * 
0304:             * @param ref
0305:             *        The container reference.
0306:             * @return The locked Container object with this id, or null if the id is in use.
0307:             */
0308:            public Edit putContainer(String ref) {
0309:                // create one with just the id
0310:                Entity entry = m_user.newContainer(ref);
0311:
0312:                // form the XML and SQL for the insert
0313:                Document doc = Xml.createDocument();
0314:                entry.toXml(doc, new Stack());
0315:                String xml = Xml.writeDocumentToString(doc);
0316:
0317:                String statement = "insert into "
0318:                        + m_containerTableName
0319:                        + insertFields(m_containerTableIdField, null,
0320:                                M_containerExtraFields, "XML") + " values ( ? "
0321:                        + ",'0'" // %%% was next id, no longer used (but still in db) -ggolden
0322:                        + ", ? )";
0323:
0324:                Object[] fields = new Object[2];
0325:                fields[0] = entry.getReference();
0326:                fields[1] = xml;
0327:
0328:                // process the insert
0329:                boolean ok = m_sql.dbWrite(statement, fields);
0330:
0331:                // if this failed, assume a key conflict (i.e. id in use)
0332:                if (!ok)
0333:                    return null;
0334:
0335:                // now get a lock on the record for edit
0336:                Edit edit = editContainer(ref);
0337:                if (edit == null) {
0338:                    M_log.warn("putContainer(): didn't get a lock!");
0339:                    return null;
0340:                }
0341:
0342:                return edit;
0343:            }
0344:
0345:            /**
0346:             * Get a lock on the Container with this id, or null if a lock cannot be gotten.
0347:             * 
0348:             * @param ref
0349:             *        The container reference.
0350:             * @return The locked Container with this id, or null if this cannot be locked.
0351:             */
0352:            public Edit editContainer(String ref) {
0353:                Edit edit = null;
0354:
0355:                if (m_locksAreInDb) {
0356:                    if ("oracle".equals(m_sql.getVendor())) {
0357:                        // read the record and get a lock on it (non blocking)
0358:                        String statement = "select XML from "
0359:                                + m_containerTableName + " where ( "
0360:                                + m_containerTableIdField + " = '"
0361:                                + Validator.escapeSql(ref) + "' )"
0362:                                + " for update nowait";
0363:                        StringBuffer result = new StringBuffer();
0364:                        Connection lock = m_sql.dbReadLock(statement, result);
0365:
0366:                        // for missing or already locked...
0367:                        if ((lock == null) || (result.length() == 0))
0368:                            return null;
0369:
0370:                        // make first a Resource, then an Edit
0371:                        Entity entry = readContainer(result.toString());
0372:                        edit = m_user.newContainerEdit(entry);
0373:
0374:                        // store the lock for this object
0375:                        m_locks.put(entry.getReference(), lock);
0376:                    } else {
0377:                        throw new UnsupportedOperationException(
0378:                                "Record locking only available when configured with Oracle database");
0379:                    }
0380:                }
0381:
0382:                // if the locks are in a separate table in the db
0383:                else if (m_locksAreInTable) {
0384:                    // get, and return if not found
0385:                    Entity entry = getContainer(ref);
0386:                    if (entry == null)
0387:                        return null;
0388:
0389:                    // write a lock to the lock table - if we can do it, we get the lock
0390:                    String statement = "insert into SAKAI_LOCKS"
0391:                            + " (TABLE_NAME,RECORD_ID,LOCK_TIME,USAGE_SESSION_ID)"
0392:                            + " values (?, ?, ?, ?)";
0393:
0394:                    // we need session id
0395:                    String sessionId = UsageSessionService.getSessionId();
0396:                    if (sessionId == null) {
0397:                        sessionId = "";
0398:                    }
0399:
0400:                    // collect the fields
0401:                    Object fields[] = new Object[4];
0402:                    fields[0] = m_containerTableName;
0403:                    fields[1] = internalRecordId(ref);
0404:                    fields[2] = TimeService.newTime();
0405:                    fields[3] = sessionId;
0406:
0407:                    // add the lock - if fails, someone else has the lock
0408:                    boolean ok = m_sql
0409:                            .dbWriteFailQuiet(null, statement, fields);
0410:                    if (!ok) {
0411:                        return null;
0412:                    }
0413:
0414:                    // make the edit from the Resource
0415:                    edit = m_user.newContainerEdit(entry);
0416:                }
0417:
0418:                // otherwise, get the lock locally
0419:                else {
0420:                    // get, and return if not found
0421:                    Entity entry = getContainer(ref);
0422:                    if (entry == null)
0423:                        return null;
0424:
0425:                    // we only sync this getting - someone may release a lock out of sync
0426:                    synchronized (m_locks) {
0427:                        // if already locked
0428:                        if (m_locks.containsKey(entry.getReference()))
0429:                            return null;
0430:
0431:                        // make the edit from the Resource
0432:                        edit = m_user.newContainerEdit(entry);
0433:
0434:                        // store the edit in the locks by reference
0435:                        m_locks.put(entry.getReference(), edit);
0436:                    }
0437:                }
0438:
0439:                return edit;
0440:            }
0441:
0442:            /**
0443:             * Commit the changes and release the lock.
0444:             * 
0445:             * @param user
0446:             *        The Edit to commit.
0447:             */
0448:            public void commitContainer(Edit edit) {
0449:                // form the SQL statement and the var w/ the XML
0450:                Document doc = Xml.createDocument();
0451:                edit.toXml(doc, new Stack());
0452:                String xml = Xml.writeDocumentToString(doc);
0453:                String statement = "update " + m_containerTableName
0454:                        + " set XML = ?" + " where " + m_containerTableIdField
0455:                        + " = ? ";
0456:
0457:                Object[] fields = new Object[2];
0458:                fields[0] = xml;
0459:                fields[1] = edit.getReference();
0460:
0461:                if (m_locksAreInDb) {
0462:                    // use this connection that is stored with the lock
0463:                    Connection lock = (Connection) m_locks.get(edit
0464:                            .getReference());
0465:                    if (lock == null) {
0466:                        M_log.warn("commitContainer(): edit not in locks");
0467:                        return;
0468:                    }
0469:
0470:                    // update, commit, release the lock's connection
0471:                    m_sql.dbUpdateCommit(statement, fields, null, lock);
0472:
0473:                    // remove the lock
0474:                    m_locks.remove(edit.getReference());
0475:                }
0476:
0477:                else if (m_locksAreInTable) {
0478:                    // process the update
0479:                    m_sql.dbWrite(statement, fields);
0480:
0481:                    // remove the lock
0482:                    statement = "delete from SAKAI_LOCKS where TABLE_NAME = ? and RECORD_ID = ?";
0483:
0484:                    // collect the fields
0485:                    Object lockFields[] = new Object[2];
0486:                    lockFields[0] = m_containerTableName;
0487:                    lockFields[1] = internalRecordId(edit.getReference());
0488:                    boolean ok = m_sql.dbWrite(statement, lockFields);
0489:                    if (!ok) {
0490:                        M_log.warn("commitContainer: missing lock for table: "
0491:                                + lockFields[0] + " key: " + lockFields[1]);
0492:                    }
0493:                }
0494:
0495:                else {
0496:                    // just process the update
0497:                    m_sql.dbWrite(statement, fields);
0498:
0499:                    // remove the lock
0500:                    m_locks.remove(edit.getReference());
0501:                }
0502:            }
0503:
0504:            /**
0505:             * Cancel the changes and release the lock.
0506:             * 
0507:             * @param user
0508:             *        The Edit to cancel.
0509:             */
0510:            public void cancelContainer(Edit edit) {
0511:                if (m_locksAreInDb) {
0512:                    // use this connection that is stored with the lock
0513:                    Connection lock = (Connection) m_locks.get(edit
0514:                            .getReference());
0515:                    if (lock == null) {
0516:                        M_log.warn("cancelContainer(): edit not in locks");
0517:                        return;
0518:                    }
0519:
0520:                    // rollback and release the lock's connection
0521:                    m_sql.dbCancel(lock);
0522:
0523:                    // release the lock
0524:                    m_locks.remove(edit.getReference());
0525:                }
0526:
0527:                else if (m_locksAreInTable) {
0528:                    // remove the lock
0529:                    String statement = "delete from SAKAI_LOCKS where TABLE_NAME = ? and RECORD_ID = ?";
0530:
0531:                    // collect the fields
0532:                    Object lockFields[] = new Object[2];
0533:                    lockFields[0] = m_containerTableName;
0534:                    lockFields[1] = internalRecordId(edit.getReference());
0535:                    boolean ok = m_sql.dbWrite(statement, lockFields);
0536:                    if (!ok) {
0537:                        M_log.warn("cancelContainer: missing lock for table: "
0538:                                + lockFields[0] + " key: " + lockFields[1]);
0539:                    }
0540:                }
0541:
0542:                else {
0543:                    // release the lock
0544:                    m_locks.remove(edit.getReference());
0545:                }
0546:            }
0547:
0548:            /**
0549:             * Remove this (locked) Container.
0550:             * 
0551:             * @param user
0552:             *        The Edit to remove.
0553:             */
0554:            public void removeContainer(Edit edit) {
0555:                // form the SQL delete statement
0556:                String statement = "delete from " + m_containerTableName
0557:                        + " where " + m_containerTableIdField + " = ? ";
0558:                Object[] fields = new Object[1];
0559:                fields[0] = edit.getReference();
0560:
0561:                if (m_locksAreInDb) {
0562:                    // use this connection that is stored with the lock
0563:                    Connection lock = (Connection) m_locks.get(edit
0564:                            .getReference());
0565:                    if (lock == null) {
0566:                        M_log.warn("removeContainer(): edit not in locks");
0567:                        return;
0568:                    }
0569:
0570:                    // process the delete statement, commit, and release the lock's connection
0571:                    m_sql.dbUpdateCommit(statement, fields, null, lock);
0572:
0573:                    // release the lock
0574:                    m_locks.remove(edit.getReference());
0575:                }
0576:
0577:                else if (m_locksAreInTable) {
0578:                    // process the delete statement
0579:                    m_sql.dbWrite(statement, fields);
0580:
0581:                    // remove the lock
0582:                    statement = "delete from SAKAI_LOCKS where TABLE_NAME = ? and RECORD_ID = ?";
0583:
0584:                    // collect the fields
0585:                    Object lockFields[] = new Object[2];
0586:                    lockFields[0] = m_containerTableName;
0587:                    lockFields[1] = internalRecordId(edit.getReference());
0588:                    boolean ok = m_sql.dbWrite(statement, lockFields);
0589:                    if (!ok) {
0590:                        M_log.warn("remove: missing lock for table: "
0591:                                + lockFields[0] + " key: " + lockFields[1]);
0592:                    }
0593:                }
0594:
0595:                else {
0596:                    // process the delete statement
0597:                    m_sql.dbWrite(statement, fields);
0598:
0599:                    // release the lock
0600:                    m_locks.remove(edit.getReference());
0601:                }
0602:            }
0603:
0604:            /**
0605:             * Read one Resource from xml
0606:             * 
0607:             * @param container
0608:             *        The container for this resource.
0609:             * @param xml
0610:             *        An string containing the xml which describes the resource.
0611:             * @return The Resource object created from the xml.
0612:             */
0613:            protected Entity readResource(Entity container, String xml) {
0614:                try {
0615:                    // read the xml
0616:                    Document doc = Xml.readDocumentFromString(xml);
0617:
0618:                    // verify the root element
0619:                    Element root = doc.getDocumentElement();
0620:                    if (!root.getTagName().equals(m_resourceEntryTagName)) {
0621:                        M_log.warn("readResource(): not = "
0622:                                + m_resourceEntryTagName + " : "
0623:                                + root.getTagName());
0624:                        return null;
0625:                    }
0626:
0627:                    // re-create a resource
0628:                    Entity entry = m_user.newResource(container, root);
0629:
0630:                    return entry;
0631:                } catch (Exception e) {
0632:                    M_log.debug("readResource(): ", e);
0633:                    return null;
0634:                }
0635:            }
0636:
0637:            /**
0638:             * Check if a Resource by this id exists.
0639:             * 
0640:             * @param container
0641:             *        The container for this resource.
0642:             * @param id
0643:             *        The id.
0644:             * @return true if a Resource by this id exists, false if not.
0645:             */
0646:            public boolean checkResource(Entity container, String id) {
0647:                // just see if the record exists
0648:                String sql = "select " + m_resourceTableIdField + "  from "
0649:                        + m_resourceTableName + " where ("
0650:                        + m_resourceTableContainerIdField + " = ? )"
0651:                        + " and ( " + m_resourceTableIdField + " = ? )";
0652:                Object[] fields = new Object[2];
0653:                fields[0] = container.getReference();
0654:                fields[1] = id;
0655:                List ids = m_sql.dbRead(sql, fields, null);
0656:                return (!ids.isEmpty());
0657:            }
0658:
0659:            /**
0660:             * Get the Resource with this id, or null if not found.
0661:             * 
0662:             * @param container
0663:             *        The container for this resource.
0664:             * @param id
0665:             *        The id.
0666:             * @return The Resource with this id, or null if not found.
0667:             */
0668:            public Entity getResource(Entity container, String id) {
0669:                Entity entry = null;
0670:
0671:                // get the user from the db
0672:                String sql = "select XML from " + m_resourceTableName
0673:                        + " where (" + m_resourceTableContainerIdField
0674:                        + " = ? )" + " and ( " + m_resourceTableIdField
0675:                        + " = ? )";
0676:                Object[] fields = new Object[2];
0677:                fields[0] = container.getReference();
0678:                fields[1] = id;
0679:                List xml = m_sql.dbRead(sql, fields, null);
0680:                if (!xml.isEmpty()) {
0681:                    // create the Resource from the db xml
0682:                    entry = readResource(container, (String) xml.get(0));
0683:                }
0684:
0685:                return entry;
0686:            }
0687:
0688:            /**
0689:             * Get all Resources.
0690:             * 
0691:             * @param container
0692:             *        The container for this resource.
0693:             * @return The list (Resource) of all Resources.
0694:             */
0695:            public List getAllResources(Entity container) {
0696:                List all = new Vector();
0697:
0698:                // read all users from the db
0699:                String sql = "select XML from "
0700:                        + m_resourceTableName
0701:                        + " where ("
0702:                        + m_resourceTableContainerIdField
0703:                        + " = ? )"
0704:                        + ((m_resourceTableOrderField != null) ? (" order by "
0705:                                + m_resourceTableOrderField + " asc") : "");
0706:                Object[] fields = new Object[1];
0707:                fields[0] = container.getReference();
0708:                List xml = m_sql.dbRead(sql, fields, null);
0709:
0710:                // process all result xml into user objects
0711:                if (!xml.isEmpty()) {
0712:                    for (int i = 0; i < xml.size(); i++) {
0713:                        Entity entry = readResource(container, (String) xml
0714:                                .get(i));
0715:                        if (entry != null)
0716:                            all.add(entry);
0717:                    }
0718:                }
0719:
0720:                return all;
0721:            }
0722:
0723:            /**
0724:             * Add a new Resource with this id.
0725:             * 
0726:             * @param container
0727:             *        The container for this resource.
0728:             * @param id
0729:             *        The id.
0730:             * @param others
0731:             *        Other fields for the newResource call
0732:             * @return The locked Resource object with this id, or null if the id is in use.
0733:             */
0734:            public Edit putResource(Entity container, String id, Object[] others) {
0735:                // create one with just the id, and perhaps some other fields, too
0736:                Entity entry = m_user.newResource(container, id, others);
0737:
0738:                // form the XML and SQL for the insert
0739:                Document doc = Xml.createDocument();
0740:                entry.toXml(doc, new Stack());
0741:                String xml = Xml.writeDocumentToString(doc);
0742:
0743:                String statement = "insert into "
0744:                        + m_resourceTableName
0745:                        + insertFields(m_containerTableIdField,
0746:                                m_resourceTableIdField,
0747:                                m_resourceTableOtherFields, "XML")
0748:                        + " values ( " + "?, ?, "
0749:                        + valuesParams(m_resourceTableOtherFields) + " ? )";
0750:
0751:                Object[] flds = m_user.storageFields(entry);
0752:                if (flds == null)
0753:                    flds = new Object[0];
0754:                Object[] fields = new Object[flds.length + 3];
0755:                System.arraycopy(flds, 0, fields, 2, flds.length);
0756:                fields[0] = container.getReference();
0757:                fields[1] = entry.getId();
0758:                fields[fields.length - 1] = xml;
0759:
0760:                // process the insert
0761:                boolean ok = m_sql.dbWrite(statement, fields);
0762:
0763:                // if this failed, assume a key conflict (i.e. id in use)
0764:                if (!ok)
0765:                    return null;
0766:
0767:                // now get a lock on the record for edit
0768:                Edit edit = editResource(container, id);
0769:                if (edit == null) {
0770:                    M_log.warn("putResource(): didn't get a lock!");
0771:                    return null;
0772:                }
0773:
0774:                return edit;
0775:            }
0776:
0777:            /**
0778:             * Get a lock on the Resource with this id, or null if a lock cannot be gotten.
0779:             * 
0780:             * @param container
0781:             *        The container for this resource.
0782:             * @param id
0783:             *        The user id.
0784:             * @return The locked Resource with this id, or null if this records cannot be locked.
0785:             */
0786:            public Edit editResource(Entity container, String id) {
0787:                Edit edit = null;
0788:
0789:                if (m_locksAreInDb) {
0790:                    if ("oracle".equals(m_sql.getVendor())) {
0791:                        // read the record and get a lock on it (non blocking)
0792:                        String statement = "select XML from "
0793:                                + m_resourceTableName + " where ("
0794:                                + m_resourceTableContainerIdField + " ='"
0795:                                + Validator.escapeSql(container.getReference())
0796:                                + "' )" + " and ( " + m_resourceTableIdField
0797:                                + " = '" + Validator.escapeSql(id) + "' )"
0798:                                + " for update nowait";
0799:                        StringBuffer result = new StringBuffer();
0800:                        Connection lock = m_sql.dbReadLock(statement, result);
0801:
0802:                        // for missing or already locked...
0803:                        if ((lock == null) || (result.length() == 0))
0804:                            return null;
0805:
0806:                        // make first a Resource, then an Edit
0807:                        Entity entry = readResource(container, result
0808:                                .toString());
0809:                        edit = m_user.newResourceEdit(container, entry);
0810:
0811:                        // store the lock for this object
0812:                        m_locks.put(entry.getReference(), lock);
0813:                    } else {
0814:                        throw new UnsupportedOperationException(
0815:                                "Record locking only available when configured with Oracle database");
0816:                    }
0817:                }
0818:
0819:                // if the locks are in a separate table in the db
0820:                else if (m_locksAreInTable) {
0821:                    // get the entry, and check for existence
0822:                    Entity entry = getResource(container, id);
0823:                    if (entry == null)
0824:                        return null;
0825:
0826:                    // write a lock to the lock table - if we can do it, we get the lock
0827:                    String statement = "insert into SAKAI_LOCKS"
0828:                            + " (TABLE_NAME,RECORD_ID,LOCK_TIME,USAGE_SESSION_ID)"
0829:                            + " values (?, ?, ?, ?)";
0830:
0831:                    // we need session id and user id
0832:                    String sessionId = UsageSessionService.getSessionId();
0833:                    if (sessionId == null) {
0834:                        sessionId = "";
0835:                    }
0836:
0837:                    // collect the fields
0838:                    Object fields[] = new Object[4];
0839:                    fields[0] = m_resourceTableName;
0840:                    fields[1] = internalRecordId(container.getReference() + "/"
0841:                            + id);
0842:                    fields[2] = TimeService.newTime();
0843:                    fields[3] = sessionId;
0844:
0845:                    // add the lock - if fails, someone else has the lock
0846:                    boolean ok = m_sql
0847:                            .dbWriteFailQuiet(null, statement, fields);
0848:                    if (!ok) {
0849:                        return null;
0850:                    }
0851:
0852:                    // make the edit from the Resource
0853:                    edit = m_user.newResourceEdit(container, entry);
0854:                }
0855:
0856:                // otherwise, get the lock locally
0857:                else {
0858:                    // get the entry, and check for existence
0859:                    Entity entry = getResource(container, id);
0860:                    if (entry == null)
0861:                        return null;
0862:
0863:                    // we only sync this getting - someone may release a lock out of sync
0864:                    synchronized (m_locks) {
0865:                        // if already locked
0866:                        if (m_locks.containsKey(entry.getReference()))
0867:                            return null;
0868:
0869:                        // make the edit from the Resource
0870:                        edit = m_user.newResourceEdit(container, entry);
0871:
0872:                        // store the edit in the locks by reference
0873:                        m_locks.put(entry.getReference(), edit);
0874:                    }
0875:                }
0876:
0877:                return edit;
0878:            }
0879:
0880:            /**
0881:             * Commit the changes and release the lock.
0882:             * 
0883:             * @param container
0884:             *        The container for this resource.
0885:             * @param user
0886:             *        The Edit to commit.
0887:             */
0888:            public void commitResource(Entity container, Edit edit) {
0889:                // form the SQL statement and the var w/ the XML
0890:                Document doc = Xml.createDocument();
0891:                edit.toXml(doc, new Stack());
0892:                String xml = Xml.writeDocumentToString(doc);
0893:                String statement = "update "
0894:                        + m_resourceTableName
0895:                        // %%% others
0896:                        + " set " + updateSet(m_resourceTableOtherFields)
0897:                        + " XML = ?" + " where ("
0898:                        + m_resourceTableContainerIdField + " = ? )"
0899:                        + " and ( " + m_resourceTableIdField + " = ? )";
0900:
0901:                Object[] flds = m_user.storageFields(edit);
0902:                if (flds == null)
0903:                    flds = new Object[0];
0904:                Object[] fields = new Object[flds.length + 3];
0905:                System.arraycopy(flds, 0, fields, 0, flds.length);
0906:                fields[fields.length - 3] = xml;
0907:                fields[fields.length - 2] = container.getReference();
0908:                fields[fields.length - 1] = edit.getId();
0909:
0910:                if (m_locksAreInDb) {
0911:                    // use this connection that is stored with the lock
0912:                    Connection lock = (Connection) m_locks.get(edit
0913:                            .getReference());
0914:                    if (lock == null) {
0915:                        M_log.warn("commitResource(): edit not in locks");
0916:                        return;
0917:                    }
0918:
0919:                    // update, commit, release the lock's connection
0920:                    m_sql.dbUpdateCommit(statement, fields, null, lock);
0921:
0922:                    // remove the lock
0923:                    m_locks.remove(edit.getReference());
0924:                }
0925:
0926:                else if (m_locksAreInTable) {
0927:                    // process the update
0928:                    m_sql.dbWrite(statement, fields);
0929:
0930:                    // remove the lock
0931:                    statement = "delete from SAKAI_LOCKS where TABLE_NAME = ? and RECORD_ID = ?";
0932:
0933:                    // collect the fields
0934:                    Object lockFields[] = new Object[2];
0935:                    lockFields[0] = m_resourceTableName;
0936:                    lockFields[1] = internalRecordId(container.getReference()
0937:                            + "/" + edit.getId());
0938:                    boolean ok = m_sql.dbWrite(statement, lockFields);
0939:                    if (!ok) {
0940:                        M_log.warn("commitResource: missing lock for table: "
0941:                                + lockFields[0] + " key: " + lockFields[1]);
0942:                    }
0943:                }
0944:
0945:                else {
0946:                    // just process the update
0947:                    m_sql.dbWrite(statement, fields);
0948:
0949:                    // remove the lock
0950:                    m_locks.remove(edit.getReference());
0951:                }
0952:            }
0953:
0954:            /**
0955:             * Cancel the changes and release the lock.
0956:             * 
0957:             * @param container
0958:             *        The container for this resource.
0959:             * @param user
0960:             *        The Edit to cancel.
0961:             */
0962:            public void cancelResource(Entity container, Edit edit) {
0963:                if (m_locksAreInDb) {
0964:                    // use this connection that is stored with the lock
0965:                    Connection lock = (Connection) m_locks.get(edit
0966:                            .getReference());
0967:                    if (lock == null) {
0968:                        M_log.warn("cancelResource(): edit not in locks");
0969:                        return;
0970:                    }
0971:
0972:                    // rollback and release the lock's connection
0973:                    m_sql.dbCancel(lock);
0974:
0975:                    // release the lock
0976:                    m_locks.remove(edit.getReference());
0977:                }
0978:
0979:                else if (m_locksAreInTable) {
0980:                    // remove the lock
0981:                    String statement = "delete from SAKAI_LOCKS where TABLE_NAME = ? and RECORD_ID = ?";
0982:
0983:                    // collect the fields
0984:                    Object lockFields[] = new Object[2];
0985:                    lockFields[0] = m_resourceTableName;
0986:                    lockFields[1] = internalRecordId(container.getReference()
0987:                            + "/" + edit.getId());
0988:                    boolean ok = m_sql.dbWrite(statement, lockFields);
0989:                    if (!ok) {
0990:                        M_log.warn("cancelResource: missing lock for table: "
0991:                                + lockFields[0] + " key: " + lockFields[1]);
0992:                    }
0993:                }
0994:
0995:                else {
0996:                    // release the lock
0997:                    m_locks.remove(edit.getReference());
0998:                }
0999:            }
1000:
1001:            /**
1002:             * Remove this (locked) Resource.
1003:             * 
1004:             * @param container
1005:             *        The container for this resource.
1006:             * @param user
1007:             *        The Edit to remove.
1008:             */
1009:            public void removeResource(Entity container, Edit edit) {
1010:                // form the SQL delete statement
1011:                String statement = "delete from " + m_resourceTableName
1012:                        + " where (" + m_resourceTableContainerIdField
1013:                        + " = ? )" + " and ( " + m_resourceTableIdField
1014:                        + " = ? )";
1015:                Object[] fields = new Object[2];
1016:                fields[0] = container.getReference();
1017:                fields[1] = edit.getId();
1018:
1019:                if (m_locksAreInDb) {
1020:                    // use this connection that is stored with the lock
1021:                    Connection lock = (Connection) m_locks.get(edit
1022:                            .getReference());
1023:                    if (lock == null) {
1024:                        M_log.warn("removeResource(): edit not in locks");
1025:                        return;
1026:                    }
1027:
1028:                    // process the delete statement, commit, and release the lock's connection
1029:                    m_sql.dbUpdateCommit(statement, fields, null, lock);
1030:
1031:                    // release the lock
1032:                    m_locks.remove(edit.getReference());
1033:                }
1034:
1035:                else if (m_locksAreInTable) {
1036:                    // process the delete statement
1037:                    m_sql.dbWrite(statement, fields);
1038:
1039:                    // remove the lock
1040:                    statement = "delete from SAKAI_LOCKS where TABLE_NAME = ? and RECORD_ID = ?";
1041:
1042:                    // collect the fields
1043:                    Object lockFields[] = new Object[2];
1044:                    lockFields[0] = m_resourceTableName;
1045:                    lockFields[1] = internalRecordId(container.getReference()
1046:                            + "/" + edit.getId());
1047:                    boolean ok = m_sql.dbWrite(statement, lockFields);
1048:                    if (!ok) {
1049:                        M_log.warn("removeResource: missing lock for table: "
1050:                                + lockFields[0] + " key: " + lockFields[1]);
1051:                    }
1052:                }
1053:
1054:                else {
1055:                    // process the delete statement
1056:                    m_sql.dbWrite(statement, fields);
1057:
1058:                    // release the lock
1059:                    m_locks.remove(edit.getReference());
1060:                }
1061:            }
1062:
1063:            /**
1064:             * Form a string of n question marks with commas, for sql value statements, one for each item in the values array, or an empty string if null.
1065:             * 
1066:             * @param values
1067:             *        The values to be inserted into the sql statement.
1068:             * @return A sql statement fragment for the values part of an insert, one for each value in the array.
1069:             */
1070:            protected String valuesParams(String[] fields) {
1071:                if ((fields == null) || (fields.length == 0))
1072:                    return "";
1073:                StringBuffer buf = new StringBuffer();
1074:                for (int i = 0; i < fields.length; i++) {
1075:                    buf.append(" ?,");
1076:                }
1077:                return buf.toString();
1078:            }
1079:
1080:            /**
1081:             * Form a string of n name=?, for sql update set statements, one for each item in the values array, or an empty string if null.
1082:             * 
1083:             * @param values
1084:             *        The values to be inserted into the sql statement.
1085:             * @return A sql statement fragment for the values part of an insert, one for each value in the array.
1086:             */
1087:            protected String updateSet(String[] fields) {
1088:                if ((fields == null) || (fields.length == 0))
1089:                    return "";
1090:                StringBuffer buf = new StringBuffer();
1091:                for (int i = 0; i < fields.length; i++) {
1092:                    buf.append(fields[i] + " = ?,");
1093:                }
1094:                return buf.toString();
1095:            }
1096:
1097:            /**
1098:             * Form a string of (field, field, field), for sql insert statements, one for each item in the fields array, plus one before, and one after.
1099:             * 
1100:             * @param before1
1101:             *        The first field name.
1102:             * @param before2
1103:             *        (options) second field name.
1104:             * @param values
1105:             *        The extra field names, in the middle.
1106:             * @param after
1107:             *        The last field name.
1108:             * @return A sql statement fragment for the insert fields.
1109:             */
1110:            protected String insertFields(String before1, String before2,
1111:                    String[] fields, String after) {
1112:                StringBuffer buf = new StringBuffer();
1113:                buf.append(" (");
1114:
1115:                buf.append(before1);
1116:                buf.append(",");
1117:
1118:                if (before2 != null) {
1119:                    buf.append(before2);
1120:                    buf.append(",");
1121:                }
1122:
1123:                if (fields != null) {
1124:                    for (int i = 0; i < fields.length; i++) {
1125:                        buf.append(fields[i] + ",");
1126:                    }
1127:                }
1128:
1129:                buf.append(after);
1130:
1131:                buf.append(")");
1132:
1133:                return buf.toString();
1134:            }
1135:
1136:            /**
1137:             * Get resources filtered by date and count and drafts, in descending (latest first) order
1138:             * 
1139:             * @param afterDate
1140:             *        if null, no date limit, else limited to only messages after this date.
1141:             * @param limitedToLatest
1142:             *        if 0, no count limit, else limited to only the latest this number of messages.
1143:             * @param draftsForId
1144:             *        how to handle drafts: null means no drafts, "*" means all, otherwise drafts only if created by this userId.
1145:             * @param pubViewOnly
1146:             *        if true, include only messages marked pubview, else include any.
1147:             * @return A list of Message objects that meet the criteria; may be empty
1148:             */
1149:            public List getResources(final Entity container, Time afterDate,
1150:                    int limitedToLatest, String draftsForId, boolean pubViewOnly) {
1151:                // if we are limiting, and are filtering out drafts or doing pubview, and don't have draft/owner/pubview support, filter here after
1152:                boolean canLimit = true;
1153:                boolean filterAfter = false;
1154:                if ((limitedToLatest > 0)
1155:                        && ((((m_resourceTableDraftField == null) || (m_resourceTableOwnerField == null)) && (!"*"
1156:                                .equals(draftsForId))) || ((m_resourceTablePubViewField == null) && pubViewOnly))) {
1157:                    canLimit = false;
1158:                    filterAfter = true;
1159:                }
1160:
1161:                StringBuffer buf = new StringBuffer();
1162:                int numFields = 1;
1163:
1164:                // start the outer statement, later finished with a limiting clause
1165:                if ((limitedToLatest > 0) && canLimit) {
1166:                    if ("oracle".equals(m_sql.getVendor())) {
1167:                        buf.append("select XML from (");
1168:                        buf.append("select XML from " + m_resourceTableName);
1169:                    } else if ("mysql".equals(m_sql.getVendor())) {
1170:                        buf.append("select messages.XML from (");
1171:                        buf.append("select XML from " + m_resourceTableName);
1172:                    } else
1173:                    // if ("hsqldb".equals(m_sql.getVendor()))
1174:                    {
1175:                        // according to SQL2000 specification (used by HSQLDB) the limit clause appears first
1176:                        buf.append("select limit 0 " + limitedToLatest
1177:                                + " XML from " + m_resourceTableName);
1178:                    }
1179:                } else {
1180:                    buf.append("select XML from " + m_resourceTableName);
1181:                }
1182:
1183:                buf.append(" where (" + m_resourceTableContainerIdField
1184:                        + " = ?");
1185:
1186:                if ((m_resourceTableOrderField != null) && (afterDate != null)) {
1187:                    buf.append(" and " + m_resourceTableOrderField + " > ?");
1188:                    numFields++;
1189:                }
1190:
1191:                // deal with drafts if we can
1192:                if ((m_resourceTableDraftField != null)
1193:                        && (m_resourceTableOwnerField != null)) {
1194:                    // if draftsForId is null, we don't want any drafts
1195:                    if (draftsForId == null) {
1196:                        buf.append(" and " + m_resourceTableDraftField
1197:                                + " = '0'");
1198:                    }
1199:                    // else a "*" means we take all drafts
1200:                    else if (!"*".equals(draftsForId)) {
1201:                        // we want only drafts if the owner field matches
1202:                        buf.append(" and ( " + m_resourceTableDraftField
1203:                                + " = '0' or " + m_resourceTableOwnerField
1204:                                + " = ? )");
1205:                        numFields++;
1206:                    }
1207:                }
1208:
1209:                // pubview
1210:                if ((m_resourceTablePubViewField != null) && pubViewOnly) {
1211:                    buf
1212:                            .append(" and " + m_resourceTablePubViewField
1213:                                    + " = '1'");
1214:                }
1215:
1216:                // close the where
1217:                buf.append(")");
1218:
1219:                if (m_resourceTableOrderField != null) {
1220:                    buf.append(" order by " + m_resourceTableOrderField
1221:                            + " desc");
1222:                }
1223:
1224:                boolean useLimitField = false;
1225:                if ((limitedToLatest > 0) && canLimit) {
1226:                    if ("oracle".equals(m_sql.getVendor())) {
1227:                        buf.append(" ) where rownum <= ?");
1228:                        numFields++;
1229:                        useLimitField = true;
1230:                    } else if ("mysql".equals(m_sql.getVendor())) {
1231:                        buf.append(" ) AS messages LIMIT " + limitedToLatest);
1232:                        useLimitField = false;
1233:                    } else
1234:                    // if ("hsqldb".equals(m_sql.getVendor()))
1235:                    {
1236:                        // the limit clause appears elsewhere in HSQLDB SQL statements, not here.
1237:                    }
1238:                }
1239:
1240:                // build up the fields
1241:                Object fields[] = new Object[numFields];
1242:                fields[0] = container.getReference();
1243:                int pos = 1;
1244:                if ((m_resourceTableOrderField != null) && (afterDate != null)) {
1245:                    fields[pos++] = afterDate;
1246:                }
1247:                if ((m_resourceTableDraftField != null)
1248:                        && (m_resourceTableOwnerField != null)
1249:                        && (draftsForId != null) && (!"*".equals(draftsForId))) {
1250:                    fields[pos++] = draftsForId;
1251:                }
1252:                if (useLimitField) {
1253:                    fields[pos++] = new Integer(limitedToLatest);
1254:                }
1255:
1256:                List all = m_sql.dbRead(buf.toString(), fields,
1257:                        new SqlReader() {
1258:                            public Object readSqlResultRecord(ResultSet result) {
1259:                                try {
1260:                                    // get the xml and parse into a Resource
1261:                                    String xml = result.getString(1);
1262:                                    Entity entry = readResource(container, xml);
1263:                                    return entry;
1264:                                } catch (SQLException ignore) {
1265:                                    return null;
1266:                                }
1267:                            }
1268:                        });
1269:
1270:                // after filter for draft / pubview and limit
1271:                if (filterAfter) {
1272:                    Vector v = new Vector();
1273:
1274:                    // deal with drafts / pubview
1275:                    for (Iterator i = all.iterator(); i.hasNext();) {
1276:                        Entity r = (Entity) i.next();
1277:                        Entity candidate = null;
1278:                        if (m_user.isDraft(r)) {
1279:                            // if some drafts
1280:                            if ((draftsForId != null)
1281:                                    && (m_user.getOwnerId(r)
1282:                                            .equals(draftsForId))) {
1283:                                candidate = r;
1284:                            }
1285:                        } else {
1286:                            candidate = r;
1287:                        }
1288:
1289:                        // if we have a candidate to add, and we need pub view only
1290:                        if ((candidate != null) && pubViewOnly) {
1291:                            // if this is not pub view, skip it
1292:                            if ((candidate.getProperties().getProperty(
1293:                                    ResourceProperties.PROP_PUBVIEW) == null)) {
1294:                                candidate = null;
1295:                            }
1296:                        }
1297:
1298:                        if (candidate != null) {
1299:                            v.add(candidate);
1300:                        }
1301:                    }
1302:
1303:                    // pick what we need
1304:                    if (limitedToLatest < v.size()) {
1305:                        all = v.subList(0, limitedToLatest);
1306:                    } else {
1307:                        all = v;
1308:                    }
1309:                }
1310:
1311:                return all;
1312:            }
1313:
1314:            /**
1315:             * Access a list of container ids match (start with) the root.
1316:             * 
1317:             * @param context
1318:             *        The id root to match.
1319:             * @return A List (String) of container id which match the root.
1320:             */
1321:            public List getContainerIdsMatching(String root) {
1322:                // the id of each container will be the part that follows the root reference
1323:                final int pos = root.length();
1324:
1325:                // read all users from the db
1326:                String sql = "select " + m_containerTableIdField + " from "
1327:                        + m_containerTableName + " where "
1328:                        + m_containerTableIdField + " like ?";
1329:                Object fields[] = new Object[1];
1330:                fields[0] = root + "%";
1331:
1332:                List all = m_sql.dbRead(sql, fields, new SqlReader() {
1333:                    public Object readSqlResultRecord(ResultSet result) {
1334:                        try {
1335:                            // get the reference form and pull off the id (what follows after the root)
1336:                            String ref = result.getString(1);
1337:                            String id = ref.substring(pos);
1338:                            return id;
1339:                        } catch (SQLException ignore) {
1340:                            return null;
1341:                        }
1342:                    }
1343:                });
1344:
1345:                return all;
1346:            }
1347:
1348:            /**
1349:             * Return a record ID to use internally in the database. This is needed for databases (MySQL) that have limits on key lengths. The hash code ensures that the record ID will be unique, even if the DB only considers a prefix of a very long record ID.
1350:             * 
1351:             * @param recordId
1352:             * @return The record ID to use internally in the database
1353:             */
1354:            private String internalRecordId(String recordId) {
1355:                if ("mysql".equals(m_sql.getVendor())) {
1356:                    if (recordId == null)
1357:                        recordId = "null";
1358:                    return recordId.hashCode() + " - " + recordId;
1359:                } else
1360:                // oracle, hsqldb
1361:                {
1362:                    return recordId;
1363:                }
1364:            }
1365:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.