//
// AddeServerInfo.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;
import java.text.FieldPosition;
import java.text.SimpleDateFormat;
import java.util.StringTokenizer;
import java.util.TimeZone;
import java.util.Vector;
import edu.wisc.ssec.mcidas.adde.ReadTextFile;
import edu.wisc.ssec.mcidas.AreaDirectoryList;
import edu.wisc.ssec.mcidas.AreaDirectory;
import edu.wisc.ssec.mcidas.McIDASException;
/**
* All things related to ADDE servers, groups and datasets
* Certain requests are dependent on appropriate prior requests.
* E.g., must set server, then group, before you can request
* File Format.
*
* @author tomw
* @version 0.2
*/
public class AddeServerInfo extends Object {
private String[] serverList;
private String selectedServer = null;
private boolean hasServers = false;
private String dataType = null;
private String[] bandNames;
private boolean hasBandNames = false;
private String selectedGroup = null;
private boolean hasGroup = false;
private String selectedDataset = null;
private boolean hasDataset = false;
private AreaDirectory [][]dirs;
private Vector table, groups;
private String status="OK";
private String userproj = null;
private String DATEFORMAT = "yyyy-MM-dd / HH:mm:ss";
private boolean debug = false;
private boolean isArchive = false;
private String archiveDate = null;
/**
* Creates new AddeServerInfo. This collects information about
* ADDE server(s) -- their groups, datasets, and date-times (right
* now only image date-time implemented). This is a helper class
* for anything else that needs to get these information.
*
* The candidate list of ADDE servers should be obtained from a
* yet-to-be-identified "well-known list", and made available
* in this class.
*/
public AddeServerInfo() {
// go find the list of well-known servers ?
this(null);
}
/**
* The non-default parameter is a list of of ADDE servers
*
* @param l a list of ADDE servers that can be used in lieu
* of automatically obtaining it.
*
*/
public AddeServerInfo(String[] l) {
// well known list of ADDE servers
// XXX TJJ - I don't like this and would prefer to force a valid
// server name into the constructor, and fail all requests otherwise
String[] list = l;
if (list == null) {
list = new String[] {
"adde.unidata.ucar.edu",
"adde.ssec.wisc.edu",
"unidata2.ssec.wisc.edu",
"uwamrc.ssec.wisc.edu"
};
}
serverList = new String[list.length];
for (int i=0; i<list.length; i++) {
serverList[i] = list[i];
}
hasServers = true;
}
/**
* get a list of servers
*
* @return names of server hosts
*/
public String[] getServerList() {
if (hasServers) {
return serverList;
} else {
return null;
}
}
/**
* get name of the server that has been selected and for
* which all group and dataset info is currently valid for
*
* @return name of server host
*/
public String getSelectedServer() {
return selectedServer;
}
/**
* define which server to select, and the type of ADDE data group
* (image, point, grid, text) to get group and descriptor info for
*
* This is the workhorse of the code.
*
* @param s the name of the ADDE server to be selected
* @param type the type of data to select.
*
* @return status code: 0=ok, -1=invalid accounting, -2=didn't get metadata
*
*/
public int setSelectedServer(String s, String type) {
selectedServer = s.trim();
int istatus = 0;
dataType = type.trim();
groups = new Vector();
status = "Failed to get PUBLIC.SRV file from from server "+s+".";
try {
// go get the modified PUBLIC.SRV file from the server...
String req = "adde://"+selectedServer+"/text?file=PUBLIC.SRV";
if (userproj != null) {
String req2 = req+"&"+userproj+"&version=1";
req = req2;
}
if (debug) System.out.println("Req:"+req);
ReadTextFile rtf = new ReadTextFile(req);
if (debug) System.out.println("Status from RTF="+rtf.getStatus());
// see if accounting data is required but not provided...
if (rtf.getStatusCode() == -3) {
return -1;
}
/* do we really want to do this????? */
// if that fails, try to get RESOLV.SRV, but keep it hidden...
if (!rtf.getStatus().equals("OK")) { // try again
req = "adde://"+selectedServer+"/text?file=RESOLV.SRV";
if (userproj != null) {
String req2 = req+"&"+userproj+"&version=1";
req = req2;
}
if (debug) System.out.println("2ndReq:"+req);
rtf = new ReadTextFile(req);
if (debug) System.out.println("Status from 2ndRTF="+rtf.getStatus());
}
table = rtf.getText();
status = "Failed to locate required information on server "+s+".";
// look at each table member and pull out info only
// when the TYPE='dataType'
for (int i=0; i<table.size(); i++) {
String a = (String) table.elementAt(i);
if (debug) System.out.println("Table: "+a);
StringTokenizer st = new StringTokenizer(a,",");
int num = st.countTokens();
String[] tok = new String[num];
String[] val = new String[num];
int indexType = -1;
int indexN1 = -1;
int indexN2 = -1;
int indexK = -1;
int indexC = -1;
// number of items in the record
for (int j=0; j<num; j++) {
String p = st.nextToken();
// simple token=value within each group
int x = p.indexOf("=");
if (x < 0) continue;
tok[j] = p.substring(0,x);
val[j] = p.substring(x+1).trim();
// flags to indicate found needed keys
if (tok[j].equalsIgnoreCase("type")) indexType = j;
if (tok[j].equalsIgnoreCase("N1")) indexN1 = j;
if (tok[j].equalsIgnoreCase("N2")) indexN2 = j;
if (tok[j].equalsIgnoreCase("K")) indexK = j;
if (tok[j].equalsIgnoreCase("C")) indexC = j;
}
// skip if: a) no =, b> not TYPE type, c) element missing
if (debug) {
System.out.println("indexType = "+indexType+
" dataType="+dataType+" indexN1,N2,C="+indexN1+" "+
indexN2+" "+indexC);
}
if (indexType < 0) continue;
if (!val[indexType].equalsIgnoreCase(dataType)) continue;
if (indexN1 < 0 || indexN2 < 0) continue;
// If no Comment field, just use N2 (kludge)
if (indexC < 0) indexC = indexN2;
boolean hit = false;
// search to see if this group has been encountered before.
// if so, just append descr; otherwise make a new entry
for (int j=0; j<groups.size(); j++) {
Vector vg = (Vector)groups.elementAt(j);
// element: 0=groupname, 1=Vector of datasets, 2=Vector of descrs
String g = (String)vg.elementAt(0);
if (g.equalsIgnoreCase(val[indexN1])) {
hit = true;
Vector v = (Vector)vg.elementAt(1);
v.addElement(val[indexN2]);
v = (Vector)vg.elementAt(2);
v.addElement(val[indexC]);
if (vg.size() >= 4) {
v = (Vector)vg.elementAt(3);
v.addElement(val[indexK]);
}
}
}
// if needed, make a new entry
if (!hit) {
Vector v = new Vector();
v.addElement(val[indexN1]);
Vector v2 = new Vector();
v2.addElement(val[indexN2]);
Vector v3 = new Vector();
v3.addElement(val[indexC]);
Vector v4 = null;
if (indexK > 0) {
v4 = new Vector();
v4.addElement(val[indexK]);
}
v.addElement(v2);
v.addElement(v3);
if (v4 != null) v.addElement(v4);
groups.addElement(v);
}
}
String reqBand = "adde://"+selectedServer+"/text?file=SATBAND";
if (userproj != null) {
String reqBand2 = reqBand+"&"+userproj+"&version=1";
reqBand = reqBand2;
}
if (debug) System.out.println("ReqBand:"+reqBand);
ReadTextFile rtfBand = new ReadTextFile(reqBand);
if (debug) System.out.println("Status from RTFBand="+rtfBand.getStatus());
Vector vBand = null;
if (rtfBand.getStatus().equals("OK")) {
vBand = rtfBand.getText();
int num = vBand.size();
bandNames = new String[num];
for (int i=0; i<num; i++) {
bandNames[i] = (String) vBand.elementAt(i);
if (debug) System.out.println("band = "+bandNames[i]);
}
hasBandNames = true;
}
status = "ADDE group & dataset information retrieved from server "+s+".";
istatus = 0;
} catch (Exception e) {e.printStackTrace(); return -2;}
return istatus;
}
/**
* get a list of all groups valid for this server
*
* @return array of group ids
*/
public String[] getGroupList() {
int num = groups.size();
String[] sg = new String[num];
for (int i=0; i < num; i++) {
Vector v = (Vector) groups.elementAt(i);
sg[i] = (String) v.elementAt(0);
}
status = "List of groups on server " + selectedServer + " obtained.";
return sg;
}
/**
* get a list of all datasets valid for this server and
* the designated group.
*
* @return array of dataset tags
*
*/
public String[] getDatasetList() {
int num = groups.size();
boolean autoUpcase = Boolean.getBoolean("adde.auto-upcase");
boolean match;
for (int i=0; i<num; i++) {
Vector v = (Vector)groups.elementAt(i);
String g = (String)v.elementAt(0);
if (autoUpcase) {
match = g.equalsIgnoreCase(selectedGroup);
} else {
match = g.equals(selectedGroup);
}
if (match) {
Vector ds = (Vector)v.elementAt(1);
int numds = ds.size();
String[] sdl = new String[numds];
for (int j=0; j<numds; j++) {
sdl[j] = (String)ds.elementAt(j);
}
status = "Dataset list for server "+selectedServer+
" and group "+selectedGroup+" obtained.";
return sdl;
}
}
status = "Dataset list for server "+selectedServer+
" and group "+selectedGroup+" not found.";
return null;
}
/**
* get a list of all dataset descriptions for this server and
* the designated group
*
* @return array of dataset descriptors
*
*/
public String[] getDatasetListDescriptions() {
boolean autoUpcase = Boolean.getBoolean("adde.auto-upcase");
boolean match;
int num = groups.size();
for (int i=0; i<num; i++) {
Vector v = (Vector)groups.elementAt(i);
String g = (String)v.elementAt(0);
if (autoUpcase) {
match = g.equalsIgnoreCase(selectedGroup);
} else {
match = g.equals(selectedGroup);
}
if (match) {
Vector dsd = (Vector)v.elementAt(2);
int numdsd = dsd.size();
String[] sdld = new String[numdsd];
for (int j=0; j<numdsd; j++) {
sdld[j] = (String)dsd.elementAt(j);
}
status = "Dataset list for server "+selectedServer+
" and group "+selectedGroup+" obtained.";
return sdld;
}
}
status = "Dataset list for server "+selectedServer+
" and group "+selectedGroup+" not found.";
return null;
}
/**
* get the valid date-time list for the selected server/group/dataset.
* Note that you must 'setSelectedGroup()' and 'setSelectedDataset()'
* prior to using this method.
*
* [Also, Don Murray at Unidata wrote the original - thanks!]
*
* @return list of date-times ("yy-MM-dd / hh:mm:ss" format)
* or the string "No data available"
*
*/
public String[] getDateTimeList() {
status = "Trying to get date-times for "+selectedGroup+
" from server "+selectedServer;
if (!hasGroup || !hasDataset) return null;
StringBuffer addeCmdBuff =
new StringBuffer("adde://"+selectedServer+
"/imagedir?group=" + selectedGroup);
addeCmdBuff.append("&descr=");
addeCmdBuff.append(selectedDataset);
// if user/proj supplied, then put them in here...
if (userproj != null) addeCmdBuff.append("&"+userproj);
addeCmdBuff.append("&pos=all&version=1");
if (isArchive && archiveDate != null) {
addeCmdBuff.append("&DAY="+archiveDate);
}
if (debug) System.out.println("cmd:"+addeCmdBuff.toString());
String[] times = {"No data available"};
try {
AreaDirectoryList adir =
new AreaDirectoryList(addeCmdBuff.toString());
dirs = adir.getSortedDirs();
int numTimes = dirs.length;
times = new String[numTimes];
SimpleDateFormat sdf = new SimpleDateFormat();
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.applyPattern(DATEFORMAT);
for (int i=0; i < numTimes; i++)
{
times[i] =
sdf.format(
dirs[i][0].getNominalTime(),
new StringBuffer(),
new FieldPosition(0)).toString();
}
}
catch (McIDASException e) {status = "Error getting times";}
return times;
}
/**
* Get the File Format (AREA, TEXT, NEXR, etc.) for the
* currently selected group.
*
* @return file format for currently selected group
*
*/
public String getFileFormat() {
int num = groups.size();
boolean autoUpcase = Boolean.getBoolean("adde.auto-upcase");
boolean match;
for (int i=0; i<num; i++) {
Vector v = (Vector) groups.elementAt(i);
String g = (String) v.elementAt(0);
if (autoUpcase) {
match = g.equalsIgnoreCase(selectedGroup);
} else {
match = g.equals(selectedGroup);
}
if (match) {
if (debug) System.out.println("VECTOR SIZE: " + v.size());
if (v.size() >= 4) {
Vector ffv = (Vector) v.elementAt(3);
String ff = (String) ffv.elementAt(0);
if (ff != null) {
status = "File Format for server " + selectedServer +
" and group " + selectedGroup + " obtained.";
return ff;
}
}
}
}
status = "File Format for server "+selectedServer+
" and group "+selectedGroup+" not found.";
return null;
}
/**
* get the sorted list of AreaDirectory objects
*
* @return list of directories
*/
public AreaDirectory[][] getAreaDirectories() {
return dirs;
}
/**
* identify the selected group
*
* @param g the name of the group to select
*/
public void setSelectedGroup(String g) {
selectedGroup = g;
hasGroup = true;
}
/**
* identify the selected dataset
*
* @param d the name of the dataset/descr to select
*/
public void setSelectedDataset(String d) {
selectedDataset = d;
hasDataset = true;
}
public void setIsArchive(boolean flag) {
isArchive = flag;
}
public boolean getIsArchive() {
return isArchive;
}
public void setArchiveDate(String d) {
archiveDate = d;
}
public String getArchiveDate() {
return archiveDate;
}
/**
* return the bandNames text
*
* @return array of text of the SATBAND data fetched from selectedServer
*
*/
public String[] getBandNames() {
if (hasBandNames) {
return bandNames;
} else {
return null;
}
}
/**
* Not used??
*/
public String getRequestString(int reqestType) {
return null;
// requestType = static ints IMAGE, DIR, etc
}
/**
* set the userID and proj number if required for transactions,
* as required by servers that use accounting.
*
* @param up the user/project number request string in
* the form "user=tom&proj=1234"
*
*/
public void setUserIDandProjString(String up) {
userproj = up;
return;
}
/**
* get the status of the last request
*
* @return words describing last transaction
*/
public String getStatus() {
return status;
}
/**
* For testing purposes. Edit server, and run the class as if it
* were an application.
*/
public static void main(String[] args) {
System.out.println("AddeServerInfo unit test begin...");
AddeServerInfo asi = new AddeServerInfo();
// NOTE!
// if you are testing this class, edit below with your server info!
asi.setUserIDandProjString("user=ZZZZ&proj=YYYY");
int sstat = asi.setSelectedServer("some-server.ssec.wisc.edu", "image");
System.out.println("Status = " + asi.getStatus() + " code=" + sstat);
String[] a = asi.getGroupList();
System.out.println("Status = " + asi.getStatus());
for (int i=0; i < a.length; i++) {
System.out.println("group = " + a[i]);
// set the selected group
asi.setSelectedGroup(a[i]);
System.out.println(" File Format: " + asi.getFileFormat());
String[] b = asi.getDatasetList();
String[] c = asi.getDatasetListDescriptions();
for (int k=0; k < b.length; k++) {
// datasets and their descriptions
System.out.println(" " + b[k] + " == " + c[k]);
if (i==0 && k==0) {
// set the selected Dataset, and fetch its date-time info
asi.setSelectedDataset(b[k]);
String[] dt = asi.getDateTimeList();
for (int m=0; m < dt.length; m++) {
System.out.println("DateTime = " + dt[m]);
}
}
}
}
System.out.println("Status = " + asi.getStatus());
}
}