001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/discussion/tags/sakai_2-4-1/discussion-impl/impl/src/java/org/sakaiproject/discussion/impl/DbDiscussionService.java $
003: * $Id: DbDiscussionService.java 8232 2006-04-25 01:11:55Z ggolden@umich.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 2005, 2006 The Sakai Foundation.
007: *
008: * Licensed under the Educational Community License, Version 1.0 (the "License");
009: * you may not use this file except in compliance with the License.
010: * You may obtain a copy of the License at
011: *
012: * http://www.opensource.org/licenses/ecl1.php
013: *
014: * Unless required by applicable law or agreed to in writing, software
015: * distributed under the License is distributed on an "AS IS" BASIS,
016: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: * See the License for the specific language governing permissions and
018: * limitations under the License.
019: *
020: **********************************************************************************/package org.sakaiproject.discussion.impl;
021:
022: import java.sql.Connection;
023: import java.sql.ResultSet;
024: import java.util.List;
025:
026: import org.apache.commons.logging.Log;
027: import org.apache.commons.logging.LogFactory;
028: import org.sakaiproject.db.api.SqlReader;
029: import org.sakaiproject.db.api.SqlService;
030: import org.sakaiproject.discussion.api.DiscussionMessage;
031: import org.sakaiproject.message.api.Message;
032: import org.sakaiproject.message.api.MessageChannel;
033: import org.sakaiproject.message.api.MessageChannelEdit;
034: import org.sakaiproject.message.api.MessageEdit;
035: import org.sakaiproject.time.api.Time;
036: import org.sakaiproject.util.BaseDbDoubleStorage;
037: import org.sakaiproject.util.StorageUser;
038: import org.sakaiproject.util.Xml;
039: import org.w3c.dom.Document;
040: import org.w3c.dom.Element;
041:
042: /**
043: * <p>
044: * DbDiscussionService fills out the BaseDiscussionService with a database implementation.
045: * </p>
046: * <p>
047: * The sql scripts in src/sql/chef_discussion.sql must be run on the database.
048: * </p>
049: */
050: public class DbDiscussionService extends BaseDiscussionService {
051: /** Our logger. */
052: private static Log M_log = LogFactory
053: .getLog(DbDiscussionService.class);
054:
055: /** The name of the db table holding discussion channels. */
056: protected String m_cTableName = "DISCUSSION_CHANNEL";
057:
058: /** The name of the db table holding discussion messages. */
059: protected String m_rTableName = "DISCUSSION_MESSAGE";
060:
061: /** If true, we do our locks in the remote database, otherwise we do them here. */
062: protected boolean m_locksInDb = true;
063:
064: protected static final String[] FIELDS = { "MESSAGE_DATE", "OWNER",
065: "DRAFT", "PUBVIEW", "CATEGORY", "REPLY" };
066:
067: /**********************************************************************************************************************************************************************************************************************************************************
068: * Constructors, Dependencies and their setter methods
069: *********************************************************************************************************************************************************************************************************************************************************/
070:
071: /** Dependency: SqlService */
072: protected SqlService m_sqlService = null;
073:
074: /**
075: * Dependency: SqlService.
076: *
077: * @param service
078: * The SqlService.
079: */
080: public void setSqlService(SqlService service) {
081: m_sqlService = service;
082: }
083:
084: /**
085: * Configuration: set the table name for the container.
086: *
087: * @param path
088: * The table name for the container.
089: */
090: public void setContainerTableName(String name) {
091: m_cTableName = name;
092: }
093:
094: /**
095: * Configuration: set the table name for the resource.
096: *
097: * @param path
098: * The table name for the resource.
099: */
100: public void setResourceTableName(String name) {
101: m_rTableName = name;
102: }
103:
104: /**
105: * Configuration: set the locks-in-db
106: *
107: * @param path
108: * The storage path.
109: */
110: public void setLocksInDb(String value) {
111: m_locksInDb = new Boolean(value).booleanValue();
112: }
113:
114: /** Set if we are to run the to-draft/owner conversion. */
115: protected boolean m_convertToDraft = false;
116:
117: /**
118: * Configuration: run the to-draft/owner conversion
119: *
120: * @param value
121: * The conversion desired value.
122: */
123: public void setConvertDraft(String value) {
124: m_convertToDraft = new Boolean(value).booleanValue();
125: }
126:
127: /** Configuration: to run the ddl on init or not. */
128: protected boolean m_autoDdl = false;
129:
130: /**
131: * Configuration: to run the ddl on init or not.
132: *
133: * @param value
134: * the auto ddl value.
135: */
136: public void setAutoDdl(String value) {
137: m_autoDdl = new Boolean(value).booleanValue();
138: }
139:
140: /**********************************************************************************************************************************************************************************************************************************************************
141: * Init and Destroy
142: *********************************************************************************************************************************************************************************************************************************************************/
143:
144: /**
145: * Final initialization, once all dependencies are set.
146: */
147: public void init() {
148: try {
149: // if we are auto-creating our schema, check and create
150: if (m_autoDdl) {
151: m_sqlService.ddl(this .getClass().getClassLoader(),
152: "sakai_discussion");
153: }
154:
155: super .init();
156:
157: M_log.info("init(): tables: " + m_cTableName + " "
158: + m_rTableName + " locks-in-db: " + m_locksInDb);
159:
160: // convert?
161: if (m_convertToDraft) {
162: m_convertToDraft = false;
163: convertToDraftPlus();
164: }
165: } catch (Throwable t) {
166: M_log.warn("init(): ", t);
167: }
168: }
169:
170: /**********************************************************************************************************************************************************************************************************************************************************
171: * BaseMessageService extensions
172: *********************************************************************************************************************************************************************************************************************************************************/
173:
174: /**
175: * Construct a Storage object.
176: *
177: * @return The new storage object.
178: */
179: protected Storage newStorage() {
180: return new DbStorage(this );
181:
182: } // newStorage
183:
184: /**********************************************************************************************************************************************************************************************************************************************************
185: * Storage implementation
186: *********************************************************************************************************************************************************************************************************************************************************/
187:
188: protected class DbStorage extends BaseDbDoubleStorage implements
189: Storage {
190: /**
191: * Construct.
192: *
193: * @param user
194: * The StorageUser class to call back for creation of Resource and Edit objects.
195: */
196: public DbStorage(StorageUser user) {
197: super (m_cTableName, "CHANNEL_ID", m_rTableName,
198: "MESSAGE_ID", "CHANNEL_ID", "MESSAGE_DATE",
199: "OWNER", "DRAFT", "PUBVIEW", FIELDS, m_locksInDb,
200: "channel", "message", user, m_sqlService);
201:
202: } // DbStorage
203:
204: /** Channels * */
205:
206: public boolean checkChannel(String ref) {
207: return super .getContainer(ref) != null;
208: }
209:
210: public MessageChannel getChannel(String ref) {
211: return (MessageChannel) super .getContainer(ref);
212: }
213:
214: public List getChannels() {
215: return super .getAllContainers();
216: }
217:
218: public MessageChannelEdit putChannel(String ref) {
219: return (MessageChannelEdit) super .putContainer(ref);
220: }
221:
222: public MessageChannelEdit editChannel(String ref) {
223: return (MessageChannelEdit) super .editContainer(ref);
224: }
225:
226: public void commitChannel(MessageChannelEdit edit) {
227: super .commitContainer(edit);
228: }
229:
230: public void cancelChannel(MessageChannelEdit edit) {
231: super .cancelContainer(edit);
232: }
233:
234: public void removeChannel(MessageChannelEdit edit) {
235: super .removeContainer(edit);
236: }
237:
238: public List getChannelIdsMatching(String root) {
239: return super .getContainerIdsMatching(root);
240: }
241:
242: /** messages * */
243:
244: public boolean checkMessage(MessageChannel channel, String id) {
245: return super .checkResource(channel, id);
246: }
247:
248: public Message getMessage(MessageChannel channel, String id) {
249: return (Message) super .getResource(channel, id);
250: }
251:
252: public List getMessages(MessageChannel channel) {
253: return super .getAllResources(channel);
254: }
255:
256: public MessageEdit putMessage(MessageChannel channel, String id) {
257: return (MessageEdit) super .putResource(channel, id, null);
258: }
259:
260: public MessageEdit editMessage(MessageChannel channel, String id) {
261: return (MessageEdit) super .editResource(channel, id);
262: }
263:
264: public void commitMessage(MessageChannel channel,
265: MessageEdit edit) {
266: super .commitResource(channel, edit);
267: }
268:
269: public void cancelMessage(MessageChannel channel,
270: MessageEdit edit) {
271: super .cancelResource(channel, edit);
272: }
273:
274: public void removeMessage(MessageChannel channel,
275: MessageEdit edit) {
276: super .removeResource(channel, edit);
277: }
278:
279: public List getMessages(MessageChannel channel, Time afterDate,
280: int limitedToLatest, String draftsForId,
281: boolean pubViewOnly) {
282: return super .getResources(channel, afterDate,
283: limitedToLatest, draftsForId, pubViewOnly);
284: }
285:
286: } // DbStorage
287:
288: /**
289: * fill in the draft and owner db fields, and also catagory and reply to
290: */
291: protected void convertToDraftPlus() {
292: M_log.info("convertToDraft");
293:
294: try {
295: // get a connection
296: final Connection connection = m_sqlService
297: .borrowConnection();
298: boolean wasCommit = connection.getAutoCommit();
299: connection.setAutoCommit(false);
300:
301: // read all message records that need conversion
302: String sql = "select CHANNEL_ID, MESSAGE_ID, XML from "
303: + m_rTableName /* + " where OWNER is null" */;
304: m_sqlService.dbRead(connection, sql, null, new SqlReader() {
305: private int count = 0;
306:
307: public Object readSqlResultRecord(ResultSet result) {
308: try {
309: // create the Resource from the db xml
310: String channelId = result.getString(1);
311: String messageId = result.getString(2);
312: String xml = result.getString(3);
313:
314: // read the xml
315: Document doc = Xml.readDocumentFromString(xml);
316:
317: // verify the root element
318: Element root = doc.getDocumentElement();
319: if (!root.getTagName().equals("message")) {
320: M_log
321: .warn("convertToDraft(): XML root element not message: "
322: + root.getTagName());
323: return null;
324: }
325: DiscussionMessage m = new BaseDiscussionMessageEdit(
326: null, root);
327:
328: // pick up the fields
329: String owner = m.getHeader().getFrom().getId();
330: boolean draft = m.getHeader().getDraft();
331: String category = m.getDiscussionHeader()
332: .getCategory();
333: String replyTo = m.getDiscussionHeader()
334: .getReplyTo();
335:
336: // update
337: String update = "update "
338: + m_rTableName
339: + " set OWNER = ?, DRAFT = ?, CATEGORY = ?, REPLY = ? where CHANNEL_ID = ? and MESSAGE_ID = ?";
340: Object fields[] = new Object[6];
341: fields[0] = owner;
342: fields[1] = (draft ? "1" : "0");
343: fields[2] = category;
344: fields[3] = replyTo;
345: fields[4] = channelId;
346: fields[5] = messageId;
347: boolean ok = m_sqlService.dbWrite(connection,
348: update, fields);
349:
350: if (!ok)
351: M_log.info("convertToDraftPlus: channel: "
352: + channelId + " message: "
353: + messageId + " owner: " + owner
354: + " draft: " + draft
355: + " category: " + category
356: + " replyTo: " + replyTo + " ok: "
357: + ok);
358:
359: count++;
360: if (count % 100 == 0) {
361: M_log.info("convertToDraftPlus: " + count);
362: }
363: return null;
364: } catch (Throwable ignore) {
365: return null;
366: }
367: }
368: });
369:
370: connection.commit();
371: connection.setAutoCommit(wasCommit);
372: m_sqlService.returnConnection(connection);
373: } catch (Throwable t) {
374: M_log.warn("convertToDraft: failed: " + t);
375: }
376:
377: M_log.info("convertToDraft: done");
378: }
379:
380: } // DbCachedDiscussionService
|