001: /*
002: * BrowseItem.java
003: *
004: * Copyright (c) 2002-2007, Hewlett-Packard Company and Massachusetts
005: * Institute of Technology. All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions are
009: * met:
010: *
011: * - Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * - Redistributions in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in the
016: * documentation and/or other materials provided with the distribution.
017: *
018: * - Neither the name of the Hewlett-Packard Company nor the name of the
019: * Massachusetts Institute of Technology nor the names of their
020: * contributors may be used to endorse or promote products derived from
021: * this software without specific prior written permission.
022: *
023: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
024: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
025: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
026: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
027: * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
028: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
029: * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
030: * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
031: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
032: * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
033: * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
034: * DAMAGE.
035: */
036: package org.dspace.browse;
037:
038: import org.apache.log4j.Logger;
039: import org.dspace.authorize.AuthorizeManager;
040: import org.dspace.content.*;
041: import org.dspace.core.Constants;
042: import org.dspace.core.Context;
043: import org.dspace.handle.HandleManager;
044:
045: import java.sql.SQLException;
046: import java.util.ArrayList;
047: import java.util.Collections;
048: import java.util.Iterator;
049: import java.util.List;
050:
051: /**
052: * Entity class to represent an item that is being used to generate Browse
053: * results. This behaves in many was similar to the Item object, but its
054: * metadata handling has been further optimised for performance in both
055: * reading and writing, and it does not deal with other objects related to
056: * items
057: *
058: * FIXME: this class violates some of the encapsulation of the Item, but there is
059: * unfortunately no way around this until DAOs and an interface are provided
060: * for the Item class.
061: *
062: * @author Richard Jones
063: *
064: */
065: public class BrowseItem extends DSpaceObject {
066: /** Logger */
067: private static Logger log = Logger.getLogger(BrowseItem.class);
068:
069: /** DSpace context */
070: private Context context;
071:
072: /** a List of all the metadata */
073: private List metadata = new ArrayList();
074:
075: /** database id of the item */
076: private int id = -1;
077:
078: /** is the item in the archive */
079: private boolean in_archive = true;
080:
081: /** is the item withdrawn */
082: private boolean withdrawn = false;
083:
084: /** item handle */
085: private String handle = null;
086:
087: /** inner item, if we really absolutely have to instantiate it */
088: private Item item;
089:
090: /**
091: * Construct a new browse item with the given context and the database id
092: *
093: * @param context the DSpace context
094: * @param id the database id of the item
095: * @param in_archive
096: * @param withdrawn
097: */
098: public BrowseItem(Context context, int id, boolean in_archive,
099: boolean withdrawn) {
100: this .context = context;
101: this .id = id;
102: this .in_archive = in_archive;
103: this .withdrawn = withdrawn;
104: }
105:
106: /**
107: * Get String array of metadata values matching the given parameters
108: *
109: * @param schema metadata schema
110: * @param element metadata element
111: * @param qualifier metadata qualifier
112: * @param lang metadata language
113: * @return array of matching values
114: * @throws SQLException
115: */
116: public DCValue[] getMetadata(String schema, String element,
117: String qualifier, String lang) throws SQLException {
118: try {
119: BrowseItemDAO dao = BrowseDAOFactory
120: .getItemInstance(context);
121:
122: // if the qualifier is a wildcard, we have to get it out of the
123: // database
124: if (Item.ANY.equals(qualifier)) {
125: return dao.queryMetadata(id, schema, element,
126: qualifier, lang);
127: }
128:
129: if (!metadata.isEmpty()) {
130: List values = new ArrayList();
131: Iterator i = metadata.iterator();
132:
133: while (i.hasNext()) {
134: DCValue dcv = (DCValue) i.next();
135:
136: if (match(schema, element, qualifier, lang, dcv)) {
137: values.add(dcv);
138: }
139: }
140:
141: if (values.isEmpty()) {
142: DCValue[] dcvs = dao.queryMetadata(id, schema,
143: element, qualifier, lang);
144: if (dcvs != null) {
145: Collections.addAll(metadata, dcvs);
146: }
147: return dcvs;
148: }
149:
150: // else, Create an array of matching values
151: DCValue[] valueArray = new DCValue[values.size()];
152: valueArray = (DCValue[]) values.toArray(valueArray);
153:
154: return valueArray;
155: } else {
156: DCValue[] dcvs = dao.queryMetadata(id, schema, element,
157: qualifier, lang);
158: if (dcvs != null) {
159: Collections.addAll(metadata, dcvs);
160: }
161: return dcvs;
162: }
163: } catch (BrowseException be) {
164: log.error("caught exception: ", be);
165: return null;
166: }
167: }
168:
169: /**
170: * Get the type of object. This object masquerates as an Item, so this
171: * returns the value of Constants.ITEM
172: *
173: *@return Constants.ITEM
174: */
175: public int getType() {
176: return Constants.ITEM;
177: }
178:
179: /**
180: * @deprecated
181: * @param real
182: * @return
183: */
184: public int getType(boolean real) {
185: if (!real) {
186: return Constants.ITEM;
187: } else {
188: return getType();
189: }
190: }
191:
192: /**
193: * get the database id of the item
194: *
195: * @return database id of item
196: */
197: public int getID() {
198: return id;
199: }
200:
201: /**
202: * Set the database id of the item
203: *
204: * @param id the database id of the item
205: */
206: public void setID(int id) {
207: this .id = id;
208: }
209:
210: /**
211: * Utility method for pattern-matching metadata elements. This
212: * method will return <code>true</code> if the given schema,
213: * element, qualifier and language match the schema, element,
214: * qualifier and language of the <code>DCValue</code> object passed
215: * in. Any or all of the elemenent, qualifier and language passed
216: * in can be the <code>Item.ANY</code> wildcard.
217: *
218: * @param schema
219: * the schema for the metadata field. <em>Must</em> match
220: * the <code>name</code> of an existing metadata schema.
221: * @param element
222: * the element to match, or <code>Item.ANY</code>
223: * @param qualifier
224: * the qualifier to match, or <code>Item.ANY</code>
225: * @param language
226: * the language to match, or <code>Item.ANY</code>
227: * @param dcv
228: * the Dublin Core value
229: * @return <code>true</code> if there is a match
230: */
231: private boolean match(String schema, String element,
232: String qualifier, String language, DCValue dcv) {
233: // We will attempt to disprove a match - if we can't we have a match
234: if (!element.equals(Item.ANY) && !element.equals(dcv.element)) {
235: // Elements do not match, no wildcard
236: return false;
237: }
238:
239: if (qualifier == null) {
240: // Value must be unqualified
241: if (dcv.qualifier != null) {
242: // Value is qualified, so no match
243: return false;
244: }
245: } else if (!qualifier.equals(Item.ANY)) {
246: // Not a wildcard, so qualifier must match exactly
247: if (!qualifier.equals(dcv.qualifier)) {
248: return false;
249: }
250: }
251:
252: if (language == null) {
253: // Value must be null language to match
254: if (dcv.language != null) {
255: // Value is qualified, so no match
256: return false;
257: }
258: } else if (!language.equals(Item.ANY)) {
259: // Not a wildcard, so language must match exactly
260: if (!language.equals(dcv.language)) {
261: return false;
262: }
263: } else if (!schema.equals(Item.ANY)) {
264: if (dcv.schema != null && !dcv.schema.equals(schema)) {
265: // The namespace doesn't match
266: return false;
267: }
268: }
269:
270: // If we get this far, we have a match
271: return true;
272: }
273:
274: /* (non-Javadoc)
275: * @see org.dspace.content.DSpaceObject#getHandle()
276: */
277: public String getHandle() {
278: // Get our Handle if any
279: if (this .handle == null) {
280: try {
281: this .handle = HandleManager.findHandle(context, this );
282: } catch (SQLException e) {
283: log.error("caught exception: ", e);
284: }
285: }
286: return this .handle;
287: }
288:
289: /**
290: * Get a thumbnail object out of the item.
291: *
292: * Warning: using this method actually instantiates an Item, which has a
293: * corresponding performance hit on the database during browse listing
294: * rendering. That's your own fault for wanting to put images on your
295: * browse page!
296: *
297: * @return
298: * @throws SQLException
299: */
300: public Thumbnail getThumbnail() throws SQLException {
301: // instantiate an item for this one. Not nice.
302: item = Item.find(context, id);
303:
304: if (item == null) {
305: return null;
306: }
307:
308: // now go sort out the thumbnail
309:
310: // if there's no original, there is no thumbnail
311: Bundle[] original = item.getBundles("ORIGINAL");
312: if (original.length == 0) {
313: return null;
314: }
315:
316: // if multiple bitstreams, check if the primary one is HTML
317: boolean html = false;
318: if (original[0].getBitstreams().length > 1) {
319: Bitstream[] bitstreams = original[0].getBitstreams();
320:
321: for (int i = 0; (i < bitstreams.length) && !html; i++) {
322: if (bitstreams[i].getID() == original[0]
323: .getPrimaryBitstreamID()) {
324: html = bitstreams[i].getFormat().getMIMEType()
325: .equals("text/html");
326: }
327: }
328: }
329:
330: // now actually pull out the thumbnail (ouch!)
331: Bundle[] thumbs = item.getBundles("THUMBNAIL");
332:
333: // if there are thumbs and we're not dealing with an HTML item
334: // then show the thumbnail
335: if ((thumbs.length > 0) && !html) {
336: Bitstream thumbnailBitstream;
337: Bitstream originalBitstream;
338:
339: if ((original[0].getBitstreams().length > 1)
340: && (original[0].getPrimaryBitstreamID() > -1)) {
341: originalBitstream = Bitstream.find(context, original[0]
342: .getPrimaryBitstreamID());
343: thumbnailBitstream = thumbs[0]
344: .getBitstreamByName(originalBitstream.getName()
345: + ".jpg");
346: } else {
347: originalBitstream = original[0].getBitstreams()[0];
348: thumbnailBitstream = thumbs[0].getBitstreams()[0];
349: }
350:
351: if ((thumbnailBitstream != null)
352: && (AuthorizeManager
353: .authorizeActionBoolean(context,
354: thumbnailBitstream, Constants.READ))) {
355: Thumbnail thumbnail = new Thumbnail(thumbnailBitstream,
356: originalBitstream);
357: return thumbnail;
358: }
359: }
360:
361: return null;
362: }
363:
364: public String getName() {
365: // FIXME: there is an exception handling problem here
366: try {
367: DCValue t[] = getMetadata("dc", "title", null, Item.ANY);
368: return (t.length >= 1) ? t[0].value : null;
369: } catch (SQLException sqle) {
370: log.error("caught exception: ", sqle);
371: return null;
372: }
373: }
374:
375: public boolean isArchived() {
376: return in_archive;
377: }
378:
379: public boolean isWithdrawn() {
380: return withdrawn;
381: }
382: }
|