001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/osp/tags/sakai_2-4-1/glossary/api-impl/src/java/org/theospi/portfolio/help/model/DbGlossary.java $
003: * $Id: DbGlossary.java 22997 2007-03-19 18:53:11Z john.ellis@rsmart.com $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2005, 2006 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: **********************************************************************************/package org.theospi.portfolio.help.model;
021:
022: import java.util.*;
023:
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026: import org.hibernate.HibernateException;
027: import org.sakaiproject.event.api.Event;
028: import org.sakaiproject.event.cover.EventTrackingService;
029: import org.sakaiproject.metaobj.shared.mgt.IdManager;
030: import org.sakaiproject.metaobj.shared.model.Id;
031: import org.sakaiproject.api.app.scheduler.SchedulerManager;
032: import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
033: import org.springframework.transaction.support.TransactionSynchronizationAdapter;
034: import org.springframework.transaction.support.TransactionSynchronizationManager;
035: import org.quartz.JobDetail;
036: import org.quartz.SimpleTrigger;
037: import org.quartz.SchedulerException;
038: import org.quartz.Trigger;
039:
040: public class DbGlossary extends HibernateDaoSupport implements
041: Glossary, Observer {
042: protected final transient Log logger = LogFactory
043: .getLog(getClass());
044: private Map worksiteGlossary = new Hashtable();
045: private IdManager idManager;
046: private List dirtyAddUpdate = new ArrayList();
047: private List dirtyRemove = new ArrayList();
048: private SchedulerManager schedulerManager;
049: private int cacheInterval = 1000 * 10;
050: private boolean useCache = true;
051:
052: private String url;
053:
054: private static final String EVENT_UPDATE_ADD = "org.theospi.glossary.updateAdd";
055: private static final String EVENT_DELETE = "org.theospi.glossary.delete";
056:
057: public GlossaryEntry load(Id id) {
058: GlossaryEntry entry = load(id, true);
059: getHibernateTemplate().evict(entry);
060: return entry;
061: }
062:
063: protected GlossaryEntry load(Id id, boolean deep) {
064: try {
065: GlossaryEntry entry = (GlossaryEntry) getSession().load(
066: GlossaryEntry.class, id);
067: if (deep) {
068: entry.setLongDescriptionObject(loadDescription(id));
069: }
070: return entry;
071: } catch (HibernateException e) {
072: logger.warn("", e);
073: return null;
074: }
075: }
076:
077: protected GlossaryEntry find(Id id) {
078: List entries = getHibernateTemplate().find(
079: "from GlossaryEntry where id = ?", id);
080: if (entries.size() > 0) {
081: return (GlossaryEntry) entries.get(0);
082: }
083: return null;
084: }
085:
086: protected GlossaryDescription loadDescription(Id entryId) {
087: Collection entries = getHibernateTemplate().findByNamedQuery(
088: "loadDescription", entryId);
089:
090: if (entries.size() > 0) {
091: return (GlossaryDescription) entries.iterator().next();
092: } else {
093: return new GlossaryDescription();
094: }
095: }
096:
097: /**
098: * find the keyword in the glossary.
099: * return null if not found.
100: *
101: * @param keyword
102: * @return
103: */
104: public GlossaryEntry find(String keyword, String worksite) {
105: Collection entries = getHibernateTemplate().findByNamedQuery(
106: "findTerms", new Object[] { keyword, worksite });
107: if (entries.size() == 0) {
108: return null;
109: } else if (entries.size() == 1) {
110: return (GlossaryEntry) entries.iterator().next();
111: } else {
112: for (Iterator i = entries.iterator(); i.hasNext();) {
113: GlossaryEntry entry = (GlossaryEntry) i.next();
114: if (entry.getWorksiteId() != null) {
115: return entry;
116: }
117: }
118: }
119:
120: return (GlossaryEntry) entries.iterator().next();
121: }
122:
123: /**
124: * returns the list of all GlossaryEntries
125: *
126: * @return
127: */
128:
129: public Collection findAll(String keyword, String worksite) {
130: return getHibernateTemplate().findByNamedQuery("findTerms",
131: new Object[] { keyword, worksite });
132: }
133:
134: /**
135: * returns the list of all GlossaryEntries
136: *
137: * @return
138: */
139: public Collection findAll(String worksite) {
140: return getHibernateTemplate().findByNamedQuery(
141: "findAllSiteTerms", new Object[] { worksite });
142: }
143:
144: public Collection findAll() {
145: return getHibernateTemplate().findByNamedQuery("findAllTerms");
146: }
147:
148: public Collection findAllGlobal() {
149: return getHibernateTemplate().findByNamedQuery(
150: "findGlobalTerms");
151: }
152:
153: public GlossaryEntry addEntry(GlossaryEntry newEntry) {
154: getHibernateTemplate().save(newEntry);
155: newEntry.getLongDescriptionObject()
156: .setEntryId(newEntry.getId());
157: getHibernateTemplate()
158: .save(newEntry.getLongDescriptionObject());
159: updateCache(newEntry, false);
160: return newEntry;
161: }
162:
163: public void removeEntry(GlossaryEntry entry) {
164: getHibernateTemplate().delete(entry);
165: GlossaryDescription desc = loadDescription(entry.getId());
166: getHibernateTemplate().delete(desc);
167: updateCache(entry, true);
168: }
169:
170: public void updateEntry(GlossaryEntry entry) {
171: getHibernateTemplate().merge(entry);
172: GlossaryDescription desc = loadDescription(entry.getId());
173: desc.setLongDescription(entry.getLongDescription());
174: getHibernateTemplate().merge(desc);
175: updateCache(entry, false);
176: }
177:
178: protected void updateCache(GlossaryEntry entry, boolean remove) {
179: if (useCache) {
180: GlossaryTxSync txSync = new GlossaryTxSync(entry, remove);
181:
182: if (TransactionSynchronizationManager
183: .isSynchronizationActive()) {
184: TransactionSynchronizationManager
185: .registerSynchronization(txSync);
186: } else {
187: txSync.afterCompletion(GlossaryTxSync.STATUS_COMMITTED);
188: }
189: }
190: }
191:
192: public Set getSortedWorksiteTerms(String worksiteId) {
193: Set sortedSet = new TreeSet(new TermComparator());
194:
195: Map worksiteTerms = getWorksiteGlossary(worksiteId);
196: if (worksiteTerms != null) {
197: sortedSet.addAll(worksiteTerms.values());
198: }
199:
200: String globalId = null;
201: Map globalTerms = getWorksiteGlossary(globalId + "");
202:
203: if (globalTerms != null) {
204: for (Iterator i = globalTerms.values().iterator(); i
205: .hasNext();) {
206: GlossaryEntry entry = (GlossaryEntry) i.next();
207: if (!sortedSet.contains(entry)) {
208: sortedSet.add(entry);
209: }
210: }
211: }
212:
213: return sortedSet;
214: }
215:
216: protected Map getWorksiteGlossary(String worksiteId) {
217: return getWorksiteGlossary(worksiteId, true);
218: }
219:
220: protected Map getWorksiteGlossary(String worksiteId,
221: boolean checkCache) {
222: if (!useCache) {
223: logger
224: .warn("using glossary without cache, this could slow down osp tool page loads");
225: Map terms = new Hashtable();
226: Collection<GlossaryEntry> entries;
227: if (worksiteId.equals(null + "")) {
228: entries = findAllGlobal();
229: } else {
230: entries = findAll(worksiteId);
231: }
232: for (Iterator<GlossaryEntry> i = entries.iterator(); i
233: .hasNext();) {
234: GlossaryEntry entry = i.next();
235: terms.put(entry.getId(), entry);
236: }
237: return terms;
238: } else {
239: if (checkCache) {
240: checkCache();
241: }
242: return (Map) worksiteGlossary.get(worksiteId);
243: }
244: }
245:
246: public void checkCache() {
247:
248: synchronized (dirtyAddUpdate) {
249: for (Iterator<Id> i = dirtyAddUpdate.iterator(); i
250: .hasNext();) {
251: GlossaryEntry entry = find(i.next());
252: if (entry != null) {
253: addUpdateTermCache(entry);
254: }
255: }
256: dirtyAddUpdate.clear();
257: }
258:
259: synchronized (dirtyRemove) {
260: for (Iterator<Id> i = dirtyRemove.iterator(); i.hasNext();) {
261: removeCachedEntry(i.next());
262: }
263: dirtyRemove.clear();
264: }
265:
266: }
267:
268: public boolean isPhraseStart(String phraseFragment, String worksite) {
269: phraseFragment += "%";
270: Collection entries = getHibernateTemplate().findByNamedQuery(
271: "findByPhrase",
272: new Object[] { phraseFragment, worksite });
273: if (entries.size() > 0) {
274: return true;
275: }
276:
277: return false;
278: }
279:
280: public String getUrl() {
281: return url;
282: }
283:
284: public void setUrl(String url) {
285: this .url = url;
286: }
287:
288: public void importResources(String fromContext, String toContext,
289: List resourceIds) {
290: Collection orig = findAll(fromContext);
291:
292: for (Iterator i = orig.iterator(); i.hasNext();) {
293: GlossaryEntry entry = (GlossaryEntry) i.next();
294:
295: entry.setLongDescriptionObject(loadDescription(entry
296: .getId()));
297:
298: getHibernateTemplate().evict(entry);
299: getHibernateTemplate().evict(
300: entry.getLongDescriptionObject());
301:
302: entry.setWorksiteId(toContext);
303: entry.setId(null);
304: getHibernateTemplate().save(entry);
305:
306: entry.getLongDescriptionObject().setEntryId(entry.getId());
307: entry.getLongDescriptionObject().setId(null);
308: getHibernateTemplate().save(
309: entry.getLongDescriptionObject());
310: addUpdateTermCache(entry);
311: }
312: }
313:
314: public void init() {
315: if (isUseCache()) {
316: logger.info("init()");
317: Collection terms = findAll();
318:
319: for (Iterator i = terms.iterator(); i.hasNext();) {
320: GlossaryEntry entry = (GlossaryEntry) i.next();
321: addUpdateTermCache(entry);
322: }
323:
324: EventTrackingService.addObserver(this );
325:
326: }
327: }
328:
329: protected void addUpdateTermCache(GlossaryEntry entry) {
330: String worksiteId = entry.getWorksiteId() + "";
331: Map worksiteMap = getWorksiteGlossary(worksiteId, false);
332:
333: if (worksiteMap == null) {
334: worksiteGlossary.put(worksiteId, new Hashtable());
335: worksiteMap = getWorksiteGlossary(worksiteId, false);
336: }
337: worksiteMap.put(entry.getId(), entry);
338: }
339:
340: protected void removeCachedEntry(Id entryId) {
341: for (Iterator i = worksiteGlossary.values().iterator(); i
342: .hasNext();) {
343: Map map = (Map) i.next();
344: if (map.remove(entryId) != null) {
345: // found it
346: return;
347: }
348: }
349: }
350:
351: /**
352: * This method is called whenever the observed object is changed. An
353: * application calls an <tt>Observable</tt> object's
354: * <code>notifyObservers</code> method to have all the object's
355: * observers notified of the change.
356: *
357: * This operates within its own Thread so normal rules and conditions don't apply
358: *
359: * @param o the observable object.
360: * @param arg an argument passed to the <code>notifyObservers</code>
361: * method.
362: */
363: public void update(Observable o, Object arg) {
364: if (arg instanceof Event) {
365: Event event = (Event) arg;
366: if (event.getEvent().equals(EVENT_UPDATE_ADD)) {
367: synchronized (dirtyAddUpdate) {
368: dirtyAddUpdate.add(getIdManager().getId(
369: event.getResource()));
370: }
371: } else if (event.getEvent().equals(EVENT_DELETE)) {
372: synchronized (dirtyRemove) {
373: dirtyRemove.add(getIdManager().getId(
374: event.getResource()));
375: }
376: }
377: }
378: }
379:
380: public IdManager getIdManager() {
381: return idManager;
382: }
383:
384: public void setIdManager(IdManager idManager) {
385: this .idManager = idManager;
386: }
387:
388: private class GlossaryTxSync extends
389: TransactionSynchronizationAdapter {
390: private GlossaryEntry entry;
391: private boolean remove = false;
392:
393: public GlossaryTxSync(GlossaryEntry entry, boolean remove) {
394: this .entry = entry;
395: this .remove = remove;
396: }
397:
398: public void afterCompletion(int status) {
399: Event event = null;
400: if (status == STATUS_COMMITTED && remove) {
401: event = EventTrackingService.newEvent(EVENT_DELETE,
402: entry.getId().getValue(), false);
403: } else if (status == STATUS_COMMITTED) {
404: event = EventTrackingService.newEvent(EVENT_UPDATE_ADD,
405: entry.getId().getValue(), false);
406: }
407:
408: if (event != null) {
409: EventTrackingService.post(event);
410: }
411: }
412:
413: public GlossaryEntry getEntry() {
414: return entry;
415: }
416:
417: public void setEntry(GlossaryEntry entry) {
418: this .entry = entry;
419: }
420: }
421:
422: public SchedulerManager getSchedulerManager() {
423: return schedulerManager;
424: }
425:
426: public void setSchedulerManager(SchedulerManager schedulerManager) {
427: this .schedulerManager = schedulerManager;
428: }
429:
430: public int getCacheInterval() {
431: return cacheInterval;
432: }
433:
434: public void setCacheInterval(int cacheInterval) {
435: this .cacheInterval = cacheInterval;
436: }
437:
438: public boolean isUseCache() {
439: return useCache;
440: }
441:
442: public void setUseCache(boolean useCache) {
443: this.useCache = useCache;
444: }
445: }
|