KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > dspace > content > packager > AbstractMETSDisseminator


1 /*
2  * AbstractMETSDisseminator.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.packager;
42
43 import java.io.IOException JavaDoc;
44 import java.io.InputStream JavaDoc;
45 import java.io.OutputStream JavaDoc;
46 import java.sql.SQLException JavaDoc;
47 import java.util.ArrayList JavaDoc;
48 import java.util.Date JavaDoc;
49 import java.util.HashMap JavaDoc;
50 import java.util.Iterator JavaDoc;
51 import java.util.List JavaDoc;
52 import java.util.Map JavaDoc;
53 import java.util.zip.ZipEntry JavaDoc;
54 import java.util.zip.ZipOutputStream JavaDoc;
55
56 import org.apache.log4j.Logger;
57 import org.dspace.authorize.AuthorizeException;
58 import org.dspace.authorize.AuthorizeManager;
59 import org.dspace.content.Bitstream;
60 import org.dspace.content.Bundle;
61 import org.dspace.content.DSpaceObject;
62 import org.dspace.content.Item;
63 import org.dspace.content.crosswalk.CrosswalkException;
64 import org.dspace.content.crosswalk.DisseminationCrosswalk;
65 import org.dspace.core.ConfigurationManager;
66 import org.dspace.core.Constants;
67 import org.dspace.core.Context;
68 import org.dspace.core.PluginManager;
69 import org.dspace.core.Utils;
70 import org.jdom.Namespace;
71 import org.jdom.output.Format;
72 import org.jdom.output.XMLOutputter;
73
74 import edu.harvard.hul.ois.mets.Agent;
75 import edu.harvard.hul.ois.mets.AmdSec;
76 import edu.harvard.hul.ois.mets.Checksumtype;
77 import edu.harvard.hul.ois.mets.Div;
78 import edu.harvard.hul.ois.mets.DmdSec;
79 import edu.harvard.hul.ois.mets.FLocat;
80 import edu.harvard.hul.ois.mets.FileGrp;
81 import edu.harvard.hul.ois.mets.FileSec;
82 import edu.harvard.hul.ois.mets.Fptr;
83 import edu.harvard.hul.ois.mets.Loctype;
84 import edu.harvard.hul.ois.mets.MdWrap;
85 import edu.harvard.hul.ois.mets.Mdtype;
86 import edu.harvard.hul.ois.mets.Mets;
87 import edu.harvard.hul.ois.mets.MetsHdr;
88 import edu.harvard.hul.ois.mets.Name;
89 import edu.harvard.hul.ois.mets.Role;
90 import edu.harvard.hul.ois.mets.StructMap;
91 import edu.harvard.hul.ois.mets.TechMD;
92 import edu.harvard.hul.ois.mets.Type;
93 import edu.harvard.hul.ois.mets.XmlData;
94 import edu.harvard.hul.ois.mets.helper.MetsElement;
95 import edu.harvard.hul.ois.mets.helper.MetsException;
96 import edu.harvard.hul.ois.mets.helper.MetsValidator;
97 import edu.harvard.hul.ois.mets.helper.MetsWriter;
98 import edu.harvard.hul.ois.mets.helper.PCData;
99 import edu.harvard.hul.ois.mets.helper.PreformedXML;
100
101 /**
102  * Base class for disseminator of
103  * METS (Metadata Encoding & Transmission Standard) Package.<br>
104  * See <a HREF="http://www.loc.gov/standards/mets/">http://www.loc.gov/standards/mets/</a>
105  * <p>
106  * This is a generic packager framework intended to be subclassed to create
107  * packagers for more specific METS "profiles". METS is an
108  * abstract and flexible framework that can encompass many
109  * different kinds of metadata and inner package structures.
110  * <p>
111  * <b>Package Parameters:</b><br>
112  * <code>manifestOnly</code> -- if true, generate a standalone XML
113  * document of the METS manifest instead of a complete package. Any
114  * other metadata (such as licenses) will be encoded inline.
115  * Default is <code>false</code>.
116  *
117  * <code>unauthorized</code> -- this determines what is done when the
118  * packager encounters a Bundle or Bitstream it is not authorized to
119  * read. By default, it just quits with an AuthorizeException.
120  * If this option is present, it must be one of the following values:
121  * <code>skip</code> -- simply exclude unreadable content from package.
122  * <code>zero</code> -- include unreadable bitstreams as 0-length files;
123  * unreadable Bundles will still cause authorize errors.
124  *
125  * @author Larry Stone
126  * @author Robert Tansley
127  * @version $Revision: 1.1 $
128  */

129 public abstract class AbstractMETSDisseminator
130     implements PackageDisseminator
131 {
132     /** log4j category */
133     private static Logger log = Logger.getLogger(AbstractMETSDisseminator.class);
134
135     /** Filename of manifest, relative to package toplevel. */
136     public static final String JavaDoc MANIFEST_FILE = "mets.xml";
137
138     // JDOM xml output writer - indented format for readability.
139
private static XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
140
141     // for gensym()
142
private int idCounter = 1;
143
144     /**
145      * Table of files to add to package, such as mdRef'd metadata.
146      * Key is relative pathname of file, value is <code>InputStream</code>
147      * with contents to put in it.
148      * New map is created by disseminate().
149      */

150     protected Map JavaDoc extraFiles = null;
151
152     /**
153      * Make a new unique ID with specified prefix.
154      * @param prefix the prefix of the identifier, constrained to XML ID schema
155      * @return a new string identifier unique in this session (instance).
156      */

157     protected String JavaDoc gensym(String JavaDoc prefix)
158     {
159         return prefix + "_" + String.valueOf(idCounter++);
160     }
161
162     public String JavaDoc getMIMEType(PackageParameters params)
163     {
164         return (params != null && params.getProperty("manifestOnly") != null) ?
165                 "text/xml" : "application/zip";
166     }
167
168     /**
169      * Export the object (Item, Collection, or Community) to a
170      * package file on the indicated OutputStream.
171      * Gets an exception of the object cannot be packaged or there is
172      * a failure creating the package.
173      *
174      * @param context - DSpace context.
175      * @param dso - DSpace object (item, collection, etc)
176      * @param pkg - output stream on which to write package
177      * @throws PackageException if package cannot be created or there is
178      * a fatal error in creating it.
179      */

180     public void disseminate(Context context, DSpaceObject dso,
181                             PackageParameters params, OutputStream JavaDoc pkg)
182         throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException JavaDoc, IOException JavaDoc
183     {
184         if (dso.getType() == Constants.ITEM)
185         {
186             Item item = (Item)dso;
187             long lmTime = item.getLastModified().getTime();
188
189             // how to handle unauthorized bundle/bitstream:
190
String JavaDoc unauth = (params == null) ? null : params.getProperty("unauthorized");
191
192             if (params != null && params.getProperty("manifestOnly") != null)
193             {
194                 extraFiles = null;
195                 writeManifest(context, item, params, pkg);
196             }
197             else
198             {
199                 extraFiles = new HashMap JavaDoc();
200                 ZipOutputStream JavaDoc zip = new ZipOutputStream JavaDoc(pkg);
201                 zip.setComment("METS archive created by DSpace METSDisseminationCrosswalk");
202
203                 // write manifest first.
204
ZipEntry JavaDoc me = new ZipEntry JavaDoc(MANIFEST_FILE);
205                 me.setTime(lmTime);
206                 zip.putNextEntry(me);
207                 writeManifest(context, item, params, zip);
208                 zip.closeEntry();
209                 
210                 // copy extra (meta?) bitstreams into zip
211
Iterator JavaDoc fi = extraFiles.keySet().iterator();
212                 while (fi.hasNext())
213                 {
214                     String JavaDoc fname = (String JavaDoc)fi.next();
215                     ZipEntry JavaDoc ze = new ZipEntry JavaDoc(fname);
216                     ze.setTime(lmTime);
217                     zip.putNextEntry(ze);
218                     Utils.copy((InputStream JavaDoc)extraFiles.get(fname), zip);
219                     zip.closeEntry();
220                 }
221
222                 // copy all non-meta bitstreams into zip
223
Bundle bundles[] = item.getBundles();
224                 for (int i = 0; i < bundles.length; i++)
225                 {
226                     if (!PackageUtils.isMetaInfoBundle(bundles[i]))
227                     {
228                         // unauthorized bundle?
229
if (!AuthorizeManager.authorizeActionBoolean(context,
230                                     bundles[i], Constants.READ))
231                         {
232                             if (unauth != null &&
233                                 (unauth.equalsIgnoreCase("skip")))
234                             {
235                                 log.warn("Skipping Bundle[\""+bundles[i].getName()+"\"] because you are not authorized to read it.");
236                                 continue;
237                             }
238                             else
239                                 throw new AuthorizeException("Not authorized to read Bundle named \""+bundles[i].getName()+"\"");
240                         }
241                         Bitstream[] bitstreams = bundles[i].getBitstreams();
242                         for (int k = 0; k < bitstreams.length; k++)
243                         {
244                             boolean auth = AuthorizeManager.authorizeActionBoolean(context,
245                                     bitstreams[k], Constants.READ);
246                             if (auth ||
247                                 (unauth != null && unauth.equalsIgnoreCase("zero")))
248                             {
249                                 ZipEntry JavaDoc ze = new ZipEntry JavaDoc(
250                                     makeBitstreamName(bitstreams[k]));
251                                 ze.setTime(lmTime);
252                                 ze.setSize(auth ? bitstreams[k].getSize() : 0);
253                                 zip.putNextEntry(ze);
254                                 if (auth)
255                                 Utils.copy(bitstreams[k].retrieve(), zip);
256                                 else
257                                     log.warn("Adding zero-length file for Bitstream, SID="+String.valueOf(bitstreams[k].getSequenceID())+", not authorized for READ.");
258                                 zip.closeEntry();
259                             }
260                             else if (unauth != null &&
261                                      unauth.equalsIgnoreCase("skip"))
262                             {
263                                 log.warn("Skipping Bitstream, SID="+String.valueOf(bitstreams[k].getSequenceID())+", not authorized for READ.");
264                             }
265                             else
266                             {
267                                 throw new AuthorizeException("Not authorized to read Bitstream, SID="+String.valueOf(bitstreams[k].getSequenceID()));
268                             }
269                         }
270                     }
271                 }
272                 zip.close();
273                 extraFiles = null;
274             }
275
276         }
277         else
278             throw new PackageValidationException("Can only disseminate an Item now.");
279     }
280
281     /**
282      * Create name that bitstream will have in archive. Name must
283      * be unique and relative to archive top level, e.g. "bitstream_<id>.ext"
284      */

285     private String JavaDoc makeBitstreamName(Bitstream bitstream)
286     {
287         String JavaDoc base = "bitstream_"+String.valueOf(bitstream.getID());
288         String JavaDoc ext[] = bitstream.getFormat().getExtensions();
289         return (ext.length > 0) ? base+"."+ext[0] : base;
290     }
291
292
293     // set metadata type - if Mdtype.parse() gets exception,
294
// that means it's not in the MDTYPE vocabulary, so use OTHER.
295
private void setMdType(MdWrap mdWrap, String JavaDoc mdtype)
296     {
297         try
298         {
299             mdWrap.setMDTYPE(Mdtype.parse(mdtype));
300         }
301         catch (MetsException e)
302         {
303             mdWrap.setMDTYPE(Mdtype.OTHER);
304             mdWrap.setOTHERMDTYPE(mdtype);
305         }
306     }
307
308     /**
309      * Write out a METS manifest.
310      * Mostly lifted from Rob Tansley's METS exporter.
311      */

312     private void writeManifest(Context context, Item item,
313                                PackageParameters params, OutputStream JavaDoc out)
314         throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException JavaDoc, IOException JavaDoc
315
316     {
317         try
318         {
319             // Create the METS file
320
Mets mets = new Mets();
321          
322             // Top-level stuff
323
mets.setID(gensym("mets"));
324             mets.setOBJID("hdl:" + item.getHandle());
325             mets.setLABEL("DSpace Item");
326             mets.setPROFILE(getProfile());
327          
328             // MetsHdr
329
MetsHdr metsHdr = new MetsHdr();
330             metsHdr.setCREATEDATE(new Date JavaDoc()); // FIXME: CREATEDATE is now:
331
// maybe should be item create
332
// date?
333

334             // Agent
335
Agent agent = new Agent();
336             agent.setROLE(Role.CUSTODIAN);
337             agent.setTYPE(Type.ORGANIZATION);
338             Name name = new Name();
339             name.getContent()
340                     .add(new PCData(ConfigurationManager
341                                     .getProperty("dspace.name")));
342             agent.getContent().add(name);
343             metsHdr.getContent().add(agent);
344             mets.getContent().add(metsHdr);
345          
346             // add DMD sections
347
// Each type element MAY be either just a MODS-and-crosswalk name, OR
348
// a combination "MODS-name:crosswalk-name" (e.g. "DC:qDC").
349
String JavaDoc dmdTypes[] = getDmdTypes(params);
350
351             // record of ID of each dmdsec to make DMDID in structmap.
352
String JavaDoc dmdGroup = gensym("dmd_group");
353             String JavaDoc dmdId[] = new String JavaDoc[dmdTypes.length];
354             for (int i = 0; i < dmdTypes.length; ++i)
355             {
356                 dmdId[i] = gensym("dmd");
357                 XmlData xmlData = new XmlData();
358                 String JavaDoc xwalkName, metsName;
359                 String JavaDoc parts[] = dmdTypes[i].split(":", 2);
360                 if (parts.length > 1)
361                 {
362                     metsName = parts[0];
363                     xwalkName = parts[1];
364                 }
365                 else
366                     xwalkName = metsName = dmdTypes[i];
367
368                 DisseminationCrosswalk xwalk = (DisseminationCrosswalk)
369                   PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName);
370                 if (xwalk == null)
371                     throw new PackageValidationException("Cannot find "+dmdTypes[i]+" crosswalk plugin!");
372                 else
373                     crosswalkToMets(xwalk, item, xmlData);
374
375                 DmdSec dmdSec = new DmdSec();
376                 dmdSec.setID(dmdId[i]);
377                 dmdSec.setGROUPID(dmdGroup);
378                 MdWrap mdWrap = new MdWrap();
379                 setMdType(mdWrap, metsName);
380                 mdWrap.getContent().add(xmlData);
381                 dmdSec.getContent().add(mdWrap);
382                 mets.getContent().add(dmdSec);
383             }
384          
385             // Only add license AMD section if there are any licenses.
386
// Catch authorization failures accessing license bitstreams
387
// only if we are skipping unauthorized bitstreams.
388
String JavaDoc licenseID = null;
389             try
390             {
391             AmdSec amdSec = new AmdSec();
392             addRightsMd(context, item, amdSec);
393             if (amdSec.getContent().size() > 0)
394             {
395                 licenseID = gensym("license");
396                 amdSec.setID(licenseID);
397                 mets.getContent().add(amdSec);
398             }
399             }
400             catch (AuthorizeException e)
401             {
402                 String JavaDoc unauth = (params == null) ? null : params.getProperty("unauthorized");
403                 if (!(unauth != null && unauth.equalsIgnoreCase("skip")))
404                     throw e;
405                 else
406                     log.warn("Skipping license metadata because of access failure: "+e.toString());
407             }
408
409             // FIXME: History data???? Nooooo!!!!
410

411             // fileSec - all non-metadata bundles go into fileGrp,
412
// and each bitstream therein into a file.
413
// Create the bitstream-level techMd and div's for structmap
414
// at the same time so we can connec the IDREFs to IDs.
415
FileSec fileSec = new FileSec();
416          
417             String JavaDoc techMdType = getTechMdType(params);
418             String JavaDoc parts[] = techMdType.split(":", 2);
419             String JavaDoc xwalkName, metsName;
420             if (parts.length > 1)
421             {
422                 metsName = parts[0];
423                 xwalkName = parts[1];
424             }
425             else
426                 xwalkName = metsName = techMdType;
427
428             DisseminationCrosswalk xwalk = (DisseminationCrosswalk)
429               PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName);
430             if (xwalk == null)
431                 throw new PackageValidationException("Cannot find "+xwalkName+" crosswalk plugin!");
432
433             // log the primary bitstream for structmap
434
String JavaDoc primaryBitstreamFileID = null;
435
436             // accumulate content DIV items to put in structMap later.
437
List JavaDoc contentDivs = new ArrayList JavaDoc();
438
439             // how to handle unauthorized bundle/bitstream:
440
String JavaDoc unauth = (params == null) ? null : params.getProperty("unauthorized");
441
442             Bundle[] bundles = item.getBundles();
443             for (int i = 0; i < bundles.length; i++)
444             {
445                 if (PackageUtils.isMetaInfoBundle(bundles[i]))
446                     continue;
447
448                 // unauthorized bundle?
449
// NOTE: This must match the logic in disseminate()
450
if (!AuthorizeManager.authorizeActionBoolean(context,
451                             bundles[i], Constants.READ))
452                 {
453                     if (unauth != null &&
454                         (unauth.equalsIgnoreCase("skip")))
455                         continue;
456                     else
457                         throw new AuthorizeException("Not authorized to read Bundle named \""+bundles[i].getName()+"\"");
458                 }
459
460                 Bitstream[] bitstreams = bundles[i].getBitstreams();
461
462                 // Create a fileGrp
463
FileGrp fileGrp = new FileGrp();
464          
465                 // Bundle name for USE attribute
466
String JavaDoc bName = bundles[i].getName();
467                 if ((bName != null) && !bName.equals(""))
468                     fileGrp.setUSE(bundleToFileGrp(bName));
469          
470                 // watch for primary bitstream
471
int primaryBitstreamID = -1;
472                 boolean isContentBundle = false;
473                 if ((bName != null) && bName.equals("ORIGINAL"))
474                 {
475                     isContentBundle = true;
476                     primaryBitstreamID = bundles[i].getPrimaryBitstreamID();
477                 }
478
479                 for (int bits = 0; bits < bitstreams.length; bits++)
480                 {
481                     // Check for authorization. Handle unauthorized
482
// bitstreams to match the logic in disseminate(),
483
// i.e. "unauth=zero" means include a 0-length bitstream,
484
// "unauth=skip" means to ignore it (and exclude from
485
// manifest).
486
boolean auth = AuthorizeManager.authorizeActionBoolean(context,
487                             bitstreams[bits], Constants.READ);
488                     if (!auth)
489                     {
490                         if (unauth != null && unauth.equalsIgnoreCase("skip"))
491                             continue;
492                         else if (!(unauth != null && unauth.equalsIgnoreCase("zero")))
493                             throw new AuthorizeException("Not authorized to read Bitstream, SID="+String.valueOf(bitstreams[bits].getSequenceID()));
494                     }
495
496                     String JavaDoc sid = String.valueOf(bitstreams[bits].getSequenceID());
497          
498                     edu.harvard.hul.ois.mets.File file = new edu.harvard.hul.ois.mets.File();
499          
500                     String JavaDoc xmlIDstart = "bitstream_";
501                     String JavaDoc fileID = xmlIDstart + sid;
502
503                     file.setID(fileID);
504
505                     // log primary bitstream for later (structMap)
506
if (bitstreams[bits].getID() == primaryBitstreamID)
507                         primaryBitstreamFileID = fileID;
508
509                     // if this is content, add to structmap too:
510
if (isContentBundle)
511                     {
512                         Div div = new Div();
513                         div.setID(gensym("div"));
514                         div.setTYPE("DSpace Content Bitstream");
515                         Fptr fptr = new Fptr();
516                         fptr.setFILEID(fileID);
517                         div.getContent().add(fptr);
518                         contentDivs.add(div);
519                     }
520
521                     file.setSEQ(bitstreams[bits].getSequenceID());
522          
523                     String JavaDoc groupID = "GROUP_" + xmlIDstart + sid;
524          
525                     /*
526                      * If we're in THUMBNAIL or TEXT bundles, the bitstream is
527                      * extracted text or a thumbnail, so we use the name to work
528                      * out which bitstream to be in the same group as
529                      */

530                     if ((bundles[i].getName() != null)
531                             && (bundles[i].getName().equals("THUMBNAIL") ||
532                                 bundles[i].getName().startsWith("TEXT")))
533                     {
534                         // Try and find the original bitstream, and chuck the
535
// derived bitstream in the same group
536
Bitstream original = findOriginalBitstream(item,
537                                 bitstreams[bits]);
538          
539                         if (original != null)
540                         {
541                             groupID = "GROUP_" + xmlIDstart
542                                     + original.getSequenceID();
543                         }
544                     }
545          
546                     file.setGROUPID(groupID);
547                     file.setMIMETYPE(bitstreams[bits].getFormat().getMIMEType());
548          
549                     // FIXME: CREATED: no date
550

551                     file.setSIZE(auth ? bitstreams[bits].getSize() : 0);
552
553                     // translate checksum and type to METS, if available.
554
String JavaDoc csType = bitstreams[bits].getChecksumAlgorithm();
555                     String JavaDoc cs = bitstreams[bits].getChecksum();
556                     if (auth && cs != null && csType != null)
557                     {
558                         try
559                         {
560                             file.setCHECKSUMTYPE(Checksumtype.parse(csType));
561                             file.setCHECKSUM(cs);
562                         }
563                         catch (MetsException e)
564                         {
565                             log.warn("Cannot set bitstream checksum type="+csType+" in METS.");
566                         }
567                     }
568          
569                     // FLocat: filename is MD5 checksum
570
FLocat flocat = new FLocat();
571                     flocat.setLOCTYPE(Loctype.URL);
572                     flocat.setXlinkHref(makeBitstreamName(bitstreams[bits]));
573
574                     // Make bitstream techMD metadata, add to file.
575
String JavaDoc techID = "techMd_for_bitstream_"+bitstreams[bits].getSequenceID();
576                     AmdSec fAmdSec = new AmdSec();
577                     fAmdSec.setID(techID);
578                     TechMD techMd = new TechMD();
579                     techMd.setID(gensym("tech"));
580                     MdWrap mdWrap = new MdWrap();
581                     setMdType(mdWrap, metsName);
582                     XmlData xmlData = new XmlData();
583                     mdWrap.getContent().add(xmlData);
584                     techMd.getContent().add(mdWrap);
585                     fAmdSec.getContent().add(techMd);
586                     mets.getContent().add(fAmdSec);
587                     crosswalkToMets(xwalk, bitstreams[bits], xmlData);
588                     file.setADMID(techID);
589
590                     // Add FLocat to File, and File to FileGrp
591
file.getContent().add(flocat);
592                     fileGrp.getContent().add(file);
593                 }
594          
595                 // Add fileGrp to fileSec
596
fileSec.getContent().add(fileGrp);
597             }
598          
599             // Add fileSec to document
600
mets.getContent().add(fileSec);
601          
602             // Create simple structMap: initial div represents the Item,
603
// and user-visible content bitstreams are in its child divs.
604
StringBuffer JavaDoc dmdIds = new StringBuffer JavaDoc();
605             for (int i = 0; i < dmdId.length; ++i)
606                 dmdIds.append(" "+dmdId[i]);
607             StructMap structMap = new StructMap();
608             structMap.setID(gensym("struct"));
609             structMap.setTYPE("LOGICAL");
610             structMap.setLABEL("DSpace");
611             Div div0 = new Div();
612             div0.setID(gensym("div"));
613             div0.setTYPE("DSpace Item");
614             div0.setDMDID(dmdIds.substring(1));
615             if (licenseID != null)
616                 div0.setADMID(licenseID);
617
618             // if there is a primary bitstream, add FPTR to it.
619
if (primaryBitstreamFileID != null)
620             {
621                 Fptr fptr = new Fptr();
622                 fptr.setFILEID(primaryBitstreamFileID);
623                 div0.getContent().add(fptr);
624             }
625
626             // add DIV for each content bitstream
627
div0.getContent().addAll(contentDivs);
628
629             structMap.getContent().add(div0);
630
631             // Does subclass have something to add to structMap?
632
addStructMap(context, item, params, mets);
633
634             mets.getContent().add(structMap);
635
636             mets.validate(new MetsValidator());
637          
638             mets.write(new MetsWriter(out));
639         }
640         catch (MetsException e)
641         {
642             // We don't pass up a MetsException, so callers don't need to
643
// know the details of the METS toolkit
644
// e.printStackTrace();
645
throw new PackageValidationException(e);
646         }
647     }
648
649
650     /**
651      * For a bitstream that's a thumbnail or extracted text, find the
652      * corresponding bitstream it was derived from, in the ORIGINAL bundle.
653      *
654      * @param item
655      * the item we're dealing with
656      * @param derived
657      * the derived bitstream
658      *
659      * @return the corresponding original bitstream (or null)
660      */

661     protected static Bitstream findOriginalBitstream(Item item, Bitstream derived)
662         throws SQLException JavaDoc
663     {
664         Bundle[] bundles = item.getBundles();
665
666         // Filename of original will be filename of the derived bitstream
667
// minus the extension (last 4 chars - .jpg or .txt)
668
String JavaDoc originalFilename = derived.getName().substring(0,
669                 derived.getName().length() - 4);
670
671         // First find "original" bundle
672
for (int i = 0; i < bundles.length; i++)
673         {
674             if ((bundles[i].getName() != null)
675                     && bundles[i].getName().equals("ORIGINAL"))
676             {
677                 // Now find the corresponding bitstream
678
Bitstream[] bitstreams = bundles[i].getBitstreams();
679
680                 for (int bsnum = 0; bsnum < bitstreams.length; bsnum++)
681                 {
682                     if (bitstreams[bsnum].getName().equals(originalFilename))
683                     {
684                         return bitstreams[bsnum];
685                     }
686                 }
687             }
688         }
689
690         // Didn't find it
691
return null;
692     }
693
694     // Get result from crosswalk plugin and add it to the document,
695
// including namespaces and schema.
696
private void crosswalkToMets(DisseminationCrosswalk xwalk,
697                                  DSpaceObject dso, MetsElement me)
698         throws CrosswalkException,
699                IOException JavaDoc, SQLException JavaDoc, AuthorizeException
700     {
701         // add crosswalk's namespaces and schemaLocation to this element:
702
String JavaDoc raw = xwalk.getSchemaLocation();
703         String JavaDoc sloc[] = raw == null ? null : raw.split("\\s+");
704         Namespace ns[] = xwalk.getNamespaces();
705         for (int i = 0; i < ns.length; ++i)
706         {
707             String JavaDoc uri = ns[i].getURI();
708             if (sloc != null && sloc.length > 1 && uri.equals(sloc[0]))
709                 me.setSchema(ns[i].getPrefix(), uri, sloc[1]);
710             else
711                 me.setSchema(ns[i].getPrefix(), uri);
712         }
713
714         // add result of crosswalk
715
PreformedXML pXML =
716           new PreformedXML(
717             xwalk.preferList() ?
718               outputter.outputString(xwalk.disseminateList(dso)) :
719               outputter.outputString(xwalk.disseminateElement(dso)));
720         me.getContent().add(pXML);
721     }
722
723     /**
724      * Returns name of METS profile to which this package conforms, e.g.
725      * "DSpace METS DIP Profile 1.0"
726      * @return string name of profile.
727      */

728     abstract public String JavaDoc getProfile();
729
730     /**
731      * Returns fileGrp's USE attribute value corresponding to a DSpace bundle name.
732      *
733      * @param bname name of DSpace bundle.
734      * @return string name of fileGrp
735      */

736     abstract public String JavaDoc bundleToFileGrp(String JavaDoc bname);
737
738     /**
739      * Get the types of Item-wide DMD to include in package.
740      * Each element of the returned array is a String, which
741      * MAY be just a simple name, naming both the Crosswalk Plugin and
742      * the METS "MDTYPE", <em>or</em> a colon-separated pair consisting of
743      * the METS name followed by a colon and the Crosswalk Plugin name.
744      * E.g. the type string <code>"DC:qualifiedDublinCore"</code> tells it to
745      * create a METS section with <code>MDTYPE="DC"</code> and use the plugin
746      * named "qualifiedDublinCore" to obtain the data.
747      * @param params the PackageParameters passed to the disseminator.
748      * @return array of metadata type strings, never null.
749      */

750     abstract public String JavaDoc [] getDmdTypes(PackageParameters params)
751         throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException;
752
753     /**
754      * Get the type string of the technical metadata to create for each
755      * Bitstream in the Item. The type string may be a simple name or
756      * colon-separated compound as specified for <code>getDmdTypes()</code> above.
757      * @param params the PackageParameters passed to the disseminator.
758      * @return array of metadata type strings, never null.
759      */

760     abstract public String JavaDoc getTechMdType(PackageParameters params)
761         throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException;
762
763     /**
764      * Add Rights metadata for the Item, in the form of
765      * (<code>rightsMd</code> elements) to the given metadata section.
766      *
767      */

768     abstract public void addRightsMd(Context context, Item item, AmdSec amdSec)
769         throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException, MetsException;
770
771     /**
772      * Add any additional <code>structMap</code> elements to the
773      * METS document, as required by this subclass. A simple default
774      * structure map which fulfills the minimal DSpace METS DIP/SIP
775      * requirements is already present, so this does not need to do anything.
776      * @param mets the METS document to which to add structMaps
777      */

778     abstract public void addStructMap(Context context, Item item,
779                                PackageParameters params, Mets mets)
780         throws SQLException JavaDoc, IOException JavaDoc, AuthorizeException, MetsException;
781 }
782
Popular Tags