001/*
002 * ============================================================================
003 *  Copyright © 2002-2023 by Thomas Thrien.
004 *  All Rights Reserved.
005 * ============================================================================
006 *  Licensed to the public under the agreements of the GNU Lesser General Public
007 *  License, version 3.0 (the "License"). You may obtain a copy of the License at
008 *
009 *       http://www.gnu.org/licenses/lgpl.html
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013 *  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014 *  License for the specific language governing permissions and limitations
015 *  under the License.
016 */
017
018package org.tquadrat.foundation.config.cli;
019
020import static org.apiguardian.api.API.Status.INTERNAL;
021import static org.tquadrat.foundation.config.CmdLineException.MSGKEY_InvalidFileName;
022import static org.tquadrat.foundation.config.CmdLineException.MSG_InvalidFileName;
023import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
024
025import javax.xml.parsers.DocumentBuilderFactory;
026import javax.xml.parsers.ParserConfigurationException;
027import java.io.FileNotFoundException;
028import java.io.IOException;
029import java.util.Collection;
030import java.util.List;
031import java.util.function.BiConsumer;
032
033import org.apiguardian.api.API;
034import org.tquadrat.foundation.annotation.ClassVersion;
035import org.tquadrat.foundation.config.CmdLineException;
036import org.tquadrat.foundation.config.spi.Parameters;
037import org.tquadrat.foundation.i18n.Message;
038import org.tquadrat.foundation.i18n.Translation;
039import org.tquadrat.foundation.util.stringconverter.FileStringConverter;
040import org.w3c.dom.Document;
041import org.xml.sax.SAXException;
042
043/**
044 *  An implementation of
045 *  {@link CmdLineValueHandler}
046 *  for
047 *  {@link Document}
048 *  values.<br>
049 *  <br>The {@code Document} will be identified by the name of the respective
050 *  {@link java.io.File}
051 *  object that of course has to exist and needs to be accessible.
052 *
053 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
054 *  @version $Id: DocumentValueHandler.java 1061 2023-09-25 16:32:43Z tquadrat $
055 *  @since 0.0.1
056 *
057 *  @UMLGraph.link
058 */
059@ClassVersion( sourceVersion = "$Id: DocumentValueHandler.java 1061 2023-09-25 16:32:43Z tquadrat $" )
060@API( status = INTERNAL, since = "0.0.1" )
061@SuppressWarnings( "exports" )
062public final class DocumentValueHandler extends CmdLineValueHandler<Document>
063{
064        /*-----------*\
065    ====** Constants **========================================================
066        \*-----------*/
067    /**
068     *  The error message for a failed read attempt for the XML file: {@value}.
069     */
070    public static final String MSG_ReadFailed = "Reading/parsing of XML file '%1$s' failed";
071
072    /**
073     *  The resource bundle key for the message about a failed read attempt for
074     *  the XML file.
075     */
076    @Message
077    (
078        description = "The error message about a failed read attempt for the XML file.",
079        translations =
080        {
081            @Translation( language = "en", text = MSG_ReadFailed ),
082            @Translation( language = "de", text = "Die XML-Datei '%1$s' kann nicht gelesen oder geparst werden" )
083        }
084    )
085    public static final int MSGKEY_ReadFailed = 27;
086
087        /*--------------*\
088    ====** Constructors **=====================================================
089        \*--------------*/
090    /**
091     *  Creates a new {@code DocumentValueHandler} instance.
092     *
093     *  @param  valueSetter The function that places the translated value to
094     *      the property.
095     */
096    public DocumentValueHandler( final BiConsumer<String,Document> valueSetter )
097    {
098        //---* Daddy will do the null check *----------------------------------
099        super( valueSetter );
100    }   //  DocumentValueHandler()
101
102        /*---------*\
103    ====** Methods **==========================================================
104        \*---------*/
105    /**
106     *  {@inheritDoc}
107     */
108    @SuppressWarnings( {"ThrowCaughtLocally", "OverlyBroadCatchBlock"} )
109    @Override
110    protected final Collection<Document> translate( final Parameters params ) throws CmdLineException
111    {
112        Collection<Document> retValue = List.of();
113        var fileName = requireNonNullArgument( params, "params" ).getParameter( 0 );
114        try
115        {
116            final var documentBuilderFactory = DocumentBuilderFactory.newInstance();
117            final var builder = documentBuilderFactory.newDocumentBuilder();
118            final var documentFile = FileStringConverter.INSTANCE.fromString( fileName ).getCanonicalFile().getAbsoluteFile();
119            fileName = documentFile.getAbsolutePath();
120            if( !documentFile.exists() ) throw new FileNotFoundException( fileName );
121            if( !documentFile.isFile() ) throw new IOException( "'%s' is not a file".formatted( fileName ) );
122            if( !documentFile.canRead() ) throw new IOException( "Cannot read '%s'".formatted( fileName ) );
123            final var document = builder.parse( documentFile );
124            retValue = List.of( document );
125        }
126        catch( final IllegalArgumentException e )
127        {
128            throw new CmdLineException( MSG_InvalidFileName, e, MSGKEY_InvalidFileName, fileName );
129        }
130        catch( final IOException | ParserConfigurationException | SAXException e )
131        {
132            throw new CmdLineException( MSG_ReadFailed, e, MSGKEY_ReadFailed, fileName );
133        }
134
135        //---* Done *----------------------------------------------------------
136        return retValue;
137    }   //  translate()
138}
139//  class DocumentValueHandler
140
141/*
142 *  End of File
143 */