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

Last change on this file since 30617 was 30617, checked in by ak19, 8 years ago

Bugfix to oversight: web document editor didn't reindex on removing metadata, only on setting it. This is because there wasn't corresponding Service on Java side to handle removing metadata. Now the Java code has a ModifyMetdata service and this is connected to both the set- and remove-metadata functions in the javascript. For now, the javascript metadataserver calls have been made synchronous by setting the async ajax-jquery property to false. Need to test whether the code still works asynchronous as before.

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