001package Torello.Java.JSON;
002
003import Torello.JavaDoc.IntoHTMLTable;
004import static Torello.JavaDoc.IntoHTMLTable.Background.*;
005
006import javax.json.JsonArray;
007import javax.json.JsonObject;
008import javax.json.JsonValue;
009import javax.json.JsonNumber;
010import javax.json.JsonString;
011
012import static javax.json.JsonValue.ValueType.*;
013
014import java.math.BigDecimal;
015import java.util.function.Function;
016import java.util.function.ObjIntConsumer;
017
018/**
019 * This class is the "Central Artery" for all Json-Array Processing done in this package.
020 * These four FOR-LOOPS handle 100% of the array processors done by all of the "RJArr"
021 * classes offered.
022 *  
023 * These four methods are extremely similar, but have a few minor subtleties that prevent 
024 * them from being unified into a single handler for all types.
025 */
026public class ProcessJsonArray
027{
028    private ProcessJsonArray() { }
029
030
031    // ********************************************************************************************
032    // ********************************************************************************************
033    // Un-Synchronized Method Variants
034    // ********************************************************************************************
035    // ********************************************************************************************
036
037
038    /**
039     * Any and all Json-Array Processors that are intended to read an array of {@link JsonNumber}
040     * will invoke this method to do their Type-Conversions.
041     * 
042     * @param <NUMERIC_DATA_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_NUM_DATA_TYPE>
043     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_NUM_RETURN_TYPE>
044     * 
045     * @param ja This should be any instance of {@link JsonArray}.  It is expected that if this
046     * array does not contain explicit {@link JsonNumber} values, that is should at least contain
047     * values that are to converted or properly parsed into Java-Numbers.
048     * 
049     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
050     * 
051     * @return An instance of the type specified by Type-Parameter {@code 'RETURN_TYPE'}
052     */
053    public static <NUMERIC_DATA_TYPE extends Number, RETURN_TYPE> RETURN_TYPE numericToJava(
054            final JsonArray                                     ja,
055            final SettingsRec<NUMERIC_DATA_TYPE, RETURN_TYPE>   rec
056        )
057    {
058        rec.ja = ja;
059
060        final int SIZE = ja.size();
061
062        JsonValue jv;
063
064
065        // If 'RETURN_TYPE' is a Stream, this builds a new Stream, and saves it to the
066        // internally-used "EffectivelyFinal" instance.  It's quite simple, actually.
067        //
068        // If 'RETURN_TYPE' is a Consumer, this is a simple "No-Op"
069
070        rec.constructNewBuilder.run();
071
072        for (int i=0; i < SIZE; i++)
073
074            switch ((jv = ja.get(i)).getValueType())
075            {
076                // javax.json.JsonValue.ValueType.NULL
077                case NULL: rec.handlerNull.accept(i); break;
078
079                // javax.json.JsonValue.ValueType.NUMBER
080                case NUMBER: rec.handlerNumber.accept((JsonNumber) jv, i); break;
081
082                // javax.json.JsonValue.ValueType.STRING
083                case STRING: rec.handlerJsonString.accept((JsonString) jv, i); break;
084
085                // OBJECT, ARRAY, TRUE, FALSE
086                default:
087
088                    if (rec.handlerWrongType != null)
089                        rec.handlerWrongType.accept(i);
090                    else
091                        throw new JsonTypeArrException(ja, i, NUMBER, jv, rec.CLASS);
092            }
093
094        // Run Stream.Builder.build()
095        return rec.runBuilderDotBuild.get();
096    }
097
098    /**
099     * Any and all Json-Array Processors that are intended to read an array of Json-Boolean Values
100     * will invoke this method to do their Type-Conversions.
101     * 
102     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_BL_RETURN_TYPE>
103     * 
104     * @param ja This should be any instance of {@link JsonArray}.  It is expected that if this
105     * array does not contain explicit Json-Boolean values, that is should at least contain values
106     * that are to converted or properly parsed into Java-Booleans.
107     * 
108     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
109     * 
110     * @return An instance of {@code Stream<Boolean>}.  If the provided instance of 
111     * {@code SettingsRec} has been constructed for a {@code Consumer}, then this method will  
112     * return null.
113     */
114    public static <RETURN_TYPE> RETURN_TYPE booleanToJava(
115            final JsonArray                         ja,
116            final SettingsRec<Boolean, RETURN_TYPE> rec
117        )
118    {
119        final int SIZE = ja.size();
120
121        JsonValue jv = null;
122
123        rec.ja = ja;
124
125        // If 'RETURN_TYPE' is a Consumer, this is a simple "No-Op"
126        rec.constructNewBuilder.run();
127
128        for (int i=0; i < SIZE; i++)
129
130            switch ((jv = ja.get(i)).getValueType())
131            {
132                // javax.json.JsonValue.ValueType.NULL, TRUE, FALSE & STRING
133                case NULL:      rec.handlerNull.accept(i); break;
134                case TRUE:      rec.ACCEPTOR.accept(true, i); break;
135                case FALSE:     rec.ACCEPTOR.accept(false, i); break;
136                case STRING:    rec.handlerJsonString.accept((JsonString) jv, i); break;
137
138                // javax.json.JsonValue.ValueType.NUMBER, OBJECT, ARRAY
139                default:
140                    if (rec.handlerWrongType != null) rec.handlerWrongType.accept(i);
141                    else throw new JsonTypeArrException(ja, i, TRUE, jv, Boolean.class);
142            }
143
144
145        // Run Stream.Builder.build() - IF NEEDED
146        // 'get()' simply returns null if the SettingsRec<T, U> had a "consumer"
147        // for it's 'U' Type, rather than a Stream.
148
149        return rec.runBuilderDotBuild.get();
150    }
151
152    /**
153     * Used to convert {@code JsonObject}'s into Java-Objects
154     * 
155     * @param <T> The Class / Type of the Objects to be extracted from the {@link JsonArray}
156     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_T_RETURN_TYPE>
157     * 
158     * @param ja This should be any instance of {@link JsonArray}.  It is expected that this array
159     * contain explicit {@link JsonObject} values, that can be converted in.to {@code 'T'}
160     * 
161     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
162     * 
163     * @return An instance of the type specified by Type-Parameter {@code 'RETURN_TYPE'}.
164     */
165    public static <T, RETURN_TYPE> RETURN_TYPE objToJava(
166            final JsonArray                     ja,
167            final SettingsRec<T, RETURN_TYPE>   rec
168        )
169    {
170        final int SIZE = ja.size();
171
172        JsonValue jv = null;
173
174        rec.ja = ja;
175
176
177        // For Stream<T>, this builds a new Stream.Builder
178        // for Consumer<T>, this is a "No-Op"
179
180        rec.constructNewBuilder.run();
181
182        for (int i=0; i < SIZE; i++)
183
184            switch ((jv = ja.get(i)).getValueType())
185            {
186                // javax.json.JsonValue.ValueType.NULL
187                case NULL:
188                    rec.handlerNull.accept(i);
189                    break;
190
191                // javax.json.JsonValue.ValueType.OBJECT
192                case OBJECT:
193                    T obj = rec.builder1Or2
194                        ? rec.objBuilder.apply((JsonObject) jv)
195                        : rec.objBuilder2.apply(i, (JsonObject) jv);
196
197                    rec.ACCEPTOR.accept(obj, i);
198                    break;
199
200                // javax.json.JsonValue.ValueType.NUMBER, STRING, TRUE, FALSE, ARRAY
201                default:
202                    if (rec.handlerWrongType != null) rec.handlerWrongType.accept(i);
203                    else throw new JsonTypeArrException(ja, i, TRUE, jv, rec.CLASS);
204            }
205
206
207        // For Stream<T>, this runs Stream.Builder.build()
208        // For Consumer<T>, this automatically returns null
209
210        return rec.runBuilderDotBuild.get();
211    }
212
213    /**
214     * Any and all Json-Array Processors that are intended to read an array of {@link JsonString}
215     * Values will invoke this method to do their Type-Conversions.
216     * 
217     * @param <RETURN_TYPE> <EMBED CLASS='external-html' DATA-FILE-ID=PJA_STR_RETURN_TYPE>
218     * 
219     * @param ja This should be any instance of {@link JsonArray}.
220     * 
221     * @param rec <EMBED CLASS='external-html' DATA-FILE-ID=PJA_REC_PARAM>
222     * 
223     * @return An instance of {@code Stream<String>}.  If the provided instance of
224     * {@code SettingsRec} has been constructed for a {@code Consumer}, then this method will
225     * return null.
226     */
227    public static <RETURN_TYPE> RETURN_TYPE strToJava(
228            final JsonArray                         ja,
229            final SettingsRec<String, RETURN_TYPE>  rec
230        )
231    {
232        final int SIZE = ja.size();
233
234        JsonValue jv = null;
235
236        rec.ja = ja;
237
238        if (rec.constructNewBuilder != null) rec.constructNewBuilder.run();
239
240        for (int i=0; i < SIZE; i++)
241
242            switch ((jv = ja.get(i)).getValueType())
243            {
244                // javax.json.JsonValue.ValueType.NULL
245                case NULL:
246                    rec.handlerNull.accept(i);
247                    break;
248
249                // javax.json.JsonValue.ValueType.STRING
250                case STRING:
251                    rec.ACCEPTOR.accept(((JsonString) jv).getString(), i);
252                    break;
253
254                // OBJECT, ARRAY, TRUE, FALSE, NUMBER
255                default:
256                    rec.jsonStringWrongTypeHandler.accept(jv, i);
257            }
258
259
260        // Returns the Built-Stream, for Streams.
261        // Returns 'null' for Consumer's
262
263        return rec.runBuilderDotBuild.get();
264    }
265
266
267    // ********************************************************************************************
268    // ********************************************************************************************
269    // Synchronized Method Variants
270    // ********************************************************************************************
271    // ********************************************************************************************
272
273
274    /**
275     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
276     *                   Multi-Threaded Programming-Environment.
277     * <BR>Wraps: Method {@link #numericToJava(JsonArray, SettingsRec)}
278     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
279     * <BR>IMPORTANT: Synchronization <B><I>is only needed</I></B> when the {@code SettingsRec}
280     *                instance shall be "re-used" in other threads.
281     */
282    @IntoHTMLTable(background=BlueDither, title="Synchronized Variant of Method 'numericToJava'")
283    public static <NUMERIC_DATA_TYPE extends Number, RETURN_TYPE> RETURN_TYPE
284        numericToJavaSync(
285            final JsonArray                                     ja,
286            final SettingsRec<NUMERIC_DATA_TYPE, RETURN_TYPE>   rec
287        )
288    { synchronized (rec) { return numericToJava(ja, rec); } }
289
290    /**
291     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
292     *                   Multi-Threaded Programming-Environment.
293     * <BR>Wraps: Method {@link #booleanToJava(JsonArray, SettingsRec)}
294     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
295     * <BR>IMPORTANT: Synchronizations <B><I>is only needed</I></B> when the {@code SettingsRec}
296     *                instance shall be "re-used" in other threads.
297     */
298    @IntoHTMLTable(background=GreenDither, title="Synchronized Variant of Method 'booleanToJava'")
299    public static <RETURN_TYPE> RETURN_TYPE booleanToJavaSync(
300            final JsonArray                         ja,
301            final SettingsRec<Boolean, RETURN_TYPE> rec
302        )
303    { synchronized (rec) { return booleanToJava(ja, rec); } }
304
305    /**
306     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
307     *                     Multi-Threaded Programming-Environment.
308     * <BR>Wraps: Method {@link #objToJava(JsonArray, SettingsRec)}
309     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
310     * <BR>IMPORTANT: Synchronizations <B><I>is only needed</I></B> when the {@code SettingsRec}
311     *                instance shall be "re-used" in other threads.
312     */
313    @IntoHTMLTable(background=BlueDither, title="Synchronized Variant of Method 'objToJava'")
314    public static <T, RETURN_TYPE> RETURN_TYPE objToJavaSync(
315            final JsonArray                     ja,
316            final SettingsRec<T, RETURN_TYPE>   rec
317        )
318    { synchronized (rec) { return objToJava(ja, rec); } }
319
320    /**
321     * <BR>Synchronized: Nothing More than a "Synchronized Wrapper" which can be used in a
322     *                     Multi-Threaded Programming-Environment.
323     * <BR>Wraps: Method {@link #strToJava(JsonArray, SettingsRec)}
324     * <BR>Locking-Object: Input-Parameter {@code 'rec'}, the {@code SettingsRec} instance 
325     * <BR>IMPORTANT: Synchronizations <B><I>is only needed</I></B> when the {@code SettingsRec}
326     *                instance shall be "re-used" in other threads.
327     */
328    @IntoHTMLTable(background=GreenDither, title="Synchronized Variant of Method 'strToJava'")
329    public static <RETURN_TYPE> RETURN_TYPE strToJavaSync(
330        final JsonArray                         ja,
331        final SettingsRec<String, RETURN_TYPE>  rec
332    )
333    { synchronized (rec) { return strToJava(ja, rec); } }
334
335}