Skip to content
Permalink
Browse files
Removing DataSources.first and use DataSources.get(0) instead (pl…
…us some minor improvements)
  • Loading branch information
sgoeschl committed Jul 7, 2020
1 parent 8ef281b commit f6f41bf8e823abbb4926a29bf441acb0c7f5a9d3
Showing 19 changed files with 218 additions and 96 deletions.
@@ -23,22 +23,23 @@
import org.apache.freemarker.generator.base.activation.StringDataSource;
import org.apache.freemarker.generator.base.mime.MimetypeParser;
import org.apache.freemarker.generator.base.util.CloseableReaper;
import org.apache.freemarker.generator.base.util.StringUtils;
import org.apache.freemarker.generator.base.util.Validate;

import javax.activation.FileDataSource;
import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.List;

import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.Objects.requireNonNull;
import static org.apache.commons.io.IOUtils.lineIterator;
import static org.apache.freemarker.generator.base.FreeMarkerConstants.DATASOURCE_UNKNOWN_LENGTH;
import static org.apache.freemarker.generator.base.util.StringUtils.emptyToNull;
import static org.apache.freemarker.generator.base.util.StringUtils.isNotEmpty;
import static org.apache.freemarker.generator.base.mime.Mimetypes.MIME_APPLICATION_OCTET_STREAM;

/**
* Data source which encapsulates data to be used for rendering
@@ -49,7 +50,7 @@
* the content type & charset might be determined using a network
* call.
*/
public class DataSource implements Closeable {
public class DataSource implements Closeable, javax.activation.DataSource {

/** Human-readable name of the data source */
private final String name;
@@ -63,7 +64,7 @@ public class DataSource implements Closeable {
/** The underlying "javax.activation.DataSource" */
private final javax.activation.DataSource dataSource;

/** Optional user-supplied content type */
/** Optional content type */
private final String contentType;

/** Optional charset for directly accessing text-based content */
@@ -80,18 +81,49 @@ public DataSource(
String contentType,
Charset charset) {
this.name = requireNonNull(name);
this.group = emptyToNull(group);
this.group = StringUtils.emptyToNull(group);
this.uri = requireNonNull(uri);
this.dataSource = requireNonNull(dataSource);
this.contentType = contentType;
this.charset = charset;
this.closables = new CloseableReaper();
}

@Override
public String getName() {
return name;
}

/**
* Get the content type.
*
* @return content type
*/
@Override
public String getContentType() {
return contentType();
}

/**
* Get an input stream which is closed together with this data source.
*
* @return InputStream
*/
@Override
public InputStream getInputStream() {
return closables.add(getUnsafeInputStream());
}

@Override
public OutputStream getOutputStream() {
throw new RuntimeException("No output stream supported");
}

@Override
public void close() {
closables.close();
}

public String getGroup() {
return group;
}
@@ -109,11 +141,11 @@ public Charset getCharset() {
}

/**
* Get the content type without additional parameters, e.g. "charset".
* Get the mimetype , i.e. content type without additional charset parameter.
*
* @return content type
* @return mimetype
*/
public String getContentType() {
public String getMimetype() {
return MimetypeParser.getMimetype(contentType());
}

@@ -138,15 +170,6 @@ public long getLength() {
}
}

/**
* Get an input stream which is closed together with this data source.
*
* @return InputStream
*/
public InputStream getInputStream() {
return closables.add(getUnsafeInputStream());
}

/**
* Get an input stream which needs to be closed by the caller.
*
@@ -165,6 +188,7 @@ public String getText() {
}

public String getText(String charsetName) {
Validate.notEmpty(charsetName, "No charset name provided");
final StringWriter writer = new StringWriter();
try (InputStream is = getUnsafeInputStream()) {
IOUtils.copy(is, writer, Charset.forName(charsetName));
@@ -192,6 +216,7 @@ public List<String> getLines() {
* @return the list of Strings, never null
*/
public List<String> getLines(String charsetName) {
Validate.notEmpty(charsetName, "No charset name provided");
try (InputStream inputStream = getUnsafeInputStream()) {
return IOUtils.readLines(inputStream, charsetName);
} catch (IOException e) {
@@ -218,8 +243,9 @@ public LineIterator getLineIterator() {
* @return line iterator
*/
public LineIterator getLineIterator(String charsetName) {
Validate.notEmpty(charsetName, "No charset name provided");
try {
return closables.add(lineIterator(getUnsafeInputStream(), Charset.forName(charsetName)));
return closables.add(IOUtils.lineIterator(getUnsafeInputStream(), Charset.forName(charsetName)));
} catch (IOException e) {
throw new RuntimeException("Failed to create line iterator: " + toString(), e);
}
@@ -233,6 +259,19 @@ public byte[] getBytes() {
}
}

/**
* Matches a metadata entry with a wildcard expression.
*
* @param part part, e.g. "name", "basename", "extension", "uri", "group"
* @param wildcard the wildcard string to match against
* @return true if the wildcard expression matches
* @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 boolean match(String part, String wildcard) {
final String value = getPart(part);
return FilenameUtils.wildcardMatch(value, wildcard);
}

/**
* Some tools create a {@link java.io.Closeable} which can bound to the
* lifecycle of the data source. When the data source is closed all the
@@ -246,11 +285,6 @@ public <T extends Closeable> T addClosable(T closeable) {
return closables.add(closeable);
}

@Override
public void close() {
closables.close();
}

@Override
public String toString() {
return "DataSource{" +
@@ -260,7 +294,43 @@ public String toString() {
'}';
}

/**
* If there is no content type we ask the underlying data source. E.g. for
* an URL data source this information is fetched from the server.
*
* @return content type
*/
private String contentType() {
return isNotEmpty(contentType) ? contentType : dataSource.getContentType();
if (StringUtils.isNotEmpty(contentType)) {
return contentType;
} else {
return StringUtils.firstNonEmpty(dataSource.getContentType(), MIME_APPLICATION_OCTET_STREAM);
}
}

private String getPart(String part) {
Validate.notEmpty(part, "No metadata part provided");
switch (part.toLowerCase()) {
case "basename":
return getBaseName();
case "contenttype":
return getContentType();
case "extension":
return getExtension();
case "group":
return getGroup();
case "mimetype":
return getContentType();
case "name":
return getName();
case "path":
return uri.getPath();
case "scheme":
return uri.getScheme();
case "uri":
return uri.toASCIIString();
default:
throw new IllegalArgumentException("Unknown part: " + part);
}
}
}
}
@@ -40,6 +40,7 @@
import java.net.URL;
import java.nio.charset.Charset;
import java.util.Properties;
import java.util.UUID;

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.apache.freemarker.generator.base.FreeMarkerConstants.DEFAULT_GROUP;
@@ -120,7 +121,7 @@ public static DataSource fromString(String content, String contentType) {

public static DataSource fromString(String name, String group, String content, String contentType) {
final StringDataSource dataSource = new StringDataSource(name, content, contentType, UTF_8);
final URI uri = UriUtils.toURI(Location.STRING, Integer.toString(content.hashCode()));
final URI uri = UriUtils.toURI(Location.STRING, UUID.randomUUID().toString());
return create(name, group, uri, dataSource, contentType, UTF_8);
}

@@ -185,11 +186,22 @@ public static DataSource fromEnvironment(String name, String group, String key,

// == General ===========================================================

public static DataSource create(String str) {
if (UriUtils.isUri(str)) {
return fromNamedUri(str);
/**
* Create a data source based on a
* <ul>
* <li>URI</li>
* <li>Named URI</li>
* <li>file name</li>
* </ul>
*
* @param source source of the data source
* @return DataSource
*/
public static DataSource create(String source) {
if (UriUtils.isUri(source)) {
return fromNamedUri(source);
} else {
final File file = new File(str);
final File file = new File(source);
return fromFile(file.getName(), DEFAULT_GROUP, file, UTF_8);
}
}
@@ -16,7 +16,6 @@
*/
package org.apache.freemarker.generator.base.datasource;

import org.apache.commons.io.FilenameUtils;
import org.apache.freemarker.generator.base.util.ClosableUtils;
import org.apache.freemarker.generator.base.util.StringUtils;
import org.apache.freemarker.generator.base.util.Validate;
@@ -34,6 +33,7 @@
*/
public class DataSources implements Closeable {

/** The underlying list of data sources */
private final List<DataSource> dataSources;

public DataSources(Collection<DataSource> dataSources) {
@@ -75,10 +75,6 @@ public boolean isEmpty() {
return dataSources.isEmpty();
}

public DataSource getFirst() {
return dataSources.get(0);
}

public List<DataSource> getList() {
return new ArrayList<>(dataSources);
}
@@ -109,26 +105,29 @@ public DataSource get(String name) {
}

/**
* Find data sources based on their name and globbing pattern.
* Find data sources based on their name and a wildcard.
*
* @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(d -> FilenameUtils.wildcardMatch(d.getName(), wildcard))
.filter(dataSource -> dataSource.match("name", wildcard))
.collect(toList());
}

/**
* Find data sources based on their group and and globbing pattern.
* Find data sources based on their metadata part and wildcard.
*
* @param part part of metadata 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 List<DataSource> findByGroup(String wildcard) {
public List<DataSource> find(String part, String wildcard) {
return dataSources.stream()
.filter(d -> FilenameUtils.wildcardMatch(d.getGroup(), wildcard))
.filter(dataSource -> dataSource.match(part, wildcard))
.collect(toList());
}

@@ -83,7 +83,7 @@ private List<File> resolve(String source) {
if (file.isFile()) {
return resolveFile(file);
} else if (file.isDirectory()) {
return new ArrayList<>(resolveDirectory(file));
return resolveDirectory(file);
} else {
throw new IllegalArgumentException("Unable to find source: " + source);
}
@@ -30,10 +30,6 @@ public static String emptyToNull(String value) {
return value != null && value.trim().isEmpty() ? null : value;
}

public static String nullToEmpty(String value) {
return value == null ? "" : value;
}

public static String firstNonEmpty(final String... values) {
if (values != null) {
for (final String value : values) {

0 comments on commit f6f41bf

Please sign in to comment.