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