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

Last change on this file since 37514 was 37514, checked in by kjdon, 13 months ago

usign the new GetRequiredMEtadataNames - has an extra arg, and we no longer need to do teh extraMEtadataList bit ourselves, as its now in getRequiredMetadataNames

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