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