001/*
002 *  Copyright 2017 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.odfsync.cdmfr.transformers;
017
018import java.io.IOException;
019import java.util.HashMap;
020import java.util.HashSet;
021import java.util.Map;
022import java.util.Set;
023import java.util.regex.Pattern;
024
025import org.apache.avalon.framework.configuration.Configurable;
026import org.apache.avalon.framework.configuration.Configuration;
027import org.apache.avalon.framework.configuration.ConfigurationException;
028import org.apache.avalon.framework.service.ServiceException;
029import org.apache.avalon.framework.service.ServiceManager;
030import org.apache.avalon.framework.service.Serviceable;
031import org.apache.cocoon.ProcessingException;
032import org.apache.cocoon.components.source.SourceUtil;
033import org.apache.commons.lang3.StringUtils;
034import org.apache.excalibur.source.Source;
035import org.apache.excalibur.source.SourceResolver;
036import org.apache.excalibur.xml.dom.DOMParser;
037import org.apache.excalibur.xml.xpath.PrefixResolver;
038import org.apache.excalibur.xml.xpath.XPathProcessor;
039import org.w3c.dom.Document;
040import org.xml.sax.SAXException;
041
042/**
043 * Default implementation of CDMFrSyncTransformer.
044 */
045public class DefaultCDMFrSyncTransformer implements CDMFrSyncTransformer, Serviceable, Configurable
046{
047    /** The default XML namespace prefixes. */
048    public static final Map<String, String> DEFAULT_NAMESPACES = new HashMap<>();
049    static
050    {
051        DEFAULT_NAMESPACES.put("cdm", "http://cdm-fr.fr/2011/CDM");
052        DEFAULT_NAMESPACES.put("cdmfr", "http://cdm-fr.fr/2011/CDM-frSchema");
053    }
054    
055    /** The DOM parser. */
056    protected DOMParser _domParser;
057    /** Ametys object resolver. */
058    protected SourceResolver _sourceResolver;
059    /** The XPath processor. */
060    protected XPathProcessor _xPathProcessor;
061    
062    /** The XSL file to transform the document. */
063    protected String _xslFile;
064
065    /** Set of applications supported by the transformer. */
066    protected Set<Pattern> _applications = new HashSet<>();
067    
068    /** The prefix resolver. */
069    protected PrefixResolver _prefixResolver;
070    
071    @Override
072    public void service(ServiceManager manager) throws ServiceException
073    {
074        _domParser = (DOMParser) manager.lookup(DOMParser.ROLE);
075        _sourceResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
076        _xPathProcessor = (XPathProcessor) manager.lookup(XPathProcessor.ROLE);
077    }
078    
079    @Override
080    public void configure(Configuration configuration) throws ConfigurationException
081    {
082        Configuration[] applications = configuration.getChildren("app");
083        for (Configuration application : applications)
084        {
085            _applications.add(Pattern.compile(application.getValue(), Pattern.DOTALL));
086        }
087
088        _xslFile = configuration.getChild("configuration").getChild("xsl-transform").getValue(StringUtils.EMPTY);
089        
090        configureNamespaces(configuration.getChild("namespaces", false));
091    }
092    
093    /**
094     * Configure the namespace to use.
095     * @param configuration the namespaces configuration, can be null.
096     */
097    protected void configureNamespaces(Configuration configuration)
098    {
099        Map<String, String> namespaces = DEFAULT_NAMESPACES;
100        
101        if (configuration != null)
102        {
103            namespaces = new HashMap<>();
104            
105            for (Configuration nsConf : configuration.getChildren("namespace"))
106            {
107                String prefix = nsConf.getAttribute("prefix", StringUtils.EMPTY);
108                String namespace = nsConf.getAttribute("value", StringUtils.EMPTY);
109                
110                namespaces.put(prefix, namespace);
111            }
112        }
113        
114        _prefixResolver = new CDMFrPrefixResolver(namespaces);
115    }
116
117    @Override
118    public boolean supports(Document document)
119    {
120        String application = _xPathProcessor.evaluateAsString(document, "/cdm:CDM/cdm:properties/cdm:datasource", _prefixResolver);
121        if (StringUtils.isNotBlank(application))
122        {
123            for (Pattern pattern : _applications)
124            {
125                if (pattern.matcher(application).matches())
126                {
127                    return true;
128                }
129            }
130        }
131        return false;
132    }
133
134    @Override
135    public Document transform(Document document, Map<String, Object> parameters) throws IOException, SAXException, ProcessingException
136    {
137        parameters.put("source", document);
138        parameters.put("xslFile", _xslFile);
139        Source src = _sourceResolver.resolveURI("cocoon://_plugins/odf-sync/cdmfr/import/file", null, parameters);
140        return SourceUtil.toDOM(src);
141    }
142    
143    /**
144     * XML prefix resolver which declares CDMFr namespaces.
145     */
146    public static class CDMFrPrefixResolver implements PrefixResolver
147    {
148        
149        /** List of namespaces, indexed by prefix. */
150        private Map<String, String> _namespaces;
151        
152        /**
153         * Constructor.
154         * @param namespaces the namespaces to resolve, indexed by prefix.
155         */
156        public CDMFrPrefixResolver(Map<String, String> namespaces)
157        {
158            _namespaces = namespaces;
159        }
160        
161        public String prefixToNamespace(String prefix)
162        {
163            return _namespaces.get(prefix);
164        }
165    }
166}