001: /**
002: * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE, version 2.1, dated February 1999.
003: *
004: * This program is free software; you can redistribute it and/or modify
005: * it under the terms of the latest version of the GNU Lesser General
006: * Public License as published by the Free Software Foundation;
007: *
008: * This program is distributed in the hope that it will be useful,
009: * but WITHOUT ANY WARRANTY; without even the implied warranty of
010: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
011: * GNU Lesser General Public License for more details.
012: *
013: * You should have received a copy of the GNU Lesser General Public License
014: * along with this program (LICENSE.txt); if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
016: */package org.jamwiki.db;
017:
018: import java.io.File;
019: import java.sql.Connection;
020: import java.util.Iterator;
021: import java.util.List;
022: import java.util.Locale;
023: import java.util.Properties;
024: import java.util.Vector;
025: import org.apache.commons.lang.StringUtils;
026: import org.jamwiki.Environment;
027: import org.jamwiki.WikiBase;
028: import org.jamwiki.model.Role;
029: import org.jamwiki.model.Topic;
030: import org.jamwiki.model.TopicVersion;
031: import org.jamwiki.model.VirtualWiki;
032: import org.jamwiki.model.WikiGroup;
033: import org.jamwiki.model.WikiUser;
034: import org.jamwiki.model.WikiUserInfo;
035: import org.jamwiki.parser.ParserUtil;
036: import org.jamwiki.parser.ParserOutput;
037: import org.jamwiki.utils.WikiLogger;
038: import org.jamwiki.utils.WikiUtil;
039:
040: /**
041: * This class contains general database utility methods that are useful for a
042: * variety of JAMWiki database functions, including setup and upgrades.
043: */
044: public class WikiDatabase {
045:
046: private static String CONNECTION_VALIDATION_QUERY = null;
047: private static String EXISTENCE_VALIDATION_QUERY = null;
048: private static final WikiLogger logger = WikiLogger
049: .getLogger(WikiDatabase.class.getName());
050:
051: /**
052: *
053: */
054: private WikiDatabase() {
055: }
056:
057: /**
058: *
059: */
060: private static Connection getConnection() throws Exception {
061: // add a connection to the conn array. BE SURE TO RELEASE IT!
062: Connection conn = DatabaseConnection.getConnection();
063: conn.setAutoCommit(false);
064: return conn;
065: }
066:
067: /**
068: *
069: */
070: protected static Connection getConnection(Object transactionObject)
071: throws Exception {
072: if (transactionObject instanceof Connection) {
073: return (Connection) transactionObject;
074: }
075: return WikiDatabase.getConnection();
076: }
077:
078: /**
079: *
080: */
081: protected static String getConnectionValidationQuery() {
082: return (!StringUtils.isBlank(CONNECTION_VALIDATION_QUERY)) ? CONNECTION_VALIDATION_QUERY
083: : null;
084: }
085:
086: /**
087: *
088: */
089: protected static String getExistenceValidationQuery() {
090: return (!StringUtils.isBlank(EXISTENCE_VALIDATION_QUERY)) ? EXISTENCE_VALIDATION_QUERY
091: : null;
092: }
093:
094: /**
095: *
096: */
097: public synchronized static void initialize() {
098: try {
099: WikiDatabase.CONNECTION_VALIDATION_QUERY = WikiDatabase
100: .queryHandler().connectionValidationQuery();
101: WikiDatabase.EXISTENCE_VALIDATION_QUERY = WikiDatabase
102: .queryHandler().existenceValidationQuery();
103: // initialize connection pool in its own try-catch to avoid an error
104: // causing property values not to be saved.
105: DatabaseConnection.setPoolInitialized(false);
106: } catch (Exception e) {
107: logger.severe("Unable to initialize database", e);
108: }
109: }
110:
111: public synchronized static void shutdown() {
112: try {
113: DatabaseConnection.closeConnectionPool();
114: } catch (Exception e) {
115: logger.severe(
116: "Unable to close the connection pool on shutdown",
117: e);
118: }
119: }
120:
121: /**
122: * This method causes all existing data to be deleted from the Wiki. Use only
123: * when totally re-initializing a system. To reiterate: CALLING THIS METHOD WILL
124: * DELETE ALL WIKI DATA!
125: */
126: protected static void purgeData(Connection conn) throws Exception {
127: // BOOM! Everything gone...
128: WikiDatabase.queryHandler().dropTables(conn);
129: try {
130: // re-create empty tables
131: WikiDatabase.queryHandler().createTables(conn);
132: } catch (Exception e) {
133: // creation failure, don't leave tables half-committed
134: WikiDatabase.queryHandler().dropTables(conn);
135: }
136: }
137:
138: /**
139: *
140: */
141: protected static QueryHandler queryHandler() throws Exception {
142: // FIXME - this is ugly
143: if (WikiBase.getDataHandler() instanceof AnsiDataHandler) {
144: AnsiDataHandler dataHandler = (AnsiDataHandler) WikiBase
145: .getDataHandler();
146: return dataHandler.queryHandler();
147: }
148: throw new Exception("Unable to determine query handler");
149: }
150:
151: /**
152: *
153: */
154: protected static void releaseConnection(Connection conn,
155: Object transactionObject) throws Exception {
156: if (transactionObject instanceof Connection) {
157: // transaction objects will be released elsewhere
158: return;
159: }
160: WikiDatabase.releaseConnection(conn);
161: }
162:
163: /**
164: *
165: */
166: private static void releaseConnection(Connection conn)
167: throws Exception {
168: if (conn == null) {
169: return;
170: }
171: try {
172: conn.commit();
173: } finally {
174: DatabaseConnection.closeConnection(conn);
175: }
176: }
177:
178: /**
179: *
180: */
181: protected static void setup(Locale locale, WikiUser user)
182: throws Exception {
183: Connection conn = null;
184: try {
185: try {
186: conn = WikiDatabase.getConnection();
187: // set up tables
188: WikiDatabase.queryHandler().createTables(conn);
189: } catch (Exception e) {
190: logger.severe("Unable to set up database tables", e);
191: // clean up anything that might have been created
192: WikiDatabase.queryHandler().dropTables(conn);
193: throw e;
194: }
195: try {
196: WikiDatabase.setupDefaultVirtualWiki(conn);
197: WikiDatabase.setupRoles(conn);
198: WikiDatabase.setupGroups(conn);
199: WikiDatabase.setupAdminUser(user, conn);
200: WikiDatabase.setupSpecialPages(locale, user, conn);
201: } catch (Exception e) {
202: DatabaseConnection.handleErrors(conn);
203: throw e;
204: }
205: } finally {
206: WikiDatabase.releaseConnection(conn);
207: }
208: }
209:
210: /**
211: *
212: */
213: private static void setupAdminUser(WikiUser user, Connection conn)
214: throws Exception {
215: if (user == null) {
216: throw new IllegalArgumentException(
217: "Cannot pass null or anonymous WikiUser object to setupAdminUser");
218: }
219: if (WikiBase.getDataHandler().lookupWikiUser(user.getUserId(),
220: conn) != null) {
221: logger.warning("Admin user already exists");
222: }
223: WikiUserInfo userInfo = null;
224: if (WikiBase.getUserHandler().isWriteable()) {
225: userInfo = new WikiUserInfo();
226: userInfo.setEncodedPassword(user.getPassword());
227: userInfo.setUsername(user.getUsername());
228: userInfo.setUserId(user.getUserId());
229: }
230: WikiBase.getDataHandler().writeWikiUser(user, userInfo, conn);
231: Vector roles = new Vector();
232: roles.add(Role.ROLE_ADMIN.getAuthority());
233: roles.add(Role.ROLE_SYSADMIN.getAuthority());
234: roles.add(Role.ROLE_TRANSLATE.getAuthority());
235: WikiBase.getDataHandler().writeRoleMapUser(user.getUserId(),
236: roles, conn);
237: }
238:
239: /**
240: *
241: */
242: public static void setupDefaultDatabase(Properties props) {
243: props.setProperty(Environment.PROP_DB_DRIVER,
244: "org.hsqldb.jdbcDriver");
245: props.setProperty(Environment.PROP_DB_TYPE,
246: WikiBase.DATA_HANDLER_HSQL);
247: props.setProperty(Environment.PROP_DB_USERNAME, "sa");
248: props.setProperty(Environment.PROP_DB_PASSWORD, "");
249: File file = new File(props
250: .getProperty(Environment.PROP_BASE_FILE_DIR),
251: "database");
252: if (!file.exists()) {
253: file.mkdirs();
254: }
255: String url = "jdbc:hsqldb:file:"
256: + new File(file.getPath(), "jamwiki").getPath()
257: + ";shutdown=true";
258: props.setProperty(Environment.PROP_DB_URL, url);
259: }
260:
261: /**
262: *
263: */
264: private static void setupDefaultVirtualWiki(Connection conn)
265: throws Exception {
266: VirtualWiki virtualWiki = new VirtualWiki();
267: virtualWiki.setName(WikiBase.DEFAULT_VWIKI);
268: virtualWiki.setDefaultTopicName(Environment
269: .getValue(Environment.PROP_BASE_DEFAULT_TOPIC));
270: WikiBase.getDataHandler().writeVirtualWiki(virtualWiki, conn);
271: }
272:
273: /**
274: *
275: */
276: protected static void setupGroups(Connection conn) throws Exception {
277: WikiGroup group = new WikiGroup();
278: group.setName(WikiGroup.GROUP_ANONYMOUS);
279: // FIXME - use message key
280: group
281: .setDescription("All non-logged in users are automatically assigned to the anonymous group.");
282: WikiBase.getDataHandler().writeWikiGroup(group, conn);
283: List anonymousRoles = new Vector();
284: anonymousRoles.add(Role.ROLE_EDIT_EXISTING.getAuthority());
285: anonymousRoles.add(Role.ROLE_EDIT_NEW.getAuthority());
286: anonymousRoles.add(Role.ROLE_UPLOAD.getAuthority());
287: anonymousRoles.add(Role.ROLE_VIEW.getAuthority());
288: WikiBase.getDataHandler().writeRoleMapGroup(group.getGroupId(),
289: anonymousRoles, conn);
290: group = new WikiGroup();
291: group.setName(WikiGroup.GROUP_REGISTERED_USER);
292: // FIXME - use message key
293: group
294: .setDescription("All logged in users are automatically assigned to the registered user group.");
295: WikiBase.getDataHandler().writeWikiGroup(group, conn);
296: List userRoles = new Vector();
297: userRoles.add(Role.ROLE_EDIT_EXISTING.getAuthority());
298: userRoles.add(Role.ROLE_EDIT_NEW.getAuthority());
299: userRoles.add(Role.ROLE_MOVE.getAuthority());
300: userRoles.add(Role.ROLE_UPLOAD.getAuthority());
301: userRoles.add(Role.ROLE_VIEW.getAuthority());
302: WikiBase.getDataHandler().writeRoleMapGroup(group.getGroupId(),
303: userRoles, conn);
304: }
305:
306: /**
307: *
308: */
309: protected static void setupRoles(Connection conn) throws Exception {
310: Role role = Role.ROLE_ADMIN;
311: // FIXME - use message key
312: role
313: .setDescription("Provides the ability to perform wiki maintenance tasks not available to normal users.");
314: WikiBase.getDataHandler().writeRole(role, conn, false);
315: role = Role.ROLE_EDIT_EXISTING;
316: // FIXME - use message key
317: role.setDescription("Allows a user to edit an existing topic.");
318: WikiBase.getDataHandler().writeRole(role, conn, false);
319: role = Role.ROLE_EDIT_NEW;
320: // FIXME - use message key
321: role.setDescription("Allows a user to create a new topic.");
322: WikiBase.getDataHandler().writeRole(role, conn, false);
323: role = Role.ROLE_MOVE;
324: // FIXME - use message key
325: role
326: .setDescription("Allows a user to move a topic to a different name.");
327: WikiBase.getDataHandler().writeRole(role, conn, false);
328: role = Role.ROLE_SYSADMIN;
329: // FIXME - use message key
330: role
331: .setDescription("Allows access to set database parameters, modify parser settings, and set other wiki system settings.");
332: WikiBase.getDataHandler().writeRole(role, conn, false);
333: role = Role.ROLE_TRANSLATE;
334: // FIXME - use message key
335: role
336: .setDescription("Allows access to the translation tool used for modifying the values of message keys used to display text on the wiki.");
337: WikiBase.getDataHandler().writeRole(role, conn, false);
338: role = Role.ROLE_UPLOAD;
339: // FIXME - use message key
340: role
341: .setDescription("Allows a user to upload a file to the wiki.");
342: WikiBase.getDataHandler().writeRole(role, conn, false);
343: role = Role.ROLE_VIEW;
344: // FIXME - use message key
345: role
346: .setDescription("Allows a user to view topics on the wiki.");
347: WikiBase.getDataHandler().writeRole(role, conn, false);
348: }
349:
350: /**
351: *
352: */
353: protected static void setupSpecialPage(Locale locale,
354: String virtualWiki, String topicName, WikiUser user,
355: boolean adminOnly, Connection conn) throws Exception {
356: logger.info("Setting up special page " + virtualWiki + " / "
357: + topicName);
358: if (user == null) {
359: throw new IllegalArgumentException(
360: "Cannot pass null WikiUser object to setupSpecialPage");
361: }
362: String contents = WikiUtil.readSpecialPage(locale, topicName);
363: Topic topic = new Topic();
364: topic.setName(topicName);
365: topic.setVirtualWiki(virtualWiki);
366: topic.setTopicContent(contents);
367: topic.setAdminOnly(adminOnly);
368: // FIXME - hard coding
369: TopicVersion topicVersion = new TopicVersion(user, user
370: .getLastLoginIpAddress(),
371: "Automatically created by system setup", contents);
372: // FIXME - it is not connection-safe to parse for metadata since we are already holding a connection
373: // ParserOutput parserOutput = ParserUtil.parserOutput(topic.getTopicContent(), virtualWiki, topicName);
374: // WikiBase.getDataHandler().writeTopic(topic, topicVersion, parserOutput.getCategories(), parserOutput.getLinks(), true, conn);
375: WikiBase.getDataHandler().writeTopic(topic, topicVersion, null,
376: null, true, conn);
377: }
378:
379: /**
380: *
381: */
382: private static void setupSpecialPages(Locale locale, WikiUser user,
383: Connection conn) throws Exception {
384: List all = WikiBase.getDataHandler().getVirtualWikiList(conn);
385: for (Iterator iterator = all.iterator(); iterator.hasNext();) {
386: VirtualWiki virtualWiki = (VirtualWiki) iterator.next();
387: // create the default topics
388: setupSpecialPage(locale, virtualWiki.getName(),
389: WikiBase.SPECIAL_PAGE_STARTING_POINTS, user, false,
390: conn);
391: setupSpecialPage(locale, virtualWiki.getName(),
392: WikiBase.SPECIAL_PAGE_LEFT_MENU, user, true, conn);
393: setupSpecialPage(locale, virtualWiki.getName(),
394: WikiBase.SPECIAL_PAGE_BOTTOM_AREA, user, true, conn);
395: setupSpecialPage(locale, virtualWiki.getName(),
396: WikiBase.SPECIAL_PAGE_STYLESHEET, user, true, conn);
397: }
398: }
399: }
|