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.apogee.scc.operator;
017
018import java.io.IOException;
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.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.odf.enumeration.OdfReferenceTableEntry;
037import org.ametys.odf.enumeration.OdfReferenceTableHelper;
038import org.ametys.runtime.plugin.component.AbstractLogEnabled;
039
040/**
041 * Get mapped values from Apogée to Ametys.
042 */
043public class ApogeeSynchronizingContentOperatorHelper extends AbstractLogEnabled implements Component, Serviceable, Initializable
044{
045    /** The Avalon Role */
046    public static final String ROLE = ApogeeSynchronizingContentOperatorHelper.class.getName();
047    
048    /** The source resolver */
049    protected SourceResolver _srcResolver;
050
051    /** The ODF TableRef Helper */
052    protected OdfReferenceTableHelper _odfRefTableHelper;
053    
054    /** Mappings Apogee code - Ametys code */
055    private Map<String, Map<String, String>> _codeMappings;
056    
057    @Override
058    public void service(ServiceManager manager) throws ServiceException
059    {
060        _srcResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
061        _odfRefTableHelper = (OdfReferenceTableHelper) manager.lookup(OdfReferenceTableHelper.ROLE);
062    }
063
064    @Override
065    public void initialize() throws Exception
066    {
067        _codeMappings = new HashMap<>();
068    }
069    
070    /**
071     * Get the id of content associated with this Apogee code
072     * @param contentTypeId The content type id
073     * @param apogeeCode The code into Apogee
074     * @return The id of content or null if no match found
075     */
076    public String getReferenceTableEntryId(String contentTypeId, String apogeeCode)
077    {
078        return Optional.ofNullable(apogeeCode)
079            .map(code -> _odfRefTableHelper.getItemFromApogee(contentTypeId, code)) // First check if we find the content from code Apogee
080            .or(() -> _getReferenceTableEntryFromMapping(apogeeCode, contentTypeId)) // Then check if we find the content from XML mapping
081            .map(OdfReferenceTableEntry::getId)
082            .orElse(null);
083    }
084    
085    private Optional<OdfReferenceTableEntry> _getReferenceTableEntryFromMapping(String apogeeCode, String contentTypeId)
086    {
087        return Optional.ofNullable(apogeeCode)
088            .map(code -> _getConvertedCode(code, contentTypeId))
089            .map(code -> _odfRefTableHelper.getItemFromCode(contentTypeId, code));
090    }
091    
092    private String _getConvertedCode(String apogeeCode, String contentTypeId)
093    {
094        String shortContentTypeId = contentTypeId.substring(contentTypeId.lastIndexOf(".") + 1);
095        return _codeMappings
096            .computeIfAbsent(shortContentTypeId, this::_readMapping)
097            .getOrDefault(apogeeCode, apogeeCode);
098    }
099
100    private Map<String, String> _readMapping(String contentTypeId)
101    {
102        Map<String, String> mapping = new HashMap<>();
103        String uri = "context://WEB-INF/param/odf/apogee/code/" + contentTypeId.toLowerCase() + "_conversion.xml";
104        Source source = null;
105        try
106        {
107            source = _srcResolver.resolveURI(uri);
108            if (source.exists())
109            {
110                try (InputStream is = source.getInputStream())
111                {
112                    Configuration configuration = new DefaultConfigurationBuilder().build(is);
113                    for (Configuration itemConf : configuration.getChildren())
114                    {
115                        String apogeeCode = itemConf.getAttribute("code");
116                        String ametysCode = itemConf.getValue();
117                        
118                        mapping.put(apogeeCode, ametysCode);
119                    }
120                }
121            }
122            else
123            {
124                getLogger().info("Apogée conversion file '{}' not found", uri);
125            }
126        }
127        catch (IOException | ConfigurationException | SAXException e)
128        {
129            getLogger().error("Unable to read the Apogee mapping file '{}' for content type '{}'", uri, contentTypeId, e);
130        }
131        finally
132        {
133            _srcResolver.release(source);
134        }
135        return mapping;
136    }
137}