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.test.jmx.xmbean;
023:
024: import java.beans.PropertyEditor;
025: import java.io.BufferedReader;
026: import java.io.File;
027: import java.io.FileInputStream;
028: import java.io.FileOutputStream;
029: import java.io.IOException;
030: import java.io.InputStreamReader;
031: import javax.management.Attribute;
032: import javax.management.AttributeList;
033: import javax.management.Descriptor;
034: import javax.management.MBeanAttributeInfo;
035: import javax.management.MBeanException;
036: import javax.management.MBeanInfo;
037: import javax.management.modelmbean.ModelMBeanAttributeInfo;
038: import javax.management.modelmbean.ModelMBeanInfo;
039:
040: import org.jboss.mx.metadata.MBeanInfoConversion;
041: import org.jboss.mx.modelmbean.ModelMBeanConstants;
042: import org.jboss.mx.modelmbean.ModelMBeanInvoker;
043: import org.jboss.mx.persistence.PersistenceManager;
044:
045: import org.jboss.logging.Logger;
046: import org.jboss.util.StringPropertyReplacer;
047: import org.jboss.util.propertyeditor.PropertyEditors;
048:
049: /**
050: * XML File Persistence Manager. <p>
051: *
052: * Persists the MBean to the file system using an XML file.
053: *
054: * The file has to follow this (simple) DTD:
055: * <pre>
056: * <!ELEMENT attribute (#PCDATA)>
057: * <!ATTLIST attribute
058: * name CDATA #REQUIRED
059: * type CDATA #REQUIRED
060: * >
061: * <!ELEMENT attributes (attribute*)>
062: * </pre>
063: *
064: * @author Heiko.Rupp@cellent.de
065: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>.
066: * @version $Revision: 57211 $
067: */
068: public class XMLFilePersistenceManager extends Object implements
069: PersistenceManager {
070: protected static Logger log = Logger
071: .getLogger(XMLFilePersistenceManager.class);
072: /** A flag set to true to prevent attribute updates from within load
073: * triggering stores.
074: */
075: protected boolean isLoading;
076:
077: // Constructors --------------------------------------------------
078:
079: public XMLFilePersistenceManager() {
080: super ();
081: }
082:
083: // Public --------------------------------------------------------
084:
085: /**
086: * Loads the attributes from the given file
087: *
088: * @param mbean to store to
089: * @param metadata with file location etc.
090: * @exception MBeanException
091: */
092: public void load(ModelMBeanInvoker mbean, MBeanInfo metadata)
093: throws MBeanException {
094: log.debug("load, resource:" + mbean.getResource());
095:
096: if (metadata == null) {
097: return;
098: }
099: if (log.isTraceEnabled())
100: log.trace("metadata: " + metadata);
101:
102: File storeFile = getStoreFile(metadata, false);
103: if (storeFile == null) {
104: return;
105: }
106:
107: try {
108: AttributeList attributes = new AttributeList();
109:
110: FileInputStream fis = new FileInputStream(storeFile);
111: BufferedReader buf = new BufferedReader(
112: new InputStreamReader(fis));
113:
114: String line, line2;
115: while ((line = buf.readLine()) != null) {
116: log.trace("Line: " + line);
117: if (line.equals("<attributes>"))
118: continue;
119: if (line.equals("</attributes>"))
120: continue;
121:
122: // trim leading spaces
123: line = line.substring(line.indexOf("<"));
124:
125: if (!line.startsWith("<attribute")) {
126: log.warn("Unknown line, skipping " + line);
127: continue;
128: }
129:
130: // read attribute name
131: int pos = line.indexOf("name=\"") + 6; // skip name="
132: line2 = line.substring(pos);
133: int pos2 = line2.indexOf("\"");
134: String name = line2.substring(0, pos2);
135: log.debug("name: " + name);
136:
137: // read attribute type
138: pos = line.indexOf("type=\"") + 6; // skip type="
139: line2 = line.substring(pos);
140: pos2 = line2.indexOf("\"");
141: String type = line2.substring(0, pos2);
142: log.debug("type: " + type);
143:
144: // read attribute value
145: pos = line.indexOf(">");
146: pos2 = line.lastIndexOf("<");
147: String value = line.substring(pos + 1, pos2);
148: log.debug("value :" + value);
149:
150: Object oVal = convert(value, type);
151: Attribute att = new Attribute(name, oVal);
152: attributes.add(att);
153:
154: } // while
155:
156: mbean.setAttributes(attributes);
157: } catch (Exception e) {
158: log.error("Error loading MBean state", e);
159: }
160: setIsLoading(false);
161: }
162:
163: /** What we need to get here is 1) the persist location, and 2) the entire
164: * contents of the mbean. #2 contains the entire contents (state) of the
165: * model object, as well as the meta data that the mbean provides.
166: * As such, serializing this (MBeanInfo) object (brute force) in effect
167: * serializes the model as well.
168: *
169: * @param metadata
170: * @exception MBeanException
171: */
172: public void store(MBeanInfo metadata) throws MBeanException {
173: if (isLoading()) {
174: return;
175: }
176:
177: ModelMBeanInfo mmeta = MBeanInfoConversion.toModelMBeanInfo(
178: metadata, true);
179:
180: log.debug("store");
181: if (log.isTraceEnabled())
182: log.trace("metadata: " + metadata);
183: File storeFile = getStoreFile(metadata, true);
184: if (storeFile == null) {
185: return;
186: }
187:
188: try {
189: log
190: .debug("Storing to file: "
191: + storeFile.getAbsolutePath());
192: FileOutputStream fos = new FileOutputStream(storeFile);
193: MBeanAttributeInfo[] mais = mmeta.getAttributes();
194: StringBuffer buf = new StringBuffer();
195: buf.append("<attributes>\n");
196: for (int i = 0; i < mais.length; i++) {
197: ModelMBeanAttributeInfo mai = (ModelMBeanAttributeInfo) mais[i];
198: buf.append(" <attribute name=\"" + mai.getName()
199: + "\" ");
200: buf.append("type=\"" + mai.getType() + "\">");
201: log.debug("Trying to load " + mai.getName());
202: Descriptor aDesc = mai.getDescriptor();
203: if (aDesc == null)
204: throw new Exception("aDesc is null");
205: log.debug(aDesc.toString());
206: Object att = aDesc
207: .getFieldValue(ModelMBeanConstants.ATTRIBUTE_VALUE);
208: if (att != null)
209: buf.append(att.toString());
210: else
211: log.warn("att was null");
212: buf.append("</attribute>\n");
213: }
214: buf.append("</attributes>");
215: log.trace(buf.toString());
216: fos.write(buf.toString().getBytes());
217: fos.close();
218: } catch (Exception e) {
219: e.printStackTrace();
220: throw new MBeanException(e, "Error in persisting MBean.");
221: }
222: }
223:
224: // Protected -----------------------------------------------------
225:
226: protected boolean isLoading() {
227: return isLoading;
228: }
229:
230: protected void setIsLoading(boolean newIsLoading) {
231: isLoading = newIsLoading;
232: }
233:
234: /**
235: * Obtain the store location from the ModelMBean Descriptor.
236: * If the file name does not end on ".xml", it will be converted
237: * to do so.
238: * @param metadata
239: * @param createFile
240: * @return
241: * @throws MBeanException
242: */
243: protected File getStoreFile(MBeanInfo metadata, boolean createFile)
244: throws MBeanException {
245: Descriptor d = ((ModelMBeanInfo) metadata).getMBeanDescriptor();
246: String dirPath = (String) d
247: .getFieldValue(ModelMBeanConstants.PERSIST_LOCATION);
248: String file = (String) d
249: .getFieldValue(ModelMBeanConstants.PERSIST_NAME);
250: if (dirPath == null) {
251: log.debug("No " + ModelMBeanConstants.PERSIST_LOCATION
252: + " descriptor value found, using '.'");
253: dirPath = ".";
254: }
255: if (file == null) {
256: log.debug("No " + ModelMBeanConstants.PERSIST_NAME
257: + " descriptor value found");
258: return null;
259: }
260:
261: dirPath = StringPropertyReplacer.replaceProperties(dirPath);
262: file = StringPropertyReplacer.replaceProperties(file);
263: // tack on .xml if not there
264: if (!file.endsWith(".xml"))
265: file = file + ".xml";
266: File dir = new File(dirPath);
267: File storeFile = new File(dir, file);
268: boolean exists = storeFile.exists();
269: log.debug("Store file is: " + storeFile.getAbsolutePath());
270: if (exists == false && createFile == true) {
271: dir.mkdirs();
272: try {
273: storeFile.createNewFile();
274: } catch (IOException e) {
275: throw new MBeanException(e,
276: "Failed to create store file");
277: }
278: } else if (exists == false) {
279: storeFile = null;
280: }
281: return storeFile;
282: }
283:
284: /**
285: * Convert val into an Object of type type -- same as in twiddle.setCommand
286: * @param val The given value
287: * @param oType the wanted return type
288: * @return the value in the correct representation
289: * @throws Exception various :)
290: */
291: private Object convert(String val, String oType) throws Exception {
292: PropertyEditor editor = PropertyEditors.getEditor(oType);
293: editor.setAsText(val);
294: return editor.getValue();
295: }
296: }
|