001/* 002 * (C) Copyright 2015 Nuxeo SA (http://nuxeo.com/) and others. 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-2.1.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 * Thomas Roger 016 */ 017package org.nuxeo.ecm.restapi.server.jaxrs.adapters; 018 019import java.io.Serializable; 020import java.net.URI; 021import java.net.URISyntaxException; 022import java.util.HashMap; 023import java.util.Map; 024 025import javax.ws.rs.FormParam; 026import javax.ws.rs.GET; 027import javax.ws.rs.POST; 028import javax.ws.rs.Produces; 029import javax.ws.rs.QueryParam; 030import javax.ws.rs.core.Context; 031import javax.ws.rs.core.MediaType; 032import javax.ws.rs.core.MultivaluedMap; 033import javax.ws.rs.core.Response; 034import javax.ws.rs.core.UriInfo; 035 036import org.apache.commons.lang.StringUtils; 037import org.nuxeo.ecm.core.api.Blob; 038import org.nuxeo.ecm.core.api.DocumentModel; 039import org.nuxeo.ecm.core.api.NuxeoException; 040import org.nuxeo.ecm.core.api.blobholder.BlobHolder; 041import org.nuxeo.ecm.core.api.blobholder.SimpleBlobHolder; 042import org.nuxeo.ecm.core.convert.api.ConversionService; 043import org.nuxeo.ecm.platform.mimetype.interfaces.MimetypeRegistry; 044import org.nuxeo.ecm.restapi.jaxrs.io.conversion.ConversionScheduled; 045import org.nuxeo.ecm.restapi.server.jaxrs.blob.BlobObject; 046import org.nuxeo.ecm.webengine.model.WebAdapter; 047import org.nuxeo.ecm.webengine.model.exceptions.IllegalParameterException; 048import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException; 049import org.nuxeo.ecm.webengine.model.impl.DefaultAdapter; 050import org.nuxeo.runtime.api.Framework; 051import org.nuxeo.runtime.transaction.TransactionHelper; 052 053/** 054 * Adapter allowing to convert a Blob using a named converter or a destination mime type. 055 * 056 * @since 7.3 057 */ 058@WebAdapter(name = ConvertAdapter.NAME, type = "convertAdapter") 059@Produces({ "application/json+nxentity", MediaType.APPLICATION_JSON }) 060public class ConvertAdapter extends DefaultAdapter { 061 062 public static final String NAME = "convert"; 063 064 @GET 065 public Blob convert(@QueryParam("converter") String converter, @QueryParam("type") String type, 066 @QueryParam("format") String format, @Context UriInfo uriInfo) { 067 BlobHolder bh = getBlobHolderToConvert(); 068 069 boolean txWasActive = false; 070 try { 071 if (TransactionHelper.isTransactionActive()) { 072 txWasActive = true; 073 TransactionHelper.commitOrRollbackTransaction(); 074 } 075 076 if (StringUtils.isNotBlank(converter)) { 077 return convertWithConverter(bh, converter, uriInfo); 078 } else if (StringUtils.isNotBlank(type)) { 079 return convertWithMimeType(bh, type, uriInfo); 080 } else if (StringUtils.isNotBlank(format)) { 081 return convertWithFormat(bh, format, uriInfo); 082 } else { 083 throw new IllegalParameterException("No converter, type or format parameter specified"); 084 } 085 } finally { 086 if (txWasActive && !TransactionHelper.isTransactionActiveOrMarkedRollback()) { 087 TransactionHelper.startTransaction(); 088 } 089 } 090 } 091 092 protected BlobHolder getBlobHolderToConvert() { 093 Blob blob = getTarget().getAdapter(Blob.class); 094 BlobHolder bh = null; 095 if (blob == null) { 096 DocumentModel doc = getTarget().getAdapter(DocumentModel.class); 097 if (doc != null) { 098 bh = doc.getAdapter(BlobHolder.class); 099 if (bh != null) { 100 blob = bh.getBlob(); 101 } 102 } 103 } 104 if (blob == null) { 105 throw new IllegalParameterException("No Blob found"); 106 } 107 108 if (getTarget().isInstanceOf("blob")) { 109 bh = ((BlobObject) getTarget()).getBlobHolder(); 110 } 111 112 if (bh == null) { 113 bh = new SimpleBlobHolder(blob); 114 } 115 return bh; 116 } 117 118 protected Blob convertWithConverter(BlobHolder bh, String converter, UriInfo uriInfo) { 119 ConversionService conversionService = Framework.getService(ConversionService.class); 120 if (!conversionService.isConverterAvailable(converter).isAvailable()) { 121 throw new IllegalParameterException(String.format("The '%s' converter is not available", converter)); 122 } 123 Map<String, Serializable> parameters = computeConversionParameters(uriInfo); 124 BlobHolder blobHolder = conversionService.convert(converter, bh, parameters); 125 Blob conversionBlob = blobHolder.getBlob(); 126 if (conversionBlob == null) { 127 throw new WebResourceNotFoundException(String.format("No converted Blob using '%s' converter", converter)); 128 } 129 return conversionBlob; 130 } 131 132 protected Map<String, Serializable> computeConversionParameters(UriInfo uriInfo) { 133 MultivaluedMap<String, String> queryParams = uriInfo.getQueryParameters(); 134 Map<String, Serializable> parameters = new HashMap<>(); 135 for (String parameterKey : queryParams.keySet()) { 136 parameters.put(parameterKey, queryParams.getFirst(parameterKey)); 137 } 138 return parameters; 139 } 140 141 protected Blob convertWithMimeType(BlobHolder bh, String mimeType, UriInfo uriInfo) { 142 Map<String, Serializable> parameters = computeConversionParameters(uriInfo); 143 ConversionService conversionService = Framework.getService(ConversionService.class); 144 BlobHolder blobHolder = conversionService.convertToMimeType(mimeType, bh, parameters); 145 Blob conversionBlob = blobHolder.getBlob(); 146 if (conversionBlob == null) { 147 throw new WebResourceNotFoundException(String.format("No converted Blob for '%s' mime type", mimeType)); 148 } 149 return conversionBlob; 150 } 151 152 protected Blob convertWithFormat(BlobHolder bh, String format, UriInfo uriInfo) { 153 MimetypeRegistry mimetypeRegistry = Framework.getService(MimetypeRegistry.class); 154 String mimeType = mimetypeRegistry.getMimetypeFromExtension(format); 155 return convertWithMimeType(bh, mimeType, uriInfo); 156 } 157 158 @POST 159 public Object convert(@FormParam("converter") String converter, @FormParam("type") String type, 160 @FormParam("format") String format, @FormParam("async") boolean async, @Context UriInfo uriInfo) { 161 if (!async) { 162 return convert(converter, type, format, uriInfo); 163 } 164 165 String conversionId; 166 BlobHolder bh = getBlobHolderToConvert(); 167 Map<String, Serializable> parameters = computeConversionParameters(uriInfo); 168 ConversionService conversionService = Framework.getService(ConversionService.class); 169 if (StringUtils.isNotBlank(converter)) { 170 conversionId = conversionService.scheduleConversion(converter, bh, parameters); 171 } else if (StringUtils.isNotBlank(type)) { 172 conversionId = conversionService.scheduleConversionToMimeType(type, bh, parameters); 173 } else if (StringUtils.isNotBlank(format)) { 174 MimetypeRegistry mimetypeRegistry = Framework.getService(MimetypeRegistry.class); 175 String mimeType = mimetypeRegistry.getMimetypeFromExtension(format); 176 conversionId = conversionService.scheduleConversionToMimeType(mimeType, bh, parameters); 177 } else { 178 throw new IllegalParameterException("No converter, type or format parameter specified"); 179 } 180 181 String serverURL = ctx.getServerURL().toString(); 182 if (serverURL.endsWith("/")) { 183 serverURL = serverURL.substring(0, serverURL.length() - 1); 184 } 185 String pollingURL = String.format("%s%s/conversions/%s/poll", serverURL, ctx.getModulePath(), conversionId); 186 ConversionScheduled conversionScheduled = new ConversionScheduled(conversionId, pollingURL); 187 try { 188 return Response.status(Response.Status.ACCEPTED) 189 .location(new URI(pollingURL)) 190 .entity(conversionScheduled) 191 .build(); 192 } catch (URISyntaxException e) { 193 throw new NuxeoException(e); 194 } 195 } 196}