1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.astrogrid.applications.http.registry;
16
17 import java.io.IOException;
18 import java.net.URL;
19 import java.util.ArrayList;
20 import java.util.Collection;
21 import java.util.Iterator;
22 import java.util.List;
23
24 import junit.framework.Test;
25 import junit.framework.TestCase;
26 import junit.framework.TestSuite;
27
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30 import org.astrogrid.applications.beans.v1.types.ApplicationKindType;
31 import org.astrogrid.config.ConfigException;
32 import org.astrogrid.config.PropertyNotFoundException;
33 import org.astrogrid.config.SimpleConfig;
34 import org.astrogrid.registry.RegistryException;
35 import org.astrogrid.registry.beans.cea.CeaHttpApplicationType;
36 import org.astrogrid.registry.beans.resource.IdentifierType;
37 import org.astrogrid.registry.client.RegistryDelegateFactory;
38 import org.astrogrid.registry.client.query.RegistryService;
39 import org.astrogrid.util.DomHelper;
40 import org.exolab.castor.xml.CastorException;
41 import org.exolab.castor.xml.MarshalException;
42 import org.exolab.castor.xml.Unmarshaller;
43 import org.exolab.castor.xml.ValidationException;
44 import org.w3c.dom.Document;
45 import org.w3c.dom.Element;
46 import org.w3c.dom.NodeList;
47
48 /***
49 * A RegistryQuerier that gets generates a list of Http applications from an
50 * actual registry. Much of the code pinched from Workflow's
51 * RegistryApplicationRegistry. Handles any transformation from objects/docs in
52 * the registry to the format we want to work with in the CEA.
53 *
54 * @author jdt
55 */
56 public class RegistryQuerierImpl implements RegistryQuerier {
57 private static final Log log = LogFactory.getLog(RegistryQuerierImpl.class);
58
59 private RegistryService service;
60
61 /***
62 * ctor allowing delegate to find own registry end-point
63 */
64 public RegistryQuerierImpl() {
65 if (log.isTraceEnabled()) {
66 log.trace("RegistryQuerierImpl() - start");
67 }
68
69 service = RegistryDelegateFactory.createQuery();
70 assert service != null;
71
72 if (log.isTraceEnabled()) {
73 log.trace("RegistryQuerierImpl() - end");
74 }
75 }
76
77 /***
78 * Construct a new RegistryQuerierImpl
79 *
80 * @param endpoint endpoint for the astrogrid registry web service
81 */
82 public RegistryQuerierImpl(URL endpoint) {
83 if (log.isTraceEnabled()) {
84 log.trace("RegistryQuerierImpl(URL endpoint = " + endpoint + ") - start");
85 }
86
87 service = RegistryDelegateFactory.createQuery(endpoint);
88 assert service != null;
89
90 if (log.isTraceEnabled()) {
91 log.trace("RegistryQuerierImpl(URL) - end");
92 }
93 }
94
95 /***
96 * Query string to select only CeaHttpApplications in the registry
97 */
98
99
100
101
102
103
104
105
106
107 private final static String LIST_QUERY_STRING = "Select * from Registry " +
108 " where @xsi:type='cea:CeaHttpApplicationType'";
109
110
111 /***
112 * Get the names of all the applications in the registry matching
113 * LIST_QUERY_STRING An empty List could indicate entries in the registry
114 * aren't in the right format and can't be unmarshalled.
115 *
116 * @return List of application name strings
117 * @throws RegistryException on registry comms probs
118 */
119 protected List listApplications() throws RegistryException {
120 if (log.isTraceEnabled()) {
121 log.trace("listApplications() - start");
122 }
123
124 try {
125 log.debug("Querying registry: "+LIST_QUERY_STRING);
126
127 Document doc = service.searchFromSADQL(LIST_QUERY_STRING);
128
129 assert doc != null;
130 NodeList nl = doc.getElementsByTagNameNS("*", "Identifier");
131 log.debug("...got doc with "+nl.getLength()+" Identifier elements");
132 List namesList = new ArrayList();
133 for (int i = 0; i < nl.getLength(); i++) {
134 IdentifierType it;
135 try {
136 it = (IdentifierType) Unmarshaller.unmarshal(IdentifierType.class, nl.item(i));
137 String name = it.getAuthorityID() + "/" + it.getResourceKey();
138 namesList.add(name);
139 log.debug("Adding "+name+" to list of applications");
140 } catch (MarshalException e1) {
141 log.error("listApplications(): problem unmarshalling " + nl.item(i) + " cannot add to list", e1);
142 } catch (ValidationException e1) {
143 log.error("listApplications(): problem validating " + nl.item(i) + " cannot add to list", e1);
144 }
145 }
146
147 if (log.isTraceEnabled()) {
148 log.trace("listApplications() - end - return value = " + namesList);
149 }
150 return namesList;
151 } catch (RegistryException e) {
152 log.error("listApplications Failed with exception from registry", e);
153 throw e;
154 }
155 }
156
157 /***
158 * Get application by name from the registry
159 *
160 * @see org.astrogrid.portal.workflow.intf.ApplicationRegistry#getDescriptionFor(java.lang.String)
161 * @param applicationName application name in registry as returned by
162 * listApplications()
163 * @return a WebHttpApplication containing all the details stored in the
164 * registry
165 * @throws CastorException castor unmarshalling probs
166 * @throws RegistryCallException on registry comms probs
167 */
168 private CeaHttpApplicationType getDescriptionFor(String applicationName) throws RegistryException, CastorException {
169 if (log.isTraceEnabled()) {
170 log.trace("getDescriptionFor(String applicationName = " + applicationName + ") - start");
171 }
172
173 try {
174 final Document doc = service.getResourceByIdentifier(applicationName);
175 assert doc != null;
176
177 final CeaHttpApplicationType webApplication = (CeaHttpApplicationType) unmarshal(doc,
178 CeaHttpApplicationType.class, "Resource");
179
180 if (log.isTraceEnabled()) {
181 log.trace("getDescriptionFor(String) - end - return value = " + webApplication);
182 }
183 return webApplication;
184 } catch (CastorException e) {
185 log.error("getDescriptionFor " + applicationName + " - castor failed to parse result", e);
186 throw e;
187 } catch (RegistryException e) {
188 log.error("getDescriptionFor " + applicationName + " - exception from registry", e);
189 throw e;
190 }
191 }
192
193
194 /***
195 * @see org.astrogrid.component.descriptor.ComponentDescriptor#getInstallationTest()
196 */
197 public Test getInstallationTest() {
198 TestSuite suite = new TestSuite();
199 suite.addTest(new InstallationTest("testRegistryEndPointPropertyFound"));
200 suite.addTest(new InstallationTest("testRegistryServiceFound"));
201 suite.addTest(new InstallationTest("testRegistryContainsOneOrMoreHttpApplications"));
202 return suite;
203 }
204 /***
205 * Some installation tests.
206 * There's a certain amount of redundancy here (test 2 will fail if test 1 does etc)
207 * but the tests are performed separately to make problems
208 * clearer to the user.
209 * @author jdt
210 */
211 public class InstallationTest extends TestCase {
212 public InstallationTest(String arg0) {
213 super(arg0);
214 }
215 /***
216 * Can we find the endpoint of the registry in properties?
217 * Not convinced this should be here, but it has
218 * the side effect that it helps us determine if *any*
219 * properties can be found
220 *
221 */
222 public void testRegistryEndPointPropertyFound() {
223
224
225 String key = "org.astrogrid.registry.query.endpoint";
226 try {
227 String endPoint = SimpleConfig.getProperty(key);
228 assertNotNull("The Property "+key+" is not set - check your configuration file");
229 } catch (ConfigException e ) {
230 fail("There was a problem accessing the configuration file: "+e.getMessage());
231 } catch (PropertyNotFoundException e) {
232 fail("The Property "+key+" is not set - check your configuration file");
233 }
234 }
235 public void testRegistryServiceFound() throws RegistryException {
236 assertNotNull("No registry service found", service);
237
238
239
240
241 Object doc = service.loadRegistry();
242 assertNotNull("No registry service found. Check that your registry is up and running and that the property org.astrogrid.registry.query.endpoint is set correctly.", doc);
243 }
244 public void testRegistryContainsOneOrMoreHttpApplications() throws IOException {
245 Collection apps = getHttpApplications();
246 assertFalse("There were no http applications in the registry. Check your registry entries and this error might go away.", apps.isEmpty());
247 }
248
249 }
250 /***
251 * Unmarshall a node of a Document into a class
252 *
253 * @param doc the document
254 * @param clazz the class you hope to get back
255 * @param elementName the element name in the document you hope matches the
256 * class
257 * @return object that will need casting...
258 * @throws MarshalException
259 * @throws ValidationException
260 * @throws RegistryCallException
261 */
262 private Object unmarshal(final Document doc, final Class clazz, final String elementName) throws MarshalException,
263 ValidationException, RegistryException {
264 if (log.isTraceEnabled()) {
265 log.trace("unmarshal(Document doc = " + doc + ", Class clazz = " + clazz + ", String elementName = "
266 + elementName + ") - start");
267 }
268
269 if (log.isDebugEnabled()) {
270 log.debug("Unmarshalling document:");
271 log.debug(DomHelper.DocumentToString(doc));
272 log.debug("=======================");
273 }
274
275 final NodeList nls = doc.getElementsByTagNameNS("*", elementName);
276 if (nls.getLength() == 0) {
277 throw new RegistryException("Registry entry has no " + elementName + " Element");
278 }
279 final Element ns = (Element) nls.item(0);
280 ns.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); //bug-fix work around.
281 Object returnObject = Unmarshaller.unmarshal(clazz, ns);
282 if (log.isTraceEnabled()) {
283 log.trace("unmarshal(Document, Class, String) - end - return value = " + returnObject);
284 }
285 return returnObject;
286 }
287
288 /***
289 * Returns a List of WebHttpApplications from the Registry. Note, that if
290 * this method returns an empty list, it might indicate communication
291 * problems with the registry, or that the registry entries are invalid and
292 * not unmarshalable
293 *
294 * @throws
295 * @see org.astrogrid.applications.http.registry.RegistryQuerier#getHttpApplications()
296 */
297 public Collection getHttpApplications() throws IOException {
298 if (log.isTraceEnabled()) {
299 log.trace("getHttpApplications() - start");
300 }
301
302
303 try {
304 List apps = new ArrayList();
305
306 List names = listApplications();
307 log.debug("Got a list of "+names.size()+" applications");
308 Iterator it = names.iterator();
309 while (it.hasNext()) {
310 String name = (String) it.next();
311 try {
312 final CeaHttpApplicationType description = getDescriptionFor(name);
313 ApplicationKindType type=description.getApplicationDefinition().getApplicationKind();
314 if (ApplicationKindType.HTTP.equals(type)) {
315 apps.add(description);
316 log.debug("Adding "+description.getShortName()+" to list");
317 } else {
318 log.warn("Description "+description.getShortName()+" is listed in the registry as a CeaHttpApplication, but is actually a "+type+" app. Must be an http app.");
319 log.warn("=>not adding to list");
320 }
321 } catch (CastorException e) {
322 log.info("getHttpApplications(): problem unmarshalling " + name + ", not adding to list", e);
323 }
324 }
325
326 if (log.isTraceEnabled()) {
327 log.trace("getHttpApplications() - end - return value = " + apps);
328 }
329 return apps;
330 } catch (RegistryException e) {
331 log.error("getHttpApplications(): RegistryException", e);
332 throw new IOException("Problem communicating with Registry");
333 }
334 }
335
336 public String toString() {
337 if (log.isTraceEnabled()) {
338 log.trace("toString() - start");
339 }
340
341 StringBuffer buffer = new StringBuffer();
342 buffer.append("[RegistryQuerierImpl:");
343 buffer.append(" log: ");
344 buffer.append(log);
345 buffer.append(" service: ");
346 buffer.append(service);
347 buffer.append(" LIST_QUERY_STRING: ");
348 buffer.append(LIST_QUERY_STRING);
349 buffer.append("]");
350 String returnString = buffer.toString();
351 if (log.isTraceEnabled()) {
352 log.trace("toString() - end - return value = " + returnString);
353 }
354 return returnString;
355 }
356
357
358
359
360 public String getName() {
361 return "RegistryQuerierImpl";
362 }
363
364
365
366
367 public String getDescription() {
368 return "Talks to the registry to get http applications";
369 }
370 }