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

Last change on this file since 30704 was 30704, checked in by kjdon, 8 years ago

use the top OID for marking doc in database - only top level ids are in there, not sections

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