public void setup(org.dspace.content.Bitstream bitstream, String expand) throws SQLException { List<String> expandFields = new ArrayList<String>(); if (expand != null) { expandFields = Arrays.asList(expand.split(",")); } // A logo bitstream might not have a bundle... if (bitstream.getBundles() != null & bitstream.getBundles().length >= 0) { if (bitstream.getParentObject().getType() == Constants.ITEM) { bundleName = bitstream.getBundles()[0].getName(); } } description = bitstream.getDescription(); format = bitstream.getFormatDescription(); sizeBytes = bitstream.getSize(); retrieveLink = "/bitstreams/" + bitstream.getID() + "/retrieve"; mimeType = bitstream.getFormat().getMIMEType(); sequenceId = bitstream.getSequenceID(); CheckSum checkSum = new CheckSum(); checkSum.setCheckSumAlgorith(bitstream.getChecksumAlgorithm()); checkSum.setValue(bitstream.getChecksum()); this.setCheckSum(checkSum); if (expandFields.contains("parent") || expandFields.contains("all")) { parentObject = new DSpaceObject(bitstream.getParentObject()); } else { this.addExpand("parent"); } if (!expandFields.contains("all")) { this.addExpand("all"); } }
/** * Return this resource's children. Item's children are its bitstreams. * * @return the DAV resource[] * @throws SQLException the SQL exception */ @Override protected DAVResource[] children() throws SQLException { // Check for overall read permission on Item if (!AuthorizeManager.authorizeActionBoolean(this.context, this.item, Constants.READ)) { return new DAVResource[0]; } Vector result = new Vector(); Bundle[] bundles = this.item.getBundles(); for (Bundle element : bundles) { // check read permission on this Bundle if (!AuthorizeManager.authorizeActionBoolean(this.context, element, Constants.READ)) { continue; } Bitstream[] bitstreams = element.getBitstreams(); for (Bitstream element0 : bitstreams) { String ext[] = element0.getFormat().getExtensions(); result.add( new DAVBitstream( this.context, this.request, this.response, makeChildPath( DAVBitstream.getPathElt( element0.getSequenceID(), ext.length < 1 ? null : ext[0])), this.item, element0)); } } return (DAVResource[]) result.toArray(new DAVResource[result.size()]); }
/** * Returns canonical link to a bitstream in the item. * * @param item The DSpace Item that the bitstream is part of * @param bitstream The bitstream to link to * @returns a String link to the bitstream */ private String makeBitstreamLink(Item item, Bitstream bitstream) { String name = bitstream.getName(); StringBuilder result = new StringBuilder(contextPath); result.append("/bitstream/item/").append(String.valueOf(item.getID())); // append name although it isn't strictly necessary try { if (name != null) { result.append("/").append(Util.encodeBitstreamName(name, "UTF-8")); } } catch (UnsupportedEncodingException uee) { // just ignore it, we don't have to have a pretty // name on the end of the url because the sequence id will // locate it. However it means that links in this file might // not work.... } result.append("?sequence=").append(String.valueOf(bitstream.getSequenceID())); return result.toString(); }
/** Write out a METS manifest. Mostly lifted from Rob Tansley's METS exporter. */ private void writeManifest(Context context, Item item, PackageParameters params, OutputStream out) throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException, IOException { try { // Create the METS file Mets mets = new Mets(); // Top-level stuff mets.setID(gensym("mets")); mets.setOBJID("hdl:" + item.getHandle()); mets.setLABEL("DSpace Item"); mets.setPROFILE(getProfile()); // MetsHdr MetsHdr metsHdr = new MetsHdr(); metsHdr.setCREATEDATE(new Date()); // FIXME: CREATEDATE is now: // maybe should be item create // date? // Agent Agent agent = new Agent(); agent.setROLE(Role.CUSTODIAN); agent.setTYPE(Type.ORGANIZATION); Name name = new Name(); name.getContent().add(new PCData(ConfigurationManager.getProperty("dspace.name"))); agent.getContent().add(name); metsHdr.getContent().add(agent); mets.getContent().add(metsHdr); // add DMD sections // Each type element MAY be either just a MODS-and-crosswalk name, OR // a combination "MODS-name:crosswalk-name" (e.g. "DC:qDC"). String dmdTypes[] = getDmdTypes(params); // record of ID of each dmdsec to make DMDID in structmap. String dmdGroup = gensym("dmd_group"); String dmdId[] = new String[dmdTypes.length]; for (int i = 0; i < dmdTypes.length; ++i) { dmdId[i] = gensym("dmd"); XmlData xmlData = new XmlData(); String xwalkName, metsName; String parts[] = dmdTypes[i].split(":", 2); if (parts.length > 1) { metsName = parts[0]; xwalkName = parts[1]; } else xwalkName = metsName = dmdTypes[i]; DisseminationCrosswalk xwalk = (DisseminationCrosswalk) PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName); if (xwalk == null) throw new PackageValidationException("Cannot find " + dmdTypes[i] + " crosswalk plugin!"); else crosswalkToMets(xwalk, item, xmlData); DmdSec dmdSec = new DmdSec(); dmdSec.setID(dmdId[i]); dmdSec.setGROUPID(dmdGroup); MdWrap mdWrap = new MdWrap(); setMdType(mdWrap, metsName); mdWrap.getContent().add(xmlData); dmdSec.getContent().add(mdWrap); mets.getContent().add(dmdSec); } // Only add license AMD section if there are any licenses. // Catch authorization failures accessing license bitstreams // only if we are skipping unauthorized bitstreams. String licenseID = null; try { AmdSec amdSec = new AmdSec(); addRightsMd(context, item, amdSec); if (amdSec.getContent().size() > 0) { licenseID = gensym("license"); amdSec.setID(licenseID); mets.getContent().add(amdSec); } } catch (AuthorizeException e) { String unauth = (params == null) ? null : params.getProperty("unauthorized"); if (!(unauth != null && unauth.equalsIgnoreCase("skip"))) throw e; else log.warn("Skipping license metadata because of access failure: " + e.toString()); } // FIXME: History data???? Nooooo!!!! // fileSec - all non-metadata bundles go into fileGrp, // and each bitstream therein into a file. // Create the bitstream-level techMd and div's for structmap // at the same time so we can connec the IDREFs to IDs. FileSec fileSec = new FileSec(); String techMdType = getTechMdType(params); String parts[] = techMdType.split(":", 2); String xwalkName, metsName; if (parts.length > 1) { metsName = parts[0]; xwalkName = parts[1]; } else xwalkName = metsName = techMdType; DisseminationCrosswalk xwalk = (DisseminationCrosswalk) PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName); if (xwalk == null) throw new PackageValidationException("Cannot find " + xwalkName + " crosswalk plugin!"); // log the primary bitstream for structmap String primaryBitstreamFileID = null; // accumulate content DIV items to put in structMap later. List contentDivs = new ArrayList(); // how to handle unauthorized bundle/bitstream: String unauth = (params == null) ? null : params.getProperty("unauthorized"); Bundle[] bundles = item.getBundles(); for (int i = 0; i < bundles.length; i++) { if (PackageUtils.isMetaInfoBundle(bundles[i])) continue; // unauthorized bundle? // NOTE: This must match the logic in disseminate() if (!AuthorizeManager.authorizeActionBoolean(context, bundles[i], Constants.READ)) { if (unauth != null && (unauth.equalsIgnoreCase("skip"))) continue; else throw new AuthorizeException( "Not authorized to read Bundle named \"" + bundles[i].getName() + "\""); } Bitstream[] bitstreams = bundles[i].getBitstreams(); // Create a fileGrp FileGrp fileGrp = new FileGrp(); // Bundle name for USE attribute String bName = bundles[i].getName(); if ((bName != null) && !bName.equals("")) fileGrp.setUSE(bundleToFileGrp(bName)); // watch for primary bitstream int primaryBitstreamID = -1; boolean isContentBundle = false; if ((bName != null) && bName.equals("ORIGINAL")) { isContentBundle = true; primaryBitstreamID = bundles[i].getPrimaryBitstreamID(); } for (int bits = 0; bits < bitstreams.length; bits++) { // Check for authorization. Handle unauthorized // bitstreams to match the logic in disseminate(), // i.e. "unauth=zero" means include a 0-length bitstream, // "unauth=skip" means to ignore it (and exclude from // manifest). boolean auth = AuthorizeManager.authorizeActionBoolean(context, bitstreams[bits], Constants.READ); if (!auth) { if (unauth != null && unauth.equalsIgnoreCase("skip")) continue; else if (!(unauth != null && unauth.equalsIgnoreCase("zero"))) throw new AuthorizeException( "Not authorized to read Bitstream, SID=" + String.valueOf(bitstreams[bits].getSequenceID())); } String sid = String.valueOf(bitstreams[bits].getSequenceID()); edu.harvard.hul.ois.mets.File file = new edu.harvard.hul.ois.mets.File(); String xmlIDstart = "bitstream_"; String fileID = xmlIDstart + sid; file.setID(fileID); // log primary bitstream for later (structMap) if (bitstreams[bits].getID() == primaryBitstreamID) primaryBitstreamFileID = fileID; // if this is content, add to structmap too: if (isContentBundle) { Div div = new Div(); div.setID(gensym("div")); div.setTYPE("DSpace Content Bitstream"); Fptr fptr = new Fptr(); fptr.setFILEID(fileID); div.getContent().add(fptr); contentDivs.add(div); } file.setSEQ(bitstreams[bits].getSequenceID()); String groupID = "GROUP_" + xmlIDstart + sid; /* * If we're in THUMBNAIL or TEXT bundles, the bitstream is * extracted text or a thumbnail, so we use the name to work * out which bitstream to be in the same group as */ if ((bundles[i].getName() != null) && (bundles[i].getName().equals("THUMBNAIL") || bundles[i].getName().startsWith("TEXT"))) { // Try and find the original bitstream, and chuck the // derived bitstream in the same group Bitstream original = findOriginalBitstream(item, bitstreams[bits]); if (original != null) { groupID = "GROUP_" + xmlIDstart + original.getSequenceID(); } } file.setGROUPID(groupID); file.setMIMETYPE(bitstreams[bits].getFormat().getMIMEType()); // FIXME: CREATED: no date file.setSIZE(auth ? bitstreams[bits].getSize() : 0); // translate checksum and type to METS, if available. String csType = bitstreams[bits].getChecksumAlgorithm(); String cs = bitstreams[bits].getChecksum(); if (auth && cs != null && csType != null) { try { file.setCHECKSUMTYPE(Checksumtype.parse(csType)); file.setCHECKSUM(cs); } catch (MetsException e) { log.warn("Cannot set bitstream checksum type=" + csType + " in METS."); } } // FLocat: filename is MD5 checksum FLocat flocat = new FLocat(); flocat.setLOCTYPE(Loctype.URL); flocat.setXlinkHref(makeBitstreamName(bitstreams[bits])); // Make bitstream techMD metadata, add to file. String techID = "techMd_for_bitstream_" + bitstreams[bits].getSequenceID(); AmdSec fAmdSec = new AmdSec(); fAmdSec.setID(techID); TechMD techMd = new TechMD(); techMd.setID(gensym("tech")); MdWrap mdWrap = new MdWrap(); setMdType(mdWrap, metsName); XmlData xmlData = new XmlData(); mdWrap.getContent().add(xmlData); techMd.getContent().add(mdWrap); fAmdSec.getContent().add(techMd); mets.getContent().add(fAmdSec); crosswalkToMets(xwalk, bitstreams[bits], xmlData); file.setADMID(techID); // Add FLocat to File, and File to FileGrp file.getContent().add(flocat); fileGrp.getContent().add(file); } // Add fileGrp to fileSec fileSec.getContent().add(fileGrp); } // Add fileSec to document mets.getContent().add(fileSec); // Create simple structMap: initial div represents the Item, // and user-visible content bitstreams are in its child divs. StringBuffer dmdIds = new StringBuffer(); for (int i = 0; i < dmdId.length; ++i) dmdIds.append(" " + dmdId[i]); StructMap structMap = new StructMap(); structMap.setID(gensym("struct")); structMap.setTYPE("LOGICAL"); structMap.setLABEL("DSpace"); Div div0 = new Div(); div0.setID(gensym("div")); div0.setTYPE("DSpace Item"); div0.setDMDID(dmdIds.substring(1)); if (licenseID != null) div0.setADMID(licenseID); // if there is a primary bitstream, add FPTR to it. if (primaryBitstreamFileID != null) { Fptr fptr = new Fptr(); fptr.setFILEID(primaryBitstreamFileID); div0.getContent().add(fptr); } // add DIV for each content bitstream div0.getContent().addAll(contentDivs); structMap.getContent().add(div0); // Does subclass have something to add to structMap? addStructMap(context, item, params, mets); mets.getContent().add(structMap); mets.validate(new MetsValidator()); mets.write(new MetsWriter(out)); } catch (MetsException e) { // We don't pass up a MetsException, so callers don't need to // know the details of the METS toolkit // e.printStackTrace(); throw new PackageValidationException(e); } }
/** * Generate a METS file element for a given bitstream. * * @param context * @param item If the bitstream is associated with an item, provide the item, otherwise leave * null. * @param bitstream The bitstream to build a file element for. * @param fileID The unique file id for this file. * @param groupID The group id for this file, if it is derived from another file then they should * share the same groupID. * @param admID The IDs of the administrative metadata sections which pertain to this file * @throws org.xml.sax.SAXException passed through. * @throws java.sql.SQLException passed through. */ protected final void renderFile( Context context, Item item, Bitstream bitstream, String fileID, String groupID, String admID) throws SAXException, SQLException { AttributeMap attributes; // ////////////////////////////// // Determine the file attributes BitstreamFormat format = bitstream.getFormat(context); String mimeType = null; if (format != null) { mimeType = format.getMIMEType(); } String checksumType = bitstream.getChecksumAlgorithm(); String checksum = bitstream.getChecksum(); long size = bitstream.getSize(); // //////////////////////////////// // Start the actual file attributes = new AttributeMap(); attributes.put("ID", fileID); attributes.put("GROUPID", groupID); if (admID != null && admID.length() > 0) { attributes.put("ADMID", admID); } if (mimeType != null && mimeType.length() > 0) { attributes.put("MIMETYPE", mimeType); } if (checksumType != null && checksum != null) { attributes.put("CHECKSUM", checksum); attributes.put("CHECKSUMTYPE", checksumType); } attributes.put("SIZE", String.valueOf(size)); startElement(METS, "file", attributes); // //////////////////////////////////// // Determine the file location attributes String name = bitstream.getName(); String description = bitstream.getDescription(); // If possible, reference this bitstream via a handle, however this may // be null if a handle has not yet been assigned. In this case reference the // item its internal id. In the last case where the bitstream is not associated // with an item (such as a community logo) then reference the bitstreamID directly. String identifier = null; if (item != null && item.getHandle() != null) { identifier = "handle/" + item.getHandle(); } else if (item != null) { identifier = "item/" + item.getID(); } else { identifier = "id/" + bitstream.getID(); } String url = contextPath + "/bitstream/" + identifier + "/"; // If we can, append the pretty name of the bitstream to the URL try { if (bitstream.getName() != null) { url += Util.encodeBitstreamName(bitstream.getName(), "UTF-8"); } } catch (UnsupportedEncodingException uee) { // just ignore it, we don't have to have a pretty // name at the end of the URL because the sequence id will // locate it. However it means that links in this file might // not work.... } url += "?sequence=" + bitstream.getSequenceID(); // ////////////////////// // Start the file location attributes = new AttributeMap(); AttributeMap attributesXLINK = new AttributeMap(); attributesXLINK.setNamespace(XLINK); attributes.put("LOCTYPE", "URL"); attributesXLINK.put("type", "locator"); attributesXLINK.put("title", name); if (description != null) { attributesXLINK.put("label", description); } attributesXLINK.put("href", url); startElement(METS, "FLocat", attributes, attributesXLINK); // /////////////////////// // End file location endElement(METS, "FLocate"); // //////////////////////////////// // End the file endElement(METS, "file"); }
private int scan(Bitstream bitstream, InputStream inputstream, String itemHandle) { try { dataOutputStream.write(INSTREAM); } catch (IOException e) { log.error("Error writing INSTREAM command . . ."); return Curator.CURATE_ERROR; } int read = DEFAULT_CHUNK_SIZE; while (read == DEFAULT_CHUNK_SIZE) { try { read = inputstream.read(buffer); } catch (IOException e) { log.error("Failed attempting to read the InputStream . . . "); return Curator.CURATE_ERROR; } if (read == -1) { break; } try { dataOutputStream.writeInt(read); dataOutputStream.write(buffer, 0, read); } catch (IOException e) { log.error("Could not write to the socket . . . "); return Curator.CURATE_ERROR; } } try { dataOutputStream.writeInt(0); dataOutputStream.flush(); } catch (IOException e) { log.error("Error writing zero-length chunk to socket"); return Curator.CURATE_ERROR; } try { read = socket.getInputStream().read(buffer); } catch (IOException e) { log.error("Error reading result from socket"); return Curator.CURATE_ERROR; } if (read > 0) { String response = new String(buffer, 0, read); logDebugMessage("Response: " + response); if (response.indexOf("FOUND") != -1) { String itemMsg = "item - " + itemHandle + ": "; String bsMsg = "bitstream - " + bitstream.getName() + ": SequenceId - " + bitstream.getSequenceID() + ": infected"; report(itemMsg + bsMsg); results.add(bsMsg); return Curator.CURATE_FAIL; } else { return Curator.CURATE_SUCCESS; } } return Curator.CURATE_ERROR; }