source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/action/NoCollQueryAction.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: 8.8 KB
Line 
1package org.greenstone.gsdl3.action;
2
3import org.greenstone.gsdl3.core.ModuleInterface;
4import org.greenstone.gsdl3.util.*;
5// XML classes
6import org.w3c.dom.Node;
7import org.w3c.dom.NodeList;
8import org.w3c.dom.Text;
9import org.w3c.dom.Document;
10import org.w3c.dom.Element;
11
12import java.util.HashMap;
13import java.util.HashSet;
14import java.util.Vector;
15import java.util.Map;
16import java.util.Iterator;
17import java.io.File;
18import java.io.Serializable;
19
20import org.apache.log4j.*;
21
22/**
23 * action class for queries this is used when querying isn't collection
24 * specific, but it occurs across all collections in the site. The service
25 * description is assumed to be known by the xslt so we dont ask for it. we just
26 * pass all the service params to the TextQuery service of all the collections
27 */
28public class NoCollQueryAction extends Action
29{
30
31 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.action.NoCollQueryAction.class.getName());
32
33 /**
34 * process - processes a request.
35 */
36 public Node process(Node message_node)
37 {
38
39 Element message = this.converter.nodeToElement(message_node);
40 Document doc = message.getOwnerDocument();
41
42 // get the request - assume there is only one
43 Element request = (Element) GSXML.getChildByTagName(message, GSXML.REQUEST_ELEM);
44
45 // create the return message
46 Element result = doc.createElement(GSXML.MESSAGE_ELEM);
47 // for now we only have one type of query - subaction not used
48 Element response = basicQuery(request);
49 result.appendChild(doc.importNode(response, true));
50 return result;
51 }
52
53 /**
54 * a generic query handler this gets the service description, does the query
55 * (just passes all the params to the service, then gets the titles for any
56 * results
57 */
58 protected Element basicQuery(Element request)
59 {
60 // the result
61 Document doc = request.getOwnerDocument();
62
63 Element page_response = doc.createElement(GSXML.RESPONSE_ELEM);
64
65 // extract the params from the cgi-request, and check that we have a coll specified
66 Element cgi_param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
67 HashMap<String, Serializable> params = GSXML.extractParams(cgi_param_list, false);
68
69 String request_type = (String) params.get(GSParams.REQUEST_TYPE);
70 UserContext userContext = new UserContext(request);
71 if (request_type.equals("d"))
72 {
73 // display the query page
74 // the only info we need to return is the collection list cos the xslt does teh rest
75
76 Element coll_list = getCollectionList(doc, userContext);
77 page_response.appendChild(doc.importNode(coll_list, true));
78 return page_response;
79
80 }
81
82 // else we have a query
83 String service_name = (String) params.get(GSParams.SERVICE);
84 if (service_name == null || service_name.equals(""))
85 {
86 service_name = "TextQuery";
87 }
88 String query_coll_list = (String) params.get(GSParams.COLLECTION);
89
90 if (query_coll_list == null || query_coll_list.equals(""))
91 {
92 logger.error("no collections were specified!");
93 Element coll_list = getCollectionList(doc,userContext);
94 page_response.appendChild(doc.importNode(coll_list, true));
95 return page_response;
96 }
97
98 // service paramList
99 HashMap service_params = (HashMap) params.get("s1");
100 if (service_params == null)
101 { // no query
102 return page_response;
103 }
104 Element query_param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
105 GSXML.addParametersToList(doc, query_param_list, service_params);
106
107 // we will do a query for each coll
108 String[] colls = query_coll_list.split(",");
109
110 Element mr_query_message = doc.createElement(GSXML.MESSAGE_ELEM);
111
112 for (int i = 0; i < colls.length; i++)
113 {
114 String to = GSPath.appendLink(colls[i], service_name);
115 Element mr_query_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
116 mr_query_message.appendChild(mr_query_request);
117 mr_query_request.appendChild(query_param_list.cloneNode(true));
118
119 }
120
121 // do the query
122 Element mr_query_response = (Element) this.mr.process(mr_query_message);
123
124 // get the Title metadata for each node - need Node title and root title
125 Element mr_meta_message = doc.createElement(GSXML.MESSAGE_ELEM);
126 NodeList responses = mr_query_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
127 for (int j = 0; j < responses.getLength(); j++)
128 {
129 Element document_list = (Element) GSXML.getChildByTagName((Element) responses.item(j), GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
130 if (document_list != null)
131 {
132 String coll_name = extractCollName(((Element) responses.item(j)).getAttribute(GSXML.FROM_ATT));
133 String path = GSPath.appendLink(coll_name, "DocumentMetadataRetrieve");
134 Element mr_meta_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, path, userContext);
135 mr_meta_message.appendChild(mr_meta_request);
136 mr_meta_request.appendChild(doc.importNode(document_list, true));
137 // metadata params
138 Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
139 Element param = GSXML.createParameter(doc, "metadata", "Title");
140 param_list.appendChild(param);
141 param = GSXML.createParameter(doc, "metadata", "root_Title");
142 param_list.appendChild(param);
143 mr_meta_request.appendChild(param_list);
144
145 }
146 }
147
148 // do the request
149 Element mr_meta_response = (Element) this.mr.process(mr_meta_message);
150
151 // the result
152 Element result_doc_list = doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
153 page_response.appendChild(result_doc_list);
154
155 responses = mr_meta_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
156 for (int j = 0; j < responses.getLength(); j++)
157 {
158 Element document_list = (Element) GSXML.getChildByTagName((Element) responses.item(j), GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
159 String coll_name = extractCollName(((Element) responses.item(j)).getAttribute(GSXML.FROM_ATT));
160
161 mergeDocLists(result_doc_list, document_list, coll_name);
162 }
163
164 return page_response;
165 }
166
167 protected String extractCollName(String path)
168 {
169 return GSPath.removeLastLink(path);
170 }
171
172 protected void mergeDocLists(Element result_list, Element from_list, String collection)
173 {
174
175 Document owner = result_list.getOwnerDocument();
176 Node child = from_list.getFirstChild();
177 while (child != null && child.getNodeType() == Node.ELEMENT_NODE)
178 {
179 ((Element) child).setAttribute("collection", collection);
180 result_list.appendChild(owner.importNode(child, true));
181 child = child.getNextSibling();
182 }
183
184 }
185
186 protected Element getCollectionList(Document doc, UserContext userContext)
187 {
188
189 // first, get the message router info
190 Element coll_list_message = doc.createElement(GSXML.MESSAGE_ELEM);
191 Element coll_list_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, "", userContext);
192 coll_list_message.appendChild(coll_list_request);
193 Element coll_list_response = (Element) this.mr.process(coll_list_message);
194 if (coll_list_response == null)
195 {
196 logger.error("couldn't query the message router!");
197 return null;
198 }
199
200 // second, get the display info for each collection
201 NodeList colls = coll_list_response.getElementsByTagName(GSXML.COLLECTION_ELEM);
202
203 Element coll_param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
204 Element param = GSXML.createParameter(doc, GSXML.SUBSET_PARAM, GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER);
205 coll_param_list.appendChild(param);
206 // we will send all the requests in a single message
207 Element metadata_message = doc.createElement(GSXML.MESSAGE_ELEM);
208 for (int i = 0; i < colls.getLength(); i++)
209 {
210 Element c = (Element) colls.item(i);
211 String name = c.getAttribute(GSXML.NAME_ATT);
212
213 Element metadata_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_DESCRIBE, name, userContext);
214 metadata_request.appendChild(coll_param_list.cloneNode(true));
215 metadata_message.appendChild(metadata_request);
216 }
217
218 Element metadata_response = (Element) this.mr.process(metadata_message);
219
220 NodeList coll_responses = metadata_response.getElementsByTagName(GSXML.RESPONSE_ELEM);
221 // check that have same number of responses as collections
222 if (colls.getLength() != coll_responses.getLength())
223 {
224 logger.error("didn't get a response for each collection - somethings gone wrong!");
225 // for now, dont use the metadata
226 }
227 else
228 {
229 for (int i = 0; i < colls.getLength(); i++)
230 {
231 Element c1 = (Element) colls.item(i);
232 Element c2 = (Element) coll_responses.item(i);
233 if (c1.getAttribute(GSXML.NAME_ATT).equals(c2.getAttribute(GSXML.FROM_ATT)))
234 {
235 //add the collection data into the original response
236 GSXML.mergeElements(c1, (Element) GSXML.getChildByTagName(c2, GSXML.COLLECTION_ELEM));
237 }
238 else
239 {
240 logger.error("response does not correspond to request!");
241 }
242
243 }
244 }
245
246 String path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.COLLECTION_ELEM + GSXML.LIST_MODIFIER);
247 Element response = (Element) GSXML.getNodeByPath(coll_list_response, path);
248 return response;
249
250 }
251}
Note: See TracBrowser for help on using the repository browser.