/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apereo.portal.portlet;
import java.util.Map;
import javax.portlet.PortletRequest;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.expression.BeanResolver;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.portlet.context.PortletWebRequest;
/**
* PortletSpELServiceImpl provides the default implementation of IPortletSpELService.
*
* Bourey)
*/
@Service
public class PortletSpELServiceImpl implements BeanFactoryAware, IPortletSpELService {
protected final Log logger = LogFactory.getLog(this.getClass());
private ExpressionParser expressionParser = new SpelExpressionParser();
private Ehcache expressionCache;
private BeanResolver beanResolver;
public void setExpressionParser(ExpressionParser expressionParser) {
Validate.notNull(expressionParser);
this.expressionParser = expressionParser;
}
@Autowired
public void setExpressionCache(
@Qualifier("portletSpELExpressionCache") Ehcache expressionCache) {
this.expressionCache = expressionCache;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanResolver = new BeanFactoryResolver(beanFactory);
}
// Primary method used assuming all defaults.
@Override
public String parseString(String expressionString, PortletRequest request) {
return getValue(expressionString, request, String.class);
}
@Override
public <T> T getValue(
String expressionString, PortletRequest request, Class<T> desiredResultType) {
final Expression expression = parseExpression(expressionString);
final EvaluationContext evaluationContext = getEvaluationContext(request);
return expression.getValue(evaluationContext, desiredResultType);
}
@Override
public Expression parseExpression(String expressionString) throws ParseException {
if (this.expressionCache == null) {
return parseExpression(expressionString, TemplateParserContext.INSTANCE);
}
Element element = this.expressionCache.get(expressionString);
if (element != null) {
return (Expression) element.getObjectValue();
}
final Expression expression =
parseExpression(expressionString, TemplateParserContext.INSTANCE);
element = new Element(expressionString, expression);
this.expressionCache.put(element);
return expression;
}
private Expression parseExpression(String expressionString, ParserContext parserContext)
throws ParseException {
if (parserContext == null) {
return this.expressionParser.parseExpression(expressionString);
}
return this.expressionParser.parseExpression(expressionString, parserContext);
}
/**
* Return a SpEL evaluation context for the supplied portlet request.
*
* @param request PortletRequest
* @return SpEL evaluation context for the supplied portlet request
*/
protected EvaluationContext getEvaluationContext(PortletRequest request) {
Map<String, String> userInfo =
(Map<String, String>) request.getAttribute(PortletRequest.USER_INFO);
final SpELEnvironmentRoot root =
new SpELEnvironmentRoot(new PortletWebRequest(request), userInfo);
final StandardEvaluationContext context = new StandardEvaluationContext(root);
// Allows for @myBeanName replacements
context.setBeanResolver(this.beanResolver);
return context;
}
/**
* Limited-use POJO representing the root of a SpEL environment. At the current moment, we're
* only using the request object and user info in the evaluation context. Can add additional
* objects in the future.
*/
private static class SpELEnvironmentRoot {
private final WebRequest request;
private final Map<String, String> userInfo;
/**
* Create a new SpEL environment root for use in a SpEL evaluation context.
*
* @param request web request
*/
private SpELEnvironmentRoot(WebRequest request, Map<String, String> userInfo) {
this.request = request;
this.userInfo = userInfo;
}
/** Get the request associated with this environment root. */
public WebRequest getRequest() {
return request;
}
/**
* User attributes associated with the person in this request.
*
* @return userInfo
*/
public Map<String, String> getUserInfo() {
return userInfo;
}
}
public static class TemplateParserContext implements ParserContext {
public static final TemplateParserContext INSTANCE = new TemplateParserContext();
@Override
public String getExpressionPrefix() {
return "${";
}
@Override
public String getExpressionSuffix() {
return "}";
}
@Override
public boolean isTemplate() {
return true;
}
}
}