001/*
002 *  Copyright 2011 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.skinfactory.generators;
017
018import java.io.IOException;
019import java.io.InputStream;
020import java.nio.file.Files;
021import java.nio.file.Path;
022import java.nio.file.StandardCopyOption;
023import java.util.HashSet;
024import java.util.Map;
025import java.util.Set;
026
027import org.apache.avalon.framework.service.ServiceException;
028import org.apache.avalon.framework.service.ServiceManager;
029import org.apache.cocoon.ProcessingException;
030import org.apache.cocoon.components.source.impl.SitemapSource;
031import org.apache.cocoon.generation.ServiceableGenerator;
032import org.apache.cocoon.xml.XMLUtils;
033import org.apache.commons.collections.SetUtils;
034import org.apache.excalibur.source.Source;
035import org.apache.excalibur.source.SourceResolver;
036import org.apache.excalibur.xml.dom.DOMParser;
037import org.apache.excalibur.xml.sax.SAXParser;
038import org.apache.excalibur.xml.xpath.XPathProcessor;
039import org.w3c.dom.Document;
040import org.w3c.dom.Element;
041import org.w3c.dom.NodeList;
042import org.xml.sax.InputSource;
043import org.xml.sax.SAXException;
044
045import org.ametys.core.util.IgnoreRootHandler;
046import org.ametys.plugins.skincommons.SkinEditionHelper;
047import org.ametys.skinfactory.SkinFactoryComponent;
048import org.ametys.skinfactory.parameters.AbstractSkinParameter;
049import org.ametys.web.skin.SkinModel;
050import org.ametys.web.skin.SkinModelsManager;
051
052/**
053 * SAX ribbon definition for skin parameters
054 *
055 */
056public class RibbonGenerator extends ServiceableGenerator
057{
058    private SourceResolver _srcResolver;
059    private SkinModelsManager _modelsManager;
060    private SkinFactoryComponent _skinFactoryManager;
061    private DOMParser _domParser;
062    private XPathProcessor _xpathProcessor;
063    private SkinEditionHelper _skinHelper;
064    
065    @Override
066    public void service(ServiceManager smanager) throws ServiceException
067    {
068        super.service(smanager);
069        _srcResolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE);
070        _skinHelper = (SkinEditionHelper) smanager.lookup(SkinEditionHelper.ROLE);
071        _modelsManager = (SkinModelsManager) smanager.lookup(SkinModelsManager.ROLE);
072        _skinFactoryManager = (SkinFactoryComponent) smanager.lookup(SkinFactoryComponent.ROLE);
073        _domParser = (DOMParser) smanager.lookup(DOMParser.ROLE);
074        _xpathProcessor = (XPathProcessor) smanager.lookup(XPathProcessor.ROLE);
075    }
076    
077    @Override
078    public void generate() throws IOException, SAXException, ProcessingException
079    {
080        String skinName = parameters.getParameter("skinName", null);
081        
082        String modelName = _skinHelper.getTempModel(skinName);
083        if (modelName == null)
084        {
085            throw new IllegalArgumentException("The current skin has no model");
086        }
087        
088        SkinModel model = _modelsManager.getModel(modelName);
089        if (model == null)
090        {
091            throw new IllegalArgumentException("The model '" + modelName + "' does not exit anymore");
092        }
093        
094        contentHandler.startDocument();
095        XMLUtils.startElement(contentHandler, "cms");
096        
097        Source src = null;
098        try
099        {
100            Path ribbonFile = model.getPath().resolve("model/cms-ribbon.xml");
101            if (Files.exists(ribbonFile))
102            {
103                if (_isUpToDate(ribbonFile, modelName))
104                {
105                    SAXParser saxParser = null;
106                    try (InputStream is = Files.newInputStream(ribbonFile))
107                    {
108                        saxParser = (SAXParser) manager.lookup(SAXParser.ROLE);
109                        saxParser.parse(new InputSource(is), new IgnoreRootHandler(contentHandler));
110                    }
111                    catch (ServiceException e)
112                    {
113                        throw new ProcessingException("Unable to get a SAX parser", e);
114                    }
115                    finally
116                    {
117                        manager.release(saxParser);
118                    }
119                }
120                else
121                {
122                    src = _srcResolver.resolveURI("cocoon:/" + modelName + "/update/cms-ribbon.xml");
123                    ((SitemapSource) src).toSAX(new IgnoreRootHandler(contentHandler));
124                    
125                    // Update file
126                    try (InputStream is = Files.newInputStream(ribbonFile))
127                    {
128                        Files.copy(is, ribbonFile, StandardCopyOption.REPLACE_EXISTING);
129                    }
130                }
131            }
132            else
133            {
134                src = _srcResolver.resolveURI("cocoon:/" + modelName + "/create/cms-ribbon.xml");
135                ((SitemapSource) src).toSAX(new IgnoreRootHandler(contentHandler));
136                
137                // Create file
138                try (InputStream is = Files.newInputStream(ribbonFile))
139                {
140                    Files.copy(is, ribbonFile);
141                }
142            }
143        }
144        finally
145        {
146            if (src != null)
147            {
148                _srcResolver.release(src);
149            }
150        }
151        
152        XMLUtils.startElement(contentHandler, "parameters");
153        Map<String, AbstractSkinParameter> modelParameters = _skinFactoryManager.getModelParameters(modelName);
154        for (AbstractSkinParameter parameter : modelParameters.values())
155        {
156            parameter.toSAX(contentHandler, modelName);
157        }
158        XMLUtils.endElement(contentHandler, "parameters");
159
160        XMLUtils.endElement(contentHandler, "cms");
161        contentHandler.endDocument();
162
163    }
164
165    private boolean _isUpToDate (Path ribbonFile, String modelName) throws IOException, SAXException
166    {
167        Set<String> ribbonParams = new HashSet<>();
168        
169        try (InputStream is = Files.newInputStream(ribbonFile))
170        {
171            Document document = _domParser.parseDocument(new InputSource(is));
172            NodeList paramNodes = _xpathProcessor.selectNodeList(document, "/ribbon/tab/groups/group//parameter");
173            
174            for (int i = 0; i < paramNodes.getLength(); i++)
175            {
176                Element consistency = (Element) paramNodes.item(i);
177                String id = consistency.getAttribute("id");
178                
179                ribbonParams.add(id);
180            }
181            
182            return SetUtils.isEqualSet(ribbonParams, _skinFactoryManager.getModelParameters(modelName).keySet());
183        }
184    }
185}