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

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