/**
* 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.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventFactory;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.events.Attribute;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.apereo.portal.utils.cache.CacheKey;
import org.apereo.portal.xml.XmlUtilitiesImpl;
import org.apereo.portal.xml.stream.FilteringXMLEventReader;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.BeanNameAware;
/**
*/
public class StAXAttributeIncorporationComponent extends StAXPipelineComponentWrapper
implements BeanNameAware {
protected final Logger logger = LoggerFactory.getLogger(getClass());
private final XMLEventFactory eventFactory = XMLEventFactory.newFactory();
private AttributeSource attributeSource;
private String beanName;
public void setAttributeSource(AttributeSource attributeSource) {
this.attributeSource = attributeSource;
}
@Override
public void setBeanName(String name) {
this.beanName = name;
}
/* (non-Javadoc)
* @see org.apereo.portal.rendering.PipelineComponent#getCacheKey(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public CacheKey getCacheKey(HttpServletRequest request, HttpServletResponse response) {
final CacheKey parentKey = this.wrappedComponent.getCacheKey(request, response);
final CacheKey attributeKey = this.attributeSource.getCacheKey(request, response);
return CacheKey.build(this.beanName, parentKey, attributeKey);
}
/* (non-Javadoc)
* @see org.apereo.portal.rendering.PipelineComponent#getEventReader(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse)
*/
@Override
public PipelineEventReader<XMLEventReader, XMLEvent> getEventReader(
HttpServletRequest request, HttpServletResponse response) {
//Get the reader from the parent and add the attribute incorporating wrapper
final PipelineEventReader<XMLEventReader, XMLEvent> cachingEventReader =
this.wrappedComponent.getEventReader(request, response);
final XMLEventReader eventReader =
new AttributeIncorporatingXMLEventReader(
request, response, cachingEventReader.getEventReader());
final Map<String, String> outputProperties = cachingEventReader.getOutputProperties();
return new PipelineEventReaderImpl<XMLEventReader, XMLEvent>(eventReader, outputProperties);
}
private final class AttributeIncorporatingXMLEventReader extends FilteringXMLEventReader {
private final HttpServletRequest request;
private final HttpServletResponse response;
public AttributeIncorporatingXMLEventReader(
HttpServletRequest request, HttpServletResponse response, XMLEventReader reader) {
super(reader);
this.request = request;
this.response = response;
}
@Override
protected XMLEvent filterEvent(XMLEvent event, boolean peek) {
//Only filtering start elements to add attributes
if (!event.isStartElement()) {
return event;
}
//Get the additional attributes, return if there are no attributes for this element
final StartElement startElement = event.asStartElement();
final Iterator<Attribute> additionalAttributes =
attributeSource.getAdditionalAttributes(request, response, startElement);
if (additionalAttributes == null || !additionalAttributes.hasNext()) {
return event;
}
//Merge the additional attributes with the existing attributes
//additional attributes overwrite
final Map<QName, Attribute> mergedAttributes = new LinkedHashMap<QName, Attribute>();
for (final Iterator<Attribute> attributes = startElement.getAttributes();
attributes.hasNext();
) {
final Attribute attribute = attributes.next();
mergedAttributes.put(attribute.getName(), attribute);
}
while (additionalAttributes.hasNext()) {
final Attribute attribute = additionalAttributes.next();
mergedAttributes.put(attribute.getName(), attribute);
if (logger.isDebugEnabled()) {
logger.debug(
"{} - Adding Attribute {} to event {}",
new Object[] {
beanName,
XmlUtilitiesImpl.toString(attribute),
XmlUtilitiesImpl.toString(event)
});
}
}
//Create the modified StartElement with the additional attribute data
final StartElement modifiedStartElement =
eventFactory.createStartElement(
startElement.getName(),
mergedAttributes.values().iterator(),
startElement.getNamespaces());
return modifiedStartElement;
}
}
}