Skip to content

Commit d2cb0f2

Browse files
authored
simplify java api (#155)
1 parent 6be6142 commit d2cb0f2

17 files changed

+178
-395
lines changed

java-src/io/github/erdos/stencil/API.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.github.erdos.stencil;
22

33
import io.github.erdos.stencil.functions.Function;
4-
import io.github.erdos.stencil.impl.NativeEvaluator;
4+
import io.github.erdos.stencil.functions.FunctionEvaluator;
55
import io.github.erdos.stencil.impl.NativeTemplateFactory;
66

77
import java.io.File;
@@ -57,10 +57,10 @@ public static EvaluatedDocument render(PreparedTemplate template, Map<String, Pr
5757
}
5858

5959
public static EvaluatedDocument render(PreparedTemplate template, Map<String, PreparedFragment> fragments, TemplateData data, Collection<Function> customFunctions) {
60-
final NativeEvaluator evaluator = new NativeEvaluator();
60+
FunctionEvaluator function = new FunctionEvaluator();
6161
if (customFunctions != null) {
62-
evaluator.getFunctionEvaluator().registerFunctions(customFunctions.toArray(new Function[0]));
62+
function.registerFunctions(customFunctions.toArray(new Function[0]));
6363
}
64-
return evaluator.render(template, fragments, data);
64+
return template.render(fragments, function, data);
6565
}
6666
}

java-src/io/github/erdos/stencil/EvaluatedDocument.java

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,14 @@
44

55
import java.io.*;
66
import java.util.concurrent.ExecutorService;
7-
import java.util.function.Consumer;
87

98
/**
109
* An evaluated document ready to be converted to the final output format.
1110
*/
1211
@SuppressWarnings("unused")
1312
public interface EvaluatedDocument {
1413

15-
TemplateDocumentFormats getFormat();
16-
17-
Consumer<OutputStream> getWriter();
14+
void write(OutputStream target);
1815

1916
/**
2017
* Writes output of this document to a file
@@ -24,14 +21,10 @@ default void writeToFile(File output) throws IOException {
2421
throw new IllegalArgumentException("Output file already exists: " + output);
2522
}
2623
try (FileOutputStream fos = new FileOutputStream(output)) {
27-
writeToStream(fos);
24+
write(fos);
2825
}
2926
}
3027

31-
default void writeToStream(OutputStream outputStream) {
32-
getWriter().accept(outputStream);
33-
}
34-
3528
/**
3629
* Creates a blocking input stream that can be used to render generated document.
3730
*
@@ -59,7 +52,7 @@ default InputStream toInputStream(ExecutorService executorService) {
5952
throw new IllegalStateException("The supplied executor must submit jobs to new threads!");
6053
} else {
6154
try {
62-
writeToStream(outputStream);
55+
write(outputStream);
6356
} catch (Throwable e) {
6457
inputStreamErrors.fail(e);
6558
throw e;
Lines changed: 3 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,13 @@
11
package io.github.erdos.stencil;
22

3-
import io.github.erdos.stencil.impl.FileHelper;
4-
5-
import java.io.File;
6-
import java.util.concurrent.atomic.AtomicBoolean;
7-
8-
public final class PreparedFragment implements AutoCloseable {
9-
10-
private final Object content;
11-
private final File zipDirResource;
12-
private final AtomicBoolean alive = new AtomicBoolean(true);
13-
14-
public PreparedFragment(Object content, File zipDirResource) {
15-
this.content = content;
16-
this.zipDirResource = zipDirResource;
17-
}
18-
19-
public Object getImpl() {
20-
if (!alive.get()) {
21-
throw new IllegalStateException("Can not render destroyed fragment!");
22-
} else {
23-
return content;
24-
}
25-
}
3+
public interface PreparedFragment extends AutoCloseable {
264

275
/**
28-
* Makes the template clean up any resources allocated for it.
6+
* Makes the template clean up resources allocated for it.
297
* <p>
308
* Subsequent invocations of this method have no effects. Rendering the template after this method call will throw
319
* an IllegalStateException.
3210
*/
33-
public void cleanup() {
34-
if (alive.compareAndSet(true, false)) {
35-
FileHelper.forceDelete(zipDirResource);
36-
}
37-
}
38-
3911
@Override
40-
public void close() {
41-
cleanup();
42-
}
12+
void close();
4313
}
Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package io.github.erdos.stencil;
22

3+
import io.github.erdos.stencil.functions.FunctionEvaluator;
4+
35
import java.io.File;
46
import java.time.LocalDateTime;
7+
import java.util.Map;
58

69
/**
710
* Represents an already preprocessed template file.
811
* <p>
912
* These files may be serialized or cached for later use.
1013
*/
1114
@SuppressWarnings("unused")
12-
public interface PreparedTemplate extends AutoCloseable{
15+
public interface PreparedTemplate extends AutoCloseable {
1316

1417
/**
1518
* Original template file that was preprocessed.
@@ -32,16 +35,7 @@ default TemplateDocumentFormats getTemplateFormat() {
3235
*
3336
* @return template preprocess call time
3437
*/
35-
LocalDateTime creationDateTime();
36-
37-
/**
38-
* Contains the preprocess result.
39-
* <p>
40-
* Implementation detail. May be used for serializing these objects. May be used for debugging too.
41-
*
42-
* @return inner representation of prepared template
43-
*/
44-
Object getSecretObject();
38+
LocalDateTime creationDateTime(); // TODO: remove?
4539

4640

4741
/**
@@ -50,20 +44,15 @@ default TemplateDocumentFormats getTemplateFormat() {
5044
TemplateVariables getVariables();
5145

5246
/**
53-
* Makes the template clean up any resources allocated for it. Subsequential invocations of this method have no
54-
* effects. Rendering the template after this method call will throw an IllegalStateException.
47+
* Makes the template clean up any resources allocated for it.
48+
* Subsequent invocations of this method have no effects.
49+
* Rendering the template after this method call will throw an IllegalStateException.
5550
*/
56-
void cleanup();
51+
@Override
52+
void close();
5753

5854
/**
5955
* Renders the current prepared template file with the given template data.
6056
*/
61-
default EvaluatedDocument render(TemplateData templateData) {
62-
return API.render(this, templateData);
63-
}
64-
65-
@Override
66-
default void close() {
67-
cleanup();
68-
}
57+
EvaluatedDocument render(Map<String, PreparedFragment> fragments, FunctionEvaluator function, TemplateData templateData);
6958
}

java-src/io/github/erdos/stencil/TemplateVariables.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ private TemplateVariables(Set<String> variables, Set<String> fragmentNames) {
3535
root = r;
3636
}
3737

38-
private Node reduce(Node originalNode, String path) {
38+
private static Node reduce(Node originalNode, String path) {
3939
if (path.isEmpty())
4040
return LEAF;
4141
else if (originalNode == null)
@@ -151,7 +151,7 @@ private List<SchemaError> validate(Object data, Node schema) {
151151
return validateImpl("", data, schema).collect(toList());
152152
}
153153

154-
private Stream<SchemaError> validateImpl(String path, Object data, Node schema) {
154+
private static Stream<SchemaError> validateImpl(String path, Object data, Node schema) {
155155
return schema.accept(new NodeVisitor<Stream<SchemaError>>() {
156156
@Override
157157
public Stream<SchemaError> visitArray(Node wrapped) {

java-src/io/github/erdos/stencil/impl/CachingTemplateFactory.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ public PreparedTemplate prepareTemplateFile(File templateFile, PrepareOptions op
3737
PreparedTemplate stored = cache.get(templateFile);
3838
if (stored.creationDateTime().toEpochSecond(ZoneOffset.UTC) <= templateFile.lastModified()) {
3939
// TODO: this is so not thread safe.
40-
stored.cleanup();
40+
stored.close();
4141
stored = templateFactory.prepareTemplateFile(templateFile, options);
4242
cache.put(templateFile, stored);
4343
}

java-src/io/github/erdos/stencil/impl/ClojureHelper.java

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
package io.github.erdos.stencil.impl;
22

33
import clojure.lang.IFn;
4-
import clojure.lang.Keyword;
54
import clojure.lang.RT;
65
import clojure.lang.Symbol;
76

8-
import java.util.Map;
9-
107
/**
118
* Clojure utilities.
129
*/
@@ -15,20 +12,6 @@ public final class ClojureHelper {
1512

1613
private ClojureHelper() {}
1714

18-
enum Keywords {
19-
DATA, FUNCTION, FRAGMENTS, TEMPLATE, VARIABLES, SOURCE_FOLDER, WRITER;
20-
21-
public final Keyword kw = Keyword.intern(name().toLowerCase().replace('_', '-'));
22-
23-
public final <V> V getOrThrow(Map<?, V> m) {
24-
if (!m.containsKey(kw)) {
25-
throw new IllegalArgumentException("Map does not contain keyword " + kw);
26-
} else {
27-
return m.get(kw);
28-
}
29-
}
30-
}
31-
3215
// requires stencil.process namespace so stencil is loaded.
3316
static {
3417
final IFn req = RT.var("clojure.core", "require");

java-src/io/github/erdos/stencil/impl/DeleteOnCloseFileInputStream.java

Lines changed: 0 additions & 26 deletions
This file was deleted.

java-src/io/github/erdos/stencil/impl/FileHelper.java

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -101,22 +101,6 @@ public static void forceDelete(final File file) {
101101
file.delete();
102102
}
103103

104-
/**
105-
* Recursively marks a directory or a file for deletion on exit.
106-
*
107-
* @param file to delete, not null
108-
* @throws NullPointerException on null or invalid file
109-
*/
110-
@SuppressWarnings({"ConstantConditions"})
111-
public static void forceDeleteOnExit(final File file) {
112-
file.deleteOnExit();
113-
if (file.isDirectory()) {
114-
for (File child : file.listFiles()) {
115-
forceDeleteOnExit(child);
116-
}
117-
}
118-
}
119-
120104
/**
121105
* Returns a string representation of path with unix separators ("/") instead of the
122106
* system-dependent separators (which is backslash on Windows).
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
package io.github.erdos.stencil.impl;
2+
3+
import java.util.*;
4+
import java.util.concurrent.Callable;
5+
import java.util.concurrent.atomic.AtomicBoolean;
6+
import java.util.concurrent.locks.ReadWriteLock;
7+
import java.util.concurrent.locks.ReentrantReadWriteLock;
8+
9+
public final class LifecycleLock implements AutoCloseable {
10+
11+
private final ReadWriteLock lock;
12+
private final AtomicBoolean alive;
13+
private final Runnable cleanup;
14+
15+
public LifecycleLock(Runnable cleanup) {
16+
this.lock = new ReentrantReadWriteLock();
17+
this.alive = new AtomicBoolean(true);
18+
this.cleanup = Objects.requireNonNull(cleanup);
19+
}
20+
21+
public static <T> T execute(List<LifecycleLock> locks, Callable<T> supplier) throws Exception {
22+
if (locks.isEmpty()) {
23+
return supplier.call();
24+
} else {
25+
ListIterator<LifecycleLock> iterator = locks.listIterator();
26+
try {
27+
while (iterator.hasNext()) {
28+
iterator.next().acquireReadLockAndCheck();
29+
}
30+
return supplier.call();
31+
} finally {
32+
while (iterator.hasPrevious()) {
33+
iterator.previous().lock.readLock().unlock();
34+
}
35+
}
36+
}
37+
}
38+
39+
private void acquireReadLockAndCheck() {
40+
lock.readLock().lock();
41+
if (!alive.get()) { // we DO NOT release read lock, because it will be released in finally block!
42+
throw new IllegalStateException("Component has already been closed.");
43+
}
44+
}
45+
46+
@Override
47+
public void close() throws Exception {
48+
if (alive.get()) {
49+
lock.writeLock().lock();
50+
try {
51+
if (alive.getAndSet(false)) {
52+
cleanup.run();
53+
}
54+
} finally {
55+
lock.writeLock().unlock();
56+
}
57+
}
58+
}
59+
}

0 commit comments

Comments
 (0)