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

Last change on this file was 37959, checked in by kjdon, 8 months ago

when we have HLists we always want to get all the siblings along the HList, not just only when the top level classifier node is an HList. As we could have HList inside a VList

  • Property svn:keywords set to Author Date Id Revision
File size: 21.8 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
217 //If we have a horizontal classifier and we have had the top-level node requested (e.g. CL1, CL2 etc.)
218 //then we want to get the children of the first classifier node (e.g. the children of CL2.1)
219 if (OID.isTop(classifier_node) && cl_structure.getAttribute(GSXML.CHILD_TYPE_ATT).equals(GSXML.HLIST)) {
220 boolean firstChildIsClassifierNode = false;
221 NodeList classifierChildrenNodes = GSXML.getChildrenByTagName(cl_structure, GSXML.CLASS_NODE_ELEM);
222 for (int i = 0; i < classifierChildrenNodes.getLength(); i++)
223 {
224 Element currentChild = (Element) classifierChildrenNodes.item(i);
225 if (currentChild.getAttribute(GSXML.NODE_ID_ATT).endsWith(".1"))
226 {
227 firstChildIsClassifierNode = true;
228 }
229 }
230
231 if (firstChildIsClassifierNode)
232 {
233 // get the children of the first child
234 Element childStructure = getClassifierChildrenFromID(doc, classifier_node + ".1", request, collection, service_name);
235
236 // and now insert it into the structure we already have
237 NodeList nodesToSearch = cl_structure.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
238 for (int i = 0; i < nodesToSearch.getLength(); i++)
239 {
240 Element currentElem = (Element) nodesToSearch.item(i);
241 if (currentElem.getAttribute(GSXML.NODE_ID_ATT).equals(classifier_node + ".1"))
242 {
243 Element parent = (Element) currentElem.getParentNode();
244 parent.insertBefore(cl_struct_doc.importNode(childStructure, true), currentElem);
245 parent.removeChild(currentElem);
246 break;
247 }
248 }
249 }
250 } // if OID.isTop(classifier_node) && we are an HList
251 //If we have a horizontal classifier and we have NOT had the top-level node requested then we need to
252 //make sure we get the full list of top-level children to display (e.g. if the user has requested
253 //CL2.1.1 we also need to make sure we have CL2.2, CL2.3, CL2.4 etc.)
254 else
255 {
256 // we need to get siblings of any HList nodes so the HLists remain expanded in the display
257 // start at the bottom (the specified element) and work up teh list of parents expanding any that have hlists
258 NodeList elems = GSXML.getNamedElements(cl_structure, GSXML.CLASS_NODE_ELEM, GSXML.NODE_ID_ATT, classifier_node);
259 Element current_node = null;
260 String current_id = classifier_node;
261 if (elems != null) {
262 // there should only be one node in the list
263 current_node = (Element)elems.item(0);
264 }
265 if (current_node != null) {
266 if (current_node.getAttribute(GSXML.CHILD_TYPE_ATT).equals(GSXML.HLIST)) {
267
268 boolean firstChildIsClassifierNode = false;
269 NodeList classifierChildrenNodes = GSXML.getChildrenByTagName(current_node, GSXML.CLASS_NODE_ELEM);
270 for (int i = 0; i < classifierChildrenNodes.getLength(); i++)
271 {
272
273 Element currentChild = (Element) classifierChildrenNodes.item(i);
274
275 if (currentChild.getAttribute(GSXML.NODE_ID_ATT).endsWith(".1"))
276 {
277 firstChildIsClassifierNode = true;
278 break;
279 }
280 }
281
282 if (firstChildIsClassifierNode)
283 {
284
285 // get the children of the first child
286 Element childStructure = getClassifierChildrenFromID(doc, classifier_node + ".1", request, collection, service_name);
287
288 // and now insert it into the structure we already have
289 NodeList nodesToSearch = cl_structure.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
290 for (int i = 0; i < nodesToSearch.getLength(); i++)
291 {
292 Element currentElem = (Element) nodesToSearch.item(i);
293 if (currentElem.getAttribute(GSXML.NODE_ID_ATT).equals(classifier_node + ".1"))
294 {
295 Element parent = (Element) currentElem.getParentNode();
296 parent.insertBefore(cl_struct_doc.importNode(childStructure, true), currentElem);
297 parent.removeChild(currentElem);
298 break;
299 }
300 }
301 }
302 //**
303 } // current_node is an HList
304 Element parent_node = (Element)current_node.getParentNode();
305 while(parent_node != null && parent_node.getNodeName().equals(GSXML.CLASS_NODE_ELEM)) {
306
307 if (((Element)parent_node).getAttribute(GSXML.CHILD_TYPE_ATT).equals(GSXML.HLIST)) {
308 // get the children of the parent
309 Element new_parent_elem = getClassifierChildrenFromID(cl_struct_doc, parent_node.getAttribute(GSXML.NODE_ID_ATT), request, collection, service_name);
310
311 // put current node into this new structure
312 Element to_be_replaced = GSXML.getNamedElement(new_parent_elem, GSXML.CLASS_NODE_ELEM, GSXML.NODE_ID_ATT, current_id);
313 if (to_be_replaced != null) {
314 new_parent_elem.insertBefore(current_node, to_be_replaced);
315 new_parent_elem.removeChild(to_be_replaced);
316
317
318 if (OID.isTop(parent_node.getAttribute(GSXML.NODE_ID_ATT))) {
319
320 // we can't go up any further.
321 cl_structure = new_parent_elem;
322 parent_node = null;
323
324 } else {
325 Element next_parent = (Element)parent_node.getParentNode();
326 next_parent.insertBefore(new_parent_elem, parent_node );
327 next_parent.removeChild(parent_node);
328 current_node = new_parent_elem;
329 current_id = current_node.getAttribute(GSXML.NODE_ID_ATT);
330 parent_node = next_parent;
331 }
332 } else {
333 // something went wrong, we'll stop this
334 parent_node = null;
335 }
336 } // end of if HList
337 else {
338 current_node = parent_node;
339 current_id = current_node.getAttribute(GSXML.NODE_ID_ATT);
340 parent_node = (Element)current_node.getParentNode();
341 }
342
343 } // while parent != null
344 } // if current_node != null
345 } // end of else
346
347
348 Element page_classifier = null;
349 // add the single classifier node as the page classifier
350 page_classifier = GSXML.duplicateWithNewName(doc, cl_structure, GSXML.CLASSIFIER_ELEM, true);
351 page_response.appendChild(page_classifier);
352 page_classifier.setAttribute(GSXML.NAME_ATT, top_id);
353
354 // get the metadata for each classifier node,
355 // then for each document node
356
357 Element metadata_message = doc.createElement(GSXML.MESSAGE_ELEM);
358
359 boolean did_classifier = false;
360 boolean did_documents = false;
361
362 // if there are classifier nodes
363 // create a metadata request for the classifier, and add it to
364 // the the message
365 NodeList cl_nodes = page_classifier.getElementsByTagName(GSXML.CLASS_NODE_ELEM);
366
367 if (cl_nodes.getLength() > 0)
368 {
369 did_classifier = true;
370 Element cl_meta_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, to + "MetadataRetrieve", userContext);
371 metadata_message.appendChild(cl_meta_request);
372
373 Element new_cl_nodes_list = doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
374 cl_meta_request.appendChild(new_cl_nodes_list);
375
376 for (int c = 0; c < cl_nodes.getLength(); c++)
377 {
378
379 Element cl = doc.createElement(GSXML.CLASS_NODE_ELEM);
380 cl.setAttribute(GSXML.NODE_ID_ATT, ((Element) cl_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
381 new_cl_nodes_list.appendChild(cl);
382 }
383
384 // create and add in the param list - for now get all the metadata
385 // should be based on info sent in from the recept, and the
386 // format stuff
387 Element cl_param_list = createMetadataParamList(doc,class_meta_names);
388 cl_meta_request.appendChild(cl_param_list);
389
390 }
391
392 // if there are document nodes in the classification (happens
393 // sometimes), create a second request for document metadata and
394 // append to the message
395 NodeList doc_nodes = page_classifier.getElementsByTagName(GSXML.DOC_NODE_ELEM);
396 if (doc_nodes.getLength() > 0)
397 {
398 did_documents = true;
399 Element doc_meta_request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_PROCESS, GSPath.appendLink(collection, "DocumentMetadataRetrieve"), userContext);
400 metadata_message.appendChild(doc_meta_request);
401
402 Element doc_list = doc.createElement(GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
403 doc_meta_request.appendChild(doc_list);
404
405 for (int c = 0; c < doc_nodes.getLength(); c++)
406 {
407
408 Element d = doc.createElement(GSXML.DOC_NODE_ELEM);
409 d.setAttribute(GSXML.NODE_ID_ATT, ((Element) doc_nodes.item(c)).getAttribute(GSXML.NODE_ID_ATT));
410 doc_list.appendChild(d);
411 }
412
413 // create and add in the param list - add all for now
414 Element doc_param_list = createMetadataParamList(doc,doc_meta_names);
415 doc_meta_request.appendChild(doc_param_list);
416
417 }
418
419 // process the metadata requests
420 Element metadata_response = (Element) this.mr.process(metadata_message);
421 if (did_classifier)
422 {
423 // the classifier one will be the first response
424 // add the metadata lists for each node back into the
425 // page_classifier nodes
426 path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
427 Node pathNode = GSXML.getNodeByPath(metadata_response, path);
428 if (pathNode == null)
429 {
430 return page_response;
431 }
432 //NodeList meta_response_cls = (Element)pathNode.getChildNodes(); // can't handle empty elements from converting formatted strings (with empty newlines) into XML
433 NodeList meta_response_cls = ((Element) pathNode).getElementsByTagName(GSXML.CLASS_NODE_ELEM);
434 for (int i = 0; i < cl_nodes.getLength(); i++)
435 {
436 GSXML.mergeMetadataLists(cl_nodes.item(i), meta_response_cls.item(i));
437 }
438 }
439
440 if (did_documents)
441 {
442 NodeList meta_response_docs = null;
443 if (!did_classifier)
444 {
445 // its the first response
446 path = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
447 Node pathNode = GSXML.getNodeByPath(metadata_response, path);
448 if (pathNode == null)
449 {
450 return page_response;
451 }
452
453 meta_response_docs = pathNode.getChildNodes();
454
455 }
456 else
457 { // its the second response
458 Node nodes = GSXML.getChildByTagName(metadata_response.getElementsByTagName(GSXML.RESPONSE_ELEM).item(1), GSXML.DOC_NODE_ELEM + GSXML.LIST_MODIFIER);
459 if (nodes == null)
460 {
461 return page_response;
462 }
463 meta_response_docs = nodes.getChildNodes();
464 }
465
466 for (int i = 0; i < doc_nodes.getLength(); i++)
467 {
468 GSXML.mergeMetadataLists(doc_nodes.item(i), meta_response_docs.item(i));
469 }
470 }
471
472 logger.debug("(GS2BrowseAction) Page:\n" + this.converter.getPrettyString(page_response));
473 return page_response;
474 }
475
476 private Element getClassifierChildrenFromID(Document doc, String id, Element request, String collection, String service_name)
477 {
478 UserContext userContext = new UserContext(request);
479 String to = GSPath.appendLink(collection, service_name);
480
481 Document msg_doc = XMLConverter.newDOM();
482 Element firstClassifierNodeChildrenMessage = msg_doc.createElement(GSXML.MESSAGE_ELEM);
483 Element firstClassifierNodeChildrenRequest = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_PROCESS, to, userContext);
484 firstClassifierNodeChildrenMessage.appendChild(firstClassifierNodeChildrenRequest);
485
486 Element paramList = msg_doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
487 firstClassifierNodeChildrenRequest.appendChild(paramList);
488
489 // Element ancestorParam = doc.createElement(GSXML.PARAM_ELEM);
490 // paramList.appendChild(ancestorParam);
491 // ancestorParam.setAttribute(GSXML.NAME_ATT, "structure");
492 // ancestorParam.setAttribute(GSXML.VALUE_ATT, "ancestors");
493
494 Element childrenParam = msg_doc.createElement(GSXML.PARAM_ELEM);
495 paramList.appendChild(childrenParam);
496 childrenParam.setAttribute(GSXML.NAME_ATT, "structure");
497 childrenParam.setAttribute(GSXML.VALUE_ATT, "children");
498
499 Element classifierToGetList = msg_doc.createElement(GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
500 Element classifierToGet = msg_doc.createElement(GSXML.CLASS_NODE_ELEM);
501 classifierToGet.setAttribute(GSXML.NODE_ID_ATT, id);
502 classifierToGetList.appendChild(classifierToGet);
503 firstClassifierNodeChildrenRequest.appendChild(classifierToGetList);
504
505 Element firstClassifierNodeChildrenResponse = (Element) this.mr.process(firstClassifierNodeChildrenMessage);
506
507 String nsPath = GSPath.appendLink(GSXML.RESPONSE_ELEM, GSXML.CLASS_NODE_ELEM + GSXML.LIST_MODIFIER);
508 Element topClassifierNode = (Element) GSXML.getNodeByPath(firstClassifierNodeChildrenResponse, nsPath);
509 nsPath = GSPath.appendLink(GSXML.CLASS_NODE_ELEM, GSXML.NODE_STRUCTURE_ELEM);
510 nsPath = GSPath.appendLink(nsPath, GSXML.CLASS_NODE_ELEM);
511 Element childStructure = (Element) GSXML.getNodeByPath(topClassifierNode, nsPath);
512 return (Element)doc.importNode(childStructure, true);
513 }
514
515 protected void extractMetadataNames(HashSet<String> doc_meta_names, HashSet<String> class_meta_names, Element new_format, Element request)
516 {
517 // for doc names, add the ones from extraMetadata
518 getRequiredMetadataNames(doc_meta_names, null, request);
519 if (new_format == null) return;
520 NodeList templates = new_format.getElementsByTagNameNS(GSXML.GSF_NAMESPACE, "template");
521 for (int i = 0; i < templates.getLength(); i++)
522 {
523 Element template = (Element) templates.item(i);
524 String match = template.getAttribute(GSXML.MATCH_ATT);
525 String name = template.getAttribute(GSXML.NAME_ATT);
526 if (match != null && match.length() > 0)
527 {
528 if (match.startsWith("documentNode"))
529 {
530 getRequiredMetadataNames(doc_meta_names, template, null);
531 }
532 else if (match.startsWith("classifierNode")) // not match.equals, as we want to match nodes like: classifierNode[@classifierStyle = 'VList']
533 {
534 getRequiredMetadataNames(class_meta_names, template, null);
535 }
536 }
537 else
538 {
539 getRequiredMetadataNames(doc_meta_names, template, null);
540 getRequiredMetadataNames(class_meta_names, template, null);
541 }
542 }
543 }
544
545}
Note: See TracBrowser for help on using the repository browser.