001 package edu.nrao.sss.model.source.parser; 002 003 import java.io.IOException; 004 import java.io.LineNumberReader; 005 import java.io.Reader; 006 import java.util.HashMap; 007 import java.util.Map; 008 009 import edu.nrao.sss.model.source.Source; 010 import edu.nrao.sss.model.source.SourceCatalog; 011 import edu.nrao.sss.model.source.SourceGroup; 012 013 /** 014 * A parser of source catalog text files in the format used by the 015 * GBT / VLA Proposal Submission Tool (PST). 016 * <p> 017 * The following are the specifications for source catalog text files 018 * found in the PST User Manual:</p> 019 * <div style="color:rgb(0,0,100)"> 020 * This ASCII file must be formatted as follows: 021 * <ul> 022 * <li>Each line of the ASCII file should contain the information for a single 023 * source, as a comma-separated list in the following order: source name; 024 * right ascension; declination; epoch; velocity; redshift; and (optional) 025 * group name(s), with each group name separated by a comma.</li> 026 * <li>Either, but not both of, the velocity or the redshift must be specified 027 * for every source.</li> 028 * <li>If any group name is given, the source will appear only as a member of 029 * the indicated group or groups: it will not appear as an ``ungrouped'' 030 * (individual) source, and will not be selectable as an individual source 031 * when creating source/resource pairs on the Sessions Tab Page (see §[*] 032 * and §[*]). To enter a source both as an individual and as part of a 033 * group, simply put the same source in two lines, one listing groups and 034 * one not listing groups.</li> 035 * <li>A valid source line must have a minimum of six commas.</li> 036 * <li>Comment lines begin with the character ``#''.</li> 037 * <li>You can use tab as the delimiter in place of comma. However, commas and 038 * tabs cannot be mixed in the same source data line.</li> 039 * <li>Embedded blank lines are fine.</li> 040 * </ul> 041 * </div> 042 * <p> 043 * <b>Version Info:</b> 044 * <table style="margin-left:2em"> 045 * <tr><td>$Revision: 1251 $</td></tr> 046 * <tr><td>$Date: 2008-04-28 16:28:37 -0600 (Mon, 28 Apr 2008) $</td></tr> 047 * <tr><td>$Author: dharland $ (last person to modify)</td></tr> 048 * </table></p> 049 * 050 * @author David M. Harland 051 * @since 2007-08-09 052 */ 053 public class PstSourceCatalogReader 054 extends AbstractSourceCatalogReader 055 { 056 private PstSourceReader sourceReader; 057 private LineNumberReader dataReader; 058 059 private Map<String, SourceGroup> catalogGroups; 060 061 /** Creates a new instance. */ 062 public PstSourceCatalogReader() 063 { 064 sourceReader = new PstSourceReader(); 065 } 066 067 /** Prepares this instance to read from a new source. */ 068 private void reset(Reader in, SourceCatalog destination) 069 { 070 catalog = (destination == null) ? new SourceCatalog() : destination; 071 072 catalogGroups = new HashMap<String, SourceGroup>(); 073 074 for (SourceGroup g : catalog.getGroups()) 075 catalogGroups.put(g.getName(), g); 076 077 readWasSuccessful = false; 078 errors.clear(); 079 080 dataReader = new LineNumberReader(in); 081 } 082 083 //============================================================================ 084 // INTERFACE SourceCatalogReader 085 //============================================================================ 086 087 /** 088 * Reads data from {@code in} and uses it to add sources to 089 * {@code destination}. 090 * <p> 091 * <b>Note:</b> this method closes the reader when it is done.</p> 092 * 093 * @param in the source of text that can be read and turned into 094 * {@code Source} objects. 095 * 096 * @param destination the catalog to which the sources should be 097 * added. If this parameter is <i>null</i>, 098 * a new catalog will be created. 099 * 100 * @return <i>true</i> if nothing unexpected occurred while reading data. 101 * 102 * @see #getCatalog() 103 * @see #getErrors() 104 */ 105 public boolean read(Reader in, SourceCatalog destination) 106 { 107 reset(in, destination); 108 109 String line = getNextLine(); 110 111 while (line != null) 112 { 113 if (sourceReader.textCouldBeData(line)) 114 { 115 //Read text, create & fill source, add to catalog. 116 if (!sourceReader.read(line, dataReader.getLineNumber())) 117 errors.addAll(sourceReader.errors); 118 119 Source source = new Source(); 120 121 sourceReader.fillSource(source); 122 123 catalog.addItem(source); 124 125 //Add source to groups, creating new ones if necessary 126 for (String groupName : sourceReader.groups) 127 { 128 SourceGroup group = catalogGroups.get(groupName); 129 130 if (group == null) 131 { 132 //Creates new group and adds it to catalog 133 group = new SourceGroup(catalog, groupName); 134 catalogGroups.put(groupName, group); 135 } 136 137 group.add(source); 138 } 139 } 140 141 line = getNextLine(); 142 } 143 144 try 145 { 146 dataReader.close(); 147 } 148 catch(IOException ioe) 149 { 150 putError(0, "Error closing Reader: " + ioe.getMessage()); 151 } 152 153 readWasSuccessful = getErrorCount() == 0; 154 155 return readWasSuccessful; 156 } 157 158 //============================================================================ 159 // 160 //============================================================================ 161 162 /** Reads lines, returning first one that does not cause an error. */ 163 private String getNextLine() 164 { 165 int attempt = 0; 166 167 while (++attempt <= 100) 168 { 169 try { 170 return dataReader.readLine(); 171 } 172 catch (IOException ex) { 173 putError(dataReader.getLineNumber(), 174 "I/O Exception: " + ex.getMessage()); 175 } 176 } 177 178 throw new RuntimeException("Failed " + attempt + 179 " times while attempting to read a line."); 180 } 181 182 //============================================================================ 183 // 184 //============================================================================ 185 186 //Here for quick testing 187 /* 188 public static void main(String[] args) throws Exception 189 { 190 if (args.length == 0) 191 { 192 System.out.println("Specify an input file on the command line."); 193 System.exit(9); 194 } 195 196 java.io.FileReader input = new java.io.FileReader(args[0]); 197 PstSourceCatalogReader reader = new PstSourceCatalogReader(); 198 199 System.out.println("Read was flawless? => " + reader.read(input, null)); 200 201 System.out.println("Catalog.toXml:"); 202 203 reader.getCatalog().writeAsXmlTo(new java.io.PrintWriter(System.out)); 204 } 205 */ 206 }