Mercurial > dive4elements > river
view artifacts/src/main/java/org/dive4elements/river/utils/RiverUtils.java @ 8186:a1ceacf15d3a
Removed NASTY package clash. We had too org.dive4elements.river.util packages.
author | Sascha L. Teichmann <teichmann@intevation.de> |
---|---|
date | Thu, 04 Sep 2014 13:00:55 +0200 |
parents | 4daaf5e51dfb |
children | e4606eae8ea5 |
line wrap: on
line source
/* Copyright (C) 2011, 2012, 2013 by Bundesanstalt für Gewässerkunde * Software engineering by Intevation GmbH * * This file is Free Software under the GNU AGPL (>=v3) * and comes with ABSOLUTELY NO WARRANTY! Check out the * documentation coming with Dive4Elements River for details. */ package org.dive4elements.river.utils; import org.dive4elements.artifactdatabase.state.State; import org.dive4elements.artifacts.Artifact; import org.dive4elements.artifacts.ArtifactNamespaceContext; import org.dive4elements.artifacts.CallContext; import org.dive4elements.artifacts.common.utils.Config; import org.dive4elements.artifacts.common.utils.XMLUtils; import org.dive4elements.river.artifacts.D4EArtifact; import org.dive4elements.river.artifacts.WINFOArtifact; import org.dive4elements.river.artifacts.access.RangeAccess; import org.dive4elements.river.artifacts.context.RiverContext; import org.dive4elements.river.artifacts.model.LocationProvider; import org.dive4elements.river.artifacts.model.RiverFactory; import org.dive4elements.river.artifacts.model.WKms; import org.dive4elements.river.artifacts.model.WQ; import org.dive4elements.river.artifacts.states.WDifferencesState; import org.dive4elements.river.artifacts.states.WaterlevelSelectState; import org.dive4elements.river.backend.SessionFactoryProvider; import org.dive4elements.river.model.Gauge; import org.dive4elements.river.model.MainValue; import org.dive4elements.river.model.River; import org.dive4elements.river.backend.utils.StringUtil; import gnu.trove.TDoubleArrayList; import gnu.trove.TIntArrayList; import gnu.trove.TLongArrayList; 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.apache.log4j.Logger; import org.hibernate.SessionFactory; import org.hibernate.impl.SessionFactoryImpl; import org.w3c.dom.Document; /** * Static helper methods to e.g. access D4EArtifacts data. * * @deprecated Don't use RiverUtils to get data from an {@link Artifact} anymore. * Instead use and/or create a {@link Access} class hierarchy. **/ @Deprecated public class RiverUtils { /** The logger that is used in this utility. */ private static Logger logger = Logger.getLogger(RiverUtils.class); /** * 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_FLOODMAP_RIVER_PROJECTION = "/artifact-database/floodmap/river[@name=$name]/srid/@value"; public static final String XPATH_FLOODMAP_SHAPEFILE_DIR = "/artifact-database/floodmap/shapefile-path/@value"; public static final String XPATH_FLOODMAP_VELOCITY_LOGFILE = "/artifact-database/floodmap/velocity/logfile/@path"; public static final String XPATH_FLOODMAP_MAPSERVER_URL = "/artifact-database/floodmap/mapserver/server/@path"; public static final String XPATH_RIVERMAP_MAPSERVER_URL = "/artifact-database/rivermap/mapserver/server/@path"; public static final String XPATH_FLOODMAP_MAPFILE_PATH = "/artifact-database/floodmap/mapserver/mapfile/@path"; public static final String XPATH_FLOODMAP_MAPFILE_TEMPLATE = "/artifact-database/floodmap/mapserver/map-template/@path"; public static final String XPATH_FLOODMAP_MAPSERVER_TEMPLATE_PATH = "/artifact-database/floodmap/mapserver/templates/@path"; public static final String CURRENT_KM = "currentKm"; public static final String XPATH_CHART_CURRENTKM = "/art:action/art:attributes/art:currentKm/@art:km"; private RiverUtils() { } /** * Pulls Artifact with given UUID fromm database. * @return D4EArtifact with given UUID or null (in case of errors). */ public static D4EArtifact 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 D4EArtifact)) { logger.error("Artifact '" +uuid+ "' is no valid D4EArtifact."); return null; } return (D4EArtifact) artifact; } // TODO: catch more selective catch (Exception e) { logger.error("Cannot get D4EArtifact " + uuid + " from database (" + e.getMessage() + ")."); return null; } } /** * Returns the RiverContext from context object. * * @param context The CallContext or the RiverContext. * * @return the RiverContext. */ public static RiverContext getFlysContext(Object context) { return context instanceof RiverContext ? (RiverContext) context : (RiverContext) ((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; } /** * 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 D4EArtifact that stores wq mode relevant parameters. * * @return an enum WQ_MODE. */ public static WQ_MODE getWQMode(D4EArtifact 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 != null && isQ) { return isFree ? WQ_MODE.QFREE : WQ_MODE.QGAUGE; } else if (isQ != null && !isQ) { return isFree ? WQ_MODE.WFREE : WQ_MODE.WGAUGE; } else { return WQ_MODE.NONE; } } public static WQ_INPUT getWQInputMode(D4EArtifact 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; } } /** * 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(D4EArtifact 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 + "'"); // Why not use getRiver(flysArtifact) ? River river = RiverFactory.getRiver(riverName); return river != null ? river.determineMinMaxDistance() : null; } public static double[] getKmFromTo(D4EArtifact 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. */ // TODO moved to RangeAccess. Resolve remaining calls. private static double[] getLocations(D4EArtifact 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 && winfo.getReferenceEndKms() != 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) { logger.debug(nfe.getLocalizedMessage(), nfe); } } locations.sort(); return locations.toNativeArray(); } /** * Returns the Qs for a given D4EArtifact. This method currently accepts * only instances of WINFOArtifact. * * @param flys A D4EArtifact. * * @return the Qs. */ public static double[] getQs(D4EArtifact flys) { // XXX this is not nice! if (flys instanceof WINFOArtifact) { return ((WINFOArtifact) flys).getQs(); } logger.warn("This method (getQs) currently supports WINFOArtifact only!"); return null; } /** * Returns the Ws for a given D4EArtifact. This method currently accepts * only instances of WINFOArtifact. * * @param flys A D4EArtifact. * * @return the Ws. */ public static double[] getWs(D4EArtifact flys) { // XXX this is not nice! if (flys instanceof WINFOArtifact) { return ((WINFOArtifact) flys).getWs(); } logger.warn("This method (getWs) currently supports WINFOArtifact only!"); return null; } /** * Returns the selected River object based on the 'river' data that might * have been inserted by the user. * * @deprecated - use RiverAccess instead * * @return the selected River or null if no river has been chosen yet. */ public static River getRiver(D4EArtifact 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 D4EArtifact that stores a river relevant information. * * @return the name of the specified river or null. */ public static String getRivername(D4EArtifact 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 D4EArtifact that stores the name of the river. * * @return the SRID as string (e.g. "31466"). */ public static String getRiverSrid(D4EArtifact 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_FLOODMAP_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(D4EArtifact flys) { River river = getRiver(flys); if (river == null) { logger.debug("no river found"); return null; } RangeAccess rangeAccess = new RangeAccess(flys); double[] dist = rangeAccess.getKmRange(); 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(D4EArtifact flys) { Gauge gauge = getGauge(flys); return gauge != null ? gauge.getName() : null; } public static Gauge getReferenceGauge(D4EArtifact flys) { Long officialNumber = flys.getDataAsLong("reference_gauge"); String river = getRivername(flys); if (officialNumber != null && river != null) { return Gauge.getGaugeByOfficialNumber(officialNumber, river); } else if (officialNumber != null) { return Gauge.getGaugeByOfficialNumber(officialNumber); } return null; } public static String getReferenceGaugeName(D4EArtifact 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; } /** Creates human-readable name for a wsp (waterlevel/longitudinal section). * @param name will be split at '='s. */ 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_FLOODMAP_MAPSERVER_URL); url = url.endsWith("/") ? url + "user-wms" : url + "/" + "user-wms"; return url; } public static String getRiverWMSUrl() { String url = getXPathString(XPATH_RIVERMAP_MAPSERVER_URL); url = url.endsWith("/") ? url + "river-wms" : url + "/" + "river-wms"; return url; } /** * Returns the description for a given <i>km</i> for a specific * river. The river is provided by the D4EArtifact <i>flys</i>. * * @param flys The D4EArtifact 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(D4EArtifact flys, double km) { String river = getRivername(flys); if (river == null) { return ""; } return LocationProvider.getLocation(river, km); } /** * 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) { WDifferencesState wState = (WDifferencesState) state; String diffids = winfo.getDataAsString("diffids"); String datas[] = diffids.split("#"); // Validate the Data-Strings. for (String s: datas) { if (!WaterlevelSelectState.isValueValid(s)) { 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 = wState.getWKms(StringUtil.unbracket(datas[i+0]), context); WKms subtrahendWKms = wState.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 ""; } } /** * 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(); } /** * 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(); } /** * 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(D4EArtifact flys) { River river = getRiver(flys); if (river == null) { logger.debug("getGauges: no river!"); return null; } RangeAccess rangeAccess = new RangeAccess(flys); double[] dist = rangeAccess.getKmRange(); if (dist == null) { logger.debug("getGauges: no dist!"); return null; } logger.debug("getGauges: " + dist[0] + " - " + dist[1]); return river.determineGauges(dist[0], dist[1]); } /** Round a Q in the AT format style **/ public static double roundQ(double q) { if (q < 10d) q = Math.rint((q*1000d)) / 1000d; else if (q < 100d) q = Math.rint((q*100d)) / 100d; else if (q < 1000d) q = Math.rint((q*10d)) / 10d; else if (q >= 1000d) q = Math.rint(q); return q; } /** Parses the request and checks if it contains a currentKM setting. * If this is the case the currentKM is added to the context.*/ public static void setKMFromRequestInContext(Document request, CallContext context) { Double dKm; String km = XMLUtils.xpathString( request, XPATH_CHART_CURRENTKM, ArtifactNamespaceContext.INSTANCE); if (km == null) { return; } try { dKm = Double.valueOf(km); } catch (NumberFormatException nfe) { return; } if (logger.isDebugEnabled()) { logger.debug("currentKm = " + dKm); } context.putContextValue(CURRENT_KM, dKm); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :