/**
* Licensed to Jasig under one or more contributor license
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig 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:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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.jasig.portal.layout;
import java.util.Collection;
import java.util.Deque;
import java.util.LinkedList;
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.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.jasig.portal.portlet.om.IPortletDefinition;
import org.jasig.portal.portlet.om.IPortletDefinitionParameter;
import org.jasig.portal.xml.stream.InjectingXMLEventReader;
/**
* @author Eric Dalquist
* @version $Revision$
*/
public class TransientUserLayoutXMLEventReader extends InjectingXMLEventReader {
private static final XMLEventFactory EVENT_FACTORY = XMLEventFactory.newFactory();
protected final Log logger = LogFactory.getLog(this.getClass());
private final TransientUserLayoutManagerWrapper userLayoutManager;
private final String rootFolderId;
public TransientUserLayoutXMLEventReader(TransientUserLayoutManagerWrapper userLayoutManager,
XMLEventReader wrappedReader) {
super(wrappedReader);
this.userLayoutManager = userLayoutManager;
this.rootFolderId = this.userLayoutManager.getRootFolderId();
}
@Override
protected Deque<XMLEvent> getAdditionalEvents(XMLEvent event) {
if (event.isStartElement()) {
final StartElement startElement = event.asStartElement();
//All following logic requires an ID attribute, ignore any element without one
final Attribute idAttribute = startElement.getAttributeByName(IUserLayoutManager.ID_ATTR_NAME);
if (idAttribute == null) {
return null;
}
//Handle adding a transient folder to the root element
if (this.rootFolderId.equals(idAttribute.getValue())) {
final QName name = startElement.getName();
final String namespaceURI = name.getNamespaceURI();
final String prefix = name.getPrefix();
final Deque<XMLEvent> transientEventBuffer = new LinkedList<XMLEvent>();
final Collection<Attribute> transientFolderAttributes = new LinkedList<Attribute>();
transientFolderAttributes.add(EVENT_FACTORY.createAttribute("ID", TransientUserLayoutManagerWrapper.TRANSIENT_FOLDER_ID));
transientFolderAttributes.add(EVENT_FACTORY.createAttribute("type", "regular"));
transientFolderAttributes.add(EVENT_FACTORY.createAttribute("hidden", "true"));
transientFolderAttributes.add(EVENT_FACTORY.createAttribute("unremovable", "true"));
transientFolderAttributes.add(EVENT_FACTORY.createAttribute("immutable", "true"));
transientFolderAttributes.add(EVENT_FACTORY.createAttribute("name", "Transient Folder"));
final StartElement transientFolder = EVENT_FACTORY.createStartElement(prefix, namespaceURI, IUserLayoutManager.FOLDER, transientFolderAttributes.iterator(), null);
transientEventBuffer.add(transientFolder);
//append channel element iff subscribeId describes a transient channel, and not a regular layout channel
final String subscribeId = this.userLayoutManager.getFocusedId();
if (null != subscribeId && !subscribeId.equals("") && this.userLayoutManager.isTransientChannel(subscribeId)) {
IPortletDefinition chanDef = null;
try {
chanDef = this.userLayoutManager.getChannelDefinition(subscribeId);
}
catch (Exception e) {
this.logger.error("Could not obtain IChannelDefinition for subscribe id: " + subscribeId, e);
}
if (chanDef != null) {
//TODO Move IChannelDefinition/IPortletDefinition -> StAX events code somewhere reusable
final Collection<Attribute> channelAttrs = new LinkedList<Attribute>();
channelAttrs.add(EVENT_FACTORY.createAttribute("ID", subscribeId));
channelAttrs.add(EVENT_FACTORY.createAttribute("typeID", Integer.toString(chanDef.getType().getId())));
channelAttrs.add(EVENT_FACTORY.createAttribute("hidden", "false"));
channelAttrs.add(EVENT_FACTORY.createAttribute("unremovable", "true"));
channelAttrs.add(EVENT_FACTORY.createAttribute("name", chanDef.getName()));
channelAttrs.add(EVENT_FACTORY.createAttribute("description", chanDef.getDescription()));
channelAttrs.add(EVENT_FACTORY.createAttribute("title", chanDef.getTitle()));
channelAttrs.add(EVENT_FACTORY.createAttribute("chanID", chanDef.getPortletDefinitionId().getStringId()));
channelAttrs.add(EVENT_FACTORY.createAttribute("fname", chanDef.getFName()));
channelAttrs.add(EVENT_FACTORY.createAttribute("timeout", Integer.toString(chanDef.getTimeout())));
channelAttrs.add(EVENT_FACTORY.createAttribute("transient", "true"));
final StartElement startChannel = EVENT_FACTORY.createStartElement(prefix, namespaceURI, IUserLayoutManager.CHANNEL, channelAttrs.iterator(), null);
transientEventBuffer.offer(startChannel);
// add channel parameter elements
for(final IPortletDefinitionParameter parm : chanDef.getParameters())
{
final Collection<Attribute> parameterAttrs = new LinkedList<Attribute>();
parameterAttrs.add(EVENT_FACTORY.createAttribute("name",parm.getName()));
parameterAttrs.add(EVENT_FACTORY.createAttribute("value",parm.getValue()));
final StartElement startParameter = EVENT_FACTORY.createStartElement(prefix, namespaceURI, IUserLayoutManager.PARAMETER, parameterAttrs.iterator(), null);
transientEventBuffer.offer(startParameter);
final EndElement endParameter = EVENT_FACTORY.createEndElement(prefix, namespaceURI, IUserLayoutManager.PARAMETER, null);
transientEventBuffer.offer(endParameter);
}
final EndElement endChannel = EVENT_FACTORY.createEndElement(prefix, namespaceURI, IUserLayoutManager.CHANNEL, null);
transientEventBuffer.offer(endChannel);
}
}
final EndElement endFolder = EVENT_FACTORY.createEndElement(prefix, namespaceURI, IUserLayoutManager.FOLDER, null);
transientEventBuffer.offer(endFolder);
return transientEventBuffer;
}
}
return null;
}
@Override
protected XMLEvent getPeekEvent(XMLEvent event) {
//Not the most efficient way of doing this since the whole deque is built but we only need the first element.
final Deque<XMLEvent> additionalEvents = this.getAdditionalEvents(event);
if (additionalEvents != null) {
return additionalEvents.pop();
}
return null;
}
}