001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/chat/tags/sakai_2-4-1/chat-migration/migration/src/java/org/sakaiproject/chat2/migration/ChatDataMigration.java $
003: * $Id: ChatDataMigration.java 28761 2007-04-12 02:20:02Z ajpoland@iupui.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2007 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: **********************************************************************************/
021:
022: /**
023: *
024: */package org.sakaiproject.chat2.migration;
025:
026: import java.io.BufferedWriter;
027: import java.io.File;
028: import java.io.FileFilter;
029: import java.io.FileInputStream;
030: import java.io.FileWriter;
031: import java.io.PrintWriter;
032: import java.lang.reflect.Method;
033: import java.net.URL;
034: import java.net.URLClassLoader;
035: import java.sql.Connection;
036: import java.sql.ResultSet;
037: import java.sql.Statement;
038: import java.text.MessageFormat;
039: import java.util.ArrayList;
040: import java.util.Arrays;
041: import java.util.Date;
042: import java.util.List;
043: import java.util.PropertyResourceBundle;
044:
045: import org.apache.commons.logging.Log;
046: import org.apache.commons.logging.LogFactory;
047: import org.sakaiproject.db.api.SqlService;
048: import org.sakaiproject.id.cover.IdManager;
049: import org.sakaiproject.util.ResourceLoader;
050: import org.sakaiproject.util.Xml;
051: import org.w3c.dom.Document;
052: import org.w3c.dom.Element;
053:
054: /**
055: * @author chrismaurer
056: *
057: */
058: public class ChatDataMigration {
059:
060: private static boolean debug = false;
061: private static String outputFile = "./migration/chat.sql";
062:
063: private static Log logger = LogFactory
064: .getLog(ChatDataMigration.class);
065:
066: protected static Object compMgr;
067:
068: private static SqlService sqlService = null;
069:
070: private static Statement stmt;
071:
072: private static ResourceLoader toolBundle;
073:
074: public static void main(String[] args) {
075: System.out.println("*******starting.");
076: printDebug("*******MAIN");
077: //TestFactoryUtil test = new TestFactoryUtil("test");
078: try {
079: debug = Boolean.parseBoolean(args[0]);
080: outputFile = args[1];
081:
082: printDebug("*******debug:" + debug);
083: printDebug("*******outputFile:" + outputFile);
084:
085: oneTimeSetup();
086: testDataMigration();
087: oneTimeTearDown();
088: } catch (Exception ex) {
089: System.out.println("ex=" + ex);
090: }
091: System.out.println("done.");
092: }
093:
094: protected static void setUp() throws Exception {
095: printDebug("*******SETUP");
096:
097: // Get the services we need for the tests
098: sqlService = (SqlService) getService(SqlService.class.getName());
099: printDebug("*******GOT SQL SERVICE");
100: }
101:
102: protected static void tearDown() throws Exception {
103: printDebug("*******TEARDOWN");
104: sqlService = null;
105: }
106:
107: public static void testDataMigration() throws Exception {
108: printDebug("*******BEGIN");
109: setUp();
110: load();
111: tearDown();
112: printDebug("*******DONE");
113: }
114:
115: public static void load() throws Exception {
116: printDebug("*******outputDir: " + outputFile);
117:
118: Connection connection = null;
119:
120: PrintWriter sqlFile = new PrintWriter(new BufferedWriter(
121: new FileWriter(outputFile, false)), true);
122:
123: try {
124:
125: sqlFile.println(getDbPrefix());
126:
127: //Add a new columns for us to keep track
128: sqlFile.println(getMessageFromBundle("alter.channel"));
129:
130: sqlFile.println(getMessageFromBundle("alter.message"));
131:
132: sqlFile.println();
133:
134: connection = sqlService.borrowConnection();
135: printDebug("*******BORROWED A CONNECTION");
136: runChannelMigration(connection, sqlFile);
137:
138: } catch (Exception e) {
139: printDebug(e.toString());
140: logger.error(e.getMessage());
141: throw new Exception(e);
142: } finally {
143: if (connection != null) {
144: try {
145: sqlService.returnConnection(connection);
146: } catch (Exception e) {
147: // can't do anything with this.
148: }
149: }
150: }
151: }
152:
153: protected static void runChannelMigration(Connection con,
154: PrintWriter output) {
155: logger.info("runChannelMigration()");
156: printDebug("*******GETTING CHANNELS");
157:
158: String sql = getMessageFromBundle("select.oldchannels");
159:
160: try {
161: stmt = con.createStatement();
162: ResultSet rs = stmt.executeQuery(sql);
163:
164: try {
165: while (rs.next()) {
166: /*
167: * CHANNEL_ID
168: * NEXT_ID
169: * XML
170: */
171: String oldId = rs.getString("CHANNEL_ID");
172: Object xml = rs.getObject("XML");
173:
174: printDebug("*******FOUND CHANNEL: " + oldId);
175: printDebug("*******FOUND CHANNEL: " + xml);
176:
177: Document doc = Xml
178: .readDocumentFromString((String) xml);
179:
180: // verify the root element
181: Element root = doc.getDocumentElement();
182: String context = root.getAttribute("context");
183: String title = root.getAttribute("id");
184: String newChannelId = IdManager.createUuid();
185:
186: //TODO Chat lookup the config params?
187: String outputSql = getMessageFromBundle(
188: "insert.channel", new Object[] {
189: newChannelId, context, null, title,
190: "", "SelectMessagesByTime", 3, 0,
191: oldId });
192: /*
193: * CHANNEL_ID,
194: * CONTEXT,
195: * CREATION_DATE,
196: * title,
197: * description,
198: * filterType,
199: * filterParam,
200: * contextDefaultChannel,
201: * migratedChannelId
202: */
203:
204: output.println(outputSql);
205:
206: //Get the messages for each channel
207: runMessageMmigration(con, output, oldId,
208: newChannelId);
209:
210: }
211: } finally {
212: rs.close();
213: }
214: } catch (Exception e) {
215: logger.error("error selecting data with this sql: " + sql);
216: logger.error("", e);
217: } finally {
218: try {
219: stmt.close();
220: } catch (Exception e) {
221: }
222: }
223: logger.info("Migration task fininshed: runChannelMigration()");
224: }
225:
226: protected static void runMessageMmigration(Connection con,
227: PrintWriter output, String oldChannelId, String newChannelId) {
228: logger.info("runMessageMigration()");
229: printDebug("*******GETTING MESSAGES");
230:
231: String sql = getMessageFromBundle("select.oldmessages",
232: new Object[] { oldChannelId });
233: //String sql = "select c.channel_id, c.xml from chat_channel c";
234:
235: try {
236: stmt = con.createStatement();
237: ResultSet rs = stmt.executeQuery(sql);
238:
239: try {
240: while (rs.next()) {
241: /*
242: * CHANNEL_ID
243: * MESSAGE_ID
244: * DRAFT
245: * PUBVIEW
246: * OWNER
247: * MESSAGE_DATE
248: * XML
249: *
250: */
251: //String oldChannelId = rs.getString("CHANNEL_ID");
252: String oldMessageId = rs.getString("MESSAGE_ID");
253: String owner = rs.getString("OWNER");
254: Date messageDate = rs.getTimestamp("MESSAGE_DATE");
255: Object xml = rs.getObject("XML");
256:
257: printDebug("*******FOUND MESSAGE: " + oldMessageId);
258: printDebug("*******FOUND MESSAGE: " + xml);
259:
260: Document doc = Xml
261: .readDocumentFromString((String) xml);
262:
263: // verify the root element
264: Element root = doc.getDocumentElement();
265: String body = Xml.decodeAttribute(root, "body");
266: //String body = root.getAttribute("body");
267: //String body = "test";
268:
269: String newMessageId = IdManager.createUuid();
270:
271: String outputSql = getMessageFromBundle(
272: "insert.message", new Object[] {
273: newMessageId, newChannelId, owner,
274: messageDate, body, oldMessageId });
275: /*
276: * insert into CHAT2_MESSAGE (MESSAGE_ID, CHANNEL_ID, OWNER, MESSAGE_DATE, BODY) \
277: values ('{0}', '{1}', '{2}', '{3}', '{4}');
278:
279: */
280: output.println(outputSql);
281: }
282: } finally {
283: rs.close();
284: }
285: } catch (Exception e) {
286: logger.error("error selecting data with this sql: " + sql);
287: logger.error("", e);
288: } finally {
289: try {
290: stmt.close();
291: } catch (Exception e) {
292: }
293: }
294: logger.info("Migration task fininshed: runChannelMigration()");
295:
296: }
297:
298: protected static void printDebug(String message) {
299: if (debug) {
300: System.out.println(message);
301: }
302: }
303:
304: /**
305: * Initialize the component manager once for all tests, and log in as admin.
306: */
307: protected static void oneTimeSetup() throws Exception {
308: if (compMgr == null) {
309: // Find the sakai home dir
310: String tomcatHome = getTomcatHome();
311: String sakaiHome = tomcatHome + File.separatorChar
312: + "sakai" + File.separatorChar;
313: String componentsDir = tomcatHome + "components/";
314:
315: // Set the system properties needed by the sakai component manager
316: System.setProperty("sakai.home", sakaiHome);
317: System.setProperty("sakai.components.root", componentsDir);
318:
319: logger.debug("Starting the component manager");
320:
321: // Add the sakai jars to the current classpath. Note: We are limited to using the sun jvm now
322: URL[] sakaiUrls = getJarUrls(new String[] {
323: tomcatHome + "common/endorsed/",
324: tomcatHome + "common/lib/",
325: tomcatHome + "shared/lib/" });
326: URLClassLoader appClassLoader = (URLClassLoader) Thread
327: .currentThread().getContextClassLoader();
328: printDebug("*******THREAD CLASSLOADER: "
329: + Thread.currentThread().getContextClassLoader());
330:
331: Method addMethod = URLClassLoader.class.getDeclaredMethod(
332: "addURL", new Class[] { URL.class });
333: addMethod.setAccessible(true);
334: for (int i = 0; i < sakaiUrls.length; i++) {
335: //printDebug("*******CLASSLOADING - " + sakaiUrls[i]);
336: addMethod.invoke(appClassLoader,
337: new Object[] { sakaiUrls[i] });
338: }
339:
340: Class clazz = Class
341: .forName("org.sakaiproject.component.cover.ComponentManager");
342: compMgr = clazz.getDeclaredMethod("getInstance",
343: (Class[]) null).invoke((Object[]) null,
344: (Object[]) null);
345:
346: logger.debug("Finished starting the component manager");
347: printDebug("*******Finished starting the component manager");
348:
349: }
350: }
351:
352: /**
353: * Close the component manager when the tests finish.
354: */
355: public static void oneTimeTearDown() {
356: try {
357: if (compMgr != null) {
358: Method closeMethod = compMgr.getClass().getMethod(
359: "close", new Class[0]);
360: closeMethod.invoke(compMgr, new Object[0]);
361: }
362: } catch (Exception e) {
363: logger.error(e);
364: }
365: }
366:
367: /**
368: * Fetches the "maven.tomcat.home" property from the maven build.properties
369: * file located in the user's $HOME directory.
370: *
371: * @return
372: * @throws Exception
373: */
374: private static String getTomcatHome() throws Exception {
375: printDebug("*******GET_TOMCAT_HOME");
376: String testTomcatHome = System.getProperty("test.tomcat.home");
377: if (testTomcatHome != null && testTomcatHome.length() > 0) {
378: logger.debug("Using tomcat home: " + testTomcatHome);
379: return testTomcatHome;
380: } else {
381: String homeDir = System.getProperty("user.home");
382: File file = new File(homeDir + File.separatorChar
383: + "build.properties");
384: FileInputStream fis = new FileInputStream(file);
385: PropertyResourceBundle rb = new PropertyResourceBundle(fis);
386: String tomcatHome = rb.getString("maven.tomcat.home");
387: logger.debug("Tomcat home = " + tomcatHome);
388: return tomcatHome;
389: }
390: }
391:
392: /**
393: * Builds an array of file URLs from a directory path.
394: *
395: * @param dirPath
396: * @return
397: * @throws Exception
398: */
399: private static URL[] getJarUrls(String dirPath) throws Exception {
400: File dir = new File(dirPath);
401: File[] jars = dir.listFiles(new FileFilter() {
402: public boolean accept(File pathname) {
403: if (pathname.getName().startsWith("xml-apis")) {
404: return false;
405: } else if (pathname.getName().startsWith(
406: "osp-warehouse")) {
407: return false;
408: }
409: return true;
410: }
411: });
412: URL[] urls = new URL[jars.length];
413: for (int i = 0; i < jars.length; i++) {
414: urls[i] = jars[i].toURL();
415: //printDebug("*******JARS: " + urls[i]);
416: }
417: return urls;
418: }
419:
420: private static URL[] getJarUrls(String[] dirPaths) throws Exception {
421: List<URL> jarList = new ArrayList<URL>();
422:
423: // Add all of the tomcat jars
424: for (int i = 0; i < dirPaths.length; i++) {
425: jarList.addAll(Arrays.asList(getJarUrls(dirPaths[i])));
426: }
427:
428: URL[] urlArray = new URL[jarList.size()];
429: jarList.toArray(urlArray);
430: return urlArray;
431: }
432:
433: /**
434: * Convenience method to get a service bean from the Sakai component manager.
435: *
436: * @param beanId The id of the service
437: *
438: * @return The service, or null if the ID is not registered
439: */
440: protected static final Object getService(String beanId) {
441: try {
442: Method getMethod = compMgr.getClass().getMethod("get",
443: new Class[] { String.class });
444: return getMethod.invoke(compMgr, new Object[] { beanId });
445: } catch (Exception e) {
446: logger.error(e);
447: return null;
448: }
449: }
450:
451: /**
452: * Looks up the db vendor from the SqlService
453: * @return The string for the db vendor (mysql, oracle, hsqldb, etc)
454: */
455: private static String getDbPrefix() {
456: return sqlService.getVendor();
457: }
458:
459: /**
460: * Looks up the sql statements defined in chat-sql.properties. Appends the db
461: * vendor key to the beginning of the message (oracle.select.channel, mysql.select.channel, etc)
462: * @param key
463: * @return
464: */
465: private static String getMessageFromBundle(String key) {
466: if (toolBundle == null)
467: toolBundle = new ResourceLoader("chat-sql");
468:
469: return toolBundle.getString(getDbPrefix().concat("." + key));
470: }
471:
472: private static String getMessageFromBundle(String key, Object[] args) {
473: return MessageFormat.format(getMessageFromBundle(key), args);
474: }
475:
476: }
|