001: /**********************************************************************************
002: * $URL: https://source.sakaiproject.org/svn/memory/tags/sakai_2-4-1/memory-impl/impl/src/java/org/sakaiproject/memory/impl/BasicMemoryService.java $
003: * $Id: BasicMemoryService.java 8041 2006-04-20 17:02:03Z ggolden@umich.edu $
004: ***********************************************************************************
005: *
006: * Copyright (c) 2003, 2004, 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.sakaiproject.memory.impl;
021:
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.Observable;
025: import java.util.Observer;
026: import java.util.Set;
027:
028: import org.apache.commons.logging.Log;
029: import org.apache.commons.logging.LogFactory;
030: import org.sakaiproject.authz.api.SecurityService;
031: import org.sakaiproject.component.cover.ComponentManager;
032: import org.sakaiproject.event.api.Event;
033: import org.sakaiproject.event.api.EventTrackingService;
034: import org.sakaiproject.event.api.UsageSessionService;
035: import org.sakaiproject.memory.api.Cache;
036: import org.sakaiproject.memory.api.CacheRefresher;
037: import org.sakaiproject.memory.api.Cacher;
038: import org.sakaiproject.memory.api.MemoryPermissionException;
039: import org.sakaiproject.memory.api.MemoryService;
040: import org.sakaiproject.memory.api.MultiRefCache;
041:
042: /**
043: * <p>
044: * MemBasicMemoryServiceoryService is an implementation for the MemoryService which reports memory usage and runs a periodic garbage collection to keep memory available.
045: * </p>
046: */
047: public abstract class BasicMemoryService implements MemoryService,
048: Observer {
049: /** Our logger. */
050: private static Log M_log = LogFactory
051: .getLog(BasicMemoryService.class);
052:
053: /** Event for the memory reset. */
054: protected static final String EVENT_RESET = "memory.reset";
055:
056: /** Set of registered cachers. */
057: protected Set m_cachers = new HashSet();
058:
059: /** If true, output verbose caching info. */
060: protected boolean m_cacheLogging = false;
061:
062: /**********************************************************************************************************************************************************************************************************************************************************
063: * Dependencies and their setter methods
064: *********************************************************************************************************************************************************************************************************************************************************/
065:
066: /**
067: * @return the EventTrackingService collaborator.
068: */
069: protected abstract EventTrackingService eventTrackingService();
070:
071: /**
072: * @return the SecurityService collaborator.
073: */
074: protected abstract SecurityService securityService();
075:
076: /**
077: * @return the UsageSessionService collaborator.
078: */
079: protected abstract UsageSessionService usageSessionService();
080:
081: /**********************************************************************************************************************************************************************************************************************************************************
082: * Configuraiton
083: *********************************************************************************************************************************************************************************************************************************************************/
084:
085: /**
086: * Configuration: cache verbose debug
087: */
088: public void setCacheLogging(boolean value) {
089: m_cacheLogging = value;
090: }
091:
092: public boolean getCacheLogging() {
093: return m_cacheLogging;
094: }
095:
096: /**********************************************************************************************************************************************************************************************************************************************************
097: * Init and Destroy
098: *********************************************************************************************************************************************************************************************************************************************************/
099:
100: /**
101: * Final initialization, once all dependencies are set.
102: */
103: public void init() {
104: try {
105: // get notified of events to watch for a reset
106: eventTrackingService().addObserver(this );
107:
108: M_log.info("init()");
109: } catch (Throwable t) {
110: M_log.warn("init(): ", t);
111: }
112:
113: } // init
114:
115: /**
116: * Returns to uninitialized state.
117: */
118: public void destroy() {
119: // if we are not in a global shutdown, remove my event notification registration
120: if (!ComponentManager.hasBeenClosed()) {
121: eventTrackingService().deleteObserver(this );
122: }
123:
124: m_cachers.clear();
125:
126: M_log.info("destroy()");
127: }
128:
129: /**********************************************************************************************************************************************************************************************************************************************************
130: * MemoryService implementation
131: *********************************************************************************************************************************************************************************************************************************************************/
132:
133: /**
134: * Return the amount of available memory.
135: *
136: * @return the amount of available memory.
137: */
138: public long getAvailableMemory() {
139: return Runtime.getRuntime().freeMemory();
140:
141: } // getAvailableMemory
142:
143: /**
144: * Cause less memory to be used by clearing any optional caches.
145: */
146: public void resetCachers() throws MemoryPermissionException {
147: // check that this is a "super" user with the security service
148: if (!securityService().isSuperUser()) {
149: // TODO: session id or session user id?
150: throw new MemoryPermissionException(usageSessionService()
151: .getSessionId(), EVENT_RESET, "");
152: }
153:
154: // post the event so this and any other app servers in the cluster will reset
155: eventTrackingService().post(
156: eventTrackingService().newEvent(EVENT_RESET, "", true));
157:
158: } // resetMemory
159:
160: /**
161: * Compute a status report on all memory users
162: */
163: public String getStatus() {
164: StringBuffer buf = new StringBuffer();
165: buf.append("** Memory report\n");
166:
167: Iterator it = m_cachers.iterator();
168: while (it.hasNext()) {
169: Cacher cacher = (Cacher) it.next();
170: buf.append(cacher.getSize() + " in "
171: + cacher.getDescription() + "\n");
172: }
173:
174: String rv = buf.toString();
175: M_log.info(rv);
176:
177: return rv;
178: }
179:
180: /**
181: * Do a reset of all cachers
182: */
183: protected void doReset() {
184: if (!m_cachers.isEmpty()) {
185: // tell all our memory users to reset their memory use
186: Iterator it = m_cachers.iterator();
187: while (it.hasNext()) {
188: Cacher cacher = (Cacher) it.next();
189: cacher.resetCache();
190: }
191:
192: // run the garbage collector now
193: System.runFinalization();
194: System.gc();
195: }
196:
197: M_log.info("doReset(): Low Memory Recovery to: "
198: + Runtime.getRuntime().freeMemory());
199:
200: } // doReset
201:
202: /**
203: * Register as a cache user
204: */
205: public void registerCacher(Cacher cacher) {
206: m_cachers.add(cacher);
207:
208: } // registerCacher
209:
210: /**
211: * Unregister as a cache user
212: */
213: public void unregisterCacher(Cacher cacher) {
214: m_cachers.remove(cacher);
215:
216: } // unregisterCacher
217:
218: /**
219: * {@inheritDoc}
220: */
221: public Cache newCache(CacheRefresher refresher, String pattern) {
222: return new MemCache(this , eventTrackingService(), refresher,
223: pattern);
224: }
225:
226: /**
227: * {@inheritDoc}
228: */
229: public Cache newHardCache(CacheRefresher refresher, String pattern) {
230: return new HardCache(this , eventTrackingService(), refresher,
231: pattern);
232: }
233:
234: /**
235: * {@inheritDoc}
236: */
237: public Cache newHardCache(long sleep, String pattern) {
238: return new HardCache(this , eventTrackingService(), sleep,
239: pattern);
240: }
241:
242: /**
243: * {@inheritDoc}
244: */
245: public Cache newCache(CacheRefresher refresher, long sleep) {
246: return new MemCache(this , eventTrackingService(), refresher,
247: sleep);
248: }
249:
250: /**
251: * {@inheritDoc}
252: */
253: public Cache newHardCache(CacheRefresher refresher, long sleep) {
254: return new HardCache(this , eventTrackingService(), refresher,
255: sleep);
256: }
257:
258: /**
259: * {@inheritDoc}
260: */
261: public Cache newCache() {
262: return new MemCache(this , eventTrackingService());
263: }
264:
265: /**
266: * {@inheritDoc}
267: */
268: public Cache newHardCache() {
269: return new HardCache(this , eventTrackingService());
270: }
271:
272: /**
273: * {@inheritDoc}
274: */
275: public MultiRefCache newMultiRefCache(long sleep) {
276: return new MultiRefCacheImpl(this , eventTrackingService(),
277: sleep);
278: }
279:
280: /**********************************************************************************************************************************************************************************************************************************************************
281: * Observer implementation
282: *********************************************************************************************************************************************************************************************************************************************************/
283:
284: /**
285: * This method is called whenever the observed object is changed. An application calls an <tt>Observable</tt> object's <code>notifyObservers</code> method to have all the object's observers notified of the change. default implementation is to
286: * cause the courier service to deliver to the interface controlled by my controller. Extensions can override.
287: *
288: * @param o
289: * the observable object.
290: * @param arg
291: * an argument passed to the <code>notifyObservers</code> method.
292: */
293: public void update(Observable o, Object arg) {
294: // arg is Event
295: if (!(arg instanceof Event))
296: return;
297: Event event = (Event) arg;
298:
299: // look for the memory reset event
300: String function = event.getEvent();
301: if (!function.equals(EVENT_RESET))
302: return;
303:
304: // do the reset here, too!
305: doReset();
306: }
307: }
|