/* * Copyright 2017 Graz University of Technology EAAF-Core Components has been developed in a * cooperation between EGIZ, A-SIT Plus, A-SIT, and Graz University of Technology. * * Licensed under the EUPL, Version 1.2 or - as soon they will be approved by the European * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in * compliance with the Licence. You may obtain a copy of the Licence at: * https://joinup.ec.europa.eu/news/understanding-eupl-v12 * * Unless required by applicable law or agreed to in writing, software distributed under the Licence * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the Licence for the specific language governing permissions and limitations under * the Licence. * * This product combines work with different licenses. See the "NOTICE" text file for details on the * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative * works that you distribute must include a readable copy of the "NOTICE" text file. */ package at.gv.egiz.eaaf.core.impl.gui; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringWriter; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.apache.velocity.VelocityContext; import org.apache.velocity.app.VelocityEngine; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import at.gv.egiz.eaaf.core.api.data.EaafConstants; import at.gv.egiz.eaaf.core.api.gui.IGuiBuilderConfiguration; import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiBuilderConfiguration; import at.gv.egiz.eaaf.core.api.gui.IVelocityGuiFormBuilder; import at.gv.egiz.eaaf.core.exceptions.GuiBuildException; import at.gv.egiz.eaaf.core.impl.gui.velocity.VelocityProvider; /** * Abstract VeloCity based GUI builder implementation. * * @author tlenz * */ public abstract class AbstractVelocityGuiFormBuilderImpl implements IVelocityGuiFormBuilder { private static final Logger log = LoggerFactory.getLogger(AbstractVelocityGuiFormBuilderImpl.class); private static final String DEFAULT_CONTENT_TYPE = EaafConstants.CONTENTTYPE_HTML_UTF8; private VelocityEngine engine; /** * Velocity based GUI builder. * * @throws GuiBuildException In case of a error */ public AbstractVelocityGuiFormBuilderImpl() throws GuiBuildException { try { engine = VelocityProvider.getClassPathVelocityEngine(); } catch (final Exception e) { log.error("Initialization of Velocity-Engine to render GUI components FAILED.", e); throw new GuiBuildException( "Initialization of Velocity-Engine to render GUI components FAILED.", e); } } @Override public final void build(final HttpServletRequest httpReq, final HttpServletResponse httpResp, final IGuiBuilderConfiguration config, final String loggerName) throws GuiBuildException { if (config instanceof IVelocityGuiBuilderConfiguration) { build(httpReq, httpResp, (IVelocityGuiBuilderConfiguration) config, loggerName); } else { throw new IllegalStateException(this.getClass().getName() + " needs a " + IVelocityGuiBuilderConfiguration.class.getName()); } } @Override public final void build(final HttpServletRequest httpReq, final HttpServletResponse httpResp, final IGuiBuilderConfiguration config, final String contentType, final String loggerName) throws GuiBuildException { if (config instanceof IVelocityGuiBuilderConfiguration) { build(httpReq, httpResp, (IVelocityGuiBuilderConfiguration) config, contentType, loggerName); } else { throw new IllegalStateException(this.getClass().getName() + " needs a " + IVelocityGuiBuilderConfiguration.class.getName()); } } @Override public void build(final HttpServletRequest httpReq, final HttpServletResponse httpResp, final IVelocityGuiBuilderConfiguration config, final String loggerName) throws GuiBuildException { build(httpReq, httpResp, config, getInternalContentType(config), loggerName); } @Override public void build(final HttpServletRequest httpReq, final HttpServletResponse httpResp, final IVelocityGuiBuilderConfiguration config, final String contentType, final String loggerName) throws GuiBuildException { InputStream is = null; try { final String viewName = config.getViewName(); is = getTemplateInputStream(config); // build Velocity Context from input paramters final VelocityContext context = buildContextFromViewParams(config.getViewParameters()); // evaluate template final StringWriter writer = new StringWriter(); engine.evaluate(context, writer, loggerName, new BufferedReader(new InputStreamReader(is, "UTF-8"))); // write template to response final byte[] content = writer.toString().getBytes("UTF-8"); httpResp.setStatus(HttpServletResponse.SC_OK); httpResp.setContentLength(content.length); httpResp.setContentType(contentType); httpResp.getOutputStream().write(content); if (log.isTraceEnabled()) { log.trace("Write Content for viewName:" + viewName + ". Contentsize:" + String.valueOf(content.length) + " BufferSize:" + httpResp.getBufferSize() + " ContentType:" + contentType); for (final String el : httpResp.getHeaderNames()) { log.trace(" * Headername:" + el + " Value:" + httpResp.getHeader(el)); } } } catch (final IOException e) { log.error("GUI form-builder has an internal error.", e); throw new GuiBuildException("GUI form-builder has an internal error.", e); } finally { if (is != null) { try { is.close(); } catch (final IOException e) { log.error("Can NOT close GUI-Template InputStream.", e); } } } } /** * Generate a new {@link VelocityContext} and populate it with MOA-ID GUI * parameters. * * @param config GUI builder config * @return Context of Velocity engine */ @Override public VelocityContext generateVelocityContextFromConfiguration( final IVelocityGuiBuilderConfiguration config) { return buildContextFromViewParams(config.getViewParameters()); } /** * Load the template from different resources. * * @param config GUI builder config * @return An {@link InputStream} but never null. The {@link InputStream} had to * be closed be the invoking method * @throws GuiBuildException In case of an error */ @Override public InputStream getTemplateInputStream(final IVelocityGuiBuilderConfiguration config) throws GuiBuildException { InputStream is = config.getTemplate(config.getViewName()); if (is == null) { log.trace("Loading GUI template:" + config.getViewName() + " from default resources ... "); is = getInternalTemplate(config); if (is == null) { log.warn("No GUI with viewName:" + config.getViewName() + " FOUND."); throw new GuiBuildException("No GUI with viewName:" + config.getViewName() + " FOUND."); } } return is; } /** * Load an internal template from default resources. * * @param config GUI builder config * @return Template that should be used * @throws GuiBuildException in case of an error */ protected abstract InputStream getInternalTemplate(IVelocityGuiBuilderConfiguration config) throws GuiBuildException; protected String getInternalClasspathTemplateDir(final IVelocityGuiBuilderConfiguration config, final String defaultClassPathDir) { String dir = config.getClasspathTemplateDir(); if (dir != null) { if (!dir.endsWith("/")) { dir += "/"; } return dir; } else { return defaultClassPathDir; } } private VelocityContext buildContextFromViewParams(final Map viewParams) { final VelocityContext context = new VelocityContext(); if (viewParams != null) { final Iterator> interator = viewParams.entrySet().iterator(); while (interator.hasNext()) { final Entry el = interator.next(); context.put(el.getKey(), el.getValue()); } } return context; } private String getInternalContentType(final IGuiBuilderConfiguration config) { if (StringUtils.isEmpty(config.getDefaultContentType())) { return DEFAULT_CONTENT_TYPE; } else { return config.getDefaultContentType(); } } }