/* * Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library 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 Lesser General Public License for more * details. */ package org.entando.entando.aps.system.services.controller.executor; import com.agiletec.aps.system.RequestContext; import com.agiletec.aps.system.SystemConstants; import com.agiletec.aps.system.exception.ApsSystemException; import com.agiletec.aps.system.services.authorization.IAuthorizationManager; import com.agiletec.aps.system.services.group.Group; import com.agiletec.aps.system.services.page.IPage; import com.agiletec.aps.system.services.page.Widget; import com.agiletec.aps.system.services.user.UserDetails; import com.agiletec.aps.tags.util.IFrameDecoratorContainer; import com.agiletec.aps.util.ApsWebApplicationUtils; import freemarker.template.Template; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.StringReader; import java.io.Writer; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javax.servlet.RequestDispatcher; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanComparator; import org.apache.commons.lang.StringUtils; import org.entando.entando.aps.system.services.guifragment.GuiFragment; import org.entando.entando.aps.system.services.guifragment.IGuiFragmentManager; import org.entando.entando.aps.system.services.widgettype.WidgetType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.context.WebApplicationContext; /** * @author E.Santoboni */ public abstract class AbstractWidgetExecutorService { private static final Logger _logger = LoggerFactory.getLogger(AbstractWidgetExecutorService.class); protected void buildWidgetsOutput(RequestContext reqCtx, IPage page, String[] widgetOutput) throws ApsSystemException { try { List<IFrameDecoratorContainer> decorators = this.extractDecorators(reqCtx); Widget[] widgets = page.getWidgets(); for (int frame = 0; frame < widgets.length; frame++) { reqCtx.addExtraParam(SystemConstants.EXTRAPAR_CURRENT_FRAME, new Integer(frame)); Widget widget = widgets[frame]; widgetOutput[frame] = this.buildWidgetOutput(reqCtx, widget, decorators); } } catch (Throwable t) { String msg = "Error detected during widget preprocessing"; _logger.error(msg, t); throw new ApsSystemException(msg, t); } } protected String buildWidgetOutput(RequestContext reqCtx, Widget widget, List<IFrameDecoratorContainer> decorators) throws ApsSystemException { StringBuilder buffer = new StringBuilder(); try { if (null != widget && this.isUserAllowed(reqCtx, widget)) { reqCtx.addExtraParam(SystemConstants.EXTRAPAR_CURRENT_WIDGET, widget); } else { reqCtx.removeExtraParam(SystemConstants.EXTRAPAR_CURRENT_WIDGET); } buffer.append(this.extractDecoratorsOutput(reqCtx, widget, decorators, false, true)); if (null != widget && this.isUserAllowed(reqCtx, widget)) { String widgetOutput = extractWidgetOutput(reqCtx, widget.getType()); //String widgetJspPath = widget.getType().getJspPath(); buffer.append(this.extractDecoratorsOutput(reqCtx, widget, decorators, true, true)); //buffer.append(this.extractJspOutput(reqCtx, widgetJspPath)); buffer.append(widgetOutput); buffer.append(this.extractDecoratorsOutput(reqCtx, widget, decorators, true, false)); } buffer.append(this.extractDecoratorsOutput(reqCtx, widget, decorators, false, false)); } catch (Throwable t) { String msg = "Error creating widget output"; _logger.error(msg, t); throw new RuntimeException(msg, t); } return buffer.toString(); } public static String extractWidgetOutput(RequestContext reqCtx, WidgetType type) throws ApsSystemException { if (null == type) { return ""; } String widgetTypeCode = (type.isLogic()) ? type.getParentType().getCode() : type.getCode(); try { IGuiFragmentManager guiFragmentManager = (IGuiFragmentManager) ApsWebApplicationUtils.getBean(SystemConstants.GUI_FRAGMENT_MANAGER, reqCtx.getRequest()); GuiFragment guiFragment = guiFragmentManager.getUniqueGuiFragmentByWidgetType(widgetTypeCode); if (null != guiFragment) { String fragmentOutput = extractFragmentOutput(guiFragment, reqCtx); if (StringUtils.isBlank(fragmentOutput)) { _logger.info("The fragment '{}' of widget '{}' is not available", guiFragment.getCode(), widgetTypeCode); return "The fragment '" + guiFragment.getCode() + "' of widget '" + widgetTypeCode + "' is not available"; } return fragmentOutput; } else { String widgetJspPath = type.getJspPath(); return extractJspWidgetOutput(widgetTypeCode, reqCtx, widgetJspPath); } } catch (Throwable t) { String msg = "Error creating widget output - Type '" + widgetTypeCode + "'"; _logger.error(msg, t); throw new ApsSystemException(msg, t); } } protected List<IFrameDecoratorContainer> extractDecorators(RequestContext reqCtx) throws ApsSystemException { HttpServletRequest request = reqCtx.getRequest(); WebApplicationContext wac = ApsWebApplicationUtils.getWebApplicationContext(request); List<IFrameDecoratorContainer> containters = new ArrayList<IFrameDecoratorContainer>(); try { String[] beanNames = wac.getBeanNamesForType(IFrameDecoratorContainer.class); for (int i = 0; i < beanNames.length; i++) { IFrameDecoratorContainer container = (IFrameDecoratorContainer) wac.getBean(beanNames[i]); containters.add(container); } BeanComparator comparator = new BeanComparator("order"); Collections.sort(containters, comparator); } catch (Throwable t) { _logger.error("Error extracting widget decorators", t); throw new ApsSystemException("Error extracting widget decorators", t); } return containters; } protected String extractDecoratorsOutput(RequestContext reqCtx, Widget widget, List<IFrameDecoratorContainer> decorators, boolean isWidgetDecorator, boolean includeHeader) throws Throwable { if (null == decorators || decorators.isEmpty()) { return ""; } StringBuilder builder = new StringBuilder(); for (int i = 0; i < decorators.size(); i++) { IFrameDecoratorContainer decoratorContainer = (includeHeader) ? decorators.get(i) : decorators.get(decorators.size() - i - 1); if ((isWidgetDecorator != decoratorContainer.isWidgetDecorator()) || !decoratorContainer.needsDecoration(widget, reqCtx)) { continue; } String fragmentCode = (includeHeader) ? decoratorContainer.getHeaderFragmentCode() : decoratorContainer.getFooterFragmentCode(); String fragmentOutput = extractFragmentOutput(fragmentCode, reqCtx); if (StringUtils.isNotBlank(fragmentCode)) { builder.append(fragmentOutput); } else { String jspPath = (includeHeader) ? decoratorContainer.getHeaderJspPath() : decoratorContainer.getFooterJspPath(); if (StringUtils.isNotBlank(jspPath)) { String output = extractJspOutput(reqCtx, jspPath); builder.append(output); } } } return builder.toString(); } protected String extractFragmentOutput(String fragmentCode, RequestContext reqCtx) throws Throwable { if (StringUtils.isBlank(fragmentCode)) { return null; } IGuiFragmentManager guiFragmentManager = (IGuiFragmentManager) ApsWebApplicationUtils.getBean(SystemConstants.GUI_FRAGMENT_MANAGER, reqCtx.getRequest()); GuiFragment fragment = guiFragmentManager.getGuiFragment(fragmentCode); return extractFragmentOutput(fragment, reqCtx); } protected static String extractFragmentOutput(GuiFragment fragment, RequestContext reqCtx) throws Throwable { if (null == fragment) { return null; } try { String currentGui = fragment.getCurrentGui(); if (StringUtils.isBlank(currentGui)) { _logger.info("The fragment '{}' is not available", fragment.getCode()); return ""; } ExecutorBeanContainer ebc = (ExecutorBeanContainer) reqCtx.getExtraParam(SystemConstants.EXTRAPAR_EXECUTOR_BEAN_CONTAINER); Integer frame = (Integer) reqCtx.getExtraParam(SystemConstants.EXTRAPAR_CURRENT_FRAME); Widget currentWidget = (Widget) reqCtx.getExtraParam(SystemConstants.EXTRAPAR_CURRENT_WIDGET); StringBuilder templateName = new StringBuilder(String.valueOf(frame)).append("_").append(fragment.getCode()); if (null != currentWidget && null != currentWidget.getType()) { templateName.append("_").append(currentWidget.getType().getCode()); } ByteArrayOutputStream baos = new ByteArrayOutputStream(); Writer out = new OutputStreamWriter(baos); Template template = new Template(templateName.toString(), new StringReader(currentGui), ebc.getConfiguration()); template.process(ebc.getTemplateModel(), out); out.flush(); return baos.toString().trim(); } catch (Throwable t) { String msg = "Error creating fragment output - code '" + fragment.getCode() + "'"; _logger.error(msg, t); throw new ApsSystemException(msg, t); } } protected boolean isUserAllowed(RequestContext reqCtx, Widget widget) { if (null == widget) { return false; } String widgetTypeGroup = widget.getType().getMainGroup(); try { if (null == widgetTypeGroup || widgetTypeGroup.equals(Group.FREE_GROUP_NAME)) { return true; } IAuthorizationManager authorizationManager = (IAuthorizationManager) ApsWebApplicationUtils.getBean(SystemConstants.AUTHORIZATION_SERVICE, reqCtx.getRequest()); UserDetails currentUser = (UserDetails) reqCtx.getRequest().getSession().getAttribute(SystemConstants.SESSIONPARAM_CURRENT_USER); return authorizationManager.isAuthOnGroup(currentUser, widgetTypeGroup); } catch (Throwable t) { _logger.error("Error checking user authorities", t); } return false; } protected static String extractJspWidgetOutput(String widgetTypeCode, RequestContext reqCtx, String jspPath) throws Throwable { try { return extractJspOutput(reqCtx, jspPath); } catch (IOException e) { _logger.error("The widget '{}' is unavailable. Expected jsp path '{}'", widgetTypeCode, jspPath, e); return "The widget '" + widgetTypeCode + "' is unavailable"; } catch (Throwable t) { _logger.error("Error extracting jsp output", t); throw t; } } protected static String extractJspOutput(RequestContext reqCtx, String jspPath) throws ServletException, IOException { HttpServletRequest request = reqCtx.getRequest(); HttpServletResponse response = reqCtx.getResponse(); BufferedHttpResponseWrapper wrapper = new BufferedHttpResponseWrapper(response); ServletContext context = request.getSession().getServletContext(); String url = response.encodeRedirectURL(jspPath); RequestDispatcher dispatcher = context.getRequestDispatcher(url); dispatcher.include(request, wrapper); return wrapper.getOutput(); } }