/** * Copyright (C) 2014 BonitaSoft S.A. * BonitaSoft, 32 rue Gustave Eiffel - 38000 Grenoble * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2.0 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package org.bonitasoft.console.common.server.page; import java.io.File; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; import javax.servlet.http.HttpServletRequest; import org.bonitasoft.console.common.server.page.extension.PageContextImpl; import org.bonitasoft.console.common.server.page.extension.PageResourceProviderImpl; import org.bonitasoft.console.common.server.page.extension.RestAPIContextImpl; import org.bonitasoft.console.common.server.page.extension.RestApiUtilImpl; import org.bonitasoft.engine.api.APIClient; import org.bonitasoft.engine.exception.BonitaException; import org.bonitasoft.engine.page.Page; import org.bonitasoft.engine.session.APISession; import org.bonitasoft.web.rest.server.api.extension.ResourceExtensionResolver; import org.codehaus.groovy.control.CompilationFailedException; import groovy.lang.GroovyClassLoader; /** * Class used by servlets to display a custom rest api * Since each instance of the servlet carry an instance of this class, it should have absolutely no instance attribute * * @author Laurent Leseigneur */ public class RestApiRenderer { private static final Logger LOGGER = Logger.getLogger(RestApiRenderer.class.getName()); private final CustomPageService customPageService = new CustomPageService(); public RestApiResponse handleRestApiCall(final HttpServletRequest request, ResourceExtensionResolver resourceExtensionResolver) throws CompilationFailedException, InstantiationException, IllegalAccessException, IOException, BonitaException { final PageContextHelper pageContextHelper = new PageContextHelper(request); final APISession apiSession = pageContextHelper.getApiSession(); final Long pageId = resourceExtensionResolver.resolvePageId(apiSession); final Page page = customPageService.getPage(apiSession, pageId); final PageResourceProviderImpl pageResourceProvider = new PageResourceProviderImpl(page, apiSession.getTenantId()); customPageService.ensurePageFolderIsUpToDate(apiSession, pageResourceProvider); final File restApiControllerFile = resourceExtensionResolver.resolveRestApiControllerFile(pageResourceProvider); final String mappingKey = resourceExtensionResolver.generateMappingKey(); if (restApiControllerFile.exists()) { return renderResponse(request, apiSession, pageContextHelper, pageResourceProvider, restApiControllerFile, mappingKey); } LOGGER.log(Level.SEVERE, "resource does not exists:" + mappingKey); throw new BonitaException("unable to handle rest api call to " + mappingKey); } private RestApiResponse renderResponse(final HttpServletRequest request, final APISession apiSession, final PageContextHelper pageContextHelper, final PageResourceProviderImpl pageResourceProvider, File restApiControllerFile, String mappingKey) throws CompilationFailedException, InstantiationException, IllegalAccessException, IOException, BonitaException { final ClassLoader originalClassloader = Thread.currentThread().getContextClassLoader(); final GroovyClassLoader pageClassloader = customPageService.getPageClassloader(apiSession, pageResourceProvider); try { Thread.currentThread().setContextClassLoader(pageClassloader); final Class<?> restApiControllerClass = customPageService.registerRestApiPage(pageClassloader, restApiControllerFile); pageResourceProvider.setResourceClassLoader(pageClassloader); try { return doHandle(request, apiSession, pageContextHelper, pageResourceProvider, restApiControllerClass); } catch (Throwable e) { LOGGER.log(Level.SEVERE, "Error when executing rest api extension call to " + mappingKey, e); throw e; } } finally { Thread.currentThread().setContextClassLoader(originalClassloader); } } protected RestApiResponse doHandle(final HttpServletRequest request, final APISession apiSession, final PageContextHelper pageContextHelper, final PageResourceProviderImpl pageResourceProvider, final Class<?> restApiControllerClass) throws InstantiationException, IllegalAccessException { if (RestApiController.class.isAssignableFrom(restApiControllerClass)) {//LEGACY MODE final RestApiController restApiController = instantiate(restApiControllerClass, RestApiController.class); return restApiController.doHandle(request, pageResourceProvider, new PageContextImpl(apiSession, pageContextHelper.getCurrentLocale(), pageContextHelper.getCurrentProfile()), new RestApiResponseBuilder(), new RestApiUtilImpl()); } else { final org.bonitasoft.web.extension.rest.RestApiController restApiController = instantiate(restApiControllerClass, org.bonitasoft.web.extension.rest.RestApiController.class); return restApiController.doHandle(request, new org.bonitasoft.web.extension.rest.RestApiResponseBuilder(), new RestAPIContextImpl(apiSession, new APIClient(apiSession), pageContextHelper.getCurrentLocale(), pageResourceProvider)); } } protected <T extends Object> T instantiate(Class<?> baseClass, Class<T> toClass) throws InstantiationException, IllegalAccessException { return (T) baseClass.newInstance(); } }