001package org.apache.maven.doxia.parser;
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.io.InputStream;
025import java.io.Reader;
026import java.io.StringReader;
027
028import java.util.Properties;
029
030import org.apache.maven.doxia.logging.Log;
031import org.apache.maven.doxia.logging.SystemStreamLog;
032import org.apache.maven.doxia.macro.Macro;
033import org.apache.maven.doxia.macro.MacroExecutionException;
034import org.apache.maven.doxia.macro.MacroRequest;
035import org.apache.maven.doxia.macro.manager.MacroManager;
036import org.apache.maven.doxia.macro.manager.MacroNotFoundException;
037import org.apache.maven.doxia.sink.Sink;
038import org.codehaus.plexus.component.annotations.Requirement;
039
040/**
041 * An abstract base class that defines some convenience methods for parsers.
042 * Provides a macro mechanism to give dynamic functionalities for the parsing.
043 *
044 * @author Jason van Zyl
045 * @version $Id$
046 * @since 1.0
047 */
048public abstract class AbstractParser
049    implements Parser
050{
051    /** Indicates that a second parsing is required. */
052    private boolean secondParsing = false;
053
054    @Requirement
055    private MacroManager macroManager;
056
057    /** Log instance. */
058    private Log logger;
059
060    /**
061     * Emit Doxia comment events when parsing comments?
062     */
063    private boolean emitComments = true;
064
065    private static final String DOXIA_VERSION;
066
067    static
068    {
069        final Properties props = new Properties();
070        final InputStream is = AbstractParser.class.getResourceAsStream( "/build-info.properties" );
071
072        if ( is == null )
073        {
074            props.setProperty( "version", "unknown" ); // should not happen
075        }
076        else
077        {
078            try
079            {
080                props.load( is );
081            }
082            catch ( IOException ex )
083            {
084                props.setProperty( "version", "unknown" ); // should not happen
085            }
086            finally
087            {
088                try
089                {
090                    is.close();
091                }
092                catch ( IOException ex )
093                {
094                    // oh well...
095                }
096            }
097        }
098
099        DOXIA_VERSION = props.getProperty( "version" );
100    }
101
102    /** {@inheritDoc} */
103    public int getType()
104    {
105        return UNKNOWN_TYPE;
106    }
107
108    public void setEmitComments( boolean emitComments )
109    {
110        this.emitComments = emitComments;
111    }
112
113    public boolean isEmitComments()
114    {
115        return emitComments;
116    }
117
118    /**
119     * Execute a macro on the given sink.
120     *
121     * @param macroId An id to lookup the macro.
122     * @param request The corresponding MacroRequest.
123     * @param sink The sink to receive the events.
124     * @throws org.apache.maven.doxia.macro.MacroExecutionException if an error occurred during execution.
125     * @throws org.apache.maven.doxia.macro.manager.MacroNotFoundException if the macro could not be found.
126     */
127    // Made public right now because of the structure of the APT parser and
128    // all its inner classes.
129    public void executeMacro( String macroId, MacroRequest request, Sink sink )
130        throws MacroExecutionException, MacroNotFoundException
131    {
132        Macro macro = getMacroManager().getMacro( macroId );
133
134        macro.enableLogging( getLog() );
135
136        macro.execute( sink, request );
137    }
138
139    /**
140     * Returns the current base directory.
141     *
142     * @return The base directory.
143     *
144     * @deprecated this does not work in multi-module builds, see DOXIA-373
145     */
146    protected File getBasedir()
147    {
148        // TODO: This is baaad, it should come in with the request.
149        // (this is only used for macro requests, see AptParser)
150
151        String basedir = System.getProperty( "basedir" );
152
153        if ( basedir != null )
154        {
155            return new File( basedir );
156        }
157
158        return new File( new File( "" ).getAbsolutePath() );
159    }
160
161    /**
162     * Convenience method to parse an arbitrary string and emit events into the given sink.
163     *
164     * @param string A string that provides the source input.
165     * @param sink A sink that consumes the Doxia events.
166     * @throws org.apache.maven.doxia.parser.ParseException if the string could not be parsed.
167     * @since 1.1
168     */
169    public void parse( String string, Sink sink )
170        throws ParseException
171    {
172        parse( new StringReader( string ), sink );
173    }
174    
175    @Override
176    public void parse( Reader source, Sink sink, String reference )
177        throws ParseException
178    {
179        parse( source, sink );
180    }
181
182    /**
183     * Set <code>secondParsing</code> to true, if we need a second parsing.
184     *
185     * @param second True for second parsing.
186     */
187    public void setSecondParsing( boolean second )
188    {
189        this.secondParsing = second;
190    }
191
192    /**
193     * Indicates if we are currently parsing a second time.
194     *
195     * @return true if we are currently parsing a second time.
196     * @since 1.1
197     */
198    protected boolean isSecondParsing()
199    {
200        return secondParsing;
201    }
202
203    /** {@inheritDoc} */
204    public void enableLogging( Log log )
205    {
206        this.logger = log;
207    }
208
209    /**
210     * Returns the current logger for this parser.
211     * If no logger has been configured yet, a new SystemStreamLog is returned.
212     *
213     * @return Log
214     * @since 1.1
215     */
216    protected Log getLog()
217    {
218        if ( logger == null )
219        {
220            logger = new SystemStreamLog();
221        }
222
223        return logger;
224    }
225
226    /**
227     * Gets the current {@link MacroManager}.
228     *
229     * @return The current {@link MacroManager}.
230     * @since 1.1
231     */
232    protected MacroManager getMacroManager()
233    {
234        return macroManager;
235    }
236
237    /**
238     * Initialize the parser. This is called first by
239     * {@link #parse(java.io.Reader, org.apache.maven.doxia.sink.Sink)} and can be used
240     * to set the parser into a clear state so it can be re-used.
241     *
242     * @since 1.1.2
243     */
244    protected void init()
245    {
246        // nop
247    }
248
249    /**
250     * The current Doxia version.
251     *
252     * @return the current Doxia version as a String.
253     *
254     * @since 1.2
255     */
256    protected static String doxiaVersion()
257    {
258        return DOXIA_VERSION;
259    }
260}