source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/GS2BrowseAction.java@ 25986

Last change on this file since 25986 was 25986, checked in by sjm84, 12 years ago

All of the actions that use format statements will now merge in the global format statement

  • Property svn:keywords set to Author Date Id Revision
File size: 18.0 KB
Line 
1package org.greenstone.gsdl3.action;
2
3import java.io.Serializable;
4import java.util.HashMap;
5import java.util.HashSet;
6
7import org.apache.log4j.Logger;
8import org.greenstone.gsdl3.util.GSParams;
9import org.greenstone.gsdl3.util.GSPath;
10import org.greenstone.gsdl3.util.GSXML;
11import org.greenstone.gsdl3.util.GSXSLT;
12import org.greenstone.gsdl3.util.OID;
13import org.greenstone.gsdl3.util.UserContext;
14import org.w3c.dom.Element;
15import org.w3c.dom.Node;
16import org.w3c.dom.NodeList;
17
18/** action for GS2 style classifier browsing */
19public class GS2BrowseAction extends Action
20{
21
22 public static final String CLASSIFIER_ARG = "cl";
23
24 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.GS2BrowseAction.class.getName());
25
26 /** process the request */
27 public Node process(Node message_node)
28 {
29
30 Element message = this.converter.nodeToElement(message_node);
31
32 // get the request - assume only one
33 Element request = (Element) GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
34
35 // the result
36 Element result = this.doc.createElement(GSXML.MESSAGE_ELEM);
37 Element response = classifierBrowse(request);
38 result.appendChild(response);
39 return result;
40 }
41
42 protected Element classifierBrowse(Element request)
43 {
44 Element page_response = this.doc.createElement(GSXML.RESPONSE_ELEM);
45
46 // extract the params from the cgi-request, and check that we have a coll specified
47 Element cgi_paramList = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
48 HashMap<String, Serializable> params = GSXML.extractParams(cgi_paramList, false);
49
50 String service_name = (String) params.get(GSParams.SERVICE);
51 String collection = (String) params.get(GSParams.COLLECTION);
52 if (collection == null || collection.equals(""))
53 {
54 logger.error("classifierBrowse, need to specify a collection!");
55 return page_response;
56 }
57
58 UserContext userContext = new UserContext(request);
59 String to = GSPath.appendLink(collection, service_name);
60
61 // the first part of the response is the service description
62 // for now get this again from the service.
63 // this should be cached somehow later on.
64
65 Element info_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
66 Element info_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_DESCRIBE, to, userContext);
67 info_message.appendChild(info_request);
68
69 // also get the format stuff now if there is some
70 Element format_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_FORMAT, to, userContext);
71 info_message.appendChild(format_request);
72 // process the requests
73
74 Element info_response = (Element) this.mr.process(info_message);
75
76 // the two responses
77 NodeList responses = info_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
78 Element service_response = (Element) responses.item(0);
79 Element format_response = (Element) responses.item(1);
80
81 Element service_description = (Element) GSXML.getChildByTagName(service_response, GSXML.SERVICE_ELEM);
82 page_response.appendChild(this.doc.importNode(service_description, true));
83
84 //append site metadata
85 addSiteMetadata(page_response, userContext);
86 addInterfaceOptions(page_response);
87
88 // if rt=d, then we are just displaying the service
89 String request_type = (String) params.get(GSParams.REQUEST_TYPE);
90 if (request_type.equals("d"))
91 {
92 //return the page that we have so far
93 return page_response;
94 }
95
96 // get the node that the user has clicked on
97 String classifier_node = (String) params.get(CLASSIFIER_ARG);
98
99 // if the node is not defined, return the page that we have so far
100 if (classifier_node == null || classifier_node.equals(""))
101 {
102 return page_response;
103 }
104
105 // the id of the classifier is the top id of the selected node
106 String top_id = OID.getTop(classifier_node);
107 HashSet<String> doc_meta_names = new HashSet<String>();
108 HashSet<String> class_meta_names = new HashSet<String>();
109 // add in the defaults
110 doc_meta_names.add("Title");
111 class_meta_names.add("Title");
112
113 // add the format info into the response
114 Element format_elem = (Element) GSXML.getChildByTagName(format_response, GSXML.FORMAT_ELEM);
115 if (format_elem != null)
116 {
117 // find the one for the classifier we are in
118 Element this_format = GSXML.getNamedElement(format_elem, GSXML.CLASSIFIER_ELEM, GSXML.NAME_ATT, top_id);
119 if (this_format == null)
120 {
121 this_format = (Element) GSXML.getChildByTagName(format_elem, GSXML.DEFAULT_ELEM);
122 }
123
124 if (this_format != null)
125 {
126 Element global_format_elem = (Element) GSXML.getChildByTagName(format_response, GSXML.GLOBAL_FORMAT_ELEM);
127 if(global_format_elem != null)
128 {
129 System.err.println("MERGING " + GSXML.xmlNodeToString(this_format) + "\n\nAND\n\n" + GSXML.xmlNodeToString(global_format_elem));
130 GSXSLT.mergeFormatElements(this_format, global_format_elem, false);
131 System.err.println("RESULT = " + GSXML.xmlNodeToString(this_format));
132 }
133
134 Element new_format = GSXML.duplicateWithNewName(this.doc, this_format, GSXML.FORMAT_ELEM, false);
135 extractMetadataNames(new_format, doc_meta_names, class_meta_names);
136 // set the format type
137 new_format.setAttribute(GSXML.TYPE_ATT, "browse");
138
139 page_response.appendChild(new_format);
140 }
141 }
142
143 // find out if this classifier is horizontal at top
144 Element class_list = (Element) GSXML.getChildByTagName(service_description, GSXML.CLASSIFIER_ELEM + GSXML.LIST_MODIFIER);
145 Element this_classifier = GSXML.getNamedElement(class_list, GSXML.CLASSIFIER_ELEM, GSXML.NAME_ATT, top_id);
146
147 // get the browse structure for the selected node
148 Element classify_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
149 Element classify_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
150 classify_message.appendChild(classify_request);
151
152 //Create a parameter list to specify the required structure information
153 // for now, always get ancestors and children
154 Element param_list = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
155 classify_request.appendChild(param_list);
156 Element param = this.doc.createElement(GSXML.PARAM_ELEM);
157 param_list.appendChild(param);
158 param.setAttribute(GSXML.NAME_ATT, "structure");
159 param.setAttribute(GSXML.VALUE_ATT, "ancestors");
160 param = this.doc.createElement(GSXML.PARAM_ELEM);
161 param_list.appendChild(param);
162 param.setAttribute(GSXML.NAME_ATT, "structure");
163 param.setAttribute(GSXML.VALUE_ATT, "children");
164
165 // put the classifier node into a classifier node list
166 Element classifier_list = this.doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
167 Element classifier = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
168 classifier.setAttribute(GSXML.NODE_ID_ATT, classifier_node);
169 classifier_list.appendChild(classifier);
170 classify_request.appendChild(classifier_list);
171
172 // process the request
173 Element classify_response = (Element) this.mr.process(classify_message);
174
175 String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
176 Element class_node_list = (Element) GSXML.getNodeByPath(classify_response, path);
177
178 path = GSPath.appendLink(GSXML.CLASS_NODE_ELEM, GSXML.NODE_STRUCTURE_ELEM);
179 // assume that we always get back the top level CL1 node - this becomes the page_classifier node
180 path = GSPath.appendLink(path, GSXML.CLASS_NODE_ELEM);
181 Element cl_structure = (Element) GSXML.getNodeByPath(class_node_list, path);
182 if (cl_structure == null)
183 {
184 logger.error("classifier structure request returned no structure");
185 return page_response;
186 }
187
188 //If the user is viewing a horizontal classifier then we need to get extra information
189 if (cl_structure.getAttribute(GSXML.CHILD_TYPE_ATT).equals(GSXML.HLIST))
190 {
191 //If we have a horizontal classifier and we have had the top-level node requested (e.g. CL1, CL2 etc.)
192 //then we want to get the children of the first classifier node (e.g. the children of CL2.1)
193 if (OID.isTop(classifier_node))
194 {
195 boolean firstChildIsClassifierNode = false;
196 NodeList classifierChildrenNodes = GSXML.getChildrenByTagName(cl_structure, GSXML.CLASS_NODE_ELEM);
197 for (int i = 0; i < classifierChildrenNodes.getLength(); i++)
198 {
199 Element currentChild = (Element) classifierChildrenNodes.item(i);
200 if (currentChild.getAttribute(GSXML.NODE_ID_ATT).endsWith(".1"))
201 {
202 firstChildIsClassifierNode = true;
203 }
204 }
205
206 if (firstChildIsClassifierNode)
207 {
208 Element childStructure = getClassifierStructureFromID(classifier_node + ".1", request, collection, service_name);
209
210 Element replacementElem = null;
211 NodeList childClassifierNodes = childStructure.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
212 for (int i = 0; i < childClassifierNodes.getLength(); i++)
213 {
214 Element currentElem = (Element) childClassifierNodes.item(i);
215 if (currentElem.getAttribute(GSXML.NODE_ID_ATT).equals(classifier_node + ".1"))
216 {
217 replacementElem = currentElem;
218 break;
219 }
220 }
221
222 NodeList nodesToSearch = cl_structure.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
223 for (int i = 0; i < nodesToSearch.getLength(); i++)
224 {
225 Element currentElem = (Element) nodesToSearch.item(i);
226 if (currentElem.getAttribute(GSXML.NODE_ID_ATT).equals(classifier_node + ".1"))
227 {
228 Element parent = (Element) currentElem.getParentNode();
229 parent.insertBefore(replacementElem, currentElem);
230 parent.removeChild(currentElem);
231 break;
232 }
233 }
234 }
235 }
236 //If we have a horizontal classifier and we have NOT had the top-level node requested then we need to
237 //make sure we get the full list of top-level children to display (e.g. if the user has requested
238 //CL2.1.1 we also need to make sure we have CL2.2, CL2.3, CL2.4 etc.)
239 else
240 {
241 Element childStructure = getClassifierStructureFromID(OID.getTop(classifier_node), request, collection, service_name);
242
243 String[] idParts = classifier_node.split("\\.");
244 String idToSearchFor = idParts[0] + "." + idParts[1];
245
246 Element replacementElem = null;
247 NodeList childClassifierNodes = cl_structure.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
248 for (int i = 0; i < childClassifierNodes.getLength(); i++)
249 {
250 Element currentElem = (Element) childClassifierNodes.item(i);
251 if (currentElem.getAttribute(GSXML.NODE_ID_ATT).equals(idToSearchFor))
252 {
253 replacementElem = currentElem;
254 break;
255 }
256 }
257
258 if (replacementElem != null)
259 {
260 NodeList nodesToSearch = childStructure.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
261 for (int i = 0; i < nodesToSearch.getLength(); i++)
262 {
263 Element currentElem = (Element) nodesToSearch.item(i);
264 if (currentElem.getAttribute(GSXML.NODE_ID_ATT).equals(idToSearchFor))
265 {
266 Element parent = (Element) currentElem.getParentNode();
267 parent.insertBefore(replacementElem, currentElem);
268 parent.removeChild(currentElem);
269 break;
270 }
271 }
272
273 cl_structure = childStructure;
274 }
275 }
276 }
277
278 Element page_classifier = null;
279 // add the single classifier node as the page classifier
280 page_classifier = GSXML.duplicateWithNewName(this.doc, cl_structure, GSXML.CLASSIFIER_ELEM, true);
281 page_response.appendChild(page_classifier);
282 page_classifier.setAttribute(GSXML.NAME_ATT, top_id);
283
284 // get the metadata for each classifier node,
285 // then for each document node
286
287 Element metadata_message = this.doc.createElement(GSXML.MESSAGE_ELEM);
288
289 boolean did_classifier = false;
290 boolean did_documents = false;
291
292 // if there are classifier nodes
293 // create a metadata request for the classifier, and add it to
294 // the the message
295 NodeList cl_nodes = page_classifier.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
296
297 if (cl_nodes.getLength() > 0)
298 {
299 did_classifier = true;
300 Element cl_meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to + "MetadataRetrieve", userContext);
301 metadata_message.appendChild(cl_meta_request);
302
303 Element new_cl_nodes_list = this.doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
304 cl_meta_request.appendChild(new_cl_nodes_list);
305
306 for (int c = 0; c < cl_nodes.getLength(); c++)
307 {
308
309 Element cl = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
310 cl.setAttribute(GSXML.NODE_ID_ATT, ((Element) cl_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
311 new_cl_nodes_list.appendChild(cl);
312 }
313
314 // create and add in the param list - for now get all the metadata
315 // should be based on info sent in from the recept, and the
316 // format stuff
317 Element cl_param_list = createMetadataParamList(class_meta_names);
318 cl_meta_request.appendChild(cl_param_list);
319
320 }
321
322 // if there are document nodes in the classification (happens
323 // sometimes), create a second request for document metadata and
324 // append to the message
325 NodeList doc_nodes = page_classifier.getElementsByTagName(GSXML.DOC_NODE_ELEM);
326 if (doc_nodes.getLength() > 0)
327 {
328 did_documents = true;
329 Element doc_meta_request = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, GSPath.appendLink(collection, "DocumentMetadataRetrieve"), userContext);
330 metadata_message.appendChild(doc_meta_request);
331
332 Element doc_list = this.doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
333 doc_meta_request.appendChild(doc_list);
334
335 for (int c = 0; c < doc_nodes.getLength(); c++)
336 {
337
338 Element d = this.doc.createElement(GSXML.DOC_NODE_ELEM);
339 d.setAttribute(GSXML.NODE_ID_ATT, ((Element) doc_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
340 doc_list.appendChild(d);
341 }
342
343 // create and add in the param list - add all for now
344 Element doc_param_list = createMetadataParamList(doc_meta_names);
345 doc_meta_request.appendChild(doc_param_list);
346
347 }
348
349 // process the metadata requests
350 Element metadata_response = (Element) this.mr.process(metadata_message);
351 if (did_classifier)
352 {
353 // the classifier one will be the first response
354 // add the metadata lists for each node back into the
355 // page_classifier nodes
356 path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
357 Node pathNode = GSXML.getNodeByPath(metadata_response, path);
358 if (pathNode == null)
359 {
360 return page_response;
361 }
362 //NodeList meta_response_cls = (Element)pathNode.getChildNodes(); // can't handle empty elements from converting formatted strings (with empty newlines) into XML
363 NodeList meta_response_cls = ((Element) pathNode).getElementsByTagName(GSXML.CLASS_NODE_ELEM);
364 for (int i = 0; i < cl_nodes.getLength(); i++)
365 {
366 GSXML.mergeMetadataLists(cl_nodes.item(i), meta_response_cls.item(i));
367 }
368 }
369
370 if (did_documents)
371 {
372 NodeList meta_response_docs = null;
373 if (!did_classifier)
374 {
375 // its the first response
376 path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
377 Node pathNode = GSXML.getNodeByPath(metadata_response, path);
378 if (pathNode == null)
379 {
380 return page_response;
381 }
382
383 meta_response_docs = pathNode.getChildNodes();
384
385 }
386 else
387 { // its the second response
388 Node nodes = GSXML.getChildByTagName(metadata_response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(1), GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
389 if (nodes == null)
390 {
391 return page_response;
392 }
393 meta_response_docs = nodes.getChildNodes();
394 }
395
396 for (int i = 0; i < doc_nodes.getLength(); i++)
397 {
398 GSXML.mergeMetadataLists(doc_nodes.item(i), meta_response_docs.item(i));
399 }
400 }
401
402 logger.debug("(GS2BrowseAction) Page:\n" + this.converter.getPrettyString(page_response));
403 return page_response;
404 }
405
406 private Element getClassifierStructureFromID(String id, Element request, String collection, String service_name)
407 {
408 UserContext userContext = new UserContext(request);
409 String to = GSPath.appendLink(collection, service_name);
410
411 Element firstClassifierNodeChildrenMessage = this.doc.createElement(GSXML.MESSAGE_ELEM);
412 Element firstClassifierNodeChildrenRequest = GSXML.createBasicRequest(this.doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
413 firstClassifierNodeChildrenMessage.appendChild(firstClassifierNodeChildrenRequest);
414
415 Element paramList = this.doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
416 firstClassifierNodeChildrenRequest.appendChild(paramList);
417
418 Element ancestorParam = this.doc.createElement(GSXML.PARAM_ELEM);
419 paramList.appendChild(ancestorParam);
420 ancestorParam.setAttribute(GSXML.NAME_ATT, "structure");
421 ancestorParam.setAttribute(GSXML.VALUE_ATT, "ancestors");
422
423 Element childrenParam = this.doc.createElement(GSXML.PARAM_ELEM);
424 paramList.appendChild(childrenParam);
425 childrenParam.setAttribute(GSXML.NAME_ATT, "structure");
426 childrenParam.setAttribute(GSXML.VALUE_ATT, "children");
427
428 Element classifierToGetList = this.doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
429 Element classifierToGet = this.doc.createElement(GSXML.CLASS_NODE_ELEM);
430 classifierToGet.setAttribute(GSXML.NODE_ID_ATT, id);
431 classifierToGetList.appendChild(classifierToGet);
432 firstClassifierNodeChildrenRequest.appendChild(classifierToGetList);
433
434 Element firstClassifierNodeChildrenResponse = (Element) this.mr.process(firstClassifierNodeChildrenMessage);
435
436 String nsPath = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
437 Element topClassifierNode = (Element) GSXML.getNodeByPath(firstClassifierNodeChildrenResponse, nsPath);
438 nsPath = GSPath.appendLink(GSXML.CLASS_NODE_ELEM, GSXML.NODE_STRUCTURE_ELEM);
439 nsPath = GSPath.appendLink(nsPath, GSXML.CLASS_NODE_ELEM);
440 Element childStructure = (Element) GSXML.getNodeByPath(topClassifierNode, nsPath);
441
442 return childStructure;
443 }
444
445 protected void extractMetadataNames(Element new_format, HashSet<String> doc_meta_names, HashSet<String> class_meta_names)
446 {
447 NodeList templates = new_format.getElementsByTagName("gsf:template");
448 for (int i = 0; i < templates.getLength(); i++)
449 {
450 Element template = (Element) templates.item(i);
451 String match = template.getAttribute("match");
452 if (match.startsWith("documentNode"))
453 {
454 getRequiredMetadataNames(template, doc_meta_names);
455 }
456 else if (match.startsWith("classifierNode")) // not match.equals, as we want to match nodes like: classifierNode[@classifierStyle = 'VList']
457 {
458 getRequiredMetadataNames(template, class_meta_names);
459 }
460 }
461 }
462
463}
Note: See TracBrowser for help on using the repository browser.