This is an automated email from the ASF dual-hosted git repository. sgoeschl pushed a commit to branch FREEMARKER-135 in repository https://gitbox.apache.org/repos/asf/freemarker-generator.git
commit 272faacc739b2bdf7dbffad83adcb915f031bd65 Author: Siegfried Goeschl <[email protected]> AuthorDate: Sat Feb 29 16:28:41 2020 +0100 FREEMARKER-135 Support user-supplied names for datasources --- CHANGELOG.md | 4 +- .../generator/base/FreeMarkerConstants.java | 8 + .../activation/MimetypesFileTypeMapFactory.java | 42 +++++ .../generator/base/datasource/Datasource.java | 16 +- .../base/datasource/DatasourceFactory.java | 39 +++-- .../generator/base/datasource/Datasources.java | 36 +++- .../base/datasource/DatasourcesSupplier.java | 56 ++++-- .../freemarker/generator/base/uri/NamedUri.java | 93 ++++++++++ .../NamedUriFragmentParser.java} | 28 ++- .../generator/base/uri/NamedUriParser.java | 74 ++++++++ .../generator/base/util/CachingSupplier.java | 16 ++ .../generator/base/util/LocaleUtils.java | 1 + .../generator/base/util/StringUtils.java | 13 ++ .../freemarker/generator/base/util/Validate.java | 150 ++++++++++++++++ .../datasource/DatasourceFactoryTest.java | 8 +- .../generator/datasource/DatasourceTest.java | 14 +- .../generator/datasource/DatasourcesTest.java | 27 ++- .../generator/uri/NamedUriParserTest.java | 192 +++++++++++++++++++++ .../org/apache/freemarker/generator/cli/Main.java | 75 +++++--- .../freemarker/generator/cli/config/Settings.java | 26 +-- .../freemarker/generator/cli/config/Suppliers.java | 2 +- .../generator/cli/task/FreeMarkerTask.java | 3 +- .../freemarker/generator/cli/ExamplesTest.java | 4 +- .../freemarker/generator/cli/ManualTest.java | 3 +- .../freemarker/generator/cli/PicocliTest.java | 74 ++++++++ .../generator/cli/config/SettingsTest.java | 4 +- freemarker-generator-cli/templates/info.ftl | 19 +- .../generator/maven/JsonPropertiesProvider.java | 1 + .../tools/properties/PropertiesToolTest.java | 3 +- .../tools/snakeyaml/SnakeYamlToolTest.java | 4 +- .../generator/tools/xml/XmlToolTest.java | 4 +- 31 files changed, 937 insertions(+), 102 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f9a227d..4a91545 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. We try to a * [FREEMARKER-129] Migrate `freemarker-cli` into `freemarker-generator` project (see [https://github.com/sgoeschl/freemarker-cli](https://github.com/sgoeschl/freemarker-cli)) ### Changed +* [FREEMARKER-134] Rename `Document` to `Datasource * [FREEMARKER-129] Use `freemarker.configuration.setting` in `freemarker-cli.properties` to configure FreeMarker * [FREEMARKER-129] Provide a `toString()` metheod for all tools * [FREEMARKER-129] Use version "0.X.Y" to cater for API changes according to [Semantic Versioning](https://semver.org) @@ -24,4 +25,5 @@ All notable changes to this project will be documented in this file. We try to a [FREEMARKER-127]: https://issues.apache.org/jira/browse/FREEMARKER-127 [FREEMARKER-128]: https://issues.apache.org/jira/browse/FREEMARKER-128 -[FREEMARKER-129]: https://issues.apache.org/jira/browse/FREEMARKER-129 \ No newline at end of file +[FREEMARKER-129]: https://issues.apache.org/jira/browse/FREEMARKER-129 +[FREEMARKER-`134`]: https://issues.apache.org/jira/browse/FREEMARKER-134 \ No newline at end of file diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/FreeMarkerConstants.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/FreeMarkerConstants.java index 94508d1..bc6f47f 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/FreeMarkerConstants.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/FreeMarkerConstants.java @@ -26,6 +26,14 @@ public class FreeMarkerConstants { /* Default encoding for textual content */ public static final Charset DEFAULT_CHARSET = UTF_8; + /* Default group name for datasources */ + public static final String DEFAULT_GROUP = "default"; + + public enum GeneratorMode { + DATASOURCE, + TEMPLATE + } + public static class Configuration { private Configuration() { diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/MimetypesFileTypeMapFactory.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/MimetypesFileTypeMapFactory.java new file mode 100644 index 0000000..b75a422 --- /dev/null +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/MimetypesFileTypeMapFactory.java @@ -0,0 +1,42 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.freemarker.generator.base.activation; + +import javax.activation.MimetypesFileTypeMap; + +public class MimetypesFileTypeMapFactory { + + private static MimetypesFileTypeMap mimeTypes; + + public static synchronized MimetypesFileTypeMap create() { + if (mimeTypes == null) { + mimeTypes = new MimetypesFileTypeMap(); + mimeTypes.addMimeTypes("application/json json JSON"); + mimeTypes.addMimeTypes("application/octet-stream bin"); + mimeTypes.addMimeTypes("application/vnd.ms-excel xls XLS"); + mimeTypes.addMimeTypes("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx XLSX"); + mimeTypes.addMimeTypes("application/xml xml XML"); + mimeTypes.addMimeTypes("text/csv csv CSV"); + mimeTypes.addMimeTypes("text/plain txt TXT log LOG ini INI properties md MD"); + mimeTypes.addMimeTypes("text/yaml yml YML yaml YAML"); + mimeTypes.addMimeTypes("text/tab-separated-values tsv TSV"); + } + + return mimeTypes; + } +} \ No newline at end of file diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/Datasource.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/Datasource.java index 5de9cae..ed038b0 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/Datasource.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/Datasource.java @@ -36,6 +36,7 @@ import static java.nio.charset.Charset.forName; import static java.util.Objects.requireNonNull; import static org.apache.commons.io.IOUtils.lineIterator; import static org.apache.freemarker.generator.base.FreeMarkerConstants.DATASOURCE_UNKNOWN_LENGTH; +import static org.apache.freemarker.generator.base.util.StringUtils.emptyToNull; /** * Datasource which encapsulates data to be used for rendering @@ -47,6 +48,9 @@ public class Datasource implements Closeable { /** Human-readable name of the datasource */ private final String name; + /** Optional group of datasource */ + private final String group; + /** Charset for directly accessing text-based content */ private final Charset charset; @@ -59,8 +63,9 @@ public class Datasource implements Closeable { /** Collect all closables handed out to the caller to be closed when the datasource is closed itself */ private final CloseableReaper closables; - public Datasource(String name, DataSource dataSource, String location, Charset charset) { + public Datasource(String name, String group, DataSource dataSource, String location, Charset charset) { this.name = requireNonNull(name); + this.group = emptyToNull(group); this.dataSource = requireNonNull(dataSource); this.location = requireNonNull(location); this.charset = requireNonNull(charset); @@ -71,6 +76,10 @@ public class Datasource implements Closeable { return name; } + public String getGroup() { + return group; + } + public String getBaseName() { return FilenameUtils.getBaseName(name); } @@ -83,6 +92,10 @@ public class Datasource implements Closeable { return charset; } + public String getContentType() { + return dataSource.getContentType(); + } + public String getLocation() { return location; } @@ -213,6 +226,7 @@ public class Datasource implements Closeable { public String toString() { return "Datasource{" + "name='" + name + '\'' + + "group='" + group + '\'' + ", location=" + location + ", charset='" + charset + '\'' + '}'; diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DatasourceFactory.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DatasourceFactory.java index c54aa4e..8cf721e 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DatasourceFactory.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DatasourceFactory.java @@ -19,6 +19,7 @@ package org.apache.freemarker.generator.base.datasource; import org.apache.freemarker.generator.base.FreeMarkerConstants.Location; import org.apache.freemarker.generator.base.activation.ByteArrayDataSource; import org.apache.freemarker.generator.base.activation.InputStreamDataSource; +import org.apache.freemarker.generator.base.activation.MimetypesFileTypeMapFactory; import org.apache.freemarker.generator.base.activation.StringDataSource; import javax.activation.DataSource; @@ -30,6 +31,7 @@ import java.net.URL; import java.nio.charset.Charset; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_GROUP; /** * Creates a Datasource from various sources. @@ -40,37 +42,48 @@ public class DatasourceFactory { } public static Datasource create(URL url) { - final String location = url.getProtocol() + "://" + url.getHost(); + final String location = url.toString(); final URLDataSource dataSource = new URLDataSource(url); - return create(url.getHost(), dataSource, location, UTF_8); + return create(url.getHost(), DEFAULT_GROUP, dataSource, location, UTF_8); } - public static Datasource create(String name, String content) { + public static Datasource create(String name, String group, URL url, Charset charset) { + final String location = url.toString(); + final URLDataSource dataSource = new URLDataSource(url); + return create(name, group, dataSource, location, charset); + } + + public static Datasource create(String name, String group, String content) { final StringDataSource dataSource = new StringDataSource(name, content, UTF_8); - return create(name, dataSource, Location.STRING, UTF_8); + return create(name, group, dataSource, Location.STRING, UTF_8); } public static Datasource create(File file, Charset charset) { + return create(file.getName(), DEFAULT_GROUP, file, charset); + } + + public static Datasource create(String name, String group, File file, Charset charset) { final FileDataSource dataSource = new FileDataSource(file); - return create(file.getName(), dataSource, file.getAbsolutePath(), charset); + dataSource.setFileTypeMap(MimetypesFileTypeMapFactory.create()); + return create(name, group, dataSource, file.getAbsolutePath(), charset); } - public static Datasource create(String name, byte[] content) { + public static Datasource create(String name, String group, byte[] content) { final ByteArrayDataSource dataSource = new ByteArrayDataSource(name, content); - return create(name, dataSource, Location.BYTES, UTF_8); + return create(name, group, dataSource, Location.BYTES, UTF_8); } - public static Datasource create(String name, InputStream is, Charset charset) { + public static Datasource create(String name, String group, InputStream is, Charset charset) { final InputStreamDataSource dataSource = new InputStreamDataSource(name, is); - return create(name, dataSource, Location.INPUTSTREAM, charset); + return create(name, group, dataSource, Location.INPUTSTREAM, charset); } - public static Datasource create(String name, InputStream is, String location, Charset charset) { + public static Datasource create(String name, String group, InputStream is, String location, Charset charset) { final InputStreamDataSource dataSource = new InputStreamDataSource(name, is); - return create(name, dataSource, location, charset); + return create(name, group, dataSource, location, charset); } - public static Datasource create(String name, DataSource dataSource, String location, Charset charset) { - return new Datasource(name, dataSource, location, charset); + public static Datasource create(String name, String group, DataSource dataSource, String location, Charset charset) { + return new Datasource(name, group, dataSource, location, charset); } } diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/Datasources.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/Datasources.java index 51d2804..5c55c6b 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/Datasources.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/Datasources.java @@ -17,6 +17,7 @@ package org.apache.freemarker.generator.base.datasource; import org.apache.freemarker.generator.base.util.ClosableUtils; +import org.apache.freemarker.generator.base.util.StringUtils; import java.io.Closeable; import java.util.ArrayList; @@ -46,6 +47,21 @@ public class Datasources implements Closeable { public List<String> getNames() { return datasources.stream() .map(Datasource::getName) + .filter(StringUtils::isNotEmpty) + .collect(toList()); + } + + /** + * Get the groups of all datasources. + * + * @return datasource names + */ + public List<String> getGroups() { + return datasources.stream() + .map(Datasource::getGroup) + .filter(StringUtils::isNotEmpty) + .sorted() + .distinct() .collect(toList()); } @@ -69,14 +85,6 @@ public class Datasources implements Closeable { return datasources.get(index); } - public boolean add(Datasource datasource) { - return datasources.add(datasource); - } - - public Datasource remove(int index) { - return datasources.remove(index); - } - /** * Get exactly one datasource. If not exactly one datasource * is found an exception is thrown. @@ -110,6 +118,18 @@ public class Datasources implements Closeable { .collect(toList()); } + /** + * Find datasources based on their group and and globbing pattern. + * + * @param wildcard globbing pattern + * @return list of mathching datasources + */ + public List<Datasource> findByGroup(String wildcard) { + return datasources.stream() + .filter(d -> wildcardMatch(d.getGroup(), wildcard)) + .collect(toList()); + } + @Override public void close() { datasources.forEach(ClosableUtils::closeQuietly); diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DatasourcesSupplier.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DatasourcesSupplier.java index 3e5a686..8309939 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DatasourcesSupplier.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DatasourcesSupplier.java @@ -17,8 +17,11 @@ package org.apache.freemarker.generator.base.datasource; import org.apache.freemarker.generator.base.file.RecursiveFileSupplier; +import org.apache.freemarker.generator.base.uri.NamedUri; +import org.apache.freemarker.generator.base.uri.NamedUriParser; import java.net.MalformedURLException; +import java.net.URI; import java.net.URL; import java.nio.charset.Charset; import java.util.ArrayList; @@ -26,9 +29,11 @@ import java.util.Collection; import java.util.List; import java.util.function.Supplier; +import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Collections.singletonList; import static java.util.Objects.requireNonNull; import static java.util.stream.Collectors.toList; +import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_GROUP; /** * Create a list of <code>Datasource</code> based on a list of sources consisting of @@ -71,20 +76,34 @@ public class DatasourcesSupplier implements Supplier<List<Datasource>> { } private List<Datasource> get(String source) { - if (isHttpUrl(source)) { - return singletonList(resolveHttpUrl(source)); - } else { - return resolveFile(source, include, exclude, charset); + try { + if (isHttpUrl(source)) { + return singletonList(resolveHttpUrl(source)); + } else { + return resolveFile(source, include, exclude, charset); + } + } catch (RuntimeException e) { + throw new RuntimeException("Unable to create the datasource: " + source, e); } } - private static Datasource resolveHttpUrl(String url) { - return DatasourceFactory.create(toUrl(url)); + private static Datasource resolveHttpUrl(String source) { + final NamedUri namedUri = NamedUriParser.parse(source); + final URI uri = namedUri.getUri(); + final String name = getNameOrElse(namedUri, uri.toString()); + final String group = getGroupOrElse(namedUri, DEFAULT_GROUP); + final Charset currCharset = getCharsetOrElse(namedUri, UTF_8); + return DatasourceFactory.create(name, group, toUrl(uri), currCharset); } private static List<Datasource> resolveFile(String source, String include, String exclude, Charset charset) { - return fileResolver(source, include, exclude).get().stream() - .map(file -> DatasourceFactory.create(file, charset)) + final NamedUri namedUri = NamedUriParser.parse(source); + final String path = namedUri.getUri().getPath(); + final String name = getNameOrElse(namedUri, path); + final String group = getGroupOrElse(namedUri, DEFAULT_GROUP); + final Charset currCharset = getCharsetOrElse(namedUri, charset); + return fileResolver(path, include, exclude).get().stream() + .map(file -> DatasourceFactory.create(name, group, file, currCharset)) .collect(toList()); } @@ -93,14 +112,27 @@ public class DatasourcesSupplier implements Supplier<List<Datasource>> { } private static boolean isHttpUrl(String value) { - return value.startsWith("http://") || value.startsWith("https://"); + return value.contains("http://") || value.contains("https://"); } - private static URL toUrl(String value) { + private static URL toUrl(URI uri) { try { - return new URL(value); + return uri.toURL(); } catch (MalformedURLException e) { - throw new IllegalArgumentException(value, e); + throw new IllegalArgumentException(uri.toString(), e); } } + + private static Charset getCharsetOrElse(NamedUri namedUri, Charset def) { + return Charset.forName(namedUri.getParameters().getOrDefault("charset", def.name())); + } + + private static String getNameOrElse(NamedUri namedUri, String def) { + return namedUri.hasName() ? namedUri.getName() : def; + } + + private static String getGroupOrElse(NamedUri namedUri, String def) { + return namedUri.hasGroup() ? namedUri.getGroup() : def; + } + } diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUri.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUri.java new file mode 100644 index 0000000..0b1211d --- /dev/null +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUri.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.freemarker.generator.base.uri; + +import java.net.URI; +import java.util.Map; + +import static java.util.Objects.requireNonNull; +import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty; + +/** + * Caputeres the information of a user-supplied "named URI". + */ +public class NamedUri { + + /** User-supplied name */ + private final String name; + + /** User-supplied group */ + private final String group; + + /** The URI */ + private final URI uri; + + /** Name/value pairs parsed from URI fragment */ + private final Map<String, String> parameters; + + public NamedUri(URI uri, Map<String, String> parameters) { + this.name = null; + this.group = null; + this.uri = requireNonNull(uri); + this.parameters = requireNonNull(parameters); + } + + public NamedUri(String name, String group, URI uri, Map<String, String> parameters) { + this.name = emptyToNull(name); + this.group = emptyToNull(group); + this.uri = requireNonNull(uri); + this.parameters = requireNonNull(parameters); + } + + public String getName() { + return name; + } + + public String getGroup() { + return group; + } + + public URI getUri() { + return uri; + } + + public Map<String, String> getParameters() { + return parameters; + } + + public boolean hasName() { + return !isEmpty(this.name); + } + + public boolean hasGroup() { + return !isEmpty(this.group); + } + + @Override + public String toString() { + return "NamedUri{" + + "name='" + name + '\'' + + ", group='" + group + '\'' + + ", uri=" + uri + + ", parameters=" + parameters + + '}'; + } + + private static String emptyToNull(String value) { + return value != null && value.trim().isEmpty() ? null : value; + } +} diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/LocaleUtils.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUriFragmentParser.java similarity index 52% copy from freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/LocaleUtils.java copy to freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUriFragmentParser.java index 5edd405..304a233 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/LocaleUtils.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUriFragmentParser.java @@ -14,20 +14,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.apache.freemarker.generator.base.util; +package org.apache.freemarker.generator.base.uri; -import java.util.Locale; +import java.util.Arrays; +import java.util.Map; +import static java.util.Collections.emptyMap; +import static java.util.stream.Collectors.toMap; import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty; -public class LocaleUtils { +/** + * Parses the URI fragment as list of name/value pairs seperated by an ampersand. + */ +public class NamedUriFragmentParser { - public static Locale parseLocale(String value) { - if (isEmpty(value) || value.equalsIgnoreCase("JVM default") || value.equalsIgnoreCase("default")) { - return Locale.getDefault(); + public static Map<String, String> parse(String fragment) { + if (isEmpty(fragment)) { + return emptyMap(); } - final String[] parts = value.split("_"); - return parts.length == 1 ? new Locale(parts[0]) : new Locale(parts[0], parts[1]); + try { + final String[] nameValuePairs = fragment.split("&"); + return Arrays.stream(nameValuePairs) + .map(s -> s.split("=")) + .collect(toMap(parts -> parts[0], parts -> parts[1])); + } catch (RuntimeException e) { + throw new RuntimeException("Unable to parse URI fragment: " + fragment, e); + } } } diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUriParser.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUriParser.java new file mode 100644 index 0000000..a5ab42b --- /dev/null +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/uri/NamedUriParser.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.freemarker.generator.base.uri; + +import org.apache.freemarker.generator.base.util.Validate; + +import java.net.URI; +import java.net.URISyntaxException; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static java.util.regex.Pattern.compile; + +/** + * Parses a named URI provided by the caller. + * <ul> + * <li>users.csv</li> + * <li>file:///users.csv</li> + * <li>users=file:///users.csv</li> + * <li>users:admin=file:///users.csv</li> + * <li>users=file:///users.csv#charset=UTF-16&mimetype=text/csv</li> + * </ul> + */ +public class NamedUriParser { + + private static final String NAME = "name"; + private static final String GROUP = "group"; + private static final String URI = "uri"; + + private static final Pattern NAMED_URI_REGEXP = compile("^(?<name>[a-zA-Z0-9-_]*):?(?<group>[a-zA-Z0-9-_]*)=(?<uri>.*)"); + + public static NamedUri parse(String value) { + Validate.notEmpty(value, "Named URI is empty"); + + final Matcher matcher = NAMED_URI_REGEXP.matcher(value); + + if (matcher.matches()) { + final String name = matcher.group(NAME); + final String group = matcher.group(GROUP); + final URI uri = uri(matcher.group(URI)); + return new NamedUri(name, group, uri, parameters(uri)); + } else { + final URI uri = uri(value); + return new NamedUri(uri, parameters(uri)); + } + } + + private static URI uri(String value) { + try { + return new URI(value); + } catch (URISyntaxException e) { + throw new RuntimeException("Failed to parse URI: " + value, e); + } + } + + private static Map<String, String> parameters(URI uri) { + return NamedUriFragmentParser.parse(uri.getFragment()); + } +} diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/CachingSupplier.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/CachingSupplier.java index fbada67..dab4334 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/CachingSupplier.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/CachingSupplier.java @@ -1,3 +1,19 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ package org.apache.freemarker.generator.base.util; import java.util.function.Supplier; diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/LocaleUtils.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/LocaleUtils.java index 5edd405..95f6a7f 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/LocaleUtils.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/LocaleUtils.java @@ -23,6 +23,7 @@ import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty; public class LocaleUtils { public static Locale parseLocale(String value) { + // "JVM default" is a special value defined by FreeMarker if (isEmpty(value) || value.equalsIgnoreCase("JVM default") || value.equalsIgnoreCase("default")) { return Locale.getDefault(); } diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/StringUtils.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/StringUtils.java index 769fd06..4dd8184 100644 --- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/StringUtils.java +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/StringUtils.java @@ -21,4 +21,17 @@ public class StringUtils { public static boolean isEmpty(String value) { return value == null || value.trim().isEmpty(); } + + public static boolean isNotEmpty(String value) { + return !isEmpty(value); + } + + public static String emptyToNull(String value) { + return value != null && value.trim().isEmpty() ? null : value; + } + + public static String nullToEmpty(String value) { + return value == null ? "" : value; + } + } diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java new file mode 100644 index 0000000..71bd28a --- /dev/null +++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/Validate.java @@ -0,0 +1,150 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.freemarker.generator.base.util; + +/** + * Simple validation methods designed for interal use. + */ +public final class Validate { + + private Validate() { + } + + /** + * Validates that the object is not null + * + * @param obj object to test + */ + public static void notNull(Object obj) { + if (obj == null) { + throw new IllegalArgumentException("Object must not be null"); + } + } + + /** + * Validates that the object is not null + * + * @param obj object to test + * @param msg message to output if validation fails + */ + public static void notNull(Object obj, String msg) { + if (obj == null) { + throw new IllegalArgumentException(msg); + } + } + + /** + * Validates that the value is true + * + * @param val object to test + */ + public static void isTrue(boolean val) { + if (!val) { + throw new IllegalArgumentException("Must be true"); + } + } + + /** + * Validates that the value is true + * + * @param val object to test + * @param msg message to output if validation fails + */ + public static void isTrue(boolean val, String msg) { + if (!val) { + throw new IllegalArgumentException(msg); + } + } + + /** + * Validates that the value is false + * + * @param val object to test + */ + public static void isFalse(boolean val) { + if (val) { + throw new IllegalArgumentException("Must be false"); + } + } + + /** + * Validates that the value is false + * + * @param val object to test + * @param msg message to output if validation fails + */ + public static void isFalse(boolean val, String msg) { + if (val) { + throw new IllegalArgumentException(msg); + } + } + + /** + * Validates that the array contains no null elements + * + * @param objects the array to test + */ + public static void noNullElements(Object[] objects) { + noNullElements(objects, "Array must not contain any null objects"); + } + + /** + * Validates that the array contains no null elements + * + * @param objects the array to test + * @param msg message to output if validation fails + */ + public static void noNullElements(Object[] objects, String msg) { + for (Object obj : objects) { + if (obj == null) { + throw new IllegalArgumentException(msg); + } + } + } + + /** + * Validates that the string is not empty + * + * @param string the string to test + */ + public static void notEmpty(String string) { + if (string == null || string.trim().isEmpty()) { + throw new IllegalArgumentException("String must not be empty"); + } + } + + /** + * Validates that the string is not empty + * + * @param string the string to test + * @param msg message to output if validation fails + */ + public static void notEmpty(String string, String msg) { + if (string == null || string.trim().isEmpty()) { + throw new IllegalArgumentException(msg); + } + } + + /** + * Cause a failure. + * + * @param msg message to output. + */ + public static void fail(String msg) { + throw new IllegalArgumentException(msg); + } +} diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourceFactoryTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourceFactoryTest.java index 677f991..c3bb493 100644 --- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourceFactoryTest.java +++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourceFactoryTest.java @@ -49,9 +49,10 @@ public class DatasourceFactoryTest { @Test public void shouldCreateStringBasedDatasource() throws IOException { - final Datasource datasource = DatasourceFactory.create("test.txt", ANY_TEXT); + final Datasource datasource = DatasourceFactory.create("test.txt", "default", ANY_TEXT); assertEquals("test.txt", datasource.getName()); + assertEquals("default", datasource.getGroup()); assertEquals(UTF_8, datasource.getCharset()); assertEquals("string", datasource.getLocation()); assertEquals(ANY_TEXT, datasource.getText()); @@ -60,9 +61,10 @@ public class DatasourceFactoryTest { @Test public void shouldCreateByteArrayBasedDatasource() throws IOException { - final Datasource datasource = DatasourceFactory.create("test.txt", ANY_TEXT.getBytes(UTF_8)); + final Datasource datasource = DatasourceFactory.create("test.txt", "default", ANY_TEXT.getBytes(UTF_8)); assertEquals("test.txt", datasource.getName()); + assertEquals("default", datasource.getGroup()); assertEquals(UTF_8, datasource.getCharset()); assertEquals("bytes", datasource.getLocation()); assertEquals(ANY_TEXT, datasource.getText()); @@ -72,7 +74,7 @@ public class DatasourceFactoryTest { @Test public void shouldCreateInputStreamBasedDatasource() throws IOException { final InputStream is = new ByteArrayInputStream(ANY_TEXT.getBytes(UTF_8)); - final Datasource datasource = DatasourceFactory.create("test.txt", is, UTF_8); + final Datasource datasource = DatasourceFactory.create("test.txt", "default", is, UTF_8); assertEquals("test.txt", datasource.getName()); assertEquals(UTF_8, datasource.getCharset()); diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourceTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourceTest.java index 878dd2c..a1b73cd 100644 --- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourceTest.java +++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourceTest.java @@ -30,12 +30,14 @@ import java.nio.charset.Charset; import java.util.Iterator; import static java.nio.charset.StandardCharsets.UTF_8; +import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_GROUP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class DatasourceTest { + private static final String ANY_GROUP = "group"; private static final String ANY_TEXT = "Hello World"; private static final String ANY_FILE_NAME = "pom.xml"; private static final Charset ANY_CHAR_SET = UTF_8; @@ -43,12 +45,14 @@ public class DatasourceTest { @Test public void shouldSupportTextDatasource() throws IOException { - try (Datasource datasource = DatasourceFactory.create("stdin", ANY_TEXT)) { + try (Datasource datasource = DatasourceFactory.create("stdin", ANY_GROUP, ANY_TEXT)) { assertEquals("stdin", datasource.getName()); + assertEquals(ANY_GROUP, datasource.getGroup()); assertEquals("stdin", datasource.getBaseName()); assertEquals("", datasource.getExtension()); assertEquals("string", datasource.getLocation()); assertEquals(UTF_8, datasource.getCharset()); + assertEquals("plain/text", datasource.getContentType()); assertTrue(datasource.getLength() > 0); assertEquals(ANY_TEXT, datasource.getText()); } @@ -58,23 +62,27 @@ public class DatasourceTest { public void shouldSupportFileDatasource() throws IOException { try (Datasource datasource = DatasourceFactory.create(ANY_FILE, ANY_CHAR_SET)) { assertEquals(ANY_FILE_NAME, datasource.getName()); + assertEquals(DEFAULT_GROUP, datasource.getGroup()); assertEquals("pom", datasource.getBaseName()); assertEquals("xml", datasource.getExtension()); assertEquals(ANY_FILE.getAbsolutePath(), datasource.getLocation()); assertEquals(Charset.defaultCharset(), datasource.getCharset()); + assertEquals("application/xml", datasource.getContentType()); assertTrue(datasource.getLength() > 0); assertFalse(datasource.getText().isEmpty()); } } - @Ignore + @Ignore("Requires internet conenection") @Test public void shouldSupportUrlDatasource() throws IOException { try (Datasource datasource = DatasourceFactory.create(new URL("https://google.com?foo=bar"))) { assertEquals("google.com", datasource.getName()); + assertEquals(DEFAULT_GROUP, datasource.getGroup()); assertEquals("google", datasource.getBaseName()); assertEquals("com", datasource.getExtension()); assertEquals("https://google.com", datasource.getLocation()); + assertEquals("text/html; charset=ISO-8859-1", datasource.getContentType()); assertEquals(UTF_8, datasource.getCharset()); assertEquals(-1, datasource.getLength()); assertFalse(datasource.getText().isEmpty()); @@ -127,7 +135,7 @@ public class DatasourceTest { } private static Datasource textDatasource() { - return DatasourceFactory.create("stdin", ANY_TEXT); + return DatasourceFactory.create("stdin", "default", ANY_TEXT); } private static final class TestClosable implements Closeable { diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourcesTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourcesTest.java index b580191..de78af5 100644 --- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourcesTest.java +++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/datasource/DatasourcesTest.java @@ -27,6 +27,8 @@ import java.net.URL; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Arrays.asList; +import static java.util.Collections.singletonList; +import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_GROUP; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -41,7 +43,7 @@ public class DatasourcesTest { private static final String ANY_URL = "https://server.invalid?foo=bar"; @Test - public void shouldFindByWildcard() { + public void shouldFindByName() { final Datasources datasources = datasources(); assertEquals(0, datasources.find(null).size()); @@ -63,6 +65,22 @@ public class DatasourcesTest { } @Test + public void shouldFindByGroup() { + final Datasources datasources = datasources(); + + assertEquals(0, datasources.findByGroup(null).size()); + assertEquals(0, datasources.findByGroup("").size()); + + assertEquals(0, datasources.findByGroup("unknown").size()); + + assertEquals(3, datasources.findByGroup("*").size()); + assertEquals(3, datasources.findByGroup("default").size()); + assertEquals(3, datasources.findByGroup("d*").size()); + assertEquals(3, datasources.findByGroup("d??????").size()); + + } + + @Test public void shouldGetDatasource() { assertNotNull(datasources().get(ANY_FILE_NAME)); } @@ -85,6 +103,11 @@ public class DatasourcesTest { assertEquals(asList("unknown", "pom.xml", "server.invalid"), datasources().getNames()); } + @Test + public void shouldGetGroups() { + assertEquals(singletonList(DEFAULT_GROUP), datasources().getGroups()); + } + @Test(expected = IllegalArgumentException.class) public void shouldThrowExceptionWhenGetDoesNotFindDatasource() { datasources().get("file-does-not-exist"); @@ -100,7 +123,7 @@ public class DatasourcesTest { } private static Datasource textDatasource() { - return DatasourceFactory.create(UNKNOWN, ANY_TEXT); + return DatasourceFactory.create(UNKNOWN, DEFAULT_GROUP, ANY_TEXT); } private static Datasource fileDatasource() { diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/uri/NamedUriParserTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/uri/NamedUriParserTest.java new file mode 100644 index 0000000..06718a0 --- /dev/null +++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/uri/NamedUriParserTest.java @@ -0,0 +1,192 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.freemarker.generator.uri; + +import org.apache.freemarker.generator.base.uri.NamedUri; +import org.apache.freemarker.generator.base.uri.NamedUriParser; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class NamedUriParserTest { + + @Test + public void shouldParseRelativeFileName() { + final NamedUri namedURI = parse("users.csv"); + + assertNull(namedURI.getName()); + assertNull(namedURI.getGroup()); + assertEquals("users.csv", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseAbsoluteFileName() { + final NamedUri namedURI = parse("/data/users.csv"); + + assertNull(namedURI.getName()); + assertNull(namedURI.getGroup()); + assertEquals("/data/users.csv", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseDirectoryName() { + final NamedUri namedURI = parse("users/"); + + assertNull(namedURI.getName()); + assertNull(namedURI.getGroup()); + assertEquals("users/", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseFileUri() { + final NamedUri namedURI = parse("file:///users.csv"); + + assertNull(namedURI.getName()); + assertNull(namedURI.getGroup()); + assertEquals("file:///users.csv", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseNamedFileUri() { + final NamedUri namedURI = parse("users=file:///users.csv"); + + assertEquals("users", namedURI.getName()); + assertNull(namedURI.getGroup()); + assertEquals("file:///users.csv", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseNamedGroupFileUri() { + final NamedUri namedURI = parse("users:admin=file:///some-admin-users.csv"); + + assertEquals("users", namedURI.getName()); + assertEquals("admin", namedURI.getGroup()); + assertEquals("file:///some-admin-users.csv", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseNamedWithEmptyGroupFileUri() { + final NamedUri namedURI = parse("users:=file:///some-admin-users.csv"); + + assertEquals("users", namedURI.getName()); + assertNull(namedURI.getGroup()); + assertEquals("file:///some-admin-users.csv", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseEmptyNamedWithGroupFileUri() { + final NamedUri namedURI = parse(":admin=file:///some-admin-users.csv"); + + assertNull(namedURI.getName()); + assertEquals("admin", namedURI.getGroup()); + assertEquals("file:///some-admin-users.csv", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseNamedFileUriWithFragment() { + final NamedUri namedURI = parse("users=file:///users.csv#charset=UTF-16&mimetype=text/csv"); + + assertEquals("users", namedURI.getName()); + assertNull(namedURI.getGroup()); + assertEquals("file:///users.csv#charset=UTF-16&mimetype=text/csv", namedURI.getUri().toString()); + assertEquals(2, namedURI.getParameters().size()); + assertEquals("UTF-16", namedURI.getParameters().get("charset")); + assertEquals("text/csv", namedURI.getParameters().get("mimetype")); + } + + @Test + public void shouldParseUrl() { + final NamedUri namedURI = parse("http://google.com"); + + assertNull(namedURI.getName()); + assertNull(namedURI.getGroup()); + assertEquals("http://google.com", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseUrlWithFragment() { + final NamedUri namedURI = parse("http://google.com#charset=UTF-16"); + + assertNull(namedURI.getName()); + assertEquals("http://google.com#charset=UTF-16", namedURI.getUri().toString()); + assertEquals(1, namedURI.getParameters().size()); + assertEquals("UTF-16", namedURI.getParameters().get("charset")); + } + + @Test + public void shouldParseNamedUrl() { + final NamedUri namedURI = parse("google=http://google.com"); + + assertEquals("google", namedURI.getName()); + assertEquals("http://google.com", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseNamedUrlWithQuery() { + final NamedUri namedURI = parse("google=http://google.com?foo=bar"); + + assertEquals("google", namedURI.getName()); + assertEquals("http://google.com?foo=bar", namedURI.getUri().toString()); + assertEquals(0, namedURI.getParameters().size()); + } + + @Test + public void shouldParseNamedUrlWithQueryAndFragment() { + final NamedUri namedURI = parse("google=http://google.com?foo=bar#charset=UTF-16"); + + assertEquals("google", namedURI.getName()); + assertEquals("http://google.com?foo=bar#charset=UTF-16", namedURI.getUri().toString()); + assertEquals(1, namedURI.getParameters().size()); + assertEquals("UTF-16", namedURI.getParameters().get("charset")); + } + + @Test + public void shouldParseNamedGroupUrlWithQueryAndFragment() { + final NamedUri namedURI = parse("google:web=http://google.com?foo=bar#charset=UTF-16"); + + assertEquals("google", namedURI.getName()); + assertEquals("web", namedURI.getGroup()); + assertEquals("http://google.com?foo=bar#charset=UTF-16", namedURI.getUri().toString()); + assertEquals(1, namedURI.getParameters().size()); + assertEquals("UTF-16", namedURI.getParameters().get("charset")); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowExceptionOnParsingNull() { + parse(null); + } + + @Test(expected = RuntimeException.class) + public void shouldThrowExceptionOnParsingEmptyString() { + parse(" "); + } + + private static NamedUri parse(String value) { + return NamedUriParser.parse(value); + } +} diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java index 82dbc6f..406c70e 100644 --- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java +++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/Main.java @@ -16,6 +16,7 @@ */ package org.apache.freemarker.generator.cli; +import org.apache.freemarker.generator.base.FreeMarkerConstants.GeneratorMode; import org.apache.freemarker.generator.base.util.ClosableUtils; import org.apache.freemarker.generator.base.util.StringUtils; import org.apache.freemarker.generator.cli.config.Settings; @@ -33,13 +34,16 @@ import java.io.FileWriter; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Writer; -import java.util.ArrayList; +import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Properties; import java.util.concurrent.Callable; +import java.util.stream.Collectors; import java.util.stream.IntStream; +import java.util.stream.Stream; import static java.util.Objects.requireNonNull; import static org.apache.freemarker.generator.cli.config.Suppliers.propertiesSupplier; @@ -51,9 +55,9 @@ public class Main implements Callable<Integer> { private static final String FREEMARKER_CLI_PROPERTY_FILE = "freemarker-cli.properties"; @ArgGroup(multiplicity = "1") - private TemplateSourceOptions templateSourceOptions; + TemplateSourceOptions templateSourceOptions; - private static final class TemplateSourceOptions { + static final class TemplateSourceOptions { @Option(names = { "-t", "--template" }, description = "FreeMarker template to render") private String template; @@ -62,52 +66,62 @@ public class Main implements Callable<Integer> { } @Option(names = { "-b", "--basedir" }, description = "Optional template base directory") - private String baseDir; + String baseDir; + + @Option(names = { "-d", "--datasource" }, description = "Datasource used for rendering") + List<String> datasources; @Option(names = { "-D", "--system-property" }, description = "Set system property") - private Properties systemProperties; + Properties systemProperties; @Option(names = { "-e", "--input-encoding" }, description = "Encoding of datasource", defaultValue = "UTF-8") - private String inputEncoding; + String inputEncoding; @Option(names = { "-E", "--expose-env" }, description = "Expose environment variables and user-supplied properties globally") - private boolean isEnvironmentExposed; + boolean isEnvironmentExposed; @Option(names = { "-l", "--locale" }, description = "Locale being used for the output, e.g. 'en_US'") - private String locale; + String locale; + + @Option(names = { "-m", "--mode" }, description = "[template|datasource]", defaultValue = "TEMPLATE") + GeneratorMode mode; @Option(names = { "-o", "--output" }, description = "Output file") - private String outputFile; + String outputFile; @Option(names = { "-P", "--param" }, description = "Set parameter") - private Map<String, String> parameters; + Map<String, String> parameters; @Option(names = { "--config" }, defaultValue = FREEMARKER_CLI_PROPERTY_FILE, description = "FreeMarker CLI configuration file") - private String configFile; + String configFile; @Option(names = { "--include" }, description = "File pattern for datasource input directory") - private String include; + String include; @Option(names = { "--exclude" }, description = "File pattern for datasource input directory") - private String exclude; + String exclude; @Option(names = { "--output-encoding" }, description = "Encoding of output, e.g. UTF-8", defaultValue = "UTF-8") - private String outputEncoding; + String outputEncoding; @Option(names = { "--stdin" }, description = "Read datasource from stdin") - private boolean readFromStdin; + boolean readFromStdin; @Option(names = { "--times" }, defaultValue = "1", description = "Re-run X times for profiling") - private int times; + int times; @Parameters(description = "List of input files and/or input directories") - private List<String> sources; + List<String> sources; /** User-supplied command line parameters */ - private final String[] args; + final String[] args; /** User-supplied writer (used mainly for unit testing) */ - private Writer userSuppliedWriter; + Writer userSuppliedWriter; + + Main() { + this.args = new String[0]; + } private Main(String[] args) { this.args = requireNonNull(args); @@ -178,7 +192,7 @@ public class Main implements Callable<Integer> { .setOutputEncoding(outputEncoding) .setOutputFile(outputFile) .setParameters(parameters != null ? parameters : new HashMap<>()) - .setSources(sources != null ? sources : new ArrayList<>()) + .setDatasources(getCombindedDatasources()) .setSystemProperties(systemProperties != null ? systemProperties : new Properties()) .setTemplateDirectories(templateDirectories) .setTemplateName(templateSourceOptions.template) @@ -206,6 +220,27 @@ public class Main implements Callable<Integer> { } } + /** + * Datasources can be passed via command line option and/or + * positional parameter so we need to merge them. + * + * @return List of datasources + */ + private List<String> getCombindedDatasources() { + if (isTemplateDrivenGeneration()) { + return Stream.of(datasources, sources) + .filter(Objects::nonNull) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + } else { + throw new IllegalArgumentException("Not implemented yet"); + } + } + + private boolean isTemplateDrivenGeneration() { + return mode == GeneratorMode.TEMPLATE; + } + private static List<File> getTemplateDirectories(String baseDir) { return templateDirectorySupplier(baseDir).get(); } diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Settings.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Settings.java index c1a63b3..5facf82 100644 --- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Settings.java +++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Settings.java @@ -52,7 +52,7 @@ public class Settings { /** List of FreeMarker template directories */ private final List<File> templateDirectories; - /** Name of the template to be loaded and rendered */ + /** Name of the template to be loaded and rendered */ private final String templateName; /** Template provided by the user interactivly */ @@ -86,7 +86,7 @@ public class Settings { private final boolean isEnvironmentExposed; /** User-supplied list of source files or directories */ - private final List<String> sources; + private final List<String> datasources; /** User-supplied parameters */ private final Map<String, String> parameters; @@ -112,7 +112,7 @@ public class Settings { Locale locale, boolean isReadFromStdin, boolean isEnvironmentExposed, - List<String> sources, + List<String> datasources, Map<String, String> parameters, Properties sytemProperties, Writer writer) { @@ -133,7 +133,7 @@ public class Settings { this.locale = requireNonNull(locale); this.isReadFromStdin = isReadFromStdin; this.isEnvironmentExposed = isEnvironmentExposed; - this.sources = requireNonNull(sources); + this.datasources = requireNonNull(datasources); this.parameters = requireNonNull(parameters); this.sytemProperties = requireNonNull(sytemProperties); this.configuration = requireNonNull(configuration); @@ -204,8 +204,8 @@ public class Settings { return isEnvironmentExposed; } - public List<String> getSources() { - return sources; + public List<String> getDatasources() { + return datasources; } public Map<String, String> getParameters() { @@ -262,7 +262,7 @@ public class Settings { ", locale=" + locale + ", isReadFromStdin=" + isReadFromStdin + ", isEnvironmentExposed=" + isEnvironmentExposed + - ", sources=" + sources + + ", datasources=" + datasources + ", properties=" + parameters + ", sytemProperties=" + sytemProperties + ", writer=" + writer + @@ -288,7 +288,7 @@ public class Settings { private String locale; private boolean isReadFromStdin; private boolean isEnvironmentExposed; - private List<String> sources; + private List<String> datasources; private Map<String, String> parameters; private Properties systemProperties; private Properties configuration; @@ -302,7 +302,7 @@ public class Settings { this.systemProperties = new Properties(); this.setInputEncoding(DEFAULT_CHARSET.name()); this.setOutputEncoding(DEFAULT_CHARSET.name()); - this.sources = emptyList(); + this.datasources = emptyList(); this.templateDirectories = emptyList(); } @@ -380,8 +380,8 @@ public class Settings { return this; } - public SettingsBuilder setSources(List<String> sources) { - this.sources = sources; + public SettingsBuilder setDatasources(List<String> datasources) { + this.datasources = datasources; return this; } @@ -393,7 +393,7 @@ public class Settings { } public SettingsBuilder setSystemProperties(Properties systemProperties) { - if(systemProperties != null) { + if (systemProperties != null) { this.systemProperties = systemProperties; } return this; @@ -432,7 +432,7 @@ public class Settings { LocaleUtils.parseLocale(currLocale), isReadFromStdin, isEnvironmentExposed, - sources, + datasources, parameters, systemProperties, writer diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java index 7d2f5f1..0a7a9f2 100644 --- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java +++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/Suppliers.java @@ -34,7 +34,7 @@ public class Suppliers { } public static DatasourcesSupplier datasourcesSupplier(Settings settings) { - return new DatasourcesSupplier(settings.getSources(), + return new DatasourcesSupplier(settings.getDatasources(), settings.getInclude(), settings.getExclude(), settings.getInputEncoding()); diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java index f537309..b59bb62 100644 --- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java +++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/task/FreeMarkerTask.java @@ -37,6 +37,7 @@ import java.util.function.Supplier; import static java.nio.charset.StandardCharsets.UTF_8; import static java.util.Objects.requireNonNull; +import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_GROUP; import static org.apache.freemarker.generator.base.FreeMarkerConstants.Location.STDIN; import static org.apache.freemarker.generator.base.FreeMarkerConstants.Model.DATASOURCES; import static org.apache.freemarker.generator.cli.config.Suppliers.configurationSupplier; @@ -89,7 +90,7 @@ public class FreeMarkerTask implements Callable<Integer> { // Add optional datasource from STDIN at the start of the list since // this allows easy sequence slicing in FreeMarker. if (settings.isReadFromStdin()) { - datasources.add(0, DatasourceFactory.create(STDIN, System.in, STDIN, UTF_8)); + datasources.add(0, DatasourceFactory.create(STDIN, DEFAULT_GROUP, System.in, STDIN, UTF_8)); } return new Datasources(datasources); diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java index e5fa6ac..97f7001 100644 --- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java +++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ExamplesTest.java @@ -26,7 +26,7 @@ import static org.junit.Assert.assertTrue; public class ExamplesTest extends AbstractMainTest { - private static final int MIN_OUTPUT_SIZE = 1; + private static final int MIN_OUTPUT_SIZE = 5; @Test public void shouldRunInfo() throws IOException { @@ -102,6 +102,7 @@ public class ExamplesTest extends AbstractMainTest { @Test public void shouldRunInteractiveTemplateExamples() throws IOException { + // @TODO We should check the generated output directly assertValid(execute("-i ${JsonPathTool.parse(Datasources.first).read(\"$.info.title\")} site/sample/json/swagger-spec.json")); assertValid(execute("-i ${XmlTool.parse(Datasources.first)[\"recipients/person[1]/name\"]} site/sample/xml/recipients.xml")); assertValid(execute("-i ${JsoupTool.parse(Datasources.first).select(\"a\")[0]} site/sample/html/dependencies.html")); @@ -129,5 +130,6 @@ public class ExamplesTest extends AbstractMainTest { private static void assertValid(String output) { assertTrue(output.length() > MIN_OUTPUT_SIZE); assertFalse(output.contains("Exception")); + assertFalse(output.contains("Error")); } } diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java index 35b1069..d693905 100644 --- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java +++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/ManualTest.java @@ -35,7 +35,8 @@ public class ManualTest { // private static final String CMD = "-i ${JsoupTool.parse(Datasources.first).select('a')[0]} site/sample/html/dependencies.html"; // private static final String CMD = "-b ./src/test -t templates/properties/csv/locker-test-users.ftl site/sample/properties"; // private static final String CMD = "-b ./src/test -e UTF-8 -l de_AT -Dcolumn=Order%20ID -Dvalues=226939189,957081544 -Dformat=DEFAULT -Ddelimiter=COMMA -t templates/csv/md/filter.ftl site/sample/csv/sales-records.csv"; - private static final String CMD = "-E -b ./src/test -t templates/environment.ftl"; + // private static final String CMD = "-E -b ./src/test -t templates/environment.ftl"; + private static final String CMD = "-b ./src/test -l de_AT -DFOO=foo -DBAR=bar -t templates/info.ftl -d user:admin=site/sample/csv/contract.csv#charset=UTF-16 google:www=https://www.google.com?foo=bar#contenttype=application/json"; public static void main(String[] args) { Main.execute(toArgs(CMD)); diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/PicocliTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/PicocliTest.java new file mode 100644 index 0000000..95662f0 --- /dev/null +++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/PicocliTest.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ +package org.apache.freemarker.generator.cli; + +import org.junit.Test; +import picocli.CommandLine; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +public class PicocliTest { + + private static final String TEMPLATE = "template.ftl"; + private static final String ANY_FILE = "users.csv"; + private static final String ANY_NAMED_FILE = "users=users.csv"; + private static final String OTHER_FILE = "transctions.csv"; + private static final String ANY_FILE_URI = "file:///users.csv"; + private static final String OTHER_FILE_URI = "file:///transctions.csv"; + + @Test + public void testSinglePositionalParameter() { + assertEquals(ANY_FILE_URI, parse("-t", TEMPLATE, ANY_FILE_URI).sources.get(0)); + assertNull(ANY_FILE, parse("-t", TEMPLATE, ANY_FILE_URI).datasources); + } + + @Test + public void testMultiplePositionalParameter() { + assertEquals(ANY_FILE, parse("-t", TEMPLATE, ANY_FILE, OTHER_FILE).sources.get(0)); + assertEquals(OTHER_FILE, parse("-t", TEMPLATE, ANY_FILE, OTHER_FILE).sources.get(1)); + + assertEquals(ANY_FILE, parse("-t", TEMPLATE, ANY_FILE, OTHER_FILE_URI).sources.get(0)); + assertEquals(OTHER_FILE_URI, parse("-t", TEMPLATE, ANY_FILE, OTHER_FILE_URI).sources.get(1)); + + assertEquals(ANY_FILE_URI, parse("-t", TEMPLATE, ANY_FILE_URI, OTHER_FILE_URI).sources.get(0)); + assertEquals(OTHER_FILE_URI, parse("-t", TEMPLATE, ANY_FILE_URI, OTHER_FILE_URI).sources.get(1)); + } + + @Test + public void testSingleNamedDatasource() { + assertEquals(ANY_FILE, parse("-t", TEMPLATE, ANY_FILE).sources.get(0)); + assertEquals(ANY_FILE, parse("-t", TEMPLATE, "-d", ANY_FILE).datasources.get(0)); + assertEquals(ANY_FILE, parse("-t", TEMPLATE, "--datasource", ANY_FILE).datasources.get(0)); + assertEquals(ANY_FILE_URI, parse("-t", TEMPLATE, "--datasource", ANY_FILE_URI).datasources.get(0)); + } + + @Test + public void testMultipleNamedDatasource() { + final Main main = parse("-t", TEMPLATE, "-d", ANY_FILE, "--datasource", OTHER_FILE_URI); + + assertEquals(ANY_FILE, main.datasources.get(0)); + assertEquals(OTHER_FILE_URI, main.datasources.get(1)); + assertNull(main.sources); + } + + private static Main parse(String... args) { + final Main main = new Main(); + new CommandLine(main).parseArgs(args); + return main; + } +} diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SettingsTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SettingsTest.java index 4821723..655fdf6 100644 --- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SettingsTest.java +++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SettingsTest.java @@ -56,7 +56,7 @@ public class SettingsTest { assertEquals(ANY_OUTPUT_ENCODING, settings.getOutputEncoding().name()); assertEquals(ANY_OUTPUT_FILE, settings.getOutputFile().getName()); assertEquals(ANY_TEMPLATE_NAME, settings.getTemplateName()); - assertNotNull(settings.getSources()); + assertNotNull(settings.getDatasources()); assertNotNull(settings.getParameters()); assertNotNull(settings.getSytemProperties()); assertTrue(settings.isReadFromStdin()); @@ -78,7 +78,7 @@ public class SettingsTest { .setOutputEncoding(ANY_OUTPUT_ENCODING) .setOutputFile(ANY_OUTPUT_FILE) .setParameters(ANY_USER_PARAMETERS) - .setSources(ANY_SOURCES) + .setDatasources(ANY_SOURCES) .setSystemProperties(ANY_SYSTEM_PROPERTIES) .setTemplateName(ANY_TEMPLATE_NAME) .setWriter(new StringWriter()) diff --git a/freemarker-generator-cli/templates/info.ftl b/freemarker-generator-cli/templates/info.ftl index 3ec4891..6b9380b 100644 --- a/freemarker-generator-cli/templates/info.ftl +++ b/freemarker-generator-cli/templates/info.ftl @@ -16,7 +16,7 @@ under the License. --> FreeMarker CLI Information ---------------------------------------------------------------------------- +------------------------------------------------------------------------------ FreeMarker version : ${.version} Template name : ${.current_template_name} Language : ${.lang} @@ -26,13 +26,13 @@ Output encoding : ${.output_encoding} Output format : ${.output_format} FreeMarker CLI Template Directories ---------------------------------------------------------------------------- +------------------------------------------------------------------------------ <#list SystemTool.getTemplateDirectories() as directory> -[${directory?counter}] ${directory} +[#${directory?counter}] ${directory} </#list> FreeMarker CLI Tools ---------------------------------------------------------------------------- +------------------------------------------------------------------------------ <#list .data_model?keys?sort as key> <#if key?ends_with("Tool")> - ${key?right_pad(20)} : ${.data_model[key]} @@ -40,25 +40,26 @@ FreeMarker CLI Tools </#list> FreeMarker CLI Datasources ---------------------------------------------------------------------------- +------------------------------------------------------------------------------ <#list Datasources.list as datasource> -[${datasource?counter}] ${datasource.name}, ${datasource.location}, ${datasource.length} Bytes +[#${datasource?counter}], name=${datasource.name}, group=${datasource.group}, charset=${datasource.charset}, length= ${datasource.length} Bytes +Location : ${datasource.location} </#list> User Supplied Parameters ---------------------------------------------------------------------------- +------------------------------------------------------------------------------ <#list SystemTool.parameters as name,value> - ${name} ==> ${value} </#list> User Supplied System Properties ---------------------------------------------------------------------------- +------------------------------------------------------------------------------ <#list SystemTool.userSystemProperties as name,value> - ${name} ==> ${value} </#list> SystemTool ---------------------------------------------------------------------------- +------------------------------------------------------------------------------ Command line : ${SystemTool.getCommandLineArgs()?join(", ")} Host Name : ${SystemTool.getHostName()} Java Home : ${SystemTool.getEnv("JAVA_HOME", "N.A.")} diff --git a/freemarker-generator-maven-plugin/src/main/java/org/apache/freemarker/generator/maven/JsonPropertiesProvider.java b/freemarker-generator-maven-plugin/src/main/java/org/apache/freemarker/generator/maven/JsonPropertiesProvider.java index f2e2cc4..1d16822 100644 --- a/freemarker-generator-maven-plugin/src/main/java/org/apache/freemarker/generator/maven/JsonPropertiesProvider.java +++ b/freemarker-generator-maven-plugin/src/main/java/org/apache/freemarker/generator/maven/JsonPropertiesProvider.java @@ -54,6 +54,7 @@ public class JsonPropertiesProvider implements OutputGeneratorPropertiesProvider } @Override + @SuppressWarnings("unchecked") public void providePropertiesFromFile(Path path, OutputGenerator.OutputGeneratorBuilder builder) { final File jsonDataFile = path.toFile(); final Map<String, Object> data = parseJson(jsonDataFile); diff --git a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/properties/PropertiesToolTest.java b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/properties/PropertiesToolTest.java index 3a29908..5a9fc79 100644 --- a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/properties/PropertiesToolTest.java +++ b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/properties/PropertiesToolTest.java @@ -24,6 +24,7 @@ import static junit.framework.TestCase.assertEquals; public class PropertiesToolTest { + private static final String ANY_GROUP = "group"; private static final String ANY_PROPERTIES_STRING = "foo=bar"; @Test @@ -43,6 +44,6 @@ public class PropertiesToolTest { } private Datasource datasource(String value) { - return DatasourceFactory.create("test.properties", value); + return DatasourceFactory.create("test.properties", ANY_GROUP, value); } } diff --git a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/snakeyaml/SnakeYamlToolTest.java b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/snakeyaml/SnakeYamlToolTest.java index ee34a28..90be879 100644 --- a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/snakeyaml/SnakeYamlToolTest.java +++ b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/snakeyaml/SnakeYamlToolTest.java @@ -27,6 +27,8 @@ import static junit.framework.TestCase.assertEquals; public class SnakeYamlToolTest { + private static final String ANY_GROUP = "group"; + private static final String ANY_YAML_STRING = "docker:\n" + " - image: ubuntu:14.04\n" + " - image: mongo:2.6.8\n" + @@ -56,6 +58,6 @@ public class SnakeYamlToolTest { } private Datasource datasource(String value) { - return DatasourceFactory.create("test.yml", value); + return DatasourceFactory.create("test.yml", ANY_GROUP, value); } } diff --git a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/xml/XmlToolTest.java b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/xml/XmlToolTest.java index 79a5432..c2b16fa 100644 --- a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/xml/XmlToolTest.java +++ b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/xml/XmlToolTest.java @@ -26,6 +26,8 @@ import static junit.framework.TestCase.assertNotNull; public class XmlToolTest { + private static final String ANY_GROUP = "group"; + private static final String ANY_XML_STRING = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + "<note>\n" + " <to>Tove</to>\n" + @@ -57,6 +59,6 @@ public class XmlToolTest { } private Datasource datasource(String value) { - return DatasourceFactory.create("test.xml", value); + return DatasourceFactory.create("test.xml", ANY_GROUP, value); } }
