/** * Copyright (c) 2000-present Liferay, Inc. 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 com.liferay.portal.template.freemarker.internal; import com.liferay.portal.kernel.template.StringTemplateResource; import com.liferay.portal.kernel.template.TemplateConstants; import com.liferay.portal.kernel.template.TemplateException; import com.liferay.portal.kernel.template.TemplateResource; import com.liferay.portal.template.AbstractSingleResourceTemplate; import com.liferay.portal.template.TemplateContextHelper; import com.liferay.portal.template.TemplateResourceThreadLocal; import freemarker.core.ParseException; import freemarker.ext.util.WrapperTemplateModel; import freemarker.template.AdapterTemplateModel; import freemarker.template.Configuration; import freemarker.template.ObjectWrapper; import freemarker.template.SimpleCollection; import freemarker.template.Template; import freemarker.template.TemplateCollectionModel; import freemarker.template.TemplateHashModelEx; import freemarker.template.TemplateModel; import freemarker.template.TemplateModelException; import freemarker.template.TemplateModelWithAPISupport; import freemarker.template.WrappingTemplateModel; import freemarker.template.utility.ObjectWrapperWithAPISupport; import java.io.Serializable; import java.io.Writer; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.HashMap; import java.util.Map; /** * @author Mika Koivisto * @author Tina Tian */ public class FreeMarkerTemplate extends AbstractSingleResourceTemplate { public FreeMarkerTemplate( TemplateResource templateResource, TemplateResource errorTemplateResource, Map<String, Object> context, Configuration configuration, TemplateContextHelper templateContextHelper, boolean privileged, long interval) { super( templateResource, errorTemplateResource, context, templateContextHelper, TemplateConstants.LANG_TYPE_FTL, interval); _configuration = configuration; _privileged = privileged; } @Override protected void handleException(Exception exception, Writer writer) throws TemplateException { if ((exception instanceof ParseException) || (exception instanceof freemarker.template.TemplateException)) { put("exception", exception.getMessage()); if (templateResource instanceof StringTemplateResource) { StringTemplateResource stringTemplateResource = (StringTemplateResource)templateResource; put("script", stringTemplateResource.getContent()); } if (exception instanceof ParseException) { ParseException pe = (ParseException)exception; put("column", pe.getColumnNumber()); put("line", pe.getLineNumber()); } try { processTemplate(errorTemplateResource, writer); } catch (Exception e) { throw new TemplateException( "Unable to process FreeMarker template " + errorTemplateResource.getTemplateId(), e); } } else { throw new TemplateException( "Unable to process FreeMarker template " + templateResource.getTemplateId(), exception); } } @Override protected void processTemplate( TemplateResource templateResource, Writer writer) throws Exception { TemplateResourceThreadLocal.setTemplateResource( TemplateConstants.LANG_TYPE_FTL, templateResource); try { Template template = null; if (_privileged) { template = AccessController.doPrivileged( new TemplatePrivilegedExceptionAction(templateResource)); } else { template = _configuration.getTemplate( getTemplateResourceUUID(templateResource), TemplateConstants.DEFAUT_ENCODING); } template.process( new CachableDefaultMapAdapter( context, template.getObjectWrapper()), writer); } catch (PrivilegedActionException pae) { throw pae.getException(); } finally { TemplateResourceThreadLocal.setTemplateResource( TemplateConstants.LANG_TYPE_FTL, null); } } private static final TemplateModel _NULL_TEMPLATE_MODEL = new TemplateModel() {}; private final Configuration _configuration; private final boolean _privileged; private class CachableDefaultMapAdapter extends WrappingTemplateModel implements TemplateHashModelEx, AdapterTemplateModel, WrapperTemplateModel, TemplateModelWithAPISupport, Serializable { @Override public TemplateModel get(String key) throws TemplateModelException { TemplateModel templateModel = _wrappedValueMap.get(key); if (templateModel == _NULL_TEMPLATE_MODEL) { return null; } if (templateModel != null) { return templateModel; } Object value = _map.get(key); if (value == null) { _wrappedValueMap.put(key, _NULL_TEMPLATE_MODEL); return null; } templateModel = _objectWrapper.wrap(value); _wrappedValueMap.put(key, templateModel); return templateModel; } @Override @SuppressWarnings("rawtypes") public Object getAdaptedObject(Class hint) { return _map; } @Override public TemplateModel getAPI() throws TemplateModelException { return ((ObjectWrapperWithAPISupport)_objectWrapper).wrapAsAPI( _map); } @Override public Object getWrappedObject() { return _map; } @Override public boolean isEmpty() { return _map.isEmpty(); } @Override public TemplateCollectionModel keys() { return new SimpleCollection(_map.keySet(), _objectWrapper); } @Override public int size() { return _map.size(); } @Override public TemplateCollectionModel values() { return new SimpleCollection(_map.values(), _objectWrapper); } private CachableDefaultMapAdapter( Map<String, Object> map, ObjectWrapper objectWrapper) { super(objectWrapper); _map = map; _objectWrapper = objectWrapper; _wrappedValueMap = new HashMap<>(); } private final Map<String, Object> _map; private final ObjectWrapper _objectWrapper; private final Map<String, TemplateModel> _wrappedValueMap; } private class TemplatePrivilegedExceptionAction implements PrivilegedExceptionAction<Template> { public TemplatePrivilegedExceptionAction( TemplateResource templateResource) { _templateResource = templateResource; } @Override public Template run() throws Exception { return _configuration.getTemplate( getTemplateResourceUUID(_templateResource), TemplateConstants.DEFAUT_ENCODING); } private final TemplateResource _templateResource; } }