source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/BrowseAction.java@ 28382

Last change on this file since 28382 was 28382, checked in by davidb, 11 years ago

Elimination of the 'this.doc' field from the Action baseclass and the subclasses that rely on it. For Greenstone3 purposes it is unsafe to create this object in the constructor to the action and then store it for other methods to access. This is because the Greenstone 3 (and in particular calls to 'process' operate in a multi-threaded context, that is managed by the Servlet server (e.g. Tomcat by default). Calls to DOM methods are not guaranteed to be thread safe, this became apparent when we started looking in to an exception that was being thrown, and centred around use of the DOM method 'item(i)'. The change this commit makes is to remove 'this.doc' being stored as a field. A document is now created in the top level of a call to 'process()' and when a DOM reference is needed in a subsequent method an Element variable (typically passed in as a parameter to the method) is used (through 'Document doc = element.getOwnerDocument()') to gain access to the DOM

  • Property svn:keywords set to Author Date Id Revision
File size: 12.4 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.Document;
15import org.w3c.dom.Element;
16import org.w3c.dom.Node;
17import org.w3c.dom.NodeList;
18
19//NOTE: this class not used at present!!!!!
20/** action for classifier browsing */
21public class BrowseAction extends Action
22{
23
24 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.BrowseAction.class.getName());
25
26 public static final String CLASSIFIER_ARG = "cl";
27 public static final String SIBLING_ARG = "sib";
28
29 /** process the request */
30 public Node process(Node message_node)
31 {
32 Element message = this.converter.nodeToElement(message_node);
33 Document doc = message.getOwnerDocument();
34
35 // get the request - assume only one
36 Element request = (Element) GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
37
38 // the result
39 Element result = doc.createElement(GSXML.MESSAGE_ELEM);
40 Element response = classifierBrowse(request);
41 result.appendChild(response);
42 return result;
43 }
44
45 protected Element classifierBrowse(Element request)
46 {
47 Document doc = request.getOwnerDocument();
48
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
64 //whether to retrieve siblings or not
65 boolean get_siblings = false;
66 String sibs = (String) params.get(SIBLING_ARG);
67 if (sibs != null && sibs.equals("1"))
68 {
69 get_siblings = true;
70 }
71
72 UserContext userContext = new UserContext(request);
73 String to = GSPath.appendLink(collection, service_name);
74
75 // the first part of the response is the service description
76 // for now get this again from the service.
77 // this should be cached somehow later on.
78
79 Element info_message = doc.createElement(GSXML.MESSAGE_ELEM);
80 Element info_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, to, userContext);
81 info_message.appendChild(info_request);
82
83 // also get the format stuff now if there is some
84 Element format_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_FORMAT, to, userContext);
85 info_message.appendChild(format_request);
86 // process the requests
87
88 Element info_response = (Element) this.mr.process(info_message);
89
90 // the two responses
91 NodeList responses = info_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
92 Element service_response = (Element) responses.item(0);
93 Element format_response = (Element) responses.item(1);
94
95 Element service_description = (Element) GSXML.getChildByTagName(service_response, GSXML.SERVICE_ELEM);
96 page_response.appendChild(doc.importNode(service_description, true));
97
98 //append site metadata
99 addSiteMetadata(page_response, userContext);
100 addInterfaceOptions(page_response);
101
102 // if rt=d, then we are just displaying the service
103 String request_type = (String) params.get(GSParams.REQUEST_TYPE);
104 if (request_type.equals("d"))
105 {
106 //return the page that we have so far
107 return page_response;
108 }
109
110 // get the node that the user has clicked on
111 String classifier_node = (String) params.get(CLASSIFIER_ARG);
112
113 // if the node is not defined, return the page that we have so far
114 if (classifier_node == null || classifier_node.equals(""))
115 {
116 return page_response;
117 }
118
119 // the id of the classifier is the top id of the selected node
120 String top_id = OID.getTop(classifier_node);
121
122 HashSet<String> metadata_names = new HashSet<String>();
123
124 // add the format info into the response
125 Element format_elem = (Element) GSXML.getChildByTagName(format_response, GSXML.FORMAT_ELEM);
126 if (format_elem != null)
127 {
128 // find the one for the classifier we are in
129 Element this_format = GSXML.getNamedElement(format_elem, GSXML.CLASSIFIER_ELEM, GSXML.NAME_ATT, top_id);
130 if (this_format == null)
131 {
132 this_format = (Element) GSXML.getChildByTagName(format_elem, GSXML.DEFAULT_ELEM);
133 }
134 if (this_format != null)
135 {
136 Element global_format_elem = (Element) GSXML.getChildByTagName(format_response, GSXML.GLOBAL_FORMAT_ELEM);
137 if(global_format_elem != null)
138 {
139 GSXSLT.mergeFormatElements(this_format, global_format_elem, false);
140 }
141 Element new_format = GSXML.duplicateWithNewName(doc, this_format, GSXML.FORMAT_ELEM, false);
142 // set teh format type
143 new_format.setAttribute(GSXML.TYPE_ATT, "browse");
144
145 page_response.appendChild(new_format);
146 getRequiredMetadataNames(new_format, metadata_names);
147 }
148 }
149
150 Element extraMetaListElem = (Element) GSXML.getChildByTagName(request, GSXML.EXTRA_METADATA + GSXML.LIST_MODIFIER);
151 if(extraMetaListElem != null)
152 {
153 NodeList extraMetaList = extraMetaListElem.getElementsByTagName(GSXML.EXTRA_METADATA);
154 for(int i = 0; i < extraMetaList.getLength(); i++)
155 {
156 metadata_names.add(((Element)extraMetaList.item(i)).getAttribute(GSXML.NAME_ATT));
157 }
158 }
159
160 logger.info("extracted meta names, " + metadata_names.toString());
161 // get the browse structure for the selected node
162 Element classify_message = doc.createElement(GSXML.MESSAGE_ELEM);
163 Element classify_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
164 classify_message.appendChild(classify_request);
165
166 //Create a parameter list to specify the required structure information
167 // for now, always get ancestors and children
168 Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
169 classify_request.appendChild(param_list);
170 Element param = doc.createElement(GSXML.PARAM_ELEM);
171 param_list.appendChild(param);
172 param.setAttribute(GSXML.NAME_ATT, "structure");
173 param.setAttribute(GSXML.VALUE_ATT, "ancestors");
174 param = doc.createElement(GSXML.PARAM_ELEM);
175 param_list.appendChild(param);
176 param.setAttribute(GSXML.NAME_ATT, "structure");
177 param.setAttribute(GSXML.VALUE_ATT, "children");
178 if (get_siblings)
179 {
180 param = doc.createElement(GSXML.PARAM_ELEM);
181 param_list.appendChild(param);
182 param.setAttribute(GSXML.NAME_ATT, "structure");
183 param.setAttribute(GSXML.VALUE_ATT, "siblings");
184 }
185
186 // put the classifier node into a classifier node list
187 Element classifier_list = doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
188 Element classifier = doc.createElement(GSXML.CLASS_NODE_ELEM);
189 classifier.setAttribute(GSXML.NODE_ID_ATT, classifier_node);
190 classifier_list.appendChild(classifier);
191 classify_request.appendChild(classifier_list);
192
193 // process the request
194 Element classify_response = (Element) this.mr.process(classify_message);
195 // get the structure element
196 String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
197 path = GSPath.appendLink(path, GSXML.CLASS_NODE_ELEM);
198 path = GSPath.appendLink(path, GSXML.NODE_STRUCTURE_ELEM);
199 // assume that we always get back the top level CL1 node - this becomes the page_classifier node
200 path = GSPath.appendLink(path, GSXML.CLASS_NODE_ELEM);
201 Element cl_structure = (Element) GSXML.getNodeByPath(classify_response, path);
202 if (cl_structure == null)
203 {
204 logger.error("classifier structure request returned no structure");
205 return page_response;
206 }
207
208 // add the classifier node as the page classifier
209 Element page_classifier = GSXML.duplicateWithNewName(doc, cl_structure, GSXML.CLASSIFIER_ELEM, true);
210 page_response.appendChild(page_classifier);
211 page_classifier.setAttribute(GSXML.NAME_ATT, top_id);
212
213 // get the metadata for each classifier node,
214 // then for each document node
215
216 Element metadata_message = doc.createElement(GSXML.MESSAGE_ELEM);
217
218 boolean did_classifier = false;
219 boolean did_documents = false;
220
221 // if there are classifier nodes
222 // create a metadata request for the classifier, and add it to
223 // the the message
224 NodeList cl_nodes = page_classifier.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
225
226 if (cl_nodes.getLength() > 0)
227 {
228 did_classifier = true;
229 Element cl_meta_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, to + "MetadataRetrieve", userContext);
230 metadata_message.appendChild(cl_meta_request);
231
232 Element new_cl_nodes_list = doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
233 cl_meta_request.appendChild(new_cl_nodes_list);
234
235 for (int c = 0; c < cl_nodes.getLength(); c++)
236 {
237
238 Element cl = doc.createElement(GSXML.CLASS_NODE_ELEM);
239 cl.setAttribute(GSXML.NODE_ID_ATT, ((Element) cl_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
240 new_cl_nodes_list.appendChild(cl);
241 }
242
243 // create and add in the param list - for now get all the metadata
244 // should be based on info sent in from the recept, and the
245 // format stuff
246 Element cl_param_list = null;
247 if (metadata_names.isEmpty())
248 {
249 cl_param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
250 Element p = doc.createElement(GSXML.PARAM_ELEM);
251 cl_param_list.appendChild(p);
252 p.setAttribute(GSXML.NAME_ATT, "metadata");
253 p.setAttribute(GSXML.VALUE_ATT, "Title");
254 }
255 else
256 {
257 cl_param_list = createMetadataParamList(doc,metadata_names);
258 }
259
260 cl_meta_request.appendChild(cl_param_list);
261
262 }
263
264 // if there are document nodes in the classification (happens
265 // sometimes), create a second request for document metadata and
266 // append to the message
267 NodeList doc_nodes = page_classifier.getElementsByTagName(GSXML.DOC_NODE_ELEM);
268 if (doc_nodes.getLength() > 0)
269 {
270 did_documents = true;
271 Element doc_meta_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, GSPath.appendLink(collection, "DocumentMetadataRetrieve"), userContext);
272 metadata_message.appendChild(doc_meta_request);
273
274 Element doc_list = doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
275 doc_meta_request.appendChild(doc_list);
276
277 for (int c = 0; c < doc_nodes.getLength(); c++)
278 {
279
280 Element d = doc.createElement(GSXML.DOC_NODE_ELEM);
281 d.setAttribute(GSXML.NODE_ID_ATT, ((Element) doc_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
282 doc_list.appendChild(d);
283 }
284
285 // create and add in the param list - add all for now
286 Element doc_param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
287 Element p = doc.createElement(GSXML.PARAM_ELEM);
288 doc_param_list.appendChild(p);
289 p.setAttribute(GSXML.NAME_ATT, "metadata");
290 p.setAttribute(GSXML.VALUE_ATT, "all");
291 doc_meta_request.appendChild(doc_param_list);
292
293 }
294
295 // process the metadata requests
296 Element metadata_response = (Element) this.mr.process(metadata_message);
297 if (did_classifier)
298 {
299 // the classifier one will be the first response
300 // add the metadata lists for each node back into the
301 // page_classifier nodes
302 path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
303 NodeList meta_response_cls = GSXML.getNodeByPath(metadata_response, path).getChildNodes();
304 for (int i = 0; i < cl_nodes.getLength(); i++)
305 {
306 GSXML.mergeMetadataLists(cl_nodes.item(i), meta_response_cls.item(i));
307 }
308 }
309 if (did_documents)
310 {
311 NodeList meta_response_docs = null;
312 if (!did_classifier)
313 {
314 // its the first response
315 path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
316 meta_response_docs = GSXML.getNodeByPath(metadata_response, path).getChildNodes();
317 }
318 else
319 { // its the second response
320 meta_response_docs = GSXML.getChildByTagName(metadata_response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(1), GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER).getChildNodes();
321 }
322
323 for (int i = 0; i < doc_nodes.getLength(); i++)
324 {
325 GSXML.mergeMetadataLists(doc_nodes.item(i), meta_response_docs.item(i));
326 }
327 }
328
329 logger.debug("(BrowseAction) Page:\n" + this.converter.getPrettyString(page_response));
330 return page_response;
331 }
332
333 protected Element unknownBrowse(Element page, Element request, String browse_type)
334 {
335 logger.error("unknown browse subtype: " + browse_type);
336 return null;
337 }
338}
Note: See TracBrowser for help on using the repository browser.