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 private final static String LIST_QUERY_STRING = "<query><selectionSequence>" +
99 "<selection item='searchElements' itemOp='EQ' value='vr:Resource'/>" +
100 "<selectionOp op='$and$'/>" +
101 "<selection item='@xsi:type' itemOp='EQ' value='CeaHttpApplicationType'/>" +
102 "<selectionOp op='OR'/>" +
103 "<selection item='@xsi:type' itemOp='EQ' value='cea:CeaHttpApplicationType'/>" +
104 "</selectionSequence></query>";
105
106
107 /***
108 * Get the names of all the applications in the registry matching
109 * LIST_QUERY_STRING An empty List could indicate entries in the registry
110 * aren't in the right format and can't be unmarshalled.
111 *
112 * @return List of application name strings
113 * @throws RegistryException on registry comms probs
114 */
115 protected List listApplications() throws RegistryException {
116 if (log.isTraceEnabled()) {
117 log.trace("listApplications() - start");
118 }
119
120 try {
121 log.debug("Querying registry: "+LIST_QUERY_STRING);
122 Document doc = service.submitQuery(LIST_QUERY_STRING);
123 assert doc != null;
124 NodeList nl = doc.getElementsByTagNameNS("*", "Identifier");
125 log.debug("...got doc with "+nl.getLength()+" Identifier elements");
126 List namesList = new ArrayList();
127 for (int i = 0; i < nl.getLength(); i++) {
128 IdentifierType it;
129 try {
130 it = (IdentifierType) Unmarshaller.unmarshal(IdentifierType.class, nl.item(i));
131 String name = it.getAuthorityID() + "/" + it.getResourceKey();
132 namesList.add(name);
133 log.debug("Adding "+name+" to list of applications");
134 } catch (MarshalException e1) {
135 log.error("listApplications(): problem unmarshalling " + nl.item(i) + " cannot add to list", e1);
136 } catch (ValidationException e1) {
137 log.error("listApplications(): problem validating " + nl.item(i) + " cannot add to list", e1);
138 }
139 }
140
141 if (log.isTraceEnabled()) {
142 log.trace("listApplications() - end - return value = " + namesList);
143 }
144 return namesList;
145 } catch (RegistryException e) {
146 log.error("listApplications Failed with exception from registry", e);
147 throw e;
148 }
149 }
150
151 /***
152 * Get application by name from the registry
153 *
154 * @see org.astrogrid.portal.workflow.intf.ApplicationRegistry#getDescriptionFor(java.lang.String)
155 * @param applicationName application name in registry as returned by
156 * listApplications()
157 * @return a WebHttpApplication containing all the details stored in the
158 * registry
159 * @throws CastorException castor unmarshalling probs
160 * @throws RegistryCallException on registry comms probs
161 */
162 private CeaHttpApplicationType getDescriptionFor(String applicationName) throws RegistryException, CastorException {
163 if (log.isTraceEnabled()) {
164 log.trace("getDescriptionFor(String applicationName = " + applicationName + ") - start");
165 }
166
167 try {
168 final Document doc = service.getResourceByIdentifier(applicationName);
169 assert doc != null;
170
171 final CeaHttpApplicationType webApplication = (CeaHttpApplicationType) unmarshal(doc,
172 CeaHttpApplicationType.class, "Resource");
173
174 if (log.isTraceEnabled()) {
175 log.trace("getDescriptionFor(String) - end - return value = " + webApplication);
176 }
177 return webApplication;
178 } catch (CastorException e) {
179 log.error("getDescriptionFor " + applicationName + " - castor failed to parse result", e);
180 throw e;
181 } catch (RegistryException e) {
182 log.error("getDescriptionFor " + applicationName + " - exception from registry", e);
183 throw e;
184 }
185 }
186
187
188 /***
189 * @see org.astrogrid.component.descriptor.ComponentDescriptor#getInstallationTest()
190 */
191 public Test getInstallationTest() {
192 TestSuite suite = new TestSuite();
193 suite.addTest(new InstallationTest("testRegistryEndPointPropertyFound"));
194 suite.addTest(new InstallationTest("testRegistryServiceFound"));
195 suite.addTest(new InstallationTest("testRegistryContainsOneOrMoreHttpApplications"));
196 return suite;
197 }
198 /***
199 * Some installation tests.
200 * There's a certain amount of redundancy here (test 2 will fail if test 1 does etc)
201 * but the tests are performed separately to make problems
202 * clearer to the user.
203 * @author jdt
204 */
205 public class InstallationTest extends TestCase {
206 public InstallationTest(String arg0) {
207 super(arg0);
208 }
209 /***
210 * Can we find the endpoint of the registry in properties?
211 * Not convinced this should be here, but it has
212 * the side effect that it helps us determine if *any*
213 * properties can be found
214 *
215 */
216 public void testRegistryEndPointPropertyFound() {
217
218
219 String key = "org.astrogrid.registry.query.endpoint";
220 try {
221 String endPoint = SimpleConfig.getProperty(key);
222 assertNotNull("The Property "+key+" is not set - check your configuration file");
223 } catch (ConfigException e ) {
224 fail("There was a problem accessing the configuration file: "+e.getMessage());
225 } catch (PropertyNotFoundException e) {
226 fail("The Property "+key+" is not set - check your configuration file");
227 }
228 }
229 public void testRegistryServiceFound() throws RegistryException {
230 assertNotNull("No registry service found", service);
231
232
233
234
235 Object doc = service.loadRegistry();
236 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);
237 }
238 public void testRegistryContainsOneOrMoreHttpApplications() throws IOException {
239 Collection apps = getHttpApplications();
240 assertFalse("There were no http applications in the registry. Check your registry entries and this error might go away.", apps.isEmpty());
241 }
242
243 }
244 /***
245 * Unmarshall a node of a Document into a class
246 *
247 * @param doc the document
248 * @param clazz the class you hope to get back
249 * @param elementName the element name in the document you hope matches the
250 * class
251 * @return object that will need casting...
252 * @throws MarshalException
253 * @throws ValidationException
254 * @throws RegistryCallException
255 */
256 private Object unmarshal(final Document doc, final Class clazz, final String elementName) throws MarshalException,
257 ValidationException, RegistryException {
258 if (log.isTraceEnabled()) {
259 log.trace("unmarshal(Document doc = " + doc + ", Class clazz = " + clazz + ", String elementName = "
260 + elementName + ") - start");
261 }
262
263 if (log.isDebugEnabled()) {
264 log.debug("Unmarshalling document:");
265 log.debug(DomHelper.DocumentToString(doc));
266 log.debug("=======================");
267 }
268
269 final NodeList nls = doc.getElementsByTagNameNS("*", elementName);
270 if (nls.getLength() == 0) {
271 throw new RegistryException("Registry entry has no " + elementName + " Element");
272 }
273 final Element ns = (Element) nls.item(0);
274 ns.setAttribute("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance"); //bug-fix work around.
275 Object returnObject = Unmarshaller.unmarshal(clazz, ns);
276 if (log.isTraceEnabled()) {
277 log.trace("unmarshal(Document, Class, String) - end - return value = " + returnObject);
278 }
279 return returnObject;
280 }
281
282 /***
283 * Returns a List of WebHttpApplications from the Registry. Note, that if
284 * this method returns an empty list, it might indicate communication
285 * problems with the registry, or that the registry entries are invalid and
286 * not unmarshalable
287 *
288 * @throws
289 * @see org.astrogrid.applications.http.registry.RegistryQuerier#getHttpApplications()
290 */
291 public Collection getHttpApplications() throws IOException {
292 if (log.isTraceEnabled()) {
293 log.trace("getHttpApplications() - start");
294 }
295
296
297 try {
298 List apps = new ArrayList();
299
300 List names = listApplications();
301 log.debug("Got a list of "+names.size()+" applications");
302 Iterator it = names.iterator();
303 while (it.hasNext()) {
304 String name = (String) it.next();
305 try {
306 final CeaHttpApplicationType description = getDescriptionFor(name);
307 ApplicationKindType type=description.getApplicationDefinition().getApplicationKind();
308 if (ApplicationKindType.HTTP.equals(type)) {
309 apps.add(description);
310 log.debug("Adding "+description.getShortName()+" to list");
311 } else {
312 log.warn("Description "+description.getShortName()+" is listed in the registry as a CeaHttpApplication, but is actually a "+type+" app. Must be an http app.");
313 log.warn("=>not adding to list");
314 }
315 } catch (CastorException e) {
316 log.info("getHttpApplications(): problem unmarshalling " + name + ", not adding to list", e);
317 }
318 }
319
320 if (log.isTraceEnabled()) {
321 log.trace("getHttpApplications() - end - return value = " + apps);
322 }
323 return apps;
324 } catch (RegistryException e) {
325 log.error("getHttpApplications(): RegistryException", e);
326 throw new IOException("Problem communicating with Registry");
327 }
328 }
329
330 public String toString() {
331 if (log.isTraceEnabled()) {
332 log.trace("toString() - start");
333 }
334
335 StringBuffer buffer = new StringBuffer();
336 buffer.append("[RegistryQuerierImpl:");
337 buffer.append(" log: ");
338 buffer.append(log);
339 buffer.append(" service: ");
340 buffer.append(service);
341 buffer.append(" LIST_QUERY_STRING: ");
342 buffer.append(LIST_QUERY_STRING);
343 buffer.append("]");
344 String returnString = buffer.toString();
345 if (log.isTraceEnabled()) {
346 log.trace("toString() - end - return value = " + returnString);
347 }
348 return returnString;
349 }
350
351
352
353
354 public String getName() {
355 return "RegistryQuerierImpl";
356 }
357
358
359
360
361 public String getDescription() {
362 return "Talks to the registry to get http applications";
363 }
364 }