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}