//
// AddeURL.java
//
/*
This source file is part of the edu.wisc.ssec.mcidas package and is
Copyright (C) 1998 - 2017 by Tom Whittaker, Tommy Jasmin, Tom Rink,
Don Murray, James Kelly, Bill Hibbard, Dave Glowacki, Curtis Rueden
and others.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library 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
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package edu.wisc.ssec.mcidas.adde;
/**
* A class for holding information about an ADDE URL.
*
* <pre>
*
* URLs must all have the following format:
*
* adde://host/request?keyword_1=value_1&keyword_2=value_2
*
* where request can be one of the following:
*
* datasetinfo - request for data set information (LWPR)
* griddirectory - request for grid directory information (GDIR)
* griddata - request for grid data (GGET)
* imagedata - request for data in AreaFile format (AGET)
* imagedirectory - request for image directory information (ADIR)
* pointdata - request for point data (MDKS)
* textdata - request to read a text file (TXTG)
* wxtext - request to read a weather text file (WTXG)
* obtext - request to read a observation text file (OBTG)
*
* There can be any valid combination of the following supported keywords:
*
* -------for any request
*
* group=<groupname> ADDE group name
* user=<user_id> ADDE user identification
* proj=<proj #> a valid ADDE project number
* trace=<0/1> setting to 1 tells server to write debug
* trace file
* version= ADDE version number, currently 1 except for
* griddata requests
* debug= set to true to watch the printlns stream by
* compress= set to "gzip" if you want to use the GZIP
* compression or "compress" if you want to use
* transfers in Unix compress format (You need to
* have the VisAD package if you want to support
* this.) default = none.
* port= Socket port to connect on. Overridden by
* a port specified in the host
* (e.g., adde.ucar.edu:500)
*
* </pre>
*/
public class AddeURL implements Cloneable {
/** The protocol */
public static final String ADDE_PROTOCOL = "adde";
/** AGET request type */
public final static String REQ_AGET = "aget";
/** ADIR request type */
public final static String REQ_ADIR = "adir";
/** LWPR request type */
public final static String REQ_LWPR = "lwpr";
/** GDIR request type */
public final static String REQ_GDIR = "gdir";
/** GGET request type */
public final static String REQ_GGET = "gget";
/** MDKS request type */
public final static String REQ_MDKS = "mdks";
/** TXTG request type */
public final static String REQ_TXTG = "txtg";
/** WTXG request type */
public final static String REQ_WTXG = "wtxg";
/** OBTG request type */
public final static String REQ_OBTG = "obtg";
/** Image data request type */
public final static String REQ_IMAGEDATA = "imagedata";
/** Image directory request type */
public final static String REQ_IMAGEDIR = "imagedirectory";
/** Data set info request type */
public final static String REQ_DATASETINFO = "datasetinfo";
/** Text request type */
public final static String REQ_TEXT = "text";
/** weather text request type */
public final static String REQ_WXTEXT = "wxtext";
/** obs text request type */
public final static String REQ_OBTEXT = "obtext";
/** Grid data request type */
public final static String REQ_GRIDDATA = "griddata";
/** Grid directory request type */
public final static String REQ_GRIDDIR = "griddir";
/** Point data request type */
public final static String REQ_POINTDATA = "point";
/** Default value for key/value pairs (X) */
public final static String DEFAULT_VALUE = "X";
/** Value for yes */
public final static String YES = "YES";
/** Value for no */
public final static String NO = "NO";
/** Value for ALL */
public final static String ALL = "ALL";
/** Keyword for trace */
public static final String KEY_TRACE = "TRACE";
/** Keyword for debug */
public static final String KEY_DEBUG = "DEBUG";
/** Keyword for port */
public static final String KEY_PORT = "PORT";
/** Keyword for project */
public static final String KEY_PROJ = "PROJ";
/** Keyword for user */
public static final String KEY_USER = "USER";
/** Keyword for compress */
public static final String KEY_COMPRESS = "COMPRESS";
/** Keyword for version */
public static final String KEY_VERSION = "VERSION";
/** Flag for "compress" compression. */
public final static int COMPRESS = 503;
/** Flag for "no compress" compression. */
public final static int NO_COMPRESS = 500;
/** Flag for GZip compression. */
public final static int GZIP = 112;
/** flag for trace on */
public static final int TRACE_ON = 0;
/** flag for trace off */
public static final int TRACE_OFF = 1;
/** the host */
private String host = "localhost";
/** the version */
private String version = "" + AddeURLConnection.VERSION_1;
/** the user id */
private String user = AddeURLConnection.DEFAULT_USER;
/** the project number */
private int project = AddeURLConnection.DEFAULT_PROJ;
/** the trace flag */
private int trace = 0;
/** the extra key/value pairs */
private String extraKeys = null;
/** the compression type */
private int compress = -1; // let port determine compression by default
/** the port */
private int port = AddeURLConnection.DEFAULT_PORT;
/** the request type */
private String requestType = "";
/** the debug type */
private boolean debug = false;
/**
* Create an ADDE URL
*/
public AddeURL() {}
/**
* Create an ADDE URL from the given spec
* @param host host to send to
* @param requestType type of request (REQ_*)
*/
public AddeURL(String host, String requestType) {
this(host, requestType, null);
}
/**
* Create an ADDE URL from the given spec
* @param host host to send to
* @param requestType type of request (REQ_*)
* @param extraKeys extra key/value arguments
*/
public AddeURL(String host, String requestType, String extraKeys) {
this.host = host;
this.requestType = requestType;
this.extraKeys = extraKeys;
}
/**
* Create the ADDE URL as a String
*
* @return an Adde URL
*/
public String getURLString() {
StringBuffer buf = new StringBuffer(ADDE_PROTOCOL);
buf.append("://");
buf.append(host);
buf.append("/");
buf.append(requestType);
buf.append("?");
buf.append(makeQuery());
return buf.toString();
}
/**
* Make the query portion of the URL (e.g., key1=value1&key2=value2..)
* Subclasses should override.
*
* @return the query portion of the URL
*/
protected String makeQuery() {
StringBuffer buf = new StringBuffer();
appendKeyValue(buf, KEY_PORT, "" + getPort());
appendKeyValue(buf, KEY_COMPRESS, getCompressionType());
appendKeyValue(buf, KEY_USER, getUser());
appendKeyValue(buf, KEY_PROJ, "" + getProject());
appendKeyValue(buf, KEY_VERSION, getVersion());
appendKeyValue(buf, KEY_DEBUG, Boolean.toString(getDebug()));
appendKeyValue(buf, KEY_TRACE, "" + getTrace());
if (getExtraKeys() != null) {
if (!getExtraKeys().startsWith("&")) buf.append("&");
buf.append(getExtraKeys());
}
return buf.toString();
}
/**
* Parse the query string and set the values accordingly, subclasses
* should extend to parse their particular keywords
* @param query query string
*/
protected void parseQuery(String query) {
String test = getValue(query, KEY_PORT);
if (test != null) {
setPort(Integer.parseInt(test));
}
test = getValue(query, KEY_COMPRESS);
if (test != null) {
setCompressionFromString(test);
}
test = getValue(query, KEY_USER);
if (test != null) {
setUser(test);
}
test = getValue(query, KEY_PROJ);
if (test != null) {
setProject(Integer.parseInt(test));
}
test = getValue(query, KEY_VERSION);
if (test != null) {
setVersion(test);
}
test = getValue(query, KEY_DEBUG);
if (test != null) {
setDebug(test.equals("true"));
}
test = getValue(query, KEY_TRACE);
if (test != null) {
setTrace(Integer.parseInt(test));
}
}
/**
* Get the value for a particular key.
* @param query the query string
* @param key the key to search
* @return the value or null if it doesn't exist
*/
public String getValue(String query, String key) {
String retVal = null;
int keyIndex = query.indexOf(key);
if (keyIndex < 0) { // try lowercase version;
keyIndex = query.indexOf(key.toLowerCase());
}
if (keyIndex >= 0) {
int equalIndex = query.indexOf("=", keyIndex);
int ampIndex = query.indexOf("&", keyIndex);
retVal = (ampIndex >= 0)
? query.substring(equalIndex+1, ampIndex) // to the amp
: query.substring(equalIndex+1); // to the end
}
return retVal;
}
/**
* A utility method to make a name=value part of the adde request string
*
* @param buf The buffer to append to
* @param name The property name
* @param value The value
*/
protected void appendKeyValue(StringBuffer buf, String name, String value) {
if ((buf.length() == 0) || (buf.charAt(buf.length() - 1) != '?')) {
buf.append("&");
}
buf.append(name);
buf.append("=");
buf.append(value);
}
/**
* Compare two AddeURLs
*
* @param o Object in question
*
* @return true if they are the same object or if all
*/
public boolean equals(Object o) {
if (!(o.getClass().equals(this.getClass()))) {
return false;
}
AddeURL that = (AddeURL)o;
if (this == that) {
return true;
}
return getURLString().equals(that.getURLString());
}
/**
* Get the hashcode for this
*
* @return the hashcode
*/
public int hashCode() {
return getURLString().hashCode();
}
/**
* Get the host for this ADDE URL
* @return the host
*/
public String getHost() {
return host;
}
/**
* Set the host for this ADDE URL
* @param host the host
*/
public void setHost(String host) {
this.host = host;
}
/**
* Get the request type for this ADDE URL
* @return the host
*/
public String getRequestType() {
return requestType;
}
/**
* Set the request type for this ADDE URL
*
* @param requestType the request Type
*/
public void setRequestType(String requestType) {
this.requestType = requestType;
}
/**
* Get the extraKeys string for this ADDE URL
* @return the extraKeys string
*/
public String getExtraKeys() {
return extraKeys;
}
/**
* Set the extraKeys string for this ADDE URL
* @param extraKeys the extraKeys
*/
public void setExtraKeys(String extraKeys) {
this.extraKeys = extraKeys;
}
/**
* Get the project for this ADDE URL
* @return the project
*/
public String getUser() {
return user;
}
/**
* Set the user for this ADDE URL
* @param user the user
*/
public void setUser(String user) {
this.user = user;
}
/**
* Get the project for this ADDE URL
* @return the project
*/
public int getProject() {
return project;
}
/**
* Set the project for this ADDE URL
* @param project the project
*/
public void setProject(int project) {
this.project = project;
}
/**
* Get the version for this ADDE URL
* @return the version
*/
public String getVersion() {
return version;
}
/**
* Set the version this ADDE URL
* @param version the version
*/
public void setVersion(String version) {
this.version = version;
}
/**
* Get the debug value for this ADDE URL
* @return the debug value (true or false)
*/
public boolean getDebug() {
return debug;
}
/**
* Set the debug value this ADDE URL
* @param debug the debug value (true or false);
*/
public void setDebug(boolean debug) {
this.debug = debug;
}
/**
* Get the port for this ADDE URL
* @return the port
*/
public int getPort() {
return port;
}
/**
* Set the port used for this ADDE URL
* @param port the port
*/
public void setPort(int port) {
this.port = port;
}
/**
* Get the compression type for this ADDE URL
* @return the compression type
*/
public int getCompression() {
return compress;
}
/**
* Set the compression type used for this ADDE URL
* @param compress the compression type (GZIP, NO_COMPRESS, COMPRESS)
*/
public void setCompression(int compress) {
this.compress = compress;
}
/**
* Get the trace value used for this ADDE URL
* @return the trace value (TRACE_ON, TRACE_OFF)
*/
public int getTrace() {
return trace;
}
/**
* Set the trace value used for this ADDE URL
* @param trace the trace value (TRACE_ON, TRACE_OFF)
*/
public void setTrace(int trace) {
this.trace = trace;
}
/**
* Get the compression type from the port number if not specified.
*
* @return the compression type as a string
*/
private String getCompressionType() {
String testStr = null;
int valueToCheck = (compress == -1)
? port
: compress;
switch (valueToCheck) {
case NO_COMPRESS: // port == 500
case 1: // port == 1
testStr = "none";
break;
case COMPRESS: // port == 503
case 2: // port == 2
testStr = "compress";
break;
case GZIP: // port == 112
case 3: // port == 3
default:
testStr = "gzip";
break;
}
return testStr;
}
/**
* Set the compression type from a string
*
* @param type the string type
*/
public void setCompressionFromString(String type) {
if (type.equals("gzip") || type.equals("112")) {
setCompression(112);
}
else if (type.equals("compress") || type.equals("503")) {
setCompression(503);
}
else if (type.equals("none") || type.equals("500")) {
setCompression(500);
}
}
/**
* Clones this instance.
*
* <p>This implementation never throws CloneNotSupportException</p>
*
* @return A clone of this instance.
* @throws CloneNotSupportedException if cloning isn't supported.
*/
public Object clone() throws CloneNotSupportedException {
Object clone = null;
try {
clone = super.clone();
}
catch (CloneNotSupportedException ex) {
throw new Error("Assertion failure", ex); // can't happen
}
return clone;
}
}