source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/collection/Collection.java@ 23489

Last change on this file since 23489 was 23489, checked in by sjb48, 13 years ago

Working on saving a format statement to the config file. This looks like it should work but changes in FormatAction have caused major issues with Document/Node violations. This is because saving required the format statement as a Document rather than a string (which did work). Added a check to GSXML for xmlNodeToString to check that attrs is not null (attrs will be null unless the node is an element).

  • Property svn:keywords set to Author Date Id Revision
File size: 18.0 KB
Line 
1/*
2 * Collection.java
3 * Copyright (C) 2002 New Zealand Digital Library, http://www.nzdl.org
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19package org.greenstone.gsdl3.collection;
20
21import org.greenstone.gsdl3.util.*;
22import org.greenstone.gsdl3.core.*;
23import org.greenstone.gsdl3.service.*;
24
25
26// java XML classes we're using
27import org.w3c.dom.Document;
28import org.w3c.dom.Node;
29import org.w3c.dom.Element;
30import org.w3c.dom.NodeList;
31
32import java.io.*;
33import java.io.File;
34import java.util.HashMap;
35
36import org.apache.log4j.*;
37
38/**
39 * Represents a collection in Greenstone. A collection is an extension of
40 * a ServiceCluster - it has local data that the services use.
41 *
42 * @author <a href="mailto:[email protected]">Katherine Don</a>
43 * @see ModuleInterface
44 */
45public class Collection
46 extends ServiceCluster {
47
48 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.collection.Collection.class.getName());
49
50 /** is this collection being tidied */
51 protected boolean useBook = false;
52 /** is this collection public or private */
53 protected boolean is_public = true;
54
55 /** does this collection provide the OAI service */
56 protected boolean has_oai = true;
57 /** time when this collection was built */
58 protected long lastmodified = 0;
59
60 /** An element containing the serviceRackList element of buildConfig.xml, used to determine whether it contains
61 * the OAIPMH serviceRack
62 */
63 //protected Element service_rack_list = null;
64
65 protected XMLTransformer transformer = null;
66 /** same as setClusterName */
67 public void setCollectionName(String name) {
68 setClusterName(name);
69 }
70
71 public Collection() {
72 super();
73 this.description = this.doc.createElement(GSXML.COLLECTION_ELEM);
74
75 }
76
77 /**
78 * Configures the collection.
79 *
80 * gsdlHome and collectionName must be set before configure is called.
81 *
82 * the file buildcfg.xml is located in gsdlHome/collect/collectionName
83 * collection metadata is obtained, and services loaded.
84 *
85 * @return true/false on success/fail
86 */
87 public boolean configure() {
88
89 if (this.site_home == null || this.cluster_name== null) {
90 logger.error("Collection: site_home and collection_name must be set before configure called!");
91 return false;
92 }
93
94 Element coll_config_xml = loadCollConfigFile();
95 Element build_config_xml = loadBuildConfigFile();
96
97 if (coll_config_xml==null||build_config_xml==null) {
98 return false;
99 }
100
101 // get the collection type attribute
102 Element search = (Element) GSXML.getChildByTagName(coll_config_xml, GSXML.SEARCH_ELEM);
103 if(search!=null) {
104 col_type = search.getAttribute(GSXML.TYPE_ATT);
105 }
106
107 // process the metadata and display items
108 findAndLoadInfo(coll_config_xml, build_config_xml);
109
110 // now do the services
111 configureServiceRacks(coll_config_xml, build_config_xml);
112
113 return true;
114
115 }
116
117 public boolean useBook() {
118 return useBook;
119 }
120
121 public boolean isPublic() {
122 return is_public;
123 }
124 //used by the OAIReceptionist to find out the earliest datestamp amongst all oai collections in the repository
125 public long getLastmodified() {
126 return lastmodified;
127 }
128 /** whether the service_map in ServiceCluster.java contains the service 'OAIPMH'
129 * 11/06/2007 xiao
130 */
131 public boolean hasOAI() {
132 return has_oai;
133 }
134 /**
135 * load in the collection config file into a DOM Element
136 */
137 protected Element loadCollConfigFile() {
138
139 File coll_config_file = new File(GSFile.collectionConfigFile(this.site_home, this.cluster_name));
140
141 if (!coll_config_file.exists()) {
142 logger.error("Collection: couldn't configure collection: "+this.cluster_name+", "+coll_config_file+" does not exist");
143 return null;
144 }
145 // get the xml for both files
146 Document coll_config_doc = this.converter.getDOM(coll_config_file, CONFIG_ENCODING);
147 Element coll_config_elem = null;
148 if (coll_config_doc != null) {
149 coll_config_elem = coll_config_doc.getDocumentElement();
150 }
151 return coll_config_elem;
152
153 }
154
155 /**
156 * load in the collection build config file into a DOM Element
157 */
158 protected Element loadBuildConfigFile() {
159
160 File build_config_file = new File(GSFile.collectionBuildConfigFile(this.site_home, this.cluster_name));
161 if (!build_config_file.exists()) {
162 logger.error("Collection: couldn't configure collection: "+this.cluster_name+", "+build_config_file+" does not exist");
163 return null;
164 }
165 Document build_config_doc = this.converter.getDOM(build_config_file, CONFIG_ENCODING);
166 Element build_config_elem = null;
167 if (build_config_doc != null) {
168 build_config_elem = build_config_doc.getDocumentElement();
169 }
170
171 lastmodified = build_config_file.lastModified();
172
173 return build_config_elem;
174 }
175
176 /**
177 * find the metadata and display elems from the two config files and add it to the appropriate lists
178 */
179 protected boolean findAndLoadInfo(Element coll_config_xml,
180 Element build_config_xml){
181
182 // metadata
183 Element meta_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
184 addMetadata(meta_list);
185 meta_list = (Element)GSXML.getChildByTagName(build_config_xml, GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER);
186 addMetadata(meta_list);
187
188 meta_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
189 GSXML.addMetadata(this.doc, meta_list, "httpPath", this.site_http_address+"/collect/"+this.cluster_name);
190 addMetadata(meta_list);
191
192 // display stuff
193 Element display_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER);
194 if (display_list != null) {
195 resolveMacros(display_list);
196 addDisplayItems(display_list);
197 }
198
199 //check whether the html are tidy or not
200 Element import_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.IMPORT_ELEM);
201 if (import_list != null) {
202 Element plugin_list = (Element)GSXML.getChildByTagName(import_list, GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER);
203 addPlugins(plugin_list);
204 if (plugin_list != null){
205 Element plugin_elem = (Element)GSXML.getNamedElement(plugin_list, GSXML.PLUGIN_ELEM, GSXML.NAME_ATT, "HTMLPlug");
206 if (plugin_elem != null) {
207 //get the option
208 Element option_elem = (Element)GSXML.getNamedElement(plugin_elem, GSXML.PARAM_OPTION_ELEM, GSXML.NAME_ATT, "-tidy_html");
209 if (option_elem != null) {
210 useBook = true;
211 }
212 }
213 }
214 }
215 meta_list = this.doc.createElement(GSXML.METADATA_ELEM + GSXML.LIST_MODIFIER);
216 if (useBook == true)
217 GSXML.addMetadata(this.doc, meta_list, "tidyoption", "tidy");
218 else
219 GSXML.addMetadata(this.doc, meta_list, "tidyoption", "untidy");
220 addMetadata(meta_list);
221
222 // check whether we are public or not
223 if (meta_list != null) {
224 Element meta_elem = (Element) GSXML.getNamedElement(metadata_list, GSXML.METADATA_ELEM, GSXML.NAME_ATT, "public");
225 if (meta_elem != null) {
226 String value = GSXML.getValue(meta_elem).toLowerCase().trim();
227 if (value.equals("false")) {
228 is_public = false;
229 }
230 }
231 }
232 return true;
233
234 }
235
236 protected boolean configureServiceRacks(Element coll_config_xml,
237 Element build_config_xml){
238 clearServices();
239 Element service_list = (Element)GSXML.getChildByTagName(build_config_xml, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
240 configureServiceRackList(service_list, coll_config_xml);
241
242 // collection Config may also contain manually added service racks
243 service_list = (Element)GSXML.getChildByTagName(coll_config_xml, GSXML.SERVICE_CLASS_ELEM+GSXML.LIST_MODIFIER);
244 if (service_list != null) {
245 configureServiceRackList(service_list, build_config_xml);
246
247 // Check for oai
248 Element oai_service_rack = GSXML.getNamedElement(service_list, GSXML.SERVICE_CLASS_ELEM, OAIXML.NAME, OAIXML.OAIPMH);
249 if (oai_service_rack == null) {
250 has_oai = false;
251 logger.info("No oai for collection: " + this.cluster_name);
252
253 } else {
254 has_oai = true;
255 }
256 }
257 return true;
258 }
259
260 protected boolean resolveMacros(Element display_list) {
261 if (display_list==null) return false;
262 NodeList displaynodes = display_list.getElementsByTagName(GSXML.DISPLAY_TEXT_ELEM);
263 if (displaynodes.getLength()>0) {
264 String http_site = this.site_http_address;
265 String http_collection = this.site_http_address +"/collect/"+this.cluster_name;
266 for(int k=0; k<displaynodes.getLength(); k++) {
267 Element d = (Element) displaynodes.item(k);
268 String text = GSXML.getNodeText(d);
269 text = text.replaceAll("_httpsite_", http_site);
270 text = text.replaceAll("_httpcollection_", http_collection);
271 GSXML.setNodeText(d, text);
272 }
273 }
274 return true;
275 }
276 /**
277 * do a configure on only part of the collection
278 */
279 protected boolean configureSubset(String subset) {
280
281 // need the coll config files
282 Element coll_config_elem = loadCollConfigFile();
283 Element build_config_elem = loadBuildConfigFile();
284 if (coll_config_elem == null||build_config_elem == null) {
285 // wont be able to do any of the requests
286 return false;
287 }
288
289 if (subset.equals(GSXML.SERVICE_ELEM+GSXML.LIST_MODIFIER)) {
290 return configureServiceRacks(coll_config_elem, build_config_elem);
291 }
292
293 if (subset.equals(GSXML.METADATA_ELEM+GSXML.LIST_MODIFIER) || subset.equals(GSXML.DISPLAY_TEXT_ELEM+GSXML.LIST_MODIFIER) || subset.equals(GSXML.PLUGIN_ELEM+GSXML.LIST_MODIFIER)) {
294 return findAndLoadInfo(coll_config_elem, build_config_elem);
295
296 }
297
298 logger.error("Collection: cant process system request, configure "+subset);
299 return false;
300 }
301
302 /** handles requests made to the ServiceCluster itself
303 *
304 * @param req - the request Element- <request>
305 * @return the result Element - should be <response>
306 */
307 protected Element processMessage(Element request) {
308
309 Element response = this.doc.createElement(GSXML.RESPONSE_ELEM);
310 response.setAttribute(GSXML.FROM_ATT, this.cluster_name);
311 String type = request.getAttribute(GSXML.TYPE_ATT);
312 String lang = request.getAttribute(GSXML.LANG_ATT);
313 response.setAttribute(GSXML.TYPE_ATT, type);
314
315 if (type.equals(GSXML.REQUEST_TYPE_FORMAT_STRING)) {
316 logger.error("Received format string request");
317
318 String subaction = request.getAttribute("subaction");
319 logger.error("Subaction is " + subaction);
320
321 String service = request.getAttribute("service");
322 logger.error("Service is " + service);
323
324 String classifier = null;
325 if(service.equals("ClassifierBrowse"))
326 {
327 classifier = request.getAttribute("classifier");
328 logger.error("Classifier is " + classifier);
329 }
330
331 Element format_element = (Element) GSXML.getChildByTagName(request, GSXML.FORMAT_STRING_ELEM);
332 //String format_string = GSXML.getNodeText(format_element);
333 Element format_statement = (Element) format_element.getFirstChild();
334
335 //logger.error("Format string: " + format_string);
336 logger.error("Config file location = " + GSFile.collectionConfigFile(this.site_home, this.cluster_name));
337
338 // check for version file
339
340 String directory = new File(GSFile.collectionConfigFile(this.site_home, this.cluster_name)).getParent() + File.separator;
341 logger.error("Directory is " + directory);
342
343 String version_filename = "";
344 if(service.equals("ClassifierBrowse"))
345 version_filename = directory + "browse_"+classifier+"_format_statement_version.txt";
346 else
347 version_filename = directory + "query_format_statement_version.txt";
348
349 File version_file = new File(version_filename);
350 logger.error("Version filename is " + version_filename);
351
352
353 if(subaction.equals("update"))
354 {
355 String version_number = "1";
356 BufferedWriter writer;
357
358 try{
359
360 if(version_file.exists())
361 {
362 // Read version
363 BufferedReader reader = new BufferedReader(new FileReader(version_filename));
364 version_number = reader.readLine();
365 int aInt = Integer.parseInt(version_number) + 1;
366 version_number = Integer.toString(aInt);
367 reader.close();
368 }
369 else{
370 // Create
371 version_file.createNewFile();
372 writer = new BufferedWriter(new FileWriter(version_filename));
373 writer.write(version_number);
374 writer.close();
375 }
376
377 // Write version file
378 String format_statement_filename = "";
379
380 if(service.equals("ClassifierBrowse"))
381 format_statement_filename = directory + "browse_"+classifier+"_format_statement_v" + version_number + ".txt";
382 else
383 format_statement_filename = directory + "query_format_statement_v" + version_number + ".txt";
384
385 logger.error("Format statement filename is " + format_statement_filename);
386
387 // Write format statement
388 String format_string = GSXML.xmlNodeToString(format_statement);
389 writer = new BufferedWriter(new FileWriter(format_statement_filename));
390 writer.write(format_string);
391 writer.close();
392
393 // Update version number
394 writer = new BufferedWriter(new FileWriter(version_filename));
395 writer.write(version_number);
396 writer.close();
397
398 } catch (IOException e) {
399 logger.error("IO Exception "+e);
400 }
401 }
402
403 if(subaction.equals("save"))
404 {
405 logger.error("SAVE format statement");
406
407 // open collectionConfig.xml and read in to w3 Document
408 String collection_config = directory + "collectionConfig.xml";
409 Document config = this.converter.getDOM(new File(collection_config), "UTF-8");
410
411 //String tag_name = "";
412 int k;
413 int index;
414 Element elem;
415 Node current_node = GSXML.getChildByTagName(config, "CollectionConfig");
416 NodeList current_node_list;
417
418 if(service.equals("ClassifierBrowse"))
419 {
420 //tag_name = "browse";
421 // if CLX then need to look in <classifier> X then <format>
422 // default is <browse><format>
423
424 current_node = GSXML.getChildByTagName(current_node, "browse");
425
426 // find CLX
427 if(classifier != null)
428 {
429 current_node_list = GSXML.getChildrenByTagName(current_node, "classifier");
430 index = Integer.parseInt(classifier.substring(2)) - 1;
431 // index should be given by X-1
432 current_node = current_node_list.item(index);
433 current_node = GSXML.getChildByTagName(current_node, "format");
434 }
435 else{
436 current_node = GSXML.getChildByTagName(current_node, "format");
437 }
438 }
439 else
440 {
441 // look in <format> with no attributes
442
443 current_node_list = GSXML.getChildrenByTagName(current_node, "search");
444 for(k=0; k<current_node_list.getLength(); k++)
445 {
446 current_node = current_node_list.item(k);
447 // if current_node has no attributes then break
448 elem = (Element) current_node;
449 if(elem.hasAttribute("name")==false)
450 break;
451 }
452 }
453
454 // Current_node should be a format tag
455 elem = (Element) current_node;
456
457 logger.error("Current_node = " + elem.getNodeName());
458
459 // seems we want to remove current child/ren and replace with format_statement's child/ren?
460
461 // remove existing
462 current_node_list = elem.getChildNodes();
463 for(k=0; k<current_node_list.getLength(); k++)
464 {
465 current_node = elem.removeChild(current_node_list.item(k));
466 }
467
468 // append new
469 current_node_list = format_statement.getChildNodes();
470 for(k=0; k<current_node_list.getLength(); k++)
471 {
472 current_node = elem.appendChild(current_node_list.item(k));
473 }
474
475 //String text = GSXML.getNodeText(elem);
476 //logger.error(text);
477 //text = text.replaceAll("_httpsite_", http_site);
478 //text = text.replaceAll("_httpcollection_", http_collection);
479 //GSXML.setNodeText(d, text);
480
481 // Now convert config document to string for writing to file
482 String new_config = GSXML.xmlNodeToString(config);
483
484 // Write to file (not original! for now)
485 try{
486 BufferedWriter writer = new BufferedWriter(new FileWriter(collection_config+".new"));
487 writer.write(new_config);
488 writer.close();
489 } catch (IOException e) {
490 logger.error("IO Exception "+e);
491 }
492 }
493 }
494 else { // unknown type
495 super.processMessage(request);
496
497 }
498 return response;
499 }
500
501}
502
503
504
505
Note: See TracBrowser for help on using the repository browser.