001/*
002 * ============================================================================
003 * Copyright © 2002-2021 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.xml.builder;
020
021import static org.apiguardian.api.API.Status.STABLE;
022import static org.tquadrat.foundation.lang.Objects.nonNull;
023import static org.tquadrat.foundation.lang.Objects.requireNonNullArgument;
024import static org.tquadrat.foundation.lang.Objects.requireNotEmptyArgument;
025import static org.tquadrat.foundation.util.StringUtils.isNotEmpty;
026
027import java.time.Instant;
028import java.time.LocalDate;
029import java.time.LocalDateTime;
030import java.time.ZonedDateTime;
031import java.util.Optional;
032
033import org.apiguardian.api.API;
034import org.tquadrat.foundation.annotation.ClassVersion;
035import org.tquadrat.foundation.xml.builder.internal.ProcessingInstructionImpl;
036import org.tquadrat.foundation.xml.builder.spi.Element;
037
038/**
039 *  <p>{@summary The definition for a processing instruction.}</p>
040 *  <p>According to the specification, an XML processing instruction have this
041 *  general structure</p>
042 *  <pre><code>&lt;?<i>name</i> <i>data</i> ?&gt;</code></pre>
043 *  <p>with <i>{@code data}</i> being arbitrary text as defined by the target
044 *  processor that responds to the respective processing instruction.</p>
045 *  <p>But in many cases, this <i>{@code data}</i> will be structured like
046 *  regular XML attributes.</p>
047 *  <p>Therefore we provide both API: with
048 *  {@link #addData(CharSequence)}
049 *  plain text can be added, with the various
050 *  {@link #setAttribute(String, CharSequence) setAttribute()}
051 *  methods the data will be formatted as attributes.</p>
052 *
053 *  @extauthor Thomas Thrien - thomas.thrien@tquadrat.org
054 *  @version $Id: ProcessingInstruction.java 1030 2022-04-06 13:42:02Z tquadrat $
055 *  @since 0.0.5
056 *
057 *  @UMLGraph.link
058 */
059@ClassVersion( sourceVersion = "$Id: ProcessingInstruction.java 1030 2022-04-06 13:42:02Z tquadrat $" )
060@API( status = STABLE, since = "0.0.5" )
061public sealed interface ProcessingInstruction extends Element
062    permits ProcessingInstructionImpl
063{
064        /*---------*\
065    ====** Methods **==========================================================
066        \*---------*/
067    /**
068     *  Adds data to the processing instruction.
069     *
070     *  @param  data    The data to add.
071     *  @return This instance.
072     */
073    public ProcessingInstruction addData( final CharSequence data );
074
075    /**
076     *  <p>{@summary Sets the attribute with the given name.}</p>
077     *  <p>The method uses
078     *  {@link Boolean#toString(boolean)}
079     *  to convert the provided flag to a {@code String}.</p>
080     *
081     *  @param  name    The name of the attribute; the name is case-sensitive.
082     *  @param  flag    The attribute's value.
083     *  @return This instance.
084     *  @throws IllegalArgumentException    An attribute with the given name is
085     *      not valid for the element, or no attributes are allowed at all.
086     */
087    public default ProcessingInstruction setAttribute( final String name, final boolean flag ) throws IllegalArgumentException
088    {
089        return setAttribute( name, Boolean.toString( flag ) );
090    }   //  setAttribute()
091
092    /**
093     *  <p>{@summary Sets the attribute with the given name.}</p>
094     *  <p>The method uses
095     *  {@link Boolean#toString()}
096     *  to convert the provided flag to a {@code String}.</p>
097     *
098     *  @param  name    The name of the attribute; the name is case-sensitive.
099     *  @param  flag    The attribute's value; if {@code null} the
100     *      attribute will be removed.
101     *  @return This instance.
102     *  @throws IllegalArgumentException    An attribute with the given name is
103     *      not valid for the element, or no attributes are allowed at all.
104     */
105    public default ProcessingInstruction setAttribute( final String name, final Boolean flag ) throws IllegalArgumentException
106    {
107        return setAttribute( name, nonNull( flag ) ? Boolean.toString( flag ) : null );
108    }   //  setAttribute()
109
110    /**
111     *  Sets the attribute with the given name.
112     *
113     *  @param  name    The name of the attribute; the name is case-sensitive.
114     *  @param  value   The attribute's value; if {@code null} the
115     *      attribute will be removed.
116     *  @return This instance.
117     *  @throws IllegalArgumentException    An attribute with the given name is
118     *      not valid for the element, or no attributes are allowed at all.
119     */
120    public default ProcessingInstruction setAttribute( final String name, final CharSequence value ) throws IllegalArgumentException
121    {
122        return setAttribute( requireNotEmptyArgument( name, "name" ), value, Optional.empty() );
123    }   //  setAttribute()
124
125    /**
126     *  Sets the attribute with the given name.
127     *
128     *  @param  name    The name of the attribute; the name is case-sensitive.
129     *  @param  value   The attribute's value; if {@code null} the
130     *      attribute will be removed.
131     *  @param  append  If not
132     *      {@linkplain Optional#empty() empty}, the new value will be appended
133     *      on an already existing one, and this sequence is used as the
134     *      separator.
135     *  @return This instance.
136     *  @throws IllegalArgumentException    An attribute with the given name is
137     *      not valid for the element.
138     */
139    @SuppressWarnings( "OptionalUsedAsFieldOrParameterType" )
140    public ProcessingInstruction setAttribute( final String name, final CharSequence value, final Optional<? extends CharSequence> append ) throws IllegalArgumentException;
141
142    /**
143     *  <p>{@summary Sets the attribute with the given name.}</p>
144     *  <p>The method uses
145     *  {@link Double#toString(double)}
146     *  to convert the provided number to a {@code String}.</p>
147     *
148     *  @param  name    The name of the attribute; the name is case-sensitive.
149     *  @param  number   The attribute's value.
150     *  @return This instance.
151     *  @throws IllegalArgumentException    An attribute with the given name is
152     *      not valid for the element, or no attributes are allowed at all.
153     */
154    public default ProcessingInstruction setAttribute( final String name, final double number ) throws IllegalArgumentException
155    {
156        return setAttribute( name, Double.toString( number ) );
157    }   //  setAttribute()
158
159    /**
160     *  <p>{@summary Sets the attribute with the given name.}</p>
161     *  <p>The method uses
162     *  {@link Enum#name()}
163     *  to convert the provided value to a {@code String}.</p>
164     *
165     *  @param  <E> The concrete enum type of {@code value}.
166     *  @param  name    The name of the attribute; the name is case-sensitive.
167     *  @param  enumValue   The attribute's value; if {@code null} the
168     *      attribute will be removed.
169     *  @return This instance.
170     *  @throws IllegalArgumentException    An attribute with the given name is
171     *      not valid for the element, or no attributes are allowed at all.
172     */
173    public default <E extends Enum<E>> ProcessingInstruction setAttribute( final String name, final E enumValue ) throws IllegalArgumentException
174    {
175        return setAttribute( name, nonNull( enumValue ) ? enumValue.name() : null );
176    }   //  setAttribute()
177
178    /**
179     *  <p>{@summary Sets the attribute with the given name.}</p>
180     *  <p>The method uses
181     *  {@link Instant#toString()}
182     *  to convert the provided number to a {@code String}.</p>
183     *
184     *  @param  name    The name of the attribute; the name is case-sensitive.
185     *  @param  date    The attribute's value; if {@code null} the
186     *      attribute will be removed.
187     *  @return This instance.
188     *  @throws IllegalArgumentException    An attribute with the given name is
189     *      not valid for the element, or no attributes are allowed at all.
190     */
191    public default ProcessingInstruction setAttribute( final String name, final Instant date ) throws IllegalArgumentException
192    {
193        return setAttribute( name, nonNull( date ) ? date.toString() : null );
194    }   //  setAttribute()
195
196    /**
197     *  <p>{@summary Sets the attribute with the given name.}</p>
198     *  <p>The method uses
199     *  {@link Integer#toString(int)}
200     *  to convert the provided number to a {@code String}.</p>
201     *
202     *  @param  name    The name of the attribute; the name is case-sensitive.
203     *  @param  number  The attribute's value.
204     *  @return This instance.
205     *  @throws IllegalArgumentException    An attribute with the given name is
206     *      not valid for the element, or no attributes are allowed at all.
207     */
208    public default ProcessingInstruction setAttribute( final String name, final int number ) throws IllegalArgumentException
209    {
210        return setAttribute( name, Integer.toString( number ) );
211    }   //  setAttribute()
212
213    /**
214     *  <p>{@summary Sets the attribute with the given name.}</p>
215     *  <p>The method uses
216     *  {@link LocalDate#toString()}
217     *  to convert the provided number to a {@code String}.</p>
218     *
219     *  @param  name    The name of the attribute; the name is case-sensitive.
220     *  @param  date    The attribute's value; if {@code null} the
221     *      attribute will be removed.
222     *  @return This instance.
223     *  @throws IllegalArgumentException    An attribute with the given name is
224     *      not valid for the element, or no attributes are allowed at all.
225     */
226    public default ProcessingInstruction setAttribute( final String name, final LocalDate date ) throws IllegalArgumentException
227    {
228        return setAttribute( name, nonNull( date ) ? date.toString() : null );
229    }   //  setAttribute()
230
231    /**
232     *  <p>{@summary Sets the attribute with the given name.}</p>
233     *  <p>The method uses
234     *  {@link LocalDateTime#toString()}
235     *  to convert the provided number to a {@code String}.</p>
236     *
237     *  @param  name    The name of the attribute; the name is case-sensitive.
238     *  @param  date    The attribute's value; if {@code null} the
239     *      attribute will be removed.
240     *  @return This instance.
241     *  @throws IllegalArgumentException    An attribute with the given name is
242     *      not valid for the element, or no attributes are allowed at all.
243     */
244    public default ProcessingInstruction setAttribute( final String name, final LocalDateTime date ) throws IllegalArgumentException
245    {
246        return setAttribute( name, nonNull( date ) ? date.toString() : null );
247    }   //  setAttribute()
248
249    /**
250     *  <p>{@summary Sets the attribute with the given name.}</p>
251     *  <p>The method uses
252     *  {@link Long#toString(long)}
253     *  to convert the provided number to a {@code String}.</p>
254     *
255     *  @param  name    The name of the attribute; the name is case-sensitive.
256     *  @param  number   The attribute's value.
257     *  @return This instance.
258     *  @throws IllegalArgumentException    An attribute with the given name is
259     *      not valid for the element, or no attributes are allowed at all.
260     */
261    public default ProcessingInstruction setAttribute( final String name, final long number ) throws IllegalArgumentException
262    {
263        return setAttribute( name, Long.toString( number ) );
264    }   //  setAttribute()
265
266    /**
267     *  <p>{@summary Sets the attribute with the given name.}</p>
268     *  <p>The method uses
269     *  {@link Number#toString()}
270     *  to convert the provided number to a {@code String}.</p>
271     *
272     *  @param  name    The name of the attribute; the name is case-sensitive.
273     *  @param  number   The attribute's value; if {@code null} the
274     *      attribute will be removed.
275     *  @return This instance.
276     *  @throws IllegalArgumentException    An attribute with the given name is
277     *      not valid for the element, or no attributes are allowed at all.
278     */
279    public default ProcessingInstruction setAttribute( final String name, final Number number ) throws IllegalArgumentException
280    {
281        return setAttribute( name, nonNull( number ) ? number.toString() : null );
282    }   //  setAttribute()
283
284    /**
285     *  <p>{@summary Sets the attribute with the given name.}</p>
286     *  <p>The method uses
287     *  {@link ZonedDateTime#toString()}
288     *  to convert the provided number to a {@code String}.</p>
289     *
290     *  @param  name    The name of the attribute; the name is case-sensitive.
291     *  @param  date    The attribute's value; if {@code null} the
292     *      attribute will be removed.
293     *  @return This instance.
294     *  @throws IllegalArgumentException    An attribute with the given name is
295     *      not valid for the element, or no attributes are allowed at all.
296     */
297    public default ProcessingInstruction setAttribute( final String name, final ZonedDateTime date ) throws IllegalArgumentException
298    {
299        return setAttribute( name, nonNull( date ) ? date.toString() : null );
300    }   //  setAttribute()
301
302    /**
303     *  <p>{@summary Sets the attribute with the given name if the provided
304     *  value is not empty.}</p>
305     *  <p>The method uses
306     *  {@link org.tquadrat.foundation.util.StringUtils#isNotEmpty(CharSequence)}
307     *  to test if the given value is empty.</p>
308     *
309     *  @param  name    The name of the attribute.
310     *  @param  value   The value for the attribute; can be {@code null}.
311     *  @return This instance.
312     *  @throws IllegalArgumentException    An attribute with the given name is
313     *      not valid for the element, or no attributes are allowed at all.
314     */
315    @SuppressWarnings( "UnusedReturnValue" )
316    public default ProcessingInstruction setAttributeIfNotEmpty( final String name, final CharSequence value ) throws IllegalArgumentException
317    {
318        if( isNotEmpty( value ) ) setAttribute( name, value );
319
320        //---* Done *----------------------------------------------------------
321        return this;
322    }   //  setAttributeIfNotEmpty()
323
324    /**
325     *  Sets the attribute with the given name if the provided value is not
326     *  empty.
327     *
328     *  @param  name    The name of the attribute.
329     *  @param  optional   The value for the attribute.
330     *  @return This instance.
331     *  @throws IllegalArgumentException    An attribute with the given name is
332     *      not valid for the element, or no attributes are allowed at all.
333     */
334    @SuppressWarnings( {"UnusedReturnValue", "OptionalUsedAsFieldOrParameterType"} )
335    public default ProcessingInstruction setAttributeIfNotEmpty( final String name, final Optional<? extends CharSequence> optional ) throws IllegalArgumentException
336    {
337        requireNonNullArgument( optional, "optional" ).ifPresent( value -> setAttribute( name, value ) );
338
339        //---* Done *----------------------------------------------------------
340        return this;
341    }   //  setAttributeIfNotEmpty()
342}
343//  interface ProcessingInstruction
344
345/*
346 *  End of File
347 */