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.comment;
017:
018: import org.outerj.daisy.repository.commonimpl.comment.CommentStrategy;
019: import org.outerj.daisy.repository.commonimpl.comment.CommentImpl;
020: import org.outerj.daisy.repository.commonimpl.AuthenticatedUser;
021: import org.outerj.daisy.repository.commonimpl.DocId;
022: import org.outerj.daisy.repository.comment.CommentVisibility;
023: import org.outerj.daisy.repository.comment.Comment;
024: import org.outerj.daisy.repository.RepositoryException;
025: import org.outerj.daisy.repository.AccessException;
026: import org.outerj.daisy.repository.VariantKey;
027: import org.outerj.daisy.repository.serverimpl.LocalRepositoryManager;
028: import org.outerj.daisy.repository.serverimpl.AbstractLocalStrategy;
029: import org.outerj.daisy.repository.acl.AclResultInfo;
030: import org.outerj.daisy.repository.acl.AclPermission;
031: import org.outerj.daisy.jdbcutil.JdbcHelper;
032: import org.apache.xmlbeans.XmlObject;
033: import org.outerx.daisy.x10.CommentCreatedDocument;
034: import org.outerx.daisy.x10.CommentDeletedDocument;
035:
036: import java.sql.*;
037: import java.util.Date;
038: import java.util.ArrayList;
039: import java.util.List;
040:
041: public class LocalCommentStrategy extends AbstractLocalStrategy
042: implements CommentStrategy {
043: public LocalCommentStrategy(LocalRepositoryManager.Context context,
044: AuthenticatedUser systemUser, JdbcHelper jdbcHelper) {
045: super (context, systemUser, jdbcHelper);
046: }
047:
048: public CommentImpl storeComment(DocId docId, long branchId,
049: long languageId, CommentVisibility visibility, String text,
050: AuthenticatedUser user) throws RepositoryException {
051:
052: // check ACL. Currently we assume that everyone with read access can add comments. Usually, this would
053: // mean we don't even have to check this permission here since otherwise the user wouldn't have been
054: // able to get a handle on the document in the first place, except if meanwhile the ACL was updated.
055: AclResultInfo aclInfo = context.getCommonRepository()
056: .getAccessManager().getAclInfoOnLive(systemUser,
057: user.getId(), user.getActiveRoleIds(), docId,
058: branchId, languageId);
059: if (!aclInfo.isAllowed(AclPermission.READ))
060: throw new AccessException("User "
061: + user.getId()
062: + " is not allowed to add comments to "
063: + getFormattedVariant(new VariantKey(docId
064: .toString(), branchId, languageId)));
065: if (visibility == CommentVisibility.EDITORS
066: && !aclInfo.isAllowed(AclPermission.WRITE))
067: throw new RepositoryException(
068: "Comments with editors-only visibility can only be created by users with write rights to the document variant.");
069:
070: Connection conn = null;
071: PreparedStatement stmt = null;
072: try {
073: conn = context.getDataSource().getConnection();
074: jdbcHelper.startTransaction(conn);
075:
076: long commentId = context.getNextCommentId();
077: Date createdOn = new Date();
078:
079: stmt = conn
080: .prepareStatement("insert into comments (id, doc_id, ns_id, branch_id, lang_id, created_by, created_on, visibility, comment_text) values (?,?,?,?,?,?,?,?,?)");
081: stmt.setLong(1, commentId);
082: stmt.setLong(2, docId.getSeqId());
083: stmt.setLong(3, docId.getNsId());
084: stmt.setLong(4, branchId);
085: stmt.setLong(5, languageId);
086: stmt.setLong(6, user.getId());
087: stmt.setTimestamp(7, new Timestamp(createdOn.getTime()));
088: stmt.setString(8, visibility.getCode());
089: stmt.setString(9, text);
090: stmt.execute();
091: stmt.close();
092:
093: CommentImpl newComment = new CommentImpl(docId, branchId,
094: languageId, commentId, text, visibility, createdOn,
095: user.getId());
096:
097: // make async event
098: XmlObject eventDescription = createCommentCreatedEvent(newComment);
099: eventHelper.createEvent(eventDescription, "CommentCreated",
100: conn);
101:
102: conn.commit();
103:
104: return newComment;
105: } catch (Throwable e) {
106: jdbcHelper.rollback(conn);
107: throw new RepositoryException("Problem storing comment.", e);
108: } finally {
109: jdbcHelper.closeStatement(stmt);
110: jdbcHelper.closeConnection(conn);
111: }
112: }
113:
114: public CommentCreatedDocument createCommentCreatedEvent(
115: Comment comment) {
116: CommentCreatedDocument commentCreatedDocument = CommentCreatedDocument.Factory
117: .newInstance();
118: CommentCreatedDocument.CommentCreated commentCreated = commentCreatedDocument
119: .addNewCommentCreated();
120: commentCreated.addNewNewComment().setComment(
121: comment.getXml().getComment());
122: return commentCreatedDocument;
123: }
124:
125: public void deleteComment(DocId docId, long branchId,
126: long languageId, long id, AuthenticatedUser user)
127: throws RepositoryException {
128:
129: AclResultInfo aclInfo = context.getCommonRepository()
130: .getAccessManager().getAclInfoOnLive(systemUser,
131: user.getId(), user.getActiveRoleIds(), docId,
132: branchId, languageId);
133: boolean writeAccess = aclInfo.isAllowed(AclPermission.WRITE);
134:
135: Connection conn = null;
136: PreparedStatement stmt = null;
137: try {
138: conn = context.getDataSource().getConnection();
139: jdbcHelper.startTransaction(conn);
140:
141: stmt = conn
142: .prepareStatement("select visibility, comment_text, created_by, created_on from comments where doc_id = ? and ns_id = ? and branch_id = ? and lang_id = ? and id = ? "
143: + jdbcHelper.getSharedLockClause());
144: stmt.setLong(1, docId.getSeqId());
145: stmt.setLong(2, docId.getNsId());
146: stmt.setLong(3, branchId);
147: stmt.setLong(4, languageId);
148: stmt.setLong(5, id);
149: ResultSet rs = stmt.executeQuery();
150:
151: CommentImpl comment;
152: if (rs.next()) {
153: comment = new CommentImpl(docId, branchId, languageId,
154: id, rs.getString("comment_text"),
155: CommentVisibility.getByCode(rs
156: .getString("visibility")), rs
157: .getDate("created_on"), rs
158: .getLong("created_by"));
159: } else {
160: throw new RepositoryException("The document " + docId
161: + ", branch " + getBranchLabel(branchId)
162: + ", language " + getLanguageLabel(languageId)
163: + " doesn't have a comment with ID " + id + ".");
164: }
165: stmt.close();
166:
167: boolean canDelete = true;
168: if (!user.isInAdministratorRole()) {
169: if (!writeAccess
170: && comment.getVisibility() != CommentVisibility.PRIVATE)
171: canDelete = false;
172: if (comment.getVisibility() == CommentVisibility.PRIVATE
173: && comment.getCreatedBy() != user.getId())
174: canDelete = false;
175: }
176:
177: if (!canDelete)
178: throw new RepositoryException(
179: "You are not allowed to remove comment "
180: + id
181: + " of "
182: + getFormattedVariant(new VariantKey(
183: docId.toString(), branchId,
184: languageId)));
185:
186: stmt = conn
187: .prepareStatement("delete from comments where id = ? and doc_id = ? and ns_id = ? and branch_id = ? and lang_id = ?");
188: stmt.setLong(1, id);
189: stmt.setLong(2, docId.getSeqId());
190: stmt.setLong(3, docId.getNsId());
191: stmt.setLong(4, branchId);
192: stmt.setLong(5, languageId);
193: stmt.execute();
194: stmt.close();
195:
196: // make async event
197: XmlObject eventDescription = createCommentDeletedEvent(
198: comment, user.getId());
199: eventHelper.createEvent(eventDescription, "CommentDeleted",
200: conn);
201:
202: conn.commit();
203: } catch (Throwable e) {
204: jdbcHelper.rollback(conn);
205: throw new RepositoryException("Problem deleting comment.",
206: e);
207: } finally {
208: jdbcHelper.closeStatement(stmt);
209: jdbcHelper.closeConnection(conn);
210: }
211: }
212:
213: public CommentDeletedDocument createCommentDeletedEvent(
214: Comment comment, long deleterId) {
215: CommentDeletedDocument commentDeletedDocument = CommentDeletedDocument.Factory
216: .newInstance();
217: CommentDeletedDocument.CommentDeleted commentDeleted = commentDeletedDocument
218: .addNewCommentDeleted();
219: commentDeleted.addNewDeletedComment().setComment(
220: comment.getXml().getComment());
221: commentDeleted.setDeletedTime(getCalendar(new Date()));
222: commentDeleted.setDeleterId(deleterId);
223: return commentDeletedDocument;
224: }
225:
226: public Comment[] loadComments(DocId docId, long branchId,
227: long languageId, AuthenticatedUser user)
228: throws RepositoryException {
229: // check ACL, people need at least read access to a document to load its comments
230: AclResultInfo aclInfo = context.getCommonRepository()
231: .getAccessManager().getAclInfoOnLive(systemUser,
232: user.getId(), user.getActiveRoleIds(), docId,
233: branchId, languageId);
234: if (!aclInfo.isAllowed(AclPermission.READ))
235: throw new AccessException("User "
236: + user.getId()
237: + " cannot read the comments of "
238: + getFormattedVariant(new VariantKey(docId
239: .toString(), branchId, languageId)));
240:
241: Connection conn = null;
242: PreparedStatement stmt = null;
243: ResultSet rs;
244: try {
245: conn = context.getDataSource().getConnection();
246: StringBuilder query = new StringBuilder(SELECT_COMMENTS);
247: query
248: .append(" where doc_id = ? and ns_id = ? and branch_id = ? and lang_id = ? ");
249: query.append(" and (visibility = '").append(
250: CommentVisibility.PUBLIC.getCode()).append("'");
251: query.append(" or (visibility = '").append(
252: CommentVisibility.PRIVATE.getCode()).append(
253: "' and created_by = ?)");
254: if (aclInfo.isAllowed(AclPermission.WRITE))
255: query.append(" or visibility = '").append(
256: CommentVisibility.EDITORS.getCode())
257: .append("'");
258: query.append(") order by created_on");
259: stmt = conn.prepareStatement(query.toString());
260: stmt.setLong(1, docId.getSeqId());
261: stmt.setLong(2, docId.getNsId());
262: stmt.setLong(3, branchId);
263: stmt.setLong(4, languageId);
264: stmt.setLong(5, user.getId());
265: rs = stmt.executeQuery();
266: return getCommentsFromResultSet(rs);
267: } catch (Throwable e) {
268: throw new RepositoryException("Problem loading comments.",
269: e);
270: } finally {
271: jdbcHelper.closeStatement(stmt);
272: jdbcHelper.closeConnection(conn);
273: }
274: }
275:
276: public Comment[] loadComments(CommentVisibility visibility,
277: AuthenticatedUser user) throws RepositoryException {
278: Connection conn = null;
279: PreparedStatement stmt = null;
280: ResultSet rs;
281: try {
282: conn = context.getDataSource().getConnection();
283: StringBuilder query = new StringBuilder(SELECT_COMMENTS);
284: query.append(" where created_by = ?");
285: if (visibility != null)
286: query.append(" and visibility = '").append(
287: visibility.getCode()).append("'");
288: query.append(" order by created_on desc");
289: stmt = conn.prepareStatement(query.toString());
290: stmt.setLong(1, user.getId());
291: rs = stmt.executeQuery();
292: return getCommentsFromResultSet(rs);
293: } catch (Throwable e) {
294: throw new RepositoryException("Problem loading comments.",
295: e);
296: } finally {
297: jdbcHelper.closeStatement(stmt);
298: jdbcHelper.closeConnection(conn);
299: }
300: }
301:
302: public Comment[] loadComments(AuthenticatedUser user)
303: throws RepositoryException {
304: return loadComments(null, user);
305: }
306:
307: private static final String SELECT_COMMENTS = "select doc_id, ns_id, ns.name_ as ns_name, branch_id, lang_id, comments.id, comment_text, visibility, created_on, created_by from comments left join daisy_namespaces ns on (comments.ns_id = ns.id) ";
308:
309: private Comment[] getCommentsFromResultSet(ResultSet rs)
310: throws SQLException {
311: List<Comment> comments = new ArrayList<Comment>();
312: while (rs.next()) {
313: DocId docId = new DocId(rs.getLong(1), rs.getString(3), rs
314: .getLong(2));
315: CommentImpl comment = new CommentImpl(docId, rs.getLong(4),
316: rs.getLong(5), rs.getLong(6), rs.getString(7),
317: CommentVisibility.getByCode(rs.getString(8)), rs
318: .getTimestamp(9), rs.getLong(10));
319: comments.add(comment);
320: }
321: return comments.toArray(new Comment[comments.size()]);
322: }
323: }
|