/* * Copyright 2011 Ronald Kurniawan. * * This file is part of CodeTraq. * * CodeTraq is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * CodeTraq is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with CodeTraq. If not, see <http://www.gnu.org/licenses/>. */ package net.mobid.codetraq.utils; import com.db4o.Db4oEmbedded; import com.db4o.ObjectContainer; import com.db4o.ObjectSet; import java.util.ArrayList; import java.util.List; import net.mobid.codetraq.persistence.MessageDTO; import net.mobid.codetraq.persistence.ServerRevision; import net.mobid.codetraq.persistence.UserRevision; /** * This class deals with CRUD operation with db4o. We chose db4o because it is * compact, easy to use, works with the Java objects directly and self-contained. * You are free to modify this class to work with other database providers. * * @author Ronald Kurniawan * @version 0.1 */ public class DbUtility { private ObjectContainer _db = null; private ObjectContainer _userRevDb = null; private ObjectContainer _serverRevDb = null; /** * Creates a new instance of DbUtility. This method automatically opens all * the "tables" (so to speak) so we can start work. */ public DbUtility() { if (_db == null) { openMessageDb(); } if (_userRevDb == null) { openUserRevisionDb(); } if (_serverRevDb == null) { openServerRevisionDb(); } } /** * Closes all the "tables" associated with this instance. */ public void closeDbs() { dbClose(); userRevisionDbClose(); serverRevisionDbClose(); } /* * Opens the "table" associated with storing message objects. */ private void openMessageDb() { // open the database _db = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), "messages.db"); } /** * Returns the number of messages left in the database. * @return number of messages still in the database */ public int getMessagePopulations() { ObjectSet result = _db.queryByExample(MessageDTO.class); return result.size(); } /** * Saves a message into the database for sending at a later time. * @param value - a <code>MessageDTO</code> object * @throws net.mobid.codetraq.utils.DbUtility.DbException - when a duplicate message is found */ public void saveMessage(MessageDTO value) throws DbException { if (getMessageByTime(value.getTimestamp()).hasNext()) { throw new DbException("Duplicate timestamp found"); } _db.store(value); } /** * Updates the number of attempts the server made to send this message. * This could indicate remote notification service is down. * @param value - a <code>MessageDTO</code> object, which should be updated */ public void updateMessageRetries(MessageDTO value) { ObjectSet result = _db.queryByExample(value); MessageDTO found = (MessageDTO)result.next(); found.appendRetries(); _db.store(found); } /** * Updates the status of message to "SENT". * @param value - a <code>MessageDTO</code> object, which should be updated */ public void updateMessageSent(MessageDTO value) { ObjectSet result = _db.queryByExample(value); MessageDTO found = (MessageDTO)result.next(); found.setSent(true); _db.store(found); } /** * Retrieves all messages that are still unsent. * @return a <code>List</code> of unsent messages */ public List<MessageDTO> getAllUnsentMessages() { return _db.query(MessageDTO.class); } /** * Deletes all messages that are marked "SENT". */ public void deleteAllSentMessages() { MessageDTO template = new MessageDTO(); template.setSent(true); ObjectSet result = _db.queryByExample(template); while(result.hasNext()) { MessageDTO found = (MessageDTO)result.next(); deleteMessage(found); logCheckDelete(found.getServerName(), found.getTimestamp()); } } /** * Deletes a single message. * @param value - a <code>MessageDTO</code> that should be deleted */ public void deleteMessage(MessageDTO value) { ObjectSet result = _db.queryByExample(value); while(result.hasNext()) { MessageDTO m = (MessageDTO)result.next(); _db.delete(m); } } /* * Returns a message that has a specified timestamp. * @param timeStamp - the required timestamp * @return an <code>ObjectSet</code> containing the message object(s) */ private ObjectSet getMessageByTime(long timeStamp) { MessageDTO m = new MessageDTO(); m.setTimestamp(timeStamp); ObjectSet result = _db.queryByExample(m); return result; } /** * Queries the number of attemps to send a specific message has. The output * would only be visible from the console. * @param serverName - server name which the message refers to * @param timestamp - the timestamp of the message */ public void logCheckRetries(String serverName, long timestamp) { MessageDTO m = new MessageDTO(); m.setServerName(serverName); m.setTimestamp(timestamp); ObjectSet os = _db.queryByExample(m); if (os.hasNext()) { MessageDTO found = (MessageDTO)os.next(); LogService.writeMessage("CHECK retries -> Message for server " + found.getServerName() + " (rev#" + found.getRevisionId() + ") has " + found.getRetries() + " retries."); } } /** * Checks whether a message has been deleted from the database. The status would * only be visible from the console. * @param serverName - server name which the message refers to * @param timestamp - the timetamp of the message */ public void logCheckDelete(String serverName, long timestamp) { MessageDTO m = new MessageDTO(); m.setServerName(serverName); m.setTimestamp(timestamp); ObjectSet os = _db.queryByExample(m); if (os.isEmpty()) { LogService.writeMessage("CHECK deleted -> Message for server " + serverName + " with timestamp " + timestamp + " has been deleted."); } else { MessageDTO found = (MessageDTO)os.next(); LogService.writeMessage("CHECK deleted -> Message for server " + found.getServerName() + " (rev#" + found.getRevisionId() + ")" + " still in database."); } } /* * Closes the message "table" */ private void dbClose() { if (_db != null) { _db.close(); } } // USER REVISION database /* * Opens the user revision "table" */ private void openUserRevisionDb() { _userRevDb = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), "user.db"); } /* * Closes the user revision "table" */ private void userRevisionDbClose() { if (_userRevDb != null) { _userRevDb.close(); } } /** * Returns the number of user revision in the database. * @return the number of user revisions */ public int getUserRecordPopulations() { ObjectSet result = _userRevDb.queryByExample(UserRevision.class); return result.size(); } /** * Queries whether a specified server (URL) has been saved into the database. * @param address - server URL * @param owner - user ID who "owns" this server * @return */ public boolean isServerInUserRecord(String address, String owner) { UserRevision r = new UserRevision(); r.setOwner(owner); r.setServerAddress(address); ObjectSet result = _userRevDb.queryByExample(r); if (result.hasNext()) { return true; } return false; } /** * Add a new user revision object into the database. * @param address - server URL * @param owner - user ID who "owns" this server */ public void addServerToUserRecord(String address, String owner) { UserRevision r = new UserRevision(); r.setServerAddress(address); r.setOwner(owner); int records = getUserRecordPopulations(); _userRevDb.store(r); int after = getUserRecordPopulations(); LogService.writeMessage("CHECK_ADD_UR: before " + records + "/after " + after); if (records == after) { LogService.writeMessage("WARNING: Adding new server to user database seems to have failed. (address: " + address + "; owner: " + owner + ")"); } } /** * Returns the user revision object for the specified URL and user ID. * @param address - server URL * @param owner - user ID who "owns" this server * @return a <code>UserRevision</code> object */ public UserRevision getUserLatestRevision(String address, String owner) { UserRevision r = new UserRevision(); r.setServerAddress(address); r.setOwner(owner); ObjectSet result = _userRevDb.queryByExample(r); // we only suppose to have one Revision per Server, so grab the first one found... if (result.hasNext()) { return (UserRevision)result.next(); } return null; } /** * Updates a user revision object with new information. * @param ur - <code>UserRevision</code> object to update */ public void updateUserLatestRevision(UserRevision ur) { UserRevision r = new UserRevision(); r.setServerAddress(ur.getServerAddress()); r.setOwner(ur.getOwner()); ObjectSet result = _userRevDb.queryByExample(r); if (result.hasNext()) { UserRevision found = (UserRevision)result.next(); found.setLastRevisionId(ur.getLastRevisionId()); _userRevDb.store(found); } } // SERVER REVISION /* * Opens the Server Revision "table". */ private void openServerRevisionDb() { _serverRevDb = Db4oEmbedded.openFile(Db4oEmbedded.newConfiguration(), "revision.db"); } /* * Closes the ServerRevision "table". */ private void serverRevisionDbClose() { if (_serverRevDb != null) { _serverRevDb.close(); } } /** * Returns the number of ServerRevision objects in the database. * @return number of <code>ServerRevision</code> objects */ public int getServerRevisionPopulations() { ObjectSet result = _serverRevDb.queryByExample(ServerRevision.class); return result.size(); } /** * Returns a list of all ServerRevision objects in the database. * @return a <code>List</code> of all <code>ServerRevision</code> objects */ public List<ServerRevision> getAllServerRevisions() { List<ServerRevision> list = new ArrayList<ServerRevision>(); ServerRevision sr = new ServerRevision(); ObjectSet result = _serverRevDb.queryByExample(sr); while(result.hasNext()) { list.add((ServerRevision)result.next()); } return list; } /** * Returns a ServerRevision objects specified by a server URL. * @param address - server URL * @return a <code>ServerRevision</code> object */ public ServerRevision getServerRevisionByAddress(String address) { ServerRevision template = new ServerRevision(); template.setServerAddress(address); ObjectSet result = _serverRevDb.queryByExample(template); if (result.hasNext()) { return (ServerRevision)result.next(); } return null; } /** * Adds a ServerRevision object into the database. * @param sr - <code>ServerRevision</code> object to be added */ public void addServerRevision(ServerRevision sr) { int srs = getServerRevisionPopulations(); _serverRevDb.store(sr); int after = getServerRevisionPopulations(); LogService.writeMessage("CHECK_ADD_SR: before " + srs + "/after " + after); if (srs == after) { LogService.writeMessage("WARNING: Adding new server revision seems to have failed. (server: " + sr.getServerAddress() + ")"); } } /** * Updates a ServerRevision object with new information. * @param sr - <code>ServerRevision</code> object to be updated */ public void updateServerLatestRevision(ServerRevision sr) { ServerRevision template = new ServerRevision(); template.setServerAddress(sr.getServerAddress()); ObjectSet result = _serverRevDb.queryByExample(template); if (result.hasNext()) { ServerRevision found = (ServerRevision)result.next(); LogService.writeMessage("CHECK_BEFORE_SR_UPDATE: rev " + found.getLastRevisionId()); found.setLastCheckedTimestamp(sr.getLastCheckedTimestamp()); found.setLastMessage(sr.getLastMessage()); found.setLastAuthor(sr.getLastAuthor()); found.setLastCommitter(sr.getLastCommitter()); found.setLastRevisionTimestamp(sr.getLastRevisionTimestamp()); found.setLastRevisionId(sr.getLastRevisionId()); _serverRevDb.store(found); LogService.writeMessage("CHECK_AFTER_SR_UPDATE: rev " + found.getLastRevisionId()); } } /** * Toggles the "update" flag of a certain ServerRevision to "ON". * @param sr - <code>ServerRevision</code> to be flagged */ public void turnServerUpdateOn(ServerRevision sr) { ServerRevision template = new ServerRevision(); template.setServerAddress(sr.getServerAddress()); ObjectSet result = _serverRevDb.queryByExample(template); if (result.hasNext()) { ServerRevision found = (ServerRevision)result.next(); found.setShouldUpdate(true); _serverRevDb.store(found); } } /** * Toggles the "update" flag of a certain ServerRevision to "OFF". * @param sr - <code>ServerRevision</code> to be flagged */ public void turnServerUpdateOff(ServerRevision sr) { ServerRevision template = new ServerRevision(); template.setServerAddress(sr.getServerAddress()); ObjectSet result = _serverRevDb.queryByExample(template); if (result.hasNext()) { ServerRevision found = (ServerRevision)result.next(); found.setShouldUpdate(false); _serverRevDb.store(found); } } /** * Toggles the "update" flag of all ServerRevision objects to "OFF". */ public void turnAllServerUpdateOff() { ServerRevision template = new ServerRevision(); ObjectSet result = _serverRevDb.queryByExample(template); while(result.hasNext()) { ServerRevision item = (ServerRevision)result.next(); item.setShouldUpdate(false); _serverRevDb.store(item); } } /** * DbException */ public class DbException extends Exception { public DbException(String message) { super(message, null); } } }