1
2
3
4
5
6
7 package org.astrogrid.tableserver.out;
8 import java.io.BufferedWriter;
9 import java.io.IOException;
10 import java.io.PrintWriter;
11 import java.io.Writer;
12 import java.security.Principal;
13 import java.util.Date;
14 import org.apache.commons.logging.Log;
15 import org.astrogrid.slinger.mime.MimeTypes;
16 import org.astrogrid.slinger.targets.TargetIdentifier;
17 import org.astrogrid.tableserver.metadata.ColumnInfo;
18
19 /***
20 * For writing out tables in votable. As far as I'm aware dates are not handled
21 * by VOTables (by Jan 2005). Since I'm stroppely ignoring VOTable development as
22 * irrelevent (ie I'm not going to try and push for standard date support, they can
23 * get around to it whenever), dates here are written as the 'C standard' number of seconds since
24 * 1970 (negative numbers before 1970), with type 'float' so we can provide milliseconds
25 * etc. NB we need to handle dates from several thousand BC.
26 *
27 * @author M Hill
28 */
29
30 public class VoTableWriter implements TableWriter {
31
32
33 protected static final Log log = org.apache.commons.logging.LogFactory.getLog(VoTableWriter.class);
34
35 protected PrintWriter printOut = null;
36
37 protected ColumnInfo[] cols = null;
38
39 public final static String TYPE_LONG = "long";
40 public final static String TYPE_BOOLEAN = "boolean";
41 public final static String TYPE_BIT = "bit";
42 public final static String TYPE_UBYTE = "unsignedByte";
43 public final static String TYPE_CHAR = "char";
44 public final static String TYPE_UNICHAR = "unicodeChar";
45 public final static String TYPE_DOUBLE = "double";
46 public final static String TYPE_FLOAT = "float";
47 public final static String TYPE_DOUBLECOMPLEX = "doubleComplex";
48 public final static String TYPE_FLOATCOMPLEX = "floatComplex";
49 public final static String TYPE_INT = "int";
50 public final static String TYPE_SHORT = "short";
51
52 public final static String[] TYPES = new String[] {
53 TYPE_LONG, TYPE_BOOLEAN, TYPE_BIT, TYPE_UBYTE, TYPE_CHAR, TYPE_UNICHAR, TYPE_DOUBLE, TYPE_FLOAT, TYPE_DOUBLECOMPLEX, TYPE_FLOATCOMPLEX, TYPE_INT, TYPE_SHORT
54 };
55
56 /***
57 * Construct this wrapping the given stream. Writes out the first few tags
58 */
59 public VoTableWriter(TargetIdentifier target, String title, Principal user) throws IOException {
60
61 target.setMimeType(MimeTypes.VOTABLE, user);
62
63 printOut = new PrintWriter(new BufferedWriter(target.resolveWriter(user)));
64
65
66 printOut.println("<VOTABLE version='1.0'>");
67
68
69
70
71
72
73
74 printOut.println("<RESOURCE>");
75
76
77
78
79
80
81
82
83
84 }
85
86
87 /*** Produces text/html */
88 public String getMimeType() {
89 return MimeTypes.VOTABLE;
90 }
91
92 /***Returns the VOTable type for the given java class type */
93 public static String getVoTableType(Class javatype) {
94 if (javatype == String.class) { return TYPE_CHAR; }
95 else if (javatype == Integer.class) { return TYPE_INT; }
96 else if (javatype == Long.class) { return TYPE_INT; }
97 else if (javatype == Float.class) { return TYPE_FLOAT; }
98 else if (javatype == Double.class) { return TYPE_FLOAT; }
99 else if (javatype == Boolean.class) { return TYPE_BOOLEAN; }
100 else if (javatype == Date.class) { return TYPE_FLOAT; }
101 else {
102 log.error("Don't know what VOtable type the java class "+javatype+" maps to, returning string");
103 return TYPE_CHAR;
104 }
105 }
106
107
108 /*** Start body - writes out header and preps col array */
109 public void startTable(ColumnInfo[] cols) throws IOException {
110
111 printOut.println("<TABLE>");
112
113 for (int i = 0; i < cols.length; i++) {
114 if (cols[i] == null) {
115 throw new IllegalArgumentException("No information for column "+i);
116 }
117
118 printOut.print("<FIELD name='"+cols[i].getName()+"' ");
119 if (cols[i].getId() != null) printOut.print("ID='"+cols[i].getId()+"' ");
120 if (cols[i].getUcd("1") != null) printOut.print(" ucd='"+cols[i].getUcd("1")+"' ");
121
122
123 if (cols[i].getPublicType() != null) {
124
125 String type = null;
126 for (int t = 0; t < TYPES.length; t++)
127 {
128 if (cols[i].getPublicType().equals(TYPES[t])) {
129 type = TYPES[t];
130 }
131 }
132 if (type == null) {
133
134 if (cols[i].getPublicType().toLowerCase().equals("real")) {
135 type = TYPE_FLOAT;
136 }
137 else if (cols[i].getPublicType().toLowerCase().equals("smallint")) {
138 type = TYPE_INT;
139 }
140 else if (cols[i].getPublicType().toLowerCase().equals("varchar")) {
141 type = TYPE_CHAR;
142 }
143 }
144
145 if (type==null) {
146 type = getVoTableType(cols[i].getJavaType());
147 }
148
149 if (type != null) {
150 printOut.print(" datatype='"+type+"'");
151 }
152 }
153
154
155 if (cols[i].getJavaType() == Date.class) {
156 printOut.print(" units='s' ");
157 }
158 else {
159 if (cols[i].getUnits() != null) printOut.print(" units='"+cols[i].getUnits()+"' ");
160 }
161 printOut.println("/>");
162 }
163
164 printOut.flush();
165
166
167 printOut.println("<DATA>");
168 printOut.println("<TABLEDATA>");
169
170 }
171
172 /*** Writes the given array of values out */
173 public void writeRow(Object[] colValues) throws IOException {
174
175 printOut.print("<TR>");
176 for (int i=0;i<colValues.length;i++) {
177 if (colValues[i] instanceof Date) {
178 printOut.print("<TD>"+ (float) (((Date) colValues[i]).getTime()/1000) +"</TD>");
179 }
180 else {
181 printOut.print("<TD>"+colValues[i]+"</TD>");
182 }
183 }
184 printOut.println("</TR>");
185
186 }
187
188 public void endTable() {
189
190 printOut.println("</TABLEDATA>");
191 printOut.println("</DATA>");
192
193
194 printOut.println("</TABLE>");
195 }
196
197 /*** Closes writer - writes out the closing tags and closes wrapped stream
198 */
199 public void close() {
200
201 printOut.println("</RESOURCE>");
202
203 printOut.println("</VOTABLE>");
204
205 printOut.close();
206 }
207
208 /*** Abort writes out a line to show the table is incomplete */
209 public void abort() {
210 printOut.println("<tr><td> ------------------ Writing Aborted -----------------</td></tr> ");
211 close();
212 }
213
214 /*** Convenience method to get direct access to the output stream, so that we can pipe votables direct */
215 public Writer getOut() {
216 return printOut;
217 }
218
219 }
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285