modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourcePermission.java | 4
modules/enterprise/gui/coregui/src/main/java/org/rhq/core/domain/measurement/MeasurementConverterClient.java | 360 ---------
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/UserPermissionsManager.java | 132 ---
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/agent/install/RemoteAgentInstallView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertFormatUtility.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/file/FileListView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/platform/PlatformPortletView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java | 11
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java | 11
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/AvailabilityBarView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/LiveGraphView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/SmallGraphView.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/report/measurement/MeasurementOOBDataSource.java | 2
modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/MeasurementConverterClient.java | 363 ++++++++++
15 files changed, 376 insertions(+), 523 deletions(-)
New commits:
commit 64aa25bcc4cb12dfe7011882365a8f0672b328d4
Author: Joseph Marques <joseph(a)redhat.com>
Date: Wed Nov 24 12:31:49 2010 -0500
fix bug introduced during ResourcePermission refactoring
* isInventory() was incorrectly checking for MANAGE_INVENTORY, which is a
global permission. however, this object only represents the collection of
resource-level permission, thus this was always returning false. the
authorization to change connection properties needs to be guarded by
MODIFY_RESOURCE
diff --git a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourcePermission.java b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourcePermission.java
index e8ea649..4141593 100644
--- a/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourcePermission.java
+++ b/modules/core/domain/src/main/java/org/rhq/core/domain/resource/composite/ResourcePermission.java
@@ -67,7 +67,7 @@ public class ResourcePermission implements Serializable {
this.permissions.add(Permission.MANAGE_MEASUREMENTS);
}
if (inventory) {
- this.permissions.add(Permission.MANAGE_INVENTORY);
+ this.permissions.add(Permission.MODIFY_RESOURCE);
}
if (control) {
this.permissions.add(Permission.CONTROL);
@@ -108,7 +108,7 @@ public class ResourcePermission implements Serializable {
}
public boolean isInventory() {
- return this.permissions.contains(Permission.MANAGE_INVENTORY);
+ return this.permissions.contains(Permission.MODIFY_RESOURCE);
}
public boolean isControl() {
commit 44de15aed85d8215111c2bf1d26584dbbe212776
Author: Joseph Marques <joseph(a)redhat.com>
Date: Wed Nov 24 12:29:31 2010 -0500
don't cache resource/group permissions (they're already in the composite)
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/UserPermissionsManager.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/UserPermissionsManager.java
index c26a2f4..9554c5f 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/UserPermissionsManager.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/UserPermissionsManager.java
@@ -28,9 +28,6 @@ import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;
import org.rhq.core.domain.authz.Permission;
-import org.rhq.core.domain.resource.composite.ResourceComposite;
-import org.rhq.core.domain.resource.composite.ResourcePermission;
-import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite;
import org.rhq.enterprise.gui.coregui.client.gwt.AuthorizationGWTServiceAsync;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.util.message.Message;
@@ -52,23 +49,11 @@ public class UserPermissionsManager {
private static final MessageCenter MESSAGE_CENTER = CoreGUI.getMessageCenter();
private static final int REFRESH_INTERVAL = 60 * 1000; // 1 minute
- private Context currentContext;
- private int currentId;
-
/** This is a reference to the last set of global perms returned to a caller. */
private Set<Permission> globalPermissions = new HashSet<Permission>(Permission.GLOBAL_ALL.size());
private boolean globalCacheDirty = true;
private PermissionsLoadedListener globalPermissionsLoadedListener;
- /** This is a reference to the last set of Resource perms returned to a caller. */
- private Set<Permission> resourcePermissions;
- private boolean resourceCacheDirty = true;
- private PermissionsLoadedListener resourcePermissionsLoadedListener;
-
- private enum Context {
- RESOURCE, GROUP;
- };
-
public static UserPermissionsManager getInstance() {
return INSTANCE;
}
@@ -88,63 +73,6 @@ public class UserPermissionsManager {
return this.globalPermissions;
}
- public void loadResourcePermissions(ResourceComposite currentResource,
- PermissionsLoadedListener permissionsLoadedListener) {
- if ((this.currentContext != Context.RESOURCE) || (this.currentId != currentResource.getResource().getId())) {
- this.resourceCacheDirty = true;
- }
- this.currentContext = Context.RESOURCE;
- this.currentId = currentResource.getResource().getId();
- if (currentResource.getResourcePermission() == null) {
- ResourcePermission resourcePermission = new ResourcePermission(new HashSet<Permission>(
- Permission.RESOURCE_ALL.size()));
- currentResource.setResourcePermission(resourcePermission);
- }
- this.resourcePermissions = currentResource.getResourcePermission().getPermissions();
-
- // TODO: This code is not working correctly, it's returning no perms. Also, why are we going to the
- // server when we basically just fetched a resource composite. Its perms should be valid.
- // Anyway, for now, bypass this...
- //if (this.resourceCacheDirty) {
- // Permissions are not cached. Kick off an async load and let it notify the caller when the load completes.
- // this.resourcePermissionsLoadedListener = permissionsLoadedListener;
- // loadCurrentResourcePermissions();
- //} else {
- // Permissions are cached - shoot em back to the caller.
- permissionsLoadedListener.onPermissionsLoaded(this.resourcePermissions);
- // }
- }
-
- /**
- * TODO
- *
- * @param currentGroup
- * @param permissionsLoadedListener
- */
- public void loadGroupPermissions(ResourceGroupComposite currentGroup,
- PermissionsLoadedListener permissionsLoadedListener) {
- if ((this.currentContext != Context.GROUP) || (this.currentId != currentGroup.getResourceGroup().getId())) {
- this.resourceCacheDirty = true;
- }
- this.currentContext = Context.GROUP;
- this.currentId = currentGroup.getResourceGroup().getId();
- if (currentGroup.getResourcePermission() == null) {
- ResourcePermission resourcePermission = new ResourcePermission(new HashSet<Permission>(
- Permission.RESOURCE_ALL.size()));
- currentGroup.setResourcePermission(resourcePermission);
- }
- this.resourcePermissions = currentGroup.getResourcePermission().getPermissions();
-
- if (this.resourceCacheDirty) {
- // Permissions are not cached. Kick off an async load and let it notify the caller when the load completes.
- this.resourcePermissionsLoadedListener = permissionsLoadedListener;
- loadCurrentGroupPermissions();
- } else {
- // Permissions are cached - shoot em back to the caller.
- permissionsLoadedListener.onPermissionsLoaded(this.resourcePermissions);
- }
- }
-
/**
* Clear all cached permissions.
*/
@@ -152,11 +80,6 @@ public class UserPermissionsManager {
// Clear global cache.
this.globalCacheDirty = true;
this.globalPermissions.clear();
-
- // Clear Resource/group cache.
- this.resourceCacheDirty = true;
- this.currentContext = null;
- this.currentId = 0;
}
private UserPermissionsManager() {
@@ -164,16 +87,6 @@ public class UserPermissionsManager {
public void run() {
Log.debug("Refreshing cached user permissions...");
loadGlobalPermissions();
- if (UserPermissionsManager.this.currentContext != null) {
- switch (UserPermissionsManager.this.currentContext) {
- case RESOURCE:
- loadCurrentResourcePermissions();
- break;
- case GROUP:
- loadCurrentGroupPermissions();
- break;
- }
- }
}
};
@@ -207,51 +120,6 @@ public class UserPermissionsManager {
}
}
- private void loadCurrentResourcePermissions() {
- AUTHORIZATION_SERVICE.getExplicitResourcePermissions(this.currentId, new AsyncCallback<Set<Permission>>() {
- public void onFailure(Throwable throwable) {
- MESSAGE_CENTER.notify(new Message(MSG.util_userPerm_loadFailResource(Integer
- .toString(UserPermissionsManager.this.currentId)), throwable, Message.Severity.Error, EnumSet
- .of(Message.Option.BackgroundJobResult)));
- UserPermissionsManager.this.resourcePermissions.clear();
- UserPermissionsManager.this.resourceCacheDirty = true;
- notifyResourcePermissionsLoadedListener();
- }
-
- public void onSuccess(Set<Permission> permissions) {
- setTo(UserPermissionsManager.this.resourcePermissions, permissions);
- UserPermissionsManager.this.resourceCacheDirty = false;
- notifyResourcePermissionsLoadedListener();
- }
- });
- }
-
- private void loadCurrentGroupPermissions() {
- AUTHORIZATION_SERVICE.getExplicitGroupPermissions(this.currentId, new AsyncCallback<Set<Permission>>() {
- public void onFailure(Throwable throwable) {
- MESSAGE_CENTER.notify(new Message(MSG.util_userPerm_loadFailGroup(Integer
- .toString(UserPermissionsManager.this.currentId)), throwable, Message.Severity.Error, EnumSet
- .of(Message.Option.BackgroundJobResult)));
- UserPermissionsManager.this.resourcePermissions.clear();
- UserPermissionsManager.this.resourceCacheDirty = true;
- notifyResourcePermissionsLoadedListener();
- }
-
- public void onSuccess(Set<Permission> permissions) {
- setTo(UserPermissionsManager.this.resourcePermissions, permissions);
- UserPermissionsManager.this.resourceCacheDirty = false;
- notifyResourcePermissionsLoadedListener();
- }
- });
- }
-
- private void notifyResourcePermissionsLoadedListener() {
- if (this.resourcePermissionsLoadedListener != null) {
- this.resourcePermissionsLoadedListener.onPermissionsLoaded(this.resourcePermissions);
- this.resourcePermissionsLoadedListener = null;
- }
- }
-
private static void setTo(Set<Permission> permissions1, Set<Permission> permissions2) {
permissions1.clear();
permissions1.addAll(permissions2);
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java
index 3226afe..4f6257e 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/groups/detail/ResourceGroupDetailView.java
@@ -38,8 +38,6 @@ import org.rhq.core.domain.resource.group.ResourceGroup;
import org.rhq.core.domain.resource.group.composite.ResourceGroupComposite;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener;
-import org.rhq.enterprise.gui.coregui.client.UserPermissionsManager;
import org.rhq.enterprise.gui.coregui.client.ViewPath;
import org.rhq.enterprise.gui.coregui.client.alert.GroupAlertHistoryView;
import org.rhq.enterprise.gui.coregui.client.alert.definitions.GroupAlertDefinitionsView;
@@ -358,14 +356,7 @@ public class ResourceGroupDetailView extends AbstractTwoLevelTabSetView<Resource
"Failed to load group composite for group with id " + groupId);
} else {
groupComposite = result.get(0);
- // First load the user's permissions for the group.
- UserPermissionsManager.getInstance().loadGroupPermissions(groupComposite,
- new PermissionsLoadedListener() {
- public void onPermissionsLoaded(Set<Permission> permissions) {
- // Next load the group's ResourceType.
- loadResourceType(groupComposite, viewPath);
- }
- });
+ loadResourceType(groupComposite, viewPath);
}
}
});
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java
index 35a929b..03420f2 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/ResourceDetailView.java
@@ -38,8 +38,6 @@ import org.rhq.core.domain.resource.composite.ResourceComposite;
import org.rhq.core.domain.resource.composite.ResourcePermission;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
-import org.rhq.enterprise.gui.coregui.client.PermissionsLoadedListener;
-import org.rhq.enterprise.gui.coregui.client.UserPermissionsManager;
import org.rhq.enterprise.gui.coregui.client.ViewPath;
import org.rhq.enterprise.gui.coregui.client.alert.ResourceAlertHistoryView;
import org.rhq.enterprise.gui.coregui.client.alert.definitions.ResourceAlertDefinitionsView;
@@ -397,14 +395,7 @@ public class ResourceDetailView extends AbstractTwoLevelTabSetView<ResourceCompo
onFailure(new Exception(MSG.view_inventory_resource_loadFailed(String.valueOf(resourceId))));
} else {
final ResourceComposite resourceComposite = result.get(0);
- // First load the user's permissions for the Resource.
- UserPermissionsManager.getInstance().loadResourcePermissions(resourceComposite,
- new PermissionsLoadedListener() {
- public void onPermissionsLoaded(Set<Permission> permissions) {
- // Next load the Resource's type.
- loadResourceType(resourceComposite, viewPath);
- }
- });
+ loadResourceType(resourceComposite, viewPath);
}
}
});
commit 362a0a6eab0dd07084a6575e19a037ac4d19ff19
Author: Joseph Marques <joseph(a)redhat.com>
Date: Mon Nov 22 17:59:26 2010 -0500
fix GWT compiler error
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/core/domain/measurement/MeasurementConverterClient.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/core/domain/measurement/MeasurementConverterClient.java
deleted file mode 100644
index 64eea4a..0000000
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/core/domain/measurement/MeasurementConverterClient.java
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * RHQ Management Platform
- * Copyright (C) 2005-2008 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, version 2, as
- * published by the Free Software Foundation, and/or the GNU Lesser
- * General Public License, version 2.1, also as published by the Free
- * Software Foundation.
- *
- * 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 and the GNU Lesser General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * and the GNU Lesser General Public License along with this program;
- * if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-package org.rhq.core.domain.measurement;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import com.google.gwt.i18n.client.NumberFormat;
-
-import org.rhq.core.domain.measurement.composite.MeasurementNumericValueAndUnits;
-import org.rhq.core.domain.measurement.util.MeasurementConversionException;
-import org.rhq.enterprise.gui.coregui.client.CoreGUI;
-import org.rhq.enterprise.gui.coregui.client.Messages;
-
-public class MeasurementConverterClient {
- private static final Messages MSG = CoreGUI.getMessages();
-
- private static final int MAX_PRECISION_DIGITS = 4;
- private static final String NULL_OR_NAN_FORMATTED_VALUE = MSG.view_measure_nan();
-
- private static NumberFormat getDefaultNumberFormat() {
- NumberFormat nf = NumberFormat.getFormat("0.0");
-
- return nf;
- }
-
- public static Double scale(MeasurementNumericValueAndUnits origin, MeasurementUnits targetUnits)
- throws MeasurementConversionException {
- MeasurementUnits originUnits = origin.getUnits();
- Double originValue = origin.getValue();
-
- return originValue * MeasurementUnits.calculateOffset(originUnits, targetUnits);
- }
-
- public static Double scale(Double origin, MeasurementUnits targetUnits) throws MeasurementConversionException {
- boolean wasNegative = false;
- if (origin < 0) {
- wasNegative = true;
- origin = -origin;
- }
-
- MeasurementUnits baseUnit = targetUnits.getBaseUnits();
- MeasurementNumericValueAndUnits valueAndUnits = new MeasurementNumericValueAndUnits(origin, baseUnit);
-
- Double results = scale(valueAndUnits, targetUnits);
- if (wasNegative) {
- results = -results;
- }
-
- return results;
- }
-
- public static String format(String value, MeasurementUnits targetUnits) {
- if (targetUnits == null) {
- return value;
- } else {
- return value + targetUnits;
- }
- }
-
- /**
- * Formats the given array of double values: determines the necessary precision such that when formatted, they are
- * distinct and reasonable to look at. For example, for values { 1.45 1.46 1.47 1.48 1.49 } the desired precision is
- * 2 - less precision loses significant digits, and more precision provides no added benefit. Max precision is
- * bounded for presentation considerations.
- *
- * @param values the values to be formatted
- * @param targetUnits the target units for the values
- * @param bestFit whether or not to use a normalized scale for the family of units
- *
- * @return the formatted values
- */
- public static String[] formatToSignificantPrecision(double[] values, MeasurementUnits targetUnits, boolean bestFit) {
- if ((null == values) || (values.length == 0)) {
- return null;
- }
-
- MeasurementUnits originalUnits = targetUnits;
-
- /*
- * in the overwhelming majority of cases, you're going to want to apply a bestFit
- * to the passed data, but it's not required; it's perfectly possible to allow a
- * list of doubles to be formatted without being fit, in which case the targetUnits
- * will be part of the formatted display for each result element
- */
- if (bestFit) {
- // find bestFit units by taking the average
- Double average = 0.0;
-
- for (int i = 0, sz = values.length; i < sz; i++) {
- /*
- * adding fractional amount iterative leads to greater
- * error, but prevents overflow on large data sets
- */
- average += (values[i] / sz);
- }
-
- MeasurementNumericValueAndUnits fittedAverage = fit(average, targetUnits);
- //noinspection UnnecessaryLocalVariable
- MeasurementUnits fittedUnits = fittedAverage.getUnits();
-
- /*
- * and change the local reference to targetUnits, so that the same logic
- * can be used both for the bestFit and non-bestFit computations
- */
- targetUnits = fittedUnits;
- }
-
- Set<String> existingStrings; // technically this *is* unused because
- int precisionDigits = 0;
- boolean scaleWithMorePrecision = true;
- String[] results = new String[values.length];
- NumberFormat nf = getDefaultNumberFormat();
-
- /*
- * we scale at most to MAX_PRECISION_DIGITS to allow for presentation limits
- *
- * increase the maxPrecisionDigits in the while condition
- * itself to ensure it gets done for every loop
- */
- while (scaleWithMorePrecision && (++precisionDigits <= MAX_PRECISION_DIGITS)) {
- /*
- * make the assumption that we no longer need to scale beyond this iteration
- */
- scaleWithMorePrecision = false;
-
- /*
- * we need to record the uniquely formatted values so we can determine
- */
- existingStrings = new HashSet<String>();
- nf = NumberFormat.getFormat(getFormat(0, precisionDigits));
-
- Double[] scaledValues = new Double[values.length];
-
- for (int i = 0; i < scaledValues.length; i++) {
- /*
- * For relative units apply the scale now, prior to the nf.format(), since we are not using format( Double...).
- * Otherwise, apply standard multi-unit scaling.
- */
- if (MeasurementUnits.Family.RELATIVE == originalUnits.getFamily()) {
- scaledValues[i] = MeasurementUnits.scaleUp(values[i], originalUnits);
- } else {
- scaledValues[i] = scale(new MeasurementNumericValueAndUnits(values[i], originalUnits), targetUnits);
- }
- }
-
- for (int i = 0; i < results.length; i++) {
- /*
- * JUST get the formatted value, specifically DON'T tack on the formatted units yet;
- * we do this to see how many units we'll have to scale to afterwards (outside this
- * while loop) to make the array of values passed to us unique
- */
- String formatted = nf.format(scaledValues[i]);
-
- /*
- * check whether formatted value was in the set or not; if it was, we have to
- * loop, but only if we're not not already at our maximum precision
- */
- boolean wasNewElement = existingStrings.add(formatted);
-
- if ((!wasNewElement) && (precisionDigits < MAX_PRECISION_DIGITS)) {
- scaleWithMorePrecision = true;
- break;
- }
-
- results[i] = formatted;
- }
- }
-
- /*
- * we did the best we could in terms of trying to find a precision that adds the most
- * uniqueness to the given set of values, NOW tack on the formatted value for the units
- */
- for (int i = 0; i < results.length; i++) {
- results[i] = format(results[i], targetUnits);
- }
-
- return results;
- }
-
- public static String format(Double value, MeasurementUnits targetUnits, boolean bestFit) {
- return format(value, targetUnits, bestFit, null, null);
- }
-
- public static String format(Double value, MeasurementUnits targetUnits, boolean bestFit,
- Integer minimumFractionDigits, Integer maximumFractionDigits) {
- if (value == null || Double.isNaN(value)) {
- return NULL_OR_NAN_FORMATTED_VALUE;
- }
- if (bestFit) {
- MeasurementNumericValueAndUnits valueAndUnits = fit(value, targetUnits);
-
- value = valueAndUnits.getValue();
- targetUnits = valueAndUnits.getUnits();
- }
-
- // apply relative scale at presentation time
- if (targetUnits != null && MeasurementUnits.Family.RELATIVE == targetUnits.getFamily()) {
- value = MeasurementUnits.scaleUp(value, targetUnits);
- }
-
- NumberFormat numberFormat = NumberFormat.getFormat(getFormat(
- minimumFractionDigits != null ? minimumFractionDigits : 1,
- maximumFractionDigits != null ? maximumFractionDigits : 1));
-
- String formatted = numberFormat.format(value);
-
- return format(formatted, targetUnits);
- }
-
- public static String scaleAndFormat(Double origin, MeasurementSchedule targetSchedule, boolean bestFit)
- throws MeasurementConversionException {
- MeasurementUnits targetUnits = targetSchedule.getDefinition().getUnits();
-
- return scaleAndFormat(origin, targetUnits, bestFit, null, null);
- }
-
- public static String scaleAndFormat(Double origin, MeasurementUnits targetUnits, boolean bestFit)
- throws MeasurementConversionException {
-
- return scaleAndFormat(origin, targetUnits, bestFit, null, null);
- }
-
- public static String scaleAndFormat(Double origin, MeasurementUnits targetUnits, boolean bestFit,
- Integer minimumFractionDigits, Integer maximumFractionDigits) throws MeasurementConversionException {
-
- MeasurementUnits baseUnits = targetUnits.getBaseUnits();
- MeasurementNumericValueAndUnits valueAndUnits = new MeasurementNumericValueAndUnits(origin, baseUnits);
- Double scaledMagnitude = scale(valueAndUnits, targetUnits);
-
- return format(scaledMagnitude, targetUnits, bestFit);
- }
-
- public static MeasurementNumericValueAndUnits fit(Double origin, MeasurementUnits units) {
- return fit(origin, units, null, null);
- }
-
- public static MeasurementNumericValueAndUnits fit(Double origin, MeasurementUnits units, MeasurementUnits lowUnits,
- MeasurementUnits highUnits) {
-
- // work-around for the various Chart descendants not properly setting their units field;
- if (null == units) {
- return new MeasurementNumericValueAndUnits(origin, units);
- }
-
- // by definition, absolutely specified units don't scale to anything
- if ((MeasurementUnits.Family.ABSOLUTE == units.getFamily())
- || (MeasurementUnits.Family.DURATION == units.getFamily())) {
- return new MeasurementNumericValueAndUnits(origin, units);
- }
-
- // by definition relative-valued units are self-scaled (converted at formatting)
- if (MeasurementUnits.Family.RELATIVE == units.getFamily()) {
- return new MeasurementNumericValueAndUnits(origin, units);
- }
-
- if (MeasurementUnits.Family.TEMPERATURE == units.getFamily()) {
- return new MeasurementNumericValueAndUnits(origin, units);
- }
-
- // if the magnitude is zero, the best-fit also will spin around forever since it won't change
- if (Math.abs(origin) < 1e-9) {
- return new MeasurementNumericValueAndUnits(origin, units);
- }
-
- boolean wasNegative = false;
-
- if (origin < 0) {
- wasNegative = true;
- origin = -origin;
- }
-
- MeasurementNumericValueAndUnits currentValueAndUnits;
- MeasurementNumericValueAndUnits nextValueAndUnits = new MeasurementNumericValueAndUnits(origin, units);
-
- // first, make the value smaller if it's too big
- int maxOrdinal = (highUnits != null) ? (highUnits.ordinal() + 1) : MeasurementUnits.values().length;
-
- do {
- currentValueAndUnits = nextValueAndUnits;
-
- int nextOrdinal = currentValueAndUnits.getUnits().ordinal() + 1;
- if (nextOrdinal == maxOrdinal) {
- // we could theoretically get bigger, but we don't have any units to represent that
- break;
- }
-
- MeasurementUnits biggerUnits = MeasurementUnits.values()[nextOrdinal];
- if (biggerUnits.getFamily() != currentValueAndUnits.getUnits().getFamily()) {
- // we're as big as we can get, break out of the loop so we can return
- break;
- }
-
- Double smallerValue = scale(currentValueAndUnits, biggerUnits);
-
- nextValueAndUnits = new MeasurementNumericValueAndUnits(smallerValue, biggerUnits);
- } while (nextValueAndUnits.getValue() > 1.0);
-
- // next, make the value bigger if it's too small
- int minOrdinal = (lowUnits != null) ? (lowUnits.ordinal() - 1) : -1;
-
- while (currentValueAndUnits.getValue() < 1.0) {
- int nextOrdinal = currentValueAndUnits.getUnits().ordinal() - 1;
- if (nextOrdinal == minOrdinal) {
- // we could theoretically get smaller, but we don't have any units to represent that
- break;
- }
-
- MeasurementUnits smallerUnits = MeasurementUnits.values()[nextOrdinal];
- if (smallerUnits.getFamily() != currentValueAndUnits.getUnits().getFamily()) {
- // we're as small as we can get, break out of the loop so we can return
- break;
- }
-
- Double biggerValue = scale(currentValueAndUnits, smallerUnits);
-
- nextValueAndUnits = new MeasurementNumericValueAndUnits(biggerValue, smallerUnits);
-
- currentValueAndUnits = nextValueAndUnits;
- }
-
- if (wasNegative) {
- return new MeasurementNumericValueAndUnits(-currentValueAndUnits.getValue(), currentValueAndUnits
- .getUnits());
- }
-
- return currentValueAndUnits;
- }
-
- public static String getFormat(int minDigits, int maxDigits) {
- StringBuilder buf = new StringBuilder("0.");
- for (int i = 0; i < minDigits; i++) {
- buf.append("0");
- }
- for (int i = 0; i < (maxDigits - minDigits); i++) {
- buf.append("#");
- }
- return buf.toString();
- }
-}
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/agent/install/RemoteAgentInstallView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/agent/install/RemoteAgentInstallView.java
index 3adcf47..656f171 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/agent/install/RemoteAgentInstallView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/admin/agent/install/RemoteAgentInstallView.java
@@ -45,12 +45,12 @@ import com.smartgwt.client.widgets.layout.VLayout;
import org.rhq.core.domain.install.remote.AgentInstallInfo;
import org.rhq.core.domain.install.remote.AgentInstallStep;
import org.rhq.core.domain.install.remote.RemoteAccessInfo;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.components.view.ViewName;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.gwt.RemoteInstallGWTServiceAsync;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
import org.rhq.enterprise.gui.coregui.client.util.message.Message;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableDynamicForm;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout;
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java
index 5b58ab2..801c06f 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertDataSource.java
@@ -42,11 +42,11 @@ import org.rhq.core.domain.alert.AlertPriority;
import org.rhq.core.domain.alert.notification.AlertNotificationLog;
import org.rhq.core.domain.common.EntityContext;
import org.rhq.core.domain.criteria.AlertCriteria;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.gwt.AlertGWTServiceAsync;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource;
/**
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertFormatUtility.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertFormatUtility.java
index 133683f..26a2477 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertFormatUtility.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/alert/AlertFormatUtility.java
@@ -26,10 +26,10 @@ import org.rhq.core.domain.alert.Alert;
import org.rhq.core.domain.alert.AlertCondition;
import org.rhq.core.domain.alert.AlertConditionCategory;
import org.rhq.core.domain.alert.AlertDefinition;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.Messages;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
/**
* The methods in this class are ported from AlertDefUtil from portal-war and MeasurementFormatter from
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/file/FileListView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/file/FileListView.java
index 305871a..31fce59 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/file/FileListView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/bundle/version/file/FileListView.java
@@ -30,12 +30,12 @@ import com.smartgwt.client.widgets.grid.ListGridRecord;
import org.rhq.core.domain.bundle.BundleFile;
import org.rhq.core.domain.criteria.BundleFileCriteria;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.components.table.Table;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout;
/**
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/platform/PlatformPortletView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/platform/PlatformPortletView.java
index 4a563c7..e04f6f6 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/platform/PlatformPortletView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/dashboard/portlets/platform/PlatformPortletView.java
@@ -36,7 +36,6 @@ import com.smartgwt.client.widgets.layout.HLayout;
import org.rhq.core.domain.criteria.ResourceTypeCriteria;
import org.rhq.core.domain.dashboard.DashboardPortlet;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.measurement.MeasurementData;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDefinition;
@@ -54,6 +53,7 @@ import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.gwt.MeasurementDataGWTServiceAsync;
import org.rhq.enterprise.gui.coregui.client.gwt.ResourceTypeGWTServiceAsync;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.ResourceDataSourceField;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableListGrid;
/**
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/AvailabilityBarView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/AvailabilityBarView.java
index 835f8e5..4abfb0e 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/AvailabilityBarView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/AvailabilityBarView.java
@@ -28,7 +28,6 @@ import com.smartgwt.client.widgets.layout.HLayout;
import org.rhq.core.domain.measurement.Availability;
import org.rhq.core.domain.measurement.AvailabilityType;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.measurement.MeasurementUnits;
import org.rhq.core.domain.resource.Resource;
import org.rhq.core.domain.util.PageControl;
@@ -37,6 +36,7 @@ import org.rhq.core.domain.util.PageOrdering;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.Messages;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
/**
* @author Greg Hinkle
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/LiveGraphView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/LiveGraphView.java
index 6d6f5bc..ca6c27d 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/LiveGraphView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/LiveGraphView.java
@@ -53,13 +53,13 @@ import com.smartgwt.client.widgets.events.CloseClientEvent;
import com.smartgwt.client.widgets.events.MouseOutEvent;
import com.smartgwt.client.widgets.events.MouseOutHandler;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.measurement.MeasurementData;
import org.rhq.core.domain.measurement.MeasurementDataNumeric;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.gwt.MeasurementDataGWTServiceAsync;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableWidgetCanvas;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableWindow;
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/SmallGraphView.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/SmallGraphView.java
index da91f8c..3c751b1 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/SmallGraphView.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/inventory/resource/detail/monitoring/SmallGraphView.java
@@ -52,7 +52,6 @@ import com.smartgwt.client.widgets.events.MouseOutHandler;
import com.smartgwt.client.widgets.layout.HLayout;
import org.rhq.core.domain.criteria.ResourceCriteria;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.measurement.MeasurementDefinition;
import org.rhq.core.domain.measurement.composite.MeasurementDataNumericHighLowComposite;
import org.rhq.core.domain.resource.Resource;
@@ -62,6 +61,7 @@ import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
import org.rhq.enterprise.gui.coregui.client.gwt.ResourceGWTServiceAsync;
import org.rhq.enterprise.gui.coregui.client.inventory.resource.type.ResourceTypeRepository;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableHLayout;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableImg;
import org.rhq.enterprise.gui.coregui.client.util.selenium.LocatableVLayout;
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/report/measurement/MeasurementOOBDataSource.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/report/measurement/MeasurementOOBDataSource.java
index f9657b4..e90e605 100644
--- a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/report/measurement/MeasurementOOBDataSource.java
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/report/measurement/MeasurementOOBDataSource.java
@@ -34,12 +34,12 @@ import com.smartgwt.client.data.fields.DataSourceTextField;
import com.smartgwt.client.widgets.HTMLFlow;
import com.smartgwt.client.widgets.grid.ListGridRecord;
-import org.rhq.core.domain.measurement.MeasurementConverterClient;
import org.rhq.core.domain.measurement.composite.MeasurementOOBComposite;
import org.rhq.core.domain.util.PageControl;
import org.rhq.core.domain.util.PageList;
import org.rhq.enterprise.gui.coregui.client.CoreGUI;
import org.rhq.enterprise.gui.coregui.client.gwt.GWTServiceLookup;
+import org.rhq.enterprise.gui.coregui.client.util.MeasurementConverterClient;
import org.rhq.enterprise.gui.coregui.client.util.RPCDataSource;
/**
diff --git a/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/MeasurementConverterClient.java b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/MeasurementConverterClient.java
new file mode 100644
index 0000000..c538e2b
--- /dev/null
+++ b/modules/enterprise/gui/coregui/src/main/java/org/rhq/enterprise/gui/coregui/client/util/MeasurementConverterClient.java
@@ -0,0 +1,363 @@
+/*
+ * RHQ Management Platform
+ * Copyright (C) 2005-2008 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, version 2, as
+ * published by the Free Software Foundation, and/or the GNU Lesser
+ * General Public License, version 2.1, also as published by the Free
+ * Software Foundation.
+ *
+ * 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 and the GNU Lesser General Public License
+ * for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.rhq.enterprise.gui.coregui.client.util;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import com.google.gwt.i18n.client.NumberFormat;
+
+import org.rhq.core.domain.measurement.MeasurementSchedule;
+import org.rhq.core.domain.measurement.MeasurementUnits;
+import org.rhq.core.domain.measurement.MeasurementUnits.Family;
+import org.rhq.core.domain.measurement.composite.MeasurementNumericValueAndUnits;
+import org.rhq.core.domain.measurement.util.MeasurementConversionException;
+import org.rhq.enterprise.gui.coregui.client.CoreGUI;
+import org.rhq.enterprise.gui.coregui.client.Messages;
+
+public class MeasurementConverterClient {
+ private static final Messages MSG = CoreGUI.getMessages();
+
+ private static final int MAX_PRECISION_DIGITS = 4;
+ private static final String NULL_OR_NAN_FORMATTED_VALUE = MSG.view_measure_nan();
+
+ private static NumberFormat getDefaultNumberFormat() {
+ NumberFormat nf = NumberFormat.getFormat("0.0");
+
+ return nf;
+ }
+
+ public static Double scale(MeasurementNumericValueAndUnits origin, MeasurementUnits targetUnits)
+ throws MeasurementConversionException {
+ MeasurementUnits originUnits = origin.getUnits();
+ Double originValue = origin.getValue();
+
+ return originValue * MeasurementUnits.calculateOffset(originUnits, targetUnits);
+ }
+
+ public static Double scale(Double origin, MeasurementUnits targetUnits) throws MeasurementConversionException {
+ boolean wasNegative = false;
+ if (origin < 0) {
+ wasNegative = true;
+ origin = -origin;
+ }
+
+ MeasurementUnits baseUnit = targetUnits.getBaseUnits();
+ MeasurementNumericValueAndUnits valueAndUnits = new MeasurementNumericValueAndUnits(origin, baseUnit);
+
+ Double results = scale(valueAndUnits, targetUnits);
+ if (wasNegative) {
+ results = -results;
+ }
+
+ return results;
+ }
+
+ public static String format(String value, MeasurementUnits targetUnits) {
+ if (targetUnits == null) {
+ return value;
+ } else {
+ return value + targetUnits;
+ }
+ }
+
+ /**
+ * Formats the given array of double values: determines the necessary precision such that when formatted, they are
+ * distinct and reasonable to look at. For example, for values { 1.45 1.46 1.47 1.48 1.49 } the desired precision is
+ * 2 - less precision loses significant digits, and more precision provides no added benefit. Max precision is
+ * bounded for presentation considerations.
+ *
+ * @param values the values to be formatted
+ * @param targetUnits the target units for the values
+ * @param bestFit whether or not to use a normalized scale for the family of units
+ *
+ * @return the formatted values
+ */
+ public static String[] formatToSignificantPrecision(double[] values, MeasurementUnits targetUnits, boolean bestFit) {
+ if ((null == values) || (values.length == 0)) {
+ return null;
+ }
+
+ MeasurementUnits originalUnits = targetUnits;
+
+ /*
+ * in the overwhelming majority of cases, you're going to want to apply a bestFit
+ * to the passed data, but it's not required; it's perfectly possible to allow a
+ * list of doubles to be formatted without being fit, in which case the targetUnits
+ * will be part of the formatted display for each result element
+ */
+ if (bestFit) {
+ // find bestFit units by taking the average
+ Double average = 0.0;
+
+ for (int i = 0, sz = values.length; i < sz; i++) {
+ /*
+ * adding fractional amount iterative leads to greater
+ * error, but prevents overflow on large data sets
+ */
+ average += (values[i] / sz);
+ }
+
+ MeasurementNumericValueAndUnits fittedAverage = fit(average, targetUnits);
+ //noinspection UnnecessaryLocalVariable
+ MeasurementUnits fittedUnits = fittedAverage.getUnits();
+
+ /*
+ * and change the local reference to targetUnits, so that the same logic
+ * can be used both for the bestFit and non-bestFit computations
+ */
+ targetUnits = fittedUnits;
+ }
+
+ Set<String> existingStrings; // technically this *is* unused because
+ int precisionDigits = 0;
+ boolean scaleWithMorePrecision = true;
+ String[] results = new String[values.length];
+ NumberFormat nf = getDefaultNumberFormat();
+
+ /*
+ * we scale at most to MAX_PRECISION_DIGITS to allow for presentation limits
+ *
+ * increase the maxPrecisionDigits in the while condition
+ * itself to ensure it gets done for every loop
+ */
+ while (scaleWithMorePrecision && (++precisionDigits <= MAX_PRECISION_DIGITS)) {
+ /*
+ * make the assumption that we no longer need to scale beyond this iteration
+ */
+ scaleWithMorePrecision = false;
+
+ /*
+ * we need to record the uniquely formatted values so we can determine
+ */
+ existingStrings = new HashSet<String>();
+ nf = NumberFormat.getFormat(getFormat(0, precisionDigits));
+
+ Double[] scaledValues = new Double[values.length];
+
+ for (int i = 0; i < scaledValues.length; i++) {
+ /*
+ * For relative units apply the scale now, prior to the nf.format(), since we are not using format( Double...).
+ * Otherwise, apply standard multi-unit scaling.
+ */
+ if (MeasurementUnits.Family.RELATIVE == originalUnits.getFamily()) {
+ scaledValues[i] = MeasurementUnits.scaleUp(values[i], originalUnits);
+ } else {
+ scaledValues[i] = scale(new MeasurementNumericValueAndUnits(values[i], originalUnits), targetUnits);
+ }
+ }
+
+ for (int i = 0; i < results.length; i++) {
+ /*
+ * JUST get the formatted value, specifically DON'T tack on the formatted units yet;
+ * we do this to see how many units we'll have to scale to afterwards (outside this
+ * while loop) to make the array of values passed to us unique
+ */
+ String formatted = nf.format(scaledValues[i]);
+
+ /*
+ * check whether formatted value was in the set or not; if it was, we have to
+ * loop, but only if we're not not already at our maximum precision
+ */
+ boolean wasNewElement = existingStrings.add(formatted);
+
+ if ((!wasNewElement) && (precisionDigits < MAX_PRECISION_DIGITS)) {
+ scaleWithMorePrecision = true;
+ break;
+ }
+
+ results[i] = formatted;
+ }
+ }
+
+ /*
+ * we did the best we could in terms of trying to find a precision that adds the most
+ * uniqueness to the given set of values, NOW tack on the formatted value for the units
+ */
+ for (int i = 0; i < results.length; i++) {
+ results[i] = format(results[i], targetUnits);
+ }
+
+ return results;
+ }
+
+ public static String format(Double value, MeasurementUnits targetUnits, boolean bestFit) {
+ return format(value, targetUnits, bestFit, null, null);
+ }
+
+ public static String format(Double value, MeasurementUnits targetUnits, boolean bestFit,
+ Integer minimumFractionDigits, Integer maximumFractionDigits) {
+ if (value == null || Double.isNaN(value)) {
+ return NULL_OR_NAN_FORMATTED_VALUE;
+ }
+ if (bestFit) {
+ MeasurementNumericValueAndUnits valueAndUnits = fit(value, targetUnits);
+
+ value = valueAndUnits.getValue();
+ targetUnits = valueAndUnits.getUnits();
+ }
+
+ // apply relative scale at presentation time
+ if (targetUnits != null && MeasurementUnits.Family.RELATIVE == targetUnits.getFamily()) {
+ value = MeasurementUnits.scaleUp(value, targetUnits);
+ }
+
+ NumberFormat numberFormat = NumberFormat.getFormat(getFormat(
+ minimumFractionDigits != null ? minimumFractionDigits : 1,
+ maximumFractionDigits != null ? maximumFractionDigits : 1));
+
+ String formatted = numberFormat.format(value);
+
+ return format(formatted, targetUnits);
+ }
+
+ public static String scaleAndFormat(Double origin, MeasurementSchedule targetSchedule, boolean bestFit)
+ throws MeasurementConversionException {
+ MeasurementUnits targetUnits = targetSchedule.getDefinition().getUnits();
+
+ return scaleAndFormat(origin, targetUnits, bestFit, null, null);
+ }
+
+ public static String scaleAndFormat(Double origin, MeasurementUnits targetUnits, boolean bestFit)
+ throws MeasurementConversionException {
+
+ return scaleAndFormat(origin, targetUnits, bestFit, null, null);
+ }
+
+ public static String scaleAndFormat(Double origin, MeasurementUnits targetUnits, boolean bestFit,
+ Integer minimumFractionDigits, Integer maximumFractionDigits) throws MeasurementConversionException {
+
+ MeasurementUnits baseUnits = targetUnits.getBaseUnits();
+ MeasurementNumericValueAndUnits valueAndUnits = new MeasurementNumericValueAndUnits(origin, baseUnits);
+ Double scaledMagnitude = scale(valueAndUnits, targetUnits);
+
+ return format(scaledMagnitude, targetUnits, bestFit);
+ }
+
+ public static MeasurementNumericValueAndUnits fit(Double origin, MeasurementUnits units) {
+ return fit(origin, units, null, null);
+ }
+
+ public static MeasurementNumericValueAndUnits fit(Double origin, MeasurementUnits units, MeasurementUnits lowUnits,
+ MeasurementUnits highUnits) {
+
+ // work-around for the various Chart descendants not properly setting their units field;
+ if (null == units) {
+ return new MeasurementNumericValueAndUnits(origin, units);
+ }
+
+ // by definition, absolutely specified units don't scale to anything
+ if ((MeasurementUnits.Family.ABSOLUTE == units.getFamily())
+ || (MeasurementUnits.Family.DURATION == units.getFamily())) {
+ return new MeasurementNumericValueAndUnits(origin, units);
+ }
+
+ // by definition relative-valued units are self-scaled (converted at formatting)
+ if (MeasurementUnits.Family.RELATIVE == units.getFamily()) {
+ return new MeasurementNumericValueAndUnits(origin, units);
+ }
+
+ if (MeasurementUnits.Family.TEMPERATURE == units.getFamily()) {
+ return new MeasurementNumericValueAndUnits(origin, units);
+ }
+
+ // if the magnitude is zero, the best-fit also will spin around forever since it won't change
+ if (Math.abs(origin) < 1e-9) {
+ return new MeasurementNumericValueAndUnits(origin, units);
+ }
+
+ boolean wasNegative = false;
+
+ if (origin < 0) {
+ wasNegative = true;
+ origin = -origin;
+ }
+
+ MeasurementNumericValueAndUnits currentValueAndUnits;
+ MeasurementNumericValueAndUnits nextValueAndUnits = new MeasurementNumericValueAndUnits(origin, units);
+
+ // first, make the value smaller if it's too big
+ int maxOrdinal = (highUnits != null) ? (highUnits.ordinal() + 1) : MeasurementUnits.values().length;
+
+ do {
+ currentValueAndUnits = nextValueAndUnits;
+
+ int nextOrdinal = currentValueAndUnits.getUnits().ordinal() + 1;
+ if (nextOrdinal == maxOrdinal) {
+ // we could theoretically get bigger, but we don't have any units to represent that
+ break;
+ }
+
+ MeasurementUnits biggerUnits = MeasurementUnits.values()[nextOrdinal];
+ if (biggerUnits.getFamily() != currentValueAndUnits.getUnits().getFamily()) {
+ // we're as big as we can get, break out of the loop so we can return
+ break;
+ }
+
+ Double smallerValue = scale(currentValueAndUnits, biggerUnits);
+
+ nextValueAndUnits = new MeasurementNumericValueAndUnits(smallerValue, biggerUnits);
+ } while (nextValueAndUnits.getValue() > 1.0);
+
+ // next, make the value bigger if it's too small
+ int minOrdinal = (lowUnits != null) ? (lowUnits.ordinal() - 1) : -1;
+
+ while (currentValueAndUnits.getValue() < 1.0) {
+ int nextOrdinal = currentValueAndUnits.getUnits().ordinal() - 1;
+ if (nextOrdinal == minOrdinal) {
+ // we could theoretically get smaller, but we don't have any units to represent that
+ break;
+ }
+
+ MeasurementUnits smallerUnits = MeasurementUnits.values()[nextOrdinal];
+ if (smallerUnits.getFamily() != currentValueAndUnits.getUnits().getFamily()) {
+ // we're as small as we can get, break out of the loop so we can return
+ break;
+ }
+
+ Double biggerValue = scale(currentValueAndUnits, smallerUnits);
+
+ nextValueAndUnits = new MeasurementNumericValueAndUnits(biggerValue, smallerUnits);
+
+ currentValueAndUnits = nextValueAndUnits;
+ }
+
+ if (wasNegative) {
+ return new MeasurementNumericValueAndUnits(-currentValueAndUnits.getValue(), currentValueAndUnits
+ .getUnits());
+ }
+
+ return currentValueAndUnits;
+ }
+
+ public static String getFormat(int minDigits, int maxDigits) {
+ StringBuilder buf = new StringBuilder("0.");
+ for (int i = 0; i < minDigits; i++) {
+ buf.append("0");
+ }
+ for (int i = 0; i < (maxDigits - minDigits); i++) {
+ buf.append("#");
+ }
+ return buf.toString();
+ }
+}