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

Last change on this file since 33051 was 33051, checked in by ak19, 5 years ago

Tweak to Friday's commit to URL encode param values: can't use nio.StandardCharsets because our release kit JDK is too old to recognise this import, so hardcoding UTF-8 charset name which is what people used to do in the past. Also updated comments. And removed some unnecessary commented out code from GS2PerlConstructor.java

  • Property svn:keywords set to Author Date Id Revision
File size: 45.4 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.io.UnsupportedEncodingException;
26import java.net.URLEncoder;
27import java.util.Collections;
28import java.util.Iterator;
29import java.util.Map.Entry;
30import java.util.HashMap;
31import java.util.Map;
32import java.util.Set;
33import java.util.regex.Matcher;
34import java.util.regex.Pattern;
35
36import org.apache.log4j.Logger;
37import org.greenstone.gsdl3.build.GS2PerlConstructor;
38import org.greenstone.gsdl3.build.GS2PerlListener;
39import org.greenstone.gsdl3.util.GSFile;
40import org.greenstone.gsdl3.util.GSParams;
41import org.greenstone.gsdl3.util.GSPath;
42import org.greenstone.gsdl3.util.GSStatus;
43import org.greenstone.gsdl3.util.GSXML;
44import org.greenstone.gsdl3.util.OID;
45import org.greenstone.gsdl3.util.SimpleCollectionDatabase;
46import org.greenstone.gsdl3.util.UserContext;
47import org.greenstone.gsdl3.util.XMLConverter;
48
49// https://developer.android.com/reference/org/json/JSONObject.html
50// https://developer.android.com/reference/org/json/JSONArray.html
51import org.json.JSONArray;
52import org.json.JSONException;
53import org.json.JSONObject;
54
55
56import org.w3c.dom.Document;
57import org.w3c.dom.Element;
58import org.w3c.dom.Node;
59import org.w3c.dom.Text;
60
61/**
62 * A Services class for building collections provides a wrapper around the old
63 * perl scripts
64 *
65 * @author Katherine Don
66 */
67public class GS2Construct extends ServiceRack
68{
69
70 static Logger logger = Logger.getLogger(org.greenstone.gsdl3.service.GS2Construct.class.getName());
71
72 // default error message
73 private static final String NO_PERMISSIONS_ERROR = "This user does not have the required permissions to perform this action.";
74
75 // services offered
76 private static final String NEW_SERVICE = "NewCollection";
77 private static final String ADD_DOC_SERVICE = "AddDocument";
78 private static final String IMPORT_SERVICE = "ImportCollection";
79 private static final String BUILD_SERVICE = "BuildCollection";
80 private static final String ACTIVATE_SERVICE = "ActivateCollection";
81 private static final String BUILD_AND_ACTIVATE_SERVICE = "BuildAndActivateCollection";
82 private static final String DELETE_SERVICE = "DeleteCollection";
83 private static final String RELOAD_SERVICE = "ReloadCollection";
84 private static final String MODIFY_METADATA_SERVICE = "ModifyMetadata"; // set or remove metadata
85
86
87 // params used
88 private static final String COL_PARAM = "collection";
89 private static final String NEW_COL_TITLE_PARAM = "collTitle";
90 private static final String NEW_COL_ABOUT_PARAM = "collAbout";
91 private static final String CREATOR_PARAM = "creator";
92 private static final String NEW_FILE_PARAM = "newfile";
93 private static final String PROCESS_ID_PARAM = GSParams.PROCESS_ID;
94 private static final String BUILDTYPE_PARAM = "buildType";
95 private static final String BUILDTYPE_MG = "mg";
96 private static final String BUILDTYPE_MGPP = "mgpp";
97
98 protected static String DATABASE_TYPE = null;
99 protected SimpleCollectionDatabase coll_db = null;
100
101 // the list of the collections - store between some method calls
102 private String[] collection_list = null;
103
104 // set of listeners for any construction commands
105 protected Map<String, GS2PerlListener> listeners = null;
106 protected HashMap<String, Boolean> collectionOperationMap = new HashMap<String, Boolean>();
107
108 public GS2Construct()
109 {
110 this.listeners = Collections.synchronizedMap(new HashMap<String, GS2PerlListener>());
111 }
112
113 // in configure we set up any params that should be saved to the session. At this stage, assuming none should be saved.
114
115 /** returns a specific service description */
116 protected Element getServiceDescription(Document doc, String service, String lang, String subset)
117 {
118
119 Element description = doc.createElement(GSXML.SERVICE_ELEM);
120 description.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
121 description.setAttribute(GSXML.NAME_ATT, service);
122 if (subset == null || subset.equals(GSXML.DISPLAY_TEXT_ELEM + GSXML.LIST_MODIFIER))
123 {
124 description.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_NAME, getTextString(service + ".name", lang)));
125 description.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_DESCRIPTION, getTextString(service + ".description", lang)));
126 description.appendChild(GSXML.createDisplayTextElement(doc, GSXML.DISPLAY_TEXT_SUBMIT, getTextString(service + ".submit", lang)));
127 }
128 if (subset == null || subset.equals(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER))
129 {
130 Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
131 description.appendChild(param_list);
132
133 if (service.equals(NEW_SERVICE))
134 {
135
136 Element param = GSXML.createParameterDescription(doc, NEW_COL_TITLE_PARAM, getTextString("param." + NEW_COL_TITLE_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
137 param_list.appendChild(param);
138 param = GSXML.createParameterDescription(doc, CREATOR_PARAM, getTextString("param." + CREATOR_PARAM, lang), GSXML.PARAM_TYPE_STRING, null, null, null);
139 param_list.appendChild(param);
140 param = GSXML.createParameterDescription(doc, NEW_COL_ABOUT_PARAM, getTextString("param." + NEW_COL_ABOUT_PARAM, lang), GSXML.PARAM_TYPE_TEXT, null, null, null);
141 param_list.appendChild(param);
142 String[] types = { BUILDTYPE_MGPP, BUILDTYPE_MG };
143 String[] type_texts = { getTextString("param." + BUILDTYPE_PARAM + "." + BUILDTYPE_MGPP, lang), getTextString("param." + BUILDTYPE_PARAM + "." + BUILDTYPE_MG, lang) };
144
145 param = GSXML.createParameterDescription(doc, BUILDTYPE_PARAM, getTextString("param." + BUILDTYPE_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, BUILDTYPE_MGPP, types, type_texts);
146 param_list.appendChild(param);
147 }
148 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))
149 {
150
151 this.collection_list = getCollectionList();
152 Element param = GSXML.createParameterDescription(doc, COL_PARAM, getTextString("param." + COL_PARAM, lang), GSXML.PARAM_TYPE_ENUM_SINGLE, null, this.collection_list, this.collection_list);
153 param_list.appendChild(param);
154 }
155 else
156 {
157 // invalid service name
158 return null;
159 }
160 }
161 return description;
162 }
163
164 // each service must have a method "process<New service name>"
165
166 protected Element processNewCollection(Element request)
167 {
168 if (!userHasCollectionEditPermissions(request)) {
169 return errorResponse("processNewCollection", NO_PERMISSIONS_ERROR);
170 }
171 return runCommand(request, GS2PerlConstructor.NEW);
172 }
173
174 /** TODO:implement this */
175 protected Element processAddDocument(Element request)
176 {
177 if (!userHasCollectionEditPermissions(request)) {
178 return errorResponse("processAddDocument", NO_PERMISSIONS_ERROR);
179 }
180
181 Document result_doc = XMLConverter.newDOM();
182 // decode the file name, add it to the import directory
183 String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
184 Element response = result_doc.createElement(GSXML.RESPONSE_ELEM);
185 response.setAttribute(GSXML.FROM_ATT, name);
186 Element status = result_doc.createElement(GSXML.STATUS_ELEM);
187 response.appendChild(status);
188 //String lang = request.getAttribute(GSXML.LANG_ATT);
189 //String request_type = request.getAttribute(GSXML.TYPE_ATT);
190 Text t = result_doc.createTextNode("AddDocument: not implemented yet");
191 status.appendChild(t);
192 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
193 return response;
194 }
195
196 protected Element processBuildAndActivateCollection(Element request)
197 {
198 // check permissions
199 if (!userHasCollectionEditPermissions(request)) {
200 return errorResponse("processBuildAndActivateCollection", NO_PERMISSIONS_ERROR);
201 }
202
203
204 waitUntilReady(request);
205 Element buildResponse = processBuildCollection(request);
206 if (buildResponse.getElementsByTagName(GSXML.ERROR_ELEM).getLength() > 0)
207 {
208 signalReady(request);
209 return buildResponse;
210 }
211
212 Element statusElem = (Element) buildResponse.getElementsByTagName(GSXML.STATUS_ELEM).item(0);
213 String id = statusElem.getAttribute("pid");
214
215 GS2PerlListener currentListener = this.listeners.get(id);
216 int statusCode = currentListener.getStatus();
217 while (!GSStatus.isCompleted(statusCode))
218 {
219 // wait for the process, and keep checking the status code
220 // there is probably a better way to do this.
221 try
222 {
223 Thread.currentThread().sleep(100);
224 }
225 catch (Exception e)
226 { // ignore
227 }
228 statusCode = currentListener.getStatus();
229 }
230
231 Element activateResponse = processActivateCollection(request);
232 signalReady(request);
233 return activateResponse;
234 }
235
236 protected Element processImportCollection(Element request)
237 {
238 if (!userHasCollectionEditPermissions(request)) {
239 return errorResponse("processImportCollection", NO_PERMISSIONS_ERROR);
240 }
241
242 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
243 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
244
245 if (params == null)
246 {
247 return null;
248 }
249
250 //If we have been requested to only build certain documents then we need to create a manifest file
251 String documentsParam = (String) params.get("documents");
252 if (documentsParam != null && !documentsParam.equals(""))
253 {
254 String s = File.separator;
255 String manifestFolderPath = this.site_home + s + "collect" + s + params.get(COL_PARAM) + s + "manifests";
256 String manifestFilePath = manifestFolderPath + File.separator + "tempManifest.xml";
257
258 File manifestFolderFile = new File(manifestFolderPath);
259 if (!manifestFolderFile.exists())
260 {
261 manifestFolderFile.mkdirs();
262 }
263
264 File manifestFile = new File(manifestFilePath);
265 if (!manifestFile.exists())
266 {
267 try
268 {
269 manifestFile.createNewFile();
270 }
271 catch (Exception ex)
272 {
273 ex.printStackTrace();
274 return null; //Probably should return an actual error
275 }
276 }
277 String[] docList = documentsParam.split(",");
278
279 try
280 {
281 BufferedWriter bw = new BufferedWriter(new FileWriter(manifestFile));
282 bw.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
283 bw.write("<Manifest>\n");
284 bw.write(" <Index>\n");
285 for (int j = 0; j < docList.length; j++)
286 {
287 bw.write(" <Filename>" + docList[j] + "</Filename>\n");
288 }
289 bw.write(" </Index>\n");
290 bw.write("</Manifest>\n");
291 bw.close();
292 }
293 catch (Exception ex)
294 {
295 ex.printStackTrace();
296 return null; //Probably should return an actual error
297 }
298 }
299
300 return runCommand(request, GS2PerlConstructor.IMPORT);
301 }
302
303 protected Element processBuildCollection(Element request)
304 {
305 if (!userHasCollectionEditPermissions(request)) {
306 return errorResponse("processBuildCollection", NO_PERMISSIONS_ERROR);
307 }
308
309 return runCommand(request, GS2PerlConstructor.BUILD);
310 }
311
312 protected Element processModifyMetadata(Element request)
313 {
314
315 // There are two types of operations whereby metadata gets modified:
316 // - document including document-meta editing: user needs document editing powers
317 // - adding user comments: user just needs an account and needs to be logged in
318 // We handle both cases in this service.
319
320 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
321 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
322
323 String metaserver_command = (String) params.get("a"); // e.g. set-archives-metadata or set-metadata-array
324 boolean supportsSettingMultipleMeta = metaserver_command.equals("set-metadata-array") ? true : false;
325 String json_str = (String) params.get("json"); // String or null if no param named "json"
326
327 String[] docids = null;
328
329
330 if (userHasCollectionEditPermissions(request, params)) { // means user can modify ANY metadata
331
332 // if dealing with an array of meta, then parse out the docids from the json
333 if(supportsSettingMultipleMeta) {
334 docids = getDocIdsWithOptFilter(json_str, null);
335 } // else set-meta operation on single metadata field of single doc,
336 // and docid will be obtained in runCommand() where it's needed
337
338 } else {
339 // check if user logged in
340 // shouldn't be able to do any meta modification if not logged in
341
342 UserContext context = new UserContext(request);
343 if (context.getUsername().equals("")) {
344
345 return errorResponse("processModifyMetadata", "Cannot modify any metadata when not logged in.");
346 } else { // User is logged in at least, see whether they can do any restricted set-meta ops
347 // that are open to regular users (those without permissions to edit this collection).
348 // For now, there's only one restricted set-meta operation open to any logged in users
349 // who don't otherwise have editing permissions for the collection: adding user comments.
350
351 boolean isAddingUserComments = false;
352 Pattern allowedMetaFieldsPattern = Pattern.compile("^(username|usertimestamp|usercomment)$");
353 if(supportsSettingMultipleMeta) {
354
355 docids = getDocIdsWithOptFilter(json_str, allowedMetaFieldsPattern);
356 if(docids != null) {
357 isAddingUserComments = true;
358 }
359 } else {
360 String metaname = (String) params.get("metaname");
361 if(isAllowedToSetMeta(metaname, allowedMetaFieldsPattern)) {
362 isAddingUserComments = true;
363 }
364 }
365
366 if(!isAddingUserComments) { // logged in user is attempting to set meta outside restricted set,
367 // In this case, they're attempting to set meta not related to user comments
368 return errorResponse("processModifyMetadata", NO_PERMISSIONS_ERROR);
369 }
370 }
371 }
372
373 // wait until we can reserve the collection for processing
374 waitUntilReady(request);
375
376
377 // process
378 Element response = runCommand(request, GS2PerlConstructor.MODIFY_METADATA_SERVER, docids);
379
380 if (response.getElementsByTagName(GSXML.ERROR_ELEM).getLength() <= 0) // if no errors, wait for process to finish
381 {
382 Element statusElem = (Element) response.getElementsByTagName(GSXML.STATUS_ELEM).item(0);
383 String id = statusElem.getAttribute("pid");
384
385 GS2PerlListener currentListener = this.listeners.get(id);
386 int statusCode = currentListener.getStatus();
387 while (!GSStatus.isCompleted(statusCode))
388 {
389 // wait for the process, and keep checking the status code
390 // there is probably a better way to do this.
391 try
392 {
393 Thread.currentThread().sleep(100);
394 }
395 catch (Exception e)
396 { // ignore
397 }
398 statusCode = currentListener.getStatus();
399 }
400 }
401
402 Element statusElem = (Element) response.getElementsByTagName(GSXML.STATUS_ELEM).item(0);
403 String statusString = GSXML.getNodeText(statusElem);
404 statusString += " and monitored until done.";
405 // check for errors
406 int status_code = Integer.parseInt(statusElem.getAttribute(GSXML.STATUS_ERROR_CODE_ATT));
407 if (GSStatus.isError(status_code)) {
408 logger.info("Got error status code: " + status_code);
409 statusString += "But got error status code: " + status_code;
410 } else { // check for Construction event errors
411 String id = statusElem.getAttribute("pid");
412 GS2PerlListener currentListener = this.listeners.get(id);
413 status_code = currentListener.getStatus();
414 if (GSStatus.isError(status_code))
415 {
416 logger.info("xxxx Got construction event error. Error status code: " + status_code);
417 statusString += "But got construction event error, status code: " + status_code;
418 // add the rest of the messages to the statusElem node
419 statusString += "\n" + currentListener.getUpdate();
420 statusElem.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(currentListener.getStatus()));
421 }
422 }
423 // can finally set statusString
424 GSXML.setNodeText(statusElem, statusString);
425
426 // release hold on collection
427 signalReady(request);
428 return response;
429
430 }
431
432 protected Element processActivateCollection(Element request)
433 {
434
435 if (!userHasCollectionEditPermissions(request)) {
436 return errorResponse("processActivateCollection", NO_PERMISSIONS_ERROR);
437 }
438
439 // this activates the collection on disk. but now we need to tell
440 // the MR about it. but we have to wait until the process is finished.
441 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
442 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
443 String coll_name = (String) params.get(COL_PARAM);
444 String lang = request.getAttribute(GSXML.LANG_ATT);
445
446 UserContext userContext = new UserContext(request);
447 String request_type = request.getAttribute(GSXML.TYPE_ATT);
448
449 // now we de-activate the collection before running activate.pl, and then re-activate at end
450 // So activate.pl only does the moving, no activation. This way will prevent java from launching
451 // perl, exiting and then leaving dangling file handles (on index/text/col.gdb) in perl.
452 if (!request_type.equals(GSXML.REQUEST_TYPE_STATUS)) {
453 systemRequest("delete", coll_name, null, userContext); // deactivate collection
454 }
455
456 Element response = runCommand(request, GS2PerlConstructor.ACTIVATE); // if request is for STATUS, then this won't run activate.pl
457
458 Element status = (Element) GSXML.getChildByTagName(response, GSXML.STATUS_ELEM);
459
460 // check for finished
461 int status_code = Integer.parseInt(status.getAttribute(GSXML.STATUS_ERROR_CODE_ATT));
462 if (GSStatus.isCompleted(status_code) && GSStatus.isError(status_code))
463 {
464 // we shouldn't carry out the next bit, just return the response
465 return response;
466 }
467 String id = status.getAttribute(GSXML.STATUS_PROCESS_ID_ATT);
468 GS2PerlListener listener = this.listeners.get(id);
469 if (listener == null)
470 {
471 logger.error("somethings gone wrong, couldn't find the listener");
472 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
473 return response;
474 }
475
476 while (!GSStatus.isCompleted(status_code))
477 {
478 // wait for the process, and keep checking the status code
479 // there is probably a better way to do this.
480 try
481 {
482 Thread.currentThread().sleep(100);
483 }
484 catch (Exception e)
485 { // ignore
486 }
487 status_code = listener.getStatus();
488 }
489
490 // add the rest of the messages to the status node
491 Text t = status.getOwnerDocument().createTextNode("\n" + listener.getUpdate());
492 status.appendChild(t);
493 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(listener.getStatus()));
494 if (GSStatus.isError(status_code))
495 {
496 return response; // without doing the next bit
497 }
498
499 t = status.getOwnerDocument().createTextNode("\n");
500 status.appendChild(t);
501 // once have got here, we assume
502 // the first bit proceeded successfully, now reload the collection (sends a collection reactivation request)
503 systemRequest("reload", coll_name, status, userContext); // this will append more messages to the status, and overwrite the error code att
504 return response;
505
506 }
507
508 protected Element processDeleteCollection(Element request)
509 {
510 if (!userHasCollectionEditPermissions(request)) {
511 return errorResponse("processDeleteCollection", NO_PERMISSIONS_ERROR);
512 }
513
514 Document result_doc = XMLConverter.newDOM();
515 // the response to send back
516 String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
517 Element response = result_doc.createElement(GSXML.RESPONSE_ELEM);
518 response.setAttribute(GSXML.FROM_ATT, name);
519 Element status = result_doc.createElement(GSXML.STATUS_ELEM);
520 response.appendChild(status);
521 Text t = null; // the text node for the error/success message
522 String lang = request.getAttribute(GSXML.LANG_ATT);
523 String request_type = request.getAttribute(GSXML.TYPE_ATT);
524
525 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
526 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
527
528 boolean get_status_only = false;
529 if (request_type.equals(GSXML.REQUEST_TYPE_STATUS))
530 {
531 get_status_only = true;
532 }
533 if (get_status_only)
534 {
535 // 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
536 logger.error("had a status request for delete - this shouldn't happen!!");
537 //t = result_doc.createTextNode("");
538 //status.appendChild(t);
539 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
540 return response;
541 }
542 String coll_name = (String) params.get(COL_PARAM);
543 String[] args = { coll_name };
544 File coll_dir = new File(GSFile.collectionBaseDir(this.site_home, coll_name));
545 // check that the coll is there in the first place
546 if (!coll_dir.exists())
547 {
548 t = result_doc.createTextNode(getTextString("delete.exists_error", lang, args));
549 status.appendChild(t);
550 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
551 return response;
552 }
553
554 // try to delete the directory
555 if (!GSFile.deleteFile(coll_dir))
556 {
557 t = result_doc.createTextNode(getTextString("delete.delete_error", lang, args));
558 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
559 status.appendChild(t);
560 return response;
561 }
562
563 UserContext userContext = new UserContext(request);
564
565 systemRequest("delete", coll_name, status, userContext);
566 return response;
567 }
568
569 protected Element processReloadCollection(Element request)
570 {
571 if (!userHasCollectionEditPermissions(request)) {
572 return errorResponse("processReloadCollection", NO_PERMISSIONS_ERROR);
573 }
574
575 Document result_doc = XMLConverter.newDOM();
576 // the response to send back
577 String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
578 Element response = result_doc.createElement(GSXML.RESPONSE_ELEM);
579 response.setAttribute(GSXML.FROM_ATT, name);
580 Element status = result_doc.createElement(GSXML.STATUS_ELEM);
581 response.appendChild(status);
582 Text t = null; // the text node for the error/success message
583
584 String lang = request.getAttribute(GSXML.LANG_ATT);
585 String request_type = request.getAttribute(GSXML.TYPE_ATT);
586
587 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
588 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
589
590 boolean get_status_only = false;
591 if (request_type.equals(GSXML.REQUEST_TYPE_STATUS))
592 {
593 get_status_only = true;
594 }
595 if (get_status_only)
596 {
597 // reload is synchronous - this makes no sense
598 logger.error("had a status request for reload - this shouldn't happen!!");
599 //t = result_doc.createTextNode("");
600 //status.appendChild(t);
601 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
602 return response;
603 }
604
605 String coll_name = (String) params.get(COL_PARAM);
606
607 UserContext userContext = new UserContext(request);
608
609 systemRequest("reload", coll_name, status, userContext);
610 return response;
611
612 }
613
614 /**
615 * send a configure request to the message router action name should be
616 * "delete" or "reload" response will be put into the status element
617 */
618 protected void systemRequest(String operation, String coll_name, Element status, UserContext userContext)
619 {
620 // send the request to the MR
621 Document doc = XMLConverter.newDOM();
622 Element message = doc.createElement(GSXML.MESSAGE_ELEM);
623 Element request = GSXML.createBasicRequest(doc, GSXML.REQUEST_TYPE_SYSTEM, "", userContext);
624 message.appendChild(request);
625 Element command = doc.createElement(GSXML.SYSTEM_ELEM);
626 request.appendChild(command);
627 command.setAttribute(GSXML.SYSTEM_MODULE_TYPE_ATT, GSXML.COLLECTION_ELEM);
628 command.setAttribute(GSXML.SYSTEM_MODULE_NAME_ATT, coll_name);
629
630 if (operation.equals("delete"))
631 {
632 command.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_DEACTIVATE);
633 }
634 else if (operation.equals("reload"))
635 {
636 command.setAttribute(GSXML.TYPE_ATT, GSXML.SYSTEM_TYPE_ACTIVATE);
637 }
638 else
639 {
640 logger.error("invalid action name passed to systemRequest:" + operation);
641 return;
642 }
643 request.appendChild(command);
644 Node response = this.router.process(message); // at the moment, get no info in response so ignore it
645 Text t;
646 String[] args = { coll_name };
647
648 if (status != null)
649 {
650 if (response == null)
651 {
652 t = status.getOwnerDocument().createTextNode(getTextString(operation + ".configure_error", userContext.getLanguage(), args));
653 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
654 status.appendChild(t);
655 return;
656 }
657
658 // if we got here, we have succeeded!
659 t = status.getOwnerDocument().createTextNode(getTextString(operation + ".success", userContext.getLanguage(), args));
660 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.SUCCESS));
661 status.appendChild(t);
662 }
663 }
664
665 /**
666 * configure the service module for now, all services have type=build - need
667 * to think about this
668 */
669 public boolean configure(Element info, Element extra_info)
670 {
671 if (!super.configure(info, extra_info))
672 {
673 return false;
674 }
675
676 logger.info("configuring GS2Construct");
677
678 Element e = null;
679 // hard code in the services for now
680
681 // set up short_service_info_ - for now just has name and type
682
683 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
684 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
685 e.setAttribute(GSXML.NAME_ATT, NEW_SERVICE);
686 this.short_service_info.appendChild(e);
687
688 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
689 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
690 e.setAttribute(GSXML.NAME_ATT, IMPORT_SERVICE);
691 this.short_service_info.appendChild(e);
692
693 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
694 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
695 e.setAttribute(GSXML.NAME_ATT, BUILD_SERVICE);
696 this.short_service_info.appendChild(e);
697
698 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
699 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
700 e.setAttribute(GSXML.NAME_ATT, ACTIVATE_SERVICE);
701 this.short_service_info.appendChild(e);
702
703 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
704 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
705 e.setAttribute(GSXML.NAME_ATT, BUILD_AND_ACTIVATE_SERVICE);
706 this.short_service_info.appendChild(e);
707
708 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
709 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
710 e.setAttribute(GSXML.NAME_ATT, DELETE_SERVICE);
711 this.short_service_info.appendChild(e);
712
713 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
714 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
715 e.setAttribute(GSXML.NAME_ATT, RELOAD_SERVICE);
716 this.short_service_info.appendChild(e);
717
718 //e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
719 //e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
720 //e.setAttribute(GSXML.NAME_ATT, ADD_DOC_SERVICE);
721 //this.short_service_info.appendChild(e);
722
723 e = this.desc_doc.createElement(GSXML.SERVICE_ELEM);
724 e.setAttribute(GSXML.TYPE_ATT, GSXML.SERVICE_TYPE_PROCESS);
725 e.setAttribute(GSXML.NAME_ATT, MODIFY_METADATA_SERVICE);
726 this.short_service_info.appendChild(e);
727
728 return true;
729 }
730
731 protected Element runCommand(Element request, int type) {
732 return runCommand(request, type, null);
733 }
734
735 /** returns a response element */
736 protected Element runCommand(Element request, int type, String[] docids)
737 {
738 Document result_doc = XMLConverter.newDOM();
739 // the response to send back
740 String name = GSPath.getFirstLink(request.getAttribute(GSXML.TO_ATT));
741 Element response = result_doc.createElement(GSXML.RESPONSE_ELEM);
742 response.setAttribute(GSXML.FROM_ATT, name);
743 Element status = result_doc.createElement(GSXML.STATUS_ELEM);
744 response.appendChild(status);
745
746 String lang = request.getAttribute(GSXML.LANG_ATT);
747 String request_type = request.getAttribute(GSXML.TYPE_ATT);
748
749 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
750
751 //GSXML.elementToLogAsString("### Extracted param_list: ", param_list, true);
752 //GSXML.elementToLogAsUnicodeDebugString("### DEBUG Extracted param_list: ", param_list, true);
753
754 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
755
756 boolean get_status_only = false;
757 if (request_type.equals(GSXML.REQUEST_TYPE_STATUS))
758 {
759 get_status_only = true;
760 }
761
762 // just check for status messages if that's all that's required
763 if (get_status_only)
764 {
765 String id = (String) params.get(PROCESS_ID_PARAM);
766 status.setAttribute(GSXML.STATUS_PROCESS_ID_ATT, id);
767 GS2PerlListener listener = this.listeners.get(id);
768 if (listener == null)
769 {
770 Text t = result_doc.createTextNode(getTextString("general.process_id_error", lang));
771 status.appendChild(t);
772 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
773 }
774 else
775 {
776 Text t = result_doc.createTextNode(listener.getUpdate());
777 status.appendChild(t);
778 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(listener.getStatus()));
779 // check that we actually should be removing the listener here
780 if (listener.isFinished())
781 { // remove this listener - its job is done
782 this.listeners.remove(id); // not working
783 }
784 }
785 return response;
786
787 }
788
789 // do the actual command
790 String coll_name = null;
791 if (type == GS2PerlConstructor.NEW)
792 {
793 String coll_title = (String) params.get(NEW_COL_TITLE_PARAM);
794 coll_name = createNewCollName(coll_title);
795 }
796 else
797 {
798 coll_name = (String) params.get(COL_PARAM);
799 }
800
801 // makes a paramList of the relevant params
802 Element other_params = extractOtherParams(params, type);
803
804 //create the constructor to do the work
805 GS2PerlConstructor constructor = new GS2PerlConstructor("perl_build");
806 if (!constructor.configure())
807 {
808 Text t = result_doc.createTextNode(getTextString("general.configure_constructor_error", lang));
809 status.appendChild(t);
810 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
811 return response;
812 }
813
814 constructor.setSiteHome(this.site_home);
815 constructor.setLibraryName(this.library_name);
816 constructor.setCollectionName(coll_name);
817 constructor.setActionType(type);
818 constructor.setProcessParams(other_params);
819 if (type == GS2PerlConstructor.IMPORT)
820 {
821 constructor.setManifestFile(this.site_home + File.separator + "collect" + File.separator + params.get(COL_PARAM) + File.separator + "manifests" + File.separator + "tempManifest.xml");
822 }
823 else if (type == GS2PerlConstructor.MODIFY_METADATA_SERVER) {
824 StringBuffer querystring = new StringBuffer();
825
826 // convert params into a single string again?
827 Set<Map.Entry<String, Serializable>> entries = params.entrySet();
828 Iterator<Map.Entry<String, Serializable>> i = entries.iterator();
829
830 String oid = null;
831
832 while (i.hasNext()) {
833
834 Map.Entry<String, Serializable> entry = i.next();
835 String paramname = entry.getKey();
836 paramname = paramname.replace("s1.", ""); // replaces all occurrences
837 if (paramname.equals("collection")) {
838 paramname = "c";
839 }
840 if (paramname.equals("d")){
841 oid = (String) entry.getValue();
842 }
843
844 String paramvalue = (String) entry.getValue();
845
846 // This will be used to set QUERY_STRING in the environment, see build/GS2PerlConstructor.java
847 // Need to also ensure that special characters in param values won't get clobbered on Windows by perl/CGI.pm,
848 // see also https://www.nntp.perl.org/group/perl.perl5.porters/2016/10/msg240120.html
849 // Therefore URL encode CGI param values in the query_string, as at https://stackoverflow.com/questions/10786042/java-url-encoding-of-query-string-parameters
850
851 // perl/CGI.pm doesn't like us URL encoding the entire QUERY_STRING such as the equal sign between each paramName and paramValue.
852 // So we URL encode each paramValue separately, which is done in GS2Construct.java::runCommand()
853 querystring.append(paramname + "=" + urlEncodeValue(paramname, paramvalue));
854 if (i.hasNext()) {
855 querystring.append("&");
856 }
857 }
858
859 if(oid != null) { // if we have only one oid
860 markDocumentInFlatDatabase("R", coll_name, OID.getTop(oid));
861 } else if (docids != null) { // check if we are dealing with many doc ids, as cold in theory happen when set-metadata-array is called
862
863 for(int index = 0; index < docids.length; index++) {
864 String docid = docids[index];
865 markDocumentInFlatDatabase("R", coll_name, OID.getTop(docid));
866 }
867 } else {
868 String msg = getTextString("general.no_valid_docid_error", lang);
869 logger.error("*** " + msg);
870 Text t = result_doc.createTextNode(msg);
871 status.appendChild(t);
872 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ERROR));
873 return response;
874 }
875
876 constructor.setQueryString(querystring.toString());
877 }
878
879 GS2PerlListener listener = new GS2PerlListener();
880 constructor.addListener(listener);
881 constructor.start();
882
883 String id = newID();
884 this.listeners.put(id, listener);
885
886 status.setAttribute(GSXML.STATUS_PROCESS_ID_ATT, id);
887 status.setAttribute(GSXML.STATUS_ERROR_CODE_ATT, Integer.toString(GSStatus.ACCEPTED));
888 Text t = result_doc.createTextNode(getTextString("general.process_start", lang));
889 status.appendChild(t);
890 return response;
891 }
892
893 //************************
894 // some helper functions
895 //************************
896
897 private String urlEncodeValue(String paramName, String paramVal) {
898 String oldParamVal = paramVal;
899 try{
900 paramVal = URLEncoder.encode(paramVal, "UTF-8");
901 // Better way as per https://stackoverflow.com/questions/10786042/java-url-encoding-of-query-string-parameters
902 // but our release kits' Java is too old for importing java.nio.charset.StandardCharsets
903 //paramVal = URLEncoder.encode(paramVal, StandardCharsets.UTF_8.name());
904 } catch(UnsupportedEncodingException uee) {
905 logger.warn("**** Unable to encode query_string param " + paramName + " in UTF-8, so attempting to continue with its unencoded value."); // don't output param value to log, in case of sensitive data?
906 paramVal = oldParamVal;
907 }
908 return paramVal;
909 }
910
911 /** parse the collect directory and return a list of collection names */
912 protected String[] getCollectionList()
913 {
914
915 File collectDir = new File(GSFile.collectDir(this.site_home));
916 if (!collectDir.exists())
917 {
918 logger.error("couldn't find collect dir: " + collectDir.toString());
919 return null;
920 }
921 logger.info("GS2Construct: reading thru directory " + collectDir.getPath() + " to find collections.");
922 File[] contents = collectDir.listFiles();
923 int num_colls = 0;
924 for (int i = 0; i < contents.length; i++)
925 {
926 if (contents[i].isDirectory() && !contents[i].getName().startsWith("CVS"))
927 {
928 num_colls++;
929 }
930 }
931
932 String[] names = new String[num_colls];
933
934 for (int i = 0, j = 0; i < contents.length; i++)
935 {
936 if (contents[i].isDirectory())
937 {
938 String colName = contents[i].getName();
939 if (!colName.startsWith("CVS"))
940 {
941 names[j] = colName;
942 j++;
943 }
944
945 }
946 }
947
948 return names;
949
950 }
951
952 /** ids used for process id */
953 private int current_id = 0;
954
955 private String newID()
956 {
957 current_id++;
958 return Integer.toString(current_id);
959 }
960
961 /** creates a new short name from the collection title */
962 protected String createNewCollName(String coll_title)
963 {
964
965 String base_name = null;
966 // take the first 6 letters
967 if (coll_title.length() < 6)
968 {
969 base_name = coll_title;
970 }
971 else
972 {
973 base_name = coll_title.substring(0, 6);
974 }
975 File coll_dir = new File(GSFile.collectionBaseDir(this.site_home, base_name));
976 if (!coll_dir.exists())
977 { // this name is ok - not used yet
978 return base_name;
979 }
980
981 // now we have to make a new name until we get a good one
982 // try name1, name2 name3 etc
983 int i = 0;
984 while (coll_dir.exists())
985 {
986 i++;
987 coll_dir = new File(GSFile.collectionBaseDir(this.site_home, base_name + Integer.toString(i)));
988 }
989 return base_name + Integer.toString(i);
990
991 }
992
993 /**
994 * takes the params from the request (in the HashMap) and extracts any that
995 * need to be passed to the constructor and puts them into a paramList
996 * element
997 */
998 protected Element extractOtherParams(HashMap<String, Serializable> params, int type)
999 {
1000 Document doc = XMLConverter.newDOM();
1001 Element param_list = doc.createElement(GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1002 if (type == GS2PerlConstructor.NEW)
1003 {
1004 Element param = doc.createElement(GSXML.PARAM_ELEM);
1005 param.setAttribute(GSXML.NAME_ATT, "creator");
1006 param.setAttribute(GSXML.VALUE_ATT, (String) params.get(CREATOR_PARAM));
1007
1008 param_list.appendChild(param);
1009 param = doc.createElement(GSXML.PARAM_ELEM);
1010 param.setAttribute(GSXML.NAME_ATT, "about");
1011 param.setAttribute(GSXML.VALUE_ATT, (String) params.get(NEW_COL_ABOUT_PARAM));
1012 param_list.appendChild(param);
1013 param = doc.createElement(GSXML.PARAM_ELEM);
1014 param.setAttribute(GSXML.NAME_ATT, "title");
1015 param.setAttribute(GSXML.VALUE_ATT, (String) params.get(NEW_COL_TITLE_PARAM));
1016 param_list.appendChild(param);
1017 param = doc.createElement(GSXML.PARAM_ELEM);
1018 param.setAttribute(GSXML.NAME_ATT, "buildtype");
1019 param.setAttribute(GSXML.VALUE_ATT, (String) params.get(BUILDTYPE_PARAM));
1020 param_list.appendChild(param);
1021 return param_list;
1022 }
1023
1024 // other ones dont have params yet
1025 return null;
1026 }
1027
1028 protected void waitUntilReady(Element request)
1029 {
1030 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1031 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
1032
1033 String collection = (String) params.get(COL_PARAM);
1034
1035 if (checkCollectionIsNotBusy(collection))
1036 {
1037 return;
1038 }
1039
1040 while (!checkCollectionIsNotBusy(collection)) // When the collection ceases to be busy, we place a hold on it
1041 {
1042 try
1043 {
1044 Thread.currentThread().sleep(1000);
1045 }
1046 catch (Exception ex)
1047 {
1048 ex.printStackTrace();
1049 }
1050 }
1051 }
1052
1053 protected void signalReady(Element request)
1054 {
1055 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1056 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
1057
1058 String collection = (String) params.get(COL_PARAM);
1059
1060 collectionOperationMap.remove(collection);
1061 }
1062
1063 // If collection is NOT busy, then reserve it
1064 protected synchronized boolean checkCollectionIsNotBusy(String collection)
1065 {
1066 if (collectionOperationMap.get(collection) == null)
1067 {
1068 collectionOperationMap.put(collection, true);
1069 return true;
1070 }
1071 return false;
1072 }
1073
1074 protected boolean isAllowedToSetMeta(String metaname, Pattern allowedMetaFieldsPattern)
1075 {
1076 if(allowedMetaFieldsPattern == null) { // null when user has edit permissions, so they can set any meta
1077 ///logger.info("### User has permissions to set any meta.");
1078 return true;
1079 }
1080 if(metaname == null) {
1081 ///logger.info("### Can't check null metaname against pattern");
1082 return false;
1083 }
1084
1085 Matcher m = allowedMetaFieldsPattern.matcher(metaname);
1086 if(!m.matches()) {
1087 ///logger.info("### metaname: " + metaname + " doesn't match allowed allowed fields: " + allowedMetaFieldsPattern.toString());
1088 return false;
1089 } else {
1090 return true;
1091 }
1092 }
1093
1094 protected String[] getDocIdsWithOptFilter(String json_str, Pattern filterFields) // boolean strictOrPermissible
1095 {
1096 if(json_str == null) {
1097 logger.error("### Shouldn't be happening: null json string");
1098 return null;
1099 }
1100
1101 String[] docids = null;
1102
1103 // check that the name of each metadata being set matches the pattern filterFields.
1104 // The presence of any other meta means something other than adding user comments is being attempted,
1105 // which is invalid
1106 try {
1107
1108 JSONArray docInfoList = new JSONArray(json_str);
1109 docids = new String[docInfoList.length()];
1110 for(int index = 0; index < docInfoList.length(); index++) {
1111 JSONObject docInfo = docInfoList.getJSONObject(index);
1112 if(docInfo.has("metatable")) { // should exist for metadata arrays
1113
1114 docids[index] = docInfo.getString("docid"); // should exist if metatable existed
1115
1116 ///logger.info("@@@ Found docid: " + docids[index]);
1117
1118 JSONArray metatable = docInfo.getJSONArray("metatable");
1119 for(int i = 0; i < metatable.length(); i++) {
1120 JSONObject meta = metatable.getJSONObject(i);
1121
1122 String metaname = meta.getString("metaname");
1123 ///logger.info("### metaname: " + metaname);
1124
1125 if(!isAllowedToSetMeta(metaname, filterFields)) {
1126 return null;
1127 }
1128 }
1129 }
1130 }
1131 } catch(JSONException jsonex) {
1132 logger.error("Exception when parsing json string: " + json_str);
1133 logger.error(jsonex);
1134
1135 }
1136
1137 // if we're here, then it means that the JSON only asked for username|usercomment|usertimestamp meta
1138 // meaning that the setmeta operation was a valid user comment operation.
1139 // In that case, we have a docid for which we need to add a user comment
1140 // set-metadata-array can take more docids, but doesn't happen for a user comment. And one comment
1141 // is added at a time, but 3 meta fields are set for each comment: username, usercomment and timestamp
1142 // hence the use of set-meta-array.
1143 return docids;
1144
1145 }
1146
1147 protected Element errorResponse(String serviceName, String errorMsg) {
1148 Document result_doc = XMLConverter.newDOM();
1149 Element result = GSXML.createBasicResponse(result_doc, serviceName);
1150 GSXML.addError(result, errorMsg);
1151 return result;
1152 }
1153
1154 /** Copy from DebugService.userHasEditPermissions
1155 This function checks that the user is logged in and that the user
1156 is in the right group to edit the collection */
1157 protected boolean userHasCollectionEditPermissions(Element request) {
1158 Element param_list = (Element) GSXML.getChildByTagName(request, GSXML.PARAM_ELEM + GSXML.LIST_MODIFIER);
1159 HashMap<String, Serializable> params = GSXML.extractParams(param_list, false);
1160
1161 return userHasCollectionEditPermissions(request, params);
1162
1163 }
1164
1165 protected boolean userHasCollectionEditPermissions(Element request, HashMap<String, Serializable> params) {
1166 String collection = (String) params.get(COL_PARAM); // could be null on newcoll operation
1167
1168
1169 UserContext context = new UserContext(request);
1170 if(collection == null) {
1171 return !context.getUsername().equals("");
1172 }
1173
1174 /*
1175 // FOR DEBUGGING
1176 Set<Map.Entry<String, Serializable>> entries = params.entrySet();
1177 Iterator<Map.Entry<String, Serializable>> i = entries.iterator();
1178
1179 StringBuffer parametersLine = new StringBuffer();
1180 while (i.hasNext()) {
1181
1182 Map.Entry<String, Serializable> entry = i.next();
1183 String paramname = entry.getKey();
1184 String paramvalue = (String) entry.getValue();
1185
1186 parametersLine.append("\t" + paramname + ": " + paramvalue + "\n");
1187 }
1188
1189 logger.info("XXXXXXXXXXXXX PARAMETERS:\n" + parametersLine);
1190 */
1191
1192 for (String group : context.getGroups()) {
1193 // administrator always has permission
1194 if (group.equals("administrator")) {
1195 return true;
1196 }
1197 // all-collections-editor can edit any collection
1198 if (!collection.equals("")) {
1199 if (group.equals("all-collections-editor")) {
1200 return true;
1201 }
1202 if (group.equals(collection+"-collection-editor")) {
1203 return true;
1204 }
1205 }
1206 }
1207 // haven't found a group with edit permissions
1208 return false;
1209
1210 }
1211 protected void markDocumentInFlatDatabase(String mark, String collection, String oid) {
1212
1213 Document msg_doc = XMLConverter.newDOM();
1214 Element message = msg_doc.createElement(GSXML.MESSAGE_ELEM);
1215 UserContext userContext = new UserContext();
1216 Element query_request = GSXML.createBasicRequest(msg_doc, GSXML.REQUEST_TYPE_DESCRIBE , collection, userContext);
1217 message.appendChild(query_request);
1218 Element result = (Element) this.router.process(message);
1219 Element resp_elem = (Element) GSXML.getChildByTagName(result, GSXML.RESPONSE_ELEM);
1220 Element coll_elem = (Element) GSXML.getChildByTagName(resp_elem, GSXML.COLLECTION_ELEM);
1221 String dbtype = coll_elem.getAttribute(GSXML.DB_TYPE_ATT);
1222
1223 SimpleCollectionDatabase coll_db = new SimpleCollectionDatabase(dbtype);
1224 if (!coll_db.databaseOK())
1225 {
1226 logger.error("Couldn't create the collection database of type " + dbtype);
1227 return;
1228 }
1229
1230 // Open database for reading. It may not exist if collection is pre-built without archives (such as demo collections)
1231 String coll_db_file = GSFile.archivesDatabaseFile(this.site_home, collection, dbtype);
1232 if (!coll_db.openDatabase(coll_db_file, SimpleCollectionDatabase.READ))
1233 {
1234 logger.error("Could not open collection archives database. Database doesn't exist or else somebody's already using it?");
1235 return;
1236 }
1237 // now we know we have an archives folder
1238 String old_value = coll_db.getValue(oid);
1239 String new_value = "<index-status>" + mark;
1240 if(old_value == null) {
1241 logger.error("### null old_value in flat DB for oid " + oid);
1242 } else {
1243 new_value = old_value.replace("<index-status>B", "<index-status>" + mark);
1244 logger.info("### Replacing db entry for oid " + oid + " which has old_value " + old_value);
1245 logger.info("### with new value " + new_value);
1246
1247 }
1248 // Close database for reading
1249 coll_db.closeDatabase();
1250
1251 if (!coll_db.openDatabase(coll_db_file, SimpleCollectionDatabase.WRITE))
1252 {
1253 logger.error("Could not open collection archives database. Somebody already using this database!");
1254 return;
1255 }
1256
1257 coll_db.setValue(oid, new_value);
1258
1259 coll_db.closeDatabase();
1260 }
1261}
Note: See TracBrowser for help on using the repository browser.