001package org.apache.maven.doxia.module.fo;
002
003/*
004 * Licensed to the Apache Software Foundation (ASF) under one
005 * or more contributor license agreements.  See the NOTICE file
006 * distributed with this work for additional information
007 * regarding copyright ownership.  The ASF licenses this file
008 * to you under the Apache License, Version 2.0 (the
009 * "License"); you may not use this file except in compliance
010 * with the License.  You may obtain a copy of the License at
011 *
012 *   http://www.apache.org/licenses/LICENSE-2.0
013 *
014 * Unless required by applicable law or agreed to in writing,
015 * software distributed under the License is distributed on an
016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017 * KIND, either express or implied.  See the License for the
018 * specific language governing permissions and limitations
019 * under the License.
020 */
021
022import java.io.File;
023import java.io.IOException;
024import java.util.List;
025
026import javax.swing.text.MutableAttributeSet;
027import javax.swing.text.SimpleAttributeSet;
028
029import org.apache.commons.configuration.ConfigurationException;
030import org.apache.commons.configuration.XMLConfiguration;
031import org.apache.maven.doxia.sink.impl.SinkUtils;
032import org.codehaus.plexus.util.ReaderFactory;
033
034/**
035 * A utility class to construct FO configuration parameters.
036 *
037 * @author ltheussl
038 * @since 1.1
039 */
040public class FoConfiguration
041{
042    /** Holds the single attributes. */
043    private MutableAttributeSet attributeSet;
044
045    /** The configuration instance. */
046    private final XMLConfiguration config;
047
048    /** The list of attribute sets. */
049    private List<?> sets;
050
051    /**
052     * Constructor.
053     */
054    public FoConfiguration()
055    {
056        this.config = new XMLConfiguration();
057
058        // necessary because some attributes contain commas:
059        config.setDelimiterParsingDisabled( true );
060
061        loadDefaultConfig();
062    }
063
064    /**
065     * Load configuration parameters from a File.
066     *
067     * @param configFile the configuration file.
068     *
069     * @throws java.io.IOException if the File cannot be read
070     *  or some error occurs when initializing the configuration parameters.
071     *
072     * @since 1.1.1
073     */
074    public void load( File configFile )
075            throws IOException
076    {
077        config.clear();
078
079        try
080        {
081            config.load( configFile );
082        }
083        catch ( ConfigurationException cex )
084        {
085            throw new IOException( cex );
086        }
087
088        loadDefaultConfig(); // this adds default values that are missing from above
089    }
090
091    /**
092     * Builds a list of attributes.
093     *
094     * @param attributeId A unique id to identify the set of attributes.
095     * This should correspond to the name of an attribute-set
096     * defined in the configuration file.
097     * @return A string that contains a list of attributes with
098     * the values configured for the current builder. Returns the
099     * empty string if attributeId is null or if attributeId
100     * is not a valid identifier.
101     */
102    public String getAttributeString( String attributeId )
103    {
104        if ( attributeId == null )
105        {
106            return "";
107        }
108
109        reset();
110        addAttributes( attributeId );
111
112        return SinkUtils.getAttributeString( attributeSet );
113    }
114
115    /**
116     * Builds a set of attributes.
117     *
118     * @param attributeId A unique id to identify the set of attributes.
119     * This should correspond to the name of an attribute-set
120     * defined in the configuration file.
121     * @return A MutableAttributeSet that contains the attributes with
122     * the values configured for the current builder. Returns null
123     * if attributeId is null or empty, or if attributeId is not a valid identifier.
124     */
125    public MutableAttributeSet getAttributeSet( String attributeId )
126    {
127        if ( attributeId == null || attributeId.length() == 0 )
128        {
129            return null;
130        }
131
132        reset();
133        addAttributes( attributeId );
134
135        if ( attributeSet.getAttributeCount() == 0 )
136        {
137            return null;
138        }
139
140        return attributeSet;
141    }
142
143    /**
144     * Adds an attribute to the current StringBuilder.
145     *
146     * @param attributeId A unique id to identify the set of attributes.
147     * This should correspond to the name of an attribute-set
148     * defined in the configuration file.
149     */
150    private void addAttributes( String attributeId )
151    {
152        int index = sets.indexOf( attributeId );
153        String keybase = "xsl:attribute-set(" + index + ")";
154
155        Object prop = config.getProperty( keybase + ".xsl:attribute" );
156
157        if ( prop instanceof List<?> )
158        {
159            List<?> values = (List<?>) prop;
160            List<?> keys = config.getList( keybase + ".xsl:attribute[@name]" );
161
162            for ( int i = 0; i < values.size(); i++ )
163            {
164                attributeSet.addAttribute( keys.get( i ), values.get( i ) );
165            }
166        }
167        else if ( prop instanceof String )
168        {
169            String value = config.getString( keybase + ".xsl:attribute" );
170            String key = config.getString( keybase + ".xsl:attribute[@name]" );
171            attributeSet.addAttribute( key, value );
172        }
173
174        String extend = config.getString( keybase + "[@use-attribute-sets]" );
175
176        if ( extend != null )
177        {
178            addAttributes( extend );
179        }
180    }
181
182    /** Load the default fo configuration file. */
183    private void loadDefaultConfig()
184    {
185        try
186        {
187            config.load( ReaderFactory.newXmlReader( getClass().getResourceAsStream( "/fo-styles.xslt" ) ) );
188        }
189        catch ( ConfigurationException | IOException cex )
190        {
191            // this should not happen
192            throw new RuntimeException( cex );
193        }
194
195        this.sets = config.getList( "xsl:attribute-set[@name]" );
196        reset();
197    }
198
199    /**
200     * (Re-)initialize the AttributeSet.
201     */
202    private void reset()
203    {
204        this.attributeSet = new SimpleAttributeSet();
205    }
206
207}