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

Last change on this file since 33672 was 33672, checked in by kjdon, 4 years ago

modified slightly so that the error messages come from the dictionary (ServiceRack.properties) instead of hard wired in the code

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