0001: /*
0002: * MCS Media Computer Software Copyright (c) 2005 by MCS
0003: * -------------------------------------- Created on 23.04.2005 by w.klaas
0004: *
0005: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
0006: * use this file except in compliance with the License. You may obtain a copy of
0007: * the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
0013: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
0014: * License for the specific language governing permissions and limitations under
0015: * the License.
0016: */
0017: package de.mcs.jmeasurement;
0018:
0019: import java.io.File;
0020: import java.io.FileInputStream;
0021: import java.io.FileNotFoundException;
0022: import java.io.FileOutputStream;
0023: import java.io.IOException;
0024: import java.io.InputStream;
0025: import java.io.ObjectInputStream;
0026: import java.io.ObjectOutputStream;
0027: import java.io.OutputStream;
0028: import java.io.PrintWriter;
0029: import java.io.Writer;
0030: import java.lang.management.ManagementFactory;
0031: import java.lang.reflect.Proxy;
0032: import java.text.SimpleDateFormat;
0033: import java.util.ArrayList;
0034: import java.util.Arrays;
0035: import java.util.Date;
0036: import java.util.HashMap;
0037: import java.util.Iterator;
0038: import java.util.Map;
0039: import java.util.Timer;
0040: import java.util.TimerTask;
0041: import java.util.Map.Entry;
0042:
0043: import javax.management.InstanceAlreadyExistsException;
0044: import javax.management.MBeanRegistrationException;
0045: import javax.management.MBeanServer;
0046: import javax.management.MalformedObjectNameException;
0047: import javax.management.NotCompliantMBeanException;
0048: import javax.management.ObjectName;
0049: import javax.xml.parsers.SAXParser;
0050: import javax.xml.parsers.SAXParserFactory;
0051:
0052: import org.xml.sax.InputSource;
0053: import org.xml.sax.SAXException;
0054: import org.xml.sax.helpers.AttributesImpl;
0055: import org.xml.sax.helpers.DefaultHandler;
0056:
0057: import com.megginson.sax.DataWriter;
0058:
0059: import de.mcs.jmeasurement.jmx.JmxConfig;
0060: import de.mcs.jmeasurement.jmx.JmxConfigMBean;
0061: import de.mcs.jmeasurement.jmx.JmxPointsImpl;
0062: import de.mcs.jmeasurement.jmx.JmxPointsMXBean;
0063: import de.mcs.jmeasurement.proxy.ProxyMonitor;
0064: import de.mcs.jmeasurement.renderer.DefaultTextRenderer;
0065: import de.mcs.jmeasurement.renderer.MeasureDataRenderer;
0066: import de.mcs.jmeasurement.renderer.MeasureDataRendererColumnHeader;
0067: import de.mcs.jmeasurement.renderer.MeasureDataRendererPage;
0068: import de.mcs.jmeasurement.renderer.MeasureDataRendererSnapshot;
0069:
0070: /**
0071: * This is the main entry point into the measurement system.
0072: *
0073: * @author w.klaas
0074: */
0075: public final class MeasureFactory {
0076:
0077: /** default buffer size. */
0078: private static final int DEFAULT_BUFFER_SIZE = 1024;
0079:
0080: /** default text renderer page size. */
0081: private static final int DEFAULT_TEXT_RENDERER_PAGE_SIZE = 80;
0082:
0083: /** default text renderer field sizes. */
0084: private static final int[] DEFAULT_TEXT_RENDERER_FIELD_SIZES = new int[] {
0085: 40, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12 };
0086:
0087: /** to prevent instancing of this static class. */
0088: private MeasureFactory() {
0089: }
0090:
0091: /** map with all measure points. */
0092: private static HashMap<String, MeasurePoint> measurePoints = new HashMap<String, MeasurePoint>();
0093:
0094: /** map with all snapshot objects. */
0095: private static ArrayList<SnapShot> snapShots = new ArrayList<SnapShot>();
0096:
0097: /** priority of this factory. */
0098: private static int priority = 0;
0099:
0100: /** master switch of this factory. */
0101: // private static boolean enable = true;
0102: /** the null monitor, whenever it will be needed. */
0103: private static NullMonitor nullMonitor = new NullMonitor();
0104:
0105: /** call back function for every measure point. */
0106: private static MeasureDataCallback measureDataCallback = null;
0107:
0108: /** constants for xml writing and reading. */
0109: static final String XMLNODE_ROOT = "JMeasurement";
0110:
0111: /** constants for xml writing and reading. */
0112: static final String XMLATT_APPNAME = "applicationname";
0113:
0114: /** constants for xml writing and reading. */
0115: static final String XMLATT_CREATED = "created";
0116:
0117: /** constants for xml writing and reading. */
0118: static final String XMLNODE_POINT = "measurepoint";
0119:
0120: /** constants for xml writing and reading. */
0121: static final String XMLATT_NAME = "name";
0122:
0123: /** constants for xml writing and reading. */
0124: static final String XMLATT_CLASS = "class";
0125:
0126: /** constants for xml writing and reading. */
0127: static final String XMLNODE_MEASUREPOINTS = "measurepoints";
0128:
0129: /** constants for xml writing and reading. */
0130: static final String XMLNODE_SNAPSHOTS = "snapshots";
0131:
0132: /** constants for xml writing and reading. */
0133: static final String XMLNODE_SNAPSHOT = "snapshot";
0134:
0135: /** constants for xml writing and reading. */
0136: static final String XMLATT_VALUE = "VALUE";
0137:
0138: /** constants for xml writing and reading. */
0139: static final String XMLNODE_PROPERTY = "property";
0140:
0141: /**
0142: * for automatic memory savings, all not actually used MeasurePoints will be
0143: * referenced here.
0144: */
0145: private static ArrayList<String> savePoints;
0146:
0147: /** the timer for background processing. */
0148: private static Timer backgroundtimer;
0149:
0150: /** configuration class. */
0151: private static JMConfig config = new JMConfig();
0152:
0153: /**
0154: * This class is the backgorund processing class for the Measure factory.
0155: *
0156: * @author w.klaas
0157: * @since 0.68
0158: */
0159: static class MeasureTask extends TimerTask {
0160:
0161: /** make automatic snapshots. */
0162: private boolean autoSnapshot;
0163:
0164: /** save memory, store measurepoints and snapshots into the filesystem. */
0165: private boolean memorySavings;
0166:
0167: /** where to save the data. */
0168: private File workingPath;
0169:
0170: /** idle time of a point, before it will be saved. */
0171: private long idleTime;
0172:
0173: /** needed for date processing. */
0174: private SimpleDateFormat dformat = new SimpleDateFormat(
0175: "yyyyMMddHHmmss");
0176:
0177: /**
0178: * Constructor of this background task. See options
0179: * {@link MeasureFactory#setOption(String, String)}
0180: *
0181: * @param aOptions
0182: * options to set.
0183: */
0184: public MeasureTask(final JMConfig aOptions) {
0185: autoSnapshot = aOptions
0186: .getBoolean(JMConfig.OPTION_ENABLE_AUTOSNAPSHOT);
0187: memorySavings = aOptions
0188: .getBoolean(JMConfig.OPTION_ENABLE_MEMORY_SAVINGS);
0189: workingPath = new File(aOptions
0190: .getProperty(JMConfig.OPTION_WORKINGPATH));
0191: idleTime = aOptions.getLong(JMConfig.OPTION_POINT_IDLETIME);
0192: }
0193:
0194: /**
0195: * processing.
0196: */
0197: @Override
0198: public void run() {
0199: if (autoSnapshot) {
0200: makeSnapShot();
0201: }
0202: if (memorySavings) {
0203: saveMemory();
0204: }
0205: }
0206:
0207: /**
0208: * try to save memory by saving all availble snapshots and all no longer
0209: * needed Measurepoints to filesystem.
0210: */
0211: private void saveMemory() {
0212: // first saving all snapshots
0213: for (Iterator iter = snapShots.iterator(); iter.hasNext();) {
0214: SnapShot snapshot = (SnapShot) iter.next();
0215: try {
0216: saveSnapShot(snapshot, new File(workingPath,
0217: snapshot.getName() + ".xml"));
0218: iter.remove();
0219: } catch (FileNotFoundException e) {
0220: e.printStackTrace();
0221: } catch (SAXException e) {
0222: e.printStackTrace();
0223: } catch (IOException e) {
0224: e.printStackTrace();
0225: }
0226: }
0227: // now testing all measurepoints, if there are open monitors and if
0228: // the measure point was used last time
0229: ArrayList<String> toSave = new ArrayList<String>();
0230:
0231: for (Iterator iter = measurePoints.keySet().iterator(); iter
0232: .hasNext();) {
0233: String name = (String) iter.next();
0234: MeasurePoint point = measurePoints.get(name);
0235: Date lastActivation;
0236: try {
0237: lastActivation = point
0238: .getData(
0239: DefaultMeasurePoint.DATA_KEY_LAST_ACTIVATION)
0240: .getAsDate();
0241: if (!point.hasActiveMonitors()
0242: && (lastActivation.before(new Date(
0243: new Date().getTime() - idleTime)))) {
0244: // System.out.println("saving measurepoint");
0245: toSave.add(name);
0246: }
0247: } catch (InvalidMeasureDataTypeException e) {
0248: // TODO Auto-generated catch block
0249: e.printStackTrace();
0250: }
0251: }
0252: for (String name : toSave) {
0253: MeasurePoint point = measurePoints.get(name);
0254: synchronized (measurePoints) {
0255: ObjectOutputStream oout;
0256: try {
0257: oout = new ObjectOutputStream(
0258: new FileOutputStream(new File(
0259: workingPath, name)));
0260: oout.writeObject(point);
0261: oout.close();
0262: if (null == savePoints) {
0263: savePoints = new ArrayList<String>();
0264: }
0265: savePoints.add(name);
0266: measurePoints.remove(name);
0267: } catch (FileNotFoundException e) {
0268: // TODO Auto-generated catch block
0269: e.printStackTrace();
0270: } catch (IOException e) {
0271: // TODO Auto-generated catch block
0272: e.printStackTrace();
0273: }
0274: }
0275: }
0276: }
0277:
0278: /**
0279: * take a snapshot.
0280: */
0281: private void makeSnapShot() {
0282: String snapShotName = "snapshot_"
0283: + dformat.format(new Date());
0284: MeasureFactory.takeSnapshot(snapShotName);
0285: }
0286: }
0287:
0288: /**
0289: * load configuration from jmconfig.properties file in the classpath.
0290: *
0291: * @return <code>true</code> if the file could be loaded, otherwise
0292: * <code>false</code>.
0293: */
0294: public static boolean configure() {
0295: if (config == null) {
0296: config = new JMConfig();
0297: }
0298: return config.configure();
0299: }
0300:
0301: /**
0302: * load configuration from the given properties file.
0303: *
0304: * @param jmConfig
0305: * the config file to load.
0306: * @return <code>true</code> if the file could be loaded, otherwise
0307: * <code>false</code>.
0308: */
0309: public static boolean configure(final File jmConfig) {
0310: if (config == null) {
0311: config = new JMConfig();
0312: }
0313: return config.configure(jmConfig);
0314: }
0315:
0316: /**
0317: * Getting a new monitor for the measurement point pointName. If the point
0318: * doesn't exists, it wil be created.
0319: *
0320: * @param pointName
0321: * name of the measurement point to use.
0322: * @return Monitor
0323: */
0324: public static Monitor getMonitor(final String pointName) {
0325: MeasurePoint point;
0326: point = getMeasurePoint(pointName);
0327: Monitor monitor;
0328: // if (enable && (point.getPriority() >= priority)) {
0329: if (config.isEnableMeasurement()
0330: && (point.getPriority() >= priority)) {
0331: monitor = point.getMonitor();
0332: } else {
0333: monitor = nullMonitor;
0334: }
0335: return monitor;
0336: }
0337:
0338: /**
0339: * getting the desired measurement point. If it doesn't exists it will be
0340: * created.
0341: *
0342: * @param pointName
0343: * name of the desired point (fully qualified)
0344: * @return MeasurePoint the desired MeasurePoint
0345: */
0346: public static MeasurePoint getMeasurePoint(final String pointName) {
0347: MeasurePoint point = null;
0348: synchronized (measurePoints) {
0349: if (measurePoints.containsKey(pointName)) {
0350: point = (MeasurePoint) measurePoints.get(pointName);
0351: } else {
0352: if ((null != savePoints)
0353: && savePoints.contains(pointName)) {
0354: File pointFile = new File(config
0355: .getProperty(JMConfig.OPTION_WORKINGPATH),
0356: pointName);
0357: if (pointFile.exists()) {
0358: ObjectInputStream oin;
0359: try {
0360: oin = new ObjectInputStream(
0361: new FileInputStream(pointFile));
0362: point = (MeasurePoint) oin.readObject();
0363: oin.close();
0364: oin = null;
0365: pointFile.delete();
0366: register(point);
0367: } catch (FileNotFoundException e) {
0368: e.printStackTrace();
0369: } catch (IOException e) {
0370: e.printStackTrace();
0371: } catch (ClassNotFoundException e) {
0372: e.printStackTrace();
0373: }
0374: }
0375: savePoints.remove(pointName);
0376: if (point == null) {
0377: point = getMeasurePoint(pointName);
0378: }
0379: } else {
0380: point = new DefaultMeasurePoint(pointName, config);
0381: register(point);
0382: }
0383: }
0384: }
0385: return point;
0386: }
0387:
0388: /**
0389: * Adding a new measurepoint to the point registration.
0390: *
0391: * @param measurePoint
0392: * measure point to add
0393: */
0394: private static void register(final MeasurePoint measurePoint) {
0395: measurePoint.setMeasureDataCallback(measureDataCallback);
0396: if (measurePoint instanceof DefaultMeasurePoint) {
0397: DefaultMeasurePoint defaultMeasurePoint = (DefaultMeasurePoint) measurePoint;
0398: defaultMeasurePoint.setConfig(config);
0399: }
0400: measurePoints.put(measurePoint.getName(), measurePoint);
0401: }
0402:
0403: /**
0404: * getting an array of measurement points. The pointname is a regular
0405: * expression of the desired points.
0406: *
0407: * @param pointName
0408: * regular expression of the desired point names (or null for all
0409: * points)
0410: * @return MeasurePoint[] the desired MeasurePoints
0411: */
0412: public static MeasurePoint[] getMeasurePoints(final String pointName) {
0413: ArrayList<MeasurePoint> points = new ArrayList<MeasurePoint>();
0414: String[] names = getMeasurePointNames(pointName);
0415: Arrays.sort(names);
0416: for (int i = 0; i < names.length; i++) {
0417: String string = names[i];
0418: MeasurePoint point = getMeasurePoint(string);
0419: points.add(point);
0420: }
0421: return (MeasurePoint[]) points.toArray(new MeasurePoint[0]);
0422: }
0423:
0424: /**
0425: * getting an array of measurement point names. The pointname is a regular
0426: * expression of the desired points.
0427: *
0428: * @param pointName
0429: * regular expression of the desired point names (or null for all
0430: * points)
0431: * @return String[] the desired MeasurePointNames
0432: */
0433: public static String[] getMeasurePointNames(final String pointName) {
0434: ArrayList<String> points = new ArrayList<String>();
0435: String regexPointName = pointName;
0436: if (null == regexPointName) {
0437: regexPointName = ".*";
0438: }
0439: String[] names = (String[]) measurePoints.keySet().toArray(
0440: new String[0]);
0441: Arrays.sort(names);
0442: for (int i = 0; i < names.length; i++) {
0443: String string = names[i];
0444: if (string.matches(regexPointName)) {
0445: points.add(string);
0446: }
0447: }
0448: if (null != savePoints) {
0449: names = savePoints.toArray(new String[0]);
0450: Arrays.sort(names);
0451: for (int i = 0; i < names.length; i++) {
0452: String string = names[i];
0453: if (string.matches(regexPointName)) {
0454: points.add(string);
0455: }
0456: }
0457: }
0458: return (String[]) points.toArray(new String[0]);
0459: }
0460:
0461: /**
0462: * Getting a new monitor for the measurement point pointName and starting
0463: * this monitor. If the point doesn't exists, it wil be created.
0464: *
0465: * @param pointName
0466: * name of the measurement point to use.
0467: * @return Monitor
0468: */
0469: public static Monitor start(final String pointName) {
0470: Monitor monitor = getMonitor(pointName);
0471: monitor.start();
0472: return monitor;
0473: }
0474:
0475: /**
0476: * This is the standard report feature with all Points as an text Report.
0477: *
0478: * @return the string representation of this measurement factory
0479: */
0480: public static String asString() {
0481: try {
0482: return getReport(new DefaultTextRenderer(
0483: DEFAULT_TEXT_RENDERER_PAGE_SIZE,
0484: DEFAULT_TEXT_RENDERER_FIELD_SIZES));
0485: } catch (RendererMustNotBeNullException e) {
0486: e.printStackTrace();
0487: }
0488: return null;
0489: }
0490:
0491: /**
0492: * Return the actual priority setting of the factory.
0493: *
0494: * @return Returns the priority.
0495: */
0496: public static int getPriority() {
0497: return priority;
0498: }
0499:
0500: /**
0501: * Setting the actual priority of the factory.
0502: *
0503: * @param aPriority
0504: * The priority to set.
0505: */
0506: public static void setPriority(final int aPriority) {
0507: MeasureFactory.priority = aPriority;
0508: }
0509:
0510: /**
0511: * Getting a rendered report of the measure data. All points be evaluating.
0512: * To get some report the renderer must be given. If not,
0513: * <code>RendererMustNotBeNullException</code> will be thrown.
0514: *
0515: * @param renderer
0516: * the renderer to use for this report
0517: * @return a string with the report
0518: * @throws RendererMustNotBeNullException
0519: * thrown, if the renderer is not set.
0520: */
0521: public static String getReport(final MeasureDataRenderer renderer)
0522: throws RendererMustNotBeNullException {
0523: return getReport(".*", renderer);
0524: }
0525:
0526: /**
0527: * Getting a rendered report of the measure data. The points in the
0528: * requested report will be evaluating with the point string. To get some
0529: * report the renderer must be given. If not,
0530: * <code>RendererMustNotBeNullException</code> will be thrown.
0531: *
0532: * @param pointname
0533: * regular expression to match the point names (or null for all
0534: * points)
0535: * @param renderer
0536: * the renderer to use for this report
0537: * @return a string with the report
0538: * @throws RendererMustNotBeNullException
0539: * thrown, if the renderer is not set.
0540: */
0541: public static String getReport(final String pointname,
0542: final MeasureDataRenderer renderer)
0543: throws RendererMustNotBeNullException {
0544: String regexPointName = pointname;
0545: if (renderer == null) {
0546: throw new RendererMustNotBeNullException(
0547: "renderer must not be null");
0548: }
0549: if (null == regexPointName) {
0550: regexPointName = ".*";
0551: }
0552: MeasurePoint[] points = getMeasurePoints(pointname);
0553: StringBuffer stringBuffer = new StringBuffer(
0554: DEFAULT_BUFFER_SIZE);
0555: if (renderer instanceof MeasureDataRendererPage) {
0556: stringBuffer.append(((MeasureDataRendererPage) renderer)
0557: .getReportHeader());
0558: stringBuffer.append(((MeasureDataRendererPage) renderer)
0559: .beginPage());
0560: }
0561: if (renderer instanceof MeasureDataRendererColumnHeader) {
0562: stringBuffer
0563: .append(((MeasureDataRendererColumnHeader) renderer)
0564: .getColumnHeaderAsString(new DefaultMeasurePoint(
0565: "empty", config)));
0566: }
0567: for (int i = 0; i < points.length; i++) {
0568: if (points[i].getPriority() >= priority) {
0569: stringBuffer.append(renderer.getDataAsString(points[i],
0570: ""));
0571: }
0572: }
0573: if (renderer instanceof MeasureDataRendererPage) {
0574: stringBuffer.append(((MeasureDataRendererPage) renderer)
0575: .endPage());
0576: }
0577: if ((snapShots.size() > 0)
0578: && (renderer instanceof MeasureDataRendererSnapshot)) {
0579: String[] snapShotsNames = getSnapShotNames();
0580: for (int i = 0; i < snapShotsNames.length; i++) {
0581: String snapShotname = snapShotsNames[i];
0582: SnapShot snapShot = getSnapShot(snapShotname);
0583: stringBuffer.append(snapShot.getReport(pointname,
0584: renderer, priority));
0585: }
0586: }
0587: if (renderer instanceof MeasureDataRendererPage) {
0588: stringBuffer.append(((MeasureDataRendererPage) renderer)
0589: .getReportFooter());
0590: }
0591:
0592: return stringBuffer.toString();
0593: }
0594:
0595: /**
0596: * Getting a rendered report of the measure data. The points in the
0597: * requested report will be evaluating with the point string. To get some
0598: * report the renderer must be given. If not,
0599: * <code>RendererMustNotBeNullException</code> will be thrown.
0600: *
0601: * @param pointname
0602: * regular expression to match the point names (or null for all
0603: * points)
0604: * @param renderer
0605: * the renderer to use for this report
0606: * @param output
0607: * the writer to output the report
0608: * @throws RendererMustNotBeNullException
0609: * thrown, if the renderer is not set.
0610: * @throws IOException
0611: * if something goes wrong with the writer IO operation.
0612: */
0613: public static void getReport(final String pointname,
0614: final MeasureDataRenderer renderer, final Writer output)
0615: throws RendererMustNotBeNullException, IOException {
0616: String regexPointName = pointname;
0617: if (renderer == null) {
0618: throw new RendererMustNotBeNullException(
0619: "renderer must not be null");
0620: }
0621: if (null == regexPointName) {
0622: regexPointName = ".*";
0623: }
0624: MeasurePoint[] points = getMeasurePoints(pointname);
0625: if (renderer instanceof MeasureDataRendererPage) {
0626: output.write(((MeasureDataRendererPage) renderer)
0627: .getReportHeader());
0628: output.write(((MeasureDataRendererPage) renderer)
0629: .beginPage());
0630: }
0631: if (renderer instanceof MeasureDataRendererColumnHeader) {
0632: output.write(((MeasureDataRendererColumnHeader) renderer)
0633: .getColumnHeaderAsString(new DefaultMeasurePoint(
0634: "empty", config)));
0635: }
0636: for (int i = 0; i < points.length; i++) {
0637: if (points[i].getPriority() >= priority) {
0638: output.write(renderer.getDataAsString(points[i], ""));
0639: }
0640: }
0641: if (renderer instanceof MeasureDataRendererPage) {
0642: output
0643: .write(((MeasureDataRendererPage) renderer)
0644: .endPage());
0645: }
0646: if ((snapShots.size() > 0)
0647: && (renderer instanceof MeasureDataRendererSnapshot)) {
0648: String[] snapShotsNames = getSnapShotNames();
0649: for (int i = 0; i < snapShotsNames.length; i++) {
0650: String snapShotname = snapShotsNames[i];
0651: SnapShot snapShot = getSnapShot(snapShotname);
0652: snapShot.getReport(pointname, renderer, priority,
0653: output);
0654: }
0655: }
0656: if (renderer instanceof MeasureDataRendererPage) {
0657: output.write(((MeasureDataRendererPage) renderer)
0658: .getReportFooter());
0659: }
0660:
0661: }
0662:
0663: /** Clearing all measure data and measure points. */
0664: public static void clear() {
0665: measurePoints.clear();
0666: snapShots.clear();
0667: }
0668:
0669: /**
0670: * saving all measurementpoints to an xml file structure for later reloading
0671: * with <code>loadFromXMLFile()</code>.
0672: *
0673: * @see #loadFromXMLFile(String, boolean)
0674: * @param filename
0675: * filename of the file to save xml to
0676: * @throws IOException
0677: * if something goes wrong in the filesystem.
0678: * @throws SAXException
0679: * if something goes wrong with xml writing
0680: */
0681: public static void saveToXMLFile(final String filename)
0682: throws IOException, SAXException {
0683: saveToXMLStream(new FileOutputStream(filename));
0684: }
0685:
0686: /**
0687: * saving all measurementpoints to an xml file structure for later
0688: * reloading.
0689: *
0690: * @param stream
0691: * the output stream to write the xml data to.
0692: * @throws IOException
0693: * if something goes wrong in the filesystem.
0694: * @throws SAXException
0695: * if something goes wrong with xml writing
0696: */
0697: public static void saveToXMLStream(final OutputStream stream)
0698: throws IOException, SAXException {
0699: DataWriter writer = new DataWriter(new PrintWriter(stream));
0700: writer.startDocument();
0701: AttributesImpl atts = new AttributesImpl();
0702: atts.addAttribute("", XMLATT_APPNAME, "", "String", config
0703: .getProperty(JMConfig.OPTION_APPLICATION_NAME));
0704: atts.addAttribute("", XMLATT_CREATED, "", "String",
0705: new SimpleDateFormat().format(new Date()));
0706: writer.startElement("", XMLNODE_ROOT, "", atts);
0707: writer.startElement(XMLNODE_MEASUREPOINTS);
0708: MeasurePoint[] points = getMeasurePoints(".*");
0709: for (int i = 0; i < points.length; i++) {
0710: if (points[i] instanceof DefaultMeasurePoint) {
0711: ((DefaultMeasurePoint) points[i]).toXML(writer);
0712: }
0713: }
0714: writer.endElement(XMLNODE_MEASUREPOINTS);
0715: if (snapShots.size() > 0) {
0716: saveSnapShots(writer);
0717: }
0718: writer.endElement("", XMLNODE_ROOT, "");
0719: writer.endDocument();
0720: }
0721:
0722: /**
0723: * save a snapshot to the xml writer.
0724: *
0725: * @param writer
0726: * the writer to use.
0727: * @throws SAXException
0728: * if something goes wrong.
0729: * @throws IOException
0730: * if something goes wrong.
0731: */
0732: private static void saveSnapShots(final DataWriter writer)
0733: throws SAXException, IOException {
0734: writer.startElement(XMLNODE_SNAPSHOTS);
0735: for (Iterator iter = snapShots.iterator(); iter.hasNext();) {
0736: SnapShot shot = (SnapShot) iter.next();
0737: shot.saveToXML(writer);
0738: }
0739: writer.endElement(XMLNODE_SNAPSHOTS);
0740: }
0741:
0742: /**
0743: * Load the measurepoints from an external XML file. (Possible saved with
0744: * <code>saveToXMLFile</code>)
0745: *
0746: * @see #saveToXMLFile(String)
0747: * @param filename
0748: * xml file
0749: * @param loadSnapShotData
0750: * loading the snapshot data if present.
0751: * @throws IOException
0752: * if something goes wrong
0753: * @throws SAXException
0754: * if something goes wrong
0755: * @throws MeasurementException
0756: * if something goes wrong
0757: */
0758: public static void loadFromXMLFile(final String filename,
0759: final boolean loadSnapShotData) throws IOException,
0760: SAXException, MeasurementException {
0761: loadFromXMLStream(new FileInputStream(filename),
0762: loadSnapShotData);
0763: }
0764:
0765: /**
0766: * Load the measurepoints with data from an inputstream.
0767: *
0768: * @param stream
0769: * InputStream to load the measure data from
0770: * @param loadSnapShotData
0771: * loading the snapshot data if present.
0772: * @throws IOException
0773: * if something goes wrong with reading of the desired xml
0774: * stream
0775: * @throws SAXException
0776: * if something goes wrong with reading of the desired xml
0777: * stream
0778: * @throws MeasurementException
0779: * if something goes wrong
0780: */
0781: public static void loadFromXMLStream(final InputStream stream,
0782: final boolean loadSnapShotData) throws IOException,
0783: SAXException, MeasurementException {
0784:
0785: /**
0786: * THis class is the inner class for parsing the xml file.
0787: *
0788: * @author w.klaas
0789: */
0790: class XMLHandler extends DefaultHandler {
0791: private static final int DEFAULT_POINTDATA_SIZE = 10;
0792:
0793: private int level = 0;
0794:
0795: private StringBuffer dataBuffer = null;
0796:
0797: private MeasurePoint measurePoint = null;
0798:
0799: private MeasureData measureData = null;
0800:
0801: private ArrayList<MeasureData> measuredatas = null;
0802:
0803: private boolean normalPoints = false;
0804:
0805: private boolean snapshot = false;
0806:
0807: private SnapShot shot;
0808:
0809: /**
0810: * @see org.xml.sax.ContentHandler#startElement
0811: * @param uri
0812: * uri
0813: * @param localName
0814: * local name
0815: * @param qName
0816: * qName
0817: * @param attributes
0818: * Attributes
0819: * @throws SAXException
0820: * saxexception
0821: */
0822: public void startElement(final String uri,
0823: final String localName, final String qName,
0824: final org.xml.sax.Attributes attributes)
0825: throws SAXException {
0826: level++;
0827: dataBuffer = new StringBuffer();
0828: if (qName.equals(XMLNODE_ROOT)) {
0829: // here we are on the root node
0830: // we have to read the application name. The created
0831: // attribute will be ignored
0832: config.setProperty(
0833: JMConfig.OPTION_APPLICATION_NAME,
0834: attributes.getValue(XMLATT_APPNAME));
0835: } else if (qName.equals(XMLNODE_SNAPSHOT)) {
0836: snapshot = true;
0837: shot = new SnapShot(attributes
0838: .getValue(XMLATT_NAME));
0839: } else if (qName.equals(XMLNODE_MEASUREPOINTS)) {
0840: normalPoints = true;
0841: } else if (qName.equals(XMLNODE_POINT)) {
0842: measuredatas = new ArrayList<MeasureData>(
0843: DEFAULT_POINTDATA_SIZE);
0844: String measurePointClass = attributes
0845: .getValue(XMLATT_CLASS);
0846: String measurePointName = attributes
0847: .getValue(XMLATT_NAME);
0848: if (null != measurePointClass) {
0849: if (!measurePointClass.equals("")) {
0850: measurePoint = getMeasurePointFromClass(
0851: measurePointClass, measurePointName);
0852: }
0853: }
0854: } else if (measurePoint != null) {
0855: // level with measurepoint data
0856: measureData = new MeasureData(qName, String.class,
0857: null, "", "");
0858: }
0859: }
0860:
0861: /**
0862: * @see org.xml.sax.ContentHandler#endElement
0863: * @param uri
0864: * uri
0865: * @param localName
0866: * local name
0867: * @param qName
0868: * qName
0869: */
0870: public void endElement(final String uri,
0871: final String localName, final String qName) {
0872: if (qName.equals(XMLNODE_SNAPSHOT)) {
0873: snapShots.add(shot);
0874: snapshot = false;
0875: shot = null;
0876: } else if (qName.equals(XMLNODE_MEASUREPOINTS)) {
0877: normalPoints = false;
0878: } else if (normalPoints && qName.equals(XMLNODE_POINT)) {
0879: measurePoint.setData((MeasureData[]) measuredatas
0880: .toArray(new MeasureData[0]));
0881: if (snapshot) {
0882: shot.register(measurePoint);
0883: } else {
0884: register(measurePoint);
0885: }
0886: measurePoint = null;
0887: } else if (measureData != null) {
0888: measureData.setAsString(dataBuffer.toString());
0889: measuredatas.add(measureData);
0890: measureData = null;
0891: }
0892: level--;
0893: }
0894:
0895: /**
0896: * @see org.xml.sax.ContentHandler#characters
0897: * @param ch
0898: * ch
0899: * @param start
0900: * start
0901: * @param length
0902: * length
0903: * @throws SAXException *
0904: * if something goes wrong
0905: */
0906: public void characters(final char[] ch, final int start,
0907: final int length) throws SAXException {
0908: dataBuffer.append(new String(ch, start, length));
0909: }
0910:
0911: }
0912:
0913: // setting up the xml parser
0914: // XMLReader reader;
0915: SAXParser parser;
0916: try {
0917: parser = SAXParserFactory.newInstance().newSAXParser();
0918: // reader = XMLReaderFactory.createXMLReader(XML_PARSER_CLASS);
0919: } catch (Exception e1) {
0920: throw new MeasurementException("can't create xml reader.",
0921: e1);
0922: }
0923: // reader.setContentHandler(new XMLHandler());
0924: InputSource isXMLInput = new InputSource(stream);
0925: try {
0926: parser.parse(isXMLInput, new XMLHandler());
0927: // reader.parse(isXMLInput);
0928: } catch (IOException e) {
0929: throw new MeasurementException("can't read xml file.", e);
0930: } catch (SAXException e) {
0931: throw new MeasurementException("error with xml file.", e);
0932: }
0933: // reader = null;
0934: parser = null;
0935: isXMLInput = null;
0936: }
0937:
0938: /**
0939: * Here we return the right measurepoint from a class. (to be written with
0940: * reflections, now i only support the defaultMeasurePoint class)
0941: *
0942: * @param measurePointClass
0943: * Classname of the object to return
0944: * @param measurePointName
0945: * name of the measure point
0946: * @return MeasurePoint object or <code>null</code>, if the class doesn't
0947: * exists.
0948: */
0949: private static MeasurePoint getMeasurePointFromClass(
0950: final String measurePointClass,
0951: final String measurePointName) {
0952: if (measurePointClass.equals(DefaultMeasurePoint.class
0953: .getName())) {
0954: return new DefaultMeasurePoint(measurePointName, config);
0955: } else {
0956: return null;
0957: }
0958: }
0959:
0960: /**
0961: * Returns the applicationName.
0962: *
0963: * @return String Returns the applicationName.
0964: */
0965: public static String getApplicationName() {
0966: return config.getProperty(JMConfig.OPTION_APPLICATION_NAME);
0967: }
0968:
0969: /**
0970: * Setting the application name.
0971: *
0972: * @param aApplicationName
0973: * The applicationName to set.
0974: */
0975: public static void setApplicationName(final String aApplicationName) {
0976: config.setProperty(JMConfig.OPTION_APPLICATION_NAME,
0977: aApplicationName);
0978: }
0979:
0980: /**
0981: * Returns the <code>measureDataCallback</code> object.
0982: *
0983: * @return Returns the measureDataCallback.
0984: */
0985: public static MeasureDataCallback getMeasureDataCallback() {
0986: return measureDataCallback;
0987: }
0988:
0989: /**
0990: * setting the <code>measureDataCallback</code> object.
0991: *
0992: * @param aMeasureDataCallback
0993: * The measureDataCallback to set.
0994: */
0995: public static void setMeasureDataCallback(
0996: final MeasureDataCallback aMeasureDataCallback) {
0997: MeasureFactory.measureDataCallback = aMeasureDataCallback;
0998: }
0999:
1000: /**
1001: * Returns if this factory can deliver monitors or not.
1002: *
1003: * @return boolean <code>true</code> if this factory can deliver monitors
1004: * or <code>false</code>.
1005: */
1006: public static boolean isEnable() {
1007: return config.isEnableMeasurement();
1008: }
1009:
1010: /**
1011: * This methode will enable the monitor factory. If it's set to false,
1012: * <code>start()</code> methode will only return <code>NullMoniotr</code>
1013: * Objects. <br/><b>This value has no influenz on the <code>start()</code>
1014: * methode of the MeasurementsPoints. They will return normal monitor
1015: * objects even when the factory is turned of. </b>
1016: *
1017: * @param aEnable
1018: * The enable to set.
1019: */
1020: public static void setEnable(final boolean aEnable) {
1021: config.setEnableMeasurement(aEnable);
1022: }
1023:
1024: /**
1025: * new methode for making a snapshot. In a snapshot all measure points data
1026: * will be saved under the desired name. All Snapshot data will be saved
1027: * into the xml files and will be renderd, if desired. The Snapshot will
1028: * contains some individual data like the a memory snapshot.
1029: *
1030: * @param snapshotname
1031: * name of the snapshot.
1032: * @return the snapshot
1033: */
1034: public static SnapShot takeSnapshot(final String snapshotname) {
1035: SnapShot snapShot = new SnapShot(snapshotname);
1036: snapShot.cloneMeasurePoints(measurePoints);
1037: snapShots.add(snapShot);
1038: return snapShot;
1039: }
1040:
1041: /**
1042: * getting a snapshot from the system.
1043: *
1044: * @param snapshotname
1045: * name of the snapshot to get
1046: * @return the desired snapshot or <code>null</code> if no snapshot with
1047: * this name is present.
1048: */
1049: public static SnapShot getSnapShot(final String snapshotname) {
1050: for (Iterator iter = snapShots.iterator(); iter.hasNext();) {
1051: SnapShot snapShot = (SnapShot) iter.next();
1052: if (snapShot.getName().equals(snapshotname)) {
1053: return snapShot;
1054: }
1055: }
1056: return null;
1057: }
1058:
1059: /**
1060: * save snapshot as XMl.
1061: *
1062: * @param snapshot
1063: * the snapshot to save.
1064: * @param file
1065: * the file to save to.
1066: * @throws SAXException
1067: * if something goes wrong.
1068: * @throws IOException
1069: * if something goes wrong.
1070: */
1071: public static void saveSnapShot(final SnapShot snapshot,
1072: final File file) throws SAXException, IOException {
1073: FileOutputStream stream;
1074: stream = new FileOutputStream(file);
1075: DataWriter writer = new DataWriter(new PrintWriter(stream));
1076: writer.startDocument();
1077: AttributesImpl atts = new AttributesImpl();
1078: atts.addAttribute("", XMLATT_APPNAME, "", "String", config
1079: .getProperty(JMConfig.OPTION_APPLICATION_NAME));
1080: atts.addAttribute("", XMLATT_CREATED, "", "String",
1081: new SimpleDateFormat().format(new Date()));
1082: writer.startElement("", XMLNODE_ROOT, "", atts);
1083: writer.startElement(XMLNODE_SNAPSHOTS);
1084: snapshot.saveToXML(writer);
1085: writer.endElement(XMLNODE_SNAPSHOTS);
1086: writer.endElement("", XMLNODE_ROOT, "");
1087: writer.endDocument();
1088: stream.close();
1089: stream.flush();
1090: stream = null;
1091: }
1092:
1093: /**
1094: * getting the names of all snapshots from the system.
1095: *
1096: * @return String[] array with all snapshot names .
1097: */
1098: public static String[] getSnapShotNames() {
1099: String[] names = new String[snapShots.size()];
1100: int i = 0;
1101: for (Iterator iter = snapShots.iterator(); iter.hasNext();) {
1102: SnapShot shot = (SnapShot) iter.next();
1103: names[i] = shot.getName();
1104: i++;
1105: }
1106: return names;
1107: }
1108:
1109: /**
1110: * removing a snapshot from the system.
1111: *
1112: * @param snapshotname
1113: * name of the snapshot to remove
1114: * @return the removed snapshot or <code>null</code> if no snapshot with
1115: * this name is present.
1116: */
1117: public static SnapShot removeSnapShot(final String snapshotname) {
1118: SnapShot snapShot = null;
1119: for (Iterator iter = snapShots.iterator(); iter.hasNext();) {
1120: snapShot = (SnapShot) iter.next();
1121: if (snapShot.getName().equals(snapshotname)) {
1122: iter.remove();
1123: }
1124: }
1125: return snapShot;
1126: }
1127:
1128: /**
1129: * Adding a Interface for automatic methode measurement. Exception handling
1130: * as defined here.
1131: *
1132: * @param object
1133: * Interface to add
1134: * @return the interface to the proxy class.
1135: * @since 0.66
1136: */
1137: public static Object registerInterface(final Object object) {
1138: return registerInterface(object, null);
1139: }
1140:
1141: /**
1142: * Adding a Interface for automatic methode measurement. Exception handling
1143: * as defined here.
1144: *
1145: * @param object
1146: * Interface to add
1147: * @param aMethodNames
1148: * names of the methodes to monitor. <code>null</code> if all
1149: * methodes should be monitored.
1150: * @since 0.72 If you wan't to define an argument as a point name you can
1151: * use the following syntax for the method name: <method
1152: * name>[.arg<index of argument>]
1153: *
1154: * @return the interface to the proxy class.
1155: * @since 0.66
1156: */
1157: public static Object registerInterface(final Object object,
1158: final String[] aMethodNames) {
1159: return Proxy.newProxyInstance(object.getClass()
1160: .getClassLoader(), object.getClass().getInterfaces(),
1161: new ProxyMonitor(object, aMethodNames));
1162: }
1163:
1164: /**
1165: * Adding a Interface for automatic methode measurement.
1166: *
1167: * @param object
1168: * Interface to add
1169: * @param storeExceptions
1170: * if the exception stacktraces should be stored.
1171: * @param fullExceptions
1172: * full exceptions with stacktraces
1173: * @return the interface to the proxy class.
1174: * @since 0.64
1175: */
1176: public static Object registerInterface(final Object object,
1177: final boolean storeExceptions, final boolean fullExceptions) {
1178: return registerInterface(object, storeExceptions,
1179: fullExceptions, null);
1180: }
1181:
1182: /**
1183: * Adding a Interface for automatic methode measurement.
1184: *
1185: * @param object
1186: * Interface to add
1187: * @param storeExceptions
1188: * if the exception stacktraces should be stored.
1189: * @param fullExceptions
1190: * full exceptions with stacktraces
1191: * @param aMethodNames
1192: * list with all methodnames that should be monitored. If this
1193: * parameter is null all methods will be monitored.
1194: * @since 0.72 If you wan't to define an argument as a point name you can
1195: * use the following syntax for the method name: <method
1196: * name>[.arg<index of argument>]
1197: * @return the interface to the proxy class.
1198: * @since 0.64
1199: */
1200: public static Object registerInterface(final Object object,
1201: final boolean storeExceptions,
1202: final boolean fullExceptions, final String[] aMethodNames) {
1203: return Proxy.newProxyInstance(object.getClass()
1204: .getClassLoader(), object.getClass().getInterfaces(),
1205: new ProxyMonitor(object, storeExceptions,
1206: fullExceptions, aMethodNames));
1207: }
1208:
1209: /**
1210: * @return value of exception handling
1211: */
1212: public static int getExceptionHandling() {
1213: return config.getInteger(JMConfig.OPTION_EXCEPTION_HANDLING);
1214: }
1215:
1216: /**
1217: * setting the value of the exception handling.
1218: *
1219: * @param aExceptionHandling
1220: * one of the constants for exception handling.
1221: */
1222: public static void setExceptionHandling(final int aExceptionHandling) {
1223: config.setInteger(JMConfig.OPTION_EXCEPTION_HANDLING,
1224: aExceptionHandling);
1225: }
1226:
1227: /**
1228: * setting some special options for this factory. Possible option names are:
1229: * <ul>
1230: * <li><b>OPTION_DISABLE_DEVIATION</b> disable calcualtion of the
1231: * deviation. Possible values are <code>true,false</code>.</li>
1232: * <li><b>OPTION_ENABLE_AUTOSNAPSHOT</b> Enable the automatic snapshot
1233: * system. Possible values are <code>true,false</code>.</li>
1234: * <li><b>OPTION_BACKGROUND_TIME</b> Time (in msec) to generate a new
1235: * snapshot and to prove the memory saving settings.</li>
1236: * <li><b>OPTION_ENABLE_MEMORY_SAVINGS</b> Enable the automatic memory
1237: * saving system. All not actually needed measure points and snapshots will
1238: * be save to the harddisk. To detemine where to sstore the data, use the
1239: * OPTIONS_WORKINGPATH. Possible values are <code>true,false</code>.</li>
1240: * <li><b>OPTION_WORKINGPATH</b> Path where to store the measuredata for
1241: * memory savings.</li>
1242: * <li><b>OPTION_POINT_IDLETIME</b> Time (in sec) how long a point must be
1243: * idle before it will be saved to disk.</li>
1244: * </ul>
1245: *
1246: * The memory savings and the auto snapshot feature will start a background
1247: * process, which is controlled by the
1248: * {@link MeasureFactory#setBackgroundProcessing(boolean)} method. If you
1249: * wan't to suspend the feature, set the background processing to false. But
1250: * don't forget to set it back to true, if you are ready. If you set
1251: * {@link MeasureFactory#OPTION_BACKGROUND_TIME} you have to manually enable
1252: * the background processing via
1253: * {@link MeasureFactory#setBackgroundProcessing(boolean)}. If you use the
1254: * method {@link MeasureFactory#setOptions(Map)} the background processing
1255: * wil automatically started.
1256: *
1257: * @param aOptionName
1258: * the option that should be set.
1259: * @param aOptionValue
1260: * value of this option as String
1261: * @since 0.67
1262: */
1263: public static void setOption(final String aOptionName,
1264: final String aOptionValue) {
1265: if ((aOptionName != null) && (aOptionValue != null)) {
1266: config.setProperty(aOptionName, aOptionValue);
1267: }
1268: }
1269:
1270: /**
1271: * Setting a bunch of options.
1272: * {@link MeasureFactory#setOption(String, String)}
1273: *
1274: * @param aOptions
1275: * a map with all options.
1276: * @since 0.68
1277: */
1278: public static void setOptions(final Map<String, String> aOptions) {
1279: for (Entry<String, String> entry : aOptions.entrySet()) {
1280: if (null != entry.getValue()) {
1281: config.setProperty(entry.getKey(), entry.getValue());
1282: }
1283: }
1284: }
1285:
1286: /**
1287: * starting and stopping background processing.
1288: *
1289: * @param enableBackground
1290: * <code>true</code> to allow background processing, otherwise
1291: * <code>false</code>
1292: * @since 0.68
1293: */
1294: public static void setBackgroundProcessing(
1295: final boolean enableBackground) {
1296: if (enableBackground) {
1297: if (backgroundtimer == null) {
1298: backgroundtimer = new Timer(
1299: "JMeasurement Background Timer", true);
1300: long period = config
1301: .getLong(JMConfig.OPTION_BACKGROUND_TIME);
1302: backgroundtimer.scheduleAtFixedRate(new MeasureTask(
1303: config), period, period);
1304: }
1305: } else {
1306: if (backgroundtimer != null) {
1307: backgroundtimer.cancel();
1308: backgroundtimer.purge();
1309: backgroundtimer = null;
1310: }
1311:
1312: }
1313: }
1314:
1315: /**
1316: * testing if backgorund processing is enabled.
1317: *
1318: * @return <code>true</code> if background processing is enabled,
1319: * otherwise <code>false</code>
1320: * @since 0.68
1321: */
1322: public static boolean isBackgroundProcessing() {
1323: return backgroundtimer != null;
1324: }
1325:
1326: /**
1327: * @return getting the actual config object.
1328: */
1329: public static JMConfig getConfig() {
1330: return config;
1331: }
1332:
1333: /**
1334: * registering the JMX extensions for JMeasurement in the standard MBean
1335: * server of this platform.
1336: *
1337: * @throws NotCompliantMBeanException
1338: * if something goes wrong with the registration
1339: * @throws MBeanRegistrationException
1340: * if something goes wrong with the registration
1341: * @throws InstanceAlreadyExistsException
1342: * if something goes wrong with the registration
1343: *
1344: */
1345: public static void registerMBeans()
1346: throws InstanceAlreadyExistsException,
1347: MBeanRegistrationException, NotCompliantMBeanException {
1348: MBeanServer mBeanServer = ManagementFactory
1349: .getPlatformMBeanServer();
1350: try {
1351: ObjectName name = new ObjectName(
1352: "de.mcs.jmeasurement.jmx:type=JmxConfig");
1353: JmxConfigMBean mbean = new JmxConfig();
1354: mBeanServer.registerMBean(mbean, name);
1355:
1356: // name = new ObjectName("de.mcs.jmeasurement.jmx:type=JmxPoints");
1357: // JmxPointsMXBean mxbean = new JmxPointsImpl();
1358: // mBeanServer.registerMBean(mxbean, name);
1359:
1360: } catch (MalformedObjectNameException e) {
1361: e.printStackTrace();
1362: } catch (NullPointerException e) {
1363: e.printStackTrace();
1364: }
1365: }
1366: }
|