/**
* 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.rendering;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import org.apereo.portal.layout.IStylesheetUserPreferencesService;
import org.apereo.portal.layout.IStylesheetUserPreferencesService.PreferencesScope;
import org.apereo.portal.layout.IUserLayoutManager;
import org.apereo.portal.layout.om.ILayoutAttributeDescriptor;
import org.apereo.portal.layout.om.IStylesheetDescriptor;
import org.apereo.portal.layout.om.IStylesheetUserPreferences;
import org.apereo.portal.spring.spel.IPortalSpELService;
import org.apereo.portal.utils.cache.CacheKey;
import org.apereo.portal.utils.cache.CacheKey.CacheKeyBuilder;
import org.slf4j.Logger;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.expression.EvaluationException;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.request.WebRequest;
/**
* Base implementation of layout attribute source that feeds off of {@link IStylesheetDescriptor}
* and {@link IStylesheetUserPreferences} data
*
*/
public abstract class StylesheetAttributeSource implements AttributeSource, BeanNameAware {
private final XMLEventFactory xmlEventFactory = XMLEventFactory.newFactory();
private String name;
protected IPortalSpELService portalSpELService;
protected IStylesheetUserPreferencesService stylesheetUserPreferencesService;
@Autowired
public void setPortalSpELService(IPortalSpELService portalSpELService) {
this.portalSpELService = portalSpELService;
}
@Autowired
public void setStylesheetUserPreferencesService(
IStylesheetUserPreferencesService stylesheetUserPreferencesService) {
this.stylesheetUserPreferencesService = stylesheetUserPreferencesService;
}
@Override
public void setBeanName(String name) {
this.name = name;
}
@Override
public final Iterator<Attribute> getAdditionalAttributes(
HttpServletRequest request, HttpServletResponse response, StartElement event) {
final IStylesheetDescriptor stylesheetDescriptor = this.getStylesheetDescriptor(request);
final PreferencesScope stylesheetPreferencesScope =
this.getStylesheetPreferencesScope(request);
final Collection<Attribute> attributes = new LinkedList<Attribute>();
for (final ILayoutAttributeDescriptor layoutAttributeDescriptor :
stylesheetDescriptor.getLayoutAttributeDescriptors()) {
final Set<String> targetElementNames =
layoutAttributeDescriptor.getTargetElementNames();
final QName eventName = event.getName();
final String localEventName = eventName.getLocalPart();
if (targetElementNames.contains(localEventName)) {
final Attribute subscribeIdAttr =
event.getAttributeByName(IUserLayoutManager.ID_ATTR_NAME);
final String subscribeId = subscribeIdAttr.getValue();
final String name = layoutAttributeDescriptor.getName();
String value =
this.stylesheetUserPreferencesService.getLayoutAttribute(
request, stylesheetPreferencesScope, subscribeId, name);
if (value == null) {
value = layoutAttributeDescriptor.getDefaultValue();
}
if (value != null) {
if (this.shouldDoSpelEvaluationForAttributeValue(value)) {
final ServletWebRequest webRequest =
new ServletWebRequest(request, response);
value = this.doSpelEvaluationForAttributeValue(webRequest, value);
}
if (value != null) {
final Attribute attribute = xmlEventFactory.createAttribute(name, value);
attributes.add(attribute);
}
}
}
}
return attributes.iterator();
}
@Override
public final CacheKey getCacheKey(HttpServletRequest request, HttpServletResponse response) {
final PreferencesScope stylesheetPreferencesScope =
this.getStylesheetPreferencesScope(request);
final CacheKeyBuilder<String, String> cacheKeyBuilder = CacheKey.builder(this.name);
final Iterable<String> layoutAttributeNodeIds =
this.stylesheetUserPreferencesService.getAllLayoutAttributeNodeIds(
request, stylesheetPreferencesScope);
for (final String nodeId : layoutAttributeNodeIds) {
cacheKeyBuilder.add(nodeId);
this.stylesheetUserPreferencesService.populateLayoutAttributes(
request, stylesheetPreferencesScope, nodeId, cacheKeyBuilder);
}
return cacheKeyBuilder.build();
}
public IStylesheetDescriptor getStylesheetDescriptor(HttpServletRequest request) {
final PreferencesScope stylesheetPreferencesScope =
this.getStylesheetPreferencesScope(request);
return this.stylesheetUserPreferencesService.getStylesheetDescriptor(
request, stylesheetPreferencesScope);
}
public abstract PreferencesScope getStylesheetPreferencesScope(HttpServletRequest request);
protected abstract Logger getLogger();
protected boolean shouldDoSpelEvaluationForAttributeValue(final String attributeValue) {
return this.portalSpELService != null
&& attributeValue != null
&& attributeValue.startsWith("${")
&& attributeValue.endsWith("}");
}
protected String getValueForSpelEvaluation(final String attributeValue) {
if (attributeValue != null
&& attributeValue.startsWith("${")
&& attributeValue.endsWith("}")) {
return attributeValue.substring(2, attributeValue.length() - 1);
} else {
return attributeValue;
}
}
protected String doSpelEvaluationForAttributeValue(
final WebRequest request, final String attributeValue) {
String result;
try {
final String valueForEvaluation = this.getValueForSpelEvaluation(attributeValue);
final Expression expression =
this.portalSpELService.parseExpression(valueForEvaluation);
result = this.portalSpELService.getValue(expression, request, String.class);
} catch (ParseException e) {
this.getLogger()
.info("SpEL parse exception parsing: {}; Exception: {}", attributeValue, e);
result = attributeValue;
} catch (EvaluationException e) {
this.getLogger()
.info(
"SpEL evaluation exception evaluating: {}; Exception: {}",
attributeValue,
e);
result = attributeValue;
}
return result;
}
}