KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dspace > content > crosswalk > PREMISCrosswalk


1 /*
2  * PREMISCrosswalk.java
3  *
4  * Version: $Revision: 1.1 $
5  *
6  * Date: $Date: 2006/03/17 00:04:38 $
7  *
8  * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts
9  * Institute of Technology. All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions are
13  * met:
14  *
15  * - Redistributions of source code must retain the above copyright
16  * notice, this list of conditions and the following disclaimer.
17  *
18  * - Redistributions in binary form must reproduce the above copyright
19  * notice, this list of conditions and the following disclaimer in the
20  * documentation and/or other materials provided with the distribution.
21  *
22  * - Neither the name of the Hewlett-Packard Company nor the name of the
23  * Massachusetts Institute of Technology nor the names of their
24  * contributors may be used to endorse or promote products derived from
25  * this software without specific prior written permission.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
30  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
31  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
32  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
33  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
34  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
35  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36  * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
38  * DAMAGE.
39  */

40
41 package org.dspace.content.crosswalk;
42
43 import java.io.IOException JavaDoc;
44 import java.sql.SQLException JavaDoc;
45 import java.util.Iterator JavaDoc;
46 import java.util.List JavaDoc;
47 import java.util.ArrayList JavaDoc;
48 import java.util.Properties JavaDoc;
49 import java.util.Enumeration JavaDoc;
50 import java.net.URLEncoder JavaDoc;
51
52 import java.sql.SQLException JavaDoc;
53
54 import org.apache.log4j.Logger;
55
56 import org.dspace.core.Context;
57 import org.dspace.core.Constants;
58 import org.dspace.core.ConfigurationManager;
59 import org.dspace.content.Bitstream;
60 import org.dspace.content.BitstreamFormat;
61 import org.dspace.content.FormatIdentifier;
62 import org.dspace.content.Bundle;
63 import org.dspace.content.Item;
64 import org.dspace.content.DSpaceObject;
65 import org.dspace.authorize.AuthorizeException;
66
67 import org.jdom.*;
68
69 /**
70  * PREMIS Crosswalk
71  * <p>
72  * Translate between DSpace Bitstream properties and PREMIS metadata format
73  * (see <a HREF="http://www.oclc.org/research/projects/pmwg/">
74  * http://www.oclc.org/research/projects/pmwg/</a> for details).
75  * This is intended to implement the requirements of the DSpace METS SIP
76  * specification for both ingest and dissemination.
77  *
78  * @author Larry Stone
79  * @version $Revision: 1.1 $
80  */

81 public class PREMISCrosswalk
82     implements IngestionCrosswalk, DisseminationCrosswalk
83 {
84     /** log4j category */
85     private static Logger log = Logger.getLogger(PREMISCrosswalk.class);
86
87     private static final Namespace PREMIS_NS =
88         Namespace.getNamespace("premis", "http://www.loc.gov/standards/premis");
89
90     // XML schemaLocation fragment for this crosswalk, from config.
91
private String JavaDoc schemaLocation =
92         PREMIS_NS.getURI()+" http://www.loc.gov/standards/premis/PREMIS-v1-0.xsd";
93
94     private static final Namespace XLINK_NS =
95         Namespace.getNamespace("xlink", "http://www.w3.org/TR/xlink");
96
97     private static final Namespace namespaces[] = { PREMIS_NS };
98
99     /*----------- Submission functions -------------------*/
100
101     public void ingest(Context context, DSpaceObject dso, Element root)
102         throws CrosswalkException, IOException JavaDoc, SQLException JavaDoc, AuthorizeException
103     {
104         if (!(root.getName().equals("premis")))
105             throw new MetadataValidationException("Wrong root element for PREMIS: "+root.toString());
106         ingest(context, dso, root.getChildren());
107     }
108
109     public void ingest(Context context, DSpaceObject dso, List JavaDoc ml)
110         throws CrosswalkException, IOException JavaDoc, SQLException JavaDoc, AuthorizeException
111     {
112         // we only understand how to crosswalk PREMIS to a Bitstream.
113
if (dso.getType() != Constants.BITSTREAM)
114             throw new CrosswalkObjectNotSupported("Wrong target object type, PREMISCrosswalk can only crosswalk to a Bitstream.");
115
116         Bitstream bitstream = (Bitstream)dso;
117         String JavaDoc MIMEType = null;
118         String JavaDoc bsName = null;
119         Iterator JavaDoc mi = ml.iterator();
120         while (mi.hasNext())
121         {
122             Element me = (Element)mi.next();
123
124             // if we're fed a <premis> wrapper object, recurse on its guts:
125
if (me.getName().equals("premis"))
126                 ingest(context, dso, me.getChildren());
127
128             // "object" section:
129
else if (me.getName().equals("object"))
130             {
131                 // originalName becomes new bitstream source and (default) name
132
Element on = me.getChild("originalName", PREMIS_NS);
133                 if (on != null)
134                     bsName = on.getTextTrim();
135
136                 // Reconcile technical metadata with bitstream content;
137
// check that length and message digest (checksum) match.
138
// XXX FIXME: wait for Checksum Checker code to add better test.
139
Element oc = me.getChild("objectCharacteristics", PREMIS_NS);
140                 if (oc != null)
141                 {
142                     String JavaDoc ssize = oc.getChildTextTrim("size", PREMIS_NS);
143                     if (ssize != null)
144                     {
145                         try
146                         {
147                             int size = Integer.parseInt(ssize);
148                             if (bitstream.getSize() != size)
149                                 throw new MetadataValidationException(
150                                  "Bitstream size ("+String.valueOf(bitstream.getSize())+
151                                  ") does not match size in PREMIS ("+ssize+"), rejecting it.");
152                         }
153                         catch (NumberFormatException JavaDoc ne)
154                         {
155                             throw new MetadataValidationException("Bad number value in PREMIS object/objectCharacteristics/size: "+ssize, ne);
156                         }
157                     }
158                     Element fixity = oc.getChild("fixity", PREMIS_NS);
159                     if (fixity != null)
160                     {
161                         String JavaDoc alg = fixity.getChildTextTrim("messageDigestAlgorithm", PREMIS_NS);
162                         String JavaDoc md = fixity.getChildTextTrim("messageDigest", PREMIS_NS);
163                         String JavaDoc b_alg = bitstream.getChecksumAlgorithm();
164                         String JavaDoc b_md = bitstream.getChecksum();
165                         if (alg != null && md != null &&
166                             b_alg != null && b_md != null &&
167                             alg.equals(b_alg))
168                         {
169                             if (md.equals(b_md))
170                                 log.debug("Bitstream checksum agrees with PREMIS: "+bitstream.getName());
171                             else
172                                 throw new MetadataValidationException("Bitstream "+alg+" Checksum does not match value in PREMIS ("+b_md+" != "+md+"), for bitstream: "+bitstream.getName());
173                         }
174                         else
175                             log.warn("Cannot test checksum on bitstream="+bitstream.getName()+
176                                      ", algorithm in PREMIS is different: "+alg);
177                     }
178
179                     // Look for formatDesignation/formatName, which is
180
// MIME Type. Match with DSpace bitstream format.
181
Element format = oc.getChild("format", PREMIS_NS);
182                     if (format != null)
183                     {
184                         Element fd = format.getChild("formatDesignation", PREMIS_NS);
185                         if (fd != null)
186                             MIMEType = fd.getChildTextTrim("formatName", PREMIS_NS);
187                     }
188                 }
189
190                 // Apply new bitstream name if we found it.
191
if (bsName != null)
192                 {
193                     bitstream.setName(bsName);
194                     log.debug("Changing bitstream id="+String.valueOf(bitstream.getID())+"name and source to: "+bsName);
195                 }
196
197                 // reconcile bitstream format; if there's a MIMEtype,
198
// get it from that, otherwise try to divine from file extension
199
// (guessFormat() looks at bitstream Name, which we just set)
200
BitstreamFormat bf = (MIMEType == null) ? null :
201                         BitstreamFormat.findByMIMEType(context, MIMEType);
202                 if (bf == null)
203                     bf = FormatIdentifier.guessFormat(context, bitstream);
204                 if (bf != null)
205                     bitstream.setFormat(bf);
206             }
207             else
208                 log.debug("Skipping element: "+me.toString());
209         }
210         bitstream.update();
211     }
212
213     /*----------- Dissemination functions -------------------*/
214
215     public Namespace[] getNamespaces()
216     {
217         return namespaces;
218     }
219
220     public String JavaDoc getSchemaLocation()
221     {
222         return schemaLocation;
223     }
224
225     public boolean canDisseminate(DSpaceObject dso)
226     {
227         return true;
228     }
229
230     public Element disseminateElement(DSpaceObject dso)
231         throws CrosswalkException,
232                IOException JavaDoc, SQLException JavaDoc, AuthorizeException
233     {
234         if (dso.getType() != Constants.BITSTREAM)
235             throw new CrosswalkObjectNotSupported("PREMISCrosswalk can only crosswalk a Bitstream.");
236         Bitstream bitstream = (Bitstream)dso;
237
238         Element premis = new Element("premis", PREMIS_NS);
239         Element object = new Element("object", PREMIS_NS);
240         premis.addContent(object);
241
242         // objectIdentifier is required
243
Element oid = new Element("objectIdentifier", PREMIS_NS);
244         Element oit = new Element("objectIdentifierType", PREMIS_NS);
245         oit.setText("URL");
246         oid.addContent(oit);
247         Element oiv = new Element("objectIdentifierValue", PREMIS_NS);
248
249         // objectIdentifier value: by preference, if available:
250
// a. DSpace "persistent" URL to bitstream, if components available.
251
// b. name of bitstream, if any
252
// c. made-up name based on sequence ID and extension.
253
String JavaDoc sid = String.valueOf(bitstream.getSequenceID());
254         String JavaDoc baseUrl = ConfigurationManager.getProperty("dspace.url");
255         String JavaDoc handle = null;
256         // get handle of parent Item of this bitstream, if there is one:
257
Bundle[] bn = bitstream.getBundles();
258         if (bn.length > 0)
259         {
260             Item bi[] = bn[0].getItems();
261             if (bi.length > 0)
262                 handle = bi[0].getHandle();
263         }
264         // get or make up name for bitstream:
265
String JavaDoc bsName = bitstream.getName();
266         if (bsName == null)
267         {
268             String JavaDoc ext[] = bitstream.getFormat().getExtensions();
269             bsName = "bitstream_"+sid+ (ext.length > 0 ? ext[0] : "");
270         }
271         if (handle != null && baseUrl != null)
272             oiv.setText(baseUrl
273                     + "/bitstream/"
274                     + URLEncoder.encode(handle, "UTF-8")
275                     + "/"
276                     + sid
277                     + "/"
278                     + URLEncoder.encode(bsName, "UTF-8"));
279         else
280             oiv.setText(URLEncoder.encode(bsName, "UTF-8"));
281
282         oid.addContent(oiv);
283         object.addContent(oid);
284
285         // objectCategory is fixed value, "File".
286
Element oc = new Element("objectCategory", PREMIS_NS);
287         oc.setText("File");
288         object.addContent(oc);
289
290         Element ochar = new Element("objectCharacteristics", PREMIS_NS);
291         object.addContent(ochar);
292
293         // checksum if available
294
String JavaDoc cks = bitstream.getChecksum();
295         String JavaDoc cka = bitstream.getChecksumAlgorithm();
296         if (cks != null && cka != null)
297         {
298             Element fixity = new Element("fixity", PREMIS_NS);
299             Element mda = new Element("messageDigestAlgorithm", PREMIS_NS);
300             mda.setText(cka);
301             fixity.addContent(mda);
302             Element md = new Element("messageDigest", PREMIS_NS);
303             md.setText(cks);
304             fixity.addContent(md);
305             ochar.addContent(fixity);
306         }
307
308         // size
309
Element size = new Element("size", PREMIS_NS);
310         size.setText(String.valueOf(bitstream.getSize()));
311         ochar.addContent(size);
312
313         // Punt and set formatName to the MIME type; the best we can
314
// do for now in the absence of any usable global format registries.
315
// objectCharacteristics/format/formatDesignation/
316
// formatName <- MIME Type
317
//
318
Element format = new Element("format", PREMIS_NS);
319         Element formatDes = new Element("formatDesignation", PREMIS_NS);
320         Element formatName = new Element("formatName", PREMIS_NS);
321         formatName.setText(bitstream.getFormat().getMIMEType());
322         formatDes.addContent(formatName);
323         format.addContent(formatDes);
324         ochar.addContent(format);
325
326         // originalName <- name (or source if none)
327
String JavaDoc oname = bitstream.getName();
328         if (oname == null)
329             oname = bitstream.getSource();
330         if (oname != null)
331         {
332             Element on = new Element("originalName", PREMIS_NS);
333             on.setText(oname);
334             object.addContent(on);
335         }
336
337         return premis;
338     }
339
340     public List JavaDoc disseminateList(DSpaceObject dso)
341         throws CrosswalkException,
342                IOException JavaDoc, SQLException JavaDoc, AuthorizeException
343     {
344         List JavaDoc result = new ArrayList JavaDoc(1);
345         result.add(disseminateElement(dso));
346         return result;
347     }
348
349     public boolean preferList()
350     {
351         return false;
352     }
353 }
354
Popular Tags