001: /*
002: * Copyright 2004 Outerthought bvba and Schaubroeck nv
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.repository.serverimpl;
017:
018: import org.outerj.daisy.repository.commonimpl.CollectionStrategy;
019: import org.outerj.daisy.repository.commonimpl.AuthenticatedUser;
020: import org.outerj.daisy.repository.commonimpl.DocumentCollectionImpl;
021: import org.outerj.daisy.repository.*;
022: import org.outerj.daisy.jdbcutil.JdbcHelper;
023: import org.apache.xmlbeans.XmlObject;
024: import org.outerx.daisy.x10.CollectionCreatedDocument;
025: import org.outerx.daisy.x10.CollectionDocument;
026: import org.outerx.daisy.x10.CollectionUpdatedDocument;
027: import org.outerx.daisy.x10.CollectionDeletedDocument;
028:
029: import java.sql.*;
030: import java.util.*;
031: import java.util.Date;
032:
033: public class LocalCollectionStrategy extends AbstractLocalStrategy
034: implements CollectionStrategy {
035: private static final String STMT_SELECT_ALL_FROM_COLLECTIONS = "select id, name, last_modified, last_modifier, updatecount from collections";
036:
037: public LocalCollectionStrategy(
038: LocalRepositoryManager.Context context,
039: AuthenticatedUser systemUser, JdbcHelper jdbcHelper) {
040: super (context, systemUser, jdbcHelper);
041: }
042:
043: public void store(DocumentCollectionImpl collection)
044: throws RepositoryException {
045: logger.debug("begin storage of collection");
046: DocumentCollectionImpl.IntimateAccess collectionInt = collection
047: .getIntimateAccess(this );
048:
049: if (!collectionInt.getCurrentUser().isInAdministratorRole())
050: throw new RepositoryException(
051: "Only Administrators can create or update collections.");
052: long id = collection.getId();
053: boolean isNew = (id == -1);
054:
055: Connection conn = null;
056: PreparedStatement stmt = null;
057: try {
058: conn = context.getDataSource().getConnection();
059: jdbcHelper.startTransaction(conn);
060:
061: logger.debug("connection fetched");
062: String collectionName = collection.getName();
063: java.util.Date lastModified = new Date();
064: logger.debug("currently in object: id " + id + " colname: "
065: + collectionName + " lastMod: " + lastModified);
066: /* The user that requested the Collection is now persisting it,
067: * therefore he will be the last modifier
068: */
069: long lastModifier = collectionInt.getCurrentUser().getId();
070: XmlObject eventDescription;
071:
072: if (id == -1) {
073: //a new collection must be stored in the data store
074: stmt = conn
075: .prepareStatement("insert into collections(id, name, last_modified, last_modifier, updatecount) values (?,?,?,?,?)");
076: id = context.getNextCollectionId();
077: stmt.setLong(1, id);
078: stmt.setString(2, collectionName);
079: stmt.setTimestamp(3, new Timestamp(lastModified
080: .getTime()));
081: stmt.setLong(4, lastModifier);
082: stmt.setLong(5, 1L);
083: stmt.execute();
084: stmt.close();
085:
086: eventDescription = createCollectionCreatedEvent(
087: collection, id, lastModified);
088: } else {
089: //we have to update an existing collection
090:
091: // check if nobody else changed it in the meantime
092: stmt = conn
093: .prepareStatement("select updatecount from collections where id = ? "
094: + jdbcHelper.getSharedLockClause());
095: stmt.setLong(1, id);
096: ResultSet rs = stmt.executeQuery();
097: if (!rs.next()) {
098: throw new RepositoryException(
099: "Unexpected error: the Collection with id "
100: + id
101: + " does not exist in the database.");
102: } else {
103: long dbUpdateCount = rs.getLong(1);
104: if (dbUpdateCount != collection.getUpdateCount())
105: throw new ConcurrentUpdateException(
106: DocumentCollection.class.getName(),
107: String.valueOf(collection.getId()));
108: }
109: stmt.close();
110:
111: DocumentCollectionImpl oldCollection = loadCollectionInt(
112: collection.getId(), collectionInt
113: .getCurrentUser(), conn);
114:
115: stmt = conn
116: .prepareStatement("update collections set name=?, last_modified=?, last_modifier=?, updatecount=? where id=?");
117: stmt.setString(1, collectionName);
118: stmt.setTimestamp(2, new Timestamp(lastModified
119: .getTime()));
120: stmt.setLong(3, lastModifier);
121: stmt.setLong(4, collection.getUpdateCount() + 1);
122: stmt.setLong(5, id);
123: stmt.execute();
124: stmt.close();
125:
126: eventDescription = createCollectionUpdatedEvent(
127: oldCollection, collection, lastModified,
128: collection.getUpdateCount() + 1);
129: }
130:
131: eventHelper.createEvent(eventDescription,
132: isNew ? "CollectionCreated" : "CollectionUpdated",
133: conn);
134:
135: //everything went ok, so we can actively update the collection OBJECT as well.
136: collectionInt.saved(id, collectionName, lastModified,
137: lastModifier, collection.getUpdateCount() + 1);
138: conn.commit();
139: } catch (Throwable e) {
140: jdbcHelper.rollback(conn);
141: throw new RepositoryException("Error storing collection.",
142: e);
143: } finally {
144: jdbcHelper.closeStatement(stmt);
145: jdbcHelper.closeConnection(conn);
146: logger.debug("collection storage complete");
147: }
148:
149: if (isNew)
150: context.getCommonRepository().fireRepositoryEvent(
151: RepositoryEventType.COLLECTION_CREATED,
152: new Long(id), collection.getUpdateCount());
153: else
154: context.getCommonRepository().fireRepositoryEvent(
155: RepositoryEventType.COLLECTION_UPDATED,
156: new Long(id), collection.getUpdateCount());
157: }
158:
159: public DocumentCollectionImpl loadCollection(long collectionId,
160: AuthenticatedUser user) throws RepositoryException {
161: Connection conn = null;
162: try {
163: conn = context.getDataSource().getConnection();
164: jdbcHelper.startTransaction(conn);
165: return loadCollectionInt(collectionId, user, conn);
166: } catch (Throwable e) {
167: throw new RepositoryException("Error loading collection.",
168: e);
169: } finally {
170: jdbcHelper.closeConnection(conn);
171: }
172: }
173:
174: private DocumentCollectionImpl loadCollectionInt(long collectionId,
175: AuthenticatedUser user, Connection conn)
176: throws RepositoryException {
177: PreparedStatement stmt = null;
178: try {
179: logger.debug("begin fetching collection with collectionId "
180: + collectionId);
181: stmt = conn
182: .prepareStatement("select id, name, last_modified, last_modifier, updatecount from collections where id = ? ");
183: stmt.setLong(1, collectionId);
184: ResultSet rs = stmt.executeQuery();
185: if (!rs.next())
186: throw new CollectionNotFoundException(collectionId);
187:
188: DocumentCollectionImpl collection;
189:
190: String name = rs.getString(2);
191: Date lastModified = rs.getTimestamp(3);
192: long lastModifier = rs.getLong(4);
193: long updateCount = rs.getLong(5);
194:
195: collection = new DocumentCollectionImpl(this , name, user);
196: DocumentCollectionImpl.IntimateAccess collectionInt = collection
197: .getIntimateAccess(this );
198: collectionInt.saved(collectionId, name, lastModified,
199: lastModifier, updateCount);
200: return collection;
201: } catch (Throwable e) {
202: throw new RepositoryException("Error loading collection.",
203: e);
204: } finally {
205: jdbcHelper.closeStatement(stmt);
206: logger.debug("collection load completed");
207: }
208: }
209:
210: public DocumentCollectionImpl loadCollectionByName(String name,
211: AuthenticatedUser user) throws RepositoryException {
212: Connection conn = null;
213: PreparedStatement stmt = null;
214: long id;
215: try {
216: conn = context.getDataSource().getConnection();
217: jdbcHelper.startTransaction(conn);
218:
219: stmt = conn
220: .prepareStatement("select id from collections where name = ?");
221: stmt.setString(1, name);
222: ResultSet rs = stmt.executeQuery();
223: if (!rs.next())
224: throw new CollectionNotFoundException(name);
225:
226: id = rs.getLong(1);
227: stmt.close();
228:
229: return loadCollectionInt(id, user, conn);
230: } catch (Throwable e) {
231: throw new RepositoryException("Error loading collection.",
232: e);
233: } finally {
234: jdbcHelper.closeStatement(stmt);
235: jdbcHelper.closeConnection(conn);
236: }
237: }
238:
239: public Collection<DocumentCollectionImpl> loadCollections(
240: AuthenticatedUser user) throws RepositoryException {
241: PreparedStatement stmt = null;
242: Connection conn = null;
243:
244: try {
245: conn = context.getDataSource().getConnection();
246: jdbcHelper.startTransaction(conn);
247:
248: stmt = conn
249: .prepareStatement(STMT_SELECT_ALL_FROM_COLLECTIONS);
250: ResultSet rs = stmt.executeQuery();
251:
252: List<DocumentCollectionImpl> list = new ArrayList<DocumentCollectionImpl>();
253: while (rs.next()) {
254: DocumentCollectionImpl coll = getDocumentCollectionImpl(
255: user, rs);
256: list.add(coll);
257: }
258:
259: return list;
260: } catch (Throwable e) {
261: throw new RepositoryException("Error loading collections.",
262: e);
263: } finally {
264: jdbcHelper.closeStatement(stmt);
265: jdbcHelper.closeConnection(conn);
266: }
267: }
268:
269: /**
270: * Note that this method does NOT call next() on the ResultSet.
271: *
272: * @param user the user requesting the DocumentCollection
273: * @param rs the resultset that has been created for the collections table
274: * @return a DocumentCollectionImpl with the values obtained from the ResultSet
275: * @throws java.sql.SQLException
276: */
277: private DocumentCollectionImpl getDocumentCollectionImpl(
278: AuthenticatedUser user, ResultSet rs) throws SQLException {
279: DocumentCollectionImpl collection;
280:
281: long id = rs.getLong(1);
282: String name = rs.getString(2);
283: Date lastModified = rs.getTimestamp(3);
284: long lastModifier = rs.getLong(4);
285: long updateCount = rs.getLong(5);
286:
287: collection = new DocumentCollectionImpl(this , name, user);
288: DocumentCollectionImpl.IntimateAccess collectionInt = collection
289: .getIntimateAccess(this );
290: collectionInt.saved(id, name, lastModified, lastModifier,
291: updateCount);
292: return collection;
293: }
294:
295: public void deleteCollection(long collectionId,
296: AuthenticatedUser user) throws RepositoryException {
297: logger.debug("begin deletion of collection");
298:
299: if (!user.isInAdministratorRole())
300: throw new RepositoryException(
301: "Only Administrators can delete collections.");
302:
303: Connection conn = null;
304: PreparedStatement stmt = null;
305: try {
306: conn = context.getDataSource().getConnection();
307: // we'll need a transaction here...
308: jdbcHelper.startTransaction(conn);
309:
310: // retrieve collection, needed for collection deleted event
311: DocumentCollectionImpl collection = loadCollectionInt(
312: collectionId, user, conn);
313:
314: logger.debug("start by removing all the child records");
315:
316: stmt = conn
317: .prepareStatement("delete from document_collections where collection_id=?");
318: stmt.setLong(1, collectionId);
319:
320: // remark that it IS possible that no records are affected, in case the collection
321: // has been defined but a document never was added to the collection
322: stmt.executeUpdate();
323: stmt.close();
324:
325: // if the previous action went ok, we can delete the collection itself
326:
327: stmt = conn
328: .prepareStatement("delete from collections where id=?");
329: stmt.setLong(1, collectionId);
330: int amountOfRecordsModified = stmt.executeUpdate();
331: stmt.close();
332:
333: if (amountOfRecordsModified == 0)
334: throw new RepositoryException(
335: "This collection was not found in the repository!");
336:
337: XmlObject eventDescription = createCollectionDeletedEvent(collection);
338: eventHelper.createEvent(eventDescription,
339: "CollectionDeleted", conn);
340:
341: conn.commit();
342: } catch (Throwable e) {
343: jdbcHelper.rollback(conn);
344: throw new RepositoryException("Error deleting collection.",
345: e);
346: } finally {
347: jdbcHelper.closeStatement(stmt);
348: jdbcHelper.closeConnection(conn);
349: logger.debug("collection deletion complete");
350: }
351:
352: context.getCommonRepository().fireRepositoryEvent(
353: RepositoryEventType.COLLECTION_DELETED,
354: new Long(collectionId), -1);
355: }
356:
357: private CollectionCreatedDocument createCollectionCreatedEvent(
358: DocumentCollectionImpl collection, long collectionId,
359: Date lastModified) {
360: CollectionDocument.Collection collectionXml = collection
361: .getXml().getCollection();
362: collectionXml.setId(collectionId);
363: collectionXml.setLastModified(getCalendar(lastModified));
364: collectionXml.setLastModifier(collection
365: .getIntimateAccess(this ).getCurrentUser().getId());
366: collectionXml.setUpdatecount(1);
367:
368: CollectionCreatedDocument collectionCreatedDocument = CollectionCreatedDocument.Factory
369: .newInstance();
370: collectionCreatedDocument.addNewCollectionCreated()
371: .addNewNewCollection().setCollection(collectionXml);
372:
373: return collectionCreatedDocument;
374: }
375:
376: private CollectionUpdatedDocument createCollectionUpdatedEvent(
377: DocumentCollectionImpl oldCollection,
378: DocumentCollectionImpl newCollection, Date lastModified,
379: long newUpdateCount) {
380: CollectionUpdatedDocument collectionUpdatedDocument = CollectionUpdatedDocument.Factory
381: .newInstance();
382: CollectionUpdatedDocument.CollectionUpdated collectionUpdated = collectionUpdatedDocument
383: .addNewCollectionUpdated();
384:
385: collectionUpdated.addNewOldCollection().setCollection(
386: oldCollection.getXml().getCollection());
387:
388: CollectionDocument.Collection newCollectionXml = newCollection
389: .getXml().getCollection();
390: newCollectionXml.setLastModifier(newCollection
391: .getIntimateAccess(this ).getCurrentUser().getId());
392: newCollectionXml.setLastModified(getCalendar(lastModified));
393: newCollectionXml.setUpdatecount(newUpdateCount);
394:
395: collectionUpdated.addNewNewCollection().setCollection(
396: newCollectionXml);
397:
398: return collectionUpdatedDocument;
399: }
400:
401: private CollectionDeletedDocument createCollectionDeletedEvent(
402: DocumentCollectionImpl collection) {
403: CollectionDeletedDocument collectionDeletedDocument = CollectionDeletedDocument.Factory
404: .newInstance();
405: CollectionDeletedDocument.CollectionDeleted collectionDeleted = collectionDeletedDocument
406: .addNewCollectionDeleted();
407: collectionDeleted.addNewDeletedCollection().setCollection(
408: collection.getXml().getCollection());
409: collectionDeleted.setDeletedTime(new GregorianCalendar());
410: collectionDeleted.setDeleterId(collection.getIntimateAccess(
411: this).getCurrentUser().getId());
412: return collectionDeletedDocument;
413: }
414: }
|