001/*
002 *  Copyright 2014 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.odf.export.indesign;
017
018import java.io.File;
019import java.io.FileFilter;
020import java.io.IOException;
021import java.io.InputStream;
022import java.util.HashMap;
023import java.util.Map;
024
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.commons.collections.MapUtils;
033import org.apache.excalibur.source.Source;
034import org.apache.excalibur.source.SourceResolver;
035import org.apache.excalibur.source.impl.FileSource;
036
037import org.ametys.runtime.i18n.I18nizableText;
038import org.ametys.runtime.plugin.component.AbstractLogEnabled;
039
040/**
041 * Helper storing mappings of xsl stylesheets (used in InDesign transformations) names with their labels. 
042 */
043public class IndesignTransformationHelper extends AbstractLogEnabled implements Component, Serviceable
044{
045    /** The Indesign Transformation Helper's role */
046    public static final String ROLE = IndesignTransformationHelper.class.getName();
047    
048    /** The path of the single program transformation stylesheets */
049    private static final String __XSLT_DIRECTORY_URI = "context://WEB-INF/stylesheets/indesign";
050    
051    /** The path of the catalog transformation stylesheets */
052    private static final String __GLOBAL_XSLT_DIRECTORY_URI = "context://WEB-INF/stylesheets/indesign/catalogue";
053
054    private SourceResolver _srcResolver;
055    
056    @Override
057    public void service(ServiceManager manager) throws ServiceException
058    {
059        _srcResolver = (SourceResolver) manager.lookup(SourceResolver.ROLE);
060    }
061    
062    /**
063     * Get available XSLT files for single program InDesign export
064     * @return the mapping of xsl names with their labels 
065     */
066    public Map<String, I18nizableText> getIndesignXslt()
067    {
068        try
069        {
070            return _parseXSLTFiles(__XSLT_DIRECTORY_URI);
071        }
072        catch (IOException e)
073        {
074            getLogger().error("Failed to get XSLT for indesign transformation", e);
075        }
076        
077        return MapUtils.EMPTY_MAP;
078    }
079    
080    /**
081     * Get available XSLT files for ODF catalog InDesign export
082     * @return the mapping of xsl names with their labels 
083     */
084    public Map<String, I18nizableText> getIndesignGlobalXslt()
085    {
086        try
087        {
088            return _parseXSLTFiles(__GLOBAL_XSLT_DIRECTORY_URI);
089        }
090        catch (IOException e)
091        {
092            getLogger().error("Failed to get XSLT for ODF catalog indesign transformation", e);
093        }
094        
095        return MapUtils.EMPTY_MAP;
096    }
097
098    /**
099     * Get the xslt data from the given directory
100     * @param rootURI The directory where to find xsl files
101     * @return the data under the form of a Map
102     * @throws IOException if error occurred while parsing files
103     */
104    private Map<String, I18nizableText> _parseXSLTFiles(String rootURI) throws IOException
105    {
106        Map<String, I18nizableText> xsltFiles = new HashMap<> ();
107        
108        FileSource rootSrc = null;
109        try
110        {
111            rootSrc = (FileSource) _srcResolver.resolveURI(rootURI);
112            if (rootSrc.exists())
113            {
114                File rootDir = rootSrc.getFile();
115                File[] xslFiles = rootDir.listFiles(new FileFilter() 
116                {
117                    public boolean accept(File file)
118                    {
119                        String lowerCasedFileName = file.getName().toLowerCase();
120                        return file.isFile() && lowerCasedFileName.endsWith(".xsl");
121                    }
122                });
123                
124                // Generate the map
125                for (File xslFile : xslFiles)
126                {
127                    I18nizableText label = _parseLabel(rootURI, xslFile.getName());
128                    xsltFiles.put(xslFile.getName(), label);
129                }
130            }
131        }
132        finally
133        {
134            if (rootSrc != null)
135            {
136                _srcResolver.release(rootSrc);
137            }
138        }
139        
140        return xsltFiles;
141    }
142    
143    private I18nizableText _parseLabel(String rootURI, String value)
144    {
145        String valueWithNoExtension = value.substring(0, value.length() - 4);
146        String url = rootURI + "/" + valueWithNoExtension + ".xml";
147        
148        Source source = null;
149        try
150        {
151            source = _srcResolver.resolveURI(url);
152            if (source.exists())
153            {
154                try (InputStream inputStream = source.getInputStream())
155                {
156                    Configuration conf = new DefaultConfigurationBuilder().build(inputStream);
157                    
158                    Configuration node = conf.getChild("label");
159                    I18nizableText text = _parseI18nizableText(node, "application");
160                    return text;
161                }
162            }
163        }
164        catch (Exception e) 
165        {
166            // Nothing
167        }
168        finally
169        {
170            _srcResolver.release(source);
171        }
172        
173        int i = valueWithNoExtension.lastIndexOf('/');
174        String shortFilename = valueWithNoExtension.substring(i + 1);
175        return new I18nizableText(shortFilename);
176    }
177    
178    private I18nizableText _parseI18nizableText(Configuration textConfig, String defaultCatalogue) throws ConfigurationException
179    {
180        boolean i18nSupported = textConfig.getAttributeAsBoolean("i18n", false);
181        String text = textConfig.getValue();
182        
183        if (i18nSupported)
184        {
185            String catalogue = textConfig.getAttribute("catalogue", null);
186            
187            if (catalogue == null)
188            {
189                catalogue = defaultCatalogue;
190            }
191            
192            return new I18nizableText(catalogue, text);
193        }
194        else
195        {
196            return new I18nizableText(text);
197        }
198    }
199}