Mercurial > dive4elements > river
diff flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.java @ 3468:f37e7e8907cb
merged flys-artifacts/2.8.1
author | Thomas Arendsen Hein <thomas@intevation.de> |
---|---|
date | Fri, 28 Sep 2012 12:14:39 +0200 |
parents | f903f1e5aed6 |
children | 8490faba00e7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/flys-artifacts/src/main/java/de/intevation/flys/utils/FLYSUtils.java Fri Sep 28 12:14:39 2012 +0200 @@ -0,0 +1,930 @@ +package de.intevation.flys.utils; + +import org.apache.log4j.Logger; + +import java.text.NumberFormat; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import javax.xml.xpath.XPathConstants; + +import org.w3c.dom.Document; + +import org.hibernate.SessionFactory; +import org.hibernate.impl.SessionFactoryImpl; + +import gnu.trove.TDoubleArrayList; +import gnu.trove.TIntArrayList; +import gnu.trove.TLongArrayList; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; + +import de.intevation.artifacts.common.utils.Config; +import de.intevation.artifacts.common.utils.XMLUtils; + +import de.intevation.flys.backend.SessionFactoryProvider; + +import de.intevation.flys.artifacts.context.FLYSContext; +import de.intevation.flys.artifacts.FLYSArtifact; +import de.intevation.flys.artifacts.WINFOArtifact; +import de.intevation.flys.artifacts.StaticWKmsArtifact; +import de.intevation.flys.artifacts.model.RiverFactory; +import de.intevation.flys.artifacts.model.LocationProvider; +import de.intevation.flys.artifacts.model.WQ; +import de.intevation.flys.artifacts.model.WKms; +import de.intevation.flys.artifacts.model.WQKms; + +import de.intevation.artifactdatabase.state.State; +import de.intevation.flys.artifacts.states.WaterlevelSelectState; +import de.intevation.flys.artifacts.states.WDifferencesState; +import de.intevation.flys.model.Gauge; +import de.intevation.flys.model.MainValue; +import de.intevation.flys.model.River; + + +/** static helper methods to e.g. access FLYSArtifacts data. */ +public class FLYSUtils { + + /** The logger that is used in this utility. */ + private static Logger logger = Logger.getLogger(FLYSUtils.class); + + public static enum KM_MODE { RANGE, LOCATIONS, NONE }; + + /** + * An enum that represents the 5 possible WQ modes in FLYS. The 5 values are + * <i>QFREE</i> <i>QGAUGE</i> <i>WGAUGE</i> <i>WFREE</i> and <i>NONE</i>. + */ + public static enum WQ_MODE { QFREE, QGAUGE, WFREE, WGAUGE, NONE }; + + /** + * An enum that represents the 4 possible WQ input modes in FLYS. The 4 + * values are + * <i>ADAPTED</i> <i>SINGLE</i> <i>RANGE</i> and <i>NONE</i>. + */ + public static enum WQ_INPUT { ADAPTED, SINGLE, RANGE, NONE }; + + public static final Pattern NUMBERS_PATTERN = + Pattern.compile("\\D*(\\d++.\\d*)\\D*"); + + public static final String XPATH_RIVER_PROJECTION = + "/artifact-database/floodmap/river[@name=$name]/srid/@value"; + + public static final String XPATH_SHAPEFILE_DIR = + "/artifact-database/floodmap/shapefile-path/@value"; + + public static final String XPATH_VELOCITY_LOGFILE = + "/artifact-database/floodmap/velocity/logfile/@path"; + + public static final String XPATH_MAPSERVER_URL = + "/artifact-database/floodmap/mapserver/server/@path"; + + public static final String XPATH_MAPFILE_PATH = + "/artifact-database/floodmap/mapserver/mapfile/@path"; + + public static final String XPATH_MAPFILE_TEMPLATE = + "/artifact-database/floodmap/mapserver/map-template/@path"; + + public static final String XPATH_MAPSERVER_TEMPLATE_PATH = + "/artifact-database/floodmap/mapserver/templates/@path"; + + + private FLYSUtils() { + } + + + /** + * Pulls Artifact with given UUID fromm database. + * @return FLYSArtifact with given UUID or null (in case of errors). + */ + public static FLYSArtifact getArtifact(String uuid, CallContext context) { + try { + Artifact artifact = context.getDatabase().getRawArtifact(uuid); + + if (artifact == null) { + logger.error("Artifact '" + uuid + "' does not exist."); + return null; + } + + if (!(artifact instanceof FLYSArtifact)) { + logger.error("Artifact '" +uuid+ "' is no valid FLYSArtifact."); + return null; + } + + return (FLYSArtifact) artifact; + } + // TODO: catch more selective + catch (Exception e) { + logger.error("Cannot get FLYSArtifact " + uuid + + " from database (" + e.getMessage() + ")."); + return null; + } + } + + + /** + * Returns the FLYSContext from context object. + * + * @param context The CallContext or the FLYSContext. + * + * @return the FLYSContext. + */ + public static FLYSContext getFlysContext(Object context) { + return context instanceof FLYSContext + ? (FLYSContext) context + : (FLYSContext) ((CallContext) context).globalContext(); + } + + + /** + * Convinience function to retrieve an XPath as string with replaced config + * directory. + * + * @param xpath The XPath expression. + * + * @return a string with replaced config directory. + */ + public static String getXPathString(String xpath) { + String tmp = Config.getStringXPath(xpath); + tmp = Config.replaceConfigDir(tmp); + + return tmp; + } + + + public static boolean isUsingOracle() { + SessionFactory sf = SessionFactoryProvider.getSessionFactory(); + + String d = SessionFactoryProvider.getDriver((SessionFactoryImpl) sf); + + return d != null ? d.indexOf("Oracle") >= 0 : false; + } + + + /** + * This method returns an WQ_MODE enum which is based on the parameters + * stored in <i>flys</i> Artifact. If there is no <i>wq_isq</i> parameter + * existing, WQ_MODE.NONE is returned. + * + * @param flys The FLYSArtifact that stores wq mode relevant parameters. + * + * @return an enum WQ_MODE. + */ + public static WQ_MODE getWQMode(FLYSArtifact flys) { + if (flys == null) { + return WQ_MODE.NONE; + } + + String values = flys.getDataAsString("wq_values"); + Boolean isQ = flys.getDataAsBoolean("wq_isq"); + + if (values != null) { + return isQ ? WQ_MODE.QGAUGE : WQ_MODE.WGAUGE; + } + + Boolean isFree = flys.getDataAsBoolean("wq_isfree"); + + if (isQ) { + return isFree ? WQ_MODE.QFREE : WQ_MODE.QGAUGE; + } + else if (!isQ) { + return isFree ? WQ_MODE.WFREE : WQ_MODE.WGAUGE; + } + else { + return WQ_MODE.NONE; + } + } + + + public static WQ_INPUT getWQInputMode(FLYSArtifact flys) { + if (flys == null) { + return WQ_INPUT.NONE; + } + + Boolean selection = flys.getDataAsBoolean("wq_isrange"); + String adapted = flys.getDataAsString("wq_values"); + + if(adapted != null && adapted.length() > 0) { + return WQ_INPUT.ADAPTED; + } + + if (selection != null && selection) { + return WQ_INPUT.RANGE; + } + else { + return WQ_INPUT.SINGLE; + } + } + + public static KM_MODE getKmRangeMode(FLYSArtifact flys) { + String mode = flys.getDataAsString("ld_mode"); + + if (mode == null || mode.length() == 0) { + return KM_MODE.NONE; + } + else if (mode.equals("distance")) { + return KM_MODE.RANGE; + } + else if (mode.equals("locations")) { + return KM_MODE.LOCATIONS; + } + else { + return KM_MODE.NONE; + } + } + + /** + * Get min and max kilometer, independent of parametization + * (ld_from/to vs ld_locations). + */ + public static double[] getKmRange(FLYSArtifact flys) { + switch (getKmRangeMode(flys)) { + case RANGE: { + return getKmFromTo(flys); + } + + case LOCATIONS: { + double[] locs = getLocations(flys); + return new double[] { locs[0], locs[locs.length-1] }; + } + + case NONE: { + double[] locs = getLocations(flys); + if (locs != null) { + return new double[] { locs[0], locs[locs.length-1] }; + } + else { + return getKmFromTo(flys); + } + } + } + + return new double[] { Double.NaN, Double.NaN }; + } + + + /** + * Get bounds for river of artifact. + * @param flysArtifact artifact which has a "river" data. + * @return double array. min is at[0], max at[1]. null if given artifact is null + */ + public static double[] getRiverMinMax(FLYSArtifact flysArtifact) { + if (flysArtifact == null) { + return null; + } + + String riverName = flysArtifact.getDataAsString("river"); + + if (riverName == null) { + riverName = ""; + } + + logger.debug("Search for the min/max distances of '" + riverName + "'"); + + River river = RiverFactory.getRiver(riverName); + + return river != null + ? river.determineMinMaxDistance() + : null; + } + + + public static double[] getKmFromTo(FLYSArtifact flys) { + String strFrom = flys.getDataAsString("ld_from"); + String strTo = flys.getDataAsString("ld_to"); + + if (strFrom == null) { + strFrom = flys.getDataAsString("from"); + } + + if (strTo == null) { + strTo = flys.getDataAsString("to"); + } + + if (strFrom == null || strTo == null) { + return null; + } + + try { + return new double[] { + Double.parseDouble(strFrom), + Double.parseDouble(strTo) }; + } + catch (NumberFormatException nfe) { + return null; + } + } + + + /** + * Return sorted array of locations at which stuff was calculated + * (from ld_locations data), null if not parameterized this way. + */ + public static double[] getLocations(FLYSArtifact flys) { + String locationStr = flys.getDataAsString("ld_locations"); + + if (locationStr == null || locationStr.length() == 0) { + if (flys instanceof WINFOArtifact) { + WINFOArtifact winfo = (WINFOArtifact) flys; + if (winfo.getReferenceStartKm() != null) { + return new double[] + { + winfo.getReferenceStartKm().doubleValue(), + winfo.getReferenceEndKms()[0] + }; + } + } + return null; + } + + String[] tmp = locationStr.split(" "); + TDoubleArrayList locations = new TDoubleArrayList(); + + for (String l: tmp) { + try { + locations.add(Double.parseDouble(l)); + } + catch (NumberFormatException nfe) { + } + } + + locations.sort(); + + return locations.toNativeArray(); + } + + + /** + * Returns the Qs for a given FLYSArtifact. This method currently accepts + * only instances of WINFOArtifact. + * + * @param flys A FLYSArtifact. + * + * @return the Qs. + */ + public static double[] getQs(FLYSArtifact flys) { + // XXX this is not nice! + if (flys instanceof WINFOArtifact) { + return ((WINFOArtifact) flys).getQs(); + } + + logger.warn("This method currently supports WINFOArtifact only!"); + + return null; + } + + + /** + * Returns the Ws for a given FLYSArtifact. This method currently accepts + * only instances of WINFOArtifact. + * + * @param flys A FLYSArtifact. + * + * @return the Ws. + */ + public static double[] getWs(FLYSArtifact flys) { + // XXX this is not nice! + if (flys instanceof WINFOArtifact) { + return ((WINFOArtifact) flys).getWs(); + } + + logger.warn("This method currently supports WINFOArtifact only!"); + + return null; + } + + + /** + * Returns the selected River object based on the 'river' data that might + * have been inserted by the user. + * + * @return the selected River or null if no river has been chosen yet. + */ + public static River getRiver(FLYSArtifact flys) { + String sRiver = getRivername(flys); + + return (sRiver != null) + ? RiverFactory.getRiver(sRiver) + : null; + } + + + /** + * Returns the name of the river specified in the given <i>flys</i> + * Artifact. + * + * @param flys The FLYSArtifact that stores a river relevant information. + * + * @return the name of the specified river or null. + */ + public static String getRivername(FLYSArtifact flys) { + return flys != null ? flys.getDataAsString("river") : null; + } + + + /** + * Extracts the SRID defined in the global configuration for the river + * specified in <i>artifact</i>. + * + * @param artifact The FLYSArtifact that stores the name of the river. + * + * @return the SRID as string (e.g. "31466"). + */ + public static String getRiverSrid(FLYSArtifact artifact) { + String river = artifact.getDataAsString("river"); + + if (river == null || river.length() == 0) { + return null; + } + + return getRiverSrid(river); + } + + + public static String getRiverSrid(String rivername) { + Map<String, String> variables = new HashMap<String, String>(1); + variables.put("name", rivername); + + Document cfg = Config.getConfig(); + + return (String) XMLUtils.xpath( + cfg, + XPATH_RIVER_PROJECTION, + XPathConstants.STRING, + null, + variables); + } + + + /** + * Return the (first) Gauge corresponding to the given location(s) of + * the artifact. + * @param flys the artifact in question. + * @return (First) gauge of locations of river of artifact. + */ + public static Gauge getGauge(FLYSArtifact flys) { + River river = getRiver(flys); + + if (river == null) { + logger.debug("no river found"); + return null; + } + + double[] dist = getKmRange(flys); + + if (dist == null) { + logger.debug("no range found"); + return null; + } + + if (logger.isDebugEnabled()) { + logger.debug("Determine gauge for:"); + logger.debug("... river: " + river.getName()); + logger.debug("... distance: " + dist[0] + " - " + dist[1]); + } + + Gauge gauge = river.determineGauge(dist[0], dist[1]); + + String name = gauge != null ? gauge.getName() : "'n/a"; + logger.debug("Found gauge: " + name); + + return gauge; + } + + + public static String getGaugename(FLYSArtifact flys) { + Gauge gauge = getGauge(flys); + + return gauge != null ? gauge.getName() : null; + } + + + public static Gauge getReferenceGauge(FLYSArtifact flys) { + Long officialNumber = flys.getDataAsLong("reference_gauge"); + + return officialNumber != null + ? Gauge.getGaugeByOfficialNumber(officialNumber) + : null; + } + + + public static String getReferenceGaugeName(FLYSArtifact flys) { + Gauge refGauge = getReferenceGauge(flys); + + return refGauge != null + ? refGauge.getName() + : "-- not found --"; + } + + + public static Double getValueFromWQ(WQ wq) { + if (wq == null) { + return null; + } + + Matcher m = NUMBERS_PATTERN.matcher(wq.getName()); + + if (m.matches()) { + logger.debug("Found a number."); + + String raw = m.group(1); + + try { + return Double.valueOf(raw); + } + catch (NumberFormatException nfe) { + } + } + + return null; + } + + + public static String createWspWTitle( + WINFOArtifact winfo, + CallContext cc, + String name + ) { + String[] parts = name.split("="); + + NumberFormat nf = Formatter.getWaterlevelW(cc); + + String namedMainValue = null; + + boolean isQ = winfo.isQ(); + boolean isFree = winfo.isFreeQ(); + + double v; + + try { + v = Double.valueOf(parts[1]); + + namedMainValue = getNamedMainValue(winfo.getGauge(), v); + } + catch (NumberFormatException nfe) { + logger.warn("Cannot parse Double of: '" + parts[1] + "'"); + return name; + } + + String prefix = null; + + if (isQ && !isFree && namedMainValue != null) { + return "W (" + namedMainValue + ")"; + } + + if (isQ) { + prefix = "Q="; + } + + return prefix == null + ? "W(" + nf.format(v) + ")" + : "W(" + prefix + nf.format(v) + ")"; + } + + + public static String createWspQTitle( + WINFOArtifact winfo, + CallContext cc, + String name + ) { + String[] parts = name.split("="); + + NumberFormat nf = Formatter.getWaterlevelQ(cc); + + String namedMainValue = null; + + boolean isQ = winfo.isQ(); + boolean isFree = winfo.isFreeQ(); + + double v; + + try { + v = Double.valueOf(parts[1]); + + namedMainValue = getNamedMainValue(winfo.getGauge(), v); + } + catch (NumberFormatException nfe) { + logger.warn("Cannot parse Double of: '" + parts[1] + "'"); + return name; + } + + String prefix = null; + + if (isQ && !isFree && namedMainValue != null) { + return namedMainValue; + } + + if (!isQ) { + prefix = "W="; + } + + return prefix == null + ? "Q(" + nf.format(v) + ")" + : "Q(" + prefix + nf.format(v) + ")"; + } + + + /** + * Returns the named main value if a Q was selected and if this Q fits to a + * named main value. Otherwise, this function returns null. + * + * @param winfo The WINFO Artifact. + * @param value The Q (or W) value. + * + * @return a named main value or null. + */ + public static String getNamedMainValue(WINFOArtifact winfo, double value) { + WQ_MODE wqmode = getWQMode(winfo); + + if (wqmode != WQ_MODE.QGAUGE) { + return null; + } + else { + return getNamedMainValue(winfo.getGauge(), value); + } + } + + + public static String getNamedMainValue(Gauge gauge, double value) { + List<MainValue> mainValues = gauge.getMainValues(); + logger.debug("Search named main value for: " + value); + + for (MainValue mv: mainValues) { + if (mv.getValue().doubleValue() == value) { + logger.debug("Found named main value: " + mv.getMainValue().getName()); + return mv.getMainValue().getName(); + } + } + + logger.debug("Did not find a named main value for: " + value); + return null; + } + + + /** + * + * @param nmv A string that represents a named main value. + * + * @throws NullPointerException if nmv is null. + */ + public static String stripNamedMainValue(String nmv) { + int startIndex = nmv.indexOf("("); + int endIndex = nmv.indexOf(")"); + + if (startIndex > 0 && endIndex > 0 && startIndex < endIndex) { + return nmv.substring(0, startIndex); + } + + return nmv; + } + + + /** + * Returns the URL of user mapfile for the owner of Artifact + * <i>artifactId</i>. + * + * @param artifactId The UUID of an artifact. + * + * @return the URL of the user wms. + */ + public static String getUserWMSUrl(String artifactId) { + String url = getXPathString(XPATH_MAPSERVER_URL); + url = url.endsWith("/") ? url + "user-wms" : url + "/" + "user-wms"; + + return url; + } + + + /** + * This method returns the description for a given <i>km</i> for a specific + * river. The river is provided by the FLYSArtifact <i>flys</i>. + * + * @param flys The FLYSArtifact that provides a river. + * @param km The kilometer. + * + * @return the description for <i>km</i> or an empty string if no + * description was found. + */ + public static String getLocationDescription(FLYSArtifact flys, double km) { + String river = getRivername(flys); + + if (river == null) { + return ""; + } + + return LocationProvider.getLocation(river, km); + } + + + /** + * This method returns the differences for a w-differences calculation. + * + * @param winfo The WINFOArtifact. + * @param context The context. + * + * @return The differences as string separated by semicolon and linebreak. + */ + public static String getWDifferences( + WINFOArtifact winfo, + CallContext context) + { + State state = winfo.getCurrentState(context); + if(state instanceof WDifferencesState) { + String diffids = winfo.getDataAsString("diffids"); + String datas[] = diffids.split("#"); + + // Validate the Data-Strings. + for (String s: datas) { + if (!WaterlevelSelectState.isValueValid(winfo.getDataAsString("diffids"))) { + return ""; + } + } + + if (datas.length < 2) { + return ""; + } + + String diffs = ""; + for(int i = 0; i < datas.length; i+=2) { + // e.g.: + // 42537f1e-3522-42ef-8968-635b03d8e9c6;longitudinal_section.w;1 + WKms minuendWKms = getWKms(StringUtil.unbracket(datas[i+0]), + context); + WKms subtrahendWKms = getWKms(StringUtil.unbracket(datas[i+1]), + context); + if (minuendWKms != null && subtrahendWKms != null) { + diffs += StringUtil.wWrap(minuendWKms.getName()) + + " - " + StringUtil.wWrap(subtrahendWKms.getName()); + } + diffs += ";\n"; + } + return diffs; + } + else { + logger.warn("Not a valid state for differences."); + return ""; + } + } + + + protected static WKms getWKms(String mingle, CallContext context) { + String[] def = mingle.split(";"); + String uuid = def[0]; + String name = def[1]; + int idx = Integer.parseInt(def[2]); + + if (name.startsWith("staticwkms")) { + StaticWKmsArtifact staticWKms = + (StaticWKmsArtifact) FLYSUtils.getArtifact( + uuid, + context); + WKms wkms = staticWKms.getWKms(idx); + if (wkms == null) + logger.error("No WKms from artifact."); + return wkms; + } + + WINFOArtifact flys = (WINFOArtifact) FLYSUtils.getArtifact( + uuid, + context); + + if (flys == null) { + logger.warn("One of the artifacts (1) for diff calculation could not be loaded"); + return null; + } + else{ + WQKms[] wqkms = (WQKms[]) flys.getWaterlevelData(). + getData(); + if (wqkms == null) + logger.warn("not waterlevels in artifact"); + else if (wqkms.length < idx) + logger.warn("not enough waterlevels in artifact"); + return wqkms[idx]; + } + } + + + /** + * This method transform a string into an int array. Therefore, the string + * <i>raw</i> must consist of int values separated by a <i>';'</i>. + * + * @param raw The raw integer array as string separated by a ';'. + * + * @return an array of int values. + */ + public static int[] intArrayFromString(String raw) { + String[] splitted = raw != null ? raw.split(";") : null; + + if (splitted == null || splitted.length == 0) { + logger.warn("No integer values found in '" + raw + "'"); + return new int[0]; + } + + TIntArrayList integers = new TIntArrayList(splitted.length); + + for (String value: splitted) { + try { + integers.add(Integer.parseInt(value)); + } + catch (NumberFormatException nfe) { + logger.warn("Parsing integer failed: " + nfe); + } + } + + return integers.toNativeArray(); + } + + + /** + * This method transform a string into a long array. Therefore, the string + * <i>raw</i> must consist of int values separated by a <i>';'</i>. + * + * @param raw The raw long array as string separated by a ';'. + * + * @return an array of int values. + */ + public static long[] longArrayFromString(String raw) { + String[] splitted = raw != null ? raw.split(";") : null; + + if (splitted == null || splitted.length == 0) { + logger.warn("No long values found in '" + raw + "'"); + return new long[0]; + } + + TLongArrayList longs = new TLongArrayList(splitted.length); + + for (String value: splitted) { + try { + longs.add(Long.valueOf(value)); + } + catch (NumberFormatException nfe) { + logger.warn("Parsing long failed: " + nfe); + } + } + + return longs.toNativeArray(); + } + + + /** + * This method transform a string into an double array. Therefore, the + * string <i>raw</i> must consist of double values separated by a + * <i>';'</i>. + * + * @param raw The raw double array as string separated by a ';'. + * + * @return an array of double values. + */ + public static double[] doubleArrayFromString(String raw) { + String[] splitted = raw != null ? raw.split(";") : null; + + if (splitted == null || splitted.length == 0) { + logger.warn("No double values found in '" + raw + "'"); + return new double[0]; + } + + TDoubleArrayList doubles = new TDoubleArrayList(splitted.length); + + for (String value: splitted) { + try { + doubles.add(Double.valueOf(value)); + } + catch (NumberFormatException nfe) { + logger.warn("Parsing double failed: " + nfe); + } + } + + return doubles.toNativeArray(); + } + + + /** + * Returns the gauges that match the selected kilometer range. + * + * @param flys the flys artifact. + * + * @return the gauges based on the selected kilometer range (null if + * none/no range set). + */ + public static List<Gauge> getGauges(FLYSArtifact flys) { + + River river = getRiver(flys); + if (river == null) { + logger.debug("getGauges: no river!"); + return null; + } + + double [] dist = getKmRange(flys); + if (dist == null) { + logger.debug("getGauges: no dist!"); + return null; + } + logger.debug("getGauges: " + dist[0] + " - " + dist[1]); + + return river.determineGauges(dist[0], dist[1]); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :