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

Last change on this file since 29947 was 29947, checked in by ak19, 9 years ago

First of two commits to fix rebuilding a collection using the online editor on Windows. Resolves the file lock problem. The java code works with changes in activate.pl. activate.pl is passed a flag so that it no longer de-activates and re-activates the collection itself, but just concerns itself with moving building to index. The GS2Construct java code now de-activates the collection prior to calling activate.pl and then re-activates it afterward. In the way it was done before, activate.pl used to handle de- and re-activating the collection. But when it was launched from the server java code, the java VM would exit having left a copy of the file handles to the perl process when forking the process for activate.pl. The perl code could not move building to index since the file handles had locks (6 of them) on the index/text/collection.gdb. Changes have been made to GS2PerlConstructor too, so that it more cleanly closes all the pipes of a process, that the process itself may thereby exit cleanly. Not yet able to move this properly into its own classes since the StreamGobbler classes in GLI are not quite suited but were customised for FormatConverter.

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