/*
* RHQ Management Platform
* Copyright (C) 2005-2010 Red Hat, Inc.
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.rhq.core.server;
import org.rhq.core.domain.measurement.MeasurementSchedule;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.core.domain.measurement.composite.MeasurementNumericValueAndUnits;
import org.rhq.core.domain.measurement.util.MeasurementConversionException;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Greg Hinkle
*/
public class MeasurementParser {
private static final String NUMBER_OPTIONAL_UNIT_PATTERN_STRING = "([\\+\\-]?" + // number sign is optional but valid
"[0-9\\.\\,]{1,})" + // followed by at least one magnitude identifier, capture number plus sign
"([\\%a-z]*)"; // followed by an optional units identifier, capture entire suffix
private static final Pattern NUMBER_OPTIONAL_UNIT_PATTERN;
static {
NUMBER_OPTIONAL_UNIT_PATTERN = Pattern.compile(NUMBER_OPTIONAL_UNIT_PATTERN_STRING, Pattern.CASE_INSENSITIVE);
}
public static MeasurementNumericValueAndUnits parse(String input, MeasurementUnits targetUnits)
throws MeasurementConversionException {
input = input.replaceAll("\\s", ""); // our pattern assumes no whitespace
Matcher matcher = NUMBER_OPTIONAL_UNIT_PATTERN.matcher(input);
if (!matcher.matches()) {
throw new MeasurementConversionException("The passed input '" + input + "' could not be parsed correctly "
+ "by the regular expression " + NUMBER_OPTIONAL_UNIT_PATTERN_STRING);
}
String magnitude = matcher.group(1);
String units = matcher.group(2);
MeasurementUnits fromUnits;
if (units.equals("")) {
/*
* no units is valid, and we assume the passed targetUnits; however, we will
* still need to check that the number is well-formed, so continue processing.
*/
fromUnits = targetUnits;
} else {
fromUnits = MeasurementUnits.getUsingDisplayUnits(units, targetUnits.getFamily());
if ((fromUnits == null) || (!fromUnits.isComparableTo(targetUnits))) {
throw new MeasurementConversionException("The units in '" + input + "' were not valid, " + "expected '"
+ targetUnits.getFamily() + "' units, received '" + units + "' units");
}
}
try {
if (magnitude.startsWith("+")) {
magnitude = magnitude.substring(1);
}
Number convertedMagnitude = DecimalFormat.getInstance().parse(magnitude);
Double scaledMagnitude;
// apply relative scale if applicable, otherwise perform standard scaling
if (MeasurementUnits.Family.RELATIVE == targetUnits.getFamily()) {
scaledMagnitude = MeasurementUnits.scaleDown(convertedMagnitude.doubleValue(), targetUnits);
} else {
MeasurementNumericValueAndUnits valueAndUnits = new MeasurementNumericValueAndUnits(convertedMagnitude
.doubleValue(), fromUnits);
scaledMagnitude = MeasurementConverter.scale(valueAndUnits, targetUnits);
}
return new MeasurementNumericValueAndUnits(scaledMagnitude, targetUnits);
} catch (ParseException pe) {
throw new MeasurementConversionException("The magnitude in '" + input + "' did not parse correctly "
+ "as a valid, localized, stringified number ");
}
}
public static MeasurementNumericValueAndUnits parse(String input, MeasurementSchedule targetSchedule)
throws MeasurementConversionException {
MeasurementUnits targetUnits = targetSchedule.getDefinition().getUnits();
return parse(input, targetUnits);
}
}