Java tutorial
/* * See the NOTICE file distributed with this work for additional * information regarding copyright ownership. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package edu.toronto.cs.phenotips.measurements; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import javax.inject.Inject; import javax.inject.Named; import javax.inject.Provider; import javax.inject.Singleton; import org.apache.commons.lang3.ArrayUtils; import org.slf4j.Logger; import org.xwiki.component.annotation.Component; import org.xwiki.component.manager.ComponentLookupException; import org.xwiki.component.manager.ComponentManager; import org.xwiki.script.service.ScriptService; import edu.toronto.cs.phenotips.measurements.internal.AbstractMeasurementHandler; /** * Bridge offering access to specific {@link MeasurementHandler measurement handlers} to scripts. * * @version $Id: aa7bedfb7907f8b4bc7ad5472cdb677e7d8b7cef $ * @since 1.0M3 */ @Component @Named("measurements") @Singleton public class MeasurementsScriptService implements ScriptService { /** Fuzzy value representing a measurement value considered extremely below normal. */ private static final String VALUE_EXTREME_BELOW_NORMAL = "extreme-below-normal"; /** Fuzzy value representing a measurement value considered below normal, but not extremely. */ private static final String VALUE_BELOW_NORMAL = "below-normal"; /** Fuzzy value representing a measurement value considered normal. */ private static final String VALUE_NORMAL = "normal"; /** Fuzzy value representing a measurement value considered above normal, but not extremely. */ private static final String VALUE_ABOVE_NORMAL = "above-normal"; /** Fuzzy value representing a measurement value considered extremely above normal. */ private static final String VALUE_EXTREME_ABOVE_NORMAL = "extreme-above-normal"; /** Logging helper object. */ @Inject private Logger logger; /** Provides access to the different measurement handlers by name at runtime. */ @Inject @Named("context") private Provider<ComponentManager> componentManager; /** * Get the handler for a specific kind of measurements. * * @param measurementType the type of measurement to return * @return the requested handler, {@code null} if not found */ public MeasurementHandler get(String measurementType) { try { return this.componentManager.get().getInstance(MeasurementHandler.class, measurementType); } catch (ComponentLookupException ex) { this.logger.warn("Requested unknown measurement type [{}]", measurementType); return null; } } /** * Get all the measurements handlers. * * @return a list of all the measurement handlers, or an empty list if there was a problem retrieving the actual * list */ public List<MeasurementHandler> getAvailableMeasurementHandlers() { try { List<MeasurementHandler> result = this.componentManager.get().getInstanceList(MeasurementHandler.class); if (result == null) { result = Collections.emptyList(); } Collections.sort(result, MeasurementSorter.instance); return result; } catch (ComponentLookupException ex) { this.logger.warn("Failed to list available measurements", ex); return Collections.emptyList(); } } /** * Get the names of all the measurements handlers. * * @return a set with the names of all the measurement handlers, or an empty set if there was a problem retrieving * the actual values */ public Set<String> getAvailableMeasurementNames() { try { Map<String, MeasurementHandler> handlers = this.componentManager.get() .getInstanceMap(MeasurementHandler.class); if (handlers != null) { Set<String> result = new TreeSet<String>(MeasurementNameSorter.instance); result.addAll(handlers.keySet()); return result; } } catch (ComponentLookupException ex) { this.logger.warn("Failed to list available measurement types", ex); } return Collections.emptySet(); } /** * Convert a percentile number into a string grossly describing the value. * * @param percentile a number between 0 and 100 * @return the percentile description */ public String getFuzzyValue(int percentile) { String returnValue = VALUE_NORMAL; if (percentile <= 1) { returnValue = VALUE_EXTREME_BELOW_NORMAL; } else if (percentile <= 3) { returnValue = VALUE_BELOW_NORMAL; } else if (percentile >= 99) { returnValue = VALUE_EXTREME_ABOVE_NORMAL; } else if (percentile >= 97) { returnValue = VALUE_ABOVE_NORMAL; } return returnValue; } /** * Convert a standard deviation number into a string grossly describing the value. * * @param deviation standard deviation value * @return the deviation description */ public String getFuzzyValue(double deviation) { String returnValue = VALUE_NORMAL; if (deviation <= -3.0) { returnValue = VALUE_EXTREME_BELOW_NORMAL; } else if (deviation <= -2.0) { returnValue = VALUE_BELOW_NORMAL; } else if (deviation >= 3.0) { returnValue = VALUE_EXTREME_ABOVE_NORMAL; } else if (deviation >= 2.0) { returnValue = VALUE_ABOVE_NORMAL; } return returnValue; } /** * Temporary mechanism for sorting measurements, uses a hardcoded list of measurements in the desired order. * * @version $Id: aa7bedfb7907f8b4bc7ad5472cdb677e7d8b7cef $ */ private static final class MeasurementSorter implements Comparator<MeasurementHandler> { /** Hardcoded list of measurements and their order. */ private static final String[] TARGET_ORDER = new String[] { "weight", "height", "bmi", "armspan", "sitting", "hc", "philtrum", "ear", "ocd", "icd", "pfl", "ipd", "hand", "palm", "foot" }; /** Singleton instance. */ private static MeasurementSorter instance = new MeasurementSorter(); @Override public int compare(MeasurementHandler o1, MeasurementHandler o2) { String n1 = ((AbstractMeasurementHandler) o1).getName(); String n2 = ((AbstractMeasurementHandler) o2).getName(); int p1 = ArrayUtils.indexOf(TARGET_ORDER, n1); int p2 = ArrayUtils.indexOf(TARGET_ORDER, n2); if (p1 == -1 && p2 == -1) { return n1.compareTo(n2); } else if (p1 == -1) { return 1; } else if (p2 == -1) { return -1; } return p1 - p2; } } /** * Temporary mechanism for sorting measurements, uses a hardcoded list of measurements in the desired order. * * @version $Id: aa7bedfb7907f8b4bc7ad5472cdb677e7d8b7cef $ */ private static final class MeasurementNameSorter implements Comparator<String> { /** Singleton instance. */ private static MeasurementNameSorter instance = new MeasurementNameSorter(); @Override public int compare(String n1, String n2) { int p1 = ArrayUtils.indexOf(MeasurementSorter.TARGET_ORDER, n1); int p2 = ArrayUtils.indexOf(MeasurementSorter.TARGET_ORDER, n2); if (p1 == -1 && p2 == -1) { return n1.compareTo(n2); } else if (p1 == -1) { return 1; } else if (p2 == -1) { return -1; } return p1 - p2; } } }