001: /*
002: * FlowRegistryUtils.java
003: *
004: * Version: $Revision: 1.3 $
005: *
006: * Date: $Date: 2006/07/13 23:20:54 $
007: *
008: * Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
009: * Institute of Technology. All rights reserved.
010: *
011: * Redistribution and use in source and binary forms, with or without
012: * modification, are permitted provided that the following conditions are
013: * met:
014: *
015: * - Redistributions of source code must retain the above copyright
016: * notice, this list of conditions and the following disclaimer.
017: *
018: * - Redistributions in binary form must reproduce the above copyright
019: * notice, this list of conditions and the following disclaimer in the
020: * documentation and/or other materials provided with the distribution.
021: *
022: * - Neither the name of the Hewlett-Packard Company nor the name of the
023: * Massachusetts Institute of Technology nor the names of their
024: * contributors may be used to endorse or promote products derived from
025: * this software without specific prior written permission.
026: *
027: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
028: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
029: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
030: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
031: * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
032: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
033: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
034: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
035: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
036: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
037: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
038: * DAMAGE.
039: */package org.dspace.app.xmlui.aspect.administrative;
040:
041: import java.io.IOException;
042: import java.io.UnsupportedEncodingException;
043: import java.net.URLDecoder;
044: import java.sql.SQLException;
045: import java.util.ArrayList;
046: import java.util.List;
047: import java.util.Locale;
048:
049: import org.apache.cocoon.environment.Request;
050: import org.dspace.app.xmlui.utils.RequestUtils;
051: import org.dspace.app.xmlui.utils.UIException;
052: import org.dspace.app.xmlui.wing.Message;
053: import org.dspace.authorize.AuthorizeException;
054: import org.dspace.content.BitstreamFormat;
055: import org.dspace.content.MetadataField;
056: import org.dspace.content.MetadataSchema;
057: import org.dspace.content.NonUniqueMetadataException;
058: import org.dspace.core.Constants;
059: import org.dspace.core.Context;
060:
061: /**
062: * Utility methods to process actions on either the metadata registry
063: * or format registry.
064: * @author scott phillips
065: */
066: public class FlowRegistryUtils {
067:
068: /** Language Strings */
069: private static final Message T_add_metadata_schema_success_notice = new Message(
070: "default",
071: "xmlui.administrative.FlowRegistryUtils.add_metadata_schema_success_notice");
072: private static final Message T_delete_metadata_schema_success_notice = new Message(
073: "default",
074: "xmlui.administrative.FlowRegistryUtils.delete_metadata_schema_success_notice");
075: private static final Message T_add_metadata_field_success_notice = new Message(
076: "default",
077: "xmlui.administrative.FlowRegistryUtils.add_metadata_field_success_notice");
078: private static final Message T_edit_metadata_field_success_notice = new Message(
079: "default",
080: "xmlui.administrative.FlowRegistryUtils.edit_metadata_field_success_notice");
081: private static final Message T_move_metadata_field_sucess_notice = new Message(
082: "default",
083: "xmlui.administrative.FlowRegistryUtils.move_metadata_field_success_notice");
084: private static final Message T_delete_metadata_field_success_notice = new Message(
085: "default",
086: "xmlui.administrative.FlowRegistryUtils.delete_metadata_field_success_notice");
087: private static final Message T_edit_bitstream_format_success_notice = new Message(
088: "default",
089: "xmlui.administrative.FlowRegistryUtils.edit_bitstream_format_success_notice");
090: private static final Message T_delete_bitstream_format_success_notice = new Message(
091: "default",
092: "xmlui.administrative.FlowRegistryUtils.delete_bitstream_format_success_notice");
093:
094: /**
095: * Add a new metadata schema. The ID of the new schema will be added
096: * as the "schemaID" parameter on the results object.
097: *
098: * @param context The DSpace context
099: * @param namespace The new schema's namespace
100: * @param name The new schema's name.
101: * @return A flow result
102: */
103: public static FlowResult processAddMetadataSchema(Context context,
104: String namespace, String name) throws SQLException,
105: AuthorizeException, NonUniqueMetadataException, UIException {
106: FlowResult result = new FlowResult();
107: result.setContinue(false);
108:
109: // Decode the namespace and name
110: try {
111: namespace = URLDecoder.decode(namespace,
112: Constants.DEFAULT_ENCODING);
113: name = URLDecoder.decode(name, Constants.DEFAULT_ENCODING);
114: } catch (UnsupportedEncodingException uee) {
115: throw new UIException(uee);
116: }
117:
118: if (namespace == null || namespace.length() <= 0)
119: result.addError("namespace");
120: if (name == null || name.length() <= 0
121: || name.indexOf('.') != -1 || name.indexOf('_') != -1
122: || name.indexOf(' ') != -1)
123: // The name must not be empty nor contain dot, underscore or spaces.
124: result.addError("name");
125:
126: if (result.getErrors() == null) {
127: MetadataSchema schema = new MetadataSchema();
128: schema.setNamespace(namespace);
129: schema.setName(name);
130: schema.create(context);
131:
132: context.commit();
133:
134: result.setContinue(true);
135: result.setOutcome(true);
136: result.setMessage(T_add_metadata_schema_success_notice);
137: result.setParameter("schemaID", schema.getSchemaID());
138: }
139:
140: return result;
141: }
142:
143: /**
144: * Delete the given schemas.
145: *
146: * @param context The DSpace context
147: * @param schemaIDs A list of schema IDs to be deleted.
148: * @return A flow result
149: */
150: public static FlowResult processDeleteMetadataSchemas(
151: Context context, String[] schemaIDs) throws SQLException,
152: AuthorizeException, NonUniqueMetadataException {
153: FlowResult result = new FlowResult();
154:
155: int count = 0;
156: for (String id : schemaIDs) {
157: MetadataSchema schema = MetadataSchema.find(context,
158: Integer.valueOf(id));
159:
160: // First remove and fields in the schema
161: MetadataField[] fields = MetadataField.findAllInSchema(
162: context, schema.getSchemaID());
163: for (MetadataField field : fields)
164: field.delete(context);
165:
166: // Once all the fields are gone, then delete the schema.
167: schema.delete(context);
168: count++;
169: }
170:
171: if (count > 0) {
172: context.commit();
173:
174: result.setContinue(true);
175: result.setOutcome(true);
176: result.setMessage(T_delete_metadata_schema_success_notice);
177: }
178:
179: return result;
180: }
181:
182: /**
183: * Add a new metadata field. The newly created field's ID will be added as
184: * the "fieldID" parameter on the results object.
185: *
186: * @param context The DSpace context
187: * @param schemaID The id of the schema where this new field should be added.
188: * @param element The field's element.
189: * @param qualifier The field's qualifier.
190: * @param note A scope not about the field.
191: * @return A results object
192: */
193: public static FlowResult processAddMetadataField(Context context,
194: int schemaID, String element, String qualifier, String note)
195: throws IOException, AuthorizeException, SQLException,
196: UIException {
197: FlowResult result = new FlowResult();
198: result.setContinue(false);
199:
200: // Decode the element, qualifier, and note.
201: try {
202: element = URLDecoder.decode(element,
203: Constants.DEFAULT_ENCODING);
204: qualifier = URLDecoder.decode(qualifier,
205: Constants.DEFAULT_ENCODING);
206: note = URLDecoder.decode(note, Constants.DEFAULT_ENCODING);
207: } catch (UnsupportedEncodingException uee) {
208: throw new UIException(uee);
209: }
210:
211: // Check if the field name is good.
212: result.setErrors(checkMetadataFieldName(element, qualifier));
213:
214: // Make sure qualifier is null if blank.
215: if ("".equals(qualifier))
216: qualifier = null;
217:
218: if (result.getErrors() == null) {
219: try {
220:
221: MetadataField field = new MetadataField();
222: field.setSchemaID(schemaID);
223: field.setElement(element);
224: field.setQualifier(qualifier);
225: field.setScopeNote(note);
226: field.create(context);
227:
228: context.commit();
229:
230: result.setContinue(true);
231: result.setOutcome(true);
232: result.setMessage(T_add_metadata_field_success_notice);
233: result.setParameter("fieldID", field.getFieldID());
234: } catch (NonUniqueMetadataException nume) {
235: result.addError("duplicate_field");
236: }
237:
238: }
239:
240: return result;
241: }
242:
243: /**
244: * Edit a metadata field.
245: *
246: * @param context The DSpace context.
247: * @param schemaID The ID of the schema for this field.
248: * @param fieldID The id of this field.
249: * @param element A new element value
250: * @param qualifier A new qualifier value
251: * @param note A new note value.
252: * @return A results object.
253: */
254: public static FlowResult processEditMetadataField(Context context,
255: int schemaID, int fieldID, String element,
256: String qualifier, String note) throws IOException,
257: AuthorizeException, SQLException, UIException {
258: FlowResult result = new FlowResult();
259: result.setContinue(false);
260:
261: // Decode the element, qualifier, and note.
262: try {
263: element = URLDecoder.decode(element,
264: Constants.DEFAULT_ENCODING);
265: qualifier = URLDecoder.decode(qualifier,
266: Constants.DEFAULT_ENCODING);
267: note = URLDecoder.decode(note, Constants.DEFAULT_ENCODING);
268: } catch (UnsupportedEncodingException uee) {
269: throw new UIException(uee);
270: }
271:
272: // Check if the field name is good.
273: result.setErrors(checkMetadataFieldName(element, qualifier));
274:
275: // Make sure qualifier is null if blank.
276: if ("".equals(qualifier))
277: qualifier = null;
278:
279: // Check to make sure the field is unique, sometimes the NonUniqueMetadataException is not thrown.
280: MetadataField possibleDuplicate = MetadataField.findByElement(
281: context, schemaID, element, qualifier);
282: if (possibleDuplicate != null
283: && possibleDuplicate.getFieldID() != fieldID)
284: result.addError("duplicate_field");
285:
286: if (result.getErrors() == null) {
287: try {
288: // Update the metadata for a DC type
289: MetadataField field = MetadataField.find(context,
290: fieldID);
291: field.setElement(element);
292: field.setQualifier(qualifier);
293: field.setScopeNote(note);
294: field.update(context);
295:
296: context.commit();
297:
298: result.setContinue(true);
299: result.setOutcome(true);
300: result.setMessage(T_edit_metadata_field_success_notice);
301: } catch (NonUniqueMetadataException nume) {
302: // This shouldn't ever occure.
303: result.addError("duplicate_field");
304: }
305: }
306:
307: return result;
308: }
309:
310: /**
311: * Simple method to check the a metadata field's name: element and qualifier.
312: *
313: * @param element The field's element.
314: * @param qualifier The field's qualifier
315: * @return A list of errors found, null if none are found.
316: */
317: private static List<String> checkMetadataFieldName(String element,
318: String qualifier) {
319: List<String> errors = new ArrayList<String>();
320:
321: // Is the element empty?
322: if (element == null || element.length() <= 0) {
323: element = ""; // so that the rest of the checks don't fail.
324: errors.add("element_empty");
325: }
326:
327: // Is there a bad character in the element?
328: if (element.indexOf('.') != -1 || element.indexOf('_') != -1
329: || element.indexOf(' ') != -1)
330: errors.add("element_badchar");
331:
332: // Is the element too long?
333: if (element.length() > 64)
334: errors.add("element_tolong");
335:
336: // The qualifier can be empty.
337: if (qualifier != null && qualifier.length() > 0) {
338: if (qualifier.length() > 64)
339: errors.add("qualifier_tolong");
340:
341: if (qualifier.indexOf('.') != -1
342: || qualifier.indexOf('_') != -1
343: || qualifier.indexOf(' ') != -1)
344: errors.add("qualifier_badchar");
345: }
346:
347: // If there were no errors then just return null.
348: if (errors.size() == 0)
349: return null;
350:
351: return errors;
352: }
353:
354: /**
355: * Move the specified metadata fields to the target schema.
356: *
357: * @param context The DSpace context
358: * @param schemaID The target schema ID
359: * @param fieldIDs The fields to be moved.
360: * @return A results object.
361: */
362: public static FlowResult processMoveMetadataField(Context context,
363: int schemaID, String[] fieldIDs)
364: throws NumberFormatException, SQLException,
365: AuthorizeException, NonUniqueMetadataException, IOException {
366: FlowResult result = new FlowResult();
367:
368: int count = 0;
369: for (String id : fieldIDs) {
370: MetadataField field = MetadataField.find(context, Integer
371: .valueOf(id));
372: field.setSchemaID(schemaID);
373: field.update(context);
374: count++;
375: }
376:
377: if (count > 0) {
378: context.commit();
379:
380: result.setContinue(true);
381: result.setOutcome(true);
382: result.setMessage(T_move_metadata_field_sucess_notice);
383: }
384:
385: return result;
386: }
387:
388: /**
389: * Delete the specified metadata fields.
390: *
391: * @param context The DSpace context
392: * @param fieldIDs The fields to be deleted.
393: * @return A results object
394: */
395: public static FlowResult processDeleteMetadataField(
396: Context context, String[] fieldIDs)
397: throws NumberFormatException, SQLException,
398: AuthorizeException {
399: FlowResult result = new FlowResult();
400:
401: int count = 0;
402: for (String id : fieldIDs) {
403: MetadataField field = MetadataField.find(context, Integer
404: .valueOf(id));
405: field.delete(context);
406: count++;
407: }
408:
409: if (count > 0) {
410: context.commit();
411:
412: result.setContinue(true);
413: result.setOutcome(true);
414: result.setMessage(T_delete_metadata_field_success_notice);
415: }
416:
417: return result;
418: }
419:
420: /**
421: * Edit a bitstream format. If the formatID is -1 then a new format is created.
422: * The formatID of the new format is added as a parameter to the results object.
423: *
424: * FIXME: the reason we accept a request object is so that we can use the
425: * RequestUtils.getFieldvalues() to get the multivalue field values.
426: *
427: * @param context The dspace context
428: * @param formatID The id of the format being updated.
429: * @param request The request object, for all the field entries.
430: * @return A results object
431: */
432: public static FlowResult processEditBitstreamFormat(
433: Context context, int formatID, Request request)
434: throws SQLException, AuthorizeException {
435: FlowResult result = new FlowResult();
436: result.setContinue(false);
437:
438: // Get the values
439: String mimeType = request.getParameter("mimetype");
440: String shortDescription = request
441: .getParameter("short_description");
442: String description = request.getParameter("description");
443: String supportLevel = request.getParameter("support_level");
444: String internal = request.getParameter("internal");
445: List<String> extensionsList = RequestUtils.getFieldValues(
446: request, "extensions");
447: String[] extensions = extensionsList
448: .toArray(new String[extensionsList.size()]);
449:
450: // The format must at least have a name.
451: if (formatID != 1
452: && (shortDescription == null || shortDescription
453: .length() == 0)) {
454: result.addError("short_description");
455: return result;
456: }
457:
458: // Remove leading periods from file extensions.
459: for (int i = 0; i < extensions.length; i++)
460: if (extensions[i].startsWith("."))
461: extensions[i] = extensions[i].substring(1);
462:
463: // Get or create the format
464: BitstreamFormat format;
465: if (formatID >= 0)
466: format = BitstreamFormat.find(context, formatID);
467: else
468: format = BitstreamFormat.create(context);
469:
470: // Update values
471: format.setMIMEType(mimeType);
472: if (formatID != 1) // don't change the unknow format.
473: format.setShortDescription(shortDescription);
474: format.setDescription(description);
475: format.setSupportLevel(Integer.valueOf(supportLevel));
476: if (internal == null)
477: format.setInternal(false);
478: else
479: format.setInternal(true);
480: format.setExtensions(extensions);
481:
482: // Commit the change
483: format.update();
484: context.commit();
485:
486: // Return status
487: result.setContinue(true);
488: result.setOutcome(true);
489: result.setMessage(T_edit_bitstream_format_success_notice);
490: result.setParameter("formatID", format.getID());
491:
492: return result;
493: }
494:
495: /**
496: * Delete the specified bitstream formats.
497: *
498: * @param context The DSpace context
499: * @param formatIDs The formats-to-be-deleted.
500: * @return A results object.
501: */
502: public static FlowResult processDeleteBitstreamFormats(
503: Context context, String[] formatIDs)
504: throws NumberFormatException, SQLException,
505: AuthorizeException {
506: FlowResult result = new FlowResult();
507:
508: int count = 0;
509: for (String id : formatIDs) {
510: BitstreamFormat format = BitstreamFormat.find(context,
511: Integer.valueOf(id));
512: format.delete();
513: count++;
514: }
515:
516: if (count > 0) {
517: context.commit();
518:
519: result.setContinue(true);
520: result.setOutcome(true);
521: result.setMessage(T_delete_bitstream_format_success_notice);
522: }
523:
524: return result;
525: }
526:
527: }
|