001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. The ASF licenses this file to You
004: * under the Apache License, Version 2.0 (the "License"); you may not
005: * 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. For additional information regarding
015: * copyright in this work, please see the NOTICE file in the top level
016: * directory of this distribution.
017: */
018:
019: package org.apache.roller.business.utils;
020:
021: import java.sql.Connection;
022: import java.sql.PreparedStatement;
023: import java.sql.ResultSet;
024: import java.sql.SQLException;
025: import java.sql.Statement;
026: import java.util.Date;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029: import org.apache.roller.RollerException;
030: import org.apache.roller.pojos.PermissionsData;
031:
032: /**
033: * Upgrade Roller Database.
034: */
035: public class UpgradeDatabase {
036:
037: private static Log mLogger = LogFactory
038: .getLog(UpgradeDatabase.class);
039:
040: // the name of the property which holds the dbversion value
041: private static final String DBVERSION_PROP = "roller.database.version";
042:
043: /**
044: * Upgrade database if dbVersion is older than desiredVersion.
045: */
046: public static void upgradeDatabase(Connection con,
047: String desiredVersion) throws RollerException {
048:
049: int myVersion = 0;
050: int dbversion = -1;
051:
052: // NOTE: this assumes a maximum of 3 digits for the version number
053: // so if we get to 10.0 then we'll need to upgrade this
054:
055: // strip out non-digits
056: desiredVersion = desiredVersion.replaceAll("\\Q.\\E", "");
057: desiredVersion = desiredVersion.replaceAll("\\D", "");
058: if (desiredVersion.length() > 3)
059: desiredVersion = desiredVersion.substring(0, 3);
060:
061: // parse to an int
062: try {
063: int parsed = Integer.parseInt(desiredVersion);
064:
065: if (parsed < 100)
066: myVersion = parsed * 10;
067: else
068: myVersion = parsed;
069: } catch (Exception e) {
070: }
071:
072: // get the current db version
073: try {
074: Statement stmt = con.createStatement();
075:
076: // just check in the roller_properties table
077: ResultSet rs = stmt
078: .executeQuery("select value from roller_properties where name = '"
079: + DBVERSION_PROP + "'");
080:
081: if (rs.next()) {
082: dbversion = Integer.parseInt(rs.getString(1));
083:
084: } else {
085: // tough to know if this is an upgrade with no db version :/
086: // however, if roller_properties is not empty then we at least
087: // we have someone upgrading from 1.2.x
088: rs = stmt
089: .executeQuery("select count(*) from roller_properties");
090: if (rs.next()) {
091: if (rs.getInt(1) > 0)
092: dbversion = 120;
093: }
094: }
095:
096: } catch (Exception e) {
097: // that's strange ... hopefully we didn't need to upgrade
098: mLogger
099: .error("Couldn't lookup current database version",
100: e);
101: return;
102: }
103:
104: mLogger.debug("Database version = " + dbversion);
105: mLogger.debug("Desired version = " + myVersion);
106:
107: if (dbversion < 0) {
108: mLogger
109: .info("New installation found, setting db version to "
110: + myVersion);
111: UpgradeDatabase.setDatabaseVersion(con, myVersion);
112: return;
113: } else if (dbversion >= myVersion) {
114: mLogger.info("Database is current, no upgrade needed");
115: return;
116: }
117:
118: mLogger.info("Database is old, beginning upgrade to version "
119: + myVersion);
120:
121: // iterate through each upgrade as needed
122: // to add to the upgrade sequence simply add a new "if" statement
123: // for whatever version needed and then define a new method upgradeXXX()
124: if (dbversion < 130) {
125: UpgradeDatabase.upgradeTo130(con);
126: dbversion = 130;
127: }
128: if (dbversion < 200) {
129: UpgradeDatabase.upgradeTo200(con);
130: dbversion = 200;
131: }
132: if (dbversion < 210) {
133: UpgradeDatabase.upgradeTo210(con);
134: dbversion = 210;
135: }
136: if (dbversion < 300) {
137: UpgradeDatabase.upgradeTo300(con);
138: dbversion = 300;
139: }
140:
141: // make sure the database version is the exact version
142: // we are upgrading too.
143: UpgradeDatabase.updateDatabaseVersion(con, myVersion);
144: }
145:
146: /**
147: * Upgrade database for Roller 1.3.0
148: */
149: private static void upgradeTo130(Connection con)
150: throws RollerException {
151: try {
152: /*
153: * The new theme management code is going into place and it uses
154: * the old website.themeEditor attribute to store a users theme.
155: *
156: * In pre-1.3 Roller *all* websites are considered to be using a
157: * custom theme, so we need to make sure this is properly defined
158: * by setting the theme on all websites to custom.
159: *
160: * NOTE: If we don't do this then nothing would break, but some users
161: * would be suprised that their template customizations are no longer
162: * in effect because they are using a shared theme instead.
163: */
164:
165: mLogger.info("Doing upgrade to 130 ...");
166: mLogger
167: .info("Ensuring that all website themes are set to custom");
168:
169: PreparedStatement setCustomThemeStmt = con
170: .prepareStatement("update website set editortheme = ?");
171:
172: setCustomThemeStmt.setString(1,
173: org.apache.roller.pojos.Theme.CUSTOM);
174: setCustomThemeStmt.executeUpdate();
175:
176: if (!con.getAutoCommit())
177: con.commit();
178:
179: mLogger.info("Upgrade to 130 complete.");
180:
181: } catch (SQLException e) {
182: mLogger.error("Problem upgrading database to version 130",
183: e);
184: throw new RollerException(
185: "Problem upgrading database to version 130", e);
186: }
187:
188: // If someone is upgrading to 1.3.x then we are setting the db version
189: // for the first time. Normally we would just updateDatabaseVersion()
190: UpgradeDatabase.setDatabaseVersion(con, 130);
191: }
192:
193: /**
194: * Upgrade database for Roller 2.0.0
195: */
196: private static void upgradeTo200(Connection con)
197: throws RollerException {
198: try {
199: mLogger.info("Doing upgrade to 200 ...");
200: mLogger.info("Populating roller_user_permissions table");
201:
202: PreparedStatement websitesQuery = con
203: .prepareStatement("select w.id as wid, u.id as uid, u.username as uname from "
204: + "website as w, rolleruser as u where u.id=w.userid");
205: PreparedStatement websiteUpdate = con
206: .prepareStatement("update website set handle=? where id=?");
207: PreparedStatement entryUpdate = con
208: .prepareStatement("update weblogentry set userid=?, status=?, "
209: + "pubtime=pubtime, updatetime=updatetime "
210: + "where publishentry=? and websiteid=?");
211: PreparedStatement permsInsert = con
212: .prepareStatement("insert into roller_user_permissions "
213: + "(id, website_id, user_id, permission_mask, pending) "
214: + "values (?,?,?,?,?)");
215:
216: // loop through websites, each has a user
217: ResultSet websiteSet = websitesQuery.executeQuery();
218: while (websiteSet.next()) {
219: String websiteid = websiteSet.getString("wid");
220: String userid = websiteSet.getString("uid");
221: String handle = websiteSet.getString("uname");
222: mLogger.info("Processing website: " + handle);
223:
224: // use website user's username as website handle
225: websiteUpdate.clearParameters();
226: websiteUpdate.setString(1, handle);
227: websiteUpdate.setString(2, websiteid);
228: websiteUpdate.executeUpdate();
229:
230: // update all of pubished entries to include userid and status
231: entryUpdate.clearParameters();
232: entryUpdate.setString(1, userid);
233: entryUpdate.setString(2, "PUBLISHED");
234: entryUpdate.setBoolean(3, true);
235: entryUpdate.setString(4, websiteid);
236: entryUpdate.executeUpdate();
237:
238: // update all of draft entries to include userid and status
239: entryUpdate.clearParameters();
240: entryUpdate.setString(1, userid);
241: entryUpdate.setString(2, "DRAFT");
242: entryUpdate.setBoolean(3, false);
243: entryUpdate.setString(4, websiteid);
244: entryUpdate.executeUpdate();
245:
246: // add permission for user in website
247: permsInsert.clearParameters();
248: permsInsert.setString(1, websiteid + "p");
249: permsInsert.setString(2, websiteid);
250: permsInsert.setString(3, userid);
251: permsInsert.setShort(4, PermissionsData.ADMIN);
252: permsInsert.setBoolean(5, false);
253: permsInsert.executeUpdate();
254: }
255:
256: if (!con.getAutoCommit())
257: con.commit();
258:
259: mLogger.info("Upgrade to 200 complete.");
260:
261: } catch (SQLException e) {
262: mLogger.error("Problem upgrading database to version 200",
263: e);
264: throw new RollerException(
265: "Problem upgrading database to version 200", e);
266: }
267:
268: UpgradeDatabase.updateDatabaseVersion(con, 200);
269: }
270:
271: /**
272: * Upgrade database for Roller 2.1.0
273: */
274: private static void upgradeTo210(Connection con)
275: throws RollerException {
276: try {
277: /*
278: * For Roller 2.1.0 we are going to standardize some of the
279: * weblog templates and make them less editable. To do this
280: * we need to do a little surgery.
281: *
282: * The goal for this upgrade is to ensure that ALL weblogs now have
283: * the required "Weblog" template as their default template.
284: */
285:
286: mLogger.info("Doing upgrade to 210 ...");
287: mLogger
288: .info("Ensuring that all weblogs use the 'Weblog' template as their default page");
289:
290: // this query will give us all websites that have modified their
291: // default page to link to something other than "Weblog"
292: PreparedStatement selectUpdateWeblogs = con
293: .prepareStatement("select website.id,template,website.handle from website,webpage "
294: + "where webpage.id = website.defaultpageid "
295: + "and webpage.link != 'Weblog'");
296:
297: PreparedStatement selectWeblogTemplate = con
298: .prepareStatement("select id from webpage where websiteid = ? and link = 'Weblog'");
299:
300: PreparedStatement updateWeblogTemplate = con
301: .prepareStatement("update webpage set template = ? where id = ?");
302:
303: // insert a new template for a website
304: PreparedStatement insertWeblogTemplate = con
305: .prepareStatement("insert into webpage"
306: + "(id, name, description, link, websiteid, template, updatetime) "
307: + "values(?,?,?,?,?,?,?)");
308:
309: // update the default page for a website
310: PreparedStatement updateDefaultPage = con
311: .prepareStatement("update website set defaultpageid = ? "
312: + "where id = ?");
313:
314: String description = "This template is used to render the main "
315: + "page of your weblog.";
316: ResultSet websiteSet = selectUpdateWeblogs.executeQuery();
317: Date now = new Date();
318: while (websiteSet.next()) {
319: String websiteid = websiteSet.getString(1);
320: String template = websiteSet.getString(2);
321: String handle = websiteSet.getString(3);
322: mLogger.info("Processing website: " + handle);
323:
324: String defaultpageid = null;
325:
326: // it's possible that this weblog has a "Weblog" template, but just
327: // isn't using it as their default. if so we need to fix that.
328: selectWeblogTemplate.clearParameters();
329: selectWeblogTemplate.setString(1, websiteid);
330: ResultSet weblogPageSet = selectWeblogTemplate
331: .executeQuery();
332: if (weblogPageSet.next()) {
333: // this person already has a "Weblog" template, so update it
334: String id = weblogPageSet.getString(1);
335:
336: updateWeblogTemplate.clearParameters();
337: updateWeblogTemplate.setString(1, template);
338: updateWeblogTemplate.setString(2, id);
339: updateWeblogTemplate.executeUpdate();
340:
341: // make sure and adjust what default page id we want to use
342: defaultpageid = id;
343: } else {
344: // no "Weblog" template, so insert a new one
345: insertWeblogTemplate.clearParameters();
346: insertWeblogTemplate.setString(1, websiteid + "q");
347: insertWeblogTemplate.setString(2, "Weblog");
348: insertWeblogTemplate.setString(3, description);
349: insertWeblogTemplate.setString(4, "Weblog");
350: insertWeblogTemplate.setString(5, websiteid);
351: insertWeblogTemplate.setString(6, template);
352: insertWeblogTemplate.setDate(7, new java.sql.Date(
353: now.getTime()));
354: insertWeblogTemplate.executeUpdate();
355:
356: // set the new default page id
357: defaultpageid = websiteid + "q";
358: }
359:
360: // update defaultpageid value
361: updateDefaultPage.clearParameters();
362: updateDefaultPage.setString(1, defaultpageid);
363: updateDefaultPage.setString(2, websiteid);
364: updateDefaultPage.executeUpdate();
365: }
366:
367: if (!con.getAutoCommit())
368: con.commit();
369:
370: mLogger.info("Upgrade to 210 complete.");
371:
372: } catch (SQLException e) {
373: mLogger.error("Problem upgrading database to version 210",
374: e);
375: throw new RollerException(
376: "Problem upgrading database to version 210", e);
377: }
378:
379: UpgradeDatabase.updateDatabaseVersion(con, 210);
380: }
381:
382: /**
383: * Upgrade database for Roller 3.0.0
384: */
385: private static void upgradeTo300(Connection con)
386: throws RollerException {
387: try {
388: /*
389: * For Roller 3.0.0 we are allowing each weblogentry to track a
390: * locale now so that we can support multi-lingual blogs. As part
391: * of the upgrade process we want to do 2 things ..
392: *
393: * 1. make sure all weblogs have a locale
394: * 2. set the locale on all entries to the locale for the weblog
395: */
396:
397: mLogger.info("Doing upgrade to 300 ...");
398:
399: // get system default language
400: String locale = java.util.Locale.getDefault().getLanguage();
401:
402: mLogger.info("Setting website locale to " + locale
403: + " for websites with no locale");
404:
405: // update all weblogs where locale is "null"
406: PreparedStatement updateNullWeblogLocale = con
407: .prepareStatement("update website set locale = ? where locale is NULL");
408: // update all weblogs where locale is empty string ""
409: PreparedStatement updateEmptyWeblogLocale = con
410: .prepareStatement("update website set locale = ? where locale = ''");
411: updateNullWeblogLocale.setString(1, locale);
412: updateEmptyWeblogLocale.setString(1, locale);
413: updateNullWeblogLocale.executeUpdate();
414: updateEmptyWeblogLocale.executeUpdate();
415:
416: mLogger
417: .info("Setting weblogentry locales to website locale");
418:
419: // get all entries and the locale of its website
420: PreparedStatement selectWeblogsLocale = con
421: .prepareStatement("select weblogentry.id,website.locale "
422: + "from weblogentry,website "
423: + "where weblogentry.websiteid = website.id");
424:
425: // set the locale for an entry
426: PreparedStatement updateWeblogLocale = con
427: .prepareStatement("update weblogentry set locale = ? where id = ?");
428:
429: ResultSet websiteSet = selectWeblogsLocale.executeQuery();
430: while (websiteSet.next()) {
431: String entryid = websiteSet.getString(1);
432: String entrylocale = websiteSet.getString(2);
433:
434: // update entry locale
435: updateWeblogLocale.clearParameters();
436: updateWeblogLocale.setString(1, entrylocale);
437: updateWeblogLocale.setString(2, entryid);
438: updateWeblogLocale.executeUpdate();
439: }
440:
441: if (!con.getAutoCommit())
442: con.commit();
443:
444: mLogger.info("Upgrade to 300 complete.");
445:
446: } catch (SQLException e) {
447: mLogger.error("Problem upgrading database to version 300",
448: e);
449: throw new RollerException(
450: "Problem upgrading database to version 300", e);
451: }
452:
453: UpgradeDatabase.updateDatabaseVersion(con, 300);
454: }
455:
456: /**
457: * Insert a new database.version property.
458: *
459: * This should only be called once for new installations
460: */
461: private static void setDatabaseVersion(Connection con, int version)
462: throws RollerException {
463:
464: try {
465: Statement stmt = con.createStatement();
466: stmt.executeUpdate("insert into roller_properties "
467: + "values('" + DBVERSION_PROP + "', '" + version
468: + "')");
469:
470: mLogger.debug("Set database verstion to " + version);
471: } catch (SQLException se) {
472: throw new RollerException(
473: "Error setting database version.", se);
474: }
475: }
476:
477: /**
478: * Update the existing database.version property
479: */
480: private static void updateDatabaseVersion(Connection con,
481: int version) throws RollerException {
482:
483: try {
484: Statement stmt = con.createStatement();
485: stmt.executeUpdate("update roller_properties "
486: + "set value = '" + version + "'"
487: + "where name = '" + DBVERSION_PROP + "'");
488:
489: mLogger.debug("Updated database verstion to " + version);
490: } catch (SQLException se) {
491: throw new RollerException(
492: "Error setting database version.", se);
493: }
494: }
495: }
|