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