001: package org.columba.core.association;
002:
003: import java.io.File;
004: import java.sql.Connection;
005: import java.sql.DriverManager;
006: import java.sql.SQLException;
007: import java.sql.Statement;
008: import java.util.Collection;
009: import java.util.HashMap;
010: import java.util.LinkedList;
011: import java.util.List;
012: import java.util.Vector;
013: import java.util.logging.ConsoleHandler;
014: import java.util.logging.Handler;
015: import java.util.logging.Level;
016: import java.util.logging.Logger;
017:
018: import javax.persistence.EntityManager;
019: import javax.persistence.EntityManagerFactory;
020: import javax.persistence.EntityTransaction;
021: import javax.persistence.Persistence;
022: import javax.persistence.PersistenceException;
023: import javax.persistence.Query;
024:
025: import org.columba.core.association.api.IAssociation;
026: import org.columba.core.association.api.IAssociationStore;
027: import org.columba.core.config.DefaultConfigDirectory;
028:
029: public class AssociationStore implements IAssociationStore, Runnable {
030:
031: final static String ENTITY_MANAGER = "associations";
032:
033: /** JDK 1.4+ logging framework logger, used for logging. */
034: private static final Logger LOG = Logger
035: .getLogger("org.columba.core.association.AssociationStore");
036:
037: EntityManagerFactory factory;
038:
039: EntityManager manager;
040:
041: Connection conn;
042:
043: static private AssociationStore instance;
044:
045: /**
046: * private constructor for the singelton implementation
047: *
048: */
049: private AssociationStore() {
050: factory = null;
051: manager = null;
052: conn = null;
053: }
054:
055: public void addAssociation(String serviceId, String metaDataId,
056: String itemId) {
057:
058: // passive: if not initialized do it now
059: if (!isReady())
060: init();
061:
062: // still not ready, exit!
063: if (!isReady())
064: return;
065:
066: // transaction is needed for the underlying jpa architecture
067: EntityTransaction tx = manager.getTransaction();
068: tx.begin();
069: try {
070: IAssociation association = new Association(itemId,
071: serviceId, metaDataId);
072: manager.persist(association);
073: tx.commit();
074: } catch (Exception ex) {
075: if (tx.isActive()) {
076: tx.rollback();
077: LOG
078: .severe("AddAssociation: Exception while persisting new association! Will Rollback! "
079: + serviceId
080: + " "
081: + metaDataId
082: + " "
083: + itemId);
084: } else
085: LOG
086: .log(
087: Level.SEVERE,
088: "Got an Exception, but no Transaction active, so no Rollback!",
089: ex);
090: }
091: }
092:
093: @SuppressWarnings("unchecked")
094: public Collection<IAssociation> getAllAssociations(String itemId) {
095:
096: // passive: if not initialized do it now
097: if (!isReady())
098: init();
099:
100: // still not ready, exit!
101: if (!isReady())
102: return new Vector<IAssociation>();
103:
104: // transaction is needed for the underlying jpa architecture
105: EntityTransaction tx = manager.getTransaction();
106:
107: // wait, if there is an active transaction
108: // TODO @author hubms retrycount!
109: while (tx.isActive())
110: ;
111:
112: tx.begin();
113: Query query = manager
114: .createQuery("select a from org.columba.core.association.Association a where a.itemId = '"
115: + itemId + "'");
116: Collection<IAssociation> results = (Collection<IAssociation>) query
117: .getResultList();
118: // for(IAssociation a : results) {
119: // System.out.println("got a association: " + a.getItemId() + " " +
120: // a.getMetaDataId() + " " + a.getServiceId());
121: // }
122: tx.commit();
123: return results;
124: }
125:
126: @SuppressWarnings("unchecked")
127: public Collection<String> getAssociatedItems(String serviceId,
128: String metaDataId) {
129:
130: // passive: if not initialized do it now
131: if (!isReady())
132: init();
133:
134: // still not ready, exit!
135: if (!isReady())
136: return new Vector<String>();
137:
138: // transaction is needed for the underlying jpa architecture
139: EntityTransaction tx = manager.getTransaction();
140: tx.begin();
141: Query query = manager
142: .createQuery("select a from org.columba.core.association.Association a where a.serviceId = '"
143: + serviceId
144: + "' and a.metaDataId = '"
145: + metaDataId + "'");
146: Collection<IAssociation> results = (Collection<IAssociation>) query
147: .getResultList();
148: Collection<String> itemCollection = new LinkedList<String>();
149: for (IAssociation a : results) {
150: itemCollection.add(a.getItemId());
151: }
152: tx.commit();
153: return itemCollection;
154: }
155:
156: /**
157: * starts the jpa manager starts the database
158: */
159: public void init() {
160:
161: // disable logging for the startup
162: Handler[] handlers = Logger.getLogger("").getHandlers();
163: ConsoleHandler consolehandler = null;
164: Level level = null;
165: for (int index = 0; index < handlers.length; index++) {
166: // set console handler to OFF
167: if (handlers[index] instanceof ConsoleHandler) {
168: level = handlers[index].getLevel();
169: handlers[index].setLevel(Level.OFF);
170: consolehandler = (ConsoleHandler) handlers[index];
171: break;
172: }
173: }
174:
175: //ShutdownManager.getInstance().register(this);
176:
177: String connectionString = "jdbc:hsqldb:file:"
178: + DefaultConfigDirectory.getInstance().getCurrentPath()
179: .getAbsolutePath() + File.separator
180: + "associations";
181:
182: // start HSQLDB
183: try {
184:
185: // do not start a second time!
186: if (conn == null) {
187: Class.forName("org.hsqldb.jdbcDriver").newInstance();
188: conn = DriverManager.getConnection(connectionString,
189: "sa", "");
190: }
191: } catch (InstantiationException e) {
192: LOG.severe("AssociationStore: Could not start the HSQLDB! "
193: + e.getClass().getName() + ": " + e.getMessage());
194: } catch (IllegalAccessException e) {
195: LOG.severe("AssociationStore: Could not start the HSQLDB! "
196: + e.getClass().getName() + ": " + e.getMessage());
197: } catch (ClassNotFoundException e) {
198: LOG.severe("AssociationStore: Could not start the HSQLDB! "
199: + e.getClass().getName() + ": " + e.getMessage());
200: } catch (SQLException e) {
201: LOG.severe("AssociationStore: Could not start the HSQLDB! "
202: + e.getClass().getName() + ": " + e.getMessage());
203: }
204:
205: try {
206:
207: // manually rewrite the connection url, because
208: // if there is no rewrite the database files are created
209: // in the starting directory, we don't want that!
210: HashMap<String, String> map = new HashMap<String, String>();
211: map.put("hibernate.connection.url", connectionString);
212: map.put("exclude-unlisted-classes", "true"); // refers to the
213: // entry in
214: // persistence.xml
215:
216: // start JPA entity manager
217: if (factory == null)
218: factory = Persistence.createEntityManagerFactory(
219: ENTITY_MANAGER, map);
220:
221: if (manager == null)
222: manager = factory.createEntityManager(map);
223:
224: } catch (PersistenceException pEx) {
225: LOG
226: .severe("AssociationStore: Could not start the Entity manager! "
227: + pEx.getMessage());
228: }
229:
230: // restore log level
231: if (consolehandler != null)
232: consolehandler.setLevel(level);
233:
234: }
235:
236: public boolean isReady() {
237: return ((factory != null) && (manager != null) && (conn != null));
238: }
239:
240: @SuppressWarnings("unchecked")
241: public void removeAssociation(String serviceId, String metaDataId,
242: String itemId) {
243:
244: // passive: if not initialized do it now
245: if (!isReady())
246: init();
247:
248: // still not ready, exit!
249: if (!isReady())
250: return;
251:
252: EntityTransaction tx = manager.getTransaction();
253: tx.begin();
254: try {
255: Query query = manager
256: .createQuery("select a from org.columba.core.association.Association a where a.itemId = '"
257: + itemId
258: + "' and a.serviceId = '"
259: + serviceId
260: + "'"
261: + " and a.metaDataId = '"
262: + metaDataId + "'");
263: if (query.getResultList().size() > 1) {
264: // more than one item, very strange! duplicate entries! remove
265: // all
266: LOG
267: .info("RemoveAssociation: Got more than one association, that is strange! We try to remove all!");
268: for (Object row : query.getResultList())
269: manager.remove(row);
270: tx.commit();
271: } else if (query.getResultList().size() == 1) {
272: manager.remove(query.getSingleResult());
273: tx.commit();
274: } else {
275: // no item exists in table
276: // -> nothing todo
277: }
278: } catch (Exception ex) {
279: if (tx.isActive()) {
280: tx.rollback();
281: LOG
282: .severe("RemoveAssociation: Exception while removing association! Will Rollback! "
283: + serviceId
284: + " "
285: + metaDataId
286: + " "
287: + itemId);
288: } else {
289: ex.printStackTrace();
290: LOG
291: .log(
292: Level.SEVERE,
293: "RemoveAssociation: Got an Exception, but no Transaction active, so no Rollback!",
294: ex);
295: }
296: }
297: }
298:
299: @SuppressWarnings("unchecked")
300: public void removeItem(String itemId) {
301:
302: // passive: if not initialized do it now
303: if (!isReady())
304: init();
305:
306: // still not ready, exit!
307: if (!isReady())
308: return;
309:
310: EntityTransaction tx = manager.getTransaction();
311: tx.begin();
312: try {
313: Query query = manager
314: .createQuery("select a from org.columba.core.association.Association a where a.itemId = '"
315: + itemId + "'");
316: List<Association> results = (List<Association>) query
317: .getResultList();
318: for (Association a : results) {
319: manager.remove(a);
320: }
321: tx.commit();
322: } catch (Exception ex) {
323: LOG.severe("RemoveItem: could not remove item"
324: + ex.getMessage());
325: ex.printStackTrace();
326: tx.rollback();
327: }
328: }
329:
330: public void shutdown() {
331:
332: // shutdown hsql
333: try {
334: // if the database is not started, don't do it
335: if (conn != null) {
336: Statement stmt = conn.createStatement();
337: stmt.execute("SHUTDOWN");
338: }
339: } catch (SQLException e) {
340: LOG
341: .severe("AssociationStore: Could not shutdwon the database! "
342: + e.getClass().getName()
343: + ": "
344: + e.getMessage());
345: }
346:
347: // shutdown entity manager
348: if (manager != null)
349: manager.close();
350:
351: if (factory != null)
352: factory.close();
353: }
354:
355: public static AssociationStore getInstance() {
356: if (instance == null) {
357: synchronized (AssociationStore.class) {
358: if (instance == null)
359: instance = new AssociationStore();
360: }
361: }
362: return instance;
363: }
364:
365: public void run() {
366: shutdown();
367: }
368: }
|