/* * Java Genetic Algorithm Library (@__identifier__@). * Copyright (c) @__year__@ Franz Wilhelmstötter * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Author: * Franz Wilhelmstötter (franz.wilhelmstoetter@gmx.at) */ package org.jenetics.util; import static java.lang.String.format; import static java.util.Optional.ofNullable; import java.io.BufferedReader; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.io.UncheckedIOException; import java.net.URL; import java.util.Arrays; import java.util.Iterator; import java.util.Spliterator; import java.util.Spliterators; import java.util.stream.Collectors; import java.util.stream.LongStream; import java.util.stream.Stream; import java.util.stream.StreamSupport; import org.jenetics.internal.util.exception; /** * Helper class for reading test data from file. The file has the following * format: {@code $resource[$param1, $param2,...].dat}. * * @author <a href="mailto:franz.wilhelmstoetter@gmx.at">Franz Wilhelmstötter</a> */ public class TestData implements Iterable<String[]> { private final String _resource; private final String[] _parameters; private TestData(final String resource, final String... parameters) { _resource = resource; _parameters = parameters; } /** * Return the base resource name, without extension and parameters. * * @return the base resource name */ public String getResource() { return _resource; } /** * Return the full resource path, with parameters and extension. * * @return the full resource path */ public String getResourcePath() { final String param = _parameters.length == 0 ? "" : Arrays.stream(_parameters) .collect(Collectors.joining(",", "[", "]")); return _resource + param + ".dat"; } /** * Return the test data parameters. * * @return the test data parameters */ public String[] getParameters() { return _parameters; } @Override public Iterator<String[]> iterator() { return new DataIterator(getResourcePath()); } /** * Return a stream with the data lines. * * @return a stream with the data lines */ public Stream<String[]> stream() { final DataIterator iterator = new DataIterator(getResourcePath()); final Spliterator<String[]> spliterator = Spliterators .spliteratorUnknownSize(iterator, 0); return StreamSupport .stream(spliterator, false) .onClose(iterator::close); } public LongStream longStream() { return stream().mapToLong(line -> Long.parseLong(line[0])); } @Override public String toString() { return getResourcePath(); } /** * Create a new {@code TestData} object from the given base resource name * and parameters. * * @param resource the base resource name * @param parameters the test data parameters * @return a new test data object */ public static TestData of(final String resource, final String... parameters) { return new TestData(resource, parameters); } public static Stream<TestData> list(final String path) { return resources(path) .map(name -> of(parseResource(name), parseParameters(name))); } private static String parseResource(final String name) { final int end = name.indexOf('['); return name.substring(0, end); } private static String[] parseParameters(final String name) { final int start = name.indexOf('['); final int end = name.lastIndexOf(']'); return (start != -1 && end != -1) ? name.substring(start + 1, end).split(",") : new String[0]; } private static Stream<String> resources(final String path) { try { final String className = TestData.class.getName(); final String classPath = className.replace(".", "/") + ".class"; final URL url = TestData.class.getClassLoader().getResource(classPath); final String absoluteClassPath = new File(url.toURI()).getAbsolutePath(); final String basePath = absoluteClassPath.substring( 0, absoluteClassPath.length() - classPath.length() ); return ofNullable(new File(basePath, path).list()) .map(Arrays::stream) .map(lines -> lines .filter(line -> line.endsWith(".dat")) .map(line -> (path + "/" + line))) .orElse(Stream.empty()); } catch (Exception e) { throw new RuntimeException(e); } } public static int[] toInt(final String[] line) { return Arrays.stream(line).mapToInt(Integer::parseInt).toArray(); } public static int[] toInt(final double[] array) { final int[] result = new int[array.length]; for (int i = 0; i < result.length; ++i) { result[i] = (int)array[i]; } return result; } public static long[] toLong(final String[] line) { return Arrays.stream(line).mapToLong(Long::parseLong).toArray(); } public static double[] toDouble(final String[] line) { return Arrays.stream(line).mapToDouble(Double::parseDouble).toArray(); } /** * The closeable line iterator. */ private static final class DataIterator implements Iterator<String[]>, Closeable { private final Reader _reader; private String[] _data; DataIterator(final String resource) { _reader = new Reader(resource); _data = _reader.read(); } @Override public boolean hasNext() { return _data != null; } @Override public String[] next() { final String[] current = _data; _data = _reader.read(); if (_data == null) { close(); } return current; } @Override public void close() { _reader.close(); } } /** * The reader class used for reading the test data. */ private static final class Reader implements Closeable { private final BufferedReader _reader; Reader(final String resource) { _reader = ofNullable(Reader.class.getResourceAsStream(resource)) .map(InputStreamReader::new) .map(BufferedReader::new) .orElseThrow(() -> new IllegalArgumentException(format( "Resource '%s' not found.", resource ))); } String[] read() { try { String line = null; do { line = _reader.readLine(); } while (line != null && (line.trim().startsWith("#") || line.trim().isEmpty())); return line != null ? line.split(",") : null; } catch (IOException e) { exception.ignore(UncheckedIOException.class, this::close); throw new UncheckedIOException(e); } } @Override public void close() { try { _reader.close(); } catch (IOException e) { throw new UncheckedIOException(e); } } } }