1
2
3
4
5
6
7 package org.astrogrid.datacenter.metadata;
8 import java.io.IOException;
9 import java.io.StringWriter;
10 import java.lang.reflect.Constructor;
11 import java.net.URL;
12 import java.text.SimpleDateFormat;
13 import java.util.Calendar;
14 import java.util.Date;
15 import java.util.GregorianCalendar;
16 import java.util.Locale;
17 import java.util.TimeZone;
18 import javax.xml.parsers.ParserConfigurationException;
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.astrogrid.config.PropertyNotFoundException;
22 import org.astrogrid.config.SimpleConfig;
23 import org.astrogrid.datacenter.DsaDomHelper;
24 import org.astrogrid.datacenter.cone.ConeResourceServer;
25 import org.astrogrid.datacenter.service.DataServer;
26 import org.astrogrid.datacenter.service.skynode.v074.SkyNodeResourceServer;
27 import org.astrogrid.io.xml.XmlPrinter;
28 import org.astrogrid.io.xml.XmlTagPrinter;
29 import org.astrogrid.registry.RegistryException;
30 import org.astrogrid.registry.client.RegistryDelegateFactory;
31 import org.astrogrid.registry.client.admin.RegistryAdminService;
32 import org.astrogrid.util.DomHelper;
33 import org.w3c.dom.Document;
34 import org.w3c.dom.Element;
35 import org.w3c.dom.NodeList;
36 import org.xml.sax.SAXException;
37
38 /***
39 * Serves the service's VoDescrption.
40 * <p>
41 * This file includes a VODescrption element, but at the moment I am assuming that
42 * the VODescription might be wrapped in other by combining the various Resources returned
43 * by the configured MetataPlugins into a VODescription.
44 *
45 * <p>See package documentation.
46 * <p>
47 * @author M Hill
48 */
49
50 public class VoDescriptionServer {
51 protected static Log log = LogFactory.getLog(VoDescriptionServer.class);
52
53 private static Document cache = null;
54
55 public static final String AUTHID_KEY = "datacenter.authorityId";
56 public static final String RESKEY_KEY = "datacenter.resourceKey";
57
58 public final static String VODESCRIPTION_ELEMENT =
59 "<VODescription xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' "+
60 "xmlns:cea='http://www.ivoa.net/xml/CEAService/v0.1' "+
61 "xmlns:ceapd='http://www.astrogrid.org/schema/AGParameterDefinition/v1' "+
62 "xmlns:ceab='http://www.astrogrid.org/schema/CommonExecutionArchitectureBase/v1' "+
63 "xmlns:vr='http://www.ivoa.net/xml/VOResource/v0.9' "+
64 "xmlns='http://www.ivoa.net/xml/VOResource/v0.9' "+ //default namespace
65 ">";
66 public final static String VODESCRIPTION_ELEMENT_END ="</VODescription>";
67
68 /*** used to format dates so that the registry can process them. eg 2005-11-04T15:34:22Z -
69 * the date must be GMT */
70 public final static SimpleDateFormat REGISTRY_DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
71
72 /***
73 * Returns the whole metadata file as a DOM document
74 */
75 public synchronized static Document getVoDescription() throws IOException {
76 if (cache == null) {
77 try {
78 cache = DomHelper.newDocument(makeVoDescription().toString());
79
80
81 validate(cache);
82 }
83 catch (ParserConfigurationException e) {
84 throw new RuntimeException("Server not setup properly: "+e,e);
85 }
86 catch (SAXException e) {
87 throw new MetadataException("XML error with Metadata: "+e,e);
88 }
89 }
90 return cache;
91 }
92
93 /*** Checks that the given document is a valid vodescription, throwing an
94 * exception if not */
95 public static void validate(Document vod) throws MetadataException {
96 Element root = vod.getDocumentElement();
97
98 NodeList children = root.getChildNodes();
99
100 for (int i = 0; i < children.getLength(); i++) {
101 if (children.item(i) instanceof Element) {
102 Element resource = (Element) children.item(i);
103
104 if (!resource.getNodeName().equals("Resource")) {
105 throw new MetadataException("VODescription Child "+i+" ("+resource.getNodeName()+") is not a Resource element");
106 }
107
108 Element id = DsaDomHelper.getSingleChildByTagName(resource, "Identifier");
109 if (id == null) {
110
111 throw new MetadataException("Resource "+i+" (xsi:type="+resource.getAttribute("xsi:type")+") has no Identifier");
112 }
113
114 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(id, "AuthorityID"), SimpleConfig.getSingleton().getString(VoDescriptionServer.AUTHID_KEY));
115 Element resKey = DsaDomHelper.getSingleChildByTagName(id, "ResourceKey");
116 if ((resKey == null) || (DomHelper.getValue(resKey).trim().length()==0)) {
117
118 throw new MetadataException("Identifier in Resource "+i+" (xsi:type="+resource.getAttribute("xsi:type")+") has no ResourceKey");
119 }
120 }
121 }
122
123 }
124
125 /*** Instantiates the class with the given name. This is useful for things
126 * such as 'plugins', where a class name might be given in a configuration file.
127 * Rather messily throws Throwable because anything might have
128 * gone wrong in the constructor.
129 */
130 public static VoResourcePlugin createPlugin(String pluginClassName) {
131
132 Object plugin = null;
133
134 try {
135 log.debug("Creating VoResourcePlugin '"+pluginClassName+"'");
136
137 Class qClass = Class.forName(pluginClassName);
138
139
140
141
142
143
144
145
146
147 Constructor constr = qClass.getConstructor(new Class[] { });
148 plugin = constr.newInstance(new Object[] { } );
149
150 }
151 catch (ClassNotFoundException cnfe) {
152 throw new RuntimeException("Could not find metadata plugin class "+pluginClassName);
153 }
154 catch (NoSuchMethodException nsme) {
155 throw new RuntimeException("Bad metadata plugin specified ("+pluginClassName+") - has no zero-argument constructor");
156 }
157 catch (Throwable th) {
158 throw new RuntimeException("Bad metadata plugin specified ("+pluginClassName+")",th);
159 }
160
161 if (!(plugin instanceof VoResourcePlugin)) {
162 throw new RuntimeException("Bad metadata plugin specified ("+pluginClassName+") - does not implement VoResourcePlugin");
163 }
164
165 return (VoResourcePlugin) plugin;
166
167 }
168
169 /***
170 * Clears the cache - useful to call before doing a set of operations, forces
171 * metadata to be refreshed from disk
172 */
173 public synchronized static void clearCache() {
174 cache = null;
175 }
176
177 /***
178 * Make a VODescription document out of all the voResourcePlugins, returning an
179 * unvalidated string. This means we can view the made (finsihed) docuemnt
180 * separate from the validating process. */
181 public static String makeVoDescription() throws IOException, MetadataException {
182
183
184 Object[] plugins = null;
185 try {
186 plugins = SimpleConfig.getSingleton().getProperties(VoResourcePlugin.RESOURCE_PLUGIN_KEY);
187 } catch (PropertyNotFoundException pnfe)
188 {
189
190 String s = SimpleConfig.getSingleton().getString("datacenter.metadata.plugin",null);
191 if (s != null) {
192 plugins = new String[] { s };
193 }
194 }
195
196
197 StringBuffer vod = new StringBuffer();
198 vod.append(VODESCRIPTION_ELEMENT+"\n");
199 boolean ceaDone = false;
200
201
202 if (plugins != null) {
203 for (int p = 0; p < plugins.length; p++) {
204
205 VoResourcePlugin plugin = createPlugin(plugins[p].toString());
206
207 addResources(vod, plugin);
208
209 if (plugin instanceof CeaResourceServer) { ceaDone = true; }
210 }
211 }
212
213
214 if (!ceaDone) { addResources(vod, new CeaResourceServer()); }
215 addResources(vod, new ConeResourceServer());
216 addResources(vod, new SkyNodeResourceServer());
217
218
219 vod.append(VODESCRIPTION_ELEMENT_END);
220
221 return vod.toString();
222 }
223
224 /*** Convenience routine for the above to load the resources from the given plugin
225 * to the given StringBuffer */
226 private static void addResources(StringBuffer b, VoResourcePlugin plugin) throws IOException {
227 String[] voResources = plugin.getVoResources();
228
229 for (int r = 0; r < voResources.length; r++) {
230 b.append(voResources[r]);
231 }
232 return;
233 }
234
235 /***
236 * Returns the Authority resource element of the description */
237 public static Element getAuthorityResource() throws IOException {
238 return getResource("AuthorityType");
239 }
240
241 /***
242 * Returns the resource element of the given type eg 'AuthorityID'.
243 * Matches the given string against the attribute 'xsi:type' of the elements
244 * named 'Resource'
245 */
246 public static Element getResource(String type) throws IOException {
247 NodeList resources = getVoDescription().getElementsByTagName("Resource");
248
249 for (int i = 0; i < resources.getLength(); i++) {
250 Element resource = (Element) resources.item(i);
251 if (resource.getAttribute("xsi:type").equals(type)) {
252 return resource;
253 }
254 }
255 return null;
256 }
257
258 /***
259 * Sends the voDescription to the registry, returning list of Registries that
260 * it was sent to
261 */
262 public static String[] pushToRegistry() throws IOException, RegistryException {
263 RegistryAdminService service = RegistryDelegateFactory.createAdmin();
264 service.update(getVoDescription());
265 return new String[] { SimpleConfig.getSingleton().getString(RegistryDelegateFactory.ADMIN_URL_PROPERTY) };
266 }
267
268 /***
269 * Sends the voDescription to the given registry URL, returning list of Registries that
270 * it was sent to
271 */
272 public static void pushToRegistry(URL targetRegistry) throws IOException, RegistryException {
273 RegistryAdminService service = RegistryDelegateFactory.createAdmin(targetRegistry);
274 service.update(getVoDescription());
275 }
276
277 /*** Adds an Identifier tag to the given XmlPrinter */
278 public static void writeIdentifier(XmlTagPrinter parent, String resourceKeyEnd) throws IOException {
279 XmlTagPrinter identifier = parent.newTag("Identifier");
280 identifier.writeTag("AuthorityID", SimpleConfig.getSingleton().getString(AUTHID_KEY));
281 identifier.writeTag("ResourceKey", SimpleConfig.getSingleton().getString(RESKEY_KEY)+resourceKeyEnd);
282 }
283
284 /*** Writes out standard summary stuff to the given XmlPrinter */
285 public static void writeSummary(XmlTagPrinter parent) throws IOException {
286 parent.writeTag("Title", DataServer.getDatacenterName());
287 parent.writeTag("ShortName", SimpleConfig.getSingleton().getString("datacenter.shortname", ""));
288
289 XmlTagPrinter summary = parent.newTag("Summary");
290 summary.writeTag("Description", SimpleConfig.getSingleton().getString("datacenter.description", ""));
291 summary.writeTag("ReferenceURL", SimpleConfig.getSingleton().getString("datacenter.url", ""));
292 }
293
294 /*** Writes out standard curation stuff to the given XmlPrinter */
295 public static void writeCuration(XmlTagPrinter parent) throws IOException {
296 XmlTagPrinter curation = parent.newTag("Curation");
297 String publisher = SimpleConfig.getSingleton().getString("datacenter.publisher",null);
298 if (publisher != null) {
299 XmlTagPrinter publisherTag = curation.newTag("Publisher");
300 publisherTag.writeTag("Title", publisher);
301 }
302
303 XmlTagPrinter contact = curation.newTag("Contact");
304 contact.writeTag("Name", SimpleConfig.getSingleton().getString("datacenter.contact.name",""));
305 contact.writeTag("Email", SimpleConfig.getSingleton().getString("datacenter.contact.email",""));
306 contact.writeTag("Date", SimpleConfig.getSingleton().getString("datacenter.contact.date",""));
307 }
308
309 public static void appendSummary(StringBuffer buffer) throws IOException {
310 StringWriter sw = new StringWriter();
311 XmlPrinter xp = new XmlPrinter(sw, false);
312 writeSummary(xp);
313 xp.close();
314 buffer.append(sw.toString());
315 }
316
317 public static void appendIdentifier(StringBuffer buffer, String resourceKeyEnd) throws IOException {
318 StringWriter sw = new StringWriter();
319 XmlPrinter xp = new XmlPrinter(sw, false);
320 writeIdentifier(xp, resourceKeyEnd);
321 xp.close();
322 buffer.append(sw.toString());
323 }
324
325 public static void appendCuration(StringBuffer buffer) throws IOException {
326 StringWriter sw = new StringWriter();
327 XmlPrinter xp = new XmlPrinter(sw, false);
328 writeCuration(xp);
329 xp.close();
330 buffer.append(sw.toString());
331 }
332
333 /*** Checks that the identifier elements are there and set to the local values,
334 * creating and setting if not. The given resourceKeyEnd is appended to the
335 datacenter's resourceKey to give the appropriate full resource key */
336 public static void ensureIdentifier(Element resource, String resourceKeyEnd) {
337
338
339 Element voIdTag = DsaDomHelper.ensuredGetSingleChild(resource, "Identifier");
340
341 String dsaResKey = SimpleConfig.getSingleton().getString(VoDescriptionServer.RESKEY_KEY);
342
343 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(voIdTag, "AuthorityID"), SimpleConfig.getSingleton().getString(VoDescriptionServer.AUTHID_KEY));
344 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(voIdTag, "ResourceKey"), SimpleConfig.getSingleton().getString(VoDescriptionServer.RESKEY_KEY)+resourceKeyEnd);
345 }
346
347 /*** Checks the summary elements are there and set to the local values (creating it if not) */
348 public static void ensureSummary(Element resource) {
349 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(resource, "Title"), DataServer.getDatacenterName());
350 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(resource, "ShortName"), SimpleConfig.getSingleton().getString("datacenter.shortname", ""));
351
352 Element summary = DsaDomHelper.ensuredGetSingleChild(resource, "Summary");
353 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(summary, "Description"), SimpleConfig.getSingleton().getString("datacenter.description", ""));
354 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(summary, "ReferenceURL"), SimpleConfig.getSingleton().getString("datacenter.url", ""));
355 }
356
357 /*** Checks the curation stuff is present and set to the local values (creating it if not) */
358 public static void ensureCuration(Element resource) {
359 Element curation = DsaDomHelper.ensuredGetSingleChild(resource, "Curation");
360 String publisher = SimpleConfig.getSingleton().getString("datacenter.publisher",null);
361 if (publisher != null) {
362 Element title = DsaDomHelper.ensuredGetSingleChild(curation, "Title");
363 DsaDomHelper.setElementValue(title, publisher);
364 }
365
366 Element contact = DsaDomHelper.ensuredGetSingleChild(curation, "Contact");
367 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(contact, "Name"), SimpleConfig.getSingleton().getString("datacenter.contact.name", ""));
368 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(contact, "Email"), SimpleConfig.getSingleton().getString("datacenter.contact.email", ""));
369 DsaDomHelper.setElementValue(DsaDomHelper.ensuredGetSingleChild(contact, "Date"), SimpleConfig.getSingleton().getString("datacenter.contact.date", ""));
370 }
371
372 /*** Converts date to string suitable for registry */
373 public String toRegistryForm(Date givenDate) {
374
375
376
377
378
379
380 SimpleDateFormat offsetGetter = new SimpleDateFormat("Z");
381 String offsetName = offsetGetter.format(givenDate);
382 TimeZone givenZone = TimeZone.getTimeZone(offsetName);
383 int offset = givenZone.getOffset(givenDate.getTime());
384
385
386
387
388 Calendar localCalender = Calendar.getInstance();
389 TimeZone localZone = localCalender.getTimeZone();
390 Calendar ukcalender = new GregorianCalendar(Locale.ENGLISH);
391 TimeZone gmtZone = TimeZone.getTimeZone("GMT");
392
393 return "";
394 }
395
396 }
397
398
399
400
401
402
403
404