source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/GeneralDocumentListAction.java@ 39015

Last change on this file since 39015 was 37615, checked in by kjdon, 15 months ago

this will now ask for format info from each collection in the documentNodeList, and get their format statements for the specified service. it groups these into a xsl:choose statement.

File size: 14.4 KB
Line 
1package org.greenstone.gsdl3.action;
2
3import java.io.File;
4import java.io.Serializable;
5import java.util.HashMap;
6import java.util.HashSet;
7import java.util.Map;
8
9import javax.xml.parsers.DocumentBuilder;
10import javax.xml.parsers.DocumentBuilderFactory;
11import javax.xml.transform.Result;
12import javax.xml.transform.Transformer;
13import javax.xml.transform.TransformerFactory;
14import javax.xml.transform.dom.DOMSource;
15import javax.xml.transform.stream.StreamResult;
16
17import org.greenstone.gsdl3.util.GSFile;
18import org.greenstone.gsdl3.util.GSParams;
19import org.greenstone.gsdl3.util.GSPath;
20import org.greenstone.gsdl3.util.GSXML;
21import org.greenstone.gsdl3.util.UserContext;
22import org.greenstone.gsdl3.util.XMLConverter;
23import org.greenstone.util.GlobalProperties;
24import org.w3c.dom.Document;
25import org.w3c.dom.Element;
26import org.w3c.dom.Node;
27import org.w3c.dom.NodeList;
28
29public class GeneralDocumentListAction extends Action
30{
31
32 /** process a request */
33 public Node process(Node message_node)
34 {
35 Element message = GSXML.nodeToElement(message_node);
36 Document doc = message.getOwnerDocument();
37
38 // the result
39 Element result = doc.createElement(GSXML.MESSAGE_ELEM);
40 Element page_response = doc.createElement(GSXML.RESPONSE_ELEM);
41 result.appendChild(page_response);
42
43 // assume only one request
44 Element request = (Element) GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
45 //logger.debug(" request=" + this.converter.getString(request));
46
47 UserContext userContext = new UserContext(request);
48
49 // get the param list
50 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
51 HashMap<String, Serializable> params = GSXML.extractParams(cgi_param_list, false);
52
53
54 String service_name = (String) params.get(GSParams.SERVICE);
55 String cluster_name = (String) params.get(GSParams.CLUSTER);
56 String response_only_p = (String) params.get(GSParams.RESPONSE_ONLY);
57 boolean response_only = false;
58 if (response_only_p != null)
59 {
60 response_only = (response_only_p.equals("1") ? true : false);
61 }
62 String request_type = (String) params.get(GSParams.REQUEST_TYPE);
63 // what is carried out depends on the request_type
64 // if rt=d, then a describe request is done,
65 // is rt=r, a request and then a describe request is done
66
67 // if ro=1, then this calls for a process only page - we do the request
68 // (rt should be r) and just give the response straight back
69 // without any page processing
70
71 // where to send requests
72 String to;
73 if (cluster_name != null)
74 {
75 to = GSPath.appendLink(cluster_name, service_name);
76 }
77 else
78 {
79 to = service_name;
80 }
81
82 // request the service info for the selected service - should be cached
83 Element description_elem = getServiceDescription(to, userContext);
84
85 if (request_type.equals("d"))
86 {
87
88 // we only want to describe the service
89 if (description_elem != null)
90 {
91 page_response.appendChild((Element) doc.importNode(description_elem, true));
92 }
93 addSiteMetadata(page_response, userContext);
94 addInterfaceOptions(page_response);
95 return result;
96 // thats all. format info here??
97 }
98
99 //ok, so now we do the actual request
100 Element mr_query_message = doc.createElement(GSXML.MESSAGE_ELEM);
101 Element mr_query_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
102
103 mr_query_message.appendChild(mr_query_request);
104
105 Element param_list = null;
106 // add in the service params - except the ones only used by the action
107 HashMap service_params = (HashMap) params.get(GSParams.SERVICE_PREFIX);
108 if (service_params != null)
109 {
110 param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
111 GSXML.addParametersToList(param_list, service_params);
112 mr_query_request.appendChild(param_list);
113 }
114
115 Element mr_query_response = (Element) this.mr.process(mr_query_message);
116 Element result_response = (Element) GSXML.getChildByTagName(mr_query_response, GSXML.RESPONSE_ELEM);
117
118 if (result_response == null) {
119 // something went wrong
120 logger.error("no result from sending request to "+to);
121 return result;
122 }
123
124 NodeList doc_nodes = result_response.getElementsByTagName(GSXML.DOC_NODE_ELEM);
125 if (doc_nodes.getLength() == 0) {
126 // no docs in the result
127 return result;
128 }
129
130 // lets get format info for each collection
131 HashSet<String> collections = getCollectionNames(doc_nodes);
132
133 //get the format info for the service
134 Element base_format_elem = getFormatInfo(to, userContext);
135 // now get any from the collections, and combine into a big if/else block
136 Element combined_format = getAndCombineFormats(doc, base_format_elem, collections, service_name);
137
138 if (combined_format != null) {
139 // set the format type - what would it be for this??
140 //format_elem.setAttribute(GSXML.TYPE_ATT, "");
141 // add to the response
142 page_response.appendChild(combined_format);
143 }
144
145 // we need to get metadata for the documents
146 // which metadata elements do we need?
147 HashSet<String> doc_meta_names = new HashSet<String>();
148 // always want this one
149 doc_meta_names.add("root_assocfilepath");
150 // we use extraMetadataList, plus anything that shows up in the service's format statement
151
152 // ... and find any metadata names mentioned in the format, or in extraMetadata
153 getRequiredMetadataNames(doc_meta_names, combined_format, request);
154
155 // TODO, do we want docType and nodeType attributes for each doc Node??
156 getAndAddMetadataToDocNodes(result_response, doc_meta_names);
157
158 if (response_only)
159 {
160 // just send the reponse as is
161 addSiteMetadata(result_response, userContext);
162 addInterfaceOptions(result_response);
163 return result_response;
164 }
165
166 // else append the contents of the response to the page
167 GSXML.copyAllChildren(page_response, result_response);
168
169 // another part of the page is the service description
170 if (description_elem != null)
171 {
172 page_response.appendChild((Element) doc.importNode(description_elem, true));
173 }
174
175 addSiteMetadata(page_response, userContext);
176 addInterfaceOptions(page_response);
177
178 return result;
179 }
180
181 protected HashSet<String> getCollectionNames(NodeList docNodes) {
182 HashSet<String> coll_names = new HashSet<String>();
183 for (int i=0; i<docNodes.getLength(); i++) {
184 String collection = ((Element)docNodes.item(i)).getAttribute(GSXML.COLLECTION_ATT);
185 if (!collection.equals("")) {
186 coll_names.add(collection);
187 }
188 }
189 return coll_names;
190 }
191
192 // TODO - store this so don't need to get it each time.
193 protected Element getAndCombineFormats(Document result_doc, Element base_format, HashSet<String> collections, String service_name)
194 {
195 Element combined_format = result_doc.createElement(GSXML.FORMAT_ELEM);
196
197 // lets see if the collections are returning any local formats
198 Document doc = XMLConverter.newDOM();
199 Element message = doc.createElement(GSXML.MESSAGE_ELEM);
200
201 // service_name is an extra attribute
202 for (String coll : collections) {
203 Element this_coll_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_FORMAT, coll, new UserContext());
204 this_coll_request.setAttribute(GSXML.SERVICE_ATT, service_name);
205 message.appendChild(this_coll_request);
206 }
207
208 // template match:mode is the key->collection->template element
209 HashMap<String, HashMap<String,Element>> template_map = new HashMap<String, HashMap<String,Element>>();
210 if (base_format != null) {
211 // to do - process the defaults differently. any non match tempaltes need to be added as is into hte result, and the options.
212 addFormatsToMap(template_map, base_format, "default_format", combined_format);
213 }
214
215 //send off the request
216 boolean has_coll_specific_format = false;
217 Element mr_response = (Element)this.mr.process(message);
218 // add all the resulting templates into the map
219 NodeList colls_responses = mr_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
220 for (int i=0; i<colls_responses.getLength(); i++) {
221 Element coll_response = (Element)colls_responses.item(i);
222 Element format = (Element)GSXML.getChildByTagName(coll_response, GSXML.FORMAT_ELEM);
223 if (format == null) continue;
224 String this_coll = coll_response.getAttribute(GSXML.FROM_ATT);
225 addFormatsToMap(template_map, format, this_coll, null);
226 }
227
228 // ok, now we need to go through the map, and join them up into a big <xsl:choose>
229 for(Map.Entry<String, HashMap<String, Element>> entry : template_map.entrySet()) {
230 String id = entry.getKey();
231 HashMap<String, Element> coll_map = entry.getValue();
232
233 Element new_template = result_doc.createElementNS("http://www.w3.org/1999/XSL/Transform", "xsl:template");
234 String[] id_parts = id.split(":");
235 String match = id_parts[0];
236 String mode = "";
237 if (id_parts.length==2) {
238 mode = id_parts[1];
239 }
240 new_template.setAttribute("match", match);
241 if (!mode.equals("")) {
242 new_template.setAttribute("mode", mode);
243 }
244 if (coll_map.size()==1 && coll_map.containsKey("default_format")) {
245 // we only have the default format - can copy it as is
246 new_template = (Element)result_doc.importNode(coll_map.get("default_format"), true);
247
248 } else if (coll_map.size()==1) {
249 // this is an error
250 logger.error("no default entry for xsl template!"); // todo better message
251 } else {
252 Element choose = result_doc.createElementNS("http://www.w3.org/1999/XSL/Transform", "xsl:choose");
253 new_template.appendChild(choose);
254 Element otherwise = null;
255 for (Map.Entry<String, Element> entry2 : coll_map.entrySet()) {
256 String coll = entry2.getKey();
257 Element template = entry2.getValue();
258 if (coll.equals("default_format")) {
259 // this is the otherwsie clause
260 otherwise = GSXML.duplicateWithNewNameNS(result_doc, template, "xsl:otherwise","http://www.w3.org/1999/XSL/Transform", false);
261
262 } else {
263 // this is a when statement
264 Element when = GSXML.duplicateWithNewNameNS(result_doc, template, "xsl:when","http://www.w3.org/1999/XSL/Transform", false);
265 when.setAttribute("test", "@collection='"+coll+"'");
266 choose.appendChild(when);
267 }
268 if (otherwise != null) {
269 // append otherwise last
270 choose.appendChild(otherwise);
271 }
272 combined_format.appendChild(new_template);
273
274 }
275
276 } // for each entry in template map
277 }
278 return combined_format;
279 }
280 protected void addFormatsToMap(HashMap<String, HashMap<String, Element>> template_map, Element format_element, String coll_name, Element combined_format) {
281 Document doc = null;
282 if (combined_format != null) {
283 doc = combined_format.getOwnerDocument();
284 }
285 NodeList children = format_element.getChildNodes();
286 for (int j=0; j<children.getLength(); j++) {
287 Node this_child = children.item(j);
288 if (this_child instanceof Element) { // lets ignore any other kind of node
289 if (this_child.getNodeName().equals("xsl:template")) {
290 Element this_template = (Element)this_child;
291 String match = this_template.getAttribute("match");
292 if (match.equals("")) {
293 if (combined_format != null) {
294 combined_format.appendChild(doc.importNode(this_template,true));
295 }
296 } else {
297 String mode = this_template.getAttribute("mode");
298 String id = match+":"+mode;
299 HashMap<String, Element> coll_map = template_map.get(id);
300 if (coll_map == null) {
301 coll_map = new HashMap<String, Element>();
302 template_map.put(id, coll_map);
303 }
304 coll_map.put(coll_name, this_template);
305 }
306 } else {
307 // the node is not xsl:template, add it to combined format, if that has been supplied.
308 if (combined_format != null) {
309 combined_format.appendChild(doc.importNode(this_child, true));
310 }
311 }
312 }// if isa Element
313 } // for each node
314
315
316 }
317
318 protected void getAndAddMetadataToDocNodes(Element result_elem, HashSet<String> meta_names) {
319
320 Document doc = XMLConverter.newDOM();
321 Document result_doc = result_elem.getOwnerDocument();
322 HashMap<String, Element>coll_requests_map = new HashMap<String, Element>();
323
324 Element message = doc.createElement(GSXML.MESSAGE_ELEM);
325
326 // the param list - will be the same for all collection requests
327 Element dm_param_list = createMetadataParamList(doc,meta_names);
328
329 NodeList doc_nodes = result_elem.getElementsByTagName(GSXML.DOC_NODE_ELEM);
330 for (int i = 0; i < doc_nodes.getLength(); i++) {
331 Element dn = (Element) doc_nodes.item(i);
332 String collection = dn.getAttribute(GSXML.COLLECTION_ATT);
333
334 Element this_coll_dn_list = coll_requests_map.get(collection);
335 if (this_coll_dn_list == null) {
336 Element this_coll_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, GSPath.appendLink(collection, "DocumentMetadataRetrieve"), new UserContext());
337 this_coll_request.appendChild(dm_param_list.cloneNode(true));
338 this_coll_dn_list = doc.createElement(GSXML.DOC_NODE_ELEM+GSXML.LIST_MODIFIER);
339 this_coll_request.appendChild(this_coll_dn_list);
340 coll_requests_map.put(collection, this_coll_dn_list);
341 message.appendChild(this_coll_request);
342 }
343
344 this_coll_dn_list.appendChild(doc.importNode(dn, false));
345 } // for each node
346
347 // ok, send off the message
348 Element dm_result = (Element)this.mr.process(message);
349 String [] att_names = {GSXML.COLLECTION_ATT, GSXML.NODE_ID_ATT};
350 // go throught he original list of doc nodes
351 for (int i = 0; i < doc_nodes.getLength(); i++) {
352 Element dn = (Element) doc_nodes.item(i);
353 String collection = dn.getAttribute(GSXML.COLLECTION_ATT);
354 String node_id = dn.getAttribute(GSXML.NODE_ID_ATT);
355 // find the corresponding one in the result
356 Element new_dn = GSXML.findMatchingElement(dm_result, GSXML.DOC_NODE_ELEM, att_names, new String[] {collection, node_id});
357 if (new_dn != null) {
358 Node new_meta = GSXML.getChildByTagName(new_dn, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
359 if (new_meta != null) {
360 dn.appendChild(result_doc.importNode(new_meta, true));
361 }
362 }
363 }
364 }
365}
Note: See TracBrowser for help on using the repository browser.