source: main/trunk/greenstone3/src/java/org/greenstone/gsdl3/service/GS2Construct.java@ 31127

Last change on this file since 31127 was 31127, checked in by ak19, 7 years ago

Related to previous revision (31125). Fix to concurrency problem when setting multiple metadata using doc editor 1. Better reporting in the status element of the response returned after setting metadata, now it indicates that it has finished setting meta on success. 2. Removed debug statements from experimental fix. 3. Not using logger error for info message in MessageRouter.

  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/*
2 * GS2Construct.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.service;
20
21import java.io.BufferedWriter;
22import java.io.File;
23import java.io.FileWriter;
24import java.io.Serializable;
25import java.util.Collections;
26import java.util.Iterator;
27import java.util.Map.Entry;
28import java.util.HashMap;
29import java.util.Map;
30import java.util.Set;
31
32import org.apache.log4j.Logger;
33import org.greenstone.gsdl3.build.GS2PerlConstructor;
34import org.greenstone.gsdl3.build.GS2PerlListener;
35import org.greenstone.gsdl3.util.GSFile;
36import org.greenstone.gsdl3.util.GSParams;
37import org.greenstone.gsdl3.util.GSPath;
38import org.greenstone.gsdl3.util.GSStatus;
39import org.greenstone.gsdl3.util.GSXML;
40import org.greenstone.gsdl3.util.OID;
41import org.greenstone.gsdl3.util.SimpleCollectionDatabase;
42import org.greenstone.gsdl3.util.UserContext;
43import org.greenstone.gsdl3.util.XMLConverter;
44
45import org.w3c.dom.Document;
46import org.w3c.dom.Element;
47import org.w3c.dom.Node;
48import org.w3c.dom.Text;
49
50/**
51 * A Services class for building collections provides a wrapper around the old
52 * perl scripts
53 *
54 * @author Katherine Don
55 */
56public class GS2Construct extends ServiceRack
57{
58
59 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2Construct.class.getName());
60
61 // services offered
62 private static final String NEW_SERVICE = "NewCollection";
63 private static final String ADD_DOC_SERVICE = "AddDocument";
64 private static final String IMPORT_SERVICE = "ImportCollection";
65 private static final String BUILD_SERVICE = "BuildCollection";
66 private static final String ACTIVATE_SERVICE = "ActivateCollection";
67 private static final String BUILD_AND_ACTIVATE_SERVICE = "BuildAndActivateCollection";
68 private static final String DELETE_SERVICE = "DeleteCollection";
69 private static final String RELOAD_SERVICE = "ReloadCollection";
70 private static final String MODIFY_METADATA_SERVICE = "ModifyMetadata"; // set or remove metadata
71
72
73 // params used
74 private static final String COL_PARAM = "collection";
75 private static final String NEW_COL_TITLE_PARAM = "collTitle";
76 private static final String NEW_COL_ABOUT_PARAM = "collAbout";
77 private static final String CREATOR_PARAM = "creator";
78 private static final String NEW_FILE_PARAM = "newfile";
79 private static final String PROCESS_ID_PARAM = GSParams.PROCESS_ID;
80 private static final String BUILDTYPE_PARAM = "buildType";
81 private static final String BUILDTYPE_MG = "mg";
82 private static final String BUILDTYPE_MGPP = "mgpp";
83
84 protected static String DATABASE_TYPE = null;
85 protected SimpleCollectionDatabase coll_db = null;
86
87 // the list of the collections - store between some method calls
88 private String[] collection_list = null;
89
90 // set of listeners for any construction commands
91 protected Map<String, GS2PerlListener> listeners = null;
92 protected HashMap<String, Boolean> collectionOperationMap = new HashMap<String, Boolean>();
93
94 public GS2Construct()
95 {
96 this.listeners = Collections.synchronizedMap(new HashMap<String, GS2PerlListener>());
97 }
98
99 /** returns a specific service description */
100 protected Element getServiceDescription(Document doc, String service, String lang, String subset)
101 {
102
103 Element description = doc.createElement(GSXML.SERVICE_ELEM);
104 description.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
105 description.setAttribute(GSXML.NAME_ATT, service);
106 if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER))
107 {
108 description.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_NAME, getTextString(service + ".name", lang)));
109 description.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(service + ".description", lang)));
110 description.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(service + ".submit", lang)));
111 }
112 if (subset == null || subset.equals(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER))
113 {
114 Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
115 description.appendChild(param_list);
116
117 if (service.equals(NEW_SERVICE))
118 {
119
120 Element param = GSXML.createParameterDescription(doc, NEW_COL_TITLE_PARAM, getTextString("param." + NEW_COL_TITLE_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
121 param_list.appendChild(param);
122 param = GSXML.createParameterDescription(doc, CREATOR_PARAM, getTextString("param." + CREATOR_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
123 param_list.appendChild(param);
124 param = GSXML.createParameterDescription(doc, NEW_COL_ABOUT_PARAM, getTextString("param." + NEW_COL_ABOUT_PARAM, lang), GSXML.PARAM_TYPE_TEXT, null, null, null);
125 param_list.appendChild(param);
126 String[] types = { BUILDTYPE_MGPP, BUILDTYPE_MG };
127 String[] type_texts = { getTextString("param." + BUILDTYPE_PARAM + "." + BUILDTYPE_MGPP, lang), getTextString("param." + BUILDTYPE_PARAM + "." + BUILDTYPE_MG, lang) };
128
129 param = GSXML.createParameterDescription(doc, BUILDTYPE_PARAM, getTextString("param." + BUILDTYPE_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, BUILDTYPE_MGPP, types, type_texts);
130 param_list.appendChild(param);
131 }
132 else if (service.equals(ACTIVATE_SERVICE) || service.equals(IMPORT_SERVICE) || service.equals(BUILD_SERVICE) || service.equals(RELOAD_SERVICE) || service.equals(DELETE_SERVICE) || service.equals(MODIFY_METADATA_SERVICE))
133 {
134
135 this.collection_list = getCollectionList();
136 Element param = GSXML.createParameterDescription(doc, COL_PARAM, getTextString("param." + COL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, null, this.collection_list, this.collection_list);
137 param_list.appendChild(param);
138 }
139 else
140 {
141 // invalid service name
142 return null;
143 }
144 }
145 return description;
146 }
147
148 // each service must have a method "process<New service name>"
149
150 protected Element processNewCollection(Element request)
151 {
152 if (!userHasCollectionEditPermissions(request)) {
153 Document result_doc = XMLConverter.newDOM();
154 Element result = GSXML.createBasicResponse(result_doc, "processNewCollection");
155 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
156 return result;
157 }
158 return runCommand(request, GS2PerlConstructor.NEW);
159 }
160
161 /** TODO:implement this */
162 protected Element processAddDocument(Element request)
163 {
164 if (!userHasCollectionEditPermissions(request)) {
165 Document result_doc = XMLConverter.newDOM();
166 Element result = GSXML.createBasicResponse(result_doc, "processAddDocument");
167 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
168 return result;
169 }
170
171 Document result_doc = XMLConverter.newDOM();
172 // decode the file name, add it to the import directory
173 String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
174 Element response = result_doc.createElement(GSXML.RESPONSE_ELEM);
175 response.setAttribute(GSXML.FROM_ATT, name);
176 Element status = result_doc.createElement(GSXML.STATUS_ELEM);
177 response.appendChild(status);
178 //String lang = request.getAttribute(GSXML.LANG_ATT);
179 //String request_type = request.getAttribute(GSXML.TYPE_ATT);
180 Text t = result_doc.createTextNode("AddDocument: not implemented yet");
181 status.appendChild(t);
182 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
183 return response;
184 }
185
186 protected Element processBuildAndActivateCollection(Element request)
187 {
188 // check permissions
189 if (!userHasCollectionEditPermissions(request)) {
190 Document result_doc = XMLConverter.newDOM();
191 Element result = GSXML.createBasicResponse(result_doc, "processBuildAndActivateCollection");
192 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
193 return result;
194 }
195
196
197 waitUntilReady(request);
198 Element buildResponse = processBuildCollection(request);
199 if (buildResponse.getElementsByTagName(GSXML.ERROR_ELEM).getLength() > 0)
200 {
201 signalReady(request);
202 return buildResponse;
203 }
204
205 Element statusElem = (Element) buildResponse.getElementsByTagName(GSXML.STATUS_ELEM).item(0);
206 String id = statusElem.getAttribute("pid");
207
208 GS2PerlListener currentListener = this.listeners.get(id);
209 int statusCode = currentListener.getStatus();
210 while (!GSStatus.isCompleted(statusCode))
211 {
212 // wait for the process, and keep checking the status code
213 // there is probably a better way to do this.
214 try
215 {
216 Thread.currentThread().sleep(100);
217 }
218 catch (Exception e)
219 { // ignore
220 }
221 statusCode = currentListener.getStatus();
222 }
223
224 Element activateResponse = processActivateCollection(request);
225 signalReady(request);
226 return activateResponse;
227 }
228
229 protected Element processImportCollection(Element request)
230 {
231 if (!userHasCollectionEditPermissions(request)) {
232 Document result_doc = XMLConverter.newDOM();
233 Element result = GSXML.createBasicResponse(result_doc, "processImportCollection");
234 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
235 return result;
236 }
237
238 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
239 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
240
241 if (params == null)
242 {
243 return null;
244 }
245
246 //If we have been requested to only build certain documents then we need to create a manifest file
247 String documentsParam = (String) params.get("documents");
248 if (documentsParam != null && !documentsParam.equals(""))
249 {
250 String s = File.separator;
251 String manifestFolderPath = this.site_home + s + "collect" + s + params.get(COL_PARAM) + s + "manifests";
252 String manifestFilePath = manifestFolderPath + File.separator + "tempManifest.xml";
253
254 File manifestFolderFile = new File(manifestFolderPath);
255 if (!manifestFolderFile.exists())
256 {
257 manifestFolderFile.mkdirs();
258 }
259
260 File manifestFile = new File(manifestFilePath);
261 if (!manifestFile.exists())
262 {
263 try
264 {
265 manifestFile.createNewFile();
266 }
267 catch (Exception ex)
268 {
269 ex.printStackTrace();
270 return null; //Probably should return an actual error
271 }
272 }
273 String[] docList = documentsParam.split(",");
274
275 try
276 {
277 BufferedWriter bw = new BufferedWriter(new FileWriter(manifestFile));
278 bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
279 bw.write("<Manifest>\n");
280 bw.write(" <Index>\n");
281 for (int j = 0; j < docList.length; j++)
282 {
283 bw.write(" <Filename>" + docList[j] + "</Filename>\n");
284 }
285 bw.write(" </Index>\n");
286 bw.write("</Manifest>\n");
287 bw.close();
288 }
289 catch (Exception ex)
290 {
291 ex.printStackTrace();
292 return null; //Probably should return an actual error
293 }
294 }
295
296 return runCommand(request, GS2PerlConstructor.IMPORT);
297 }
298
299 protected Element processBuildCollection(Element request)
300 {
301 if (!userHasCollectionEditPermissions(request)) {
302 Document result_doc = XMLConverter.newDOM();
303 Element result = GSXML.createBasicResponse(result_doc, "processBuildCollection");
304 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
305 return result;
306 }
307
308 return runCommand(request, GS2PerlConstructor.BUILD);
309 }
310
311 protected Element processModifyMetadata(Element request)
312 {
313 if (!userHasCollectionEditPermissions(request)) {
314 Document result_doc = XMLConverter.newDOM();
315 Element result = GSXML.createBasicResponse(result_doc, "processModifyMetadata");
316 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
317 return result;
318 }
319
320 // wait until we can reserve the collection for processing
321 waitUntilReady(request);
322
323
324 // process
325 Element response = runCommand(request, GS2PerlConstructor.MODIFY_METADATA_SERVER);
326
327 if (response.getElementsByTagName(GSXML.ERROR_ELEM).getLength() <= 0) // if no errors, wait for process to finish
328 {
329 Element statusElem = (Element) response.getElementsByTagName(GSXML.STATUS_ELEM).item(0);
330 String id = statusElem.getAttribute("pid");
331
332 GS2PerlListener currentListener = this.listeners.get(id);
333 int statusCode = currentListener.getStatus();
334 while (!GSStatus.isCompleted(statusCode))
335 {
336 // wait for the process, and keep checking the status code
337 // there is probably a better way to do this.
338 try
339 {
340 Thread.currentThread().sleep(100);
341 }
342 catch (Exception e)
343 { // ignore
344 }
345 statusCode = currentListener.getStatus();
346 }
347 }
348
349 Element statusElem = (Element) response.getElementsByTagName(GSXML.STATUS_ELEM).item(0);
350 String statusString = GSXML.getNodeText(statusElem);
351 statusString += " and monitored until done.";
352 GSXML.setNodeText(statusElem, statusString);
353
354 // release hold on collection
355 signalReady(request);
356 return response;
357
358 }
359
360 protected Element processActivateCollection(Element request)
361 {
362
363 if (!userHasCollectionEditPermissions(request)) {
364 Document result_doc = XMLConverter.newDOM();
365 Element result = GSXML.createBasicResponse(result_doc, "processActivateCollection");
366 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
367 return result;
368 }
369
370 // this activates the collection on disk. but now we need to tell
371 // the MR about it. but we have to wait until the process is finished.
372 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
373 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
374 String coll_name = (String) params.get(COL_PARAM);
375 String lang = request.getAttribute(GSXML.LANG_ATT);
376
377 UserContext userContext = new UserContext(request);
378 String request_type = request.getAttribute(GSXML.TYPE_ATT);
379
380 // now we de-activate the collection before running activate.pl, and then re-activate at end
381 // So activate.pl only does the moving, no activation. This way will prevent java from launching
382 // perl, exiting and then leaving dangling file handles (on index/text/col.gdb) in perl.
383 if (!request_type.equals(GSXML.REQUEST_TYPE_STATUS)) {
384 systemRequest("delete", coll_name, null, userContext); // deactivate collection
385 }
386
387 Element response = runCommand(request, GS2PerlConstructor.ACTIVATE); // if request is for STATUS, then this won't run activate.pl
388
389 Element status = (Element) GSXML.getChildByTagName(response, GSXML.STATUS_ELEM);
390
391 // check for finished
392 int status_code = Integer.parseInt(status.getAttribute(GSXML.STATUS_ERROR_CODE_ATT));
393 if (GSStatus.isCompleted(status_code) && GSStatus.isError(status_code))
394 {
395 // we shouldn't carry out the next bit, just return the response
396 return response;
397 }
398 String id = status.getAttribute(GSXML.STATUS_PROCESS_ID_ATT);
399 GS2PerlListener listener = this.listeners.get(id);
400 if (listener == null)
401 {
402 logger.error("somethings gone wrong, couldn't find the listener");
403 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
404 return response;
405 }
406
407 while (!GSStatus.isCompleted(status_code))
408 {
409 // wait for the process, and keep checking the status code
410 // there is probably a better way to do this.
411 try
412 {
413 Thread.currentThread().sleep(100);
414 }
415 catch (Exception e)
416 { // ignore
417 }
418 status_code = listener.getStatus();
419 }
420
421 // add the rest of the messages to the status node
422 Text t = status.getOwnerDocument().createTextNode("\n" + listener.getUpdate());
423 status.appendChild(t);
424 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(listener.getStatus()));
425 if (GSStatus.isError(status_code))
426 {
427 return response; // without doing the next bit
428 }
429
430 t = status.getOwnerDocument().createTextNode("\n");
431 status.appendChild(t);
432 // once have got here, we assume
433 // the first bit proceeded successfully, now reload the collection (sends a collection reactivation request)
434 systemRequest("reload", coll_name, status, userContext); // this will append more messages to the status, and overwrite the error code att
435 return response;
436
437 }
438
439 protected Element processDeleteCollection(Element request)
440 {
441 if (!userHasCollectionEditPermissions(request)) {
442 Document result_doc = XMLConverter.newDOM();
443 Element result = GSXML.createBasicResponse(result_doc, "processDeleteCollection");
444 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
445 return result;
446 }
447
448 Document result_doc = XMLConverter.newDOM();
449 // the response to send back
450 String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
451 Element response = result_doc.createElement(GSXML.RESPONSE_ELEM);
452 response.setAttribute(GSXML.FROM_ATT, name);
453 Element status = result_doc.createElement(GSXML.STATUS_ELEM);
454 response.appendChild(status);
455 Text t = null; // the text node for the error/success message
456 String lang = request.getAttribute(GSXML.LANG_ATT);
457 String request_type = request.getAttribute(GSXML.TYPE_ATT);
458
459 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
460 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
461
462 boolean get_status_only = false;
463 if (request_type.equals(GSXML.REQUEST_TYPE_STATUS))
464 {
465 get_status_only = true;
466 }
467 if (get_status_only)
468 {
469 // at the moment, delete is synchronous. but it may take ages so should do the command in another thread maybe? in which case we will want to ask for status
470 logger.error("had a status request for delete - this shouldn't happen!!");
471 //t = result_doc.createTextNode("");
472 //status.appendChild(t);
473 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
474 return response;
475 }
476 String coll_name = (String) params.get(COL_PARAM);
477 String[] args = { coll_name };
478 File coll_dir = new File(GSFile.collectionBaseDir(this.site_home, coll_name));
479 // check that the coll is there in the first place
480 if (!coll_dir.exists())
481 {
482 t = result_doc.createTextNode(getTextString("delete.exists_error", lang, args));
483 status.appendChild(t);
484 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
485 return response;
486 }
487
488 // try to delete the directory
489 if (!GSFile.deleteFile(coll_dir))
490 {
491 t = result_doc.createTextNode(getTextString("delete.delete_error", lang, args));
492 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
493 status.appendChild(t);
494 return response;
495 }
496
497 UserContext userContext = new UserContext(request);
498
499 systemRequest("delete", coll_name, status, userContext);
500 return response;
501 }
502
503 protected Element processReloadCollection(Element request)
504 {
505 if (!userHasCollectionEditPermissions(request)) {
506 Document result_doc = XMLConverter.newDOM();
507 Element result = GSXML.createBasicResponse(result_doc, "processReloadCollection");
508 GSXML.addError(result, "This user does not have the required permissions to perform this action.");
509 return result;
510 }
511
512 Document result_doc = XMLConverter.newDOM();
513 // the response to send back
514 String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
515 Element response = result_doc.createElement(GSXML.RESPONSE_ELEM);
516 response.setAttribute(GSXML.FROM_ATT, name);
517 Element status = result_doc.createElement(GSXML.STATUS_ELEM);
518 response.appendChild(status);
519 Text t = null; // the text node for the error/success message
520
521 String lang = request.getAttribute(GSXML.LANG_ATT);
522 String request_type = request.getAttribute(GSXML.TYPE_ATT);
523
524 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
525 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
526
527 boolean get_status_only = false;
528 if (request_type.equals(GSXML.REQUEST_TYPE_STATUS))
529 {
530 get_status_only = true;
531 }
532 if (get_status_only)
533 {
534 // reload is synchronous - this makes no sense
535 logger.error("had a status request for reload - this shouldn't happen!!");
536 //t = result_doc.createTextNode("");
537 //status.appendChild(t);
538 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
539 return response;
540 }
541
542 String coll_name = (String) params.get(COL_PARAM);
543
544 UserContext userContext = new UserContext(request);
545
546 systemRequest("reload", coll_name, status, userContext);
547 return response;
548
549 }
550
551 /**
552 * send a configure request to the message router action name should be
553 * "delete" or "reload" response will be put into the status element
554 */
555 protected void systemRequest(String operation, String coll_name, Element status, UserContext userContext)
556 {
557 // send the request to the MR
558 Document doc = XMLConverter.newDOM();
559 Element message = doc.createElement(GSXML.MESSAGE_ELEM);
560 Element request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_SYSTEM, "", userContext);
561 message.appendChild(request);
562 Element command = doc.createElement(GSXML.SYSTEM_ELEM);
563 request.appendChild(command);
564 command.setAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT, GSXML.COLLECTION_ELEM);
565 command.setAttribute(GSXML.SYSTEM_MODULE_NAME_ATT, coll_name);
566
567 if (operation.equals("delete"))
568 {
569 command.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_DEACTIVATE);
570 }
571 else if (operation.equals("reload"))
572 {
573 command.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_ACTIVATE);
574 }
575 else
576 {
577 logger.error("invalid action name passed to systemRequest:" + operation);
578 return;
579 }
580 request.appendChild(command);
581 Node response = this.router.process(message); // at the moment, get no info in response so ignore it
582 Text t;
583 String[] args = { coll_name };
584
585 if (status != null)
586 {
587 if (response == null)
588 {
589 t = status.getOwnerDocument().createTextNode(getTextString(operation + ".configure_error", userContext.getLanguage(), args));
590 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
591 status.appendChild(t);
592 return;
593 }
594
595 // if we got here, we have succeeded!
596 t = status.getOwnerDocument().createTextNode(getTextString(operation + ".success", userContext.getLanguage(), args));
597 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.SUCCESS));
598 status.appendChild(t);
599 }
600 }
601
602 /**
603 * configure the service module for now, all services have type=build - need
604 * to think about this
605 */
606 public boolean configure(Element info, Element extra_info)
607 {
608 if (!super.configure(info, extra_info))
609 {
610 return false;
611 }
612
613 logger.info("configuring GS2Construct");
614
615 Element e = null;
616 // hard code in the services for now
617
618 // set up short_service_info_ - for now just has name and type
619
620 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
621 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
622 e.setAttribute(GSXML.NAME_ATT, NEW_SERVICE);
623 this.short_service_info.appendChild(e);
624
625 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
626 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
627 e.setAttribute(GSXML.NAME_ATT, IMPORT_SERVICE);
628 this.short_service_info.appendChild(e);
629
630 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
631 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
632 e.setAttribute(GSXML.NAME_ATT, BUILD_SERVICE);
633 this.short_service_info.appendChild(e);
634
635 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
636 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
637 e.setAttribute(GSXML.NAME_ATT, ACTIVATE_SERVICE);
638 this.short_service_info.appendChild(e);
639
640 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
641 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
642 e.setAttribute(GSXML.NAME_ATT, BUILD_AND_ACTIVATE_SERVICE);
643 this.short_service_info.appendChild(e);
644
645 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
646 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
647 e.setAttribute(GSXML.NAME_ATT, DELETE_SERVICE);
648 this.short_service_info.appendChild(e);
649
650 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
651 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
652 e.setAttribute(GSXML.NAME_ATT, RELOAD_SERVICE);
653 this.short_service_info.appendChild(e);
654
655 //e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
656 //e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
657 //e.setAttribute(GSXML.NAME_ATT, ADD_DOC_SERVICE);
658 //this.short_service_info.appendChild(e);
659
660 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
661 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
662 e.setAttribute(GSXML.NAME_ATT, MODIFY_METADATA_SERVICE);
663 this.short_service_info.appendChild(e);
664
665 return true;
666 }
667
668 /** returns a response element */
669 protected Element runCommand(Element request, int type)
670 {
671 Document result_doc = XMLConverter.newDOM();
672 // the response to send back
673 String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
674 Element response = result_doc.createElement(GSXML.RESPONSE_ELEM);
675 response.setAttribute(GSXML.FROM_ATT, name);
676 Element status = result_doc.createElement(GSXML.STATUS_ELEM);
677 response.appendChild(status);
678
679 String lang = request.getAttribute(GSXML.LANG_ATT);
680 String request_type = request.getAttribute(GSXML.TYPE_ATT);
681
682 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
683 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
684
685 boolean get_status_only = false;
686 if (request_type.equals(GSXML.REQUEST_TYPE_STATUS))
687 {
688 get_status_only = true;
689 }
690
691 // just check for status messages if that's all that's required
692 if (get_status_only)
693 {
694 String id = (String) params.get(PROCESS_ID_PARAM);
695 status.setAttribute(GSXML.STATUS_PROCESS_ID_ATT, id);
696 GS2PerlListener listener = this.listeners.get(id);
697 if (listener == null)
698 {
699 Text t = result_doc.createTextNode(getTextString("general.process_id_error", lang));
700 status.appendChild(t);
701 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
702 }
703 else
704 {
705 Text t = result_doc.createTextNode(listener.getUpdate());
706 status.appendChild(t);
707 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(listener.getStatus()));
708 // check that we actually should be removing the listener here
709 if (listener.isFinished())
710 { // remove this listener - its job is done
711 this.listeners.remove(id); // not working
712 }
713 }
714 return response;
715
716 }
717
718 // do the actual command
719 String coll_name = null;
720 if (type == GS2PerlConstructor.NEW)
721 {
722 String coll_title = (String) params.get(NEW_COL_TITLE_PARAM);
723 coll_name = createNewCollName(coll_title);
724 }
725 else
726 {
727 coll_name = (String) params.get(COL_PARAM);
728 }
729
730 // makes a paramList of the relevant params
731 Element other_params = extractOtherParams(params, type);
732
733 //create the constructor to do the work
734 GS2PerlConstructor constructor = new GS2PerlConstructor("perl_build");
735 if (!constructor.configure())
736 {
737 Text t = result_doc.createTextNode(getTextString("general.configure_constructor_error", lang));
738 status.appendChild(t);
739 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
740 return response;
741 }
742
743 constructor.setSiteHome(this.site_home);
744 constructor.setCollectionName(coll_name);
745 constructor.setActionType(type);
746 constructor.setProcessParams(other_params);
747 if (type == GS2PerlConstructor.IMPORT)
748 {
749 constructor.setManifestFile(this.site_home + File.separator + "collect" + File.separator + params.get(COL_PARAM) + File.separator + "manifests" + File.separator + "tempManifest.xml");
750 }
751 else if (type == GS2PerlConstructor.MODIFY_METADATA_SERVER) {
752 StringBuffer querystring = new StringBuffer();
753
754 // convert params into a single string again?
755 Set<Map.Entry<String, Serializable>> entries = params.entrySet();
756 Iterator<Map.Entry<String, Serializable>> i = entries.iterator();
757
758 String oid = null;
759
760 while (i.hasNext()) {
761
762 Map.Entry<String, Serializable> entry = i.next();
763 String paramname = entry.getKey();
764 paramname = paramname.replace("s1.", ""); // replaces all
765 // occurrences
766 if (paramname.equals("collection")) {
767 paramname = "c";
768 }
769 if (paramname.equals("d")){
770 oid = (String) entry.getValue();
771 }
772 String paramvalue = (String) entry.getValue();
773
774 querystring.append(paramname + "=" + paramvalue);
775 if (i.hasNext()) {
776 querystring.append("&");
777 }
778 }
779
780 markDocumentInFlatDatabase("R", coll_name, OID.getTop(oid));
781
782 constructor.setQueryString(querystring.toString());
783 }
784
785 GS2PerlListener listener = new GS2PerlListener();
786 constructor.addListener(listener);
787 constructor.start();
788
789 String id = newID();
790 this.listeners.put(id, listener);
791
792 status.setAttribute(GSXML.STATUS_PROCESS_ID_ATT, id);
793 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ACCEPTED));
794 Text t = result_doc.createTextNode(getTextString("general.process_start", lang));
795 status.appendChild(t);
796 return response;
797 }
798
799 //************************
800 // some helper functions
801 //************************
802
803 /** parse the collect directory and return a list of collection names */
804 protected String[] getCollectionList()
805 {
806
807 File collectDir = new File(GSFile.collectDir(this.site_home));
808 if (!collectDir.exists())
809 {
810 logger.error("couldn't find collect dir: " + collectDir.toString());
811 return null;
812 }
813 logger.info("GS2Construct: reading thru directory " + collectDir.getPath() + " to find collections.");
814 File[] contents = collectDir.listFiles();
815 int num_colls = 0;
816 for (int i = 0; i < contents.length; i++)
817 {
818 if (contents[i].isDirectory() && !contents[i].getName().startsWith("CVS"))
819 {
820 num_colls++;
821 }
822 }
823
824 String[] names = new String[num_colls];
825
826 for (int i = 0, j = 0; i < contents.length; i++)
827 {
828 if (contents[i].isDirectory())
829 {
830 String colName = contents[i].getName();
831 if (!colName.startsWith("CVS"))
832 {
833 names[j] = colName;
834 j++;
835 }
836
837 }
838 }
839
840 return names;
841
842 }
843
844 /** ids used for process id */
845 private int current_id = 0;
846
847 private String newID()
848 {
849 current_id++;
850 return Integer.toString(current_id);
851 }
852
853 /** creates a new short name from the collection title */
854 protected String createNewCollName(String coll_title)
855 {
856
857 String base_name = null;
858 // take the first 6 letters
859 if (coll_title.length() < 6)
860 {
861 base_name = coll_title;
862 }
863 else
864 {
865 base_name = coll_title.substring(0, 6);
866 }
867 File coll_dir = new File(GSFile.collectionBaseDir(this.site_home, base_name));
868 if (!coll_dir.exists())
869 { // this name is ok - not used yet
870 return base_name;
871 }
872
873 // now we have to make a new name until we get a good one
874 // try name1, name2 name3 etc
875 int i = 0;
876 while (coll_dir.exists())
877 {
878 i++;
879 coll_dir = new File(GSFile.collectionBaseDir(this.site_home, base_name + Integer.toString(i)));
880 }
881 return base_name + Integer.toString(i);
882
883 }
884
885 /**
886 * takes the params from the request (in the HashMap) and extracts any that
887 * need to be passed to the constructor and puts them into a paramList
888 * element
889 */
890 protected Element extractOtherParams(HashMap<String, Serializable> params, int type)
891 {
892 Document doc = XMLConverter.newDOM();
893 Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
894 if (type == GS2PerlConstructor.NEW)
895 {
896 Element param = doc.createElement(GSXML.PARAM_ELEM);
897 param.setAttribute(GSXML.NAME_ATT, "creator");
898 param.setAttribute(GSXML.VALUE_ATT, (String) params.get(CREATOR_PARAM));
899
900 param_list.appendChild(param);
901 param = doc.createElement(GSXML.PARAM_ELEM);
902 param.setAttribute(GSXML.NAME_ATT, "about");
903 param.setAttribute(GSXML.VALUE_ATT, (String) params.get(NEW_COL_ABOUT_PARAM));
904 param_list.appendChild(param);
905 param = doc.createElement(GSXML.PARAM_ELEM);
906 param.setAttribute(GSXML.NAME_ATT, "title");
907 param.setAttribute(GSXML.VALUE_ATT, (String) params.get(NEW_COL_TITLE_PARAM));
908 param_list.appendChild(param);
909 param = doc.createElement(GSXML.PARAM_ELEM);
910 param.setAttribute(GSXML.NAME_ATT, "buildtype");
911 param.setAttribute(GSXML.VALUE_ATT, (String) params.get(BUILDTYPE_PARAM));
912 param_list.appendChild(param);
913 return param_list;
914 }
915
916 // other ones dont have params yet
917 return null;
918 }
919
920 protected void waitUntilReady(Element request)
921 {
922 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
923 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
924
925 String collection = (String) params.get(COL_PARAM);
926
927 if (checkCollectionIsNotBusy(collection))
928 {
929 return;
930 }
931
932 while (!checkCollectionIsNotBusy(collection)) // When the collection ceases to be busy, we place a hold on it
933 {
934 try
935 {
936 Thread.currentThread().sleep(1000);
937 }
938 catch (Exception ex)
939 {
940 ex.printStackTrace();
941 }
942 }
943 }
944
945 protected void signalReady(Element request)
946 {
947 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
948 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
949
950 String collection = (String) params.get(COL_PARAM);
951
952 collectionOperationMap.remove(collection);
953 }
954
955 // If collection is NOT busy, then reserve it
956 protected synchronized boolean checkCollectionIsNotBusy(String collection)
957 {
958 if (collectionOperationMap.get(collection) == null)
959 {
960 collectionOperationMap.put(collection, true);
961 return true;
962 }
963 return false;
964 }
965
966
967 /** Copy from DebugService.userHasEditPermissions
968 This function checks that the user is logged in and that the user
969 is in the right group to edit the collection */
970 protected boolean userHasCollectionEditPermissions(Element request) {
971 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
972 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
973 String collection = (String) params.get(COL_PARAM); // could be null on newcoll operation
974
975 UserContext context = new UserContext(request);
976 if(collection == null) {
977 return !context.getUsername().equals("");
978 }
979 for (String group : context.getGroups()) {
980 // administrator always has permission
981 if (group.equals("administrator")) {
982 return true;
983 }
984 // all-collections-editor can edit any collection
985 if (!collection.equals("")) {
986 if (group.equals("all-collections-editor")) {
987 return true;
988 }
989 if (group.equals(collection+"-collection-editor")) {
990 return true;
991 }
992 }
993 }
994 // haven't found a group with edit permissions
995 return false;
996
997 }
998 protected void markDocumentInFlatDatabase(String mark, String collection, String oid) {
999
1000 Document msg_doc = XMLConverter.newDOM();
1001 Element message = msg_doc.createElement(GSXML.MESSAGE_ELEM);
1002 UserContext userContext = new UserContext();
1003 Element query_request = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_DESCRIBE , collection, userContext);
1004 message.appendChild(query_request);
1005 Element result = (Element) this.router.process(message);
1006 Element resp_elem = (Element) GSXML.getChildByTagName(result, GSXML.RESPONSE_ELEM);
1007 Element coll_elem = (Element) GSXML.getChildByTagName(resp_elem, GSXML.COLLECTION_ELEM);
1008 String dbtype = coll_elem.getAttribute(GSXML.DB_TYPE_ATT);
1009
1010 SimpleCollectionDatabase coll_db = new SimpleCollectionDatabase(dbtype);
1011 if (!coll_db.databaseOK())
1012 {
1013 logger.error("Couldn't create the collection database of type " + dbtype);
1014 return;
1015 }
1016
1017 // Open database for reading. It may not exist if collection is pre-built without archives (such as demo collections)
1018 String coll_db_file = GSFile.archivesDatabaseFile(this.site_home, collection, dbtype);
1019 if (!coll_db.openDatabase(coll_db_file, SimpleCollectionDatabase.READ))
1020 {
1021 logger.error("Could not open collection archives database. Database doesn't exist or else somebody's already using it?");
1022 return;
1023 }
1024 // now we know we have an archives folder
1025 String old_value = coll_db.getValue(oid);
1026 String new_value = old_value.replace("<index-status>B", "<index-status>" + mark);
1027 // Close database for reading
1028 coll_db.closeDatabase();
1029 if (!coll_db.openDatabase(coll_db_file, SimpleCollectionDatabase.WRITE))
1030 {
1031 logger.error("Could not open collection archives database. Somebody already using this database!");
1032 return;
1033 }
1034 coll_db.setValue(oid, new_value);
1035 coll_db.closeDatabase();
1036
1037 }
1038}
Note: See TracBrowser for help on using the repository browser.