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}