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