/* * Copyright 2012 JBoss Inc * * 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 org.artificer.server.atom.services; import org.apache.commons.io.IOUtils; import org.artificer.atom.archive.ArtificerArchive; import org.artificer.atom.beans.HttpResponseBean; import org.artificer.atom.err.ArtificerAtomException; import org.artificer.atom.visitors.ArtifactToFullAtomEntryVisitor; import org.artificer.common.ArtificerConfig; import org.artificer.common.ArtificerException; import org.artificer.common.MediaType; import org.artificer.common.error.ArtificerServerException; import org.artificer.common.visitors.ArtifactVisitorHelper; import org.artificer.server.BatchServiceImpl; import org.artificer.server.core.api.BatchResult; import org.artificer.server.i18n.Messages; import org.jboss.resteasy.annotations.providers.multipart.PartType; import org.jboss.resteasy.plugins.providers.atom.Entry; import org.jboss.resteasy.plugins.providers.multipart.MultipartOutput; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; import javax.ws.rs.HeaderParam; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import java.io.InputStream; /** * The JAX-RS resource that handles pushing artifacts into the repository in batches. The * S-RAMP specification defines two mechanisms for this. The first is via an archive file * and the second is via a multipart/related http POST. * * @author eric.wittmann@redhat.com */ @Path("/s-ramp") public class BatchResource extends AbstractResource { private static Logger logger = LoggerFactory.getLogger(BatchResource.class); private final BatchServiceImpl batchService = new BatchServiceImpl(); /** * S-RAMP atom POST of a package file (.zip) containing the artifacts and meta data that * should be published in the repository. * @param fileName the name of the .zip file (optional) * @param content the zip content * @return a multipart/mixed response as defined in the S-RAMP Atom binding document * @throws org.artificer.atom.err.ArtificerAtomException */ @POST @Consumes(MediaType.APPLICATION_ZIP) @Produces(MediaType.MULTIPART_MIXED) @PartType("message/http") public MultipartOutput zipPackagePost(@Context HttpServletRequest request, @HeaderParam("Slug") String fileName, InputStream content) throws ArtificerAtomException, ArtificerException { return doZipPackage(request, content); } /** * S-RAMP atom PUT of a package file (.zip) containing the artifacts and meta data that * should be published in the repository. * @param fileName the name of the .zip file (optional) * @param content the zip content * @return a multipart/mixed response as defined in the S-RAMP Atom binding document * @throws org.artificer.atom.err.ArtificerAtomException */ @PUT @Consumes(MediaType.APPLICATION_ZIP) @Produces(MediaType.MULTIPART_MIXED) @PartType("message/http") public MultipartOutput zipPackagePut(@Context HttpServletRequest request, @HeaderParam("Slug") String fileName, InputStream content) throws ArtificerServerException { return doZipPackage(request, content); } private MultipartOutput doZipPackage(HttpServletRequest request, InputStream content) throws ArtificerServerException { ArtificerArchive archive = null; String baseUrl = ArtificerConfig.getBaseUrl(request.getRequestURL().toString()); try { archive = new ArtificerArchive(content); MultipartOutput output = new MultipartOutput(); output.setBoundary("package"); BatchResult batchResult = batchService.upload(archive); for (String batchItemId : batchResult.getCreates().keySet()) { ArtifactToFullAtomEntryVisitor visitor = new ArtifactToFullAtomEntryVisitor(baseUrl); ArtifactVisitorHelper.visitArtifact(visitor, batchResult.getCreates().get(batchItemId)); Entry atomEntry = visitor.getAtomEntry(); addCreatedPart(output, batchItemId, atomEntry); } for (String batchItemId : batchResult.getUpdates().keySet()) { ArtifactToFullAtomEntryVisitor visitor = new ArtifactToFullAtomEntryVisitor(baseUrl); ArtifactVisitorHelper.visitArtifact(visitor, batchResult.getUpdates().get(batchItemId)); Entry atomEntry = visitor.getAtomEntry(); addUpdatedPart(output, batchItemId, atomEntry); } return output; } catch (ArtificerServerException e) { // Simply re-throw. Don't allow the following catch it -- ArtificerServerException is mapped to a unique // HTTP response type. throw e; } catch (Exception e) { logError(logger, Messages.i18n.format("ERROR_CONSUMING_ZIP"), e); throw new ArtificerAtomException(e); } finally { IOUtils.closeQuietly(content); if (archive != null) ArtificerArchive.closeQuietly(archive); } } /** * Adds an appropriate part to the batch response. This takes the form of an HTTP * response bean with the appropriate headers and data. * @param output * @param contentId * @param atomEntry */ private void addCreatedPart(MultipartOutput output, String contentId, Entry atomEntry) { HttpResponseBean createdResponse = new HttpResponseBean(201, "Created"); createdResponse.setBody(atomEntry, MediaType.APPLICATION_ATOM_XML_ENTRY_TYPE); output.addPart(createdResponse, MediaType.MESSAGE_HTTP_TYPE).getHeaders().putSingle("Content-ID", contentId); } /** * Adds an appropriate part to the batch response. This takes the form of an HTTP * response bean with the appropriate headers and data. * @param output * @param contentId * @param atomEntry */ private void addUpdatedPart(MultipartOutput output, String contentId, Entry atomEntry) { HttpResponseBean createdResponse = new HttpResponseBean(200, "OK"); createdResponse.setBody(atomEntry, MediaType.APPLICATION_ATOM_XML_ENTRY_TYPE); output.addPart(createdResponse, MediaType.MESSAGE_HTTP_TYPE).getHeaders().putSingle("Content-ID", contentId); } }