Merge remote-tracking branch 'origin/master' into FREEMARKER-154. Also updated website module and DocBook content to be compatible with it.
diff --git a/freemarker-generator-base/pom.xml b/freemarker-generator-base/pom.xml
index deb18fb..512158d 100644
--- a/freemarker-generator-base/pom.xml
+++ b/freemarker-generator-base/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.freemarker.generator</groupId>
<artifactId>freemarker-generator</artifactId>
- <version>0.1.0-SNAPSHOT</version>
+ <version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>freemarker-generator-base</artifactId>
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 86a69ab..f4e19bd 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
@@ -93,6 +93,15 @@
public static final String FREEMARKER_USER_PARAMETERS = "freemarker.user.parameters";
}
+ public static class SeedType {
+
+ private SeedType() {
+ }
+
+ public static final String TEMPLATE = "template";
+ public static final String DATASOURCE = "datasource";
+ }
+
public static class SystemProperties {
private SystemProperties() {
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/CachingUrlDataSource.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/CachingUrlDataSource.java
index 6616598..81b41c4 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/CachingUrlDataSource.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/activation/CachingUrlDataSource.java
@@ -26,6 +26,7 @@
*/
public class CachingUrlDataSource extends URLDataSource {
+ /** Cached content type. */
private String contentType;
public CachingUrlDataSource(URL url) {
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 66557d1..de2b295 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
@@ -59,24 +59,29 @@
*/
public class DataSource implements Closeable, javax.activation.DataSource {
- public static final String METADATA_BASE_NAME = "basename";
+ public static final String METADATA_BASE_NAME = "baseName";
+ public static final String METADATA_CHARSET = "charset";
public static final String METADATA_EXTENSION = "extension";
- public static final String METADATA_FILE_NAME = "filename";
- public static final String METADATA_FILE_PATH = "filepath";
+ public static final String METADATA_FILE_NAME = "fileName";
+ public static final String METADATA_FILE_PATH = "filePath";
public static final String METADATA_GROUP = "group";
+ public static final String METADATA_MIME_TYPE = "mimeType";
public static final String METADATA_NAME = "name";
+ public static final String METADATA_RELATIVE_FILE_PATH = "relativeFilePath";
public static final String METADATA_URI = "uri";
- public static final String METADATA_MIME_TYPE = "mimetype";
+ /** List of metadata keys */
public static final List<String> METADATA_KEYS = Arrays.asList(
METADATA_BASE_NAME,
+ METADATA_CHARSET,
METADATA_EXTENSION,
METADATA_FILE_NAME,
METADATA_FILE_PATH,
METADATA_GROUP,
+ METADATA_MIME_TYPE,
METADATA_NAME,
- METADATA_URI,
- METADATA_MIME_TYPE
+ METADATA_RELATIVE_FILE_PATH,
+ METADATA_URI
);
/** Human-readable name of the data source */
@@ -91,6 +96,9 @@
/** The underlying "javax.activation.DataSource" */
private final javax.activation.DataSource dataSource;
+ /** The relative path for a file-based data source */
+ private final String relativeFilePath;
+
/** Content type of data source either provided by the caller or fetched directly from the data source */
private final String contentType;
@@ -106,19 +114,21 @@
/**
* Constructor.
*
- * @param name Human-readable name of the data source
- * @param group Optional group of data source
- * @param uri source URI of the data source
- * @param dataSource JAF data source being wrapped
- * @param contentType content type of data source either provided by the caller or fetched directly from the data source
- * @param charset option charset for directly accessing text-based content
- * @param properties optional name/value pairs
+ * @param name Human-readable name of the data source
+ * @param group Optional group of data source
+ * @param uri source URI of the data source
+ * @param dataSource JAF data source being wrapped
+ * @param relativeFilePath relative path regarding a source directory
+ * @param contentType content type of data source either provided by the caller or fetched directly from the data source
+ * @param charset option charset for directly accessing text-based content
+ * @param properties optional name/value pairs
*/
public DataSource(
String name,
String group,
URI uri,
javax.activation.DataSource dataSource,
+ String relativeFilePath,
String contentType,
Charset charset,
Map<String, String> properties) {
@@ -126,12 +136,17 @@
this.group = StringUtils.emptyToNull(group);
this.uri = requireNonNull(uri);
this.dataSource = requireNonNull(dataSource);
+ this.relativeFilePath = relativeFilePath != null ? relativeFilePath : "";
this.contentType = contentType;
this.charset = charset;
this.properties = properties != null ? new HashMap<>(properties) : new HashMap<>();
this.closeables = new CloseableReaper();
}
+ public static DataSourceBuilder builder() {
+ return DataSourceBuilder.builder();
+ }
+
@Override
public String getName() {
return name;
@@ -182,6 +197,16 @@
}
/**
+ * Get the path from the underlying "FileDataSource". All
+ * other data sources will return an empty string.
+ *
+ * @return file name or empty string
+ */
+ public String getFilePath() {
+ return isFileDataSource() ? FilenameUtils.getFullPathNoEndSeparator(uri.getPath()) : "";
+ }
+
+ /**
* Get the base name from the underlying "FileDataSource". All
* other data sources will return an empty string.
*
@@ -202,6 +227,16 @@
}
/**
+ * Get the relative path for a file-based data source starting from
+ * the data source directory.
+ *
+ * @return relative path
+ */
+ public String getRelativeFilePath() {
+ return relativeFilePath;
+ }
+
+ /**
* Get the charset. If no charset can be detected UTF-8 is assumed.
*
* @return charset
@@ -341,12 +376,16 @@
switch (key) {
case METADATA_BASE_NAME:
return getBaseName();
+ case METADATA_CHARSET:
+ return getCharset().name();
case METADATA_EXTENSION:
return getExtension();
case METADATA_FILE_NAME:
return getFileName();
case METADATA_FILE_PATH:
- return FilenameUtils.getFullPathNoEndSeparator(uri.getPath());
+ return getFilePath();
+ case METADATA_RELATIVE_FILE_PATH:
+ return getRelativeFilePath();
case METADATA_GROUP:
return getGroup();
case METADATA_NAME:
@@ -371,7 +410,8 @@
}
/**
- * Matches a metadata key with a wildcard expression.
+ * Matches a metadata key with a wildcard expression. If the wildcard is prefixed
+ * with a "!" than the match will be negated.
*
* @param key metadata key, e.g. "name", "fileName", "baseName", "extension", "uri", "group"
* @param wildcard the wildcard string to match against
@@ -380,7 +420,11 @@
*/
public boolean match(String key, String wildcard) {
final String value = getMetadata(key);
- return FilenameUtils.wildcardMatch(value, wildcard);
+ if (wildcard != null && wildcard.startsWith("!")) {
+ return !FilenameUtils.wildcardMatch(value, wildcard.substring(1));
+ } else {
+ return FilenameUtils.wildcardMatch(value, wildcard);
+ }
}
/**
@@ -432,4 +476,66 @@
private boolean isByteArrayDataSource() {
return dataSource instanceof ByteArrayDataSource;
}
+
+ public static final class DataSourceBuilder {
+ private String name;
+ private String group;
+ private URI uri;
+ private javax.activation.DataSource dataSource;
+ private String relativeFilePath;
+ private String contentType;
+ private Charset charset;
+ private Map<String, String> properties;
+
+ private DataSourceBuilder() {
+ }
+
+ static DataSourceBuilder builder() {
+ return new DataSourceBuilder();
+ }
+
+ public DataSourceBuilder name(String name) {
+ this.name = name;
+ return this;
+ }
+
+ public DataSourceBuilder group(String group) {
+ this.group = group;
+ return this;
+ }
+
+ public DataSourceBuilder uri(URI uri) {
+ this.uri = uri;
+ return this;
+ }
+
+ public DataSourceBuilder dataSource(javax.activation.DataSource dataSource) {
+ this.dataSource = dataSource;
+ return this;
+ }
+
+ public DataSourceBuilder relativeFilePath(String relativeFilePath) {
+ this.relativeFilePath = relativeFilePath;
+ return this;
+ }
+
+ public DataSourceBuilder contentType(String contentType) {
+ this.contentType = contentType;
+ return this;
+ }
+
+ public DataSourceBuilder charset(Charset charset) {
+ this.charset = charset;
+ return this;
+ }
+
+ public DataSourceBuilder properties(Map<String, String> properties) {
+ this.properties = properties;
+ return this;
+ }
+
+ public DataSource build() {
+ return new DataSource(name, group, uri, dataSource, relativeFilePath, contentType, charset, properties);
+ }
+ }
}
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 e6f37f5..d1ee551 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
@@ -62,7 +62,13 @@
URI uri,
javax.activation.DataSource dataSource,
Map<String, String> properties) {
- return new DataSource(name, group, uri, dataSource, null, null, properties);
+ return DataSource.builder()
+ .name(name)
+ .group(group)
+ .uri(uri)
+ .dataSource(dataSource)
+ .properties(properties)
+ .build();
}
public static DataSource create(
@@ -73,7 +79,15 @@
String contentType,
Charset charset,
Map<String, String> properties) {
- return new DataSource(name, group, uri, dataSource, contentType, charset, properties);
+ return DataSource.builder()
+ .name(name)
+ .group(group)
+ .uri(uri)
+ .dataSource(dataSource)
+ .contentType(contentType)
+ .charset(charset)
+ .properties(properties)
+ .build();
}
// == URL ===============================================================
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceLoader.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceLoader.java
index 4a22137..d2d80c2 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceLoader.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceLoader.java
@@ -22,7 +22,7 @@
* Check if the data source can be loaded by this instance.
*
* @param source source to be loaded from
- * @return true if the instance wold be able to load a data source
+ * @return true if the instance would be able to load a data source
*/
boolean accept(String source);
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceLoaderFactory.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceLoaderFactory.java
index b7c4a3e..2e061bb 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceLoaderFactory.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/datasource/DataSourceLoaderFactory.java
@@ -24,21 +24,16 @@
import java.util.Arrays;
/**
- * Creates a FreeMarker data source from various sources.
+ * Factory method to create a <code>DataSourceLoader</code>.
*/
public abstract class DataSourceLoaderFactory {
- private static DataSourceLoader dataSourceLoader;
-
- public static synchronized DataSourceLoader create() {
- if (dataSourceLoader == null) {
- dataSourceLoader = new DefaultDataSourceLoader(
- Arrays.asList(
- new FileDataSourceLoader(),
- new HttpDataSourceLoader(),
- new EnvironmentDataSourceLoader()
- ));
- }
- return dataSourceLoader;
+ public static DataSourceLoader create() {
+ return new DefaultDataSourceLoader(
+ Arrays.asList(
+ new FileDataSourceLoader(),
+ new HttpDataSourceLoader(),
+ new EnvironmentDataSourceLoader()
+ ));
}
}
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 fcb3432..7762c41 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
@@ -23,9 +23,12 @@
import java.io.Closeable;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
+import java.util.function.Function;
import java.util.stream.Collectors;
import static java.util.function.Function.identity;
@@ -39,24 +42,27 @@
/** The underlying list of data sources */
private final List<DataSource> dataSources;
+ /** Map of named data sources */
+ private final Map<String, DataSource> dataSourcesMap;
+
public DataSources(Collection<DataSource> dataSources) {
- Validate.notNull(dataSources, "No data sources provided");
- this.dataSources = new ArrayList<>(dataSources);
+ Validate.notNull(dataSources, "dataSources must not be null");
+
+ this.dataSources = Collections.unmodifiableList(new ArrayList<>(dataSources));
+ this.dataSourcesMap = Collections.unmodifiableMap(dataSourcesMap(dataSources));
}
/**
* Get the names of all data sources.
*
- * @return data source names
+ * @return list of data source names
*/
public List<String> getNames() {
- return dataSources.stream()
- .map(DataSource::getName)
- .collect(Collectors.toList());
+ return new ArrayList<>(dataSourcesMap.keySet());
}
/**
- * Get the requested metadata value for all data sources.
+ * Get a list of distinct metadata values for all data sources.
*
* @param key key of the metadata part
* @return list of metadata values
@@ -64,13 +70,15 @@
public List<String> getMetadata(String key) {
return dataSources.stream()
.map(ds -> ds.getMetadata(key))
+ .filter(StringUtils::isNotEmpty)
+ .distinct()
.collect(Collectors.toList());
}
/**
- * Get a list of unique groups of all data sources.
+ * Get a list of distinct group names of all data sources.
*
- * @return list of groups
+ * @return list of group names
*/
public List<String> getGroups() {
return dataSources.stream()
@@ -80,27 +88,46 @@
.collect(Collectors.toList());
}
+ /**
+ * Returns the number of elements in this list.
+ *
+ * @return the number of elements in this list
+ */
public int size() {
return dataSources.size();
}
+ /**
+ * Returns <tt>true</tt> if this list contains no elements.
+ *
+ * @return <tt>true</tt> if this list contains no elements
+ */
public boolean isEmpty() {
return dataSources.isEmpty();
}
/**
+ * Get an array representation of the underlying data sources.
+ *
+ * @return array of data sources
+ */
+ public DataSource[] toArray() {
+ return dataSources.toArray(new DataSource[0]);
+ }
+
+ /**
* Get a list representation of the underlying data sources.
*
* @return list of data sources
*/
public List<DataSource> toList() {
- return new ArrayList<>(dataSources);
+ return dataSources;
}
/**
* Get a map representation of the underlying data sources.
* In <code>freemarker-cli</code> the map is also used to
- * iterate over data source so we need to return a
+ * iterate over data source, so we need to return a
* <code>LinkedHashMap</code>.
* <p>
* The implementation also throws as <code>IllegalStateException</code>
@@ -109,15 +136,15 @@
* @return linked hasp map of data sources
*/
public Map<String, DataSource> toMap() {
- return dataSources.stream().collect(Collectors.toMap(
- DataSource::getName,
- identity(),
- (ds1, ds2) -> {
- throw new IllegalStateException("Duplicate key detected when generating map: " + ds1 + ", " + ds2);
- },
- LinkedHashMap::new));
+ return dataSourcesMap;
}
+ /**
+ * Returns the element at the specified position in this list.
+ *
+ * @param index index of the element to return
+ * @return the element at the specified position in this list
+ */
public DataSource get(int index) {
return dataSources.get(index);
}
@@ -130,7 +157,7 @@
* @return data source
*/
public DataSource get(String name) {
- final List<DataSource> list = find(name);
+ final List<DataSource> list = findByName(name);
if (list.isEmpty()) {
throw new IllegalArgumentException("Data source not found : " + name);
@@ -144,20 +171,18 @@
}
/**
- * Find data sources based on their name using a wildcard string..
+ * Find data sources based on their name using a wildcard string.
*
* @param wildcard the wildcard string to match against
* @return list of matching data sources
* @see <a href="https://commons.apache.org/proper/commons-io/javadocs/api-2.7/org/apache/commons/io/FilenameUtils.html#wildcardMatch-java.lang.String-java.lang.String-">Apache Commons IO</a>
*/
- public List<DataSource> find(String wildcard) {
- return dataSources.stream()
- .filter(dataSource -> dataSource.match("name", wildcard))
- .collect(Collectors.toList());
+ public List<DataSource> findByName(String wildcard) {
+ return find(DataSource.METADATA_NAME, wildcard);
}
/**
- * Find data sources based on their metadata key and wildcard string.
+ * Find <code>DataSources</code> based on their metadata key and wildcard string.
*
* @param key metadata key to match
* @param wildcard the wildcard string to match against
@@ -170,6 +195,32 @@
.collect(Collectors.toList());
}
+ /**
+ * Create a new <code>DataSources</code> instance consisting of
+ * data sources matching the filter.
+ *
+ * @param key metadata key to match
+ * @param wildcard the wildcard string to match against
+ * @return list of matching data sources
+ * @see <a href="https://commons.apache.org/proper/commons-io/javadocs/api-2.7/org/apache/commons/io/FilenameUtils.html#wildcardMatch-java.lang.String-java.lang.String-">Apache Commons IO</a>
+ */
+ public DataSources filter(String key, String wildcard) {
+ return new DataSources(find(key, wildcard));
+ }
+
+ /**
+ * Group the <code>DataSources</code> by a metadata value.
+ * @param key metadata key to group by
+ * @return groups of <code>DataSources</code>
+ */
+ public Map<String, DataSources> groupingBy(String key) {
+ final Function<DataSource, String> metadataFunction = dataSource -> dataSource.getMetadata(key);
+ return dataSources.stream()
+ .collect(Collectors.groupingBy(metadataFunction))
+ .entrySet().stream()
+ .collect(Collectors.toMap(Entry::getKey, p -> new DataSources(p.getValue())));
+ }
+
@Override
public void close() {
dataSources.forEach(ClosableUtils::closeQuietly);
@@ -181,4 +232,21 @@
"dataSources=" + dataSources +
'}';
}
+
+ private static List<DataSource> getNamedDataSources(Collection<DataSource> dataSources) {
+ return dataSources.stream()
+ .filter(dataSource -> StringUtils.isNotEmpty(dataSource.getName()))
+ .collect(Collectors.toList());
+ }
+
+ private Map<String, DataSource> dataSourcesMap(Collection<DataSource> dataSources) {
+ final List<DataSource> namedDataSources = getNamedDataSources(dataSources);
+ return namedDataSources.stream().collect(Collectors.toMap(
+ DataSource::getName,
+ identity(),
+ (ds1, ds2) -> {
+ throw new IllegalStateException("Duplicate names detected when generating data source map: " + ds1 + ", " + ds2);
+ },
+ LinkedHashMap::new));
+ }
}
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 cc919fc..7d84af5 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,11 +17,13 @@
package org.apache.freemarker.generator.base.datasource;
import org.apache.freemarker.generator.base.file.RecursiveFileSupplier;
+import org.apache.freemarker.generator.base.mime.MimetypesFileTypeMapFactory;
import org.apache.freemarker.generator.base.uri.NamedUri;
import org.apache.freemarker.generator.base.uri.NamedUriStringParser;
-import org.apache.freemarker.generator.base.util.UriUtils;
+import org.apache.freemarker.generator.base.util.FileUtils;
import org.apache.freemarker.generator.base.util.Validate;
+import javax.activation.FileDataSource;
import java.io.File;
import java.nio.charset.Charset;
import java.util.ArrayList;
@@ -34,10 +36,9 @@
import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toList;
import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_GROUP;
-import static org.apache.freemarker.generator.base.datasource.DataSourceFactory.fromFile;
/**
- * Create a list of <code>DataSource</code> based on a list URIs, directories and files.
+ * Supply a list of <code>DataSource</code> based on a list URIs, directories and files.
*/
public class DataSourcesSupplier implements Supplier<List<DataSource>> {
@@ -110,16 +111,43 @@
}
private static List<DataSource> resolveFileOrDirectory(String source, String include, String exclude, Charset charset) {
- final NamedUri namedUri = NamedUriStringParser.parse(source);
- final String path = namedUri.getFile().getPath();
- final String group = namedUri.getGroupOrDefault(DEFAULT_GROUP);
- final Charset currCharset = getCharsetOrDefault(namedUri, charset);
- final Map<String, String> parameters = namedUri.getParameters();
+ final NamedUri sourceUri = NamedUriStringParser.parse(source);
+ final String path = sourceUri.getFile().getPath();
+ final String group = sourceUri.getGroupOrDefault(DEFAULT_GROUP);
+ final Charset currCharset = getCharsetOrDefault(sourceUri, charset);
+ final Map<String, String> parameters = sourceUri.getParameters();
return fileSupplier(path, include, exclude).get().stream()
- .map(file -> fromFile(getDataSourceName(namedUri, file), group, file, currCharset, parameters))
+ .map(file -> fromFile(sourceUri, getDataSourceName(sourceUri, file), group, file, currCharset, parameters))
.collect(toList());
}
+ private static DataSource fromFile(
+ NamedUri sourceUri,
+ String name,
+ String group,
+ File file,
+ Charset charset,
+ Map<String, String> properties) {
+ Validate.isTrue(file.exists(), "File not found: " + file);
+
+ final FileDataSource dataSource = new FileDataSource(file);
+ // content type is determined from file extension
+ dataSource.setFileTypeMap(MimetypesFileTypeMapFactory.create());
+ final String relativePath = FileUtils.getRelativePath(sourceUri.getFile(), file);
+ final String contentType = dataSource.getContentType();
+
+ return DataSource.builder()
+ .name(name)
+ .group(group)
+ .uri(file.toURI())
+ .dataSource(dataSource)
+ .relativeFilePath(relativePath)
+ .contentType(contentType)
+ .charset(charset)
+ .properties(properties)
+ .build();
+ }
+
private static RecursiveFileSupplier fileSupplier(String source, String include, String exclude) {
return new RecursiveFileSupplier(singletonList(source), singletonList(include), singletonList(exclude));
}
@@ -140,7 +168,7 @@
if (namedUri.hasName()) {
return namedUri.getName();
} else {
- return UriUtils.toStringWithoutFragment(file.toURI());
+ return file.getAbsolutePath();
}
}
}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/file/RecursiveFileSupplier.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/file/RecursiveFileSupplier.java
index bc89df3..fb4b9b7 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/file/RecursiveFileSupplier.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/file/RecursiveFileSupplier.java
@@ -16,11 +16,14 @@
*/
package org.apache.freemarker.generator.base.file;
+import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.AndFileFilter;
+import org.apache.commons.io.filefilter.HiddenFileFilter;
import org.apache.commons.io.filefilter.IOFileFilter;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.io.filefilter.OrFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
+import org.apache.freemarker.generator.base.util.StringUtils;
import java.io.File;
import java.util.ArrayList;
@@ -32,10 +35,6 @@
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static java.util.stream.Collectors.toList;
-import static org.apache.commons.io.FileUtils.listFiles;
-import static org.apache.commons.io.filefilter.HiddenFileFilter.HIDDEN;
-import static org.apache.commons.io.filefilter.HiddenFileFilter.VISIBLE;
-import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty;
/**
* Resolve a list of files or directories recursively.
@@ -94,7 +93,7 @@
}
private List<File> resolveDirectory(File directory) {
- return new ArrayList<>(listFiles(directory, fileFilter, directoryFilter));
+ return new ArrayList<>(FileUtils.listFiles(directory, fileFilter, directoryFilter));
}
private static IOFileFilter fileFilter(Collection<String> includes, Collection<String> excludes) {
@@ -113,7 +112,10 @@
}
private static IOFileFilter includeFilter(String include) {
- return isEmpty(include) ? VISIBLE : new AndFileFilter(new WildcardFileFilter(include), VISIBLE);
+ return StringUtils.isEmpty(include) ?
+ HiddenFileFilter.VISIBLE :
+ new AndFileFilter(
+ new WildcardFileFilter(include), HiddenFileFilter.VISIBLE);
}
private static List<IOFileFilter> excludeFilters(Collection<String> excludes) {
@@ -125,12 +127,14 @@
}
private static IOFileFilter excludeFilter(String exclude) {
- return isEmpty(exclude) ?
- VISIBLE :
- new NotFileFilter(new OrFileFilter(new WildcardFileFilter(exclude), HIDDEN));
+ return StringUtils.isEmpty(exclude) ?
+ HiddenFileFilter.VISIBLE :
+ new NotFileFilter(
+ new OrFileFilter(
+ new WildcardFileFilter(exclude), HiddenFileFilter.HIDDEN));
}
private static IOFileFilter directoryFilter() {
- return VISIBLE;
+ return HiddenFileFilter.VISIBLE;
}
}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/mime/Mimetypes.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/mime/Mimetypes.java
index c8bb76c..6f70b69 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/mime/Mimetypes.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/mime/Mimetypes.java
@@ -31,6 +31,9 @@
public static final String MIME_TEXT_TSV = "text/tab-separated-values";
public static final String MIME_TEXT_YAML = "text/yaml";
+ public static final String MIME_TYPE_ZIP = "application/zip";
+ public static final String MIME_TYPE_GZIP = "application/gzip";
+
public static final String MIME_VENDOR_MS_EXCEL = "application/vnd.ms-excel xls XLS";
public static final String MIME_VENDOR_OPEN_XML_SPREADSHEET = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx XLSX\"";
}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/mime/MimetypesFileTypeMapFactory.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/mime/MimetypesFileTypeMapFactory.java
index f8bbf2a..9445fe9 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/mime/MimetypesFileTypeMapFactory.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/mime/MimetypesFileTypeMapFactory.java
@@ -29,10 +29,12 @@
import static org.apache.freemarker.generator.base.mime.Mimetypes.MIME_TEXT_RTF;
import static org.apache.freemarker.generator.base.mime.Mimetypes.MIME_TEXT_TSV;
import static org.apache.freemarker.generator.base.mime.Mimetypes.MIME_TEXT_YAML;
+import static org.apache.freemarker.generator.base.mime.Mimetypes.MIME_TYPE_GZIP;
+import static org.apache.freemarker.generator.base.mime.Mimetypes.MIME_TYPE_ZIP;
import static org.apache.freemarker.generator.base.mime.Mimetypes.MIME_VENDOR_MS_EXCEL;
import static org.apache.freemarker.generator.base.mime.Mimetypes.MIME_VENDOR_OPEN_XML_SPREADSHEET;
-public class MimetypesFileTypeMapFactory {
+public abstract class MimetypesFileTypeMapFactory {
private static MimetypesFileTypeMap mimeTypes;
@@ -52,6 +54,8 @@
mimeTypes.addMimeTypes(MIME_TEXT_RTF + " rtf RTF");
mimeTypes.addMimeTypes(MIME_TEXT_TSV + " tsv TSV");
mimeTypes.addMimeTypes(MIME_TEXT_YAML + " yml YML yaml YAML");
+ mimeTypes.addMimeTypes(MIME_TYPE_GZIP + " gzip GZIP");
+ mimeTypes.addMimeTypes(MIME_TYPE_ZIP + " zip ZIP");
}
return mimeTypes;
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/output/OutputGenerator.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/output/OutputGenerator.java
index 5ce4cf4..ebdd409 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/output/OutputGenerator.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/output/OutputGenerator.java
@@ -26,10 +26,16 @@
import static java.util.Objects.requireNonNull;
/**
- * Information about loading templates and writing their output.
+ * Information about loading templates and writing their output. An instance
+ * describes a transformation of 0..N data sources to an output file.
*/
public class OutputGenerator {
+ public enum SeedType {
+ DATASOURCE,
+ TEMPLATE
+ }
+
/** Source of template */
private final TemplateSource templateSource;
@@ -42,15 +48,20 @@
/** Variables (as a map) used for the transformation */
private final Map<String, Object> variables;
+ /** Seed type of "DATASOURCE* only takes a single data soure */
+ private final SeedType seedType;
+
public OutputGenerator(
TemplateSource templateSource,
TemplateOutput templateOutput,
List<DataSource> dataSources,
- Map<String, Object> variables) {
+ Map<String, Object> variables,
+ SeedType seedType) {
this.templateSource = requireNonNull(templateSource);
this.templateOutput = requireNonNull(templateOutput);
this.dataSources = requireNonNull(dataSources);
this.variables = requireNonNull(variables);
+ this.seedType = requireNonNull(seedType);
}
public TemplateSource getTemplateSource() {
@@ -69,6 +80,10 @@
return variables;
}
+ public SeedType getSeedType() {
+ return seedType;
+ }
+
@Override
public String toString() {
return "OutputGenerator{" +
@@ -76,6 +91,7 @@
", templateOutput=" + templateOutput +
", dataSources=" + dataSources +
", variables=" + variables +
+ ", seedType=" + seedType +
'}';
}
}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/table/Table.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/table/Table.java
index 1abf21b..b1710b1 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/table/Table.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/table/Table.java
@@ -141,7 +141,7 @@
/**
* Create a table from a list of rows representing tabular data
- * where the first row may consists of column headers.
+ * where the first row may consist of column headers.
*
* @param rows row values
* @param withFirstRowAsColumnNames column names as first row?
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/FileUtils.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/FileUtils.java
new file mode 100644
index 0000000..c850d1e
--- /dev/null
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/FileUtils.java
@@ -0,0 +1,48 @@
+/*
+ * 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.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+public class FileUtils {
+
+ /**
+ * Determines the relative path between a directory and a file within the directory (excluding the file name).
+ *
+ * @param directory the directory
+ * @param file the file
+ * @return relative path or an empty string if no relative path exists
+ */
+ public static String getRelativePath(File directory, File file) {
+ Validate.notNull(directory, "directory is null");
+ Validate.notNull(file, "file is null");
+ Validate.isTrue(directory.exists(), "directory does not exist");
+
+ final Path filePath = Paths.get(file.toURI()).normalize();
+ final Path directoryPath = Paths.get(directory.toURI()).normalize();
+ final String relativePath = directoryPath.relativize(filePath).normalize().toString();
+
+ // strip last path segment
+ if (relativePath.lastIndexOf(File.separatorChar) >= 0) {
+ return relativePath.substring(0, relativePath.lastIndexOf(File.separatorChar));
+ } else {
+ return "";
+ }
+ }
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
index 4ec6fbc..08ccd5b 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/ListUtils.java
@@ -17,8 +17,11 @@
package org.apache.freemarker.generator.base.util;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
public class ListUtils {
@@ -57,10 +60,24 @@
* @param <T> the type of the array
* @return copied array
*/
- public static <T> T coalesce(List<T> list) {
+ public static <T> T coalesce(Collection<T> list) {
return list.stream()
.filter(Objects::nonNull)
.findFirst()
.orElse(null);
}
+
+ /**
+ * Concatenate an array of lists.
+ *
+ * @param lists array of lists
+ * @param <T> the type of the array
+ * @return concatenated list
+ */
+ @SafeVarargs
+ public static <T> List<T> concatenate(Collection<T>... lists) {
+ return Stream.of(lists)
+ .flatMap(Collection::stream)
+ .collect(Collectors.toList());
+ }
}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/NonClosableWriterWrapper.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/NonClosableWriterWrapper.java
index e2637b7..cd48b5b 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/NonClosableWriterWrapper.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/NonClosableWriterWrapper.java
@@ -22,7 +22,7 @@
import static java.util.Objects.requireNonNull;
/**
- * Wraps a writer (usually the internal FreeMarker's writer instance
+ * Wraps a writer (usually the internal FreeMarker's writer instance)
* and avoids closing it since this would crash FreeMarker. E.g. the
* Commons CSV integration uses the FreeMarker writer directly but
* some implementation could call "CSVPrinter#close"
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/OperatingSystem.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/OperatingSystem.java
index 180b7ac..02158cb 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/OperatingSystem.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/OperatingSystem.java
@@ -19,7 +19,7 @@
import java.util.Locale;
/**
- * Helper class to detect the operting system (mostly Windows).
+ * Helper class to detect the operating system.
*/
public class OperatingSystem {
private static final String OS = System.getProperty("os.name", "unknown").toLowerCase(Locale.ROOT);
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/PropertiesTransformer.java b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/PropertiesTransformer.java
index 90b2f6a..97ed173 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/PropertiesTransformer.java
+++ b/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/util/PropertiesTransformer.java
@@ -24,7 +24,8 @@
public class PropertiesTransformer {
/**
- * Create a new <code>java.util.Properties</code> instance having only key with the prefix.
+ * Create a new <code>java.util.Properties</code> instance having only key with the
+ * given prefix.
*
* @param properties the properties
* @param prefix prefix
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 c3eabf1..c41fefa 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
@@ -30,6 +30,10 @@
return value != null && value.trim().isEmpty() ? null : value;
}
+ public static String nullToEmpty(String value) {
+ return isEmpty(value) ? "" : value;
+ }
+
public static String firstNonEmpty(final String... values) {
if (values != null) {
for (final String value : values) {
@@ -41,6 +45,10 @@
return null;
}
+ public static String trim(String value) {
+ return value != null ? value.trim() : null;
+ }
+
public static int count(final String s, final char c) {
final char[] chars = s.toCharArray();
int count = 0;
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 e1a8f80..cb7b252 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
@@ -54,6 +54,7 @@
assertEquals("", dataSource.getBaseName());
assertEquals("", dataSource.getExtension());
assertTrue(dataSource.getUri().toString().startsWith("string:///"));
+ assertEquals("", dataSource.getRelativeFilePath());
assertEquals(UTF_8, dataSource.getCharset());
assertEquals("text/plain", dataSource.getContentType());
assertTrue(dataSource.getLength() > 0);
@@ -72,13 +73,14 @@
assertEquals("xml", dataSource.getExtension());
assertEquals(ANY_FILE.toURI().toString(), dataSource.getUri().toString());
assertEquals(ANY_CHAR_SET.name(), dataSource.getCharset().name());
+ assertEquals("", dataSource.getRelativeFilePath());
assertEquals("application/xml", dataSource.getContentType());
assertTrue(dataSource.getLength() > 0);
assertFalse(dataSource.getText().isEmpty());
assertTrue(dataSource.match("name", "*" + ANY_FILE_NAME));
assertTrue(dataSource.match("uri", "file:/*/pom.xml"));
assertTrue(dataSource.match("extension", "xml"));
- assertTrue(dataSource.match("basename", "pom"));
+ assertTrue(dataSource.match("baseName", "pom"));
}
}
@@ -91,6 +93,7 @@
assertEquals("", dataSource.getBaseName());
assertEquals("", dataSource.getExtension());
assertEquals("https://www.google.com/?foo=bar", dataSource.getUri().toString());
+ assertEquals("", dataSource.getRelativeFilePath());
assertEquals("text/html; charset=ISO-8859-1", dataSource.getContentType());
assertEquals(MIME_TEXT_HTML, dataSource.getMimeType());
assertEquals("ISO-8859-1", dataSource.getCharset().name());
@@ -128,15 +131,18 @@
try (DataSource dataSource = stringDataSource()) {
final Map<String, String> metadata = dataSource.getMetadata();
- assertEquals(8, metadata.size());
- assertEquals("", metadata.get("basename"));
+ assertEquals(10, metadata.size());
+ assertEquals("", metadata.get("baseName"));
assertEquals("", metadata.get("extension"));
- assertEquals("", metadata.get("filename"));
- assertEquals("/", metadata.get("filepath"));
+ assertEquals("", metadata.get("fileName"));
+ assertEquals("", metadata.get("filePath"));
+ assertEquals("", metadata.get("relativeFilePath"));
+
assertEquals("default", metadata.get("group"));
assertEquals("stdin", metadata.get("name"));
assertTrue(metadata.get("uri").startsWith("string://"));
- assertEquals("text/plain", metadata.get("mimetype"));
+ assertEquals("text/plain", metadata.get("mimeType"));
+ assertEquals("UTF-8", metadata.get("charset"));
}
}
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 85bdedc..9885a81 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
@@ -25,6 +25,7 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
+import java.util.Map;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Arrays.asList;
@@ -45,28 +46,32 @@
private static final String GROUP_PART = "group";
@Test
- public void shouldFindByName() {
+ public void shouldFindDataSourcesByName() {
try (DataSources dataSources = dataSources()) {
- assertEquals(0, dataSources.find(null).size());
- assertEquals(0, dataSources.find("").size());
- assertEquals(0, dataSources.find("*.bar").size());
- assertEquals(0, dataSources.find("foo.*").size());
- assertEquals(0, dataSources.find("foo.bar").size());
+ assertEquals(0, dataSources.findByName(null).size());
+ assertEquals(0, dataSources.findByName("").size());
+ assertEquals(0, dataSources.findByName("*.bar").size());
+ assertEquals(0, dataSources.findByName("foo.*").size());
+ assertEquals(0, dataSources.findByName("foo.bar").size());
- assertEquals(2, dataSources.find("*.*").size());
- assertEquals(1, dataSources.find("*." + ANY_FILE_EXTENSION).size());
- assertEquals(1, dataSources.find("*.???").size());
- assertEquals(1, dataSources.find("*om*").size());
- assertEquals(1, dataSources.find("*o*.xml").size());
+ assertEquals(2, dataSources.findByName("*.*").size());
+ assertEquals(1, dataSources.findByName("*." + ANY_FILE_EXTENSION).size());
+ assertEquals(1, dataSources.findByName("*.???").size());
+ assertEquals(1, dataSources.findByName("*om*").size());
+ assertEquals(1, dataSources.findByName("*o*.xml").size());
- assertEquals(3, dataSources.find("*").size());
+ assertEquals(3, dataSources.findByName("*").size());
+
+ assertEquals(2, dataSources.findByName("!pom.xml").size());
+ assertEquals(3, dataSources.findByName("!").size());
+ assertEquals(0, dataSources.findByName("!*").size());
+ assertEquals(1, dataSources.findByName("!*.*").size());
}
}
@Test
- public void shouldFindByGroupPart() {
+ public void shouldFindDataSourcesByMetadata() {
try (DataSources dataSources = dataSources()) {
-
assertEquals(0, dataSources.find(GROUP_PART, null).size());
assertEquals(0, dataSources.find(GROUP_PART, "").size());
@@ -76,6 +81,10 @@
assertEquals(3, dataSources.find(GROUP_PART, "default").size());
assertEquals(3, dataSources.find(GROUP_PART, "d*").size());
assertEquals(3, dataSources.find(GROUP_PART, "d??????").size());
+
+ assertEquals(0, dataSources.find(GROUP_PART, "!*").size());
+ assertEquals(3, dataSources.find(GROUP_PART, "!unknown").size());
+ assertEquals(0, dataSources.find(GROUP_PART, "!default").size());
}
}
@@ -87,10 +96,10 @@
@Test
public void shouldGetAllDataSource() {
try (DataSources dataSources = dataSources()) {
-
assertEquals("unknown", dataSources.get(0).getName());
assertEquals("pom.xml", dataSources.get(1).getName());
assertEquals("server.invalid?foo=bar", dataSources.get(2).getName());
+ assertEquals(3, dataSources.toArray().length);
assertEquals(3, dataSources.toList().size());
assertEquals(3, dataSources.toMap().size());
assertEquals(3, dataSources.size());
@@ -100,9 +109,9 @@
@Test
public void shouldGetMetadataParts() {
- assertEquals(asList("", "pom.xml", ""), dataSources().getMetadata("filename"));
- assertEquals(asList("default", "default", "default"), dataSources().getMetadata("group"));
- assertEquals(asList("", "xml", ""), dataSources().getMetadata("extension"));
+ assertEquals(asList("pom.xml"), dataSources().getMetadata("fileName"));
+ assertEquals(asList("default"), dataSources().getMetadata("group"));
+ assertEquals(asList("xml"), dataSources().getMetadata("extension"));
assertEquals(asList("unknown", "pom.xml", "server.invalid?foo=bar"), dataSources().getMetadata("name"));
}
@@ -111,6 +120,36 @@
assertEquals(singletonList(DEFAULT_GROUP), dataSources().getGroups());
}
+ @Test
+ public void shouldSupportGroupingByMetadata() {
+ try (DataSources dataSources = dataSources()) {
+ final Map<String, DataSources> map = dataSources.groupingBy("mimeType");
+
+ assertEquals(2, map.size());
+ assertEquals(1, map.get("application/xml").size());
+ assertEquals(2, map.get("text/plain").size());
+ }
+ }
+
+ @Test
+ public void shouldSupportFilteringByMetadata() {
+ try (DataSources dataSources = dataSources().filter("mimeType", "text/plain")) {
+ assertEquals(2, dataSources.size());
+ assertEquals("text/plain", dataSources.get(0).getMimeType());
+ assertEquals("text/plain", dataSources.get(1).getMimeType());
+ }
+
+ try (DataSources dataSources = dataSources().filter("mimeType", "application/xml")) {
+ assertEquals(1, dataSources.size());
+ assertEquals("application/xml", dataSources.get(0).getMimeType());
+ }
+
+ try (DataSources dataSources = dataSources().filter("mimeType", "!text/plain")) {
+ assertEquals(1, dataSources.size());
+ assertEquals("application/xml", dataSources.get(0).getMimeType());
+ }
+ }
+
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionWhenGetDoesNotFindDataSource() {
dataSources().get("file-does-not-exist");
@@ -134,7 +173,7 @@
}
private static DataSource urlDataSource() {
- return DataSourceFactory.fromUrl("server.invalid?foo=bar", "default", toUrl(ANY_URL), "plain/text", UTF_8, new HashMap<>());
+ return DataSourceFactory.fromUrl("server.invalid?foo=bar", "default", toUrl(ANY_URL), "text/plain", UTF_8, new HashMap<>());
}
private static URL toUrl(String value) {
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/util/FileUtilsTest.java b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/util/FileUtilsTest.java
new file mode 100644
index 0000000..f799c6b
--- /dev/null
+++ b/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/util/FileUtilsTest.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.util;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.freemarker.generator.base.util.FileUtils;
+import org.apache.freemarker.generator.base.util.OperatingSystem;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.apache.freemarker.generator.base.util.FileUtils.getRelativePath;
+import static org.junit.Assert.assertEquals;
+
+public class FileUtilsTest {
+
+ @Test
+ public void shouldGetRelativePathForSameDirectory() {
+ assertEquals("", getRelativePath(new File("/"), new File("/pom.xml")));
+ assertEquals("", getRelativePath(new File("."), new File("pom.xml")));
+ assertEquals("", getRelativePath(new File("."), new File("./pom.xml")));
+ assertEquals("", getRelativePath(new File("."), new File("./pom.xml")));
+ assertEquals("", getRelativePath(new File("../freemarker-generator-base"), new File("pom.xml")));
+ assertEquals("", getRelativePath(new File("../freemarker-generator-base"), new File("./pom.xml")));
+ assertEquals("", getRelativePath(new File("../freemarker-generator-base"), new File("../freemarker-generator-base/pom.xml")));
+ }
+
+ @Test
+ public void shouldGetRelativePathForNestedDirectory() {
+ assertEquals(fixSeparators("src/test/data/env"), getRelativePath(new File("."), new File("src/test/data/env/nginx.env")));
+ assertEquals(fixSeparators("src/test/data/env"), getRelativePath(new File("."), new File("./src/test/data/env/nginx.env")));
+ }
+
+ @Test
+ public void shouldGetRelativePathForDisjunctDirectories() {
+ assertEquals(fixSeparators("../test/data/env"), getRelativePath(new File("./src/site"), new File("src/test/data/env/nginx.env")));
+ }
+
+ @Test
+ public void shouldHandleInvalidArgumentsGracefully() {
+ assertEquals("", getRelativePath(new File("."), new File(".")));
+ assertEquals("", getRelativePath(new File("pom.xml"), new File("pom.xml")));
+ assertEquals("", getRelativePath(new File("."), new File("does-not-exist.xml")));
+ assertEquals("foo", getRelativePath(new File("."), new File("foo/does-not-exist.xml")));
+ assertEquals("foo", getRelativePath(new File("."), new File("foo/./does-not-exist.xml")));
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void shouldThrowIllegalArgumentExceptionForNonExistingDirectoy() {
+ getRelativePath(new File("does-not-exit"), new File("pom.xml"));
+ }
+
+ private static String fixSeparators(String str) {
+ if (OperatingSystem.isWindows()) {
+ return FilenameUtils.separatorsToWindows(str);
+ } else {
+ return str;
+ }
+ }
+}
diff --git a/freemarker-generator-cli/CHANGELOG.md b/freemarker-generator-cli/CHANGELOG.md
index 993890c..c440886 100644
--- a/freemarker-generator-cli/CHANGELOG.md
+++ b/freemarker-generator-cli/CHANGELOG.md
@@ -2,9 +2,19 @@
All notable changes to this project will be documented in this file. We try to adhere to https://github.com/olivierlacan/keep-a-changelog.
-## 0.1.0-SNAPSHOT
+## 0.2.0-SNAPSHOT
### Added
+* [FREEMARKER-199] Add [utah-parser-tool](https://github.com/sonalake/utah-parser) to parse semi-structured text.
+
+### Changed
+* [FREEMARKER-195] Improve exposure of DataSources using TemplateHashModelEx2
+
+## 0.1.0-SNAPSHOT (unreleased)
+
+### Added
+* Use `-Xverify:none -XX:TieredStopAtLevel=1` to improve startup time of CLI
+* [FREEMARKER-188] Support an output "generation" mode to create an output for each `DataSource`
* [FREEMARKER-181] Support custom pattern definitions for Grok tool
* Parse a list of `DataSources` for the various tools
* [FREEMARKER-161] Allow multiple transformations on the CLI
@@ -20,7 +30,6 @@
* [FREEMARKER-129] Migrate `freemarker-cli` into `freemarker-generator` project (see [https://github.com/sgoeschl/freemarker-cli](https://github.com/sgoeschl/freemarker-cli))
* [FREEMARKER-129] Provide a `toString()` method for all tools
-### Changed
* [FREEMARKER-182] Upgrade to Apache FreeMarker 2.3.31
* [FREEMARKER-175] Use latest FreeMarker version
* [FREEMARKER-173] Allow to pass arbitrary key/value pairs to DataSource when using NamedURIs
@@ -82,4 +91,7 @@
[FREEMARKER-176]: https://issues.apache.org/jira/browse/FREEMARKER-176
[FREEMARKER-181]: https://issues.apache.org/jira/browse/FREEMARKER-181
[FREEMARKER-182]: https://issues.apache.org/jira/browse/FREEMARKER-182
+[FREEMARKER-188]: https://issues.apache.org/jira/browse/FREEMARKER-188
+[FREEMARKER-195]: https://issues.apache.org/jira/browse/FREEMARKER-195
+[FREEMARKER-199]: https://issues.apache.org/jira/browse/FREEMARKER-199
diff --git a/freemarker-generator-cli/pom.xml b/freemarker-generator-cli/pom.xml
index 4984b36..05497dc 100644
--- a/freemarker-generator-cli/pom.xml
+++ b/freemarker-generator-cli/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.freemarker.generator</groupId>
<artifactId>freemarker-generator</artifactId>
- <version>0.1.0-SNAPSHOT</version>
+ <version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>freemarker-generator-cli</artifactId>
@@ -46,7 +46,13 @@
<configuration>
<repositoryLayout>flat</repositoryLayout>
<repositoryName>lib</repositoryName>
- <extraJvmArguments>-Xms64m -Xmx512m</extraJvmArguments>
+ <!--
+ See https://ryanharrison.co.uk/2018/04/29/faster-java-startup-time.html
+ "-Xverify:none -XX:TieredStopAtLevel=1" improves startup time by 50%
+ See https://www.eclipse.org/openj9/docs/xverify/
+ "-Xverifiy:none" is deprecated in Java 13
+ -->
+ <extraJvmArguments>-Xms64m -Xmx512m -XX:TieredStopAtLevel=1</extraJvmArguments>
<endorsedDir>endorsed</endorsedDir>
<useWildcardClassPath>true</useWildcardClassPath>
<configurationDirectory>config</configurationDirectory>
diff --git a/freemarker-generator-cli/src/app/config/freemarker-generator.properties b/freemarker-generator-cli/src/app/config/freemarker-generator.properties
index 25b7029..d65937b 100644
--- a/freemarker-generator-cli/src/app/config/freemarker-generator.properties
+++ b/freemarker-generator-cli/src/app/config/freemarker-generator.properties
@@ -34,6 +34,7 @@
freemarker.tools.jsoup=org.apache.freemarker.generator.tools.jsoup.JsoupTool
freemarker.tools.properties=org.apache.freemarker.generator.tools.properties.PropertiesTool
freemarker.tools.system=org.apache.freemarker.generator.tools.system.SystemTool
+freemarker.tools.utahparser=org.apache.freemarker.generator.tools.utahparser.UtahParserTool
freemarker.tools.uuid=org.apache.freemarker.generator.tools.uuid.UUIDTool
freemarker.tools.xml=org.apache.freemarker.generator.tools.xml.XmlTool
freemarker.tools.yaml=org.apache.freemarker.generator.tools.snakeyaml.SnakeYamlTool
diff --git a/freemarker-generator-cli/src/app/examples/data/ftl/nginx/nginx.conf.ftl b/freemarker-generator-cli/src/app/examples/data/ftl/nginx/nginx.conf.ftl
index 3cbf310..d74b193 100644
--- a/freemarker-generator-cli/src/app/examples/data/ftl/nginx/nginx.conf.ftl
+++ b/freemarker-generator-cli/src/app/examples/data/ftl/nginx/nginx.conf.ftl
@@ -1,4 +1,4 @@
-<#assign env = tools.properties.parse(dataSources?values[0])>
+<#assign env = tools.properties.parse(dataSources[0])>
server {
listen 80;
diff --git a/freemarker-generator-cli/src/app/examples/data/nginx/test1-api.nginx b/freemarker-generator-cli/src/app/examples/data/nginx/test1-api.nginx
new file mode 100644
index 0000000..2c2486f
--- /dev/null
+++ b/freemarker-generator-cli/src/app/examples/data/nginx/test1-api.nginx
@@ -0,0 +1,30 @@
+server {
+ listen 443 ssl;
+ server_name test1-api.company.org;
+
+ access_log /var/log/nginx/test1-api.access.log;
+ error_log /var/log/nginx/test1-api.error.log;
+
+ ssl_certificate /etc/nginx/ssl/wildcard.company.org-public.crt;
+ ssl_certificate_key /etc/nginx/ssl/wildcard.company.org-private.rsa;
+
+ include /etc/nginx/includes/FLKPMM.nginx;
+
+ proxy_buffers 16 64k;
+ proxy_buffer_size 128k;
+ proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
+ proxy_redirect off;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto https;
+ proxy_set_header X-TPP-QWAC $ssl_client_cert;
+
+ ssl_verify_client optional_no_ca;
+
+
+ location / {
+ return 403;
+ }
+
+}
diff --git a/freemarker-generator-cli/src/app/examples/data/nginx/test1-application.nginx b/freemarker-generator-cli/src/app/examples/data/nginx/test1-application.nginx
new file mode 100644
index 0000000..b618991
--- /dev/null
+++ b/freemarker-generator-cli/src/app/examples/data/nginx/test1-application.nginx
@@ -0,0 +1,27 @@
+server {
+ listen 443 ssl;
+ server_name test1-application.company.org;
+
+ access_log /var/log/nginx/test1-application.access.log;
+ error_log /var/log/nginx/test1-application.error.log;
+
+ ssl_certificate /etc/nginx/ssl/wildcard.company.org-public.crt;
+ ssl_certificate_key /etc/nginx/ssl/wildcard.company.org-private.rsa;
+
+ proxy_buffers 16 64k;
+ proxy_buffer_size 128k;
+
+ location / {
+ proxy_pass https://osroutercpssl/;
+ proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
+ proxy_redirect off;
+
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto https;
+ }
+
+}
+
+
diff --git a/freemarker-generator-cli/src/app/examples/data/text/utahparser/juniper_bgp_summary_example.txt b/freemarker-generator-cli/src/app/examples/data/text/utahparser/juniper_bgp_summary_example.txt
new file mode 100644
index 0000000..c4a209e
--- /dev/null
+++ b/freemarker-generator-cli/src/app/examples/data/text/utahparser/juniper_bgp_summary_example.txt
@@ -0,0 +1,12 @@
+Groups: 3 Peers: 3 Down peers: 0
+Table Tot Paths Act Paths Suppressed History Damp State Pending
+inet.0 947 310 0 0 0 0
+inet6.0 849 807 0 0 0 0
+Peer AS InPkt OutPkt OutQ Flaps Last Up/Dwn State|#Active/Received/Damped...
+10.247.68.182 65550 131725 28179233 0 11 6w3d17h Establ
+ inet.0: 4/5/1
+ inet6.0: 0/0/0
+10.254.166.246 65550 136159 29104942 0 0 6w5d6h Establ
+ inet.0: 0/0/0
+ inet6.0: 7/8/1
+192.0.2.100 65551 1269381 1363320 0 1 9w5d6h 1/2/3 4/5/6
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/app/examples/data/text/utahparser/juniper_bgp_summary_template.xml b/freemarker-generator-cli/src/app/examples/data/text/utahparser/juniper_bgp_summary_template.xml
new file mode 100644
index 0000000..76084aa
--- /dev/null
+++ b/freemarker-generator-cli/src/app/examples/data/text/utahparser/juniper_bgp_summary_template.xml
@@ -0,0 +1,83 @@
+<!--
+ 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.
+-->
+<config>
+ <searches>
+
+ <!-- in this case, we have a CSV (space delimited file) so we define the line once, and then reuse it over
+ and again for each value -->
+ <search id="QUERY-LINE"><![CDATA[\s*{ipAddress}\s+{numbers}\s+{numbers}\s+{numbers}\s+{numbers}\s+{numbers}\s+{numbersThenText}]]></search>
+ <search id="inetInline"><![CDATA[{inet} {inet}]]></search>
+ <search id="inet4"><![CDATA[inet.0:\s*{inet}]]></search>
+ <search id="inet6"><![CDATA[inet6.0:\s*{inet}]]></search>
+ <search id="inet"><![CDATA[{numbers}/{numbers}/{numbers}]]></search>
+
+ <!-- Some rules for finding text, to make the values a little easier below -->
+ <search id="numbers"><![CDATA[(\d+)]]></search>
+ <search id="numbersThenText"><![CDATA[(\d+\S+)]]></search>
+ <search id="string"><![CDATA[(\S+?)]]></search>
+ <search id="ipAddress"><![CDATA[(\d+(\.\d+){3})]]></search>
+ <search id="EOL"><![CDATA[[\n\r]]]></search>
+ </searches>
+
+ <!-- the record starts with a line with an ip address and ends with either an inet6 line, or where the ids are at
+ the end of the line-->
+ <delim retain="true">{ipAddress}.*(\/\d+)\s*{EOL}</delim>
+ <delim>\s*({inet6})</delim>
+
+ <!--
+ This is the last line of the header
+ -->
+ <header-delim><![CDATA[Peer\s+AS\s+InPkt]]></header-delim>
+
+ <!--
+ Files look like this:
+
+ 10.247.68.182 65550 131725 28179233 0 11 6w3d17h Establ
+ inet.0: 4/5/1
+ inet6.0: 0/0/0
+
+ or
+
+ 192.0.2.100 65551 1269381 1363320 0 1 9w5d6h 2/3/0 0/0/0
+ -->
+ <values>
+ <!-- here we reuse the line pattern, only we pull out different group values -->
+ <value id="remoteIp" group="1"><![CDATA[{QUERY-LINE}]]></value>
+ <value id="uptime" group="8"><![CDATA[{QUERY-LINE}]]></value>
+
+ <!-- here we check for values in the inet* lines and use these -->
+ <value id="activeV4" group="1"><![CDATA[{inet4}]]></value>
+ <value id="receivedV4" group="2"><![CDATA[{inet4}]]></value>
+ <value id="accepted_V4" group="3"><![CDATA[{inet4}]]></value>
+
+ <value id="activeV6" group="1"><![CDATA[{inet6}]]></value>
+ <value id="receivedV6" group="2"><![CDATA[{inet6}]]></value>
+ <value id="accepted_V6" group="3"><![CDATA[{inet6}]]></value>
+
+ <!--
+ here we check for values at the end of the query line, and use these
+ NOTE: since we only set non-null values, these will not overwrite any values set above
+ -->
+ <value id="activeV4" group="9"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="receivedV4" group="10"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="accepted_V4" group="11"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="activeV6" group="12"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="receivedV6" group="13"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="accepted_V6" group="14"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+
+ </values>
+</config>
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/app/examples/templates/accesslog/combined-access.ftl b/freemarker-generator-cli/src/app/examples/templates/accesslog/combined-access.ftl
index 944a826..28f7f71 100644
--- a/freemarker-generator-cli/src/app/examples/templates/accesslog/combined-access.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/accesslog/combined-access.ftl
@@ -16,7 +16,7 @@
under the License.
-->
<#assign grok = tools.grok.create("%{COMBINEDAPACHELOG}")>
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign lines = dataSource.getLineIterator()>
<#compress>
diff --git a/freemarker-generator-cli/src/app/examples/templates/csv/csv/gatling-user-credentials.ftl b/freemarker-generator-cli/src/app/examples/templates/csv/csv/gatling-user-credentials.ftl
index aae83f4..46d505b 100644
--- a/freemarker-generator-cli/src/app/examples/templates/csv/csv/gatling-user-credentials.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/csv/csv/gatling-user-credentials.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign cvsFormat = tools.csv.formats.DEFAULT.withDelimiter(';')>
<#assign csvParser = tools.csv.parse(dataSource, cvsFormat)>
<#assign csvRecords = csvParser.records>
diff --git a/freemarker-generator-cli/src/app/examples/templates/csv/fo/transactions.ftl b/freemarker-generator-cli/src/app/examples/templates/csv/fo/transactions.ftl
index 9a513ca..089790f 100644
--- a/freemarker-generator-cli/src/app/examples/templates/csv/fo/transactions.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/csv/fo/transactions.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign name = dataSource.name>
<#assign cvsFormat = tools.csv.formats.DEFAULT.withDelimiter('\t').withHeader()>
<#assign csvParser = tools.csv.parse(dataSource, cvsFormat)>
diff --git a/freemarker-generator-cli/src/app/examples/templates/csv/fo/transform.ftl b/freemarker-generator-cli/src/app/examples/templates/csv/fo/transform.ftl
index 7e77af2..8f49b72 100644
--- a/freemarker-generator-cli/src/app/examples/templates/csv/fo/transform.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/csv/fo/transform.ftl
@@ -17,7 +17,7 @@
-->
<#assign csvFormatName = CVS_IN_FORMAT!"DEFAULT">
<#assign cvsFormat = tools.csv.formats[csvFormatName].withHeader()>
-<#assign csvParser = tools.csv.parse(dataSources?values[0], cvsFormat)>
+<#assign csvParser = tools.csv.parse(dataSources[0], cvsFormat)>
<#assign csvHeaders = csvParser.getHeaderMap()?keys>
<#assign csvRecords = csvParser.records>
<#--------------------------------------------------------------------------->
diff --git a/freemarker-generator-cli/src/app/examples/templates/csv/html/transactions.ftl b/freemarker-generator-cli/src/app/examples/templates/csv/html/transactions.ftl
index 030cd82..c2eaa05 100644
--- a/freemarker-generator-cli/src/app/examples/templates/csv/html/transactions.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/csv/html/transactions.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign name = dataSource.name>
<#assign cvsFormat = tools.csv.formats.DEFAULT.withDelimiter('\t').withHeader()>
<#assign csvParser = tools.csv.parse(dataSource, cvsFormat)>
diff --git a/freemarker-generator-cli/src/app/examples/templates/csv/md/filter.ftl b/freemarker-generator-cli/src/app/examples/templates/csv/md/filter.ftl
index 49beb57..acec8b3 100644
--- a/freemarker-generator-cli/src/app/examples/templates/csv/md/filter.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/csv/md/filter.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign parser = parser(dataSource)>
<#assign headers = parser.getHeaderNames()>
<#assign column = tools.system.getParameter("column")>
diff --git a/freemarker-generator-cli/src/app/examples/templates/csv/shell/curl.ftl b/freemarker-generator-cli/src/app/examples/templates/csv/shell/curl.ftl
index 114dd4f..4a18ecf 100644
--- a/freemarker-generator-cli/src/app/examples/templates/csv/shell/curl.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/csv/shell/curl.ftl
@@ -16,7 +16,7 @@
under the License.
-->
<#assign cvsFormat = tools.csv.formats.DEFAULT.withHeader()>
-<#assign csvParser = tools.csv.parse(dataSources?values[0], cvsFormat)>
+<#assign csvParser = tools.csv.parse(dataSources[0], cvsFormat)>
<#assign records = csvParser.records>
<#assign csvMap = tools.csv.toMap(records, "disposer")>
<#--------------------------------------------------------------------------->
diff --git a/freemarker-generator-cli/src/app/examples/templates/dataframe/example.ftl b/freemarker-generator-cli/src/app/examples/templates/dataframe/example.ftl
index 3b154ea..7cbf309 100644
--- a/freemarker-generator-cli/src/app/examples/templates/dataframe/example.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/dataframe/example.ftl
@@ -14,7 +14,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign csvParser = tools.csv.parse(dataSource, tools.csv.formats.DATAFRAME)>
<#assign users = tools.dataframe.fromCSVParser(csvParser)>
diff --git a/freemarker-generator-cli/src/app/examples/templates/dataframe/html/print.ftl b/freemarker-generator-cli/src/app/examples/templates/dataframe/html/print.ftl
index 3ae73c8..82343b8 100644
--- a/freemarker-generator-cli/src/app/examples/templates/dataframe/html/print.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/dataframe/html/print.ftl
@@ -16,7 +16,7 @@
under the License.
-->
<#assign cvsFormat = tools.csv.formats.DEFAULT.withHeader().withDelimiter(';')>
-<#assign csvParser = tools.csv.parse(dataSources?values[0], cvsFormat)>
+<#assign csvParser = tools.csv.parse(dataSources[0], cvsFormat)>
<#assign dataFrame = tools.dataframe.toDataFrame(csvParser)>
<#--------------------------------------------------------------------------->
<!DOCTYPE html>
diff --git a/freemarker-generator-cli/src/app/examples/templates/datasources.ftl b/freemarker-generator-cli/src/app/examples/templates/datasources.ftl
index 84e8bb3..e00e76a 100644
--- a/freemarker-generator-cli/src/app/examples/templates/datasources.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/datasources.ftl
@@ -1,79 +1,112 @@
-<#ftl output_format="plainText">
<#--
- 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.
+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.
-->
-Support FreeMarker Directives
+Support Of FreeMarker Directives
==============================================================================
-has_content: ${dataSources?has_content?c}
-size: ${dataSources?size}
+dataSources?has_content: ${dataSources?has_content?c}
+dataSources?size: ${dataSources?size}
-Use FTL Array-style Access
+Iterate Over DataSources Using Array-style Access
==============================================================================
-${dataSources?values[0].name}
-${dataSources?values?first.name}
+<#if dataSources?has_content>
+<#list 0..<dataSources?size as i>
+- dataSource[${i}] ==> ${dataSources[i].name}
+</#list>
+<#else>
+No data sources provided ...
+</#if>
-Get Document Names As Keys
+Iterate Over DataSources Using Sequence
==============================================================================
-<#list dataSources?keys as name>
- ${name}<#lt>
+<#list dataSources as dataSource>
+- dataSource[${dataSource?index}] => ${dataSource.name}
+<#else>
+No data sources provided ...
</#list>
-Iterate Over Names & DataSources
+Iterate Over DataSources Using Key & Values
==============================================================================
<#list dataSources as name, dataSource>
- ${name} => ${dataSource.uri}<#lt>
-</#list>
-
-<#list dataSources?values>
- <#items as dataSource>
- <@writeDataSource dataSource/>
- </#items>
+- dataSource["${name}"] => ${dataSource.name}<#lt>
<#else>
- No data sources found ...
+No data sources provided ...
</#list>
-<#macro writeDataSource dataSource>
+Iterate Over DataSources Using Values
+==============================================================================
+<#list dataSources?values as dataSource>
+- dataSource[${dataSource?index}] => ${dataSource.name}
+<#else>
+No data sources provided ...
+</#list>
-${dataSource.name}
+Iterate Over DataSources Using Hash Map Keys
+==============================================================================
+<#list dataSources?keys as key>
+- dataSource["${key}"] => ${dataSources[key].name}
+<#else>
+No data sources provided ...
+</#list>
+
+Iterate Over DataSources Using Local Lambda Expression
+==============================================================================
+<#list dataSources?filter(ds -> ds.match("group", "default")) as dataSource>
+- Group "default" => ${dataSource.name}
+<#else>
+No data sources provided ...
+</#list>
+
+Iterate Over DataSources Using Wildcard Search
+==============================================================================
+<#list dataSources?api.findByName("*") as dataSource>
+- ${dataSource.name}
+<#else>
+No data sources provided ...
+</#list>
+
+Access Underlying DataSources API
+==============================================================================
+DataSources.getNames(): ${dataSources?api.names?size}
+DataSources.getGroups(): ${dataSources?api.getGroups()?size}
+DataSources.find("name", "*"): ${dataSources?api.find("name", "*")?size}
+DataSources.find("name", "!readme"): ${dataSources?api.find("name", "!readme")?size}
+DataSources.find("uri", "*.md"): ${dataSources?api.find("uri", "*.md")?size}
+DataSources.find("extension", "md"): ${dataSources?api.find("extension", "md")?size}
+
+<#if dataSources?has_content>
+<#list dataSources as dataSource>
+[#${dataSource?counter}] - ${dataSource.name}
==============================================================================
Invoke Arbitrary Methods On DataSource
---------------------------------------------------------------------------
-<#assign dataSource=dataSources?values?first>
-Name : ${dataSource.name}
-Group : ${dataSource.group}
-Nr of lines : ${dataSource.lines?size}
-ContentType : ${dataSource.contentType}
-MimeType : ${dataSource.mimeType}
-Charset : ${dataSource.charset}
-Extension : ${dataSource.extension}
-Nr of chars : ${dataSource.text?length}
-Nr of bytes : ${dataSource.bytes?size}
-File name : ${dataSource.fileName}
-URI schema : ${dataSource.uri.scheme}
+<#assign dataSource=dataSources?first>
+Name : ${dataSource.name}
+Nr of lines : ${dataSource.lines?size}
+Content Type : ${dataSource.contentType}
+Charset : ${dataSource.charset}
+Extension : ${dataSource.extension}
+Nr of chars : ${dataSource.text?length}
+Nr of bytes : ${dataSource.bytes?size}
Iterating Over Metadata Of A Datasource
---------------------------------------------------------------------------
<#list dataSource.metadata as name, value>
-${name?right_pad(15)} : ${value}
+${name?right_pad(19)} : ${value}
</#list>
-Iterating Over Properties Of A Datasource
----------------------------------------------------------------------------
-<#list dataSource.properties as name, value>
-${name?right_pad(15)} : ${value}
</#list>
-</#macro>
+</#if>
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/app/examples/templates/demo.ftl b/freemarker-generator-cli/src/app/examples/templates/demo.ftl
index d929fe2..2217e2b 100644
--- a/freemarker-generator-cli/src/app/examples/templates/demo.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/demo.ftl
@@ -49,7 +49,7 @@
6) Display list of data sources
---------------------------------------------------------------------------
List all data sources:
-<#list dataSources?values as dataSource>
+<#list dataSources as dataSource>
- Document: name=${dataSource.name} uri=${dataSource.uri} length=${dataSource.length} charset=${dataSource.charset}
</#list>
@@ -107,22 +107,22 @@
- ${dataSources?size}
<#if dataSources?has_content>
Get the first data source:
-- ${dataSources?values[0].name!"No data sources provided"}
+- ${dataSources[0].name!"No data sources provided"}
</#if>
Get all documents as map:
<#list dataSources as name, ds>
- ${name} => ${ds.mimeType}
</#list>
List all data sources containing "test" in the name
-<#list dataSources?values?filter(ds -> ds.match("name", "*test*")) as ds>
+<#list dataSources?filter(ds -> ds.match("name", "*test*")) as ds>
- ${ds.name}
</#list>
List all data sources having "json" extension
-<#list dataSources?values?filter(ds -> ds.match("extension", "json")) as ds>
+<#list dataSources?filter(ds -> ds.match("extension", "json")) as ds>
- ${ds.name}
</#list>
List all data sources having "src/test/data/properties" in their file path
-<#list dataSources?values?filter(ds -> ds.match("filepath", "*/src/test/data/properties")) as ds>
+<#list dataSources?filter(ds -> ds.match("filePath", "*/src/test/data/properties")) as ds>
- ${ds.name}
</#list>
diff --git a/freemarker-generator-cli/src/app/examples/templates/excel/csv/custom.ftl b/freemarker-generator-cli/src/app/examples/templates/excel/csv/custom.ftl
index 1e2bd06..59ca407 100644
--- a/freemarker-generator-cli/src/app/examples/templates/excel/csv/custom.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/excel/csv/custom.ftl
@@ -18,7 +18,7 @@
<#assign format = CSV_TARGET_FORMAT!"DEFAULT">
<#assign salt = tools.system.parameters.salt!"salt">
<#-- Parse the first data source & sheet of the Excel document -->
-<#assign workbook = tools.excel.parse(dataSources?values[0])>
+<#assign workbook = tools.excel.parse(dataSources[0])>
<#assign sheet = tools.excel.getSheets(workbook)[0]>
<#assign records = tools.excel.toTable(sheet)>
<#-- Setup CSVPrinter -->
diff --git a/freemarker-generator-cli/src/app/examples/templates/excel/dataframe/transform.ftl b/freemarker-generator-cli/src/app/examples/templates/excel/dataframe/transform.ftl
index 5b24903..bd5252c 100644
--- a/freemarker-generator-cli/src/app/examples/templates/excel/dataframe/transform.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/excel/dataframe/transform.ftl
@@ -14,7 +14,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign workbook = tools.excel.parse(dataSource)>
<#list tools.excel.getSheets(workbook) as sheet>
<#assign table = tools.excel.toTable(sheet)>
diff --git a/freemarker-generator-cli/src/app/examples/templates/html/csv/dependencies.ftl b/freemarker-generator-cli/src/app/examples/templates/html/csv/dependencies.ftl
index 51fe17e..4c2e2de 100644
--- a/freemarker-generator-cli/src/app/examples/templates/html/csv/dependencies.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/html/csv/dependencies.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign name = dataSource.name>
<#assign html = tools.jsoup.parse(dataSource)>
diff --git a/freemarker-generator-cli/src/app/examples/templates/html/txt/licence.ftl b/freemarker-generator-cli/src/app/examples/templates/html/txt/licence.ftl
index 2807493..d503011 100644
--- a/freemarker-generator-cli/src/app/examples/templates/html/txt/licence.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/html/txt/licence.ftl
@@ -17,7 +17,7 @@
<#--
FreeMarker template to create a LICENCE file.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign html = tools.jsoup.parse(dataSource)>
<#assign dataframe = tools.dataframe.create()
.addStringColumn("GroupId")
diff --git a/freemarker-generator-cli/src/app/examples/templates/javafaker/csv/testdata.ftl b/freemarker-generator-cli/src/app/examples/templates/javafaker/csv/testdata.ftl
index 1976644..0c6418e 100644
--- a/freemarker-generator-cli/src/app/examples/templates/javafaker/csv/testdata.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/javafaker/csv/testdata.ftl
@@ -16,7 +16,7 @@
-->
<#-- Get a localized JavaFaker instance -->
<#assign faker = tools.javafaker.getFaker("de_DE")>
-<#assign nrOfRecords = tools.system.getString("NR_OF_RECORDS","100")>
+<#assign nrOfRecords = tools.system.getProperty("NR_OF_RECORDS","100")>
<#assign days = tools.javafaker.timeUnits["DAYS"]>
<#assign csvTargetFormat = tools.csv.formats["DEFAULT"].withFirstRecordAsHeader()>
<#assign csvPrinter = tools.csv.printer(csvTargetFormat)>
diff --git a/freemarker-generator-cli/src/app/examples/templates/json/csv/swagger-endpoints.ftl b/freemarker-generator-cli/src/app/examples/templates/json/csv/swagger-endpoints.ftl
index 6ab4ce2..a70286c 100644
--- a/freemarker-generator-cli/src/app/examples/templates/json/csv/swagger-endpoints.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/json/csv/swagger-endpoints.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign map = tools.gson.parse(dataSources?values[0])>
+<#assign map = tools.gson.parse(dataSources[0])>
<#assign basePath = map.basePath!"/">
<#assign paths = map.paths!{}>
diff --git a/freemarker-generator-cli/src/app/examples/templates/json/dataframe/github-users.ftl b/freemarker-generator-cli/src/app/examples/templates/json/dataframe/github-users.ftl
index 480f59a..49c21c2 100644
--- a/freemarker-generator-cli/src/app/examples/templates/json/dataframe/github-users.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/json/dataframe/github-users.ftl
@@ -15,6 +15,6 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign json = tools.gson.parse(dataSources?values[0])>
+<#assign json = tools.gson.parse(dataSources[0])>
<#assign dataframe = tools.dataframe.fromMaps(json)>
${tools.dataframe.print(dataframe)}
diff --git a/freemarker-generator-cli/src/app/examples/templates/json/md/github-users.ftl b/freemarker-generator-cli/src/app/examples/templates/json/md/github-users.ftl
index a83d07b..39b37a2 100644
--- a/freemarker-generator-cli/src/app/examples/templates/json/md/github-users.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/json/md/github-users.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign json = tools.jsonpath.parse(dataSources?values[0])>
+<#assign json = tools.jsonpath.parse(dataSources[0])>
<#assign users = json.read("$[*]")>
<#--------------------------------------------------------------------------->
# GitHub Users
diff --git a/freemarker-generator-cli/src/app/examples/templates/logs/csv/serverlog-to-csv.ftl b/freemarker-generator-cli/src/app/examples/templates/logs/csv/serverlog-to-csv.ftl
index 544975f..d53e24f 100644
--- a/freemarker-generator-cli/src/app/examples/templates/logs/csv/serverlog-to-csv.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/logs/csv/serverlog-to-csv.ftl
@@ -35,7 +35,7 @@
<#compress>
TIMESTAMP;MILLIS
<#if dataSources?has_content>
- <#list dataSources?values as dataSource>
+ <#list dataSources as dataSource>
<#list dataSource.getLineIterator() as line>
<#assign parts = grok.match(line).capture()>
<#if parts?has_content>
diff --git a/freemarker-generator-cli/src/app/examples/templates/nginx/confluence/nginx-config-parser.ftl b/freemarker-generator-cli/src/app/examples/templates/nginx/confluence/nginx-config-parser.ftl
new file mode 100644
index 0000000..79331a5
--- /dev/null
+++ b/freemarker-generator-cli/src/app/examples/templates/nginx/confluence/nginx-config-parser.ftl
@@ -0,0 +1,34 @@
+<#compress>
+ || FILE || SERVER || ACCESSLOG || SPLUNK ||
+ <#list dataSources as dataSource>
+ <#assign fileName = dataSource.fileName>
+ <#assign serverName = "N.A">
+ <#-- Transform to a single line to avoid matching OS-specific line endings -->
+ <#assign text = dataSource.getText()?replace("\r", "")?replace("\n", " ")>
+ <#assign accessLog = getAccessLog(text)>
+ <#assign serverName = getServerName(text)>
+ | ${fileName} | ${serverName} | ${accessLog} | [${splunkSearchUrl(accessLog)}] |
+ </#list>
+</#compress>
+<#--------------------------------------------------------------------------->
+<#function splunkSearchUrl accessLog>
+ <#return "https://splunk.p.santanderconsumer.at/en-US/app/scbdevteam/search?q=search%20source%3D%22${accessLog?url}%22">
+</#function>
+<#--------------------------------------------------------------------------->
+<#function getAccessLog text>
+ <#assign matches = text?matches(r".*access_log\s*([\w\.\-\/\\]*);.*")>
+ <#if matches>
+ <#return matches?groups[1]?trim>
+ <#else>
+ <#return "N.A.">
+ </#if>
+</#function>
+<#--------------------------------------------------------------------------->
+<#function getServerName text>
+ <#assign matches = text?matches(r".*server_name\s*([\w\.\-\\]*);.*")>
+ <#if matches>
+ <#return matches?groups[1]?trim>
+ <#else>
+ <#return "N.A.">
+ </#if>
+</#function>
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/app/examples/templates/properties/csv/locker-test-users.ftl b/freemarker-generator-cli/src/app/examples/templates/properties/csv/locker-test-users.ftl
index 8e01dac..32dd5d6 100644
--- a/freemarker-generator-cli/src/app/examples/templates/properties/csv/locker-test-users.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/properties/csv/locker-test-users.ftl
@@ -17,7 +17,7 @@
-->
<#compress>
TENANT,SITE,USER_ID,DISPOSER_ID,PASSWORD,SMS_OTP,NAME,DESCRIPTION
- <#list dataSources?values as dataSource>
+ <#list dataSources as dataSource>
<#assign properties = tools.properties.parse(dataSource)>
<#assign environments = properties.ENVIRONMENTS!"">
<#assign tenant = extractTenant(environments)>
diff --git a/freemarker-generator-cli/src/app/examples/templates/tsv/fo/transactions.ftl b/freemarker-generator-cli/src/app/examples/templates/tsv/fo/transactions.ftl
index 5beefc3..46a89de 100644
--- a/freemarker-generator-cli/src/app/examples/templates/tsv/fo/transactions.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/tsv/fo/transactions.ftl
@@ -16,7 +16,7 @@
under the License.
-->
<#assign cvsFormat = tools.csv.formats.TDF.withHeader()>
-<#assign csvParser = tools.csv.parse(dataSources?values[0], cvsFormat)>
+<#assign csvParser = tools.csv.parse(dataSources[0], cvsFormat)>
<#assign csvHeaders = csvParser.getHeaderMap()?keys>
<#assign csvRecords = csvParser.records>
<#--------------------------------------------------------------------------->
diff --git a/freemarker-generator-cli/src/app/examples/templates/utahparser/csv/transform.ftl b/freemarker-generator-cli/src/app/examples/templates/utahparser/csv/transform.ftl
new file mode 100644
index 0000000..f67729c
--- /dev/null
+++ b/freemarker-generator-cli/src/app/examples/templates/utahparser/csv/transform.ftl
@@ -0,0 +1,32 @@
+<#--
+ 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.
+-->
+<#-- Setup Utah-Parser and parse all records to determine the headers -->
+<#assign conf = tools.utahparser.getConfig(dataSources[0])>
+<#assign parser = tools.utahparser.getParser(conf, dataSources[1])>
+<#assign records = parser.toList()>
+<#assign headers = tools.utahparser.getHeaders(records)>
+<#-- Setup CSVPrinter -->
+<#assign defaultCsvformat = tools.csv.formats[CSV_TARGET_FORMAT!"DEFAULT"]>
+<#assign csvDelimiter = tools.csv.toDelimiter(CSV_TARGET_DELIMITER!defaultCsvformat.getDelimiter())>
+<#assign cvsFormat = defaultCsvformat.withHeader(headers).withDelimiter(csvDelimiter)>
+<#assign csvPrinter = tools.csv.printer(cvsFormat)>
+<#-- Print records as CSV -->
+<#compress>
+ <#list records as record>
+ ${csvPrinter.printRecord(record, headers)}
+ </#list>
+</#compress>
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/app/examples/templates/utahparser/json/transform.ftl b/freemarker-generator-cli/src/app/examples/templates/utahparser/json/transform.ftl
new file mode 100644
index 0000000..4c2a53e
--- /dev/null
+++ b/freemarker-generator-cli/src/app/examples/templates/utahparser/json/transform.ftl
@@ -0,0 +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.
+-->
+<#assign conf = tools.utahparser.getConfig(dataSources[0])>
+<#assign parser = tools.utahparser.getParser(conf, dataSources[1])>
+${tools.gson.toJson(parser.toList())}
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/app/examples/templates/xml/txt/recipients.ftl b/freemarker-generator-cli/src/app/examples/templates/xml/txt/recipients.ftl
index b67e8e7..83bf4e5 100644
--- a/freemarker-generator-cli/src/app/examples/templates/xml/txt/recipients.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/xml/txt/recipients.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign xml = tools.xml.parse(dataSources?values[0])>
+<#assign xml = tools.xml.parse(dataSources[0])>
<#list xml.recipients.person as recipient>
To: ${recipient.name}
${recipient.address}
diff --git a/freemarker-generator-cli/src/app/examples/templates/yaml/txt/transform.ftl b/freemarker-generator-cli/src/app/examples/templates/yaml/txt/transform.ftl
index ebcf525..1e13504 100644
--- a/freemarker-generator-cli/src/app/examples/templates/yaml/txt/transform.ftl
+++ b/freemarker-generator-cli/src/app/examples/templates/yaml/txt/transform.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign map = tools.yaml.parse(dataSources?values[0])>
+<#assign map = tools.yaml.parse(dataSources[0])>
<#--------------------------------------------------------------------------->
<#compress>
<@print map 1/>
diff --git a/freemarker-generator-cli/src/app/scripts/run-examples.bat b/freemarker-generator-cli/src/app/scripts/run-examples.bat
index 5467382..a55395d 100644
--- a/freemarker-generator-cli/src/app/scripts/run-examples.bat
+++ b/freemarker-generator-cli/src/app/scripts/run-examples.bat
@@ -51,17 +51,20 @@
REM Interactive Mode
REM =========================================================================
-%FREEMARKER_CMD% -i '${tools.jsonpath.parse(dataSources?values[0]).read("""$.info.title""")}' examples\data\json\swagger-spec.json > target\out\interactive-json.txt
-%FREEMARKER_CMD% -i '${tools.xml.parse(dataSources?values[0])["""recipients/person[1]/name"""]}' examples\data\xml\recipients.xml > target\out\interactive-xml.txt
-%FREEMARKER_CMD% -i '${tools.jsoup.parse(dataSources?values[0]).select("""a""")[0]}' examples\data\html\dependencies.html > target\out\interactive-html.txt
-%FREEMARKER_CMD% -i '${tools.gson.toJson(tools.yaml.parse(dataSources?values[0]))}' examples\data\yaml\swagger-spec.yaml > target\out\interactive-swagger.json
-%FREEMARKER_CMD% -i '${tools.yaml.toYaml(tools.gson.parse(dataSources?values[0]))}' examples\data\json\swagger-spec.json > target\out\interactive-swagger.yaml
-%FREEMARKER_CMD% -i '${tools.dataframe.print(tools.dataframe.fromMaps(tools.gson.parse(dataSources?values[0])))}' examples\data\json\github-users.json > target\out\interactive-dataframe.txt
+%FREEMARKER_CMD% -i '${tools.jsonpath.parse(dataSources[0]).read("""$.info.title""")}' examples\data\json\swagger-spec.json > target\out\interactive-json.txt
+%FREEMARKER_CMD% -i '${tools.xml.parse(dataSources[0])["""recipients/person[1]/name"""]}' examples\data\xml\recipients.xml > target\out\interactive-xml.txt
+%FREEMARKER_CMD% -i '${tools.jsoup.parse(dataSources[0]).select("""a""")[0]}' examples\data\html\dependencies.html > target\out\interactive-html.txt
+%FREEMARKER_CMD% -i '${tools.gson.toJson(tools.yaml.parse(dataSources[0]))}' examples\data\yaml\swagger-spec.yaml > target\out\interactive-swagger.json
+%FREEMARKER_CMD% -i '${tools.yaml.toYaml(tools.gson.parse(dataSources[0]))}' examples\data\json\swagger-spec.json > target\out\interactive-swagger.yaml
+%FREEMARKER_CMD% -i '${tools.dataframe.print(tools.dataframe.fromMaps(tools.gson.parse(dataSources[0])))}' examples\data\json\github-users.json > target\out\interactive-dataframe.txt
REM =========================================================================
REM CSV
REM =========================================================================
+echo "templates\freemarker-generator\csv\confluence\transform.ftl"
+%FREEMARKER_CMD% -t freemarker-generator\csv\confluence\transform.ftl examples\data\csv\contract.csv > target\out\contract.txt
+
echo "templates\freemarker-generator\csv\html\transform.ftl"
%FREEMARKER_CMD% -t freemarker-generator\csv\html\transform.ftl examples\data\csv\contract.csv > target\out\contract.html
@@ -159,6 +162,13 @@
%FREEMARKER_CMD% -t examples\templates\json\md\github-users.ftl examples\data\json\github-users.json > target\out\github-users.md
REM =========================================================================
+REM NGINX
+REM =========================================================================
+
+echo "examples\templates\nginx\confluence\nginx-config-parser.ftl"
+%FREEMARKER_CMD% -t examples\templates\nginx\confluence\nginx-config-parser.ftl -s examples\data\nginx > target\out\nginx-config.txt
+
+REM =========================================================================
REM Properties
REM =========================================================================
@@ -173,6 +183,16 @@
%FREEMARKER_CMD% -t examples\data\template -PNGINX_HOSTNAME=localhost -o target\out\template
REM =========================================================================
+REM Utah Parser
+REM =========================================================================
+
+echo "examples\templates\utahparser\csv\transform.ftl"
+%FREEMARKER_CMD% -PCSV_TARGET_FORMAT=EXCEL -PCSV_TARGET_DELIMITER=SEMICOLON -t examples\templates\utahparser\csv\transform.ftl examples\data\text\utahparser\juniper_bgp_summary_template.xml examples\data\text\utahparser\juniper_bgp_summary_example.txt -o target\out\utahparserjuniper_bgp_summary_example.csv
+
+echo "examples\templates\utahparser\json\transform.ftl"
+%FREEMARKER_CMD% -t examples\templates\utahparser\json\transform.ftl examples\data\text\utahparser\juniper_bgp_summary_template.xml examples\data\text\utahparser\juniper_bgp_summary_example.txt -o target\out\utahparser\uniper_bgp_summary_example.json
+
+REM =========================================================================
REM XML
REM =========================================================================
@@ -189,5 +209,15 @@
echo "templates\freemarker-generator\yaml\json\transform.ftl"
%FREEMARKER_CMD% -t freemarker-generator\yaml\json\transform.ftl examples\data\yaml\swagger-spec.yaml > target\out\swagger-spec.json
+REM =========================================================================
+REM DataSource Seeding
+REM =========================================================================
+
+echo "examples\data\csv"
+%FREEMARKER_CMD% --seed=datasource --template freemarker-generator\csv\html\transform.ftl --output target\out\datasource\csv --output-mapper="*.html" examples\data\csv
+
+echo "examples\data\csv"
+%FREEMARKER_CMD% --seed=datasource --template freemarker-generator\csv\html\transform.ftl --data-source . --data-source-include="*.csv" --output target\out\datasource\csv --output-mapper="*.html"
+
echo "Created the following sample files in .\target\out"
dir .\target\out
diff --git a/freemarker-generator-cli/src/app/scripts/run-examples.sh b/freemarker-generator-cli/src/app/scripts/run-examples.sh
index 1fce8b7..9bc5d81 100755
--- a/freemarker-generator-cli/src/app/scripts/run-examples.sh
+++ b/freemarker-generator-cli/src/app/scripts/run-examples.sh
@@ -56,17 +56,20 @@
# Interactive Mode
#############################################################################
-$FREEMARKER_CMD -i '${tools.jsonpath.parse(dataSources?values[0]).read("$.info.title")}' examples/data/json/swagger-spec.json > target/out/interactive-json.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
-$FREEMARKER_CMD -i '${tools.xml.parse(dataSources?values[0])["recipients/person[1]/name"]}' examples/data/xml/recipients.xml > target/out/interactive-xml.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
-$FREEMARKER_CMD -i '${tools.jsoup.parse(dataSources?values[0]).select("a")[0]}' examples/data/html/dependencies.html > target/out/interactive-html.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
-$FREEMARKER_CMD -i '${tools.gson.toJson(tools.yaml.parse(dataSources?values[0]))}' examples/data/yaml/swagger-spec.yaml > target/out/interactive-swagger.json || { echo >&2 "Test failed. Aborting."; exit 1; }
-$FREEMARKER_CMD -i '${tools.yaml.toYaml(tools.gson.parse(dataSources?values[0]))}' examples/data/json/swagger-spec.json > target/out/interactive-swagger.yaml || { echo >&2 "Test failed. Aborting."; exit 1; }
-$FREEMARKER_CMD -i '${tools.dataframe.print(tools.dataframe.fromMaps(tools.gson.parse(dataSources?values[0])))}' examples/data/json/github-users.json > target/out/interactive-dataframe.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
+$FREEMARKER_CMD -i '${tools.jsonpath.parse(dataSources[0]).read("$.info.title")}' examples/data/json/swagger-spec.json > target/out/interactive-json.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
+$FREEMARKER_CMD -i '${tools.xml.parse(dataSources[0])["recipients/person[1]/name"]}' examples/data/xml/recipients.xml > target/out/interactive-xml.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
+$FREEMARKER_CMD -i '${tools.jsoup.parse(dataSources[0]).select("a")[0]}' examples/data/html/dependencies.html > target/out/interactive-html.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
+$FREEMARKER_CMD -i '${tools.gson.toJson(tools.yaml.parse(dataSources[0]))}' examples/data/yaml/swagger-spec.yaml > target/out/interactive-swagger.json || { echo >&2 "Test failed. Aborting."; exit 1; }
+$FREEMARKER_CMD -i '${tools.yaml.toYaml(tools.gson.parse(dataSources[0]))}' examples/data/json/swagger-spec.json > target/out/interactive-swagger.yaml || { echo >&2 "Test failed. Aborting."; exit 1; }
+$FREEMARKER_CMD -i '${tools.dataframe.print(tools.dataframe.fromMaps(tools.gson.parse(dataSources[0])))}' examples/data/json/github-users.json > target/out/interactive-dataframe.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
#############################################################################
# CSV
#############################################################################
+echo "templates/freemarker-generator/csv/confluence/transform.ftl"
+$FREEMARKER_CMD -t freemarker-generator/csv/confluence/transform.ftl examples/data/csv/contract.csv > target/out/contract.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
+
echo "templates/freemarker-generator/csv/html/transform.ftl"
$FREEMARKER_CMD -t freemarker-generator/csv/html/transform.ftl examples/data/csv/contract.csv > target/out/contract.html || { echo >&2 "Test failed. Aborting."; exit 1; }
@@ -180,6 +183,13 @@
$FREEMARKER_CMD -t examples/templates/json/md/github-users.ftl examples/data/json/github-users.json > target/out/github-users.md || { echo >&2 "Test failed. Aborting."; exit 1; }
#############################################################################
+# NGINX
+#############################################################################
+
+echo "examples/templates/nginx/confluence/nginx-config-parser.ftl"
+$FREEMARKER_CMD -t examples/templates/nginx/confluence/nginx-config-parser.ftl -s examples/data/nginx > target/out/nginx-config.txt || { echo >&2 "Test failed. Aborting."; exit 1; }
+
+#############################################################################
# Properties
#############################################################################
@@ -194,6 +204,16 @@
$FREEMARKER_CMD -t examples/data/template -PNGINX_HOSTNAME=localhost -o target/out/template || { echo >&2 "Test failed. Aborting."; exit 1; }
#############################################################################
+# Utah Parser
+#############################################################################
+
+echo "examples/templates/utahparser/csv/transform.ftl"
+$FREEMARKER_CMD -PCSV_TARGET_FORMAT=EXCEL -PCSV_TARGET_DELIMITER=SEMICOLON -t examples/templates/utahparser/csv/transform.ftl examples/data/text/utahparser/juniper_bgp_summary_template.xml examples/data/text/utahparser/juniper_bgp_summary_example.txt -o target/out/utahparserjuniper_bgp_summary_example.csv || { echo >&2 "Test failed. Aborting."; exit 1; }
+
+echo "examples/templates/utahparser/json/transform.ftl"
+$FREEMARKER_CMD -t examples/templates/utahparser/json/transform.ftl examples/data/text/utahparser/juniper_bgp_summary_template.xml examples/data/text/utahparser/juniper_bgp_summary_example.txt -o target/out/utahparser/juniper_bgp_summary_example.json || { echo >&2 "Test failed. Aborting."; exit 1; }
+
+#############################################################################
# XML
#############################################################################
@@ -210,5 +230,15 @@
echo "templates/freemarker-generator/yaml/json/transform.ftl"
$FREEMARKER_CMD -t freemarker-generator/yaml/json/transform.ftl examples/data/yaml/swagger-spec.yaml > target/out/swagger-spec.json || { echo >&2 "Test failed. Aborting."; exit 1; }
+#############################################################################
+# DataSource Seeding
+#############################################################################
+
+echo "examples/data/csv"
+$FREEMARKER_CMD --seed=datasource --template freemarker-generator/csv/html/transform.ftl --output target/out/datasource/csv --output-mapper="*.html" examples/data/csv
+
+echo "examples/data/csv"
+$FREEMARKER_CMD --seed=datasource --template freemarker-generator/csv/html/transform.ftl --data-source . --data-source-include="*.csv" --output target/out/datasource/csv --output-mapper="*.html"
+
echo "Created the following sample files in ./target/out"
ls -l ./target/out
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/cat.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/cat.ftl
index cdbe0fa..f4f82e8 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/cat.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/cat.ftl
@@ -14,7 +14,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#list dataSources?values as dataSource>
+<#list dataSources as dataSource>
<#list dataSource.lineIterator as line>
${line}
</#list>
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/confluence/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/confluence/transform.ftl
new file mode 100644
index 0000000..35857db
--- /dev/null
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/confluence/transform.ftl
@@ -0,0 +1,40 @@
+<#--
+ 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.
+-->
+<#import "/freemarker-generator/lib/commons-csv.ftl" as csv />
+<#assign dataSource = dataSources[0]>
+<#assign csvParser = tools.csv.parse(dataSource, csv.sourceFormat())>
+<#assign headers = (csvParser.getHeaderMap()!{})?keys>
+<#assign records = csvParser.records>
+<#--------------------------------------------------------------------------->
+<#compress>
+ <@writeHeaders headers/>
+ <@writeColums records/>
+</#compress>
+<#--------------------------------------------------------------------------->
+<#macro writeHeaders headers>
+ <#if headers?has_content>
+ || ${headers?join(" || ", "")} ||
+ </#if>
+</#macro>
+<#--------------------------------------------------------------------------->
+<#macro writeColums columns>
+ <#if columns?has_content>
+ <#list columns as column>
+ | ${column.iterator()?join(" | ", "")} |
+ </#list>
+ </#if>
+</#macro>
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/csv/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/csv/transform.ftl
index 3941c4c..c999235 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/csv/transform.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/csv/transform.ftl
@@ -16,7 +16,7 @@
under the License.
-->
<#import "/freemarker-generator/lib/commons-csv.ftl" as csv />
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign csvParser = tools.csv.parse(dataSource, csv.sourceFormat())>
<#assign csvTargetFormat = csv.targetFormat()>
<#assign csvPrinter = tools.csv.printer(csvTargetFormat)>
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/html/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/html/transform.ftl
index d027672..e39a76d 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/html/transform.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/html/transform.ftl
@@ -16,7 +16,7 @@
under the License.
-->
<#import "/freemarker-generator/lib/commons-csv.ftl" as csv />
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign csvParser = tools.csv.parse(dataSource, csv.sourceFormat())>
<#assign csvHeaders = csvParser.getHeaderNames()>
<#--------------------------------------------------------------------------->
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/md/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/md/transform.ftl
index 6929b31..edd8b3e 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/md/transform.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/csv/md/transform.ftl
@@ -15,7 +15,7 @@
under the License.
-->
<#import "/freemarker-generator/lib/commons-csv.ftl" as csv />
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign csvParser = tools.csv.parse(dataSource, csv.sourceFormat())>
<#assign headers = (csvParser.getHeaderMap()!{})?keys>
<#assign records = csvParser.records>
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/csv/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/csv/transform.ftl
index 18179f4..22dec59 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/csv/transform.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/csv/transform.ftl
@@ -17,7 +17,7 @@
-->
<#-- Parse the first data source & sheet of the Excel document -->
<#import "/freemarker-generator/lib/commons-csv.ftl" as csv />
-<#assign workbook = tools.excel.parse(dataSources?values[0])>
+<#assign workbook = tools.excel.parse(dataSources[0])>
<#assign sheet = tools.excel.getSheets(workbook)[0]>
<#assign records = tools.excel.toTable(sheet)>
<#-- Setup CSVPrinter -->
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/html/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/html/transform.ftl
index 7564751..e1e9409 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/html/transform.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/html/transform.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign name = dataSource.name>
<#assign workbook = tools.excel.parse(dataSource)>
<#assign date = .now?iso_utc>
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/md/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/md/transform.ftl
index e3fb970..a0e13b7 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/md/transform.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/excel/md/transform.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign name = dataSource.name>
<#assign workbook = tools.excel.parse(dataSource)>
<#assign date = .now?iso_utc>
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/info.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/info.ftl
index c165be3..0a3f0ce 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/info.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/info.ftl
@@ -1,4 +1,3 @@
-<#ftl output_format="plainText" strip_whitespace=true>
<#--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
@@ -16,40 +15,66 @@
under the License.
-->
FreeMarker Generator Information
-------------------------------------------------------------------------------
+==============================================================================
+
FreeMarker version : ${.version}
Template name : ${.current_template_name}
Language : ${.lang}
Locale : ${.locale}
Timestamp : ${.now}
+Time zone : ${.now?string["z"]}
Output encoding : ${.output_encoding}
Output format : ${.output_format}
+FreeMarker Command-line Parameters
+==============================================================================
+
+<#list tools.system.getCommandLineArgs() as arg>
+[#${arg?counter}] ${arg}
+</#list>
+
FreeMarker Generator Template Loader Directories
-------------------------------------------------------------------------------
+==============================================================================
+
<#list tools.system.getTemplateDirectories() as directory>
[#${directory?counter}] ${directory}
</#list>
FreeMarker Generator Data Model
----------------------------------------------------------------------------
+==============================================================================
+
<#list .data_model?keys?sort as key>
- ${key}<#lt>
</#list>
-FreeMarker Generator DataSources
-------------------------------------------------------------------------------
+FreeMarker Generator Data Sources
+==============================================================================
<#if dataSources?has_content>
-<#list dataSources?values as ds>
-[#${ds?counter}]: name=${ds.name}, group=${ds.group}, fileName=${ds.fileName}, mimeType=${ds.mimeType}, charset=${ds.charset}, length=${ds.length} Bytes
-URI : ${ds.uri}
+<#list dataSources as dataSource>
+
+DataSource #${dataSource?counter}
+------------------------------------------------------------------------------
+name : ${dataSource.name}
+group : ${dataSource.group}
+contentType : ${dataSource.contentType}
+fileName : ${dataSource.fileName}
+baseName : ${dataSource.baseName}
+extension : ${dataSource.extension}
+relativeFilePath : ${dataSource.relativeFilePath}
+charset : ${dataSource.charset}
+mimeType : ${dataSource.mimeType}
+uri : ${dataSource.uri}
+length : ${dataSource.length} bytes
+metadata : ${dataSource.metadata?size} entries
</#list>
<#else>
+
No data sources found ...
</#if>
FreeMarker Generator Parameters
-------------------------------------------------------------------------------
+==============================================================================
+
<#if tools.system.parameters?has_content>
<#list tools.system.parameters as key,value>
<#if value?is_hash>
@@ -63,7 +88,8 @@
</#if>
FreeMarker Generator Tools
-------------------------------------------------------------------------------
+==============================================================================
+
<#list tools?keys?sort as name>
-- ${name?right_pad(20)} : ${tools[name]}
+- ${name?right_pad(19)} : ${tools[name]}
</#list>
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/json/yaml/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/json/yaml/transform.ftl
index 6e48945..d5b32f9 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/json/yaml/transform.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/json/yaml/transform.ftl
@@ -14,4 +14,4 @@
specific language governing permissions and limitations
under the License.
-->
-${tools.yaml.toYaml(tools.gson.parse(dataSources?values[0]))}
\ No newline at end of file
+${tools.yaml.toYaml(tools.gson.parse(dataSources[0]))}
\ No newline at end of file
diff --git a/freemarker-generator-cli/src/app/templates/freemarker-generator/yaml/json/transform.ftl b/freemarker-generator-cli/src/app/templates/freemarker-generator/yaml/json/transform.ftl
index 81a704a..d0f0581 100644
--- a/freemarker-generator-cli/src/app/templates/freemarker-generator/yaml/json/transform.ftl
+++ b/freemarker-generator-cli/src/app/templates/freemarker-generator/yaml/json/transform.ftl
@@ -14,4 +14,4 @@
specific language governing permissions and limitations
under the License.
-->
-${tools.gson.toJson(tools.yaml.parse(dataSources?values[0]))}
\ No newline at end of file
+${tools.gson.toJson(tools.yaml.parse(dataSources[0]))}
\ No newline at end of file
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 5158668..7c9c4d9 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
@@ -140,15 +140,14 @@
@Override
public Integer call() {
- validate();
+ validateCommandLineParameters();
+ updateGlobalSystemProperties();
return IntStream.range(0, times).map(i -> onCall()).max().orElse(0);
}
private Integer onCall() {
- updateSystemProperties();
-
final String currentConfigFile = isNotEmpty(configFile) ? configFile : getDefaultConfigFileName();
- final Properties configuration = loadFreeMarkerCliConfiguration(currentConfigFile);
+ final Properties configuration = loadFreeMarkerGeneratorConfiguration(currentConfigFile);
final List<File> templateDirectories = getTemplateDirectories(templateDir);
final Settings settings = settings(configuration, templateDirectories, outputGeneratorDefinitions);
@@ -166,7 +165,11 @@
}
}
- void validate() {
+ /**
+ * Invoke a custom validation of the command line parameters supplementing
+ * the checks already done by Picocli.
+ */
+ void validateCommandLineParameters() {
outputGeneratorDefinitions.forEach(t -> t.validate(spec.commandLine()));
}
@@ -195,7 +198,7 @@
.build();
}
- private void updateSystemProperties() {
+ private void updateGlobalSystemProperties() {
if (systemProperties != null && !systemProperties.isEmpty()) {
System.getProperties().putAll(systemProperties);
}
@@ -203,7 +206,7 @@
/**
* Data sources can be passed via command line option and/or
- * positional parameter so we need to merge them.
+ * positional parameter, so we need to merge them.
*
* @return List of data sources
*/
@@ -226,7 +229,7 @@
return isNotEmpty(appHome) ? new File(appHome, Configuration.CONFIG_FILE_NAME).getAbsolutePath() : null;
}
- private static Properties loadFreeMarkerCliConfiguration(String fileName) {
+ private static Properties loadFreeMarkerGeneratorConfiguration(String fileName) {
if (isEmpty(fileName)) {
return new Properties();
}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplier.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplier.java
index 593f7f7..a54f98d 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplier.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplier.java
@@ -20,6 +20,7 @@
import freemarker.template.Configuration;
import freemarker.template.Version;
import org.apache.freemarker.generator.base.util.PropertiesTransformer;
+import org.apache.freemarker.generator.cli.wrapper.FreeMarkerGeneratorObjectWrapper;
import java.util.Properties;
import java.util.function.Supplier;
@@ -50,6 +51,10 @@
try {
final Configuration configuration = new Configuration(FREEMARKER_VERSION);
+ // support a custom "DataSourcesAdaptor"
+ configuration.setAPIBuiltinEnabled(true);
+ configuration.setObjectWrapper(new FreeMarkerGeneratorObjectWrapper(configuration.getIncompatibleImprovements()));
+
// apply all "freemarker.configuration.setting" values
configuration.setSettings(freeMarkerConfigurationSettings());
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/DataModelSupplier.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/DataModelSupplier.java
index 57591d6..6cc81d0 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/DataModelSupplier.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/DataModelSupplier.java
@@ -16,6 +16,7 @@
*/
package org.apache.freemarker.generator.cli.config;
+import org.apache.commons.io.FilenameUtils;
import org.apache.freemarker.generator.base.datasource.DataSource;
import org.apache.freemarker.generator.base.datasource.DataSourceLoader;
import org.apache.freemarker.generator.base.datasource.DataSourceLoaderFactory;
@@ -79,15 +80,22 @@
if (contentType.startsWith(MIME_APPLICATION_JSON)) {
return fromJson(dataSource, isExplodedDataModel);
+ } else if (isYamlDataSource(dataSource)) {
+ return fromYaml(dataSource, isExplodedDataModel);
} else if (contentType.startsWith(MIME_TEXT_PLAIN)) {
return fromProperties(dataSource, isExplodedDataModel);
- } else if (contentType.startsWith(MIME_TEXT_YAML)) {
- return fromYaml(dataSource, isExplodedDataModel);
} else {
throw new IllegalArgumentException("Don't know how to handle content type: " + contentType);
}
}
+ private static boolean isYamlDataSource(DataSource dataSource) {
+ final String contentType = dataSource.getContentType();
+ final String extension = FilenameUtils.getExtension(dataSource.getUri().toString());
+ return contentType.startsWith(MIME_TEXT_YAML)
+ || (contentType.startsWith(MIME_TEXT_PLAIN)) && "yaml".equalsIgnoreCase(extension);
+ }
+
private static Map<String, Object> fromJson(DataSource dataSource, boolean isExplodedDataModel) {
final GsonTool gsonTool = new GsonTool();
final Object json = gsonTool.parse(dataSource);
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/OutputGeneratorsSupplier.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/OutputGeneratorsSupplier.java
index 059a9ab..e1b11b1 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/OutputGeneratorsSupplier.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/OutputGeneratorsSupplier.java
@@ -16,127 +16,46 @@
*/
package org.apache.freemarker.generator.cli.config;
-import org.apache.freemarker.generator.base.FreeMarkerConstants.Location;
-import org.apache.freemarker.generator.base.datasource.DataSource;
-import org.apache.freemarker.generator.base.datasource.DataSourceFactory;
-import org.apache.freemarker.generator.base.datasource.DataSourcesSupplier;
+import org.apache.freemarker.generator.base.FreeMarkerConstants.SeedType;
import org.apache.freemarker.generator.base.output.OutputGenerator;
-import org.apache.freemarker.generator.base.template.TemplateTransformation;
-import org.apache.freemarker.generator.base.template.TemplateTransformationsBuilder;
-import org.apache.freemarker.generator.base.util.UriUtils;
+import org.apache.freemarker.generator.cli.config.output.DataSourceSeedingOutputGenerator;
+import org.apache.freemarker.generator.cli.config.output.TemplateSeedingOutputGenerator;
import org.apache.freemarker.generator.cli.picocli.OutputGeneratorDefinition;
-import org.apache.freemarker.generator.cli.picocli.TemplateOutputDefinition;
-import org.apache.freemarker.generator.cli.picocli.TemplateSourceDefinition;
-import java.net.URI;
-import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
-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.mime.Mimetypes.MIME_TEXT_PLAIN;
+/**
+ * Supplies a list of <code>OutputGenerators</code> based on the user input.
+ */
public class OutputGeneratorsSupplier implements Supplier<List<OutputGenerator>> {
private final Settings settings;
public OutputGeneratorsSupplier(Settings settings) {
- this.settings = settings;
+ this.settings = requireNonNull(settings);
}
@Override
public List<OutputGenerator> get() {
return settings.getOutputGeneratorDefinitions().stream()
- .map(this::outputGenerator)
+ .map(definition -> outputGenerator(settings, definition))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
- private List<OutputGenerator> outputGenerator(OutputGeneratorDefinition definition) {
- final List<OutputGenerator> result = new ArrayList<>();
- final TemplateSourceDefinition templateSourceDefinition = requireNonNull(definition.getTemplateSourceDefinition());
- final TemplateOutputDefinition templateOutputDefinition = definition.getTemplateOutputDefinition();
- final TemplateTransformationsBuilder builder = TemplateTransformationsBuilder.builder();
-
- // set the template
- if (templateSourceDefinition.isInteractiveTemplate()) {
- builder.setInteractiveTemplate(templateSourceDefinition.interactiveTemplate);
+ private List<OutputGenerator> outputGenerator(Settings settings, OutputGeneratorDefinition definition) {
+ final String seedType = definition.getOutputSeedType();
+ if (SeedType.TEMPLATE.equalsIgnoreCase(seedType)) {
+ return new TemplateSeedingOutputGenerator(settings).apply(definition);
+ } else if (SeedType.DATASOURCE.equalsIgnoreCase(seedType)) {
+ return new DataSourceSeedingOutputGenerator(settings).apply(definition);
} else {
- builder.setTemplateSource(templateSourceDefinition.template);
+ throw new RuntimeException("Unknown seed type:" + seedType);
}
-
- // set encoding of loaded templates
- builder.setTemplateEncoding(settings.getTemplateEncoding());
-
- // set the writer
- builder.setCallerSuppliedWriter(settings.getCallerSuppliedWriter());
-
- // set template output
- if (templateOutputDefinition != null && templateOutputDefinition.hasOutput()) {
- builder.setOutput(templateOutputDefinition.outputs.get(0));
- }
-
- // set the output encoding
- builder.setOutputEncoding(settings.getOutputEncoding());
-
- // set template filter
- if (definition.hasTemplateSourceIncludes()) {
- builder.addInclude(definition.getTemplateSourceFilterDefinition().templateIncludePatterns.get(0));
- }
-
- if (definition.hasTemplateSourceExcludes()) {
- builder.addExclude(definition.getTemplateSourceFilterDefinition().templateExcludePatterns.get(0));
- }
-
- final List<TemplateTransformation> templateTransformations = builder.build();
-
- for (TemplateTransformation templateTransformation : templateTransformations) {
- final OutputGenerator outputGenerator = new OutputGenerator(
- templateTransformation.getTemplateSource(),
- templateTransformation.getTemplateOutput(),
- dataSources(settings, definition),
- dataModels(definition)
- );
- result.add(outputGenerator);
- }
-
- return result;
- }
-
- private List<DataSource> dataSources(Settings settings, OutputGeneratorDefinition outputGeneratorDefinition) {
- final ArrayList<DataSource> result = new ArrayList<>();
-
- // Add optional data source from STDIN at the start of the list since
- // this allows easy sequence slicing in FreeMarker.
- if (settings.isReadFromStdin()) {
- result.add(0, stdinDataSource());
- }
-
- final DataSourcesSupplier outputGeneratorDataSourcesSupplier = new DataSourcesSupplier(
- outputGeneratorDefinition.getDataSources(),
- settings.getSourceIncludePattern(),
- settings.getSourceExcludePattern(),
- settings.getInputEncoding()
- );
-
- result.addAll(outputGeneratorDataSourcesSupplier.get());
-
- return result;
- }
-
- private Map<String, Object> dataModels(OutputGeneratorDefinition outputGeneratorDefinition) {
- return new DataModelSupplier(outputGeneratorDefinition.getDataModels()).get();
- }
-
- private static DataSource stdinDataSource() {
- final URI uri = UriUtils.toUri(Location.SYSTEM, STDIN);
- return DataSourceFactory.fromInputStream(STDIN, DEFAULT_GROUP, uri, System.in, MIME_TEXT_PLAIN, UTF_8, new HashMap<>());
}
}
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 c45a479..d699a8d 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
@@ -16,6 +16,7 @@
*/
package org.apache.freemarker.generator.cli.config;
+import org.apache.freemarker.generator.base.FreeMarkerConstants;
import org.apache.freemarker.generator.base.FreeMarkerConstants.Model;
import org.apache.freemarker.generator.base.util.LocaleUtils;
import org.apache.freemarker.generator.base.util.NonClosableWriterWrapper;
@@ -36,8 +37,6 @@
import static java.util.Collections.emptyList;
import static java.util.Objects.requireNonNull;
import static org.apache.freemarker.generator.base.FreeMarkerConstants.Configuration.LOCALE_KEY;
-import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_CHARSET;
-import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_LOCALE;
/**
* Capture all the settings required for rendering a FreeMarker template.
@@ -65,11 +64,11 @@
/** List of additional shared data models */
private final List<String> sharedDataModels;
- /** Include pattern for sources */
- private final String sourceIncludePattern;
+ /** Global include pattern for data sources */
+ private final String dataSourceIncludePattern;
- /** Exclude pattern for sources */
- private final String sourceExcludePattern;
+ /** Global exclude pattern for data sources */
+ private final String dataSourceExcludePattern;
/** Encoding of input files */
private final Charset inputEncoding;
@@ -86,10 +85,10 @@
/** Read from stdin? */
private final boolean isReadFromStdin;
- /** User-supplied parameters */
+ /** User-supplied parameters available for template processing */
private final Map<String, Object> userParameters;
- /** User-supplied system properties */
+ /** User-supplied properties to be copied to global system properties */
private final Properties userSystemProperties;
/** Caller-supplied writer */
@@ -103,8 +102,8 @@
List<OutputGeneratorDefinition> outputGeneratorDefinitions,
List<String> sharedDataSources,
List<String> sharedDataModels,
- String sourceIncludePattern,
- String sourceExcludePattern,
+ String dataSourceIncludePattern,
+ String dataSourceExcludePattern,
Charset inputEncoding,
Charset outputEncoding,
boolean verbose,
@@ -120,8 +119,8 @@
this.outputGeneratorDefinitions = requireNonNull(outputGeneratorDefinitions);
this.sharedDataSources = requireNonNull(sharedDataSources);
this.sharedDataModels = requireNonNull(sharedDataModels);
- this.sourceIncludePattern = sourceIncludePattern;
- this.sourceExcludePattern = sourceExcludePattern;
+ this.dataSourceIncludePattern = dataSourceIncludePattern;
+ this.dataSourceExcludePattern = dataSourceExcludePattern;
this.inputEncoding = inputEncoding;
this.outputEncoding = outputEncoding;
this.verbose = verbose;
@@ -161,12 +160,12 @@
return sharedDataModels;
}
- public String getSourceIncludePattern() {
- return sourceIncludePattern;
+ public String getDataSourceIncludePattern() {
+ return dataSourceIncludePattern;
}
- public String getSourceExcludePattern() {
- return sourceExcludePattern;
+ public String getDataSourceExcludePattern() {
+ return dataSourceExcludePattern;
}
public Charset getInputEncoding() {
@@ -231,8 +230,8 @@
", outputGeneratorDefinitions=" + outputGeneratorDefinitions +
", sharedDataSources=" + sharedDataSources +
", sharedDataModels=" + sharedDataModels +
- ", sourceIncludePattern='" + sourceIncludePattern + '\'' +
- ", sourceExcludePattern='" + sourceExcludePattern + '\'' +
+ ", dataSourceIncludePattern='" + dataSourceIncludePattern +
+ ", dataSourceExcludePattern='" + dataSourceExcludePattern +
", inputEncoding=" + inputEncoding +
", outputEncoding=" + outputEncoding +
", verbose=" + verbose +
@@ -275,11 +274,11 @@
this.sourceIncludePattern = null;
this.sourceExcludePattern = null;
this.configuration = new Properties();
- this.locale = DEFAULT_LOCALE.toString();
+ this.locale = FreeMarkerConstants.DEFAULT_LOCALE.toString();
this.parameters = new HashMap<>();
this.systemProperties = new Properties();
- this.setInputEncoding(DEFAULT_CHARSET.name());
- this.setOutputEncoding(DEFAULT_CHARSET.name());
+ this.setInputEncoding(FreeMarkerConstants.DEFAULT_CHARSET.name());
+ this.setOutputEncoding(FreeMarkerConstants.DEFAULT_CHARSET.name());
}
public SettingsBuilder setCommandLineArgs(String[] args) {
@@ -406,7 +405,7 @@
private String getDefaultLocale() {
return configuration.getProperty(
LOCALE_KEY,
- System.getProperty(LOCALE_KEY, DEFAULT_LOCALE.toString()));
+ System.getProperty(LOCALE_KEY, FreeMarkerConstants.DEFAULT_LOCALE.toString()));
}
}
}
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 ab3681e..310744a 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
@@ -48,8 +48,8 @@
public static DataSourcesSupplier sharedDataSourcesSupplier(Settings settings) {
return new DataSourcesSupplier(settings.getSharedDataSources(),
- settings.getSourceIncludePattern(),
- settings.getSourceExcludePattern(),
+ settings.getDataSourceIncludePattern(),
+ settings.getDataSourceExcludePattern(),
settings.getInputEncoding());
}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/AbstractOutputGenerator.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/AbstractOutputGenerator.java
new file mode 100644
index 0000000..81f9633
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/AbstractOutputGenerator.java
@@ -0,0 +1,80 @@
+/*
+ * 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.config.output;
+
+import org.apache.freemarker.generator.base.FreeMarkerConstants.Location;
+import org.apache.freemarker.generator.base.datasource.DataSource;
+import org.apache.freemarker.generator.base.datasource.DataSourceFactory;
+import org.apache.freemarker.generator.base.datasource.DataSourcesSupplier;
+import org.apache.freemarker.generator.base.util.NonClosableWriterWrapper;
+import org.apache.freemarker.generator.base.util.UriUtils;
+import org.apache.freemarker.generator.cli.config.DataModelSupplier;
+import org.apache.freemarker.generator.cli.config.Settings;
+import org.apache.freemarker.generator.cli.picocli.OutputGeneratorDefinition;
+
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.net.URI;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+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.mime.Mimetypes.MIME_TEXT_PLAIN;
+
+public abstract class AbstractOutputGenerator {
+
+ protected List<DataSource> dataSources(Settings settings, OutputGeneratorDefinition outputGeneratorDefinition) {
+ final ArrayList<DataSource> result = new ArrayList<>();
+
+ // Add optional data source from STDIN at the start of the list since
+ // this allows easy sequence slicing in FreeMarker.
+ if (settings.isReadFromStdin()) {
+ result.add(0, stdinDataSource());
+ }
+
+ final DataSourcesSupplier outputGeneratorDataSourcesSupplier = new DataSourcesSupplier(
+ outputGeneratorDefinition.getDataSources(),
+ settings.getDataSourceIncludePattern(),
+ settings.getDataSourceExcludePattern(),
+ settings.getInputEncoding()
+ );
+
+ result.addAll(outputGeneratorDataSourcesSupplier.get());
+
+ return result;
+ }
+
+ protected Map<String, Object> dataModels(OutputGeneratorDefinition outputGeneratorDefinition) {
+ return new DataModelSupplier(outputGeneratorDefinition.getDataModels()).get();
+ }
+
+ protected Writer stdoutWriter(Charset outputEncoding) {
+ // avoid closing System.out after rendering the template
+ return new BufferedWriter(new NonClosableWriterWrapper(new OutputStreamWriter(System.out, outputEncoding)));
+ }
+
+ private static DataSource stdinDataSource() {
+ final URI uri = UriUtils.toUri(Location.SYSTEM, STDIN);
+ return DataSourceFactory.fromInputStream(STDIN, DEFAULT_GROUP, uri, System.in, MIME_TEXT_PLAIN, UTF_8, new HashMap<>());
+ }
+}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputGenerator.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputGenerator.java
new file mode 100644
index 0000000..fc9a418
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputGenerator.java
@@ -0,0 +1,112 @@
+/*
+ * 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.config.output;
+
+import org.apache.freemarker.generator.base.datasource.DataSource;
+import org.apache.freemarker.generator.base.output.OutputGenerator;
+import org.apache.freemarker.generator.base.output.OutputGenerator.SeedType;
+import org.apache.freemarker.generator.base.template.TemplateOutput;
+import org.apache.freemarker.generator.base.template.TemplateSource;
+import org.apache.freemarker.generator.base.util.ListUtils;
+import org.apache.freemarker.generator.base.util.Validate;
+import org.apache.freemarker.generator.cli.config.Settings;
+import org.apache.freemarker.generator.cli.config.Suppliers;
+import org.apache.freemarker.generator.cli.picocli.OutputGeneratorDefinition;
+import org.apache.freemarker.generator.cli.picocli.TemplateOutputDefinition;
+import org.apache.freemarker.generator.cli.picocli.TemplateSourceDefinition;
+import org.apache.freemarker.generator.cli.util.TemplateSourceFactory;
+
+import java.io.File;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+
+import static java.util.Collections.singletonList;
+
+/**
+ * Generates an <code>OutputGenerator</code> per <code>DataSource</code>.
+ */
+public class DataSourceSeedingOutputGenerator
+ extends AbstractOutputGenerator
+ implements Function<OutputGeneratorDefinition, List<OutputGenerator>> {
+
+ private final Settings settings;
+
+ public DataSourceSeedingOutputGenerator(Settings settings) {
+ this.settings = settings;
+ }
+
+ @Override
+ public List<OutputGenerator> apply(OutputGeneratorDefinition outputGeneratorDefinition) {
+ Validate.notNull(outputGeneratorDefinition, "outputGeneratorDefinition must not be null");
+
+ final List<OutputGenerator> result = new ArrayList<>();
+ final TemplateSourceDefinition templateSourceDefinition = outputGeneratorDefinition.getTemplateSourceDefinition();
+ final TemplateOutputDefinition templateOutputDefinition = outputGeneratorDefinition.getTemplateOutputDefinition();
+ final Map<String, Object> dataModels = super.dataModels(outputGeneratorDefinition);
+ final List<DataSource> dataSources = super.dataSources(settings, outputGeneratorDefinition);
+ final List<DataSource> sharedDataSources = Suppliers.sharedDataSourcesSupplier(settings).get();
+ final List<DataSource> combinedDataSources = ListUtils.concatenate(dataSources, sharedDataSources);
+ final TemplateSource templateSource = TemplateSourceFactory.create(templateSourceDefinition, settings.getTemplateEncoding());
+ final DataSourceSeedingOutputMapper outputMapper = outputMapper(outputGeneratorDefinition.getOutputMapper());
+
+ for (DataSource dataSource : combinedDataSources) {
+ final TemplateOutput templateOutput = templateOutput(templateOutputDefinition, settings, dataSource, outputMapper);
+ final OutputGenerator outputGenerator = new OutputGenerator(
+ templateSource,
+ templateOutput,
+ singletonList(dataSource),
+ dataModels,
+ SeedType.DATASOURCE
+ );
+ result.add(outputGenerator);
+ }
+
+ return result;
+ }
+
+ private TemplateOutput templateOutput(TemplateOutputDefinition templateOutputDefinition, Settings settings, DataSource dataSource, DataSourceSeedingOutputMapper outputMapper) {
+ final Charset outputEncoding = settings.getOutputEncoding();
+ final File templateOutputFile = templateOutputFile(templateOutputDefinition, dataSource, outputMapper);
+ if (settings.getCallerSuppliedWriter() != null) {
+ return TemplateOutput.fromWriter(settings.getCallerSuppliedWriter());
+ } else if (templateOutputFile != null) {
+ return TemplateOutput.fromFile(templateOutputFile, outputEncoding);
+ } else {
+ return TemplateOutput.fromWriter(stdoutWriter(outputEncoding));
+ }
+ }
+
+ private File templateOutputFile(
+ TemplateOutputDefinition templateOutputDefinition,
+ DataSource dataSource,
+ DataSourceSeedingOutputMapper outputMapper) {
+
+ if (templateOutputDefinition == null || !templateOutputDefinition.hasOutput()) {
+ return null;
+ }
+
+ final File outputDirectory = new File(templateOutputDefinition.outputs.get(0));
+ return outputMapper.map(outputDirectory, dataSource);
+ }
+
+ private DataSourceSeedingOutputMapper outputMapper(String template) {
+ return new DataSourceSeedingOutputMapper(template);
+ }
+}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputMapper.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputMapper.java
new file mode 100644
index 0000000..43d56d5
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputMapper.java
@@ -0,0 +1,58 @@
+/*
+ * 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.config.output;
+
+import org.apache.freemarker.generator.base.datasource.DataSource;
+
+import java.io.File;
+
+import static org.apache.freemarker.generator.base.util.StringUtils.firstNonEmpty;
+import static org.apache.freemarker.generator.base.util.StringUtils.isEmpty;
+
+public class DataSourceSeedingOutputMapper {
+
+ private final String template;
+
+ public DataSourceSeedingOutputMapper(String template) {
+ this.template = template;
+ }
+
+ public File map(File outputDirectory, DataSource dataSource) {
+ final String relativeFilePath = dataSource.getRelativeFilePath();
+ final String fileName = isEmpty(template) ? fromDataSource(dataSource) : fromTemplate(template, dataSource);
+
+ return isEmpty(relativeFilePath) ?
+ new File(outputDirectory, fileName) :
+ new File(new File(outputDirectory, relativeFilePath), fileName);
+ }
+
+ private static String fromTemplate(String value, DataSource dataSource) {
+ return value.replace("*", firstNonEmpty(dataSource.getBaseName(), dataSource.getName()));
+ }
+
+ private static String fromDataSource(DataSource dataSource) {
+ if (isEmpty(dataSource.getBaseName())) {
+ return dataSource.getName();
+ } else {
+ if (isEmpty(dataSource.getExtension())) {
+ return dataSource.getBaseName();
+ } else {
+ return dataSource.getBaseName() + "." + dataSource.getExtension();
+ }
+ }
+ }
+}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateSeedingOutputGenerator.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateSeedingOutputGenerator.java
new file mode 100644
index 0000000..8dfa8bb
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateSeedingOutputGenerator.java
@@ -0,0 +1,97 @@
+/*
+ * 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.config.output;
+
+import org.apache.freemarker.generator.base.output.OutputGenerator;
+import org.apache.freemarker.generator.base.output.OutputGenerator.SeedType;
+import org.apache.freemarker.generator.cli.config.Settings;
+import org.apache.freemarker.generator.cli.picocli.OutputGeneratorDefinition;
+import org.apache.freemarker.generator.cli.picocli.TemplateOutputDefinition;
+import org.apache.freemarker.generator.cli.picocli.TemplateSourceDefinition;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Function;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Generates an <code>OutputGenerator</code> per <code>Template</code>.
+ */
+public class TemplateSeedingOutputGenerator
+ extends AbstractOutputGenerator
+ implements Function<OutputGeneratorDefinition, List<OutputGenerator>> {
+
+ private final Settings settings;
+
+ public TemplateSeedingOutputGenerator(Settings settings) {
+ this.settings = requireNonNull(settings);
+ }
+
+ @Override
+ public List<OutputGenerator> apply(OutputGeneratorDefinition definition) {
+ final List<OutputGenerator> result = new ArrayList<>();
+ final TemplateSourceDefinition templateSourceDefinition = requireNonNull(definition.getTemplateSourceDefinition());
+ final TemplateOutputDefinition templateOutputDefinition = definition.getTemplateOutputDefinition();
+ final TemplateTransformationsBuilder builder = TemplateTransformationsBuilder.builder();
+
+ // set the template
+ if (templateSourceDefinition.isInteractiveTemplate()) {
+ builder.setInteractiveTemplate(templateSourceDefinition.interactiveTemplate);
+ } else {
+ builder.setTemplateSource(templateSourceDefinition.template);
+ }
+
+ // set encoding of loaded templates
+ builder.setTemplateEncoding(settings.getTemplateEncoding());
+
+ // set the writer
+ builder.setCallerSuppliedWriter(settings.getCallerSuppliedWriter());
+
+ // set template output
+ if (templateOutputDefinition != null && templateOutputDefinition.hasOutput()) {
+ builder.setOutput(templateOutputDefinition.outputs.get(0));
+ }
+
+ // set the output encoding
+ builder.setOutputEncoding(settings.getOutputEncoding());
+
+ // set template filter
+ if (definition.hasTemplateSourceIncludes()) {
+ builder.addInclude(definition.getTemplateSourceFilterDefinition().templateIncludePatterns.get(0));
+ }
+
+ if (definition.hasTemplateSourceExcludes()) {
+ builder.addExclude(definition.getTemplateSourceFilterDefinition().templateExcludePatterns.get(0));
+ }
+
+ final List<TemplateTransformation> templateTransformations = builder.build();
+
+ for (TemplateTransformation templateTransformation : templateTransformations) {
+ final OutputGenerator outputGenerator = new OutputGenerator(
+ templateTransformation.getTemplateSource(),
+ templateTransformation.getTemplateOutput(),
+ dataSources(settings, definition),
+ dataModels(definition),
+ SeedType.TEMPLATE
+ );
+ result.add(outputGenerator);
+ }
+
+ return result;
+ }
+}
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformation.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformation.java
similarity index 89%
rename from freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformation.java
rename to freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformation.java
index 6f0ed90..74a1522 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformation.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformation.java
@@ -14,7 +14,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.freemarker.generator.base.template;
+package org.apache.freemarker.generator.cli.config.output;
+
+import org.apache.freemarker.generator.base.template.TemplateOutput;
+import org.apache.freemarker.generator.base.template.TemplateSource;
import static java.util.Objects.requireNonNull;
diff --git a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformationsBuilder.java
similarity index 97%
rename from freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java
rename to freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformationsBuilder.java
index c9b0814..2e9d04b 100644
--- a/freemarker-generator-base/src/main/java/org/apache/freemarker/generator/base/template/TemplateTransformationsBuilder.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformationsBuilder.java
@@ -14,13 +14,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.freemarker.generator.base.template;
+package org.apache.freemarker.generator.cli.config.output;
import org.apache.freemarker.generator.base.FreeMarkerConstants.Location;
import org.apache.freemarker.generator.base.datasource.DataSource;
import org.apache.freemarker.generator.base.datasource.DataSourceLoader;
import org.apache.freemarker.generator.base.datasource.DataSourceLoaderFactory;
import org.apache.freemarker.generator.base.file.RecursiveFileSupplier;
+import org.apache.freemarker.generator.base.template.TemplateOutput;
+import org.apache.freemarker.generator.base.template.TemplateSource;
import org.apache.freemarker.generator.base.util.NonClosableWriterWrapper;
import org.apache.freemarker.generator.base.util.StringUtils;
import org.apache.freemarker.generator.base.util.Validate;
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/DataModelDefinition.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/DataModelDefinition.java
index 0c4ffcf..f586feb 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/DataModelDefinition.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/DataModelDefinition.java
@@ -27,4 +27,11 @@
@Option(names = { "-m", "--data-model" }, description = "data model used for rendering")
public List<String> dataModels;
+
+ @Override
+ public String toString() {
+ return "DataModelDefinition{" +
+ "dataModels=" + dataModels +
+ '}';
+ }
}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/DataSourceDefinition.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/DataSourceDefinition.java
index 61e9924..0adc292 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/DataSourceDefinition.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/DataSourceDefinition.java
@@ -27,4 +27,11 @@
@Option(names = { "-s", "--data-source" }, description = "data source used for rendering")
public List<String> dataSources;
+
+ @Override
+ public String toString() {
+ return "DataSourceDefinition{" +
+ "dataSources=" + dataSources +
+ '}';
+ }
}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/GitVersionProvider.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/GitVersionProvider.java
index bfa3f3d..ce8555e 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/GitVersionProvider.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/GitVersionProvider.java
@@ -53,4 +53,13 @@
}
return properties;
}
+
+ @Override
+ public String toString() {
+ return "GitVersionProvider{" +
+ "gitBuildVersion='" + gitBuildVersion + '\'' +
+ ", gitCommitId='" + gitCommitId + '\'' +
+ ", gitCommitTime='" + gitCommitTime + '\'' +
+ '}';
+ }
}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputGeneratorDefinition.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputGeneratorDefinition.java
index 532cf42..728d6a7 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputGeneratorDefinition.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputGeneratorDefinition.java
@@ -16,6 +16,7 @@
*/
package org.apache.freemarker.generator.cli.picocli;
+import org.apache.freemarker.generator.base.FreeMarkerConstants.SeedType;
import picocli.CommandLine;
import picocli.CommandLine.ArgGroup;
import picocli.CommandLine.ParameterException;
@@ -24,6 +25,9 @@
import static java.util.Collections.emptyList;
+/**
+ * Collects the setting for an output generator.
+ */
public class OutputGeneratorDefinition {
@ArgGroup(multiplicity = "1")
@@ -41,6 +45,12 @@
@ArgGroup(exclusive = false)
public DataModelDefinition dataModelDefinition;
+ @ArgGroup(exclusive = false)
+ public OutputSeedDefinition outputSeedDefinition;
+
+ @ArgGroup(exclusive = false)
+ public OutputMapperDefinition outputMapperDefinition;
+
public void validate(CommandLine commandLine) {
if (templateSourceDefinition == null) {
throw new ParameterException(commandLine, "No template defined to be rendered");
@@ -99,6 +109,31 @@
!getTemplateSourceFilterDefinition().templateExcludePatterns.isEmpty();
}
+ public String getOutputSeedType() {
+ if (outputSeedDefinition != null && outputSeedDefinition.type != null) {
+ return outputSeedDefinition.type;
+ } else {
+ return SeedType.TEMPLATE;
+ }
+ }
+
+ public String getOutputMapper() {
+ return (outputMapperDefinition != null) ? outputMapperDefinition.outputMapper : null;
+ }
+
+ @Override
+ public String toString() {
+ return "OutputGeneratorDefinition{" +
+ "templateSourceDefinition=" + templateSourceDefinition +
+ ", templateSourceFilterDefinition=" + templateSourceFilterDefinition +
+ ", templateOutputDefinition=" + templateOutputDefinition +
+ ", dataSourceDefinition=" + dataSourceDefinition +
+ ", dataModelDefinition=" + dataModelDefinition +
+ ", outputSeedDefinition=" + outputSeedDefinition +
+ ", outputMapperDefinition=" + outputMapperDefinition +
+ '}';
+ }
+
private static boolean isFileSource(String source) {
if (source.contains("file://")) {
return true;
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputMapperDefinition.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputMapperDefinition.java
new file mode 100644
index 0000000..c4bed1a
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputMapperDefinition.java
@@ -0,0 +1,32 @@
+/*
+ * 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.picocli;
+
+import picocli.CommandLine.Option;
+
+public class OutputMapperDefinition {
+
+ @Option(names = { "--output-mapper" }, description = "maps the name of the output file")
+ public String outputMapper;
+
+ @Override
+ public String toString() {
+ return "OutputMapperDefinition{" +
+ "outputMapper='" + outputMapper + '\'' +
+ '}';
+ }
+}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputSeedDefinition.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputSeedDefinition.java
new file mode 100644
index 0000000..50cea95
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/OutputSeedDefinition.java
@@ -0,0 +1,35 @@
+/*
+ * 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.picocli;
+
+import picocli.CommandLine.Option;
+
+/**
+ * Seeding of template output.
+ */
+public class OutputSeedDefinition {
+
+ @Option(names = { "--seed" }, defaultValue = "template", description = "seed mode: [template|datasource]")
+ public String type;
+
+ @Override
+ public String toString() {
+ return "OutputSeedDefinition{" +
+ "type='" + type + '\'' +
+ '}';
+ }
+}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateOutputDefinition.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateOutputDefinition.java
index 59627e3..3f3244f 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateOutputDefinition.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateOutputDefinition.java
@@ -28,4 +28,11 @@
public boolean hasOutput() {
return outputs != null && !outputs.isEmpty();
}
+
+ @Override
+ public String toString() {
+ return "TemplateOutputDefinition{" +
+ "outputs=" + outputs +
+ '}';
+ }
}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateSourceDefinition.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateSourceDefinition.java
index 6193c7b..0d35752 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateSourceDefinition.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateSourceDefinition.java
@@ -29,4 +29,12 @@
public boolean isInteractiveTemplate() {
return interactiveTemplate != null && !interactiveTemplate.isEmpty();
}
+
+ @Override
+ public String toString() {
+ return "TemplateSourceDefinition{" +
+ "template='" + template + '\'' +
+ ", interactiveTemplate='" + interactiveTemplate + '\'' +
+ '}';
+ }
}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateSourceFilterDefinition.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateSourceFilterDefinition.java
index 68cce4e..0a3bb4b 100644
--- a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateSourceFilterDefinition.java
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/picocli/TemplateSourceFilterDefinition.java
@@ -20,7 +20,9 @@
import java.util.List;
-/** Include/exclude pattern when processing template directories */
+/**
+ * Include/exclude pattern when processing template directories
+ */
public class TemplateSourceFilterDefinition {
@Option(names = { "--template-include" }, description = "template include pattern")
@@ -28,4 +30,12 @@
@Option(names = { "--template-exclude" }, description = "template exclude pattern")
public List<String> templateExcludePatterns;
+
+ @Override
+ public String toString() {
+ return "TemplateSourceFilterDefinition{" +
+ "templateIncludePatterns=" + templateIncludePatterns +
+ ", templateExcludePatterns=" + templateExcludePatterns +
+ '}';
+ }
}
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 4ae0377..8e158e4 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
@@ -23,8 +23,11 @@
import org.apache.freemarker.generator.base.datasource.DataSource;
import org.apache.freemarker.generator.base.datasource.DataSources;
import org.apache.freemarker.generator.base.output.OutputGenerator;
+import org.apache.freemarker.generator.base.output.OutputGenerator.SeedType;
import org.apache.freemarker.generator.base.template.TemplateOutput;
import org.apache.freemarker.generator.base.template.TemplateSource;
+import org.apache.freemarker.generator.base.util.ListUtils;
+import org.apache.freemarker.generator.base.util.Validate;
import java.io.BufferedWriter;
import java.io.File;
@@ -33,14 +36,11 @@
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.util.Arrays;
-import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Supplier;
-import java.util.stream.Collectors;
-import java.util.stream.Stream;
import static java.util.Objects.requireNonNull;
import static org.apache.freemarker.generator.base.FreeMarkerConstants.Model;
@@ -50,7 +50,7 @@
*/
public class FreeMarkerTask implements Callable<Integer> {
- private static final int SUCCESS = 0;
+ private static final int SUCCESS_CODE = 0;
private final Supplier<Configuration> configurationSupplier;
private final Supplier<List<OutputGenerator>> outputGeneratorsSupplier;
@@ -85,7 +85,7 @@
sharedDataSources,
sharedParameters));
- return SUCCESS;
+ return SUCCESS_CODE;
}
private void process(Configuration configuration,
@@ -102,22 +102,43 @@
try (Writer writer = writer(templateOutput)) {
final Template template = template(configuration, templateSource);
template.process(templateDataModel, writer);
- } catch (TemplateException | IOException e) {
+ } catch (TemplateException | IOException | RuntimeException e) {
throw new RuntimeException("Failed to process template: " + templateSource.getName(), e);
}
}
+ /**
+ * Merge the <code>DataSourced</code>.
+ * The data sources to be used are determined by the seed type
+ * <ul>
+ * <li>TEMPLATE: aggregates a list of data source</li>
+ * <li>DATASOURCE: only takes a single data source</li>
+ * </ul>
+ *
+ * @param outputGenerator current output generator
+ * @param sharedDataSources shared data sources
+ * @return <code>DataSources</code> to be passed to FreeMarker
+ */
private static DataSources toDataSources(OutputGenerator outputGenerator, List<DataSource> sharedDataSources) {
- return new DataSources(Stream.of(outputGenerator.getDataSources(), sharedDataSources)
- .flatMap(Collection::stream).collect(Collectors.toList()));
+ final List<DataSource> dataSources = outputGenerator.getDataSources();
+ final SeedType seedType = outputGenerator.getSeedType();
+
+ if (seedType == SeedType.TEMPLATE) {
+ return new DataSources(ListUtils.concatenate(dataSources, sharedDataSources));
+ } else if (seedType == SeedType.DATASOURCE) {
+ // Since every data source shall generate an output there can be only 1 datasource supplied.
+ Validate.isTrue(dataSources.size() == 1, "One data source expected for generation driven by data sources");
+ return new DataSources(dataSources);
+ } else {
+ throw new IllegalArgumentException("Don't know how to handle the seed type: " + seedType);
+ }
}
@SafeVarargs
private static Map<String, Object> toTemplateDataModel(DataSources dataSources, Map<String, Object>... maps) {
final Map<String, Object> result = new HashMap<>();
Arrays.stream(maps).forEach(result::putAll);
- // expose only the map and not the "DataSources" instance (see FREEMARKER-174)
- result.put(Model.DATASOURCES, dataSources.toMap());
+ result.put(Model.DATASOURCES, dataSources);
return result;
}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/util/TemplateSourceFactory.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/util/TemplateSourceFactory.java
new file mode 100644
index 0000000..606f57c
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/util/TemplateSourceFactory.java
@@ -0,0 +1,50 @@
+/*
+ * 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.util;
+
+import org.apache.freemarker.generator.base.FreeMarkerConstants.Location;
+import org.apache.freemarker.generator.base.datasource.DataSource;
+import org.apache.freemarker.generator.base.datasource.DataSourceLoader;
+import org.apache.freemarker.generator.base.datasource.DataSourceLoaderFactory;
+import org.apache.freemarker.generator.base.template.TemplateSource;
+import org.apache.freemarker.generator.base.util.Validate;
+import org.apache.freemarker.generator.cli.picocli.TemplateSourceDefinition;
+
+import java.io.File;
+import java.nio.charset.Charset;
+
+public class TemplateSourceFactory {
+
+ public static TemplateSource create(TemplateSourceDefinition templateSourceDefinition, Charset charset) {
+ Validate.notNull(templateSourceDefinition, "templateSourceDefinition must not be null");
+ Validate.notNull(charset, "charset must not be null");
+
+ final String template = templateSourceDefinition.template;
+ final DataSourceLoader dataSourceLoader = DataSourceLoaderFactory.create();
+
+ if (templateSourceDefinition.isInteractiveTemplate()) {
+ return TemplateSource.fromCode(Location.INTERACTIVE, templateSourceDefinition.interactiveTemplate);
+ } else if (new File(template).exists()) {
+ final String templateSource = templateSourceDefinition.template;
+ try (DataSource dataSource = dataSourceLoader.load(templateSource)) {
+ return TemplateSource.fromCode(dataSource.getName(), dataSource.getText(charset.name()));
+ }
+ } else {
+ return TemplateSource.fromPath(template, charset);
+ }
+ }
+}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/wrapper/DataSourcesAdapter.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/wrapper/DataSourcesAdapter.java
new file mode 100644
index 0000000..de25ed4
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/wrapper/DataSourcesAdapter.java
@@ -0,0 +1,115 @@
+/*
+ * 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.wrapper;
+
+import freemarker.ext.util.WrapperTemplateModel;
+import freemarker.template.AdapterTemplateModel;
+import freemarker.template.MapKeyValuePairIterator;
+import freemarker.template.ObjectWrapper;
+import freemarker.template.SimpleCollection;
+import freemarker.template.TemplateCollectionModel;
+import freemarker.template.TemplateHashModelEx2;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.TemplateModelWithAPISupport;
+import freemarker.template.TemplateSequenceModel;
+import freemarker.template.WrappingTemplateModel;
+import freemarker.template.utility.ObjectWrapperWithAPISupport;
+import org.apache.freemarker.generator.base.datasource.DataSources;
+
+import java.io.Serializable;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Wraps an instance of <code>DataSources</code> into a FreeMarker template model
+ * providing sequence and hash type access. If required the <code>DataSources</code>
+ * API can be accessed using FreeMarkers "?api" built-in.
+ */
+public class DataSourcesAdapter extends WrappingTemplateModel
+ implements TemplateHashModelEx2, AdapterTemplateModel, WrapperTemplateModel, TemplateModelWithAPISupport,
+ TemplateSequenceModel, Serializable {
+
+ /** Wrapped instance */
+ private final DataSources dataSources;
+
+ /**
+ * Factory method for creating new adapter instances.
+ *
+ * @param dataSources The dataSources to adapt; can't be {@code null}.
+ * @param wrapper The {@link ObjectWrapper} used to wrap the items in the array.
+ * @return adapter
+ */
+ public static DataSourcesAdapter create(DataSources dataSources, ObjectWrapperWithAPISupport wrapper) {
+ return new DataSourcesAdapter(dataSources, wrapper);
+ }
+
+ private DataSourcesAdapter(DataSources dataSources, ObjectWrapper wrapper) {
+ super(requireNonNull(wrapper));
+ this.dataSources = requireNonNull(dataSources);
+ }
+
+ @Override
+ public TemplateModel get(String key) throws TemplateModelException {
+ return wrap(dataSources.toMap().get(key));
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return dataSources.isEmpty();
+ }
+
+ @Override
+ public int size() {
+ return dataSources.size();
+ }
+
+ @Override
+ public TemplateCollectionModel keys() {
+ return new SimpleCollection(dataSources.toMap().keySet(), getObjectWrapper());
+ }
+
+ @Override
+ public TemplateCollectionModel values() {
+ return new SimpleCollection(dataSources.toMap().values(), getObjectWrapper());
+ }
+
+ @Override
+ public KeyValuePairIterator keyValuePairIterator() {
+ return new MapKeyValuePairIterator(dataSources.toMap(), getObjectWrapper());
+ }
+
+ @Override
+ public TemplateModel get(int index) throws TemplateModelException {
+ return index >= 0 && index < dataSources.size() ? wrap(dataSources.get(index)) : null;
+ }
+
+ @Override
+ public Object getAdaptedObject(Class hint) {
+ return dataSources;
+ }
+
+ @Override
+ public Object getWrappedObject() {
+ return dataSources;
+ }
+
+ @Override
+ public TemplateModel getAPI() throws TemplateModelException {
+ return ((ObjectWrapperWithAPISupport) getObjectWrapper()).wrapAsAPI(dataSources);
+ }
+}
diff --git a/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/wrapper/FreeMarkerGeneratorObjectWrapper.java b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/wrapper/FreeMarkerGeneratorObjectWrapper.java
new file mode 100644
index 0000000..102a84e
--- /dev/null
+++ b/freemarker-generator-cli/src/main/java/org/apache/freemarker/generator/cli/wrapper/FreeMarkerGeneratorObjectWrapper.java
@@ -0,0 +1,39 @@
+/*
+ * 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.wrapper;
+
+import freemarker.template.DefaultObjectWrapper;
+import freemarker.template.TemplateModel;
+import freemarker.template.TemplateModelException;
+import freemarker.template.Version;
+import org.apache.freemarker.generator.base.datasource.DataSources;
+
+public class FreeMarkerGeneratorObjectWrapper extends DefaultObjectWrapper {
+
+ public FreeMarkerGeneratorObjectWrapper(Version incompatibleImprovements) {
+ super(incompatibleImprovements);
+ }
+
+ @Override
+ protected TemplateModel handleUnknownType(final Object obj) throws TemplateModelException {
+ if (obj instanceof DataSources) {
+ return DataSourcesAdapter.create((DataSources) obj, this);
+ }
+
+ return super.handleUnknownType(obj);
+ }
+}
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-models.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-models.md
index bd56d76..42b048f 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-models.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-models.md
@@ -43,7 +43,7 @@
post title is: qui est esse
```
-Expose all environment variables as `env` in theFreeMarker model
+Expose all environment variables as `env` in the FreeMarker model
```
> freemarker-generator --data-model env=env:/// -i '<#list env as name,value>${name}=${value}${"\n"}</#list>'
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md
index f46f71d..f04675d 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/data-sources.md
@@ -96,9 +96,9 @@
### Selecting A DataSource
-After loading one or more `DataSource` they are accessible as `dataSource` map in the FreeMarker model
+After loading one or more `DataSource` they are accessible as `dataSources` map in the FreeMarker model
-* `dataSources?values[0]` or `dataSources?values?first` selects the first data source
+* `dataSources[0]` or `dataSources?first` selects the first data source
* `dataSources["user.csv"]` selects the data source with the name "user.csv"
### Iterating Over DataSources
@@ -122,7 +122,7 @@
</#list>
<#-- Iterate over a list of data sources -->
-<#list dataSources?values as dataSource>
+<#list dataSources as dataSource>
- [#${dataSource?counter}]: name=${dataSource.name}
</#list>
```
@@ -134,22 +134,22 @@
```
<#-- List all data sources containing "test" in the name -->
-<#list dataSources?values?filter(ds -> ds.match("name", "*test*")) as ds>
+<#list dataSources?filter(ds -> ds.match("name", "*test*")) as ds>
- ${ds.name}
</#list>
<#-- List all data sources having "json" extension -->
-<#list dataSources?values?filter(ds -> ds.match("extension", "json")) as ds>
+<#list dataSources?filter(ds -> ds.match("extension", "json")) as ds>
- ${ds.name}
</#list>
<#-- List all data sources having "src/test/data/properties" in their file path -->
-<#list dataSources?values?filter(ds -> ds.match("filePath", "*/src/test/data/properties")) as ds>
+<#list dataSources?filter(ds -> ds.match("filePath", "*/src/test/data/properties")) as ds>
- ${ds.name}
</#list>
<#-- List all data sources of a group -->
-<#list dataSources?values?filter(ds -> ds.match("group", "default")) as ds>
+<#list dataSources?filter(ds -> ds.match("group", "default")) as ds>
- ${ds.name}
</#list>
@@ -163,7 +163,7 @@
Invoke Arbitrary Methods On DataSource
---------------------------------------------------------------------------
<#if dataSources?has_content>
-<#assign dataSource=dataSources?values?first>
+<#assign dataSource=dataSources?first>
Name : ${dataSource.name}
Nr of lines : ${dataSource.lines?size}
Content Type : ${dataSource.contentType}
@@ -199,10 +199,10 @@
---------------------------------------------------------------------------
extension : csv
filename : contract.csv
-basename : contract
-filepath : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/src/app/examples/data/csv
+baseName : contract
+filePath : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/src/app/examples/data/csv
name : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/src/app/examples/data/csv/contract.csv
-mimetype : text/csv
+mimeType : text/csv
uri : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/src/app/examples/data/csv/contract.csv
group : default
```
@@ -230,16 +230,16 @@
Nr of chars : 12,643
Nr of bytes : 12,643
File name : transactions.csv
-URI schema : file
+URI scheme : file
Iterating Over Metadata Of A Datasource
---------------------------------------------------------------------------
extension : csv
-basename : transactions
-filename : transactions.csv
-filepath : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/csv
+baseName : transactions
+fileName : transactions.csv
+filePath : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/csv
name : transactions
-mimetype : text/csv
+mimeType : text/csv
uri : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/csv/transactions.csv
group : csv
@@ -261,16 +261,16 @@
Nr of chars : 330
Nr of bytes : 330
File name :
-URI schema : https
+URI scheme : https
Iterating Over Metadata Of A Datasource
---------------------------------------------------------------------------
extension :
-basename :
-filename :
-filepath : /
+baseName :
+fileName :
+filePath : /
name : https://xkcd.com/info.0.json
-mimetype : application/json
+mimeType : application/json
uri : https://xkcd.com/info.0.json
group : default
@@ -291,23 +291,21 @@
Nr of chars : 1,476
Nr of bytes : 1,478
File name :
-URI schema : env
+URI scheme : env
Iterating Over Metadata Of A Datasource
---------------------------------------------------------------------------
extension :
-basename :
-filename :
-filepath : /
+baseName :
+fileName :
+filePath : /
name : envvars
-mimetype : text/plain
+mimeType : text/plain
uri : env:///
group : default
Iterating Over Properties Of A Datasource
---------------------------------------------------------------------------
-
-
```
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/named-uris.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/named-uris.md
index 5fecc46..bb84d92 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/named-uris.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/named-uris.md
@@ -93,7 +93,7 @@
or use a charset for all files of a directory
```text
-freemarker-generator -t freemarker-generator/info.ftl 'examples/data/csv#charset=UTF-16&mimetype=text/plain'
+freemarker-generator -t freemarker-generator/info.ftl 'examples/data/csv#charset=UTF-16&mimeType=text/plain'
FreeMarker Generator DataSources
------------------------------------------------------------------------------
@@ -123,16 +123,16 @@
Nr of chars : 376
Nr of bytes : 376
File name : user.csv
-URI schema : file
+URI scheme : file
Iterating Over Metadata Of A Datasource
---------------------------------------------------------------------------
extension : csv
-basename : user
-filename : user.csv
-filepath : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/csv
+baseName : user
+fileName : user.csv
+filePath : /Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/csv
name : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/csv/user.csv
-mimetype : text/csv
+mimeType : text/csv
uri : file:/Users/sgoeschl/work/github/apache/freemarker-generator/freemarker-generator-cli/target/appassembler/examples/data/csv/user.csv
group : default
diff --git a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
index 9b20e10..b6ce911 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/concepts/transformation.md
@@ -3,15 +3,17 @@
The `freemarker-generator` generates text output based on processing FreeMarker templates and data
* A command line invocation requires 1..n `templates` and 0..n `data sources` / `data models`
-* A command line invocation is internally mapped to a list of `output generators`
+* A command line invocation is internally mapped to a list of `output generators` - the mapping is controlled by the `seed`
+ * `template` transforms 0 ..n `data sources` using a `template` to an `output`
+ * `datasource` applies a `template` for 1..n `data sources` generating 1..n `outputs`
* The `output generator` consists of exactly one `template`, 0..n `data sources` / `data models` written to an `output` destination
* The `output` of an `output generator` is either written to
* `stdout`
- * an output file
- * an output directory
+ * An output file
+ * An output directory
* When the output is written to a directory
- * the structure of the input directory is preserved
- * any `ftl` file extension is removed
+ * The structure of the input directory is preserved
+ * Any `ftl` file extension is removed
* Positional command line arguments are interpreted as `data sources` (or directories) and accessible by a all `output generators`
### Examples
@@ -25,7 +27,7 @@
Transform multiple templates to multiple output files (1:1 mapping between templates and outputs)
```
-freemarker-generator \
+> freemarker-generator \
-t freemarker-generator/csv/md/transform.ftl -o target/contract.md \
-t freemarker-generator/csv/html/transform.ftl -o target/contract.html \
examples/data/csv/contract.csv
@@ -40,7 +42,8 @@
```
> freemarker-generator \
--t examples/data/template -o target/template1
+-t examples/data/template \
+-o target/template1
> tree target
target
@@ -53,7 +56,7 @@
Transforming multiple template directories to multiple output directories
```
-freemarker-generator \
+> freemarker-generator \
-t examples/data/template -o target/template1 \
-t examples/data/template -o target/template2
@@ -69,6 +72,31 @@
`-- nginx.conf
```
+Transforming multiple `data sources` to multiple output files (aka source code generation)
+
+```
+> freemarker-generator \
+ --seed=datasource \
+ --template freemarker-generator/csv/html/transform.ftl \
+ --data-source . \
+ --data-source-include="*.csv" \
+ --output target \
+ --output-mapper="*.html"
+
+> tree target
+target
+`-- examples
+ `-- data
+ `-- csv
+ |-- contract.html
+ |-- dataframe.html
+ |-- excel-export-utf8.html
+ |-- locker-test-users.html
+ |-- sales-records.html
+ |-- transactions.html
+ `-- user.html
+```
+
Defining multiple transformation on the command line can be clumsy but [Picolic's @-Files](https://picocli.info/#AtFiles) can help - the following `@-File` defined, e.g. `@examples.args`
```
diff --git a/freemarker-generator-cli/src/site/markdown/cli/usage/parsing-with-grok.md b/freemarker-generator-cli/src/site/markdown/cli/usage/parsing-with-grok.md
index 5cbadda..7f4404c 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/usage/parsing-with-grok.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/usage/parsing-with-grok.md
@@ -33,7 +33,7 @@
```text
<#ftl output_format="plainText" strip_whitespace=true>
<#assign grok = tools.grok.create("%{COMBINEDAPACHELOG}")>
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign lines = dataSource.getLineIterator()>
<#compress>
@@ -93,7 +93,7 @@
<#compress>
TIMESTAMP;MILLIS
<#if dataSources?has_content>
- <#list dataSources?values as dataSource>
+ <#list dataSources as dataSource>
<#list dataSource.getLineIterator() as line>
<#assign parts = grok.match(line).capture()>
<#if parts?has_content>
diff --git a/freemarker-generator-cli/src/site/markdown/cli/usage/running-examples.md b/freemarker-generator-cli/src/site/markdown/cli/usage/running-examples.md
index e4cc875..ab46cea 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/usage/running-examples.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/usage/running-examples.md
@@ -6,72 +6,44 @@
```text
./run-examples.sh
-templates/info.ftl
+templates/freemarker-generator/info.ftl
examples/templates/demo.ftl
-templates/csv/html/transform.ftl
-templates/csv/md/transform.ftl
+examples/templates/datasources.ftl
+examples/templates/datasources.ftl
+templates/freemarker-generator/csv/confluence/transform.ftl
+templates/freemarker-generator/csv/html/transform.ftl
+templates/freemarker-generator/csv/md/transform.ftl
examples/templates/csv/shell/curl.ftl
examples/templates/csv/md/filter.ftl
examples/templates/csv/fo/transform.ftl
fop -fo target/out/locker-test-users.fo target/out/locker-test-users.pdf
examples/templates/csv/fo/transactions.ftl
fop -fo target/out/transactions.fo target/out/transactions-fo.pdf
-templates/csv/html/transform.ftl
+examples/templates/csv/html/transform.ftl
wkhtmltopdf -O landscape target/out/transactions.html target/out/transactions-html.pdf
examples/templates/dataframe/example.ftl
examples/templates/accesslog/combined-access.ftl
+examples/templates/logs/csv/serverlog-to-csv.ftl
examples/templates/excel/dataframe/transform.ftl
-templates/excel/html/transform.ftl
-templates/excel/md/transform.ftl
-templates/excel/csv/transform.ftl
+templates/freemarker-generator/excel/html/transform.ftl
+templates/freemarker-generator/excel/md/transform.ftl
+templates/freemarker-generator/excel/csv/transform.ftl
examples/templates/excel/csv/custom.ftl
examples/templates/html/csv/dependencies.ftl
+examples/templates/html/txt/licence.ftl
+examples/templates/javafaker/csv/testdata.ftl
examples/templates/json/csv/swagger-endpoints.ftl
-templates/json/yaml/transform.ftl
+templates/freemarker-generator/json/yaml/transform.ftl
examples/templates/json/md/github-users.ftl
examples/templates/properties/csv/locker-test-users.ftl
examples/data/template
-examples/templates/yaml/txt/transform.ftl
-templates/yaml/json/transform.ftl
+examples/templates/utahparser/csv/transform.ftl
+examples/templates/utahparser/json/transform.ftl
examples/templates/xml/txt/recipients.ftl
-Created the following sample files in ./target/out
-total 1464
--rw-r--r-- 1 sgoeschl staff 646 Jun 27 16:38 combined-access.log.txt
--rw-r--r-- 1 sgoeschl staff 25676 Jun 27 16:38 contract.html
--rw-r--r-- 1 sgoeschl staff 7933 Jun 27 16:38 contract.md
--rw-r--r-- 1 sgoeschl staff 784 Jun 27 16:38 curl.sh
--rw-r--r-- 1 sgoeschl staff 232 Jun 27 16:38 customer.txt
--rw-r--r-- 1 sgoeschl staff 6486 Jun 27 16:38 dataframe.txt
--rw-r--r-- 1 sgoeschl staff 15613 Jun 27 16:38 demo.txt
--rw-r--r-- 1 sgoeschl staff 1310 Jun 27 16:38 dependencies.csv
--rw-r--r-- 1 sgoeschl staff 2029 Jun 27 16:38 github-users-curl.md
--rw-r--r-- 1 sgoeschl staff 2627 Jun 27 16:38 info.txt
--rw-r--r-- 1 sgoeschl staff 8075 Jun 27 16:38 interactive-dataframe.txt
--rw-r--r-- 1 sgoeschl staff 66 Jun 27 16:38 interactive-html.txt
--rw-r--r-- 1 sgoeschl staff 16 Jun 27 16:38 interactive-json.txt
--rw-r--r-- 1 sgoeschl staff 25090 Jun 27 16:38 interactive-swagger.json
--rw-r--r-- 1 sgoeschl staff 16870 Jun 27 16:38 interactive-swagger.yaml
--rw-r--r-- 1 sgoeschl staff 10 Jun 27 16:38 interactive-xml.txt
--rw-r--r-- 1 sgoeschl staff 285 Jun 27 16:38 locker-test-users.csv
--rw-r--r-- 1 sgoeschl staff 6341 Jun 27 16:38 locker-test-users.fo
--rw-r--r-- 1 sgoeschl staff 5526 Jun 27 16:38 locker-test-users.pdf
--rw-r--r-- 1 sgoeschl staff 921 Jun 27 16:38 recipients.txt
--rw-r--r-- 1 sgoeschl staff 910 Jun 27 16:38 sales-records.md
--rw-r--r-- 1 sgoeschl staff 2453 Jun 27 16:38 swagger-spec.csv
--rw-r--r-- 1 sgoeschl staff 25090 Jun 27 16:38 swagger-spec.json
--rw-r--r-- 1 sgoeschl staff 16870 Jun 27 16:38 swagger-spec.yaml
-drwxr-xr-x 4 sgoeschl staff 128 Jun 27 16:38 template
--rw-r--r-- 1 sgoeschl staff 154 Jun 27 16:38 test-multiple-sheets.xlsx.csv
--rw-r--r-- 1 sgoeschl staff 1917 Jun 27 16:38 test-multiple-sheets.xlsx.html
--rw-r--r-- 1 sgoeschl staff 389 Jun 27 16:38 test-multiple-sheets.xlsx.md
--rw-r--r-- 1 sgoeschl staff 155 Jun 27 16:38 test-transform-xls.csv
--rw-r--r-- 1 sgoeschl staff 1439 Jun 27 16:38 test.xls.dataframe.txt
--rw-r--r-- 1 sgoeschl staff 1556 Jun 27 16:38 test.xls.html
--rw-r--r-- 1 sgoeschl staff 1558 Jun 27 16:38 test.xslx.html
--rw-r--r-- 1 sgoeschl staff 25757 Jun 27 16:38 transactions-fo.pdf
--rw-r--r-- 1 sgoeschl staff 66016 Jun 27 16:38 transactions-html.pdf
--rw-r--r-- 1 sgoeschl staff 330128 Jun 27 16:38 transactions.fo
--rw-r--r-- 1 sgoeschl staff 51008 Jun 27 16:38 transactions.html
+examples/templates/yaml/txt/transform.ftl
+templates/freemarker-generator/yaml/json/transform.ftl
+examples/data/csv
+examples/data/csv
```
Please note that generated PDF files are very likely not found since they require `wkhtmltopdf` and `Apache FOP` installation.
@@ -92,7 +64,7 @@
```text
<#ftl output_format="plainText" >
-<#assign json = tools.jsonpath.parse(dataSources?values[0])>
+<#assign json = tools.jsonpath.parse(dataSources[0])>
<#assign users = json.read("$[*]")>
<#--------------------------------------------------------------------------->
# GitHub Users
@@ -130,7 +102,7 @@
```text
<#ftl output_format="plainText">
<#assign cvsFormat = tools.csv.formats["DEFAULT"].withHeader()>
-<#assign csvParser = tools.csv.parse(dataSources?values[0], cvsFormat)>
+<#assign csvParser = tools.csv.parse(dataSources[0], cvsFormat)>
<#assign csvHeaders = csvParser.getHeaderMap()?keys>
<#assign csvRecords = csvParser.records>
<#--------------------------------------------------------------------------->
@@ -167,7 +139,7 @@
```text
<#ftl output_format="plainText" >
-<#assign xml = tools.xml.parse(dataSources?values[0])>
+<#assign xml = tools.xml.parse(dataSources[0])>
<#list xml.recipients.person as recipient>
To: ${recipient.name}
${recipient.address}
@@ -214,7 +186,7 @@
```text
<#ftl output_format="plainText" strip_text="true">
-<#assign json = tools.jsonpath.parse(dataSources?values[0])>
+<#assign json = tools.jsonpath.parse(dataSources[0])>
<#assign basePath = json.read("$.basePath")>
<#assign paths = json.read("$.paths")>
@@ -276,7 +248,7 @@
```text
<#ftl output_format="HTML" >
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign name = dataSource.name>
<#assign workbook = tools.excel.parse(dataSource)>
<#assign date = .now?iso_utc>
@@ -402,7 +374,7 @@
```text
<#ftl output_format="XML" >
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign name = dataSource.name>
<#assign cvsFormat = tools.csv.formats.DEFAULT.withDelimiter('\t').withHeader()>
<#assign csvParser = tools.csv.parse(dataSource, cvsFormat)>
@@ -523,7 +495,7 @@
```text
<#ftl output_format="plainText" strip_text="true">
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign html = tools.jsoup.parse(dataSource)>
<#compress>
@@ -598,7 +570,7 @@
```text
<#ftl output_format="plainText">
<#assign cvsFormat = tools.csv.formats["DEFAULT"].withHeader()>
-<#assign csvParser = tools.csv.parse(dataSources?values[0], cvsFormat)>
+<#assign csvParser = tools.csv.parse(dataSources[0], cvsFormat)>
<#assign records = csvParser.records>
<#assign csvMap = tools.csv.toMap(records, "disposer")>
<#--------------------------------------------------------------------------->
@@ -713,16 +685,16 @@
> bin/freemarker-generator -i 'Hello ${tools.system.envs["USER"]}'; echo
Hello sgoeschl
-> bin/freemarker-generator -i '${tools.jsonpath.parse(dataSources?values[0]).read("$.info.title")}' examples/data/json/swagger-spec.json; echo
+> bin/freemarker-generator -i '${tools.jsonpath.parse(dataSources[0]).read("$.info.title")}' examples/data/json/swagger-spec.json; echo
Swagger Petstore
-> bin/freemarker-generator -i 'Post Title : ${tools.jsonpath.parse(dataSources?values[0]).read("$.title")}' https://jsonplaceholder.typicode.com/posts/2; echo
+> bin/freemarker-generator -i 'Post Title : ${tools.jsonpath.parse(dataSources[0]).read("$.title")}' https://jsonplaceholder.typicode.com/posts/2; echo
Post Title : qui est esse
-> bin/freemarker-generator -i '${tools.xml.parse(dataSources?values[0])["recipients/person[1]/name"]}' examples/data/xml/recipients.xml; echo
+> bin/freemarker-generator -i '${tools.xml.parse(dataSources[0])["recipients/person[1]/name"]}' examples/data/xml/recipients.xml; echo
John Smith
-> bin/freemarker-generator -i '${tools.jsoup.parse(dataSources?values[0]).select("a")[0]}' examples/data/html/dependencies.html; echo
+> bin/freemarker-generator -i '${tools.jsoup.parse(dataSources[0]).select("a")[0]}' examples/data/html/dependencies.html; echo
<a href="${project.url}" title="FreeMarker Generator">FreeMarker Generator</a>
> freemarker-generator -i '<#list tools.system.envs as name,value>${name} ==> ${value}${"\n"}</#list>'
@@ -749,7 +721,7 @@
```text
<#ftl output_format="plainText" strip_text="true">
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign parser = parser(dataSource)>
<#assign headers = parser.getHeaderNames()>
<#assign column = tools.system.getParameter("column")>
@@ -835,11 +807,11 @@
```
> freemarker-generator -t freemarker-generator/yaml/json/transform.ftl examples/data/yaml/swagger-spec.yaml
-> freemarker-generator -i '${tools.gson.toJson(tools.yaml.parse(dataSources?values[0]))}' examples/data/yaml/swagger-spec.yaml
+> freemarker-generator -i '${tools.gson.toJson(tools.yaml.parse(dataSources[0]))}' examples/data/yaml/swagger-spec.yaml
> freemarker-generator -i '${tools.gson.toJson(yaml)}' -m yaml=examples/data/yaml/swagger-spec.yaml
> freemarker-generator -t freemarker-generator/json/yaml/transform.ftl examples/data/json/swagger-spec.json
-> freemarker-generator -i '${tools.yaml.toYaml(tools.gson.parse(dataSources?values[0]))}' examples/data/json/swagger-spec.json
+> freemarker-generator -i '${tools.yaml.toYaml(tools.gson.parse(dataSources[0]))}' examples/data/json/swagger-spec.json
> freemarker-generator -i '${tools.yaml.toYaml(json)}' -m json=examples/data/json/swagger-spec.json
```
diff --git a/freemarker-generator-cli/src/site/markdown/cli/usage/using-dataframes.md b/freemarker-generator-cli/src/site/markdown/cli/usage/using-dataframes.md
index 9fbf9d2..8866983 100644
--- a/freemarker-generator-cli/src/site/markdown/cli/usage/using-dataframes.md
+++ b/freemarker-generator-cli/src/site/markdown/cli/usage/using-dataframes.md
@@ -30,7 +30,7 @@
and create a `DateFrame` using the following code snippet
```
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign csvParser = tools.csv.parse(dataSource, tools.csv.formats["DATAFRAME"])>
<#assign users = tools.dataframe.fromCSVParser(csvParser)>
```
@@ -162,7 +162,7 @@
```
freemarker-generator \
--i '${tools.dataframe.print(tools.dataframe.fromMaps(tools.gson.parse(dataSources?values[0])))}' \
+-i '${tools.dataframe.print(tools.dataframe.fromMaps(tools.gson.parse(dataSources[0])))}' \
examples/data/json/github-users.json
┌────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┬────────────┐
@@ -189,7 +189,7 @@
Let's transform an Excel Sheet to a `DataFrame` being printed using the following template
```
-<#assign dataSource = dataSources?values[0]>
+<#assign dataSource = dataSources[0]>
<#assign workbook = tools.excel.parse(dataSource)>
<#list tools.excel.getSheets(workbook) as sheet>
<#assign table = tools.excel.toTable(sheet)>
diff --git a/freemarker-generator-base/src/test/template/application.properties b/freemarker-generator-cli/src/test/data/template/application.properties
similarity index 100%
rename from freemarker-generator-base/src/test/template/application.properties
rename to freemarker-generator-cli/src/test/data/template/application.properties
diff --git a/freemarker-generator-base/src/test/template/nginx/nginx.conf.ftl b/freemarker-generator-cli/src/test/data/template/nginx/nginx.conf.ftl
similarity index 100%
rename from freemarker-generator-base/src/test/template/nginx/nginx.conf.ftl
rename to freemarker-generator-cli/src/test/data/template/nginx/nginx.conf.ftl
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 8b84c71..1a09d23 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
@@ -49,11 +49,13 @@
@Test
public void shouldRunDataSourceExamples() throws IOException {
+ assertValid(execute("-t src/app/examples/templates/datasources.ftl"));
assertValid(execute("-t src/app/examples/templates/datasources.ftl -s :csv=src/app/examples/data/csv"));
}
@Test
public void shouldRunCsvExamples() throws IOException {
+ assertValid(execute("-t freemarker-generator/csv/confluence/transform.ftl src/app/examples/data/csv/contract.csv"));
assertValid(execute("-t freemarker-generator/csv/html/transform.ftl src/app/examples/data/csv/contract.csv"));
assertValid(execute("-t freemarker-generator/csv/md/transform.ftl src/app/examples/data/csv/contract.csv"));
assertValid(execute("-t src/app/examples/templates/csv/shell/curl.ftl src/app/examples/data/csv/user.csv"));
@@ -80,6 +82,11 @@
}
@Test
+ public void shouldRunNginxParsingExamples() throws IOException {
+ assertValid(execute("-t src/app/examples/templates/nginx/confluence/nginx-config-parser.ftl -s src/app/examples/data/nginx"));
+ }
+
+ @Test
public void shouldRunJsonExamples() throws IOException {
assertValid(execute("-t src/app/examples/templates/json/csv/swagger-endpoints.ftl src/app/examples/data/json/swagger-spec.json"));
assertValid(execute("-t src/app/examples/templates/json/md/github-users.ftl src/app/examples/data/json/github-users.json"));
@@ -124,15 +131,28 @@
}
@Test
+ public void shouldRunUtahParserExamples() throws IOException {
+ assertValid(execute("-PCSV_TARGET_FORMAT=EXCEL " +
+ "-PCSV_TARGET_DELIMITER=SEMICOLON " +
+ "-t src/app/examples/templates/utahparser/csv/transform.ftl " +
+ "src/app/examples/data/text/utahparser/juniper_bgp_summary_template.xml " +
+ "src/app/examples/data/text/utahparser/juniper_bgp_summary_example.txt"));
+
+ assertValid(execute("-t src/app/examples/templates/utahparser/json/transform.ftl " +
+ "src/app/examples/data/text/utahparser/juniper_bgp_summary_template.xml " +
+ "src/app/examples/data/text/utahparser/juniper_bgp_summary_example.txt"));
+ }
+
+ @Test
public void shouldRunInteractiveTemplateExamples() throws IOException {
- assertValid(execute("-i ${tools.jsonpath.parse(dataSources?values[0]).read(\"$.info.title\")} src/app/examples/data/json/swagger-spec.json"));
- assertValid(execute("-i ${tools.xml.parse(dataSources?values[0])[\"recipients/person[1]/name\"]} src/app/examples/data/xml/recipients.xml"));
- assertValid(execute("-i ${tools.jsoup.parse(dataSources?values[0]).select(\"a\")[0]} src/app/examples/data/html/dependencies.html"));
- assertValid(execute("-i ${tools.gson.toJson(tools.yaml.parse(dataSources?values[0]))} src/app/examples/data/yaml/swagger-spec.yaml"));
+ assertValid(execute("-i ${tools.jsonpath.parse(dataSources[0]).read(\"$.info.title\")} src/app/examples/data/json/swagger-spec.json"));
+ assertValid(execute("-i ${tools.xml.parse(dataSources[0])[\"recipients/person[1]/name\"]} src/app/examples/data/xml/recipients.xml"));
+ assertValid(execute("-i ${tools.jsoup.parse(dataSources[0]).select(\"a\")[0]} src/app/examples/data/html/dependencies.html"));
+ assertValid(execute("-i ${tools.gson.toJson(tools.yaml.parse(dataSources[0]))} src/app/examples/data/yaml/swagger-spec.yaml"));
assertValid(execute("-i ${tools.gson.toJson(yaml)} -m yaml=src/app/examples/data/yaml/swagger-spec.yaml"));
- assertValid(execute("-i ${tools.yaml.toYaml(tools.gson.parse(dataSources?values[0]))} src/app/examples/data/json/swagger-spec.json"));
+ assertValid(execute("-i ${tools.yaml.toYaml(tools.gson.parse(dataSources[0]))} src/app/examples/data/json/swagger-spec.json"));
assertValid(execute("-i ${tools.yaml.toYaml(json)} -m json=src/app/examples/data/json/swagger-spec.json"));
- assertValid(execute("-i ${tools.dataframe.print(tools.dataframe.fromMaps(tools.gson.parse(dataSources?values[0])))} src/app/examples/data/json/github-users.json"));
+ assertValid(execute("-i ${tools.dataframe.print(tools.dataframe.fromMaps(tools.gson.parse(dataSources[0])))} src/app/examples/data/json/github-users.json"));
}
@Test
@@ -178,6 +198,20 @@
}
@Test
+ public void shouldSupportDataSourceSeedingTransformation() throws IOException {
+ final String output = execute("--seed=datasource " +
+ "--template freemarker-generator/csv/html/transform.ftl " +
+ "--data-source src/app/examples/data/csv " +
+ "--data-source-include=*.csv " +
+ "--output target " +
+ "--output-mapper=*.html");
+
+ assertTrue(output.startsWith("<!DOCTYPE html>"));
+ assertTrue(output.contains("The Electric Company"));
+ assertTrue(output.contains("test user DDDDDDD"));
+ }
+
+ @Test
@Ignore("Manual test to check memory consumption and resource handling")
public void shouldCloseAllResources() throws IOException {
for (int i = 0; i < 500; i++) {
@@ -199,6 +233,7 @@
}
private static void assertValid(String output) {
+ // System.out.println(output);
assertTrue(output.length() > MIN_OUTPUT_SIZE);
assertFalse(output.contains("Exception"));
assertFalse(output.contains("FreeMarker template 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 b9cce26..2f1dd69 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
@@ -24,7 +24,9 @@
public class ManualTest extends AbstractMainTest {
// private static final String CMD = "-V";
- private static final String CMD = "-t src/app/examples/templates/datasources.ftl transactions:csv=src/app/examples/data/csv/transactions.csv#delimiter=TAB https://xkcd.com/info.0.json envvars=env:///";
+ private static final String CMD =
+ "-t src/app/examples/templates/nginx/confluence/nginx-config-parser.ftl -s src/app/examples/data/nginx";
+ // "-t src/app/examples/templates/datasources.ftl";
@Override
public String execute(String commandLine) throws IOException {
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
index 4a3a5b8..4531b4f 100644
--- 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
@@ -148,7 +148,7 @@
"-i", "some-interactive-template01", "-s", "datasource30.csv", "-o", "out.txt",
"-i", "some-interactive-template02");
- main.validate();
+ main.validateCommandLineParameters();
final List<OutputGeneratorDefinition> defs = main.outputGeneratorDefinitions;
assertEquals(4, defs.size());
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/AbstractOutputGeneratorTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/AbstractOutputGeneratorTest.java
new file mode 100644
index 0000000..99eef2e
--- /dev/null
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/AbstractOutputGeneratorTest.java
@@ -0,0 +1,79 @@
+/*
+ * 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.config;
+
+import org.apache.freemarker.generator.cli.picocli.DataSourceDefinition;
+import org.apache.freemarker.generator.cli.picocli.OutputGeneratorDefinition;
+import org.apache.freemarker.generator.cli.picocli.OutputMapperDefinition;
+import org.apache.freemarker.generator.cli.picocli.OutputSeedDefinition;
+import org.apache.freemarker.generator.cli.picocli.TemplateOutputDefinition;
+import org.apache.freemarker.generator.cli.picocli.TemplateSourceDefinition;
+
+import java.util.Arrays;
+
+import static java.util.Collections.singletonList;
+
+public abstract class AbstractOutputGeneratorTest {
+
+ protected static final String ANY_TEMPLATE_NAME = "cat.ftl";
+ protected static final String ANY_TEMPLATE = "src/app/templates/freemarker-generator/" + ANY_TEMPLATE_NAME;
+ protected static final String ANY_DATASOURCE_DIRECTORY = "src/test/data/json";
+ protected static final String ANY_DATASOURCE_FILE_01 = ANY_DATASOURCE_DIRECTORY + "/environments.json";
+ protected static final String ANY_DATASOURCE_FILE_02 = ANY_DATASOURCE_DIRECTORY + "/list.json";
+ protected static final String ANY_OUTPUT_DIRECTORY = "target";
+ protected static final String ANY_OUTPUT_FILE = "target/out.txt";
+
+ protected static OutputGeneratorDefinition outputGeneratorDefinition() {
+ return new OutputGeneratorDefinition();
+ }
+
+ protected static Settings settings(OutputGeneratorDefinition... outputGeneratorDefinitions) {
+ return Settings.builder()
+ .setOutputGeneratorDefinitions(Arrays.asList(outputGeneratorDefinitions))
+ .build();
+ }
+
+ protected static OutputSeedDefinition outputSeedDefinition(String type) {
+ final OutputSeedDefinition outputSeedDefinition = new OutputSeedDefinition();
+ outputSeedDefinition.type = type;
+ return outputSeedDefinition;
+ }
+
+ protected static TemplateSourceDefinition templateSourceDefinition(String template) {
+ final TemplateSourceDefinition templateSourceDefinition = new TemplateSourceDefinition();
+ templateSourceDefinition.template = template;
+ return templateSourceDefinition;
+ }
+
+ protected static DataSourceDefinition dataSourceDefinition(String... dataSources) {
+ final DataSourceDefinition dataSourceDefinition = new DataSourceDefinition();
+ dataSourceDefinition.dataSources = Arrays.asList(dataSources);
+ return dataSourceDefinition;
+ }
+
+ protected static TemplateOutputDefinition templateOutputDirectoryDefinition(String directoryName) {
+ final TemplateOutputDefinition templateOutputDefinition = new TemplateOutputDefinition();
+ templateOutputDefinition.outputs = singletonList(directoryName);
+ return templateOutputDefinition;
+ }
+
+ protected static OutputMapperDefinition outputMapperDefinition(String template) {
+ final OutputMapperDefinition outputMapperDefinition = new OutputMapperDefinition();
+ outputMapperDefinition.outputMapper = template;
+ return outputMapperDefinition;
+ }
+}
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
index 3c8f6ef..b2daff2 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/ConfigurationSupplierTest.java
@@ -29,8 +29,6 @@
public class ConfigurationSupplierTest {
- private static final String ANY_TEMPLATE_NAME = "templateName";
-
@Test
public void shouldProvideDefaultConfiguration() {
final ConfigurationSupplier configurationSupplier = configurationSupplier(settingsBuilder().build());
@@ -43,11 +41,12 @@
assertTrue(configuration.isOutputEncodingSet());
assertFalse(configuration.isCacheStorageExplicitlySet());
- assertFalse(configuration.isObjectWrapperExplicitlySet());
+ assertTrue(configuration.isObjectWrapperExplicitlySet());
assertFalse(configuration.isOutputFormatExplicitlySet());
assertFalse(configuration.isTemplateExceptionHandlerExplicitlySet());
assertFalse(configuration.isTimeZoneExplicitlySet());
assertFalse(configuration.isWrapUncheckedExceptionsExplicitlySet());
+ assertTrue(configuration.isAPIBuiltinEnabled());
}
private ConfigurationSupplier configurationSupplier(Settings settings) {
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SuppliersTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SuppliersTest.java
index a12cb1d..fa9b47e 100644
--- a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SuppliersTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/SuppliersTest.java
@@ -39,7 +39,6 @@
import static java.util.Collections.singletonList;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
@@ -95,7 +94,6 @@
assertNotNull(configuration.getSharedVariable(Model.TOOLS));
assertTrue(configuration.isTemplateLoaderExplicitlySet());
- assertFalse(configuration.isObjectWrapperExplicitlySet());
}
@Test
@@ -106,7 +104,7 @@
final List<DataSource> dataSourceList = dataSourcesSupplier.get();
assertEquals(1, dataSourceList.size());
- assertTrue(dataSourceList.get(0).getName().endsWith(ANY_DATA_SOURCE_NAME));
+ assertTrue(dataSourceList.get(0).getName().endsWith(fixSeparators(ANY_DATA_SOURCE_NAME)));
}
@Test
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/TemplateSeedingOutputGeneratorTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/TemplateSeedingOutputGeneratorTest.java
new file mode 100644
index 0000000..c75a121
--- /dev/null
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/TemplateSeedingOutputGeneratorTest.java
@@ -0,0 +1,121 @@
+/*
+ * 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.config;
+
+import org.apache.freemarker.generator.base.FreeMarkerConstants.SeedType;
+import org.apache.freemarker.generator.base.output.OutputGenerator;
+import org.apache.freemarker.generator.cli.picocli.OutputGeneratorDefinition;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class TemplateSeedingOutputGeneratorTest extends AbstractOutputGeneratorTest {
+
+ /**
+ * One data source -> one output generator
+ */
+ @Test
+ public void shouldCreateSingleOutputGeneratorForMultipleDataSources() {
+ final OutputGeneratorDefinition outputGeneratorDefinition = outputGeneratorDefinition();
+ outputGeneratorDefinition.templateSourceDefinition = templateSourceDefinition(ANY_TEMPLATE);
+ outputGeneratorDefinition.templateOutputDefinition = templateOutputDirectoryDefinition(ANY_OUTPUT_FILE);
+ outputGeneratorDefinition.dataSourceDefinition = dataSourceDefinition(ANY_DATASOURCE_FILE_01, ANY_DATASOURCE_FILE_02);
+ outputGeneratorDefinition.outputSeedDefinition = outputSeedDefinition(SeedType.TEMPLATE);
+ final Settings settings = settings(outputGeneratorDefinition);
+ final OutputGeneratorsSupplier outputGeneratorsSupplier = new OutputGeneratorsSupplier(settings);
+
+ final List<OutputGenerator> outputGenerators = outputGeneratorsSupplier.get();
+ final OutputGenerator outputGenerator = outputGenerators.get(0);
+
+ assertEquals(1, outputGenerators.size());
+ assertEquals(2, outputGenerator.getDataSources().size());
+
+ assertEquals(OutputGenerator.SeedType.TEMPLATE, outputGenerator.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_FILE), outputGenerator.getTemplateOutput().getFile());
+ assertEquals("environments.json", outputGenerator.getDataSources().get(0).getFileName());
+ assertEquals("list.json", outputGenerator.getDataSources().get(1).getFileName());
+ }
+
+ /**
+ * N file data sources for a given directory -> one output generator
+ */
+ @Test
+ public void shouldCreateSingleOutputGeneratorForMultipleDataSourcesInDirectory() {
+ final OutputGeneratorDefinition outputGeneratorDefinition = outputGeneratorDefinition();
+ outputGeneratorDefinition.templateSourceDefinition = templateSourceDefinition(ANY_TEMPLATE);
+ outputGeneratorDefinition.templateOutputDefinition = templateOutputDirectoryDefinition(ANY_OUTPUT_FILE);
+ outputGeneratorDefinition.dataSourceDefinition = dataSourceDefinition(ANY_DATASOURCE_DIRECTORY);
+ outputGeneratorDefinition.outputSeedDefinition = outputSeedDefinition(SeedType.TEMPLATE);
+ final Settings settings = settings(outputGeneratorDefinition);
+ final OutputGeneratorsSupplier outputGeneratorsSupplier = new OutputGeneratorsSupplier(settings);
+
+ final List<OutputGenerator> outputGenerators = outputGeneratorsSupplier.get();
+ final OutputGenerator outputGenerator = outputGenerators.get(0);
+
+ assertEquals(1, outputGenerators.size());
+ assertEquals(2, outputGenerator.getDataSources().size());
+
+ assertEquals(OutputGenerator.SeedType.TEMPLATE, outputGenerator.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_FILE), outputGenerator.getTemplateOutput().getFile());
+ assertEquals("environments.json", outputGenerator.getDataSources().get(0).getFileName());
+ assertEquals("list.json", outputGenerator.getDataSources().get(1).getFileName());
+ }
+
+ /**
+ * N output generator definitions -> N output generators
+ */
+ @Test
+ public void shouldCreateOutputGeneratorForEachOutputGeneratorDefinition() {
+ final OutputGeneratorDefinition outputGeneratorDefinition_01 = outputGeneratorDefinition();
+ outputGeneratorDefinition_01.templateSourceDefinition = templateSourceDefinition(ANY_TEMPLATE);
+ outputGeneratorDefinition_01.templateOutputDefinition = templateOutputDirectoryDefinition(ANY_OUTPUT_FILE);
+ outputGeneratorDefinition_01.dataSourceDefinition = dataSourceDefinition(ANY_DATASOURCE_FILE_01);
+ outputGeneratorDefinition_01.outputSeedDefinition = outputSeedDefinition(SeedType.TEMPLATE);
+
+ final OutputGeneratorDefinition outputGeneratorDefinition_02 = outputGeneratorDefinition();
+ outputGeneratorDefinition_02.templateSourceDefinition = templateSourceDefinition(ANY_TEMPLATE);
+ outputGeneratorDefinition_02.templateOutputDefinition = templateOutputDirectoryDefinition(ANY_OUTPUT_FILE);
+ outputGeneratorDefinition_02.dataSourceDefinition = dataSourceDefinition(ANY_DATASOURCE_FILE_02);
+ outputGeneratorDefinition_02.outputSeedDefinition = outputSeedDefinition(SeedType.TEMPLATE);
+
+ final Settings settings = settings(outputGeneratorDefinition_01, outputGeneratorDefinition_02);
+ final OutputGeneratorsSupplier outputGeneratorsSupplier = new OutputGeneratorsSupplier(settings);
+
+ final List<OutputGenerator> outputGenerators = outputGeneratorsSupplier.get();
+ final OutputGenerator outputGenerator_01 = outputGenerators.get(0);
+ final OutputGenerator outputGenerator_02 = outputGenerators.get(1);
+
+ assertEquals(2, outputGenerators.size());
+
+ assertEquals(1, outputGenerator_01.getDataSources().size());
+ assertEquals(OutputGenerator.SeedType.TEMPLATE, outputGenerator_01.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator_01.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_FILE), outputGenerator_01.getTemplateOutput().getFile());
+ assertEquals("environments.json", outputGenerator_01.getDataSources().get(0).getFileName());
+
+ assertEquals(1, outputGenerator_02.getDataSources().size());
+ assertEquals(OutputGenerator.SeedType.TEMPLATE, outputGenerator_02.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator_02.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_FILE), outputGenerator_02.getTemplateOutput().getFile());
+ assertEquals("list.json", outputGenerator_02.getDataSources().get(0).getFileName());
+ }
+}
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputGeneratorTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputGeneratorTest.java
new file mode 100644
index 0000000..5b1219b
--- /dev/null
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputGeneratorTest.java
@@ -0,0 +1,135 @@
+/*
+ * 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.config.output;
+
+import org.apache.freemarker.generator.base.FreeMarkerConstants.SeedType;
+import org.apache.freemarker.generator.base.output.OutputGenerator;
+import org.apache.freemarker.generator.cli.config.AbstractOutputGeneratorTest;
+import org.apache.freemarker.generator.cli.config.OutputGeneratorsSupplier;
+import org.apache.freemarker.generator.cli.config.Settings;
+import org.apache.freemarker.generator.cli.picocli.OutputGeneratorDefinition;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+public class DataSourceSeedingOutputGeneratorTest extends AbstractOutputGeneratorTest {
+
+ /**
+ * Edge case - a single data source shall create a single output generator
+ */
+ @Test
+ public void shouldCreateOutputGeneratorForSingleDataSource() {
+ final OutputGeneratorDefinition outputGeneratorDefinition = outputGeneratorDefinition();
+ outputGeneratorDefinition.templateSourceDefinition = templateSourceDefinition(ANY_TEMPLATE);
+ outputGeneratorDefinition.templateOutputDefinition = templateOutputDirectoryDefinition(ANY_OUTPUT_DIRECTORY);
+ outputGeneratorDefinition.dataSourceDefinition = dataSourceDefinition(ANY_DATASOURCE_FILE_01);
+ outputGeneratorDefinition.outputSeedDefinition = outputSeedDefinition(SeedType.DATASOURCE);
+ outputGeneratorDefinition.outputMapperDefinition = outputMapperDefinition("*.txt");
+ final Settings settings = settings(outputGeneratorDefinition);
+ final OutputGeneratorsSupplier outputGeneratorsSupplier = new OutputGeneratorsSupplier(settings);
+
+ final List<OutputGenerator> outputGenerators = outputGeneratorsSupplier.get();
+ final OutputGenerator outputGenerator = outputGenerators.get(0);
+
+ assertEquals(1, outputGenerators.size());
+
+ assertEquals(1, outputGenerator.getDataSources().size());
+ assertEquals(OutputGenerator.SeedType.DATASOURCE, outputGenerator.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_DIRECTORY, "environments.txt"), outputGenerator.getTemplateOutput().getFile());
+ assertEquals("environments.json", outputGenerator.getDataSources().get(0).getFileName());
+ }
+
+ /**
+ * N given data sources -> N output generators
+ */
+ @Test
+ public void shouldCreateOutputGeneratorForEachDataSource() {
+ final OutputGeneratorDefinition outputGeneratorDefinition_01 = outputGeneratorDefinition();
+ outputGeneratorDefinition_01.templateSourceDefinition = templateSourceDefinition(ANY_TEMPLATE);
+ outputGeneratorDefinition_01.templateOutputDefinition = templateOutputDirectoryDefinition(ANY_OUTPUT_DIRECTORY);
+ outputGeneratorDefinition_01.dataSourceDefinition = dataSourceDefinition(ANY_DATASOURCE_FILE_01);
+ outputGeneratorDefinition_01.outputSeedDefinition = outputSeedDefinition(SeedType.DATASOURCE);
+ outputGeneratorDefinition_01.outputMapperDefinition = outputMapperDefinition("*.txt");
+
+ final OutputGeneratorDefinition outputGeneratorDefinition_02 = outputGeneratorDefinition();
+ outputGeneratorDefinition_02.templateSourceDefinition = templateSourceDefinition(ANY_TEMPLATE);
+ outputGeneratorDefinition_02.templateOutputDefinition = templateOutputDirectoryDefinition(ANY_OUTPUT_DIRECTORY);
+ outputGeneratorDefinition_02.dataSourceDefinition = dataSourceDefinition(ANY_DATASOURCE_FILE_02);
+ outputGeneratorDefinition_02.outputSeedDefinition = outputSeedDefinition(SeedType.DATASOURCE);
+ outputGeneratorDefinition_02.outputMapperDefinition = outputMapperDefinition("*.txt");
+
+ final Settings settings = settings(outputGeneratorDefinition_01, outputGeneratorDefinition_02);
+ final OutputGeneratorsSupplier outputGeneratorsSupplier = new OutputGeneratorsSupplier(settings);
+
+ final List<OutputGenerator> outputGenerators = outputGeneratorsSupplier.get();
+ final OutputGenerator outputGenerator_01 = outputGenerators.get(0);
+ final OutputGenerator outputGenerator_02 = outputGenerators.get(1);
+
+ assertEquals(2, outputGenerators.size());
+
+ assertEquals(1, outputGenerator_01.getDataSources().size());
+ assertEquals(OutputGenerator.SeedType.DATASOURCE, outputGenerator_01.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator_01.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_DIRECTORY, "environments.txt"), outputGenerator_01.getTemplateOutput()
+ .getFile());
+ assertEquals("environments.json", outputGenerator_01.getDataSources().get(0).getFileName());
+
+ assertEquals(1, outputGenerator_02.getDataSources().size());
+ assertEquals(OutputGenerator.SeedType.DATASOURCE, outputGenerator_02.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator_02.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_DIRECTORY, "list.txt"), outputGenerator_02.getTemplateOutput().getFile());
+ assertEquals("list.json", outputGenerator_02.getDataSources().get(0).getFileName());
+ }
+
+ /**
+ * N file data sources in a given directory -> N output generators
+ */
+ @Test
+ public void shouldCreateOutputGeneratorsForAllDataSourcesInDirectory() {
+ final OutputGeneratorDefinition outputGeneratorDefinition = outputGeneratorDefinition();
+ outputGeneratorDefinition.templateSourceDefinition = templateSourceDefinition(ANY_TEMPLATE);
+ outputGeneratorDefinition.templateOutputDefinition = templateOutputDirectoryDefinition(ANY_OUTPUT_DIRECTORY);
+ outputGeneratorDefinition.dataSourceDefinition = dataSourceDefinition(ANY_DATASOURCE_DIRECTORY);
+ outputGeneratorDefinition.outputSeedDefinition = outputSeedDefinition(SeedType.DATASOURCE);
+ outputGeneratorDefinition.outputMapperDefinition = outputMapperDefinition("*.txt");
+ final Settings settings = settings(outputGeneratorDefinition);
+ final OutputGeneratorsSupplier outputGeneratorsSupplier = new OutputGeneratorsSupplier(settings);
+
+ final List<OutputGenerator> outputGenerators = outputGeneratorsSupplier.get();
+ final OutputGenerator outputGenerator_01 = outputGenerators.get(0);
+ final OutputGenerator outputGenerator_02 = outputGenerators.get(1);
+
+ assertEquals(2, outputGenerators.size());
+
+ assertEquals(1, outputGenerator_01.getDataSources().size());
+ assertEquals(OutputGenerator.SeedType.DATASOURCE, outputGenerator_01.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator_01.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_DIRECTORY, "environments.txt"), outputGenerator_01.getTemplateOutput()
+ .getFile());
+ assertEquals("environments.json", outputGenerator_01.getDataSources().get(0).getFileName());
+
+ assertEquals(1, outputGenerator_02.getDataSources().size());
+ assertEquals(OutputGenerator.SeedType.DATASOURCE, outputGenerator_02.getSeedType());
+ assertEquals(ANY_TEMPLATE_NAME, outputGenerator_02.getTemplateSource().getName());
+ assertEquals(new File(ANY_OUTPUT_DIRECTORY, "list.txt"), outputGenerator_02.getTemplateOutput().getFile());
+ assertEquals("list.json", outputGenerator_02.getDataSources().get(0).getFileName());
+ }
+}
diff --git a/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputMapperTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputMapperTest.java
new file mode 100644
index 0000000..3d58930
--- /dev/null
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/DataSourceSeedingOutputMapperTest.java
@@ -0,0 +1,95 @@
+/*
+ * 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.config.output;
+
+import org.apache.commons.io.FilenameUtils;
+import org.apache.freemarker.generator.base.datasource.DataSource;
+import org.apache.freemarker.generator.base.datasource.DataSourceFactory;
+import org.apache.freemarker.generator.base.util.FileUtils;
+import org.apache.freemarker.generator.base.util.OperatingSystem;
+import org.apache.freemarker.generator.base.util.StringUtils;
+import org.junit.Test;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+
+import static org.junit.Assert.assertEquals;
+
+public class DataSourceSeedingOutputMapperTest {
+
+ private final File CURRENT_DIRECTORY = new File(".");
+ private final File PARENT_DIRECTORY = new File("..");
+ private final File ANY_DIRECTORY = new File("target");
+ private final File ANY_FILE = new File("pom.xml");
+ private final DataSource FILE_DATA_SOURCE = DataSourceFactory.fromFile(ANY_FILE, StandardCharsets.UTF_8);
+ private final DataSource URL_DATA_SOURCE = DataSourceFactory.fromUrl("google.com", "group", DataSourceFactory.toUrl("https://www.google.com"));
+
+ @Test
+ public void shouldGenerateOutputFileForCurrentDirectory() {
+ assertEquals("pom.xml", path(outputMapper(null).map(CURRENT_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("pom.xml", path(outputMapper("").map(CURRENT_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("pom.html", path(outputMapper("*.html").map(CURRENT_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("pom.html", path(outputMapper("pom.html").map(CURRENT_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("html/pom.html", path(outputMapper("html/*.html").map(CURRENT_DIRECTORY, FILE_DATA_SOURCE)));
+ }
+
+ @Test
+ public void shouldGenerateOutputFileForParentDirectory() {
+ assertEquals("../pom.xml", path(outputMapper(null).map(PARENT_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("../pom.xml", path(outputMapper("").map(PARENT_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("../pom.html", path(outputMapper("*.html").map(PARENT_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("../pom.html", path(outputMapper("pom.html").map(PARENT_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("../html/pom.html", path(outputMapper("html/*.html").map(PARENT_DIRECTORY, FILE_DATA_SOURCE)));
+ }
+
+ @Test
+ public void shouldGenerateOutputFileForAnyDirectory() {
+ assertEquals("target/pom.xml", path(outputMapper(null).map(ANY_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("target/pom.xml", path(outputMapper("").map(ANY_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("target/pom.html", path(outputMapper("*.html").map(ANY_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("target/pom.html", path(outputMapper("pom.html").map(ANY_DIRECTORY, FILE_DATA_SOURCE)));
+ assertEquals("target/html/pom.html", path(outputMapper("html/*.html").map(ANY_DIRECTORY, FILE_DATA_SOURCE)));
+ }
+
+ @Test
+ public void shouldHandleUrlDataSources() {
+ assertEquals("target/google.com", path(outputMapper(null).map(ANY_DIRECTORY, URL_DATA_SOURCE)));
+ assertEquals("target/google.com", path(outputMapper("").map(ANY_DIRECTORY, URL_DATA_SOURCE)));
+ assertEquals("target/google.com.html", path(outputMapper("*.html").map(ANY_DIRECTORY, URL_DATA_SOURCE)));
+ }
+
+ private static DataSourceSeedingOutputMapper outputMapper(String template) {
+ return new DataSourceSeedingOutputMapper(template);
+ }
+
+ private static String fixSeparators(String str) {
+ if (OperatingSystem.isWindows()) {
+ return FilenameUtils.separatorsToUnix(str);
+ } else {
+ return str;
+ }
+ }
+
+ private static String path(File file) {
+ final File workingDir = new File(".");
+ final String relativePath = FileUtils.getRelativePath(workingDir, file);
+
+ return fixSeparators(StringUtils.isEmpty(relativePath) ?
+ file.getName() :
+ relativePath + File.separatorChar + file.getName());
+ }
+}
diff --git a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformationsBuilderTest.java
similarity index 95%
rename from freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java
rename to freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformationsBuilderTest.java
index 7170cd7..6755404 100644
--- a/freemarker-generator-base/src/test/java/org/apache/freemarker/generator/template/TemplateTransformationsBuilderTest.java
+++ b/freemarker-generator-cli/src/test/java/org/apache/freemarker/generator/cli/config/output/TemplateTransformationsBuilderTest.java
@@ -14,14 +14,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.freemarker.generator.template;
+package org.apache.freemarker.generator.cli.config.output;
import org.apache.freemarker.generator.base.FreeMarkerConstants.Location;
import org.apache.freemarker.generator.base.template.TemplateOutput;
import org.apache.freemarker.generator.base.template.TemplateSource;
import org.apache.freemarker.generator.base.template.TemplateSource.Origin;
-import org.apache.freemarker.generator.base.template.TemplateTransformation;
-import org.apache.freemarker.generator.base.template.TemplateTransformationsBuilder;
import org.apache.freemarker.generator.base.util.NonClosableWriterWrapper;
import org.junit.Ignore;
import org.junit.Test;
@@ -41,10 +39,9 @@
public class TemplateTransformationsBuilderTest {
- private static final String ANY_TEMPLATE_FILE_NAME = "src/test/template/application.properties";
- private static final String OTHER_TEMPLATE_FILE_NAME = "src/test/template/nginx/nginx.conf.ftl";
+ private static final String ANY_TEMPLATE_FILE_NAME = "src/test/data/template/application.properties";
private static final String ANY_TEMPLATE_PATH = "template/info.ftl";
- private static final String ANY_TEMPLATE_DIRECTORY_NAME = "src/test/template";
+ private static final String ANY_TEMPLATE_DIRECTORY_NAME = "src/test/data/template";
private static final String ANY_TEMPLATE_URL = "https://raw.githubusercontent.com/apache/freemarker-generator/master/freemarker-generator-cli/src/app/templates/freemarker-generator/info.ftl";
private static final String ANY_ENV_URI = "env:///JAVA_HOME";
diff --git a/freemarker-generator-cli/src/test/templates/echo.ftl b/freemarker-generator-cli/src/test/templates/echo.ftl
index 38627f4..56c0b56 100644
--- a/freemarker-generator-cli/src/test/templates/echo.ftl
+++ b/freemarker-generator-cli/src/test/templates/echo.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#list dataSources?values as ds>
+<#list dataSources as ds>
${ds.name}, ${ds.uri}
=============================================================================
${ds.text}
diff --git a/freemarker-generator-cli/src/test/templates/manual.ftl b/freemarker-generator-cli/src/test/templates/manual.ftl
index c1112be..1e6f5ac 100644
--- a/freemarker-generator-cli/src/test/templates/manual.ftl
+++ b/freemarker-generator-cli/src/test/templates/manual.ftl
@@ -22,8 +22,8 @@
Use FTL Array-style Access
==============================================================================
-${dataSources?values[0].toString()}
-${dataSources?values?first.toString()}
+${dataSources[0].toString()}
+${dataSources?first.toString()}
Get Document Names As Keys
==============================================================================
@@ -38,13 +38,13 @@
</#list>
<#if dataSources?has_content>
- <#list dataSources?values as dataSource>
+ <#list dataSources as dataSource>
[#${dataSource?counter}] - ${dataSource.name}
==============================================================================
Invoke Arbitrary Methods On DataSource
---------------------------------------------------------------------------
-<#assign dataSource=dataSources?values?first>
+<#assign dataSource=dataSources?first>
Name : ${dataSource.name}
Nr of lines : ${dataSource.lines?size}
Content Type : ${dataSource.contentType}
diff --git a/freemarker-generator-cli/src/test/templates/tools/csv.ftl b/freemarker-generator-cli/src/test/templates/tools/csv.ftl
index 25dfb3b..07c4f43 100644
--- a/freemarker-generator-cli/src/test/templates/tools/csv.ftl
+++ b/freemarker-generator-cli/src/test/templates/tools/csv.ftl
@@ -15,7 +15,7 @@
specific language governing permissions and limitations
under the License.
-->
-<#assign records = tools.csv.parse(dataSources?values[0], CSVFormat.DEFAULT.withHeader()).records>
+<#assign records = tools.csv.parse(dataSources[0], CSVFormat.DEFAULT.withHeader()).records>
tools.csv.toMap(name)
=============================================================================
diff --git a/freemarker-generator-maven-plugin-sample/pom.xml b/freemarker-generator-maven-plugin-sample/pom.xml
index cbd84a1..1ce4a10 100644
--- a/freemarker-generator-maven-plugin-sample/pom.xml
+++ b/freemarker-generator-maven-plugin-sample/pom.xml
@@ -20,7 +20,7 @@
<parent>
<groupId>org.apache.freemarker.generator</groupId>
<artifactId>freemarker-generator</artifactId>
- <version>0.1.0-SNAPSHOT</version>
+ <version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>freemarker-generator-maven-plugin-sample</artifactId>
<name>Apache FreeMarker Generator: Maven Plugin Sample</name>
diff --git a/freemarker-generator-maven-plugin/pom.xml b/freemarker-generator-maven-plugin/pom.xml
index d1f9515..c8b014a 100644
--- a/freemarker-generator-maven-plugin/pom.xml
+++ b/freemarker-generator-maven-plugin/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.freemarker.generator</groupId>
<artifactId>freemarker-generator</artifactId>
- <version>0.1.0-SNAPSHOT</version>
+ <version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>freemarker-generator-maven-plugin</artifactId>
diff --git a/freemarker-generator-tools/pom.xml b/freemarker-generator-tools/pom.xml
index e532237..04ca3f1 100644
--- a/freemarker-generator-tools/pom.xml
+++ b/freemarker-generator-tools/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.freemarker.generator</groupId>
<artifactId>freemarker-generator</artifactId>
- <version>0.1.0-SNAPSHOT</version>
+ <version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>freemarker-generator-tools</artifactId>
@@ -129,6 +129,12 @@
<artifactId>snakeyaml</artifactId>
<version>1.28</version>
</dependency>
+ <!-- UtahPrserTool -->
+ <dependency>
+ <groupId>com.sonalake</groupId>
+ <artifactId>utah-parser</artifactId>
+ <version>1.0.2</version>
+ </dependency>
<!-- Testing -->
<dependency>
<groupId>junit</groupId>
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVTool.java
index 3490ee8..12c757d 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/CommonsCSVTool.java
@@ -110,7 +110,7 @@
}
/**
- * Extract the list of unique values (keys) of the column with the given index..
+ * Extract the list of unique values (keys) of the column with the given index.
*
* @param records records to process
* @param index column index to map
@@ -123,7 +123,7 @@
/**
* Map the given value of the CVS record into (key to record). If duplicates
* are encountered return the first occurrence of the CVS record. The map
- * retains the insertion order of they keys.
+ * retains the insertion order of their keys.
*
* @param records records to process
* @param name column name to map
@@ -136,7 +136,7 @@
/**
* Map the given value of the CVS record into (key to record). If duplicates
* are encountered return the first occurrence of the CVS record. The map
- * retains the insertion order of they keys.
+ * retains the insertion order of their keys.
*
* @param records records to process
* @param index column index to map
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/impl/CommonsCSVPrinterFacade.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/impl/CommonsCSVPrinterFacade.java
index 9909d17..958dbdb 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/impl/CommonsCSVPrinterFacade.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/commonscsv/impl/CommonsCSVPrinterFacade.java
@@ -25,6 +25,9 @@
import java.io.StringWriter;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
/**
* Wrap <code>CSVPrinter</code> so each print method returns
@@ -91,6 +94,15 @@
return getOutput();
}
+ public String printRecord(Map<String, Object> map, String[] headers) throws IOException {
+ final List<String> values = new ArrayList<>(headers.length);
+ for (String header : headers) {
+ final Object value = map.get(header);
+ values.add(value != null ? value.toString() : "");
+ }
+ return printRecord(values);
+ }
+
private String getOutput() {
writer.flush();
final String output = writer.getBuffer().toString();
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/CSVConverter.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/CSVConverter.java
index 5745c35..30c1938 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/CSVConverter.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/dataframe/impl/CSVConverter.java
@@ -40,7 +40,7 @@
final CSVRecord firstRecord = records.get(0);
// build dataframe with headers
- if (headerNames != null && !headerNames.isEmpty()) {
+ if (!headerNames.isEmpty()) {
headerNames.forEach(builder::addStringColumn);
} else {
for (int i = 0; i < firstRecord.size(); i++) {
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
index eff89ea..300cf44 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/excel/ExcelTool.java
@@ -80,7 +80,7 @@
}
/**
- * Transform the Excel sheet into a table. Please not that locales are mostly
+ * Transform the Excel sheet into a table. Please note that locales are mostly
* ignored by Apache POI (see https://poi.apache.org/apidocs/dev/org/apache/poi/ss/usermodel/DataFormatter.html)
*
* @param sheet Excel sheet
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokTool.java
index 5f3a485..34af4bd 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/grok/GrokTool.java
@@ -28,7 +28,7 @@
private static final String DEFAULT_PATTERN_FILE = "/patterns/patterns";
/**
- * Create a default Grok instance using the the default pattern files loaded
+ * Create a default Grok instance using the default pattern files loaded
* from the classpath.
*
* @param pattern Grok pattern to compile
@@ -39,7 +39,7 @@
}
/**
- * Get a default Grok instance using the the default pattern files loaded
+ * Get a default Grok instance using the default pattern files loaded
* from the classpath.
*
* @param pattern Grok pattern to compile
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/system/SystemTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/system/SystemTool.java
index 36a8139..be6ad05 100644
--- a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/system/SystemTool.java
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/system/SystemTool.java
@@ -95,18 +95,41 @@
return System.getProperties();
}
+ /**
+ * Get the value of a user-supplied parameter.
+ *
+ * @param name name of the parameter
+ * @return value or null
+ */
public String getParameter(String name) {
return parameters.get(name);
}
+ /**
+ * Get the value of a user-supplied parameter.
+ *
+ * @param name name of the parameter
+ * @param def default value
+ * @return value or default value
+ */
public String getParameter(String name, String def) {
return parameters.getOrDefault(name, def);
}
+ /**
+ * Get the map of user-supplied parameters.
+ *
+ * @return map of parameters
+ */
public Map<String, String> getParameters() {
return parameters;
}
+ /**
+ * Get the list of system properties provided by the caller.
+ *
+ * @return list of user-supplied system properties
+ */
public Properties getUserSystemProperties() {
return userSystemProperties;
}
@@ -132,7 +155,7 @@
* @param name name of the configuration parameter
* @return value of null
*/
- public String getString(String name) {
+ public String getProperty(String name) {
return StringUtils.firstNonEmpty(
getParameter(name),
System.getProperty(name),
@@ -148,8 +171,8 @@
* @param def default value
* @return value of null
*/
- public String getString(String name, String def) {
- return StringUtils.firstNonEmpty(getString(name), def);
+ public String getProperty(String name, String def) {
+ return StringUtils.firstNonEmpty(getProperty(name), def);
}
public String getHostName() {
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/utahparser/UtahParserTool.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/utahparser/UtahParserTool.java
new file mode 100644
index 0000000..82520ef
--- /dev/null
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/utahparser/UtahParserTool.java
@@ -0,0 +1,100 @@
+/*
+ * 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.tools.utahparser;
+
+import com.sonalake.utah.Parser;
+import com.sonalake.utah.config.Config;
+import com.sonalake.utah.config.ConfigLoader;
+import org.apache.freemarker.generator.base.datasource.DataSource;
+import org.apache.freemarker.generator.base.datasource.DataSourceLoaderFactory;
+import org.apache.freemarker.generator.tools.utahparser.impl.ParserWrapper;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class UtahParserTool {
+
+ /**
+ * Create a Utah Parser config based on the given source.
+ *
+ * @param source source of configuration file
+ * @return config instance
+ */
+ public Config getConfig(String source) {
+ return getConfig(DataSourceLoaderFactory.create().load(source));
+ }
+
+ /**
+ * Create a Utah Parser config based on teh textual content of the data source,
+ *
+ * @param dataSource XML configuration file
+ * @return config instance
+ */
+ public Config getConfig(DataSource dataSource) {
+ try (InputStream is = dataSource.getUnsafeInputStream()) {
+ return loadConfig(is);
+ } catch (Exception e) {
+ throw new RuntimeException("Failed to load parser configuration: " + dataSource, e);
+ }
+ }
+
+ /**
+ * Create a parser instance.
+ *
+ * @param config configuration
+ * @param dataSource data source to be parsed
+ * @return parser
+ */
+ public ParserWrapper getParser(Config config, DataSource dataSource) {
+ final InputStreamReader is = new InputStreamReader(dataSource.getInputStream());
+ final Parser parser = Parser.parse(config, is);
+ return new ParserWrapper(parser);
+ }
+
+ public List<String> getHeaders(Map<String, Object> record) {
+ if (record == null || record.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ return new ArrayList<>(record.keySet());
+ }
+
+ public List<String> getHeaders(Collection<Map<String, String>> records) {
+ if (records == null || records.isEmpty()) {
+ return Collections.emptyList();
+ }
+
+ return records.stream()
+ .map(Map::keySet)
+ .flatMap(Collection::stream).distinct().sorted().collect(Collectors.toList());
+ }
+
+ public String toString() {
+ return "Parse semi-structured text using regular expressions (see https://github.com/sonalake/utah-parser)";
+ }
+
+ private static Config loadConfig(InputStream is) throws IOException {
+ return new ConfigLoader().loadConfig(new InputStreamReader(is));
+ }
+}
\ No newline at end of file
diff --git a/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/utahparser/impl/ParserWrapper.java b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/utahparser/impl/ParserWrapper.java
new file mode 100644
index 0000000..9aad9bc
--- /dev/null
+++ b/freemarker-generator-tools/src/main/java/org/apache/freemarker/generator/tools/utahparser/impl/ParserWrapper.java
@@ -0,0 +1,86 @@
+/*
+ * 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.tools.utahparser.impl;
+
+import com.sonalake.utah.Parser;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import static java.util.Objects.requireNonNull;
+
+/**
+ * Wraps the <code>com.sonalake.utah.Parser</code> to provide convenience
+ * methods such as support of iterators.
+ */
+public class ParserWrapper implements Iterable<Map<String, String>> {
+
+ /** The wrapped parser instance */
+ private final Parser parser;
+
+ public ParserWrapper(Parser parser) {
+ this.parser = requireNonNull(parser);
+ }
+
+ @Override
+ public Iterator<Map<String, String>> iterator() {
+ return new RecordsIterator(parser);
+ }
+
+ /**
+ * Iterates over all records and return a list.
+ *
+ * @return list of records
+ */
+ public List<Map<String, String>> toList() {
+ final List<Map<String, String>> result = new ArrayList<>();
+ for (Map<String, String> record : this) {
+ result.add(record);
+ }
+ return result;
+ }
+
+ private static final class RecordsIterator implements Iterator<Map<String, String>> {
+
+ private final Parser parser;
+ private Map<String, String> nextRecord;
+
+ RecordsIterator(Parser parser) {
+ this.parser = requireNonNull(parser);
+ this.nextRecord = parser.next();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return nextRecord != null;
+ }
+
+ @Override
+ public Map<String, String> next() {
+ if (nextRecord == null) {
+ throw new NoSuchElementException();
+ }
+
+ final Map<String, String> currentRecord = nextRecord;
+ nextRecord = parser.next();
+ return currentRecord;
+ }
+ }
+}
\ No newline at end of file
diff --git a/freemarker-generator-tools/src/test/data/utahparser/juniper_bgp_summary_example.txt b/freemarker-generator-tools/src/test/data/utahparser/juniper_bgp_summary_example.txt
new file mode 100644
index 0000000..c4a209e
--- /dev/null
+++ b/freemarker-generator-tools/src/test/data/utahparser/juniper_bgp_summary_example.txt
@@ -0,0 +1,12 @@
+Groups: 3 Peers: 3 Down peers: 0
+Table Tot Paths Act Paths Suppressed History Damp State Pending
+inet.0 947 310 0 0 0 0
+inet6.0 849 807 0 0 0 0
+Peer AS InPkt OutPkt OutQ Flaps Last Up/Dwn State|#Active/Received/Damped...
+10.247.68.182 65550 131725 28179233 0 11 6w3d17h Establ
+ inet.0: 4/5/1
+ inet6.0: 0/0/0
+10.254.166.246 65550 136159 29104942 0 0 6w5d6h Establ
+ inet.0: 0/0/0
+ inet6.0: 7/8/1
+192.0.2.100 65551 1269381 1363320 0 1 9w5d6h 1/2/3 4/5/6
\ No newline at end of file
diff --git a/freemarker-generator-tools/src/test/data/utahparser/juniper_bgp_summary_template.xml b/freemarker-generator-tools/src/test/data/utahparser/juniper_bgp_summary_template.xml
new file mode 100644
index 0000000..bb1093a
--- /dev/null
+++ b/freemarker-generator-tools/src/test/data/utahparser/juniper_bgp_summary_template.xml
@@ -0,0 +1,69 @@
+<config>
+ <searches>
+
+ <!-- in this case, we have a CSV (space delimited file) so we define the line once, and then reuse it over
+ and again for each value -->
+ <search id="QUERY-LINE"><![CDATA[\s*{ipAddress}\s+{numbers}\s+{numbers}\s+{numbers}\s+{numbers}\s+{numbers}\s+{numbersThenText}]]></search>
+
+
+ <search id="inetInline"><![CDATA[{inet} {inet}]]></search>
+ <search id="inet4"><![CDATA[inet.0:\s*{inet}]]></search>
+ <search id="inet6"><![CDATA[inet6.0:\s*{inet}]]></search>
+ <search id="inet"><![CDATA[{numbers}/{numbers}/{numbers}]]></search>
+
+ <!-- Some rules for finding text, to make the values a little easier below -->
+ <search id="numbers"><![CDATA[(\d+)]]></search>
+ <search id="numbersThenText"><![CDATA[(\d+\S+)]]></search>
+ <search id="string"><![CDATA[(\S+?)]]></search>
+ <search id="ipAddress"><![CDATA[(\d+(\.\d+){3})]]></search>
+ <search id="EOL"><![CDATA[[\n\r]]]></search>
+ </searches>
+
+ <!-- the record starts with a line with an ip address and ends with either an inet6 line, or where the ids are at
+ the end of the line-->
+ <delim retain="true">{ipAddress}.*(\/\d+)\s*{EOL}</delim>
+ <delim>\s*({inet6})</delim>
+
+ <!--
+ This is the last line of the header
+ -->
+ <header-delim><![CDATA[Peer\s+AS\s+InPkt]]></header-delim>
+
+ <!--
+ Files look like this:
+
+ 10.247.68.182 65550 131725 28179233 0 11 6w3d17h Establ
+ inet.0: 4/5/1
+ inet6.0: 0/0/0
+
+ or
+
+ 192.0.2.100 65551 1269381 1363320 0 1 9w5d6h 2/3/0 0/0/0
+ -->
+ <values>
+ <!-- here we reuse the line pattern, only we pull out different group values -->
+ <value id="remoteIp" group="1"><![CDATA[{QUERY-LINE}]]></value>
+ <value id="uptime" group="8"><![CDATA[{QUERY-LINE}]]></value>
+
+ <!-- here we check for values in the inet* lines and use these -->
+ <value id="activeV4" group="1"><![CDATA[{inet4}]]></value>
+ <value id="receivedV4" group="2"><![CDATA[{inet4}]]></value>
+ <value id="accepted_V4" group="3"><![CDATA[{inet4}]]></value>
+
+ <value id="activeV6" group="1"><![CDATA[{inet6}]]></value>
+ <value id="receivedV6" group="2"><![CDATA[{inet6}]]></value>
+ <value id="accepted_V6" group="3"><![CDATA[{inet6}]]></value>
+
+ <!--
+ here we check for values at the end of the query line, and use these
+ NOTE: since we only set non-null values, these will not overwrite any values set above
+ -->
+ <value id="activeV4" group="9"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="receivedV4" group="10"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="accepted_V4" group="11"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="activeV6" group="12"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="receivedV6" group="13"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+ <value id="accepted_V6" group="14"><![CDATA[{QUERY-LINE}\s*{inetInline}]]></value>
+
+ </values>
+</config>
\ No newline at end of file
diff --git a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/commonsexec/CommonsExecToolTest.java b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/commonsexec/CommonsExecToolTest.java
index 8f30444..a9a49d2 100644
--- a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/commonsexec/CommonsExecToolTest.java
+++ b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/commonsexec/CommonsExecToolTest.java
@@ -16,13 +16,39 @@
*/
package org.apache.freemarker.generator.tools.commonsexec;
+import org.apache.freemarker.generator.base.util.OperatingSystem;
import org.junit.Test;
+import java.util.Collections;
+
+import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
public class CommonsExecToolTest {
@Test
+ public void shouldExecuteCommandLine() {
+ if (OperatingSystem.isMac() || OperatingSystem.isUnix()) {
+ final String output = commonsExecTool().execute("echo Hello World!");
+ assertEquals("Hello World!\n", output);
+ }
+ }
+
+ @Test
+ public void shouldExecuteCommandLineArgs() {
+ if (OperatingSystem.isMac() || OperatingSystem.isUnix()) {
+ final String output = commonsExecTool().execute("echo", Collections.singletonList("Hello World!"));
+
+ assertEquals("\"Hello World!\"\n", output);
+ }
+ }
+
+ @Test(expected = RuntimeException.class)
+ public void shouldThrowExceptionForInvalidCommand() {
+ commonsExecTool().execute("does-not-exist.bat");
+ }
+
+ @Test
public void shouldReturnDescription() {
assertFalse(commonsExecTool().toString().isEmpty());
}
diff --git a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/system/SystemToolTest.java b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/system/SystemToolTest.java
index 23d90ee..de55318 100644
--- a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/system/SystemToolTest.java
+++ b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/system/SystemToolTest.java
@@ -36,13 +36,13 @@
}
@Test
- public void shouldGetString() {
- assertEquals(USER, systemTool().getString("USER"));
+ public void shouldGetProperty() {
+ assertEquals(USER, systemTool().getProperty("USER"));
}
@Test
- public void shouldGetStringWithDefault() {
- assertEquals("foo", systemTool().getString("_DOES_NOT_EXIST_", "foo"));
+ public void shouldGetPropertyWithDefault() {
+ assertEquals("foo", systemTool().getProperty("_DOES_NOT_EXIST_", "foo"));
}
@Test
diff --git a/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/utahparser/UtahParserToolTest.java b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/utahparser/UtahParserToolTest.java
new file mode 100644
index 0000000..fac9e75
--- /dev/null
+++ b/freemarker-generator-tools/src/test/java/org/apache/freemarker/generator/tools/utahparser/UtahParserToolTest.java
@@ -0,0 +1,103 @@
+package org.apache.freemarker.generator.tools.utahparser;
+
+import com.sonalake.utah.config.Config;
+import org.apache.freemarker.generator.base.datasource.DataSource;
+import org.apache.freemarker.generator.base.datasource.DataSourceFactory;
+import org.apache.freemarker.generator.base.util.MapBuilder;
+import org.apache.freemarker.generator.tools.utahparser.impl.ParserWrapper;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertNotNull;
+import static junit.framework.TestCase.assertTrue;
+
+public class UtahParserToolTest {
+
+ private static final String EXAMPLE_FILE_NAME = "src/test/data/utahparser/juniper_bgp_summary_example.txt";
+ private static final String TEMPLATE_FILE_NAME = "src/test/data/utahparser/juniper_bgp_summary_template.xml";
+
+ @Test
+
+ public void shallLoadConfFromFile() {
+ final Config config = utahParserTool().getConfig(TEMPLATE_FILE_NAME);
+
+ assertNotNull(config);
+ assertTrue(config.isDelimiterValid());
+ }
+
+ @Test
+ public void shallLoadConfFromDataSource() {
+ final DataSource dataSource = dataSource(TEMPLATE_FILE_NAME);
+ final Config config = utahParserTool().getConfig(dataSource);
+
+ assertNotNull(config);
+ assertTrue(config.isDelimiterValid());
+ }
+
+ @Test
+ public void shallGetParserInstance() {
+ final DataSource dataSource = dataSource(EXAMPLE_FILE_NAME);
+ final UtahParserTool utahParserTool = utahParserTool();
+ final Config config = utahParserTool.getConfig(TEMPLATE_FILE_NAME);
+ final ParserWrapper parser = utahParserTool.getParser(config, dataSource);
+
+ assertNotNull(parser);
+ assertNotNull(parser.iterator());
+ }
+
+ @Test
+ public void shallParseAllData() {
+ final DataSource dataSource = dataSource(EXAMPLE_FILE_NAME);
+ final UtahParserTool utahParserTool = utahParserTool();
+ final Config config = utahParserTool.getConfig(TEMPLATE_FILE_NAME);
+ final ParserWrapper parser = utahParserTool.getParser(config, dataSource);
+ final List<Map<String, String>> records = parser.toList();
+
+ assertEquals(3, records.size());
+ }
+
+ @Test
+ public void shallGetHeadersFromRecord() {
+ final UtahParserTool utahParserTool = utahParserTool();
+ final Map<String, Object> record = MapBuilder.toLinkedMap("header1", "foo", "header2", "bar");
+
+ final List<String> headers = utahParserTool.getHeaders(record);
+
+ assertEquals("header1", headers.get(0));
+ assertEquals("header2", headers.get(1));
+ }
+
+ @Test
+ public void shallGetHeadersFromRecords() {
+ final DataSource dataSource = dataSource(EXAMPLE_FILE_NAME);
+ final UtahParserTool utahParserTool = utahParserTool();
+ final Config config = utahParserTool.getConfig(TEMPLATE_FILE_NAME);
+ final ParserWrapper parser = utahParserTool.getParser(config, dataSource);
+ final List<Map<String, String>> records = parser.toList();
+
+ final List<String> headers = utahParserTool.getHeaders(records);
+
+ assertEquals("accepted_V4", headers.get(0));
+ assertEquals("accepted_V6", headers.get(1));
+ assertEquals("activeV4", headers.get(2));
+ assertEquals("activeV6", headers.get(3));
+ assertEquals("receivedV4", headers.get(4));
+ assertEquals("receivedV6", headers.get(5));
+ assertEquals("remoteIp", headers.get(6));
+ assertEquals("uptime", headers.get(7));
+ }
+
+ private static UtahParserTool utahParserTool() {
+ return new UtahParserTool();
+ }
+
+ private static DataSource dataSource(String fileName) {
+ return DataSourceFactory.fromFile(new File(fileName), UTF_8);
+ }
+
+}
diff --git a/freemarker-generator-website/pom.xml b/freemarker-generator-website/pom.xml
index a5cc6ff..f8424c5 100644
--- a/freemarker-generator-website/pom.xml
+++ b/freemarker-generator-website/pom.xml
@@ -22,7 +22,7 @@
<parent>
<groupId>org.apache.freemarker.generator</groupId>
<artifactId>freemarker-generator</artifactId>
- <version>0.1.0-SNAPSHOT</version>
+ <version>0.2.0-SNAPSHOT</version>
</parent>
<artifactId>freemarker-generator-website</artifactId>
diff --git a/freemarker-generator-website/src/main/docgen/book.xml b/freemarker-generator-website/src/main/docgen/book.xml
index 791051c..0da2433 100644
--- a/freemarker-generator-website/src/main/docgen/book.xml
+++ b/freemarker-generator-website/src/main/docgen/book.xml
@@ -627,15 +627,15 @@
[/docgen.insertWithOutput]
[docgen.insertWithOutput]
-freemarker-generator -i '${tools.jsonpath.parse(dataSources?values[0]).read("$.info.title")}' [docgen.wd]/examples/data/json/swagger-spec.json
+freemarker-generator -i '${tools.jsonpath.parse(dataSources[0]).read("$.info.title")}' [docgen.wd]/examples/data/json/swagger-spec.json
[/docgen.insertWithOutput]
[docgen.insertWithOutput]
-freemarker-generator -i '${tools.xml.parse(dataSources?values[0])["recipients/person[1]/name"]}' [docgen.wd]/examples/data/xml/recipients.xml
+freemarker-generator -i '${tools.xml.parse(dataSources[0])["recipients/person[1]/name"]}' [docgen.wd]/examples/data/xml/recipients.xml
[/docgen.insertWithOutput]
[docgen.insertWithOutput]
-freemarker-generator -i '${tools.jsoup.parse(dataSources?values[0]).select("a")[0]}' [docgen.wd]/examples/data/html/dependencies.html
+freemarker-generator -i '${tools.jsoup.parse(dataSources[0]).select("a")[0]}' [docgen.wd]/examples/data/html/dependencies.html
[/docgen.insertWithOutput]</programlisting>
<remark>I have deleted some examples above, as they were problematic
@@ -653,7 +653,7 @@
filtering (based on some primary key) and and transforming into a
human-readable output format (Markdown).</para>
- <para>So lets start the filtering & transformaction using the
+ <para>So lets start the filtering & transformation using the
following command line</para>
<programlisting>[docgen.insertWithOutput]
@@ -674,11 +674,11 @@
YAML or the other way around.</para>
<programlisting>[docgen.insertWithOutput]freemarker-generator -t freemarker-generator/yaml/json/transform.ftl [docgen.wd]/examples/data/yaml/swagger-spec.yaml[/docgen.insertWithOutput]
-[docgen.insertWithOutput]freemarker-generator -i '${tools.gson.toJson(tools.yaml.parse(dataSources?values[0]))}' [docgen.wd]/examples/data/yaml/swagger-spec.yaml[/docgen.insertWithOutput]
+[docgen.insertWithOutput]freemarker-generator -i '${tools.gson.toJson(tools.yaml.parse(dataSources[0]))}' [docgen.wd]/examples/data/yaml/swagger-spec.yaml[/docgen.insertWithOutput]
[docgen.insertWithOutput]freemarker-generator -i '${tools.gson.toJson(yaml)}' -m yaml=[docgen.wd]/examples/data/yaml/swagger-spec.yaml[/docgen.insertWithOutput]
[docgen.insertWithOutput]freemarker-generator -t freemarker-generator/json/yaml/transform.ftl [docgen.wd]/examples/data/json/swagger-spec.json[/docgen.insertWithOutput]
-[docgen.insertWithOutput]freemarker-generator -i '${tools.yaml.toYaml(tools.gson.parse(dataSources?values[0]))}' [docgen.wd]/examples/data/json/swagger-spec.json[/docgen.insertWithOutput]
+[docgen.insertWithOutput]freemarker-generator -i '${tools.yaml.toYaml(tools.gson.parse(dataSources[0]))}' [docgen.wd]/examples/data/json/swagger-spec.json[/docgen.insertWithOutput]
[docgen.insertWithOutput]freemarker-generator -i '${tools.yaml.toYaml(json)}' -m json=[docgen.wd]/examples/data/json/swagger-spec.json[/docgen.insertWithOutput]</programlisting>
</section>
@@ -848,20 +848,20 @@
<para>A <literal>DataSource</literal> can be loaded from the file
system, e.g., as positional command line argument:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl [docgen.wd]/README.md
[/docgen.insertWithOutput]</programlisting>
<para>from an URL:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl --data-source xkcd=https://xkcd.com/info.0.json
[/docgen.insertWithOutput]</programlisting>
<para>or from an environment variable, e.g.
<literal>NGINX_CONF</literal> having a JSON payload:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"
systemProperties={'freemarker.generator.datasource.envOverride.NGINX_CONF': '{"NGINX_PORT":"8443","NGINX_HOSTNAME":"localhost"}'}
]
freemarker-generator -t freemarker-generator/info.ftl --data-source conf=env:///NGINX_CONF#mimeType=application/json
@@ -869,20 +869,20 @@
<para>Of course you can load multiple data sources directly:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl [docgen.wd]/README.md xkcd=https://xkcd.com/info.0.json
[/docgen.insertWithOutput]</programlisting>
<para>or load them from a directory:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl --data-source [docgen.wd]/examples/data
[/docgen.insertWithOutput]</programlisting>
<para>which can be combined with <literal>include</literal> and
<literal>exclude</literal> filters:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl -s [docgen.wd]/examples/data --data-source-include='*.json'
[/docgen.insertWithOutput]</programlisting>
@@ -894,7 +894,7 @@
<programlisting>cat examples/data/csv/contract.csv | bin/freemarker-generator -t freemarker-generator/info.ftl --stdin
-FreeMarker Generator DataSources
+FreeMarker Generator Data Sources
------------------------------------------------------------------------------
[#1]: name=stdin, group=default, fileName=stdin mimeType=text/plain, charset=UTF-8, length=-1 Bytes
URI : system:///stdin</programlisting>
@@ -909,8 +909,8 @@
<itemizedlist>
<listitem>
- <para><literal>dataSources?values[0]</literal> or
- <literal>dataSources?values?first</literal> selects the first data
+ <para><literal>dataSources[0]</literal> or
+ <literal>dataSources?first</literal> selects the first data
source</para>
</listitem>
@@ -944,7 +944,7 @@
</#list>
<#-- Iterate over a list of data sources -->
-<#list dataSources?values as dataSource>
+<#list dataSources as dataSource>
- [#${dataSource?counter}]: name=${dataSource.name}
</#list></programlisting>
</section>
@@ -959,22 +959,22 @@
here)</remark>:</para>
<programlisting><#-- List all data sources containing "test" in the name -->
-<#list dataSources?values?filter(ds -> ds.match("name", "*test*")) as ds>
+<#list dataSources?filter(ds -> ds.match("name", "*test*")) as ds>
- ${ds.name}
</#list>
<#-- List all data sources having "json" extension -->
-<#list dataSources?values?filter(ds -> ds.match("extension", "json")) as ds>
+<#list dataSources?filter(ds -> ds.match("extension", "json")) as ds>
- ${ds.name}
</#list>
<#-- List all data sources having "src/test/data/properties" in their file path -->
-<#list dataSources?values?filter(ds -> ds.match("filePath", "*/src/test/data/properties")) as ds>
+<#list dataSources?filter(ds -> ds.match("filePath", "*/src/test/data/properties")) as ds>
- ${ds.name}
</#list>
<#-- List all data sources of a group -->
-<#list dataSources?values?filter(ds -> ds.match("group", "default")) as ds>
+<#list dataSources?filter(ds -> ds.match("group", "default")) as ds>
- ${ds.name}
</#list></programlisting>
</section>
@@ -1073,27 +1073,27 @@
<para>The following Named URI loads a <literal>user.csv</literal> and
the data source is available as <literal>my_users</literal>:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl my_users=[docgen.wd]/examples/data/csv/user.csv
[/docgen.insertWithOutput]</programlisting>
<para>A Named URI allows to pass additional information as part of the
fragment, e.g. the charset of the text file:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl my_users=[docgen.wd]/examples/data/csv/user.csv#charset=UTF-16
[/docgen.insertWithOutput]</programlisting>
<para>In addition to the simplified file syntax full URIs can be
used:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl https://www.google.com#charset=ISO-8859-1
[/docgen.insertWithOutput]</programlisting>
<para>and also combined with a name:</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl page=http://www.google.com#charset=ISO-8859-1
[/docgen.insertWithOutput]</programlisting>
</section>
@@ -1105,14 +1105,14 @@
<para>Load all CVS files of a directory using the group "csv":</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
freemarker-generator -t freemarker-generator/info.ftl :csv=[docgen.wd]/examples/data/csv
[/docgen.insertWithOutput]</programlisting>
<para>or use a charset for all files of a directory</para>
- <programlisting>[docgen.insertWithOutput from="FreeMarker Generator DataSources" to=r"^\s*$"]
-freemarker-generator -t freemarker-generator/info.ftl '[docgen.wd]/examples/data/csv#charset=UTF-16&mimetype=text/plain'
+ <programlisting>[docgen.insertWithOutput from="FreeMarker Generator Data Sources" to=r"^\s*$"]
+freemarker-generator -t freemarker-generator/info.ftl '[docgen.wd]/examples/data/csv#charset=UTF-16&mimeType=text/plain'
[/docgen.insertWithOutput]</programlisting>
<para>It is also possible to provide data source properties to all
diff --git a/licences/LICENCE_utahparser.txt b/licences/LICENCE_utahparser.txt
new file mode 100644
index 0000000..9c8f3ea
--- /dev/null
+++ b/licences/LICENCE_utahparser.txt
@@ -0,0 +1,201 @@
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "{}"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright {yyyy} {name of copyright owner}
+
+ 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.
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index e15144c..daf9e42 100644
--- a/pom.xml
+++ b/pom.xml
@@ -27,7 +27,7 @@
<groupId>org.apache.freemarker.generator</groupId>
<artifactId>freemarker-generator</artifactId>
<packaging>pom</packaging>
- <version>0.1.0-SNAPSHOT</version>
+ <version>0.2.0-SNAPSHOT</version>
<name>Apache FreeMarker Generator</name>
<url>https://freemarker-generator.apache.org/</url>
@@ -163,6 +163,10 @@
<version>3.12.0</version>
</plugin>
<plugin>
+ <artifactId>maven-surefire-plugin</artifactId>
+ <version>3.0.0-M5</version>
+ </plugin>
+ <plugin>
<!-- Required by custom Maven skin -->
<artifactId>maven-site-plugin</artifactId>
<version>3.8.2</version>
@@ -219,6 +223,10 @@
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-surefire-report-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-pmd-plugin</artifactId>
<configuration>
<linkXRef>false</linkXRef>