001/*
002 * ============================================================================
003 * Copyright © 2002-2022 by Thomas Thrien.
004 * All Rights Reserved.
005 * ============================================================================
006 *
007 * Licensed to the public under the agreements of the GNU Lesser General Public
008 * License, version 3.0 (the "License"). You may obtain a copy of the License at
009 *
010 *      http://www.gnu.org/licenses/lgpl.html
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
014 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
015 * License for the specific language governing permissions and limitations
016 * under the License.
017 */
018
019package org.tquadrat.foundation.util.stringconverter;
020
021import static java.net.URLDecoder.decode;
022import static java.net.URLEncoder.encode;
023import static org.apiguardian.api.API.Status.STABLE;
024import static org.tquadrat.foundation.lang.CommonConstants.UTF8;
025import static org.tquadrat.foundation.lang.Objects.nonNull;
026import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
027
028import java.io.Serial;
029import java.net.URL;
030import java.nio.charset.Charset;
031
032import org.apiguardian.api.API;
033import org.tquadrat.foundation.annotation.ClassVersion;
034import org.tquadrat.foundation.lang.StringConverter;
035
036/**
037 *  <p>{@summary An implementation of
038 *  {@link StringConverter}
039 *  for
040 *  {@link URL}
041 *  values.}
042 *  Different from
043 *  {@link URLStringConverter},
044 *  this implementation expects an &quot;{@code application/x-www-form-url}&quot;
045 *  encoded String as the argument for
046 *  {@link #fromString(CharSequence)}
047 *  and returns such a String from
048 *  {@link #toString(URL)}.</p>
049 *  <p>The method
050 *  {@link #fromString(CharSequence)}
051 *  will use
052 *  {@link java.net.URLDecoder#decode(String, Charset)}
053 *  to get the decode URL String, then it calls
054 *  {@link URLStringConverter#fromString(CharSequence)}
055 *  to create a {@code URL} instance from it.</p>
056 *  <p>{@link #toString(URL)}
057 *  uses
058 *  {@link URLStringConverter#toString(URL)}
059 *  to get a String out of the URL and encodes it with a call to
060 *  {@link java.net.URLEncoder#encode(String, Charset)}.</p>
061 *  <p>Based on the {@href http://www.w3.org/TR/html40/appendix/notes.html#non-ascii-chars World Wide Web Consortium Recommendation}
062 *  both methods ({@code fromString()} and {@code toString()}) are using
063 *  {@code UTF-8} as the
064 *  {@linkplain Charset <code>charset</code> argument}.</p>
065 *
066 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
067 *  @version $Id: EncodedURLStringConverter.java 1080 2024-01-03 11:05:21Z tquadrat $
068 *  @since 0.1.0
069 *
070 *  @UMLGraph.link
071 */
072@ClassVersion( sourceVersion = "$Id: EncodedURLStringConverter.java 1080 2024-01-03 11:05:21Z tquadrat $" )
073@API( status = STABLE, since = "0.1.0" )
074public final class EncodedURLStringConverter extends URLStringConverter
075{
076        /*------------*\
077    ====** Attributes **=======================================================
078        \*------------*/
079    /**
080     *  The character encoding that is used at default.
081     *
082     *  @serial
083     */
084    private final Charset m_Encoding;
085
086        /*------------------------*\
087    ====** Static Initialisations **===========================================
088        \*------------------------*/
089    /**
090     *  The serial version UID for objects of this class: {@value}.
091     *
092     *  @hidden
093     */
094    @Serial
095    private static final long serialVersionUID = 1L;
096
097    /**
098     *  <p>{@summary An instance of this class.}</p>
099     *  <p>This instance uses
100     *  {@linkplain org.tquadrat.foundation.lang.CommonConstants#UTF8 UTF-8}
101     *  as the default encoding.</p>
102     */
103    public static final EncodedURLStringConverter INSTANCE = new EncodedURLStringConverter();
104
105        /*--------------*\
106    ====** Constructors **=====================================================
107        \*--------------*/
108    /**
109     *  Creates a new instance of {@code EncodedURLStringConverter} that uses
110     *  {@linkplain org.tquadrat.foundation.lang.CommonConstants#UTF8 UTF-8}
111     *  as the default encoding.
112     */
113    public EncodedURLStringConverter() { this( UTF8 ); }
114
115    /**
116     *  Creates a new instance of {@code EncodedURLStringConverter} that uses
117     *  the given encoding as the default encoding.
118     *
119     *  @param  encoding    The default character encoding.
120     *
121     *  @see java.net.URLEncoder#encode(String, Charset)
122     *  @see java.net.URLDecoder#decode(String, Charset)
123     */
124    public EncodedURLStringConverter( final Charset encoding )
125    {
126        m_Encoding = requireNonNullArgument( encoding, "encoding" );
127    }   //  EncodedURLStringConverter()
128
129        /*---------*\
130    ====** Methods **==========================================================
131        \*---------*/
132    /**
133     *  Converts the given String that contains a valid
134     *  {@code application/x-www-form-url} encoded URL into an instance of
135     *  {@link URL},
136     *  using the provided character encoding.
137     *
138     *  @param  source  The source; can be {@code null}.
139     *  @param  charset The character encoding of the String.
140     *  @return The respective URL, or {@code null} if the source was already
141     *      {@code null}.
142     *  @throws IllegalArgumentException    The source was either not a valid
143     *      URL, or the encoding was invalid.
144     */
145    public final URL fromString( final CharSequence source, final Charset charset ) throws IllegalArgumentException
146    {
147        requireNonNullArgument( charset, "charset" );
148        URL retValue = null;
149        if( nonNull( source ) )
150        {
151            final var url = decode( source.toString(), charset );
152            retValue = super.fromString( url );
153        }
154
155        //---* Done *----------------------------------------------------------
156        return retValue;
157    }   //  fromString()
158
159    /**
160     *  {@inheritDoc}
161     *  <p>This method uses the default character encoding as set by the
162     *  constructor.</p>
163     */
164    @Override
165    public URL fromString( final CharSequence source ) throws IllegalArgumentException
166    {
167        final var retValue = fromString( source, m_Encoding );
168
169        //---* Done *----------------------------------------------------------
170        return retValue;
171    }   //  fromString()
172
173    /**
174     *  Converts the given
175     *  {@link URL},
176     *  into an {@code application/x-www-form-url} encoded String
177     *  representation, using the provided character encoding.
178     *
179     *  @param  source  The source; can be {@code null}.
180     *  @param  charset The character encoding for the String.
181     *  @return The respective String representation, or {@code null} if the
182     *      source was already {@code null}.
183     *  @throws IllegalArgumentException    The source was either not a valid
184     *      URL, or the encoding was invalid.
185     */
186    public final String toString( final URL source, final Charset charset )
187    {
188        requireNonNullArgument( charset, "charset" );
189        final var url = super.toString( source);
190        final var retValue = nonNull( url ) ? encode( url, charset ) : null;
191
192        //---* Done *----------------------------------------------------------
193        return retValue;
194    }   //  toString()
195
196    /**
197     *  {@inheritDoc}
198     *  <p>This method uses the default character encoding as set by the
199     *  constructor.</p>
200     */
201    @Override
202    public final String toString( final URL source )
203    {
204        final var retValue = toString( source, m_Encoding );
205
206        //---* Done *----------------------------------------------------------
207        return retValue;
208    }   //  toString()
209}
210//  class EncodedURLStringConverter
211
212/*
213 *  End of File
214 */