/** * 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.portlets.sitemap; import java.util.HashMap; import java.util.Map; import javax.portlet.PortletRequest; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.XMLEvent; import javax.xml.transform.stax.StAXSource; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.Validate; import org.apereo.portal.rendering.PipelineEventReader; import org.apereo.portal.rendering.StAXPipelineComponent; import org.apereo.portal.url.IPortalRequestUtils; import org.apereo.portal.url.xml.XsltPortalUrlProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.portlet.ModelAndView; /** * SitemapPortletController produces a sitemap view of the current user's portal layout. * * <p>Woefully, this implementation is dependent upon XSLT details of the portal rendering pipeline, * which auto-wire in. In the case where necessary components fail to auto-wire in, portlet * exceptions out at render time. * */ @Controller @RequestMapping("VIEW") public class SitemapPortletController { /** * Name of XSL parameter indicating whether to use tab groups or not (configured in * portal.properties). */ public static final String USE_TAB_GROUPS = "USE_TAB_GROUPS"; /** Name of XSL parameter representing user's locale. */ public static final String USER_LANG = "USER_LANG"; /** * We must use {@link StAXPipelineComponent} over the user layout document, because layout * document doesn't contain required attributes for tab group functionality. Those attributes * must be incorporated into user's layout using this component. */ private StAXPipelineComponent attributeIncorporationComponent; /** * Auto-wires in the structureAttributeIncorporationComponent when available. Annotated as not * required because portlet detects and treats as a runtime (rather than * component-initialization-time) error failure to find dependencies. * * @param attributeIncorporationComponent */ @Autowired(required = false) @Qualifier("structureAttributeIncorporationComponent") public void setStructureAttributeIncorporationComponent( StAXPipelineComponent attributeIncorporationComponent) { this.attributeIncorporationComponent = attributeIncorporationComponent; } /** Required by XSL to build portal URL's. */ private IPortalRequestUtils portalRequestUtils; /** * Auto-wires in the PortalRequestUtils when available. Annotated as not required because * portlet detects and treats as a runtime (rather than component-initialization-time) error * failure to find dependencies. * * @param portalRequestUtils the portalRequestUtils to set */ @Autowired(required = false) public void setPortalRequestUtils(IPortalRequestUtils portalRequestUtils) { Validate.notNull(portalRequestUtils); this.portalRequestUtils = portalRequestUtils; } /** Required by XSL to build portal URL's. */ private XsltPortalUrlProvider xsltPortalUrlProvider; /** * Auto-wires in the XsltPortalUrlProvider when available. Annotated as not required because * portlet detects and treats as a runtime (rather than component-initialization-time) error * failure to find dependencies. * * @param xsltPortalUrlProvider */ @Autowired(required = false) public void setXsltPortalUrlProvider(XsltPortalUrlProvider xsltPortalUrlProvider) { this.xsltPortalUrlProvider = xsltPortalUrlProvider; } /** * Whether to use tab groups or not. The value of this attribute will be passed to XSL using * {@value #USE_TAB_GROUPS} as parameter name. */ private boolean useTabGroups; @Value("${org.apereo.portal.layout.useTabGroups}") public void setUseTabGroups(boolean useTabGroups) { this.useTabGroups = useTabGroups; } /** * Display the user sitemap. * * @param request * @return "sitemapView" and a supporting model * @throws XMLStreamException * @throws IllegalStateException if components required for the SiteMap portlet fail to * auto-wire */ @RequestMapping public ModelAndView displaySitemap(PortletRequest request) throws XMLStreamException { Map<String, Object> model = new HashMap<String, Object>(); if (this.xsltPortalUrlProvider == null) { throw new IllegalStateException( "Sitemap portlet requires a XsltPortalUrlProvider but it failed to " + "auto-wire"); } if (this.attributeIncorporationComponent == null) { throw new IllegalStateException( "Sitemap portlet requires a StAXPipelineComponent with qualifier structureAttributeIncorporationComponent but it failed to auto-wire"); } if (this.portalRequestUtils == null) { throw new IllegalStateException( "Sitemap portlet requires an IPortalRequestUtils but it failed to " + "auto-wire"); } // retrieve the user layout with structure attributes applied (required in order to display tab groups) final HttpServletRequest httpServletRequest = this.portalRequestUtils.getPortletHttpRequest(request); final HttpServletResponse httpServletResponse = this.portalRequestUtils.getOriginalPortalResponse(request); final PipelineEventReader<XMLEventReader, XMLEvent> reader = attributeIncorporationComponent.getEventReader( httpServletRequest, httpServletResponse); // create a Source from the user's layout document StAXSource source = new StAXSource(reader.getEventReader()); model.put("source", source); model.put(XsltPortalUrlProvider.CURRENT_REQUEST, httpServletRequest); model.put(XsltPortalUrlProvider.XSLT_PORTAL_URL_PROVIDER, this.xsltPortalUrlProvider); model.put(USE_TAB_GROUPS, useTabGroups); model.put(USER_LANG, ObjectUtils.toString(request.getLocale())); return new ModelAndView("sitemapView", model); } }