001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.interceptor;
023:
024: import java.util.HashMap;
025: import java.util.Timer;
026: import java.util.TimerTask;
027:
028: import javax.management.Descriptor;
029: import javax.management.PersistentMBean;
030: import javax.management.MBeanException;
031: import javax.management.InstanceNotFoundException;
032: import javax.management.modelmbean.ModelMBeanInfo;
033:
034: import org.jboss.mx.modelmbean.ModelMBeanConstants;
035: import org.jboss.mx.service.ServiceConstants;
036: import org.jboss.mx.server.Invocation;
037: import org.jboss.mx.server.MBeanInvoker;
038:
039: /** A peristence interceptor that uses the java.util.Timer framework for the
040: * scheculed peristence policies.
041: *
042: * @see javax.management.PersistentMBean
043: *
044: * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
045: * @author Scott.Stark@jboss.org
046: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>.
047: *
048: * @version $Revision: 57200 $
049: */
050: public class PersistenceInterceptor extends AbstractInterceptor
051: implements ModelMBeanConstants, ServiceConstants {
052: /** The HashMap<name, policy> of attribute level policies */
053: private HashMap attrPersistencePolicies = new HashMap();
054: /** The HashMap<name, PersistenceTimerTask> of scheduled peristence */
055: private HashMap timerTaskMap = new HashMap();
056: /** The bean level peristence policy */
057: private String mbeanPersistencePolicy;
058: /** The PersistentMBean load/store callback interface */
059: private PersistentMBean callback;
060:
061: public PersistenceInterceptor() {
062: super ("Default Persistence Interceptor");
063: }
064:
065: // Public --------------------------------------------------------
066: public Object invoke(Invocation invocation) throws Throwable {
067: if (callback == null) {
068: lazyInit(invocation);
069: }
070:
071: Object returnValue = invocation.nextInterceptor().invoke(
072: invocation);
073: String type = invocation.getType();
074: if (type != Invocation.OP_SETATTRIBUTE)
075: return returnValue;
076:
077: String attrName = invocation.getName();
078: String policy = (String) attrPersistencePolicies.get(attrName);
079: if (policy == null)
080: policy = mbeanPersistencePolicy;
081:
082: if (policy.equalsIgnoreCase(PP_ON_UPDATE) == true) {
083: MBeanInvoker invoker = invocation.getInvoker();
084: Descriptor attrDesc = invocation.getDescriptor();
085: invoker.updateAttributeInfo(attrDesc);
086: callback.store();
087: } else if (policy.equalsIgnoreCase(PP_NO_MORE_OFTEN_THAN) == true) {
088: PersistenceTimerTask task = (PersistenceTimerTask) timerTaskMap
089: .get(attrName);
090: if (task != null)
091: task.setHasUpdated(true);
092: }
093: return returnValue;
094: }
095:
096: /**
097: *
098: * @param invocation
099: */
100: private synchronized void lazyInit(Invocation invocation)
101: throws MBeanException {
102: // This requires the invoker to implement PersistentMBean
103: MBeanInvoker invoker = invocation.getInvoker();
104: callback = (PersistentMBean) invocation.getInvoker();
105: ModelMBeanInfo info = (ModelMBeanInfo) invoker.getMetaData();
106: Descriptor mbeanDesc = info.getMBeanDescriptor();
107:
108: String policy = (String) mbeanDesc
109: .getFieldValue(PERSIST_POLICY);
110: String persistPeriod = (String) mbeanDesc
111: .getFieldValue(PERSIST_PERIOD);
112:
113: mbeanPersistencePolicy = PP_NEVER;
114: if (policy != null) {
115: mbeanPersistencePolicy = policy;
116: if (mbeanPersistencePolicy.equalsIgnoreCase(PP_ON_TIMER)
117: || mbeanPersistencePolicy
118: .equalsIgnoreCase(PP_NO_MORE_OFTEN_THAN)) {
119: boolean isNoMoreOftenThan = mbeanPersistencePolicy
120: .equalsIgnoreCase(PP_NO_MORE_OFTEN_THAN);
121: schedulePersistenceNotifications(Long
122: .parseLong(persistPeriod), MBEAN_DESCRIPTOR,
123: isNoMoreOftenThan);
124: }
125: }
126:
127: Descriptor[] attrDescs = info
128: .getDescriptors(ATTRIBUTE_DESCRIPTOR);
129: for (int i = 0; i < attrDescs.length; ++i) {
130: policy = (String) attrDescs[i]
131: .getFieldValue(PERSIST_POLICY);
132: persistPeriod = (String) attrDescs[i]
133: .getFieldValue(PERSIST_PERIOD);
134:
135: if (policy != null) {
136: String name = (String) attrDescs[i].getFieldValue(NAME);
137: attrPersistencePolicies.put(name, policy);
138:
139: if (policy.equalsIgnoreCase(PP_ON_TIMER)
140: || policy
141: .equalsIgnoreCase(PP_NO_MORE_OFTEN_THAN)) {
142: boolean isNoMoreOftenThan = policy
143: .equalsIgnoreCase(PP_NO_MORE_OFTEN_THAN);
144: schedulePersistenceNotifications(Long
145: .parseLong(persistPeriod), name,
146: isNoMoreOftenThan);
147: }
148: }
149: }
150: }
151:
152: private void schedulePersistenceNotifications(long persistPeriod,
153: String name, boolean isNoMoreOftenThan) {
154: // @todo: unschedule on unregistration/descriptor field change
155: PersistenceTimerTask task = new PersistenceTimerTask(name,
156: isNoMoreOftenThan);
157: Timer timer = new Timer(true);
158: timer.scheduleAtFixedRate(task, 0, persistPeriod);
159: timerTaskMap.put(name, task);
160: }
161:
162: // Inner classes -------------------------------------------------
163: private class PersistenceTimerTask extends TimerTask {
164: boolean noMoreOftenThan;
165: boolean hasUpdated;
166: String name;
167:
168: PersistenceTimerTask(String name, boolean noMoreOftenThan) {
169: this .name = name;
170: this .noMoreOftenThan = noMoreOftenThan;
171: }
172:
173: synchronized void setHasUpdated(boolean flag) {
174: hasUpdated = flag;
175: }
176:
177: public void run() {
178: try {
179: // @todo: add PersistenceContext field to MBean's descriptor to
180: // relay attribute name (and possibly other) info with the
181: // persistence callback
182: boolean doStore = (noMoreOftenThan == true && hasUpdated == true)
183: || noMoreOftenThan == false;
184: if (doStore == true) {
185: callback.store();
186: setHasUpdated(false);
187: }
188: } catch (MBeanException e) {
189: // FIXME: log exception
190: } catch (InstanceNotFoundException e) {
191: // FIXME: log exception
192: }
193: }
194: }
195: }
|