Java tutorial
/** * Copyright 2010 The University of North Carolina at Chapel Hill * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package cdr.forms; import edu.unc.lib.schemas.acl.AccessControlType; import edu.unc.lib.schemas.acl.AclFactory; import edu.unc.lib.schemas.acl.AclPackage; import edu.unc.lib.schemas.acl.GrantType; import gov.loc.mets.AgentType; import gov.loc.mets.AmdSecType; import gov.loc.mets.DivType; import gov.loc.mets.FLocatType; import gov.loc.mets.FileGrpType1; import gov.loc.mets.FileSecType; import gov.loc.mets.FileType; import gov.loc.mets.FptrType; import gov.loc.mets.LOCTYPEType; import gov.loc.mets.MDTYPEType; import gov.loc.mets.MdSecType; import gov.loc.mets.MdWrapType; import gov.loc.mets.MetsFactory; import gov.loc.mets.MetsHdrType; import gov.loc.mets.MetsPackage; import gov.loc.mets.MetsType; import gov.loc.mets.ROLEType; import gov.loc.mets.SmLinkType; import gov.loc.mets.StructLinkType1; import gov.loc.mets.StructMapType; import gov.loc.mets.TYPEType; import gov.loc.mets.XmlDataType1; import gov.loc.mets.util.Link; import gov.loc.mets.util.METSConstants; import gov.loc.mets.util.MetsResourceFactoryImpl; import gov.loc.mods.mods.MODSFactory; import gov.loc.mods.mods.MODSPackage; import gov.loc.mods.mods.ModsDefinition; import gov.loc.mods.mods.NameDefinition; import gov.loc.mods.mods.XsString; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintStream; import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.IdentityHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.HttpException; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.httpclient.auth.AuthScope; import org.apache.commons.httpclient.methods.FileRequestEntity; import org.apache.commons.httpclient.methods.PostMethod; import org.apache.commons.httpclient.methods.RequestEntity; import org.eclipse.emf.common.util.URI; import org.eclipse.emf.ecore.EClass; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.resource.ResourceSet; import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; import org.eclipse.emf.ecore.xmi.XMLResource; import org.eclipse.emf.ecore.xml.type.internal.XMLCalendar; import org.jdom.Element; import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3._1999.xlink.XlinkPackage; import crosswalk.DateInputField; import crosswalk.FileBlock; import crosswalk.Form; import crosswalk.FormElement; import crosswalk.InputField; import crosswalk.MajorBlock; import crosswalk.MajorEntry; import crosswalk.MetadataBlock; import crosswalk.OutputElement; import crosswalk.OutputMetadataSections; import crosswalk.OutputProfile; import crosswalk.TextInputField; import cdr.forms.DepositResult.Status; public class SwordDepositHandler implements DepositHandler, ExternalDepositFileConfigurationProvider { private static final Logger LOG = LoggerFactory.getLogger(SwordDepositHandler.class); private String serviceUrl; private String username; private String password; private String externalPath; private String externalUriBase; public String getServiceUrl() { return serviceUrl; } public void setServiceUrl(String serviceUrl) { this.serviceUrl = serviceUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } private String defaultContainer = null; public String getDefaultContainer() { return defaultContainer; } /** * Set the default deposit container. String should be appropriate * * @param defaultContainer */ public void setDefaultContainer(String defaultContainer) { this.defaultContainer = defaultContainer; } public String getExternalPath() { return externalPath; } public void setExternalPath(String externalPath) { this.externalPath = externalPath; } public String getExternalUriBase() { return externalUriBase; } public void setExternalUriBase(String externalUriBase) { this.externalUriBase = externalUriBase; } public DepositResult deposit(Deposit deposit) { // Prepare the submission package Submission submission = Submission.create(deposit, this); File zipFile = makeZipFile(submission.getMetsDocumentRoot(), submission.getFiles()); // Obtain the path for the collection in which we'll attempt to make the deposit Form form = deposit.getForm(); String containerId = form.getDepositContainerId(); if (containerId == null || "".equals(containerId.trim())) containerId = this.getDefaultContainer(); String depositPath = getServiceUrl() + "collection/" + containerId; // Make the SWORD request String pid = "uuid:" + UUID.randomUUID().toString(); HttpClient client = new HttpClient(); UsernamePasswordCredentials creds = new UsernamePasswordCredentials(this.getUsername(), this.getPassword()); client.getState().setCredentials(getAuthenticationScope(depositPath), creds); client.getParams().setAuthenticationPreemptive(true); PostMethod post = new PostMethod(depositPath); RequestEntity fileRequestEntity = new FileRequestEntity(zipFile, "application/zip"); Header contentDispositionHeader = new Header("Content-Disposition", "attachment; filename=package.zip"); post.addRequestHeader(contentDispositionHeader); Header packagingHeader = new Header("Packaging", "http://cdr.unc.edu/METS/profiles/Simple"); post.addRequestHeader(packagingHeader); Header slugHeader = new Header("Slug", pid); post.addRequestHeader(slugHeader); post.setRequestEntity(fileRequestEntity); // Interpret the response from the SWORD endpoint DepositResult result = new DepositResult(); try { // Set the result's status based on the HTTP response code int responseCode = client.executeMethod(post); if (responseCode >= 300) { LOG.error(String.valueOf(responseCode)); LOG.error(post.getResponseBodyAsString()); result.setStatus(Status.FAILED); } else { result.setStatus(Status.COMPLETE); } // Save the response body result.setResponseBody(post.getResponseBodyAsString()); // Assign additional attributes based on the response body. try { Namespace atom = Namespace.getNamespace("http://www.w3.org/2005/Atom"); SAXBuilder sx = new SAXBuilder(); org.jdom.Document d = sx.build(post.getResponseBodyAsStream()); // Set accessURL to the href of the first <link rel="alternate"> inside an Atom entry if (result.getStatus() == Status.COMPLETE) { if (d.getRootElement().getNamespace().equals(atom) && d.getRootElement().getName().equals("entry")) { @SuppressWarnings("unchecked") List<Element> links = d.getRootElement().getChildren("link", atom); for (Element link : links) { if ("alternate".equals(link.getAttributeValue("rel"))) { result.setAccessURL(link.getAttributeValue("href")); break; } } } } } catch (JDOMException e) { LOG.error("There was a problem parsing the SWORD response.", e); } LOG.debug("response was: \n" + post.getResponseBodyAsString()); } catch (HttpException e) { LOG.error("Exception during SWORD deposit", e); throw new Error(e); } catch (IOException e) { LOG.error("Exception during SWORD deposit", e); throw new Error(e); } return result; } private String serializeMets(gov.loc.mets.DocumentRoot root) { ResourceSet rs = new ResourceSetImpl(); rs.getResourceFactoryRegistry().getExtensionToFactoryMap().put("mets", new MetsResourceFactoryImpl()); rs.getPackageRegistry().put(MODSPackage.eNS_URI, MODSPackage.eINSTANCE); rs.getPackageRegistry().put(MetsPackage.eNS_URI, MetsPackage.eINSTANCE); rs.getPackageRegistry().put(XlinkPackage.eNS_URI, XlinkPackage.eINSTANCE); rs.getPackageRegistry().put(AclPackage.eNS_URI, AclPackage.eINSTANCE); gov.loc.mets.MetsType mets = root.getMets(); File tmp; try { tmp = File.createTempFile("tmp", ".mets"); } catch (IOException e1) { throw new Error(e1); } URI uri = URI.createURI(tmp.toURI().toString()); XMLResource res = (XMLResource) rs.createResource(uri); res.getContents().add(root); StringWriter sw = new StringWriter(); Map<Object, Object> options = new HashMap<Object, Object>(); options.put(XMLResource.OPTION_ENCODING, "utf-8"); options.put(XMLResource.OPTION_DECLARE_XML, ""); options.put(XMLResource.OPTION_LINE_WIDTH, new Integer(80)); options.put(XMLResource.OPTION_ROOT_OBJECTS, Collections.singletonList(mets)); try { res.save(sw, options); } catch (IOException e) { throw new Error("failed to serialize XML for model object", e); } return sw.toString(); } private File makeZipFile(gov.loc.mets.DocumentRoot metsDocumentRoot, IdentityHashMap<DepositFile, String> filenames) { // Get the METS XML String metsXml = serializeMets(metsDocumentRoot); // Create the zip file File zipFile; try { zipFile = File.createTempFile("tmp", ".zip"); } catch (IOException e) { throw new Error(e); } FileOutputStream fileOutput; try { fileOutput = new FileOutputStream(zipFile); } catch (FileNotFoundException e) { throw new Error(e); } ZipOutputStream zipOutput = new ZipOutputStream(fileOutput); try { ZipEntry entry; // Write the METS entry = new ZipEntry("mets.xml"); zipOutput.putNextEntry(entry); PrintStream xmlPrintStream = new PrintStream(zipOutput); xmlPrintStream.print(metsXml); // Write files for (DepositFile file : filenames.keySet()) { if (!file.isExternal()) { entry = new ZipEntry(filenames.get(file)); zipOutput.putNextEntry(entry); FileInputStream fileInput = new FileInputStream(file.getFile()); byte[] buffer = new byte[1024]; int length; while ((length = fileInput.read(buffer)) != -1) zipOutput.write(buffer, 0, length); fileInput.close(); } } zipOutput.finish(); zipOutput.close(); fileOutput.close(); } catch (IOException e) { throw new Error(e); } return zipFile; } /** * Generates a limited authentication scope for the supplied URL, so that an HTTP client will not send username and * passwords to other URLs. * * @param queryURL * the URL for the query. * @return an authentication scope tuned to the requested URL. * @throws IllegalArgumentException * if <code>queryURL</code> is not a well-formed URL. */ public static AuthScope getAuthenticationScope(String queryURL) { if (queryURL == null) { throw new NullPointerException("Cannot derive authentication scope for null URL"); } try { URL url = new URL(queryURL); // port defaults to 80 unless the scheme is https // or the port is explicitly set in the URL. int port = 80; if (url.getPort() == -1) { if ("https".equals(url.getProtocol())) { port = 443; } } else { port = url.getPort(); } return new AuthScope(url.getHost(), port); } catch (MalformedURLException mue) { throw new IllegalArgumentException("supplied URL <" + queryURL + "> is ill-formed:" + mue.getMessage()); } } }