001/*
002 *  Copyright 2018 Anyware Services
003 *
004 *  Licensed under the Apache License, Version 2.0 (the "License");
005 *  you may not use this file except in compliance with the License.
006 *  You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 *  Unless required by applicable law or agreed to in writing, software
011 *  distributed under the License is distributed on an "AS IS" BASIS,
012 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 *  See the License for the specific language governing permissions and
014 *  limitations under the License.
015 */
016package org.ametys.plugins.userdirectory.generator;
017
018import java.io.IOException;
019import java.util.List;
020
021import org.apache.avalon.framework.service.ServiceException;
022import org.apache.avalon.framework.service.ServiceManager;
023import org.apache.cocoon.ProcessingException;
024import org.apache.cocoon.components.source.impl.SitemapSource;
025import org.apache.cocoon.environment.ObjectModelHelper;
026import org.apache.cocoon.environment.Request;
027import org.apache.cocoon.generation.ServiceableGenerator;
028import org.apache.cocoon.xml.AttributesImpl;
029import org.apache.cocoon.xml.XMLUtils;
030import org.apache.commons.lang.StringUtils;
031import org.apache.excalibur.source.SourceResolver;
032import org.xml.sax.SAXException;
033
034import org.ametys.cms.data.ContentValue;
035import org.ametys.cms.repository.Content;
036import org.ametys.core.util.IgnoreRootHandler;
037import org.ametys.plugins.repository.AmetysObjectIterable;
038import org.ametys.plugins.repository.UnknownAmetysObjectException;
039import org.ametys.plugins.repository.data.holder.group.impl.ModelAwareRepeater;
040import org.ametys.plugins.repository.data.holder.group.impl.ModelAwareRepeaterEntry;
041import org.ametys.plugins.userdirectory.OrganisationChartPageHandler;
042import org.ametys.web.WebConstants;
043
044/**
045 * Generate information to render the organization chart service.
046 */
047public class OrgChartGenerator extends ServiceableGenerator
048{
049    private static final String __VIEW_NAME = "organizationChart";
050    
051    private OrganisationChartPageHandler _organizationChartPageHandler;
052    private SourceResolver _sourceResolver;
053    
054    @Override
055    public void service(ServiceManager serviceManager) throws ServiceException
056    {
057        super.service(serviceManager);
058        _organizationChartPageHandler = (OrganisationChartPageHandler) serviceManager.lookup(OrganisationChartPageHandler.ROLE);
059        _sourceResolver = (SourceResolver) serviceManager.lookup(SourceResolver.ROLE);
060    }
061
062    public void generate() throws IOException, SAXException, ProcessingException
063    {
064        Request request = ObjectModelHelper.getRequest(objectModel);
065        String language = (String) request.getAttribute(WebConstants.REQUEST_ATTR_SITEMAP_NAME);
066        
067        contentHandler.startDocument();
068        XMLUtils.startElement(contentHandler, "orgUnits");
069
070        AmetysObjectIterable<Content> contents = _organizationChartPageHandler.getFirstLevelOfContents(language);
071        for (Content content : contents)
072        {
073            saxOrganizationUnit(content);
074        }
075
076        XMLUtils.endElement(contentHandler, "orgUnits");
077        contentHandler.endDocument();
078    }
079    
080    /**
081     * SAX an organization unit content
082     * @param orgUnit the organization unit to sax.
083     * @throws SAXException if an error occurs
084     */
085    protected void saxOrganizationUnit(Content orgUnit) throws SAXException
086    {
087        SitemapSource src = null; 
088        try
089        {
090            AttributesImpl attrs = new AttributesImpl();
091            attrs.addCDATAAttribute("id", orgUnit.getId());
092            attrs.addCDATAAttribute("unique-id", org.ametys.core.util.StringUtils.md5Base64(orgUnit.getId()));
093            attrs.addCDATAAttribute("name", orgUnit.getName());
094            
095            XMLUtils.startElement(contentHandler, "orgUnit", attrs);
096            
097            String format = parameters.getParameter("output-format", "html");
098            String uri = "cocoon://_content." + format + "?contentId=" + orgUnit.getId() + "&viewName=" + __VIEW_NAME + "&output-format=" + format;
099            src = (SitemapSource) _sourceResolver.resolveURI(uri);
100            src.toSAX(new IgnoreRootHandler(contentHandler));
101            
102            saxFirstUserOfOrganizationUnit(orgUnit);
103            saxOrganizationUnitChildren(orgUnit);
104            
105            XMLUtils.endElement(contentHandler, "orgUnit");
106        }
107        catch (IOException e)
108        {
109            throw new SAXException(e);
110        }
111        finally
112        {
113            _sourceResolver.release(src);
114        }
115    }
116    
117    /**
118     * SAX the first user with a role in the organization unit content
119     * @param orgUnit the organization unit
120     * @throws SAXException if an error occurred
121     */
122    protected void saxFirstUserOfOrganizationUnit(Content orgUnit) throws SAXException
123    {
124        if (orgUnit.hasValue("users"))
125        {
126            ModelAwareRepeater repeaters = orgUnit.getRepeater("users");
127            for (ModelAwareRepeaterEntry entry : repeaters.getEntries())
128            {
129                String role = entry.getValue("role");
130                ContentValue userValue = entry.getValue("user");
131                if (StringUtils.isNotEmpty(role) && userValue != null)
132                {
133                    try
134                    {
135                        Content user = userValue.getContent();
136                        saxUser(user, role);
137                    }
138                    catch (UnknownAmetysObjectException e)
139                    {
140                        getLogger().error("The entity " + orgUnit.getTitle() + " (" + orgUnit.getId() + ") is referencing an unexisting user '" + userValue.getContentId() + "'");
141                    }
142                    catch (Exception e)
143                    {
144                        getLogger().error("Fail to sax main user '" + userValue.getContentId() + "' for entity " + orgUnit.getTitle() + " (" + orgUnit.getId() + ")", e);
145                    }
146                    
147                    break;
148                }
149            }
150        }
151    }
152    
153    /**
154     * SAX a user content
155     * @param user the user to sax.
156     * @param role the user's role
157     * @throws SAXException if an error occurs
158     */
159    protected void saxUser(Content user, String role) throws SAXException
160    {
161        SitemapSource src = null;      
162        try
163        {
164            AttributesImpl attrs = new AttributesImpl();
165            attrs.addCDATAAttribute("id", user.getId());
166            attrs.addCDATAAttribute("name", user.getName());
167            
168            XMLUtils.startElement(contentHandler, "main-user", attrs);
169            
170            XMLUtils.createElement(contentHandler, "role", role);
171            
172            String format = parameters.getParameter("output-format", "html");
173            String uri = "cocoon://_content." + format + "?contentId=" + user.getId() + "&viewName=" + __VIEW_NAME + "&output-format=" + format;
174            src = (SitemapSource) _sourceResolver.resolveURI(uri);
175            src.toSAX(new IgnoreRootHandler(contentHandler));
176            
177            XMLUtils.endElement(contentHandler, "main-user");
178        }
179        catch (IOException e)
180        {
181            throw new SAXException(e);
182        }
183        finally
184        {
185            _sourceResolver.release(src);
186        }
187    }
188    
189    /**
190     * SAX children of an organization unit
191     * @param orgUnit the organization unit
192     * @throws SAXException if an error occurred
193     */
194    protected void saxOrganizationUnitChildren(Content orgUnit) throws SAXException
195    {
196        List<Content> children = _organizationChartPageHandler.getChildContents(orgUnit);
197
198        if (!children.isEmpty())
199        {
200            XMLUtils.startElement(contentHandler, "orgUnits");
201
202            for (Content child : children)
203            {
204                saxOrganizationUnit(child);
205            }
206
207            XMLUtils.endElement(contentHandler, "orgUnits");
208        }
209    }
210}