/* * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * 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.guvnor.m2repo.backend.server.helpers; import java.io.BufferedInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; import java.util.List; import javax.inject.Inject; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.FileItemFactory; import org.apache.commons.fileupload.FileUploadException; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.maven.project.ProjectBuildingException; import org.drools.compiler.kproject.xml.PomModel; import org.guvnor.common.services.backend.exceptions.ExceptionUtilities; import org.guvnor.common.services.project.model.GAV; import org.guvnor.m2repo.backend.server.ExtendedM2RepoService; import org.guvnor.m2repo.model.HTMLFileManagerFields; import org.kie.scanner.embedder.MavenEmbedderException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static org.guvnor.m2repo.model.HTMLFileManagerFields.*; import static org.guvnor.m2repo.utils.FileNameUtilities.*; public class HttpPostHelper { private static final Logger log = LoggerFactory.getLogger(HttpPostHelper.class); @Inject private ExtendedM2RepoService m2RepoService; /** * Posting accepts content of various types - * may be an attachment for an asset, or perhaps a repository import to process. */ public void handle(final HttpServletRequest request, final HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); final FormData formData = extractFormData(request); final String result = upload(formData); response.getWriter().write(result); } @SuppressWarnings("rawtypes") private FormData extractFormData(final HttpServletRequest request) throws IOException { FileItemFactory factory = new DiskFileItemFactory(); ServletFileUpload upload = new ServletFileUpload(factory); upload.setHeaderEncoding("UTF-8"); FormData data = new FormData(); GAV emptyGAV = new GAV(); try { List items = upload.parseRequest(request); Iterator it = items.iterator(); while (it.hasNext()) { FileItem item = (FileItem) it.next(); if (!item.isFormField()) { data.setFile(item); } if (item.isFormField() && item.getFieldName().equals(HTMLFileManagerFields.GROUP_ID)) { emptyGAV.setGroupId(item.getString()); } else if (item.isFormField() && item.getFieldName().equals(HTMLFileManagerFields.ARTIFACT_ID)) { emptyGAV.setArtifactId(item.getString()); } else if (item.isFormField() && item.getFieldName().equals(HTMLFileManagerFields.VERSION_ID)) { emptyGAV.setVersion(item.getString()); } } if (isNullOrEmpty(emptyGAV.getGroupId()) || isNullOrEmpty(emptyGAV.getArtifactId()) || isNullOrEmpty(emptyGAV.getVersion())) { data.setGav(null); } else { data.setGav(emptyGAV); } return data; } catch (FileUploadException e) { log.error(e.getMessage(), e); } return null; } private String upload(final FormData formData) throws IOException { //Validate upload final FileItem fileItem = formData.getFile(); if (fileItem == null) { throw new IOException("No file selected."); } final String fileName = fileItem.getName(); if (isNullOrEmpty(fileName)) { throw new IOException("No file selected."); } if (isJar(fileName) || isKJar(fileName)) { return uploadJar(formData); } else if (isPom(fileName)) { return uploadPom(formData); } else { throw new IOException("Unsupported file type selected."); } } private String uploadJar(final FormData formData) throws IOException { GAV gav = formData.getGav(); InputStream jarStream = null; try { jarStream = formData.getFile().getInputStream(); if (gav == null) { if (!jarStream.markSupported()) { jarStream = new BufferedInputStream(jarStream); } // is available() safe? jarStream.mark(jarStream.available()); PomModel pomModel = PomModelResolver.resolveFromJar(jarStream); //If we were able to get a POM model we can get the GAV if (pomModel != null) { String groupId = pomModel.getReleaseId().getGroupId(); String artifactId = pomModel.getReleaseId().getArtifactId(); String version = pomModel.getReleaseId().getVersion(); if (isNullOrEmpty(groupId) || isNullOrEmpty(artifactId) || isNullOrEmpty(version)) { return UPLOAD_MISSING_POM; } else { gav = new GAV(groupId, artifactId, version); } } else { return UPLOAD_MISSING_POM; } jarStream.reset(); } m2RepoService.deployJar(jarStream, gav); return UPLOAD_OK; } catch (IOException ioe) { log.error(ioe.getMessage(), ioe); throw ExceptionUtilities.handleException(ioe); } finally { if (jarStream != null) { jarStream.close(); } } } private String uploadPom(final FormData formData) throws IOException { ReusableInputStream pomStream = null; try { GAV gav; pomStream = new ReusableInputStream(formData.getFile().getInputStream()); // is available() safe? pomStream.mark(pomStream.available()); try { final PomModel pomModel = PomModelResolver.resolveFromPom(pomStream); final String groupId = pomModel.getReleaseId().getGroupId(); final String artifactId = pomModel.getReleaseId().getArtifactId(); final String version = pomModel.getReleaseId().getVersion(); if (isNullOrEmpty(groupId) || isNullOrEmpty(artifactId) || isNullOrEmpty(version)) { return UPLOAD_UNABLE_TO_PARSE_POM; } else { gav = new GAV(groupId, artifactId, version); } } catch (Exception e) { log.error("Could not parse the uploaded POM.XML file.", e); return UPLOAD_UNABLE_TO_PARSE_POM; } pomStream.reset(); m2RepoService.deployPom(pomStream, gav); return UPLOAD_OK; } catch (IOException ioe) { log.error(ioe.getMessage(), ioe); throw ExceptionUtilities.handleException(ioe); } finally { if (pomStream != null) { pomStream.doClose(); } } } private boolean isNullOrEmpty(String value) { return value == null || value.isEmpty(); } /** * PomModelResolver uses org.kie.scanner.embedder.MavenEmbedder which closes the underlying * InputStream once the PomModel has been resolved. We however need to keep the InputStream * open to be able to write the file to GuvnorM2Repository. Therefore this sub-class * overrides close to prevent the InputStream from being closed prematurely. */ private static class ReusableInputStream extends BufferedInputStream { public ReusableInputStream(InputStream in) { super(in); } @Override public void close() throws IOException { //Do nothing. } void doClose() throws IOException { //Do the closure super.close(); } } }