001: /*
002: * BitstreamFormat.java
003: *
004: * Version: $Revision: 1670 $
005: *
006: * Date: $Date: 2006-11-10 13:39:17 -0600 (Fri, 10 Nov 2006) $
007: *
008: * Copyright (c) 2002-2005, 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: */
040: package org.dspace.content;
041:
042: import java.sql.SQLException;
043: import java.util.ArrayList;
044: import java.util.List;
045:
046: import org.apache.log4j.Logger;
047: import org.dspace.authorize.AuthorizeException;
048: import org.dspace.authorize.AuthorizeManager;
049: import org.dspace.core.ConfigurationManager;
050: import org.dspace.core.Context;
051: import org.dspace.core.LogManager;
052: import org.dspace.storage.rdbms.DatabaseManager;
053: import org.dspace.storage.rdbms.TableRow;
054: import org.dspace.storage.rdbms.TableRowIterator;
055:
056: /**
057: * Class representing a particular bitstream format.
058: * <P>
059: * Changes to the bitstream format metadata are only written to the database
060: * when <code>update</code> is called.
061: *
062: * @author Robert Tansley
063: * @version $Revision: 1670 $
064: */
065: public class BitstreamFormat {
066: /** log4j logger */
067: private static Logger log = Logger.getLogger(BitstreamFormat.class);
068:
069: /**
070: * The "unknown" support level - for bitstream formats that are unknown to
071: * the system
072: */
073: public static final int UNKNOWN = 0;
074:
075: /**
076: * The "known" support level - for bitstream formats that are known to the
077: * system, but not fully supported
078: */
079: public static final int KNOWN = 1;
080:
081: /**
082: * The "supported" support level - for bitstream formats known to the system
083: * and fully supported.
084: */
085: public static final int SUPPORTED = 2;
086:
087: /** Our context */
088: private Context bfContext;
089:
090: /** The row in the table representing this format */
091: private TableRow bfRow;
092:
093: /** File extensions for this format */
094: private List extensions;
095:
096: /**
097: * Class constructor for creating a BitstreamFormat object based on the
098: * contents of a DB table row.
099: *
100: * @param context
101: * the context this object exists in
102: * @param row
103: * the corresponding row in the table
104: * @throws SQLException
105: */
106: BitstreamFormat(Context context, TableRow row) throws SQLException {
107: bfContext = context;
108: bfRow = row;
109: extensions = new ArrayList();
110:
111: TableRowIterator tri = DatabaseManager
112: .query(
113: context,
114: "SELECT * FROM fileextension WHERE bitstream_format_id= ? ",
115: getID());
116:
117: while (tri.hasNext()) {
118: extensions.add(tri.next().getStringColumn("extension"));
119: }
120: // close the TableRowIterator to free up resources
121: tri.close();
122:
123: // Cache ourselves
124: context.cache(this , row.getIntColumn("bitstream_format_id"));
125: }
126:
127: /**
128: * Get a bitstream format from the database.
129: *
130: * @param context
131: * DSpace context object
132: * @param id
133: * ID of the bitstream format
134: *
135: * @return the bitstream format, or null if the ID is invalid.
136: * @throws SQLException
137: */
138: public static BitstreamFormat find(Context context, int id)
139: throws SQLException {
140: // First check the cache
141: BitstreamFormat fromCache = (BitstreamFormat) context
142: .fromCache(BitstreamFormat.class, id);
143:
144: if (fromCache != null) {
145: return fromCache;
146: }
147:
148: TableRow row = DatabaseManager.find(context,
149: "bitstreamformatregistry", id);
150:
151: if (row == null) {
152: if (log.isDebugEnabled()) {
153: log.debug(LogManager.getHeader(context,
154: "find_bitstream_format",
155: "not_found,bitstream_format_id=" + id));
156: }
157:
158: return null;
159: }
160:
161: // not null, return format object
162: if (log.isDebugEnabled()) {
163: log.debug(LogManager.getHeader(context,
164: "find_bitstream_format", "bitstream_format_id="
165: + id));
166: }
167:
168: return new BitstreamFormat(context, row);
169: }
170:
171: /**
172: * Find a bitstream format by its (unique) MIME type.
173: * If more than one bitstream format has the same MIME type, the
174: * one returned is unpredictable.
175: *
176: * @param context
177: * DSpace context object
178: * @param mimeType
179: * MIME type value
180: *
181: * @return the corresponding bitstream format, or <code>null</code> if
182: * there's no bitstream format with the given MIMEtype.
183: * @throws SQLException
184: */
185: public static BitstreamFormat findByMIMEType(Context context,
186: String mimeType) throws SQLException {
187: // NOTE: Avoid internal formats since e.g. "License" also has
188: // a MIMEtype of text/plain.
189: TableRow formatRow = DatabaseManager.querySingle(context,
190: "SELECT * FROM bitstreamformatregistry "
191: + "WHERE mimetype LIKE ? AND internal = '0' ",
192: mimeType);
193:
194: if (formatRow == null)
195: return null;
196: return findByFinish(context, formatRow);
197: }
198:
199: /**
200: * Find a bitstream format by its (unique) short description
201: *
202: * @param context
203: * DSpace context object
204: * @param desc
205: * the short description
206: *
207: * @return the corresponding bitstream format, or <code>null</code> if
208: * there's no bitstream format with the given short description
209: * @throws SQLException
210: */
211: public static BitstreamFormat findByShortDescription(
212: Context context, String desc) throws SQLException {
213: TableRow formatRow = DatabaseManager.findByUnique(context,
214: "bitstreamformatregistry", "short_description", desc);
215:
216: if (formatRow == null) {
217: return null;
218: }
219:
220: return findByFinish(context, formatRow);
221: }
222:
223: // shared final logic in findBy... methods;
224: // use context's cache for object mapped from table row.
225: private static BitstreamFormat findByFinish(Context context,
226: TableRow formatRow) throws SQLException {
227: // not null
228: if (log.isDebugEnabled()) {
229: log
230: .debug(LogManager
231: .getHeader(
232: context,
233: "find_bitstream",
234: "bitstream_format_id="
235: + formatRow
236: .getIntColumn("bitstream_format_id")));
237: }
238:
239: // From cache?
240: BitstreamFormat fromCache = (BitstreamFormat) context
241: .fromCache(BitstreamFormat.class, formatRow
242: .getIntColumn("bitstream_format_id"));
243:
244: if (fromCache != null) {
245: return fromCache;
246: }
247:
248: return new BitstreamFormat(context, formatRow);
249: }
250:
251: /**
252: * Get the generic "unknown" bitstream format.
253: *
254: * @param context
255: * DSpace context object
256: *
257: * @return the "unknown" bitstream format.
258: * @throws SQLException
259: *
260: * @throws IllegalStateException
261: * if the "unknown" bitstream format couldn't be found
262: */
263: public static BitstreamFormat findUnknown(Context context)
264: throws SQLException {
265: BitstreamFormat bf = findByShortDescription(context, "Unknown");
266:
267: if (bf == null) {
268: throw new IllegalStateException(
269: "No `Unknown' bitstream format in registry");
270: }
271:
272: return bf;
273: }
274:
275: /**
276: * Retrieve all bitstream formats from the registry, ordered by ID
277: *
278: * @param context
279: * DSpace context object
280: *
281: * @return the bitstream formats.
282: * @throws SQLException
283: */
284: public static BitstreamFormat[] findAll(Context context)
285: throws SQLException {
286: List formats = new ArrayList();
287:
288: TableRowIterator tri = DatabaseManager
289: .queryTable(context, "bitstreamformatregistry",
290: "SELECT * FROM bitstreamformatregistry ORDER BY bitstream_format_id");
291:
292: while (tri.hasNext()) {
293: TableRow row = tri.next();
294:
295: // From cache?
296: BitstreamFormat fromCache = (BitstreamFormat) context
297: .fromCache(BitstreamFormat.class, row
298: .getIntColumn("bitstream_format_id"));
299:
300: if (fromCache != null) {
301: formats.add(fromCache);
302: } else {
303: formats.add(new BitstreamFormat(context, row));
304: }
305: }
306: // close the TableRowIterator to free up resources
307: tri.close();
308:
309: // Return the formats as an array
310: BitstreamFormat[] formatArray = new BitstreamFormat[formats
311: .size()];
312: formatArray = (BitstreamFormat[]) formats.toArray(formatArray);
313:
314: return formatArray;
315: }
316:
317: /**
318: * Retrieve all non-internal bitstream formats from the registry. The
319: * "unknown" format is not included, and the formats are ordered by support
320: * level (highest first) first then short description.
321: *
322: * @param context
323: * DSpace context object
324: *
325: * @return the bitstream formats.
326: * @throws SQLException
327: */
328: public static BitstreamFormat[] findNonInternal(Context context)
329: throws SQLException {
330: List formats = new ArrayList();
331:
332: String myQuery = "SELECT * FROM bitstreamformatregistry WHERE internal='0' "
333: + "AND short_description NOT LIKE 'Unknown' "
334: + "ORDER BY support_level DESC, short_description";
335:
336: TableRowIterator tri = DatabaseManager.queryTable(context,
337: "bitstreamformatregistry", myQuery);
338:
339: while (tri.hasNext()) {
340: TableRow row = tri.next();
341:
342: // From cache?
343: BitstreamFormat fromCache = (BitstreamFormat) context
344: .fromCache(BitstreamFormat.class, row
345: .getIntColumn("bitstream_format_id"));
346:
347: if (fromCache != null) {
348: formats.add(fromCache);
349: } else {
350: formats.add(new BitstreamFormat(context, row));
351: }
352: }
353: // close the TableRowIterator to free up resources
354: tri.close();
355:
356: // Return the formats as an array
357: BitstreamFormat[] formatArray = new BitstreamFormat[formats
358: .size()];
359: formatArray = (BitstreamFormat[]) formats.toArray(formatArray);
360:
361: return formatArray;
362: }
363:
364: /**
365: * Create a new bitstream format
366: *
367: * @param context
368: * DSpace context object
369: * @return the newly created BitstreamFormat
370: * @throws SQLException
371: * @throws AuthorizeException
372: */
373: public static BitstreamFormat create(Context context)
374: throws SQLException, AuthorizeException {
375: // Check authorisation - only administrators can create new formats
376: if (!AuthorizeManager.isAdmin(context)) {
377: throw new AuthorizeException(
378: "Only administrators can create bitstream formats");
379: }
380:
381: // Create a table row
382: TableRow row = DatabaseManager.create(context,
383: "bitstreamformatregistry");
384:
385: log.info(LogManager.getHeader(context,
386: "create_bitstream_format", "bitstream_format_id="
387: + row.getIntColumn("bitstream_format_id")));
388:
389: return new BitstreamFormat(context, row);
390: }
391:
392: /**
393: * Get the internal identifier of this bitstream format
394: *
395: * @return the internal identifier
396: */
397: public int getID() {
398: return bfRow.getIntColumn("bitstream_format_id");
399: }
400:
401: /**
402: * Get a short (one or two word) description of this bitstream format
403: *
404: * @return the short description
405: */
406: public String getShortDescription() {
407: return bfRow.getStringColumn("short_description");
408: }
409:
410: /**
411: * Set the short description of the bitstream format
412: *
413: * @param s
414: * the new short description
415: */
416: public void setShortDescription(String s) throws SQLException {
417: // You can not reset the unknown's registry's name
418: BitstreamFormat unknown = null;
419: ;
420: try {
421: unknown = findUnknown(bfContext);
422: } catch (IllegalStateException e) {
423: // No short_description='Unknown' found in bitstreamformatregistry
424: // table. On first load of registries this is expected because it
425: // hasn't been inserted yet! So, catch but ignore this runtime
426: // exception thrown by method findUnknown.
427: }
428:
429: // If the exception was thrown, unknown will == null so goahead and
430: // load s. If not, check that the unknown's registry's name is not
431: // being reset.
432: if (unknown == null || unknown.getID() != getID()) {
433: bfRow.setColumn("short_description", s);
434: }
435: }
436:
437: /**
438: * Get a description of this bitstream format, including full application or
439: * format name
440: *
441: * @return the description
442: */
443: public String getDescription() {
444: return bfRow.getStringColumn("description");
445: }
446:
447: /**
448: * Set the description of the bitstream format
449: *
450: * @param s
451: * the new description
452: */
453: public void setDescription(String s) {
454: bfRow.setColumn("description", s);
455: }
456:
457: /**
458: * Get the MIME type of this bitstream format, for example
459: * <code>text/plain</code>
460: *
461: * @return the MIME type
462: */
463: public String getMIMEType() {
464: return bfRow.getStringColumn("mimetype");
465: }
466:
467: /**
468: * Set the MIME type of the bitstream format
469: *
470: * @param s
471: * the new MIME type
472: */
473: public void setMIMEType(String s) {
474: bfRow.setColumn("mimetype", s);
475: }
476:
477: /**
478: * Get the support level for this bitstream format - one of
479: * <code>UNKNOWN</code>,<code>KNOWN</code> or <code>SUPPORTED</code>.
480: *
481: * @return the support level
482: */
483: public int getSupportLevel() {
484: return bfRow.getIntColumn("support_level");
485: }
486:
487: /**
488: * Set the support level for this bitstream format - one of
489: * <code>UNKNOWN</code>,<code>KNOWN</code> or <code>SUPPORTED</code>.
490: *
491: * @param sl
492: * the new support level
493: */
494: public void setSupportLevel(int sl) {
495: // Sanity check
496: if ((sl < 0) || (sl > 2)) {
497: throw new IllegalArgumentException("Invalid support level");
498: }
499:
500: bfRow.setColumn("support_level", sl);
501: }
502:
503: /**
504: * Find out if the bitstream format is an internal format - that is, one
505: * that is used to store system information, rather than the content of
506: * items in the system
507: *
508: * @return <code>true</code> if the bitstream format is an internal type
509: */
510: public boolean isInternal() {
511: return bfRow.getBooleanColumn("internal");
512: }
513:
514: /**
515: * Set whether the bitstream format is an internal format
516: *
517: * @param b
518: * pass in <code>true</code> if the bitstream format is an
519: * internal type
520: */
521: public void setInternal(boolean b) {
522: bfRow.setColumn("internal", b);
523: }
524:
525: /**
526: * Update the bitstream format metadata
527: *
528: * @throws SQLException
529: * @throws AuthorizeException
530: */
531: public void update() throws SQLException, AuthorizeException {
532: // Check authorisation - only administrators can change formats
533: if (!AuthorizeManager.isAdmin(bfContext)) {
534: throw new AuthorizeException(
535: "Only administrators can modify bitstream formats");
536: }
537:
538: log.info(LogManager.getHeader(bfContext,
539: "update_bitstream_format", "bitstream_format_id="
540: + getID()));
541:
542: // Delete extensions
543: DatabaseManager
544: .updateQuery(
545: bfContext,
546: "DELETE FROM fileextension WHERE bitstream_format_id= ? ",
547: getID());
548:
549: // Rewrite extensions
550: for (int i = 0; i < extensions.size(); i++) {
551: String s = (String) extensions.get(i);
552: TableRow r = DatabaseManager.create(bfContext,
553: "fileextension");
554: r.setColumn("bitstream_format_id", getID());
555: r.setColumn("extension", s);
556: DatabaseManager.update(bfContext, r);
557: }
558:
559: DatabaseManager.update(bfContext, bfRow);
560: }
561:
562: /**
563: * Delete this bitstream format. This converts the types of any bitstreams
564: * that may have this type to "unknown". Use this with care!
565: *
566: * @throws SQLException
567: * @throws AuthorizeException
568: */
569: public void delete() throws SQLException, AuthorizeException {
570: // Check authorisation - only administrators can delete formats
571: if (!AuthorizeManager.isAdmin(bfContext)) {
572: throw new AuthorizeException(
573: "Only administrators can delete bitstream formats");
574: }
575:
576: // Find "unknown" type
577: BitstreamFormat unknown = findUnknown(bfContext);
578:
579: if (unknown.getID() == getID())
580: throw new IllegalArgumentException(
581: "The Unknown bitstream format may not be deleted.");
582:
583: // Remove from cache
584: bfContext.removeCached(this , getID());
585:
586: // Set bitstreams with this format to "unknown"
587: int numberChanged = DatabaseManager.updateQuery(bfContext,
588: "UPDATE bitstream SET bitstream_format_id= ? "
589: + " WHERE bitstream_format_id= ? ", unknown
590: .getID(), getID());
591:
592: // Delete extensions
593: DatabaseManager
594: .updateQuery(
595: bfContext,
596: "DELETE FROM fileextension WHERE bitstream_format_id= ? ",
597: getID());
598:
599: // Delete this format from database
600: DatabaseManager.delete(bfContext, bfRow);
601:
602: log.info(LogManager.getHeader(bfContext,
603: "delete_bitstream_format", "bitstream_format_id="
604: + getID() + ",bitstreams_changed="
605: + numberChanged));
606: }
607:
608: /**
609: * Get the filename extensions associated with this format
610: *
611: * @return the extensions
612: */
613: public String[] getExtensions() {
614: String[] exts = new String[extensions.size()];
615: exts = (String[]) extensions.toArray(exts);
616:
617: return exts;
618: }
619:
620: /**
621: * Set the filename extensions associated with this format
622: *
623: * @param exts
624: * String [] array of extensions
625: */
626: public void setExtensions(String[] exts) {
627: extensions = new ArrayList();
628:
629: for (int i = 0; i < exts.length; i++) {
630: extensions.add(exts[i]);
631: }
632: }
633: }
|