001: /*
002: * Copyright (c) 2001-2007, Jean Tessier
003: * All rights reserved.
004: *
005: * Redistribution and use in source and binary forms, with or without
006: * modification, are permitted provided that the following conditions
007: * are met:
008: *
009: * * Redistributions of source code must retain the above copyright
010: * notice, this list of conditions and the following disclaimer.
011: *
012: * * Redistributions in binary form must reproduce the above copyright
013: * notice, this list of conditions and the following disclaimer in the
014: * documentation and/or other materials provided with the distribution.
015: *
016: * * Neither the name of Jean Tessier nor the names of his contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032:
033: package com.jeantessier.metrics;
034:
035: import java.io.*;
036: import java.util.*;
037:
038: import org.apache.log4j.*;
039:
040: /**
041: * <p>Base class that accumulates entries, filtering with regular
042: * expressions. If no regular expressions are given, matches
043: * everything for the given measurement, which must implement
044: * the <code>CollectionMeasurement</code> interface. Regular
045: * expressions matching using <code>Perl5Util</code> from
046: * Jakarta-ORO. This measurement will use
047: * <code>Perl5Util.group(1)</code> if not null, otherwise the
048: * full string.</p>
049: *
050: * <p>This is the syntax for initializing this type of
051: * measurement:</p>
052: *
053: * <pre>
054: * <init>
055: * measurement name [perl regular expression]
056: * ...
057: * </init>
058: * </pre>
059: */
060: public abstract class AccumulatorMeasurement extends MeasurementBase
061: implements CollectionMeasurement {
062: private Map<String, Collection<String>> terms = new HashMap<String, Collection<String>>();
063: private Collection<String> values = new TreeSet<String>();
064:
065: public AccumulatorMeasurement(MeasurementDescriptor descriptor,
066: Metrics context, String initText) {
067: super (descriptor, context, initText);
068:
069: if (initText != null) {
070: try {
071: BufferedReader in = new BufferedReader(
072: new StringReader(initText));
073: String line;
074:
075: while ((line = in.readLine()) != null) {
076: synchronized (perl()) {
077: if (perl().match("/^\\s*(\\S+)\\s*(.*)/", line)) {
078: String name = perl().group(1);
079: String re = perl().group(2);
080:
081: Collection<String> res = terms.get(name);
082: if (res == null) {
083: res = new ArrayList<String>();
084: terms.put(name, res);
085: }
086:
087: if (re != null && re.length() > 0) {
088: res.add(re);
089: }
090: }
091: }
092: }
093:
094: in.close();
095: } catch (Exception ex) {
096: Logger.getLogger(getClass()).debug(
097: "Cannot initialize with \"" + initText + "\"",
098: ex);
099: terms.clear();
100: }
101: }
102:
103: logTerms(initText);
104: }
105:
106: private void logTerms(String initText) {
107: Logger.getLogger(getClass()).debug(
108: "Initialize with\n" + initText);
109: Logger.getLogger(getClass()).debug("Terms:");
110:
111: for (Map.Entry<String, Collection<String>> entry : terms
112: .entrySet()) {
113: Logger.getLogger(getClass()).debug("\t" + entry.getKey());
114:
115: for (String s : entry.getValue()) {
116: Logger.getLogger(getClass()).debug("\t\t" + s);
117: }
118: }
119: }
120:
121: public Number getValue() {
122: return getValues().size();
123: }
124:
125: public boolean isEmpty() {
126: return getValues().isEmpty();
127: }
128:
129: protected double compute() {
130: return getValues().size();
131: }
132:
133: public Collection<String> getValues() {
134: if (!isCached()) {
135: values.clear();
136:
137: populateValues();
138:
139: setCached(true);
140: }
141:
142: return Collections.unmodifiableCollection(values);
143: }
144:
145: protected abstract void populateValues();
146:
147: protected void filterMetrics(Metrics metrics) {
148: for (Map.Entry<String, Collection<String>> entry : terms
149: .entrySet()) {
150: String name = entry.getKey();
151: Collection<String> res = entry.getValue();
152:
153: Measurement measurement = metrics.getMeasurement(name);
154: if (measurement instanceof CollectionMeasurement) {
155: filterMeasurement((CollectionMeasurement) measurement,
156: res);
157: }
158: }
159: }
160:
161: private void filterMeasurement(CollectionMeasurement measurement,
162: Collection<String> res) {
163: if (res.isEmpty()) {
164: values.addAll(measurement.getValues());
165: } else {
166: for (String member : measurement.getValues()) {
167: filterElement(member, res);
168: }
169: }
170: }
171:
172: private void filterElement(String element, Collection<String> res) {
173: boolean found = false;
174: Iterator<String> i = res.iterator();
175: while (!found && i.hasNext()) {
176: found = evaluateRE(i.next(), element);
177: }
178: }
179:
180: private boolean evaluateRE(String re, String element) {
181: boolean result = false;
182:
183: synchronized (perl()) {
184: if (perl().match(re, element)) {
185: result = true;
186: if (perl().group(1) != null) {
187: values.add(perl().group(1));
188: } else {
189: values.add(element);
190: }
191: }
192: }
193:
194: return result;
195: }
196: }
|