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