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

Last change on this file since 30516 was 30516, checked in by Georgiy Litvinov, 8 years ago

Moved to incremental rebuild in webeditor

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