1 40 41 package org.dspace.content.packager; 42 43 import java.io.IOException ; 44 import java.io.InputStream ; 45 import java.sql.SQLException ; 46 import java.util.HashMap ; 47 import java.util.HashSet ; 48 import java.util.Iterator ; 49 import java.util.List ; 50 import java.util.Map ; 51 import java.util.Set ; 52 import java.util.zip.ZipEntry ; 53 import java.util.zip.ZipInputStream ; 54 55 import org.apache.log4j.Logger; 56 import org.dspace.app.mediafilter.MediaFilter; 57 import org.dspace.authorize.AuthorizeException; 58 import org.dspace.content.Bitstream; 59 import org.dspace.content.BitstreamFormat; 60 import org.dspace.content.Bundle; 61 import org.dspace.content.Collection; 62 import org.dspace.content.FormatIdentifier; 63 import org.dspace.content.Item; 64 import org.dspace.content.WorkspaceItem; 65 import org.dspace.content.crosswalk.CrosswalkException; 66 import org.dspace.content.crosswalk.MetadataValidationException; 67 import org.dspace.core.ConfigurationManager; 68 import org.dspace.core.Constants; 69 import org.dspace.core.Context; 70 import org.dspace.core.LogManager; 71 import org.dspace.core.PluginManager; 72 import org.jdom.Element; 73 74 94 public abstract class AbstractMETSIngester 95 implements PackageIngester 96 { 97 98 private static Logger log = Logger.getLogger(AbstractMETSIngester.class); 99 100 101 public static final String MANIFEST_FILE = "mets.xml"; 102 103 private static final String MANIFEST_BITSTREAM_FORMAT = 105 "DSpace METS SIP"; 106 107 private static final boolean preserveManifest = 109 ConfigurationManager.getBooleanProperty("mets.submission.preserveManifest", false); 110 111 121 protected class MdrefManager 122 implements METSManifest.Mdref 123 { 124 private Bundle mdBundle = null; 125 126 private MdrefManager(Bundle mdBundle) 128 { 129 super(); 130 this.mdBundle = mdBundle; 131 } 132 133 139 public Bitstream getBitstreamForMdRef(Element mdref) 140 throws MetadataValidationException, IOException , SQLException , AuthorizeException 141 { 142 String path = METSManifest.getFileName(mdref); 143 if (mdBundle == null) 144 throw new MetadataValidationException("Failed referencing mdRef element, because there were no metadata files."); 145 return mdBundle.getBitstreamByName(path); 146 } 147 148 155 public InputStream getInputStream(Element mdref) 156 throws MetadataValidationException, IOException , SQLException , AuthorizeException 157 { 158 Bitstream mdbs = getBitstreamForMdRef(mdref); 159 if (mdbs == null) 160 throw new MetadataValidationException("Failed dereferencing bitstream for mdRef element="+mdref.toString()); 161 return mdbs.retrieve(); 162 } 163 } 164 165 179 public WorkspaceItem ingest(Context context, Collection collection, 180 InputStream pkg, PackageParameters params, 181 String license) 182 throws PackageValidationException, CrosswalkException, 183 AuthorizeException, SQLException , IOException 184 { 185 ZipInputStream zip = new ZipInputStream (pkg); 186 HashMap fileIdToBitstream = new HashMap (); 187 WorkspaceItem wi = null; 188 boolean success = false; 189 HashSet packageFiles = new HashSet (); 190 191 boolean validate = params.getBooleanProperty("validate", true); 192 193 try 194 { 195 201 METSManifest manifest = null; 202 wi = WorkspaceItem.create(context, collection, false); 203 Item item = wi.getItem(); 204 Bundle contentBundle = item.createBundle(Constants.CONTENT_BUNDLE_NAME); 205 Bundle mdBundle = null; 206 ZipEntry ze; 207 while ((ze = zip.getNextEntry()) != null) 208 { 209 if (ze.isDirectory()) 210 continue; 211 Bitstream bs = null; 212 String fname = ze.getName(); 213 if (fname.equals(MANIFEST_FILE)) 214 { 215 if (preserveManifest) 216 { 217 mdBundle = item.createBundle(Constants.METADATA_BUNDLE_NAME); 218 bs = mdBundle.createBitstream(new PackageUtils.UnclosableInputStream(zip)); 219 bs.setName(fname); 220 bs.setSource(fname); 221 222 BitstreamFormat manifestFormat = null; 224 manifestFormat = PackageUtils.findOrCreateBitstreamFormat(context, 225 MANIFEST_BITSTREAM_FORMAT, "application/xml", 226 MANIFEST_BITSTREAM_FORMAT+" package manifest"); 227 bs.setFormat(manifestFormat); 228 229 manifest = METSManifest.create(bs.retrieve(), validate); 230 } 231 else 232 { 233 manifest = METSManifest.create(new PackageUtils.UnclosableInputStream(zip), validate); 234 continue; 235 } 236 } 237 else 238 { 239 bs = contentBundle.createBitstream(new PackageUtils.UnclosableInputStream(zip)); 240 bs.setSource(fname); 241 bs.setName(fname); 242 } 243 packageFiles.add(fname); 244 bs.setSource(fname); 245 bs.update(); 246 } 247 zip.close(); 248 249 if (manifest == null) 250 throw new PackageValidationException("No METS Manifest found (filename="+MANIFEST_FILE+"). Package is unacceptable."); 251 252 checkManifest(manifest); 254 255 258 List manifestContentFiles = manifest.getContentFiles(); 259 260 HashSet missingFiles = new HashSet (); 263 for (Iterator mi = manifestContentFiles.iterator(); mi.hasNext(); ) 264 { 265 Element mfile = (Element)mi.next(); 268 String mfileId = mfile.getAttributeValue("ID"); 269 if (mfileId == null) 270 throw new PackageValidationException("Invalid METS Manifest: file element without ID attribute."); 271 String path = METSManifest.getFileName(mfile); 272 Bitstream bs = contentBundle.getBitstreamByName(path); 273 if (bs == null) 274 { 275 log.warn("Cannot find bitstream for filename=\""+path+ 276 "\", skipping it..may cause problems later."); 277 missingFiles.add(path); 278 } 279 else 280 { 281 fileIdToBitstream.put(mfileId, bs); 282 283 String fname = bs.getName(); 289 int lastSlash = fname.lastIndexOf('/'); 290 if (lastSlash >= 0 && lastSlash+1 < fname.length()) 291 bs.setName(fname.substring(lastSlash+1)); 292 293 String mimeType = mfile.getAttributeValue("MIMETYPE"); 297 BitstreamFormat bf = (mimeType == null) ? null : 298 BitstreamFormat.findByMIMEType(context, mimeType); 299 if (bf == null) 300 bf = FormatIdentifier.guessFormat(context, bs); 301 bs.setFormat(bf); 302 303 String bundleName = manifest.getBundleName(mfile); 305 if (!bundleName.equals(Constants.CONTENT_BUNDLE_NAME)) 306 { 307 Bundle bn; 308 Bundle bns[] = item.getBundles(bundleName); 309 if (bns != null && bns.length > 0) 310 bn = bns[0]; 311 else 312 bn = item.createBundle(bundleName); 313 bn.addBitstream(bs); 314 contentBundle.removeBitstream(bs); 315 } 316 317 if (packageFiles.contains(path)) 319 packageFiles.remove(path); 320 else 321 missingFiles.add(path); 322 } 323 } 324 325 for (Iterator mi = manifest.getMdFiles().iterator(); mi.hasNext(); ) 328 { 329 Element mdref = (Element)mi.next(); 330 String path = METSManifest.getFileName(mdref); 331 332 if (packageFiles.contains(path)) 334 packageFiles.remove(path); 335 else 336 missingFiles.add(path); 337 338 Bitstream mdbs = contentBundle.getBitstreamByName(path); 341 if (mdbs != null) 342 { 343 if (mdBundle == null) 344 mdBundle = item.createBundle(Constants.METADATA_BUNDLE_NAME); 345 mdBundle.addBitstream(mdbs); 346 contentBundle.removeBitstream(mdbs); 347 } 348 } 349 350 if (packageFiles.contains(MANIFEST_FILE)) 353 packageFiles.remove(MANIFEST_FILE); 354 355 checkPackageFiles(packageFiles, missingFiles, manifest); 358 359 if (!(packageFiles.isEmpty() && missingFiles.isEmpty())) 361 { 362 StringBuffer msg = new StringBuffer ("Package is unacceptable: contents do not match manifest."); 363 if (!missingFiles.isEmpty()) 364 { 365 msg.append("\nPackage is missing these files listed in Manifest:"); 366 for (Iterator mi = missingFiles.iterator(); mi.hasNext(); ) 367 msg.append("\n\t"+(String )mi.next()); 368 } 369 if (!packageFiles.isEmpty()) 370 { 371 msg.append("\nPackage contains extra files NOT in manifest:"); 372 for (Iterator mi = packageFiles.iterator(); mi.hasNext(); ) 373 msg.append("\n\t"+(String )mi.next()); 374 } 375 throw new PackageValidationException(msg.toString()); 376 } 377 378 380 MdrefManager callback = new MdrefManager(mdBundle); 382 383 chooseItemDmd(context, item, manifest, callback, manifest.getItemDmds()); 384 385 for (Iterator ei = fileIdToBitstream.entrySet().iterator(); 387 ei.hasNext();) 388 { 389 Map.Entry ee = (Map.Entry )ei.next(); 390 manifest.crosswalkBitstream(context, (Bitstream)ee.getValue(), 391 (String )ee.getKey(), callback); 392 } 393 394 for (Iterator mi = manifestContentFiles.iterator(); mi.hasNext(); ) 397 { 398 Element mfile = (Element)mi.next(); 399 String bundleName = manifest.getBundleName(mfile); 400 if (!bundleName.equals(Constants.CONTENT_BUNDLE_NAME)) 401 { 402 Element origFile = manifest.getOriginalFile(mfile); 403 if (origFile != null) 404 { 405 String ofileId = origFile.getAttributeValue("ID"); 406 Bitstream obs = (Bitstream)fileIdToBitstream.get(ofileId); 407 String newName = makeDerivedFilename(bundleName, obs.getName()); 408 if (newName != null) 409 { 410 String mfileId = mfile.getAttributeValue("ID"); 411 Bitstream bs = (Bitstream)fileIdToBitstream.get(mfileId); 412 bs.setName(newName); 413 bs.update(); 414 } 415 } 416 } 417 } 418 419 PackageUtils.checkMetadata(item); 421 422 424 Element pbsFile = manifest.getPrimaryBitstream(); 425 if (pbsFile != null) 426 { 427 Bitstream pbs = (Bitstream)fileIdToBitstream.get(pbsFile.getAttributeValue("ID")); 428 if (pbs == null) 429 log.error("Got Primary Bitstream file ID="+pbsFile.getAttributeValue("ID")+ 430 ", but found no corresponding bitstream."); 431 else 432 { 433 Bundle bn[] = pbs.getBundles(); 434 if (bn.length > 0) 435 bn[0].setPrimaryBitstreamID(pbs.getID()); 436 else 437 log.error("Sanity check, got primary bitstream without any parent bundle."); 438 } 439 } 440 441 addLicense(context, collection, item, manifest, callback, license ); 443 444 finishItem(context, item); 446 447 Bundle allBn[] = item.getBundles(); 449 for (int i = 0; i < allBn.length; ++i) 450 { 451 allBn[i].update(); 452 } 453 454 wi.update(); 455 success = true; 456 log.info(LogManager.getHeader(context, "ingest", 457 "Created new Item, db ID="+String.valueOf(item.getID())+ 458 ", WorkspaceItem ID="+String.valueOf(wi.getID()))); 459 return wi; 460 } 461 catch (SQLException se) 462 { 463 wi = null; 467 468 throw se; 470 } 471 finally 472 { 473 if (!success && wi != null) 475 wi.deleteAll(); 476 } 477 } 478 479 482 public Item replace(Context ctx, Item item, InputStream pckage, PackageParameters params) 483 throws PackageException, UnsupportedOperationException , 484 CrosswalkException, AuthorizeException, 485 SQLException , IOException 486 { 487 throw new UnsupportedOperationException ("The replace operation is not implemented."); 488 } 489 490 private String makeDerivedFilename(String bundleName, String origName) 492 { 493 String mfNames[] = PluginManager.getAllPluginNames(MediaFilter.class); 495 496 for (int i = 0; i < mfNames.length; ++i) 497 { 498 MediaFilter mf = (MediaFilter)PluginManager.getNamedPlugin(MediaFilter.class, mfNames[i]); 499 if (bundleName.equals(mf.getBundleName())) 500 return mf.getFilteredName(origName); 501 } 502 return null; 503 } 504 505 511 abstract void checkManifest(METSManifest manifest) 512 throws MetadataValidationException; 513 514 540 abstract public void checkPackageFiles(Set packageFiles, Set missingFiles, 541 METSManifest manifest) 542 throws PackageValidationException, CrosswalkException; 543 544 562 abstract public void chooseItemDmd(Context context, Item item, 563 METSManifest manifest, MdrefManager cb, 564 Element dmds[]) 565 throws CrosswalkException, 566 AuthorizeException, SQLException , IOException ; 567 568 585 abstract public void addLicense(Context context, Collection collection, 586 Item item, METSManifest manifest, 587 MdrefManager callback, String license) 588 throws PackageValidationException, CrosswalkException, 589 AuthorizeException, SQLException , IOException ; 590 591 600 abstract public void finishItem(Context context, Item item) 601 throws PackageValidationException, CrosswalkException, 602 AuthorizeException, SQLException , IOException ; 603 604 } 605 | Popular Tags |