001/* 002 * Copyright 2024 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 */ 016 017package org.ametys.plugins.odfsync.generic.scc; 018 019import java.io.IOException; 020import java.io.InputStream; 021import java.util.HashMap; 022import java.util.Map; 023import java.util.Optional; 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.configuration.DefaultConfigurationBuilder; 029import org.apache.avalon.framework.service.ServiceException; 030import org.apache.avalon.framework.service.ServiceManager; 031import org.apache.avalon.framework.service.Serviceable; 032import org.apache.excalibur.source.Source; 033import org.apache.excalibur.source.SourceResolver; 034import org.xml.sax.SAXException; 035 036import org.ametys.runtime.plugin.component.AbstractLogEnabled; 037 038/** 039 * Abstract class for reading mapping files in ODF helpers. 040 * First look for a project mapping files in WEB-INF/param/odf 041 * Then look for the default mapping files in plugin.odf-sync 042 */ 043public abstract class AbstractMappingHelper extends AbstractLogEnabled implements Serviceable, Configurable 044{ 045 /** The source resolver */ 046 protected SourceResolver _srcResolver; 047 048 /** The implementation name */ 049 protected String _implementationName; 050 051 @Override 052 public void configure(Configuration configuration) throws ConfigurationException 053 { 054 _implementationName = configuration.getChild("name").getValue(); 055 } 056 057 @Override 058 public void service(ServiceManager manager) throws ServiceException 059 { 060 _srcResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE); 061 } 062 063 /** 064 * Read the mapping file to convert types. 065 * @param baseUri The base uri of the file 066 * @return The mapping 067 */ 068 protected Map<String, String> _readMapping(String baseUri) 069 { 070 // First, search in WEB-INF/param/odf/[implementationName] 071 // Then in the ODF-sync plugin conversions folder 072 return _parseMapping("context://WEB-INF/param/odf/" + _implementationName + baseUri) 073 .or(() -> _parseMapping("plugin:odf-sync://conversions/" + _implementationName + baseUri)) 074 .orElseGet(Map::of); 075 } 076 077 private Optional<Map<String, String>> _parseMapping(String uri) 078 { 079 Source source = null; 080 try 081 { 082 source = _srcResolver.resolveURI(uri); 083 084 // If a project mapping file is found, read it 085 if (source.exists()) 086 { 087 return Optional.of(_parseMappingFile(source)); 088 } 089 else 090 { 091 getLogger().debug("No mapping at '{}'.", uri); 092 } 093 } 094 catch (IOException | ConfigurationException | SAXException e) 095 { 096 throw new RuntimeException("Unable to read the mapping file '" + uri + "'", e); 097 } 098 catch (Exception e) 099 { 100 throw new RuntimeException("An error occured while parsing the mapping file '" + uri + "'", e); 101 } 102 finally 103 { 104 _srcResolver.release(source); 105 } 106 107 return Optional.empty(); 108 } 109 110 /** 111 * Parse the mapping file 112 * @param source The source of the file 113 * @return The mapping 114 * @throws Exception If an error occurs 115 */ 116 protected Map<String, String> _parseMappingFile(Source source) throws Exception 117 { 118 Map<String, String> mapping = new HashMap<>(); 119 120 try (InputStream is = source.getInputStream()) 121 { 122 Configuration configuration = new DefaultConfigurationBuilder().build(is); 123 for (Configuration itemConf : configuration.getChildren()) 124 { 125 String remoteValue = itemConf.getAttribute("code"); 126 String ametysValue = itemConf.getValue(); 127 128 mapping.put(remoteValue, ametysValue); 129 } 130 } 131 132 return mapping; 133 } 134}