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.InputStream;
020import java.util.HashMap;
021import java.util.Map;
022import java.util.Optional;
023
024import org.apache.avalon.framework.activity.Initializable;
025import org.apache.avalon.framework.component.Component;
026import org.apache.avalon.framework.configuration.Configurable;
027import org.apache.avalon.framework.configuration.Configuration;
028import org.apache.avalon.framework.configuration.ConfigurationException;
029import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
030import org.apache.avalon.framework.service.ServiceException;
031import org.apache.avalon.framework.service.ServiceManager;
032import org.apache.avalon.framework.service.Serviceable;
033import org.apache.excalibur.source.Source;
034import org.apache.excalibur.source.SourceResolver;
035
036import org.ametys.core.cache.AbstractCacheManager;
037import org.ametys.core.cache.Cache;
038import org.ametys.core.util.filereloader.FileReloader;
039import org.ametys.core.util.filereloader.FileReloaderUtils;
040import org.ametys.runtime.i18n.I18nizableText;
041import org.ametys.runtime.plugin.component.AbstractLogEnabled;
042import org.ametys.runtime.plugin.component.PluginAware;
043
044/**
045 * Abstract class for reading mapping files in ODF helpers.
046 * First look for a project mapping files in WEB-INF/param/odf
047 * Then look for the default mapping files in plugin.odf-sync
048 */
049public abstract class AbstractMappingHelper extends AbstractLogEnabled implements Component, Serviceable, Configurable, PluginAware, Initializable, FileReloader
050{
051    /** The source resolver */
052    protected SourceResolver _srcResolver;
053    
054    /** The cache manager */
055    protected AbstractCacheManager _cacheManager;
056
057    /** The file reloader utils */
058    protected FileReloaderUtils _fileReloaderUtils;
059    
060    /** The implementation name */
061    protected String _implementationName;
062
063    private String _id;
064    
065    public void setPluginInfo(String pluginName, String featureName, String id)
066    {
067        _id = id;
068    }
069    
070    @Override
071    public void configure(Configuration configuration) throws ConfigurationException
072    {
073        _implementationName = configuration.getChild("name").getValue();
074    }
075    
076    @Override
077    public void service(ServiceManager manager) throws ServiceException
078    {
079        _srcResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
080        _cacheManager = (AbstractCacheManager) manager.lookup(AbstractCacheManager.ROLE);
081        _fileReloaderUtils = (FileReloaderUtils) manager.lookup(FileReloaderUtils.ROLE);
082    }
083
084    public void initialize() throws Exception
085    {
086        _cacheManager.createMemoryCache(
087            _getCacheId(),
088            getCacheLabel(),
089            getCacheDescription(),
090            true,
091            null
092        );
093    }
094    
095    /**
096     * Read the mapping file to convert types.
097     * @param baseUri The base uri of the file
098     * @return The mapping
099     * @throws Exception if an exception occurs
100     */
101    protected Map<String, String> _readMapping(String baseUri) throws Exception
102    {
103        // First, search in WEB-INF/param/odf/[implementationName]
104        Map<String, String> mapping = _readMappingFrom("context://WEB-INF/param/odf/" + _implementationName + baseUri);
105        
106        if (mapping == null)
107        {
108            // Then in the ODF-sync plugin conversions folder
109            mapping = _readMappingFrom("plugin:odf-sync://conversions/" + _implementationName + baseUri);
110        }
111        
112        return Optional.ofNullable(mapping).orElseGet(Map::of);
113    }
114    
115    private Map<String, String> _readMappingFrom(String uri) throws Exception
116    {
117        _fileReloaderUtils.updateFile(uri, !_getCache().hasKey(uri), this);
118        return _getCache().get(uri);
119    }
120
121    /**
122     * Parse the mapping file
123     * @param is The source input stream
124     * @return The mapping
125     * @throws Exception If an error occurs
126     */
127    private Map<String, String> _parseMappingFile(InputStream is) throws Exception
128    {
129        Map<String, String> mapping = new HashMap<>();
130        
131        Configuration configuration = new DefaultConfigurationBuilder().build(is);
132        for (Configuration itemConf : configuration.getChildren())
133        {
134            String remoteValue = itemConf.getAttribute("code");
135            String ametysValue = itemConf.getValue();
136            
137            mapping.put(remoteValue, ametysValue);
138        }
139        
140        return mapping;
141    }
142    
143    public void updateFile(String sourceUrl, Source source, InputStream is) throws Exception
144    {
145        if (is != null)
146        {
147            _getCache().put(sourceUrl, _parseMappingFile(is));
148        }
149        else
150        {
151            _getCache().invalidate(sourceUrl);
152        }
153    }
154
155    public String getId(String sourceUrl)
156    {
157        return sourceUrl;
158    }
159    
160    private Cache<String, Map<String, String>> _getCache()
161    {
162        return _cacheManager.get(_getCacheId());
163    }
164    
165    private String _getCacheId()
166    {
167        return _id + "$mapping";
168    }
169
170    /**
171     * Get the cache label.
172     * @return the cache label
173     */
174    protected abstract I18nizableText getCacheLabel();
175    
176    /**
177     * Get the cache description.
178     * @return the cache description
179     */
180    protected abstract I18nizableText getCacheDescription();
181}