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    private SAXParser _saxParser;
065    
066    @Override
067    public void service(ServiceManager smanager) throws ServiceException
068    {
069        super.service(smanager);
070        _srcResolver = (SourceResolver) smanager.lookup(SourceResolver.ROLE);
071        _skinHelper = (SkinEditionHelper) smanager.lookup(SkinEditionHelper.ROLE);
072        _modelsManager = (SkinModelsManager) smanager.lookup(SkinModelsManager.ROLE);
073        _skinFactoryManager = (SkinFactoryComponent) smanager.lookup(SkinFactoryComponent.ROLE);
074        _domParser = (DOMParser) smanager.lookup(DOMParser.ROLE);
075        _xpathProcessor = (XPathProcessor) smanager.lookup(XPathProcessor.ROLE);
076        _saxParser = (SAXParser) manager.lookup(SAXParser.ROLE);
077    }
078    
079    @Override
080    public void generate() throws IOException, SAXException, ProcessingException
081    {
082        String skinName = parameters.getParameter("skinName", null);
083        
084        String modelName = _skinHelper.getTempModel(skinName);
085        if (modelName == null)
086        {
087            throw new IllegalArgumentException("The current skin has no model");
088        }
089        
090        SkinModel model = _modelsManager.getModel(modelName);
091        if (model == null)
092        {
093            throw new IllegalArgumentException("The model '" + modelName + "' does not exit anymore");
094        }
095        
096        contentHandler.startDocument();
097        XMLUtils.startElement(contentHandler, "cms");
098        
099        Source src = null;
100        try
101        {
102            Path ribbonFile = model.getPath().resolve("model/cms-ribbon.xml");
103            if (Files.exists(ribbonFile))
104            {
105                if (_isUpToDate(ribbonFile, modelName))
106                {
107                    try (InputStream is = Files.newInputStream(ribbonFile))
108                    {
109                        _saxParser.parse(new InputSource(is), new IgnoreRootHandler(contentHandler));
110                    }
111                }
112                else
113                {
114                    src = _srcResolver.resolveURI("cocoon:/" + modelName + "/update/cms-ribbon.xml");
115                    ((SitemapSource) src).toSAX(new IgnoreRootHandler(contentHandler));
116                    
117                    // Update file
118                    try (InputStream is = Files.newInputStream(ribbonFile))
119                    {
120                        Files.copy(is, ribbonFile, StandardCopyOption.REPLACE_EXISTING);
121                    }
122                }
123            }
124            else
125            {
126                src = _srcResolver.resolveURI("cocoon:/" + modelName + "/create/cms-ribbon.xml");
127                ((SitemapSource) src).toSAX(new IgnoreRootHandler(contentHandler));
128                
129                // Create file
130                try (InputStream is = Files.newInputStream(ribbonFile))
131                {
132                    Files.copy(is, ribbonFile);
133                }
134            }
135        }
136        finally
137        {
138            if (src != null)
139            {
140                _srcResolver.release(src);
141            }
142        }
143        
144        XMLUtils.startElement(contentHandler, "parameters");
145        Map<String, AbstractSkinParameter> modelParameters = _skinFactoryManager.getModelParameters(modelName);
146        for (AbstractSkinParameter parameter : modelParameters.values())
147        {
148            parameter.toSAX(contentHandler, modelName);
149        }
150        XMLUtils.endElement(contentHandler, "parameters");
151
152        XMLUtils.endElement(contentHandler, "cms");
153        contentHandler.endDocument();
154
155    }
156
157    private boolean _isUpToDate (Path ribbonFile, String modelName) throws IOException, SAXException
158    {
159        Set<String> ribbonParams = new HashSet<>();
160        
161        try (InputStream is = Files.newInputStream(ribbonFile))
162        {
163            Document document = _domParser.parseDocument(new InputSource(is));
164            NodeList paramNodes = _xpathProcessor.selectNodeList(document, "/ribbon/tab/groups/group//parameter");
165            
166            for (int i = 0; i < paramNodes.getLength(); i++)
167            {
168                Element consistency = (Element) paramNodes.item(i);
169                String id = consistency.getAttribute("id");
170                
171                ribbonParams.add(id);
172            }
173            
174            return SetUtils.isEqualSet(ribbonParams, _skinFactoryManager.getModelParameters(modelName).keySet());
175        }
176    }
177}