/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wcs2_0.response; import java.io.IOException; import java.io.OutputStream; import java.util.HashMap; import java.util.Map; import javax.activation.DataHandler; import javax.mail.BodyPart; import javax.mail.MessagingException; import javax.mail.Session; import javax.mail.internet.MimeBodyPart; import javax.mail.internet.MimeMessage; import javax.mail.internet.MimeMultipart; import net.opengis.wcs20.ExtensionItemType; import net.opengis.wcs20.ExtensionType; import net.opengis.wcs20.GetCoverageType; import org.eclipse.emf.common.util.EList; import org.geoserver.ows.Response; import org.geoserver.platform.Operation; import org.geoserver.wcs.responses.CoverageEncoder; import org.geoserver.wcs.responses.CoverageResponseDelegate; import org.geoserver.wcs.responses.CoverageResponseDelegateFinder; import org.geoserver.wcs2_0.response.GMLCovHandler.CoverageData; import org.geoserver.wcs2_0.util.EnvelopeAxesLabelsMapper; import org.geotools.coverage.grid.GridCoverage2D; import org.opengis.coverage.grid.GridCoverage; import org.vfny.geoserver.wcs.WcsException; /** * Returns a single coverage encoded in the specified output format (eventually the native one) * along with the XML describing the coverage, in a MIME multipart package * * @author Andrea Aime - GeoSolutions */ public class WCS20GetCoverageMultipartResponse extends Response { CoverageResponseDelegateFinder responseFactory; EnvelopeAxesLabelsMapper envelopeDimensionsMapper; public WCS20GetCoverageMultipartResponse(CoverageResponseDelegateFinder responseFactory, EnvelopeAxesLabelsMapper envelopeDimensionsMapper) { super(GridCoverage.class); this.responseFactory = responseFactory; this.envelopeDimensionsMapper = envelopeDimensionsMapper; } public String getPreferredDisposition(Object value, Operation operation) { return DISPOSITION_ATTACH; } public String getMimeType(Object value, Operation operation) { return "multipart/related"; } @Override public boolean canHandle(Operation operation) { Object firstParam = operation.getParameters()[0]; if (!(firstParam instanceof GetCoverageType)) { // we only handle WCS 2.0 requests return false; } GetCoverageType getCoverage = (GetCoverageType) firstParam; // this class only handles encoding the coverage with mediatype String mediaType = getCoverage.getMediaType(); return mediaType != null && mediaType.equals("multipart/related"); } public void write(Object value, OutputStream output, Operation operation) throws IOException { // grab the coverage GridCoverage2D coverage = (GridCoverage2D) value; // grab the format GetCoverageType getCoverage = (GetCoverageType) operation.getParameters()[0]; String format = getCoverage.getFormat(); if (format == null) { format = "image/tiff"; } // extract additional extensions final Map<String, String> encodingParameters = new HashMap<String, String>(); final ExtensionType extension = getCoverage.getExtension(); if (extension != null) { final EList<ExtensionItemType> extensions = extension.getContents(); for (ExtensionItemType ext : extensions) { encodingParameters.put(ext.getName(), ext.getSimpleContent()); } } // grab the delegate CoverageResponseDelegate delegate = responseFactory.encoderFor(format); // use javamail classes to actually encode the document try { MimeMultipart multipart = new MimeMultipart(); multipart.setSubType("related"); String fileName = "/coverages/" + getCoverage.getCoverageId() + "." + delegate.getFileExtension(format); // coverages xml structure, which is very close to the DescribeFeatureType output BodyPart coveragesPart = new MimeBodyPart(); FileReference reference = new FileReference(fileName, delegate.getMimeType(format), delegate.getConformanceClass(format)); final CoverageData coveragesData = new CoverageData(coverage, reference, envelopeDimensionsMapper); coveragesPart.setDataHandler(new DataHandler(coveragesData, "geoserver/coverages20")); coveragesPart.setHeader("Content-ID", "wcs"); coveragesPart.setHeader("Content-Type", "application/gml+xml"); multipart.addBodyPart(coveragesPart); // the actual coverage BodyPart coveragePart = new MimeBodyPart(); CoverageEncoder encoder = new CoverageEncoder(delegate, coverage, format, encodingParameters); coveragePart.setDataHandler(new DataHandler(encoder, "geoserver/coverageDelegate")); coveragePart.setHeader("Content-ID", fileName); coveragePart.setHeader("Content-Type", delegate.getMimeType(format)); coveragePart.setHeader("Content-Transfer-Encoding", "binary"); multipart.addBodyPart(coveragePart); // write out the multipart (we need to use mime message trying to // encode directly with multipart or BodyPart does not set properly // the encodings and binary files gets ruined MimeMessage message = new GeoServerMimeMessage(); message.setContent(multipart); message.writeTo(output); output.flush(); } catch (MessagingException e) { throw new WcsException("Error occurred while encoding the mime multipart response", e); } } @Override public String getAttachmentFileName(Object value, Operation operation) { // the only thing that can open this format normally available on a desktop is a e-mail client GetCoverageType getCoverage = (GetCoverageType) operation.getParameters()[0]; return getCoverage.getCoverageId() + ".eml"; } /** * A special mime message that does not set any header other than the * content type * * @author Andrea Aime - GeoSolutions */ private static class GeoServerMimeMessage extends MimeMessage { public GeoServerMimeMessage() { super((Session) null); } @Override protected void updateMessageID() throws MessagingException { // it's just ugly to see ... removeHeader("Message-ID"); } } }