001/* 002 * (C) Copyright 2014 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Nuxeo - initial API and implementation 016 * vpasquier <vpasquier@nuxeo.com> 017 * 018 */ 019package org.nuxeo.ecm.automation.server.jaxrs.batch; 020 021import java.io.ByteArrayOutputStream; 022import java.io.IOException; 023import java.io.InputStream; 024import java.net.URLDecoder; 025import java.util.ArrayList; 026import java.util.HashMap; 027import java.util.List; 028import java.util.Map; 029 030import javax.mail.MessagingException; 031import javax.servlet.http.HttpServletRequest; 032import javax.ws.rs.GET; 033import javax.ws.rs.POST; 034import javax.ws.rs.Path; 035import javax.ws.rs.PathParam; 036import javax.ws.rs.Produces; 037import javax.ws.rs.core.Context; 038import javax.ws.rs.core.MediaType; 039import javax.ws.rs.core.Response; 040import javax.ws.rs.core.Response.Status; 041 042import org.apache.commons.lang.StringUtils; 043import org.apache.commons.logging.Log; 044import org.apache.commons.logging.LogFactory; 045import org.codehaus.jackson.map.ObjectMapper; 046import org.nuxeo.ecm.automation.OperationContext; 047import org.nuxeo.ecm.automation.jaxrs.io.operations.ExecutionRequest; 048import org.nuxeo.ecm.automation.server.jaxrs.ResponseHelper; 049import org.nuxeo.ecm.core.api.Blob; 050import org.nuxeo.ecm.core.api.CoreSession; 051import org.nuxeo.ecm.core.api.NuxeoException; 052import org.nuxeo.ecm.webengine.WebException; 053import org.nuxeo.ecm.webengine.forms.FormData; 054import org.nuxeo.ecm.webengine.jaxrs.context.RequestCleanupHandler; 055import org.nuxeo.ecm.webengine.jaxrs.context.RequestContext; 056import org.nuxeo.ecm.webengine.jaxrs.session.SessionFactory; 057import org.nuxeo.ecm.webengine.model.WebObject; 058import org.nuxeo.ecm.webengine.model.impl.AbstractResource; 059import org.nuxeo.ecm.webengine.model.impl.ResourceTypeImpl; 060import org.nuxeo.runtime.api.Framework; 061import org.nuxeo.runtime.services.config.ConfigurationService; 062 063/** 064 * Exposes {@link Batch} as a JAX-RS resource 065 * 066 * @deprecated Use {@link org.nuxeo.ecm.restapi.server.jaxrs.BatchUploadObject} instead. 067 * @author Tiry (tdelprat@nuxeo.com) 068 * @author Antoine Taillefer 069 */ 070@Deprecated 071@WebObject(type = "batch") 072public class BatchResource extends AbstractResource<ResourceTypeImpl> { 073 074 private static final String REQUEST_BATCH_ID = "batchId"; 075 076 private static final String REQUEST_FILE_IDX = "fileIdx"; 077 078 protected static final Log log = LogFactory.getLog(BatchResource.class); 079 080 public CoreSession getCoreSession(HttpServletRequest request) { 081 return SessionFactory.getSession(request); 082 } 083 084 protected Response buildFromString(String message) { 085 return Response.ok(message, MediaType.APPLICATION_JSON).header("Content-Length", message.length()).build(); 086 } 087 088 protected Response buildHtmlFromString(String message) { 089 message = "<html>" + message + "</html>"; 090 return Response.ok(message, MediaType.TEXT_HTML_TYPE).header("Content-Length", message.length()).build(); 091 } 092 093 protected Response buildFromMap(Map<String, String> map) throws IOException { 094 return buildFromMap(map, false); 095 } 096 097 protected Response buildFromMap(Map<String, String> map, boolean html) throws IOException { 098 ObjectMapper mapper = new ObjectMapper(); 099 ByteArrayOutputStream out = new ByteArrayOutputStream(128); 100 mapper.writeValue(out, map); 101 String result = out.toString("UTF-8"); 102 if (html) { 103 // for msie with iframe transport : we need to return html ! 104 return buildHtmlFromString(result); 105 } else { 106 return buildFromString(result); 107 } 108 } 109 110 /** 111 * @deprecated since 5.7.2. The timeout is managed by the {@link BatchManager#execute} method. 112 */ 113 @Deprecated 114 protected int getUploadWaitTimeout() { 115 String t = Framework.getProperty("org.nuxeo.batch.upload.wait.timeout", "5"); 116 return Integer.parseInt(t); 117 } 118 119 /** 120 * @deprecated since 7.4, use {@link BatchUploadObject#upload(HttpServletRequest, String, String)} instead. 121 */ 122 @Deprecated 123 @POST 124 @Path("/upload") 125 public Object doPost(@Context HttpServletRequest request) throws IOException { 126 127 boolean useIFrame = false; 128 129 // Parameters are passed as request header 130 // the request body is the stream 131 String fileName = request.getHeader("X-File-Name"); 132 String fileSize = request.getHeader("X-File-Size"); 133 String batchId = request.getHeader("X-Batch-Id"); 134 String mimeType = request.getHeader("X-File-Type"); 135 String idx = request.getHeader("X-File-Idx"); 136 InputStream is = null; 137 138 // handle multipart case : mainly MSIE with jQueryFileupload 139 String contentType = request.getHeader("Content-Type"); 140 if (contentType != null && contentType.contains("multipart")) { 141 useIFrame = true; 142 FormData formData = new FormData(request); 143 if (formData.getString("batchId") != null) { 144 batchId = formData.getString("batchId"); 145 } 146 if (formData.getString("fileIdx") != null) { 147 idx = formData.getString("fileIdx"); 148 } 149 if (idx == null || "".equals(idx.trim())) { 150 idx = "0"; 151 } 152 Blob blob = formData.getFirstBlob(); 153 if (blob != null) { 154 is = blob.getStream(); 155 fileName = blob.getFilename(); 156 mimeType = blob.getMimeType(); 157 } 158 } else { 159 fileName = URLDecoder.decode(fileName, "UTF-8"); 160 is = request.getInputStream(); 161 } 162 163 log.debug("Uploading " + fileName + " (" + fileSize + "b)"); 164 BatchManager bm = Framework.getLocalService(BatchManager.class); 165 if (StringUtils.isEmpty(batchId)) { 166 batchId = bm.initBatch(); 167 } else if (!bm.hasBatch(batchId)) { 168 if (!Framework.getService(ConfigurationService.class).isBooleanPropertyTrue( 169 BatchManagerComponent.CLIENT_BATCH_ID_FLAG)) { 170 String errorMsg = String.format( 171 "Cannot upload a file with a client-side generated batch id, please use new upload API or set configuration property %s to true (not recommended)", 172 BatchManagerComponent.CLIENT_BATCH_ID_FLAG); 173 return Response.status(Status.INTERNAL_SERVER_ERROR).entity("{\"error\" : \"" + errorMsg + "\"}").build(); 174 } else { 175 log.warn(String.format( 176 "Allowing to initialize upload batch with a client-side generated id since configuration property %s is set to true but this is not recommended, please use new upload API instead", 177 BatchManagerComponent.CLIENT_BATCH_ID_FLAG)); 178 } 179 } 180 bm.addStream(batchId, idx, is, fileName, mimeType); 181 182 Map<String, String> result = new HashMap<String, String>(); 183 result.put("batchId", batchId); 184 result.put("uploaded", "true"); 185 return buildFromMap(result, useIFrame); 186 } 187 188 @Deprecated 189 @POST 190 @Produces("application/json") 191 @Path("/execute") 192 public Object exec(@Context HttpServletRequest request, ExecutionRequest xreq) { 193 Map<String, Object> params = xreq.getParams(); 194 String batchId = (String) params.get(REQUEST_BATCH_ID); 195 String fileIdx = (String) params.get(REQUEST_FILE_IDX); 196 String operationId = (String) params.get("operationId"); 197 params.remove(REQUEST_BATCH_ID); 198 params.remove("operationId"); 199 200 final BatchManager bm = Framework.getLocalService(BatchManager.class); 201 // register commit hook for cleanup 202 request.setAttribute(REQUEST_BATCH_ID, batchId); 203 RequestContext.getActiveContext(request).addRequestCleanupHandler(new RequestCleanupHandler() { 204 @Override 205 public void cleanup(HttpServletRequest req) { 206 String bid = (String) req.getAttribute(REQUEST_BATCH_ID); 207 bm.clean(bid); 208 } 209 210 }); 211 212 try { 213 OperationContext ctx = xreq.createContext(request, getCoreSession(request)); 214 215 Object result; 216 if (StringUtils.isEmpty(fileIdx)) { 217 result = bm.execute(batchId, operationId, getCoreSession(request), ctx, params); 218 } else { 219 result = bm.execute(batchId, fileIdx, operationId, getCoreSession(request), ctx, params); 220 } 221 return ResponseHelper.getResponse(result, request); 222 } catch (NuxeoException | MessagingException | IOException e) { 223 log.error("Error while executing automation batch ", e); 224 if (WebException.isSecurityError(e)) { 225 return Response.status(Status.FORBIDDEN).entity("{\"error\" : \"" + e.getMessage() + "\"}").build(); 226 } else { 227 return Response.status(Status.INTERNAL_SERVER_ERROR).entity("{\"error\" : \"" + e.getMessage() + "\"}").build(); 228 } 229 } 230 } 231 232 /** 233 * @deprecated since 7.4, use {@link BatchUploadObject#getBatchInfo(String)} instead. 234 */ 235 @Deprecated 236 @GET 237 @Path("/files/{batchId}") 238 public Object getFilesBatch(@PathParam(REQUEST_BATCH_ID) String batchId) throws IOException { 239 BatchManager bm = Framework.getLocalService(BatchManager.class); 240 List<Blob> blobs = bm.getBlobs(batchId); 241 242 List<Map<String, Object>> result = new ArrayList<>(); 243 for (Blob blob : blobs) { 244 Map<String, Object> map = new HashMap<>(); 245 map.put("name", blob.getFilename()); 246 map.put("size", blob.getLength()); 247 result.add(map); 248 } 249 250 ObjectMapper mapper = new ObjectMapper(); 251 ByteArrayOutputStream out = new ByteArrayOutputStream(128); 252 mapper.writeValue(out, result); 253 return buildFromString(out.toString("UTF-8")); 254 } 255 256 /** 257 * @deprecated since 7.4, use {@link BatchUploadObject#dropBatch(String)} instead. 258 */ 259 @Deprecated 260 @GET 261 @Path("/drop/{batchId}") 262 public Object dropBatch(@PathParam(REQUEST_BATCH_ID) String batchId) throws IOException { 263 BatchManager bm = Framework.getLocalService(BatchManager.class); 264 bm.clean(batchId); 265 266 Map<String, String> result = new HashMap<String, String>(); 267 result.put("batchId", batchId); 268 result.put("dropped", "true"); 269 return buildFromMap(result); 270 } 271 272}