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.persistence;
023:
024: import javax.management.Attribute;
025: import javax.management.AttributeList;
026: import javax.management.Descriptor;
027: import javax.management.InstanceNotFoundException;
028: import javax.management.MBeanAttributeInfo;
029: import javax.management.MBeanException;
030: import javax.management.MBeanInfo;
031: import javax.management.MBeanServer;
032: import javax.management.MalformedObjectNameException;
033: import javax.management.ObjectName;
034: import javax.management.ReflectionException;
035: import javax.management.modelmbean.ModelMBeanAttributeInfo;
036: import javax.management.modelmbean.ModelMBeanInfo;
037:
038: import org.jboss.logging.Logger;
039: import org.jboss.mx.modelmbean.ModelMBeanConstants;
040: import org.jboss.mx.modelmbean.ModelMBeanInvoker;
041:
042: /**
043: * DelegatingPersistenceManager.
044: *
045: * An XMBean Persistence Manager that delegates to an external
046: * MBean-controlled implementation the actual persistence of
047: * MBean attributes.
048: *
049: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
050: * @version $Revision: 57200 $
051: */
052: public class DelegatingPersistenceManager implements PersistenceManager {
053: // Private Data --------------------------------------------------
054:
055: private static Logger log = Logger
056: .getLogger(DelegatingPersistenceManager.class);
057:
058: /** where calls are delegated */
059: private AttributePersistenceManager persistor;
060:
061: /** the associated name to use at load/store */
062: private String persistName;
063:
064: /** load operation triggers save, so we want to prevent this */
065: private boolean isLoading;
066:
067: // Constructors --------------------------------------------------
068:
069: public DelegatingPersistenceManager() {
070: // emtpy
071: }
072:
073: // PersistenceManager overrides ----------------------------------
074:
075: /**
076: * Called initialy when the XMBean is constructed in order
077: * to load and set the attributes of the MBean,
078: * if their persistent image exists.
079: */
080: public void load(ModelMBeanInvoker invoker, MBeanInfo metadata)
081: throws MBeanException {
082: if (this .persistor == null) {
083: // lazy initialization on first load - couldn't do
084: // otherwise with this PersistenceManager interface
085: init(invoker, metadata);
086: }
087:
088: if (log.isDebugEnabled())
089: log.debug("load() called for: '" + this .persistName + "'");
090:
091: AttributeList attrs = null;
092:
093: // load from the persistor
094: try {
095: attrs = this .persistor.load(this .persistName);
096: } catch (Exception e) {
097: // problem while loading
098: log.warn("Caught exception while loading", e);
099: throw new MBeanException(e);
100: }
101:
102: if (attrs != null) {
103: // a persistent attribute list image was found so restore it
104:
105: try {
106: // need to mark we are loading because setting the attributes
107: // will triger a store() that should be ignored
108: setIsLoading(true);
109:
110: if (log.isDebugEnabled())
111: log.debug("loading attributes: " + attrs);
112: invoker.setAttributes(attrs);
113: } finally {
114: setIsLoading(false);
115: }
116: } else {
117: if (log.isDebugEnabled())
118: log.debug("No attributes to load");
119: }
120: }
121:
122: /**
123: * store() is triggered by the PersistenceInterceptor based
124: * on the persistence policy.
125: *
126: * In the simple case, it will be called for every attribute set.
127: *
128: * store() will save *all* attributes that:
129: * (a) are writable (so we can re-load them later on)
130: * (b) their value exists in the ATTRIBUTE_VALUE descriptor
131: * (c) are not marked as PM_NEVER
132: */
133: public void store(MBeanInfo metadata) throws MBeanException {
134: if (this .persistor == null) {
135: // shouln't happen
136: throw new MBeanException(new Exception(
137: "store() called before instance initialized"));
138: }
139:
140: // while loading store() is triggered
141: if (isLoading()) {
142: return; // ignore call
143: } else {
144: if (log.isDebugEnabled())
145: log.debug("store() called for: '" + this .persistName
146: + "'");
147:
148: // placehold for attributes to be persisted
149: AttributeList attributes = new AttributeList();
150:
151: // iterate over all attributes in metadata
152: MBeanAttributeInfo[] attrs = metadata.getAttributes();
153:
154: if (log.isDebugEnabled() && attrs.length > 0)
155: log.debug("store() --- ModelMBeanAttributeInfo[] ---");
156:
157: for (int i = 0; i < attrs.length; i++) {
158: /// for each (a) writable attribute (b) in the model cache,
159: // create a new Attribute object and add it to the collection.
160: ModelMBeanAttributeInfo attributeInfo = (ModelMBeanAttributeInfo) attrs[i];
161:
162: if (log.isDebugEnabled())
163: log.debug(" attr (#" + i + ") - " + attributeInfo);
164:
165: if (attributeInfo.isWritable()) {
166: Descriptor attrDesc = attributeInfo.getDescriptor();
167:
168: Object name = attrDesc
169: .getFieldValue(ModelMBeanConstants.NAME);
170: Object value = attrDesc
171: .getFieldValue(ModelMBeanConstants.ATTRIBUTE_VALUE);
172: Object updated = attrDesc
173: .getFieldValue(ModelMBeanConstants.LAST_UPDATED_TIME_STAMP2);
174: Object pPolicy = attrDesc
175: .getFieldValue(ModelMBeanConstants.PERSIST_POLICY);
176:
177: boolean noPersistPolicy = pPolicy != null
178: && ((String) pPolicy)
179: .equalsIgnoreCase(ModelMBeanConstants.PP_NEVER) ? true
180: : false;
181:
182: // to persist the attribute:
183: //
184: // (a) must be writable (so we can re-load it later on)
185: // (b) its value must be set in the ATTRIBUTE_VALUE descriptor
186: // (c) must not be marked as PM_NEVER
187: if (updated != null && noPersistPolicy == false) {
188: attributes.add(new Attribute(name.toString(),
189: value));
190: }
191: }
192: }
193: try {
194: if (!attributes.isEmpty()) {
195:
196: if (log.isDebugEnabled())
197: log.debug("calling persistor.store("
198: + this .persistName + ") attrs="
199: + attributes);
200:
201: persistor.store(this .persistName, attributes);
202: } else {
203: if (log.isDebugEnabled())
204: log.debug("nothing to persist");
205: }
206: } catch (Exception e) {
207: log.warn("cought exception during store()", e);
208: }
209: }
210: }
211:
212: // Protected -----------------------------------------------------
213:
214: /**
215: * Lazy initialization
216: *
217: * Gets the external persistor to use and decides on the
218: * persistName to use for this MBean load()/store() calls.
219: */
220: protected void init(ModelMBeanInvoker invoker, MBeanInfo metadata)
221: throws MBeanException {
222: Descriptor desc = ((ModelMBeanInfo) metadata)
223: .getMBeanDescriptor();
224:
225: if (log.isDebugEnabled()) {
226: log.debug("init() --- ModelMBeanInfo Descriptor --- ");
227: log.debug(desc);
228: }
229:
230: // Decide what to use as a persistent name (id) for this MBean
231:
232: // If the user has explicitly specified a "persistName", use it
233: String name = (String) desc
234: .getFieldValue(ModelMBeanConstants.PERSIST_NAME);
235:
236: if (name != null) {
237: this .persistName = name;
238: } else {
239: // Try to find ObjectName stored (or lets say hidden) there by ModelMBeanInvoker
240: ObjectName objectName = (ObjectName) desc
241: .getFieldValue(ModelMBeanConstants.OBJECT_NAME);
242:
243: if (objectName != null) {
244: this .persistName = objectName.toString();
245: } else {
246: throw new MBeanException(new Exception(
247: "must specify a value for: "
248: + ModelMBeanConstants.PERSIST_NAME));
249: }
250: }
251:
252: if (log.isDebugEnabled())
253: log.debug("chosen persistent id: '" + this .persistName
254: + "'");
255:
256: // get the name of the MBean factory service that creates
257: // the AttributePersistenceManager implementation
258: String service = (String) desc
259: .getFieldValue(ModelMBeanConstants.DELEGATING_PM_SERVICE_DESCRIPTOR);
260: if (service == null) {
261: // use default
262: service = ModelMBeanConstants.DELEGATING_PM_SERVICE_DEFAULT_VALUE;
263: }
264:
265: // get the name of the operation to call on the MBean service
266: String operation = (String) desc
267: .getFieldValue(ModelMBeanConstants.DELEGATING_PM_OPERATION_DESCRIPTOR);
268: if (operation == null) {
269: // use default
270: operation = ModelMBeanConstants.DELEGATING_PM_OPERATION_DEFAULT_VALUE;
271: }
272:
273: // Create the AttributePersistenceManager
274: try {
275: ObjectName objName = new ObjectName(service);
276: MBeanServer server = invoker.getServer();
277:
278: this .persistor = (AttributePersistenceManager) server
279: .invoke(objName, operation, new Object[] {},
280: new String[] {});
281: if (this .persistor == null) {
282: throw new MBeanException(new NullPointerException(
283: "null AttributePersistenceManager from: "
284: + service));
285: }
286: } catch (MalformedObjectNameException e) {
287: throw new MBeanException(e, "not a valid ObjectName: "
288: + service);
289: } catch (InstanceNotFoundException e) {
290: throw new MBeanException(e, "service not registered: "
291: + service);
292: } catch (ReflectionException e) {
293: throw new MBeanException(e);
294: }
295:
296: if (log.isDebugEnabled())
297: log.debug("using AttributePersistenceManager: "
298: + this .persistor.getClass().getName());
299: }
300:
301: /**
302: * Check if we are loading state
303: */
304: protected boolean isLoading() {
305: return isLoading;
306: }
307:
308: /**
309: * Set the loading status
310: *
311: * @param newIsLoading
312: */
313: protected void setIsLoading(boolean newIsLoading) {
314: isLoading = newIsLoading;
315: }
316:
317: }
|