Reader.java
001 /*
002  * Java Genetic Algorithm Library (jenetics-6.3.0).
003  * Copyright (c) 2007-2021 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
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,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.xml.stream;
021 
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024 import static javax.xml.stream.XMLStreamConstants.CDATA;
025 import static javax.xml.stream.XMLStreamConstants.CHARACTERS;
026 import static javax.xml.stream.XMLStreamConstants.END_ELEMENT;
027 import static javax.xml.stream.XMLStreamConstants.START_ELEMENT;
028 
029 import java.util.ArrayList;
030 import java.util.Collections;
031 import java.util.HashMap;
032 import java.util.List;
033 import java.util.Map;
034 import java.util.Objects;
035 import java.util.function.Function;
036 import java.util.stream.Collectors;
037 import java.util.stream.IntStream;
038 import java.util.stream.Stream;
039 
040 import javax.xml.stream.XMLStreamException;
041 import javax.xml.stream.XMLStreamReader;
042 
043 import io.jenetics.xml.stream.Reader.Type;
044 
045 /**
046  * XML reader class, used for reading objects in XML format.
047  *
048  <b>XML</b>
049  <pre> {@code
050  <int-chromosome length="3">
051  *     <min>-2147483648</min>
052  *     <max>2147483647</max>
053  *     <alleles>
054  *         <allele>-1878762439</allele>
055  *         <allele>-957346595</allele>
056  *         <allele>-88668137</allele>
057  *     </alleles>
058  </int-chromosome>
059  * }</pre>
060  *
061  <b>Reader definition</b>
062  <pre>{@code
063  * final Reader<IntegerChromosome> reader =
064  *     elem(
065  *         (Object[] v) -> {
066  *             final int length = (int)v[0];
067  *             final int min = (int)v[1];
068  *             final int max = (int)v[2];
069  *             final List<Integer> alleles = (List<Integer>)v[3];
070  *             assert alleles.size() == length;
071  *
072  *             return IntegerChromosome.of(
073  *                 alleles.stream()
074  *                     .map(value -> IntegerGene.of(value, min, max)
075  *                     .toArray(IntegerGene[]::new)
076  *             );
077  *         },
078  *         "int-chromosome",
079  *         attr("length").map(Integer::parseInt),
080  *         elem("min", text().map(Integer::parseInt)),
081  *         elem("max", text().map(Integer::parseInt)),
082  *         elem("alleles",
083  *             elems(elem("allele", text().map(Integer::parseInt)))
084  *         )
085  *     );
086  * }</pre>
087  *
088  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
089  @version 3.9
090  @since 3.9
091  */
092 public abstract class Reader<T> {
093 
094     /**
095      * Represents the XML element type.
096      */
097     enum Type {
098 
099         /**
100          * Denotes a element reader.
101          */
102         ELEM,
103 
104         /**
105          * Denotes a element attribute reader.
106          */
107         ATTR,
108 
109         /**
110          * Denotes a reader of elements of the same type.
111          */
112         LIST,
113 
114         /**
115          * Denotes a reader of the text of a element.
116          */
117         TEXT
118 
119     }
120 
121     private final String _name;
122     private final Type _type;
123 
124     /**
125      * Create a new XML reader with the given name and type.
126      *
127      @param name the element name of the reader
128      @param type the element type of the reader
129      @throws NullPointerException if one of the give arguments is {@code null}
130      */
131     Reader(final String name, final Type type) {
132         _name = requireNonNull(name);
133         _type = requireNonNull(type);
134     }
135 
136     /**
137      * Read the given type from the underlying XML stream {@code reader}.
138      *
139      <pre>{@code
140      * try (AutoCloseableXMLStreamReader xml = XML.reader(in)) {
141      *     // Move XML stream to first element.
142      *     xml.next();
143      *     return reader.read(xml);
144      * }
145      * }</pre>
146      *
147      @param xml the underlying XML stream {@code reader}
148      @return the data read from the XML stream, maybe {@code null}
149      @throws XMLStreamException if an error occurs while reading the value
150      @throws NullPointerException if the given {@code xml} stream reader is
151      *         {@code null}
152      */
153     public abstract T read(final XMLStreamReader xmlthrows XMLStreamException;
154 
155     /**
156      * Create a new reader for the new mapped type {@code B}.
157      *
158      @param mapper the mapper function
159      @param <B> the target type of the new reader
160      @return a new reader
161      @throws NullPointerException if the given {@code mapper} function is
162      *         {@code null}
163      */
164     public <B> Reader<B> map(final Function<? super T, ? extends B> mapper) {
165         requireNonNull(mapper);
166 
167         return new Reader<>(_name, _type) {
168             @Override
169             public B read(final XMLStreamReader xml)
170                 throws XMLStreamException {
171                 try {
172                     return mapper.apply(Reader.this.read(xml));
173                 catch (RuntimeException e) {
174                     throw new XMLStreamException(e);
175                 }
176             }
177         };
178     }
179 
180     /**
181      * Return the name of the element processed by this reader.
182      *
183      @return the element name the reader is processing
184      */
185     String name() {
186         return _name;
187     }
188 
189     /**
190      * Return the element type of the reader.
191      *
192      @return the element type of the reader
193      */
194     Type type() {
195         return _type;
196     }
197 
198     @Override
199     public String toString() {
200         return format("Reader[%s, %s]", name(), type());
201     }
202 
203 
204     /* *************************************************************************
205      * Static reader factory methods.
206      * ************************************************************************/
207 
208     /**
209      * Return a {@code Reader} for reading an attribute of an element.
210      <p>
211      <b>XML</b>
212      <pre> {@code <element length="3"/>}</pre>
213      *
214      <b>Reader definition</b>
215      <pre>{@code
216      * final Reader<Integer> reader =
217      *     elem(
218      *         v -> (Integer)v[0],
219      *         "element",
220      *         attr("length").map(Integer::parseInt)
221      *     );
222      * }</pre>
223      *
224      @param name the attribute name
225      @return an attribute reader
226      @throws NullPointerException if the given {@code name} is {@code null}
227      */
228     public static Reader<String> attr(final String name) {
229         return new AttrReader(name);
230     }
231 
232     /**
233      * Return a {@code Reader} for reading the text of an element.
234      <p>
235      <b>XML</b>
236      <pre> {@code <element>1234<element>}</pre>
237      *
238      <b>Reader definition</b>
239      <pre>{@code
240      * final Reader<Integer> reader =
241      *     elem(
242      *         v -> (Integer)v[0],
243      *         "element",
244      *         text().map(Integer::parseInt)
245      *     );
246      * }</pre>
247      *
248      @return an element text reader
249      */
250     public static Reader<String> text() {
251         return new TextReader();
252     }
253 
254     /**
255      * Return a {@code Reader} for reading an object of type {@code T} from the
256      * XML element with the given {@code name}.
257      *
258      <p>
259      <b>XML</b>
260      <pre> {@code <property name="size">1234<property>}</pre>
261      *
262      <b>Reader definition</b>
263      <pre>{@code
264      * final Reader<Property> reader =
265      *     elem(
266      *         v -> {
267      *             final String name = (String)v[0];
268      *             final Integer value = (Integer)v[1];
269      *             return Property.of(name, value);
270      *         },
271      *         "property",
272      *         attr("name"),
273      *         text().map(Integer::parseInt)
274      *     );
275      * }</pre>
276      *
277      @param generator the generator function, which build the result object
278      *        from the given parameter array
279      @param name the name of the root (sub-tree) element
280      @param children the child element reader, which creates the values
281      *        forwarded to the {@code generator} function
282      @param <T> the reader result type
283      @return a node reader
284      @throws NullPointerException if one of the given arguments is {@code null}
285      @throws IllegalArgumentException if the given child readers contains more
286      *         than one <em>text</em> reader
287      */
288     public static <T> Reader<T> elem(
289         final Function<Object[], T> generator,
290         final String name,
291         final Reader<?>... children
292     ) {
293         requireNonNull(name);
294         requireNonNull(generator);
295         Stream.of(requireNonNull(children)).forEach(Objects::requireNonNull);
296 
297         return new ElemReader<>(name, generator, List.of(children), Type.ELEM);
298     }
299 
300     /**
301      * Return a {@code Reader} which reads the value from the child elements of
302      * the given parent element {@code name}.
303      <p>
304      <b>XML</b>
305      <pre> {@code <min><property name="size">1234<property></min>}</pre>
306      *
307      <b>Reader definition</b>
308      <pre>{@code
309      * final Reader<Property> reader =
310      *     elem("min",
311      *         elem(
312      *             v -> {
313      *                 final String name = (String)v[0];
314      *                 final Integer value = (Integer)v[1];
315      *                 return Property.of(name, value);
316      *             },
317      *             "property",
318      *             attr("name"),
319      *             text().map(Integer::parseInt)
320      *         )
321      *     );
322      * }</pre>
323      *
324      @param name the parent element name
325      @param reader the child elements reader
326      @param <T> the result type
327      @return a node reader
328      @throws NullPointerException if one of the given arguments is {@code null}
329      */
330     public static <T> Reader<T> elem(
331         final String name,
332         final Reader<? extends T> reader
333     ) {
334         requireNonNull(name);
335         requireNonNull(reader);
336 
337         return elem(
338             v -> {
339                 @SuppressWarnings("unchecked")
340                 T value = v.length > (T)v[0null;
341                 return value;
342             },
343             name,
344             reader
345         );
346     }
347 
348     /**
349      * Return a {@code Reader} which collects the elements, read by the given
350      * child {@code reader}, and returns it as list of these elements.
351      <p>
352      <b>XML</b>
353      <pre> {@code
354      <properties length="3">
355      *     <property>-1878762439</property>
356      *     <property>-957346595</property>
357      *     <property>-88668137</property>
358      </properties>
359      * }</pre>
360      *
361      <b>Reader definition</b>
362      <pre>{@code
363      * Reader<List<Integer>> reader =
364      *     elem(
365      *         v -> (List<Integer>)v[0],
366      *         "properties",
367      *         elems(elem("property", text().map(Integer::parseInt)))
368      *     );
369      * }</pre>
370      *
371      @param reader the child element reader
372      @param <T> the element type
373      @return a list reader
374      */
375     public static <T> Reader<List<T>> elems(final Reader<? extends T> reader) {
376         return new ListReader<>(reader);
377     }
378 }
379 
380 
381 /* *****************************************************************************
382  * XML reader implementations.
383  * ****************************************************************************/
384 
385 /**
386  * Reader implementation for reading the attribute of the current node.
387  *
388  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
389  @version 3.9
390  @since 3.9
391  */
392 final class AttrReader extends Reader<String> {
393 
394     AttrReader(final String name) {
395         super(name, Type.ATTR);
396     }
397 
398     @Override
399     public String read(final XMLStreamReader xmlthrows XMLStreamException {
400         xml.require(START_ELEMENT, null, null);
401         return xml.getAttributeValue(null, name());
402     }
403 
404 }
405 
406 /**
407  * Reader implementation for reading the text of the current node.
408  *
409  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
410  @version 3.9
411  @since 3.9
412  */
413 final class TextReader extends Reader<String> {
414 
415     TextReader() {
416         super("", Type.TEXT);
417     }
418 
419     @Override
420     public String read(final XMLStreamReader xmlthrows XMLStreamException {
421         final StringBuilder out = new StringBuilder();
422 
423         int type = xml.getEventType();
424         do {
425             out.append(xml.getText());
426         while (xml.hasNext() && (type = xml.next()) == CHARACTERS || type == CDATA);
427 
428 
429         return out.toString();
430     }
431 }
432 
433 /**
434  * Reader implementation for reading list of elements.
435  *
436  @param <T> the element type
437  *
438  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
439  @version 3.9
440  @since 3.9
441  */
442 final class ListReader<T> extends Reader<List<T>> {
443 
444     private final Reader<? extends T> _adoptee;
445 
446     ListReader(final Reader<? extends T> adoptee) {
447         super(adoptee.name(), Type.LIST);
448         _adoptee = adoptee;
449     }
450 
451     @Override
452     public List<T> read(final XMLStreamReader xmlthrows XMLStreamException {
453         xml.require(START_ELEMENT, null, name());
454         return Collections.singletonList(_adoptee.read(xml));
455     }
456 }
457 
458 /**
459  * The main XML element reader implementation.
460  *
461  @param <T> the reader data type
462  *
463  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
464  @version 3.9
465  @since 3.9
466  */
467 final class ElemReader<T> extends Reader<T> {
468 
469     // Given parameters.
470     private final Function<Object[], T> _creator;
471     private final List<Reader<?>> _children;
472 
473     // Derived parameters.
474     private final Map<String, Integer> _readerIndexMapping = new HashMap<>();
475     private final int[] _attrReaderIndexes;
476     private final int[] _textReaderIndex;
477 
478     ElemReader(
479         final String name,
480         final Function<Object[], T> creator,
481         final List<Reader<?>> children,
482         final Type type
483     ) {
484         super(name, type);
485 
486         _creator = requireNonNull(creator);
487         _children = requireNonNull(children);
488 
489         for (int i = 0; i < _children.size(); ++i) {
490             _readerIndexMapping.put(_children.get(i).name(), i);
491         }
492         _attrReaderIndexes = IntStream.range(0, _children.size())
493             .filter(i -> _children.get(i).type() == Type.ATTR)
494             .toArray();
495         _textReaderIndex = IntStream.range(0, _children.size())
496             .filter(i -> _children.get(i).type() == Type.TEXT)
497             .toArray();
498 
499         if (_textReaderIndex.length > 1) {
500             throw new IllegalArgumentException(
501                 "Found more than one TEXT reader."
502             );
503         }
504     }
505 
506     @Override
507     public T read(final XMLStreamReader xml)
508         throws XMLStreamException
509     {
510         xml.require(START_ELEMENT, null, name());
511 
512         final List<ReaderResult> results = _children.stream()
513             .map(ReaderResult::of)
514             .collect(Collectors.toList());
515 
516         final ReaderResult text = _textReaderIndex.length == 1
517             ? results.get(_textReaderIndex[0])
518             null;
519 
520         for (int i : _attrReaderIndexes) {
521             final ReaderResult result = results.get(i);
522             result.put(result.reader().read(xml));
523         }
524 
525         if (xml.hasNext()) {
526             xml.next();
527 
528             boolean hasNext = false;
529             do {
530                 switch (xml.getEventType()) {
531                     case START_ELEMENT:
532                         final ReaderResult result = results
533                             .get(_readerIndexMapping.get(xml.getLocalName()));
534 
535                         if (result != null) {
536                             result.put(result.reader().read(xml));
537                             if (xml.hasNext()) {
538                                 hasNext = true;
539                                 xml.next();
540                             else {
541                                 hasNext = false;
542                             }
543                         }
544 
545                         break;
546                     case CHARACTERS:
547                     case CDATA:
548                         if (text != null) {
549                             text.put(text.reader().read(xml));
550                         else {
551                             xml.next();
552                         }
553                         hasNext = true;
554 
555                         break;
556                     case END_ELEMENT:
557                         if (name().equals(xml.getLocalName())) {
558                             try {
559                                 return _creator.apply(
560                                     results.stream()
561                                         .map(ReaderResult::value)
562                                         .toArray()
563                                 );
564                             catch (RuntimeException e) {
565                                 throw new XMLStreamException(e);
566                             }
567                         }
568                 }
569 
570             while (hasNext);
571         }
572 
573         throw new XMLStreamException(format(
574             "Premature end of file while reading '%s'.", name()
575         ));
576     }
577 
578 }
579 
580 /**
581  * Helper interface for storing the XML reader (intermediate) results.
582  */
583 interface ReaderResult {
584 
585     /**
586      * Return the underlying XML reader, which reads the result.
587      *
588      @return return the underlying XML reader
589      */
590     Reader<?> reader();
591 
592     /**
593      * Put the given {@code value} to the reader result.
594      *
595      @param value the reader result
596      */
597     void put(final Object value);
598 
599     /**
600      * Return the current reader result value.
601      *
602      @return the current reader result value
603      */
604     Object value();
605 
606     /**
607      * Create a reader result for the given XML reader
608      *
609      @param reader the XML reader
610      @return a reader result for the given reader
611      */
612     static ReaderResult of(final Reader<?> reader) {
613         return reader.type() == Type.LIST
614             new ListResult(reader)
615             new ValueResult(reader);
616     }
617 
618 }
619 
620 /**
621  * Result object for values read from XML elements.
622  */
623 final class ValueResult implements ReaderResult {
624 
625     private final Reader<?> _reader;
626     private Object _value;
627 
628     ValueResult(final Reader<?> reader) {
629         _reader = reader;
630     }
631 
632     @Override
633     public void put(final Object value) {
634         _value = value;
635     }
636 
637     @Override
638     public Reader<?> reader() {
639         return _reader;
640     }
641 
642 
643     @Override
644     public Object value() {
645         return _value;
646     }
647 
648 }
649 
650 /**
651  * Result object for list values read from XML elements.
652  */
653 final class ListResult implements ReaderResult {
654 
655     private final Reader<?> _reader;
656     private final List<Object> _value = new ArrayList<>();
657 
658     ListResult(final Reader<?> reader) {
659         _reader = reader;
660     }
661 
662     @Override
663     public void put(final Object value) {
664         if (value instanceof List) {
665             _value.addAll((List<?>)value);
666         else {
667             _value.add(value);
668         }
669     }
670 
671     @Override
672     public Reader<?> reader() {
673         return _reader;
674     }
675 
676     @Override
677     public List<Object> value() {
678         return _value;
679     }
680 
681 }