package org.autoplot.datasource; import java.awt.Component; import java.awt.Desktop; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URISyntaxException; import java.net.URL; import java.net.URLDecoder; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.text.ParseException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.JOptionPane; import javax.xml.xpath.XPathFactory; import javax.xml.xpath.XPathFactoryConfigurationException; import org.das2.datum.DatumRange; import org.das2.datum.DatumRangeUtil; import org.das2.util.LoggerManager; import org.das2.datum.TimeUtil; import org.das2.datum.Units; import org.das2.datum.TimeParser; import org.das2.datum.UnitsUtil; import org.das2.util.monitor.ProgressMonitor; import org.das2.qds.DataSetOps; import org.das2.qds.QDataSet; import org.das2.qds.SemanticOps; import org.autoplot.datasource.capability.TimeSeriesBrowse; import org.das2.qds.ops.Ops; /** * DataSource utilities. * @author jbf */ public class DataSourceUtil { private static final Logger logger= LoggerManager.getLogger("apdss.util"); /** * used in Autoplot's Application object and in the DataSetSelector. */ public static final DatumRange DEFAULT_TIME_RANGE= DatumRangeUtil.parseTimeRangeValid( "2010-01-01" ); private DataSourceUtil() { // this class cannot be instatiated. } /** * remove escape sequences like %20 to create a human-editable string * This contains a kludge that looks for single spaces that are the result of * cut-n-pasting on Linux. If there is a space and a "%3A", then single spaces * are removed. * & is replaced with &. * @param s * @return */ public static String unescape(String s) { try { if ( s.contains(" ") && s.contains("%3A") ) { //copy and paste on linux sometimes inserts a space, so take these out. s= s.replaceAll(" ", ""); } s = URLDecoder.decode(s, "UTF-8"); s = s.replaceAll("\\&","&"); if ( s.startsWith("vap ")) { s= "vap+"+s.substring(4); } return s; } catch (UnsupportedEncodingException ex) { throw new RuntimeException(ex); } } /** * Carefully remove pluses from URIs that mean to interpret pluses * as spaces. Note this is not done automatically because some data sources * need the pluses, like vap+inline:ripples(20)+linspace(0.,10.,20). * This should be done carefully, because we realize that some pluses may * intentionally exist in URIs, such as &where=energy.gt(1e+3). While this * is discouraged, it will inevitably happen. * * * * *
&where=energy.gt(1e+3)&where=energy.gt(1e+3)
&where=energy.within(1e+3+to+1e+5)&where=energy.gt(1e+3 to 1e+5)
* @param s the parameter string, such as * @return */ public static String unescapeParam( String s ) { String[] ss= s.split("\\+\\D"); if ( ss.length==1 ) return s; // return String.join( " ",ss ); // Oh, for Java 8 I can't wait. (Note I realized later that it couldn't be used anyway. StringBuilder b= new StringBuilder(ss[0]); int ich= ss[0].length()+1; // we need to preserve the \D for ( int i=1; i targets ) { int i0= Integer.MAX_VALUE; for ( String t: targets ) { int i= str.indexOf(t); if ( i>-1 && i findAggregations( List files, boolean remove ) { return findAggregations( files, remove, false ); } /** * return the aggregations we can find. * If remove is true, then the input list will have all items * removed that are not part of an aggregation. * * @param files * @param remove remove the files that are accounted for by the aggregation. * @param loose only only one file to qualify for an aggregation. We need this to support case where we know it's from an agg. * @return list of aggregations found. */ public static List findAggregations( List files, boolean remove, boolean loose ) { List accountedFor= new ArrayList<>(); List result= new ArrayList<>(); List nonAgg= new ArrayList<>(); List notAccountedFor; notAccountedFor= new LinkedList(files); String[] ss= files.toArray( new String[notAccountedFor.size()] ); while ( notAccountedFor.size()>0 ) { String surl= notAccountedFor.remove(0); String sagg = makeAggregationForGroup(surl,ss); if (sagg==null || sagg.equals(surl)) { nonAgg.add(surl); continue; } else { accountedFor.add(surl); } DatumRange dr; // remove parameter sagg = URISplit.removeParam(sagg, "timerange"); TimeParser tp; try { tp= TimeParser.create(sagg,"v", TimeParser.IGNORE_FIELD_HANDLER ); tp.parse(surl); } catch (ParseException ex) { continue; } catch ( IllegalArgumentException ex ) { logger.log( Level.SEVERE, ex.getMessage(), ex ); continue; // bad format code "N" from "file:///c:/WINDOWS/$NtUninstallKB2079403$/" } dr = tp.getTimeRange(); DatumRange dr1= dr; // keep track of the first one to measure continuity. List moveUs= new ArrayList(); Pattern p= Pattern.compile( tp.getRegex() ); for ( String s: notAccountedFor ) { if ( p.matcher(s).matches() ) { try { tp.parse(s); dr = DatumRangeUtil.union(dr, tp.getTimeRange() ); moveUs.add( s ); } catch (IllegalArgumentException | ParseException ex) { // it's not part of the agg. } } } double nc= dr.width().divide(dr1.width()).doubleValue(Units.dimensionless); // number of intervals estimate // see if we can make the agg more specific, in particular, handling $Y$m01.dat when $Y$m$d was detected. Of course we have to guess // here, since we are not going to look inside the files. // I'm disabling this for now. It doesn't work and needs to be revisited. // if ( moveUs.size()>4 && sagg.contains("$d") ) { // String sagg1= sagg.replace("$d","01"); // TimeParser tp1= TimeParser.create(sagg,"v", TimeParser.IGNORE_FIELD_HANDLER ); // boolean fail= false; // for ( int i=0; i0 && ( moveUs.size()>4 || nc<((1+moveUs.size())*2) ) ) { // reject small aggregations notAccountedFor.removeAll(moveUs); accountedFor.addAll(moveUs); result.add( URISplit.putParam(sagg, "timerange", dr.toString()) ); } else { notAccountedFor.removeAll(moveUs); } } logger.log(Level.FINER, "found {0}.", nonAgg.size()); if ( remove ) { files.removeAll(accountedFor); } return result; } /** * attempt to make an aggregation from the URLs. If one cannot be created * (for example if the filenames are not consistent), then the original * URI is returned. * * @param surl * @param surls * @return */ public static String makeAggregation( String surl, String[] surls ) { try { String sagg = makeAggregationForGroup(surl, surls); if (sagg==null || sagg.equals(surl)) return surl; DatumRange dr; // remove parameter sagg = URISplit.removeParam(sagg, "timerange"); TimeParser tp = TimeParser.create(sagg); tp.parse(surl); dr = tp.getTimeRange(); boolean okay= true; for (int i = 0; okay && i < surls.length; i++) { try { tp.parse(surls[i]); dr = DatumRangeUtil.union(dr, tp.getTimeRange()); } catch (ParseException ex) { okay= false; logger.log(Level.SEVERE, ex.getMessage(), ex); } } if ( okay==false ) { return surl; } else { return URISplit.putParam(sagg, "timerange", dr.toString()); } } catch (ParseException ex) { logger.log(Level.SEVERE, ex.getMessage(), ex); return surl; } } /** * return true if the characters in the range st to en do not change. * @param others * @param st * @param en * @return */ public static boolean isConstant( String[] others, int st, int en ) { if ( others.length==0 ) return true; if ( st>en ) throw new IllegalArgumentException("st is greater than en"); if ( others[0].length()-1 ) { return 2; } else { int id3= replaceWith1.indexOf("$3"); if ( id3>-1 ) { return 3; } else { int id4= replaceWith1.indexOf("$4"); if ( id4>-1 ) { return 4; } else { return -1; } } } } /** * return the replacement or null. remove the used items. This will not match anything * after the question mark, if there is one. * @param s the URI. * @param search * @param replaceWith * @param resolution * @param others other strings which will be used with the same template, or null. * @param constraint if non-null, the time must be within this time range. * @return the string with 2014 replaced with $Y, etc. */ private static String replaceLast( String s, List search, List replaceWith, List resolution, String[] others, DatumRange timerange) { Map found= new HashMap(); int last= -1; String flast= null; String frepl= null; int best= -1; int fdelimGroup= -1; String bestDelim= ""; int limit= s.indexOf('?'); if ( limit==-1 ) limit=s.length(); DatumRange dr= null; while (true ) { String delim= null; int delimGroup= -1; int n= search.size(); for ( int i=0; i-1 ) delim= m.group(delimGroup); } if ( idx>-1 && idxlast ) { if ( others!=null ) { if ( isConstant( others, idx, ien ) ) { continue; } } if ( timerange!=null ) { String trypattern= replaceWith1; trypattern= trypattern.replaceAll("\\$\\d", "."); trypattern= trypattern.replaceAll("\\\\",""); TimeParser tp= TimeParser.create(trypattern); try { DatumRange tr= tp.parse(s.substring(idx,ien)).getTimeRange(); if ( !tr.contains(timerange) ) { continue; } } catch (ParseException ex) { Logger.getLogger(DataSourceUtil.class.getName()).log(Level.SEVERE, null, ex); } } last= idx; flast= search1; frepl= replaceWith1; fdelimGroup= delimGroup; bestDelim= delim; best= i; } } } if ( best>-1 ) { String date= s.substring(last); assert frepl!=null; String stp= frepl.replaceAll("\\\\",""); stp= stp.replaceAll("\\$"+fdelimGroup,bestDelim); TimeParser tp= TimeParser.create( stp ); DatumRange dr1=null; try { dr1= tp.parse(date).getTimeRange(); } catch ( ParseException ex ) { } if ( dr1!=null && ( dr==null || dr1.intersects(dr) ) ) { dr= dr1; s= s.substring(0,last) + s.substring(last).replaceAll(flast, frepl); int res= resolution.get(best); int count=0; for ( int j=0; jres ) { count++; search.set(j,null); } } if ( count==search.size() ) { return s; } else { best= -1; last= -1; //search for courser resolutions } } else { return s; } } else { return s; } } } /** * something which returns a new URI given an old one. */ public static interface URIMap { public String map(String uri); } private static final Map makeAggSchemes= new HashMap<>(); /** * register a map which might modify a URI so that it uses aggregation. * This was introduced for "vap+inline" URIs which must be taken apart and * then each of the getDataSet calls is aggregated. * @param scheme the scheme where this should be used, e.g. "vap+inline" * @param map the map, which might return the input URI or an aggregated one. */ public static void addMakeAggregationForScheme( String scheme, URIMap map ) { makeAggSchemes.put(scheme,map); } /** * attempt to create an equivalent URL that uses an aggregation template * instead of the explicit filename. This also return null when things go wrong. * For example, file:/tmp/20091102.dat -> file:/tmp/$Y$m$d.dat?timerange=20091102 * Also, look for version numbers. If multiple periods are found, then use $(v,sep) otherwise use numeric $v. *
{@code
     *y= makeAggregation("file:/tmp/20091102.dat")       // file:/tmp/$Y$m$d.dat?timerange=2009-11-02
     *x= makeAggregation("file:/tmp/20091102T02.dat");   // file:/tmp/$Y$m$dT$H.dat?timerange=2009-11-02 2:00 to 3:00
     *}
* @param surl the URI. * @return null or the string with aggregations ($Y.dat) instead of filename (1999.dat), or the original filename. */ public static String makeAggregation( String surl ) { String agg= makeAggregationForGroup( surl, null ); if ( agg==null ) return null; URISplit split= URISplit.parse(agg); return URISplit.format(split); } /** * attempt to create a String that uses an aggregation template * instead of the particular time. This also return null when things * go wrong. For example, * file:/tmp/20091102.dat -> file:/tmp/$Y$m$d.dat?timerange=20091102 * Also, look for version numbers. If multiple periods are found, then use * $(v,sep) otherwise use numeric $v. *
{@code
     *ss= [ "1991_095/1993/19930303.dat","1991_095/1993/19930304.dat","1991_095/1991/19930305.dat" ]
     *y= makeAggregationForGroup("1991_095/1993/19930303.dat",ss)       // 1991_095/$Y/$Y$m$d.dat?timerange=2009-11-02
     *}
* @see https://github.com/autoplot/dev/blob/master/bugs/sf/0484/makeAggregationForGroup_001.jy * @param surl the URI. * @param others other URIs in the group, used to reject solutions which would not produce unique results. * @return null or the string with aggregations ($Y.dat) instead of filename (1999.dat), or the original filename. */ public static String makeAggregationForGroup( String surl, String[] others ) { if ( surl==null && others!=null && others.length>0 ) { surl= others[0]; } String sfile= surl; String yyyy= "/(19|20)\\d{2}/"; String y4= "(19|20)\\d{2}"; String mm= "(01|02|03|04|05|06|07|08|09|10|11|12)"; String dd= "((?:0|1|2|3)\\d)"; String ddd= "([0123]\\d\\d)"; String hh= "(00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24)"; String min= "([0-6]\\d)"; String yyyymmdd= "(? search= new ArrayList( Arrays.asList( yyyymmdd_HHMM, yyyymmdd_HH, yyyymmdd, yyyy_jjj, yyyyjjj, yyyymm, yyyy_mm_dd, yyyy_mm, yyyy ) ); List replac= new ArrayList( Arrays.asList( "\\$Y\\$m\\$d$4\\$H\\$M", "\\$Y\\$m\\$d$4\\$H", "\\$Y\\$m\\$d", "\\$Y$2\\$j","\\$Y\\$j","\\$Y\\$m", "\\$Y$2\\$m$2\\$d", "\\$Y$2\\$m", "/\\$Y/" ) ); List resol= new ArrayList( Arrays.asList( minute, hour, day, day, day, month, day, month, year ) ); String s; try { s= replaceLast(sfile, search, replac, resol, others, null ); } catch ( IllegalArgumentException ex ) { logger.log( Level.FINE, ex.getMessage(), ex ); return null; } try { TimeParser tp= TimeParser.create(s); DatumRange drtr= tp.parse( sfile ).getTimeRange(); timeRange= drtr.toString(); //s= s.replaceFirst(version, "$1\\$2v"); //TODO: version causes problems elsewhere, see line 189. Why? int i=s.indexOf("$Y"); if ( i>-1 ) { String s0= s.substring(0,i); String s1= replaceLast( s0, search, replac, resol, null, drtr ); if ( !s1.equals(s0) ) { s= s1 + s.substring(i); } } Matcher m; m= Pattern.compile(vsep).matcher(s); if ( m.find() ) { s= s.replaceFirst( m.group(), Matcher.quoteReplacement(m.group(1)+"$(v,sep)") ); } m= Pattern.compile(version).matcher(s); if ( m.find() ) { s= s.replaceFirst( m.group(), Matcher.quoteReplacement(m.group(1)+"$v") ); } String result= s; if ( result.contains("?") ) { return result + "&timerange=" + timeRange; } else { return result + "?timerange=" + timeRange; } } catch ( IllegalArgumentException | ParseException ex ) { return null; // I had the file in my directory: "file:///home/jbf/das2Server?dataset=juno%2Fwaves%2Fflight%2Fsurvey.dsdf;start_time=$Y-$m-$dT15:00:00.000Z;end_time=$Y-$m-$dT19:00:00.000Z;params=EINT;server=dataset" } catch ( StringIndexOutOfBoundsException ex ) { StringIndexOutOfBoundsException e= new StringIndexOutOfBoundsException(s); // rte_0336734710_20191127_115020 e.initCause(ex); throw e; } } /** * make a valid Java identifier from the label. Data sources may wish * to allow labels to be used to identify data sources, and this contains * the standard logic. Strings are replaced with underscores, invalid * chars removed, etc. * @param label * @return valid Java identifier. */ public static String toJavaIdentifier( String label ) { StringBuilder buf= new StringBuilder(label.length()); for ( int i=0; i c, String delim) { StringBuilder result = new StringBuilder(); for (String s : c) { if (result.length() > 0) { result.append(delim); } result.append(s); } return result.toString(); } public static String strjoin( long[] dims, String delim ) { StringBuilder sdims= new StringBuilder(); if ( dims.length>0 ) { sdims.append( dims[0] ); for ( int i=1; i0 ) { sdims.append( dims[0] ); for ( int i=1; i *
  • [::1,:] -> { 0:[0,l0,1], 1:[1,l1,1] } *
  • [:,2] -> { 0:[0,l0,1], 1:[2,-1,-1] } //TODO: verify * * * This returns a map from dimension (0,1,...,rank-1) to [ start, stop, stride ]. * @param constraint, such as "[0:100:2]" for even records between 0 and 100, non-inclusive. * @param qubeDims the dimension of the data. * @return the [startRecord,stopRecordExclusive,stride] for each index. * @throws java.text.ParseException when the constraint cannot be parsed. */ public static Map parseConstraint(String constraint, long[] qubeDims ) throws ParseException { String[] ss; if ( constraint==null ) { ss= new String[] { null, null, null }; } else { if ( constraint.startsWith("[") && constraint.endsWith("]") ) { constraint= constraint.substring(1,constraint.length()-1); } ss= constraint.split("\\,",-2); } Map result= new HashMap<>(); int ndim= Math.min(ss.length,qubeDims.length); for ( int i=0; i0 && ss[0].length()>0 ) { result[0]= Integer.parseInt(ss[0]); if ( result[0]<0 ) result[0]= recCount+result[0]; } if ( ss.length>1 && ss[1].length()>0 ) { result[1]= Integer.parseInt(ss[1]); if ( result[1]<0 ) result[1]= recCount+result[1]; } if ( ss.length>2 && ss[2].length()>0 ) { result[2]= Integer.parseInt(ss[2]); } if ( ss.length==1 ) { // slice result[1]= -1; result[2]= -1; } } catch ( NumberFormatException ex ) { throw new ParseException("expected integer: "+ex.toString(),0); } if ( result[0]>recCount ) result[0]= recCount; if ( result[1]>recCount ) result[1]= recCount; return result; } } /** * @see Autoplot org.autoplot.AutoplotUtil.guessRenderType. * @param fillds * @return */ public static String guessRenderType(QDataSet fillds) { String spec; String specPref= "spectrogram"; String srenderType= (String) fillds.property(QDataSet.RENDER_TYPE); if ( srenderType!=null && srenderType.length()>0 ) { return srenderType; } QDataSet dep1 = (QDataSet) fillds.property(QDataSet.DEPEND_1); QDataSet plane0 = (QDataSet) fillds.property(QDataSet.PLANE_0); QDataSet bundle1= (QDataSet) fillds.property(QDataSet.BUNDLE_1); if ( fillds.property( QDataSet.JOIN_0 )!=null ) { if ( fillds.length()==0 ) { return "series"; } dep1 = (QDataSet) fillds.property(QDataSet.DEPEND_1,0); plane0 = (QDataSet) fillds.property(QDataSet.PLANE_0,0); bundle1= (QDataSet) fillds.property(QDataSet.BUNDLE_1,0); } if (fillds.rank() >= 2) { if ( bundle1!=null || (dep1 != null && SemanticOps.isBundle(fillds) || Ops.isLegacyBundle(fillds) ) ) { if (fillds.length() > 80000) { spec = "hugeScatter"; } else { spec = "series"; } if ( bundle1!=null ) { if ( bundle1.length()==3 && bundle1.property(QDataSet.DEPEND_0,2)!=null ) { // bad kludge spec= "colorScatter"; } else if ( bundle1.length()==3 || bundle1.length()==4 ) { Units u0= (Units) bundle1.property(QDataSet.UNITS,0); if ( u0==null ) u0= Units.dimensionless; Units u1= (Units) bundle1.property(QDataSet.UNITS,1); if ( u1==null ) u1= Units.dimensionless; Units u3= (Units) bundle1.property(QDataSet.UNITS,bundle1.length()-1); if ( u3!=null && UnitsUtil.isOrdinalMeasurement(u3) && u0.getOffsetUnits().isConvertibleTo(u1) ) { spec= "eventsBar"; } } } } else { if ( dep1==null && fillds.rank()==2 && fillds.length()>3 && fillds.length(0)<4 ) { // Vector quantities without labels. [3x3] is a left a matrix. spec = "series"; } else { spec = specPref; } } } else if ( fillds.rank()==0 || fillds.rank()==1 && SemanticOps.isBundle(fillds) ) { spec= "digital"; } else { if (fillds.length() > 80000) { spec = "hugeScatter"; } else { spec = "series"; } if (plane0 != null) { Units u = (Units) plane0.property(QDataSet.UNITS); if (u==null) u= Units.dimensionless; if (u != null && (UnitsUtil.isRatioMeasurement(u) || UnitsUtil.isIntervalMeasurement(u))) { spec = "colorScatter"; } } } return spec; } /** * open the URL in a browser. Borrowed from http://www.centerkey.com/java/browser/. * See also openBrowser in Autoplot, * which this replaces. * * Java 6 introduced standard code for doing this. The old code is still * used in case there's a problem. * * @param url the URL */ public static void openBrowser(String url) { try { java.net.URI target= DataSetURI.getResourceURI(url); Desktop.getDesktop().browse( target ); return; } catch (IOException ex) { logger.log(Level.SEVERE, null, ex); } catch ( UnsupportedOperationException ex ) { logger.log(Level.SEVERE, null, ex); // Linux, for example. } final String errMsg = "Error attempting to launch web browser"; String osName; try { osName =System.getProperty("os.name", "applet" ); } catch (SecurityException ex) { osName= "applet"; } try { if (osName.startsWith("Mac OS")) { Class fileMgr = Class.forName("com.apple.eio.FileManager"); Method openURL = fileMgr.getDeclaredMethod("openURL", new Class[]{String.class}); openURL.invoke(null, new Object[]{url}); } else if (osName.startsWith("Windows")) { Runtime.getRuntime().exec("rundll32 url.dll,FileProtocolHandler " + url); } else if (osName.equals("applet")) { throw new RuntimeException("applets can't start browser yet"); //TODO: this shouldn't be difficult, just get the AppletContext. } else { //assume Unix or Linux String[] browsers = {"firefox", "opera", "konqueror", "epiphany", "mozilla", "netscape"}; String browser = null; for (int count = 0; count < browsers.length && browser == null; count++) { if (Runtime.getRuntime().exec(new String[]{"which", browsers[count]}).waitFor() == 0) { browser = browsers[count]; } } if (browser == null) { throw new Exception("Could not find web browser"); } else { Runtime.getRuntime().exec(new String[]{browser, url}); } } } catch (Exception e) { JOptionPane.showMessageDialog(null, errMsg + ":\n" + e.getLocalizedMessage()); } } /** * returns true if the text appears to be html. Right now the test is * for " args= URISplit.parseParams(split.params); String name="ds"; //default name String altName=null; if ( args.containsKey(URISplit.PARAM_ARG_0) ) { altName= Ops.safeName( args.get(URISplit.PARAM_ARG_0) ); } else if ( args.containsKey(URISplit.PARAM_ID) ) { altName= Ops.safeName( args.get(URISplit.PARAM_ID) ); } else if ( args.containsKey("column") ) { altName= Ops.safeName( args.get("column") ); } if ( altName!=null && altName.length()<30 ) { name= altName; } // identifiers starting with upper case are going to bug me. reset the case. UPPER->upper and UpperCase->upperCase if ( name.length()>1 && Character.isUpperCase(name.charAt(0)) && Character.isUpperCase(name.charAt(1) ) ) { name= name.toLowerCase(); } else if ( name.length()>0 && Character.isUpperCase(name.charAt(0) ) ) { name= name.substring(0,1).toLowerCase() + name.substring(1); } return name; } /** * create a name which is unique, not in otherNames, perhaps looking at * differences with other URIs found in otherURIs. TODO: there's lots of * fun we could have here, for example looking for the closest URI in * otherNames, and then basing the name on the difference. (Possible student * project!) * @param uri the URI which needs naming. * @param otherURIs list of URIs, or null. * @param otherNames list of names for each URI, or null. * @return the suggested name */ public static String guessNameFor( String uri, List otherURIs, List otherNames ) { String n= guessNameFor(uri); if ( otherNames.contains(n) ) { int serial= 1; String newn= n + serial; while ( otherNames.contains(newn) ) { serial++; newn= n + serial; } return newn; } else { return n; } } /** * return a one-line string representation of the exception. This was introduced * when a NullPointerException was represented as "null", and it was somewhat * unclear about what was going on. * @param ex an exception * @return a 1-line string representation of the error, for the end user. */ public static String getMessage( Exception ex ) { if ( ex==null ) { throw new IllegalArgumentException("Expected exception, but got null"); } if ( ex instanceof NullPointerException ) { return ex.toString(); } else { if ( ex.getMessage()==null ) { return ex.toString(); } else if ( ex.getMessage().length()<5 ) { return ex.toString() + ": " +ex.getMessage(); } else { return ex.getMessage(); } } } public static void main(String[] args ) { String surl= "ftp://virbo.org/LANL/LANL1991/SOPA+ESP/H0/LANL_1991_080_H0_SOPA_ESP_19920308_V01.cdf?L"; //String surl= "http://cdaweb.gsfc.nasa.gov/istp_public/data/polar/hyd_h0/2000/po_h0_hyd_20000109_v01.cdf?ELECTRON_DIFFERENTIAL_ENERGY_FLUX"; System.err.println( makeAggregation(surl) ); //logger okay System.err.println( makeAggregation(surl) ); //logger okay } /** * this will make the exception available. (Someday. TODO: where is this used?) * @param parent * @param msg * @param title * @param messageType * @param causeBy */ public static void showMessageDialog( Component parent, String msg, String title, int messageType, Exception causeBy ) { JOptionPane.showMessageDialog( parent, msg, title, messageType ); } /** * Matlab uses net.sf.saxon.xpath.XPathEvaluator by default, so we explicitly look for the Java 6 one. * @return com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl, probably. */ public static XPathFactory getXPathFactory() { XPathFactory xpf; try { xpf= XPathFactory.newInstance( XPathFactory.DEFAULT_OBJECT_MODEL_URI, "com.sun.org.apache.xpath.internal.jaxp.XPathFactoryImpl", null ); } catch (XPathFactoryConfigurationException ex) { xpf= XPathFactory.newInstance(); logger.log( Level.INFO, "using default xpath implementation: {0}", xpf.getClass()); } return xpf; } // /** // * Used for debugging, this dumps the data out to a das2stream. // * @param ds // * @param f // */ // public static void dumpToFile( QDataSet ds, String f ) { // try { // SimpleStreamFormatter fo= new SimpleStreamFormatter(); // OutputStream fout= new FileOutputStream(f); // try { // fo.format( ds, fout, true); // } finally { // fout.close(); // } // } catch (StreamException ex) { // ex.printStackTrace(); // } catch ( IOException ex ) { // ex.printStackTrace(); // } // } }