Skip to content

Commit

Permalink
simplify java api
Browse files Browse the repository at this point in the history
  • Loading branch information
erdos committed Nov 15, 2023
1 parent 80bd0d6 commit 7a4fb1a
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 102 deletions.
13 changes: 5 additions & 8 deletions java-src/io/github/erdos/stencil/PreparedTemplate.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,20 +50,17 @@ default TemplateDocumentFormats getTemplateFormat() {
TemplateVariables getVariables();

/**
* Makes the template clean up any resources allocated for it. Subsequential invocations of this method have no
* effects. Rendering the template after this method call will throw an IllegalStateException.
* Makes the template clean up any resources allocated for it.
* Subsequent invocations of this method have no effects.
* Rendering the template after this method call will throw an IllegalStateException.
*/
void cleanup();
@Override
void close();

/**
* Renders the current prepared template file with the given template data.
*/
default EvaluatedDocument render(TemplateData templateData) {
return API.render(this, templateData);
}

@Override
default void close() {
cleanup();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public PreparedTemplate prepareTemplateFile(File templateFile, PrepareOptions op
PreparedTemplate stored = cache.get(templateFile);
if (stored.creationDateTime().toEpochSecond(ZoneOffset.UTC) <= templateFile.lastModified()) {
// TODO: this is so not thread safe.
stored.cleanup();
stored.close();
stored = templateFactory.prepareTemplateFile(templateFile, options);
cache.put(templateFile, stored);
}
Expand Down
84 changes: 6 additions & 78 deletions java-src/io/github/erdos/stencil/impl/NativeTemplateFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,8 @@
import io.github.erdos.stencil.exceptions.ParsingException;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;

import static io.github.erdos.stencil.TemplateDocumentFormats.ofExtension;
import static io.github.erdos.stencil.impl.FileHelper.forceDeleteOnExit;
Expand All @@ -33,8 +29,12 @@ public PreparedTemplate prepareTemplateFile(final File inputTemplateFile, Prepar
throw new IllegalArgumentException("Template preparation options are missing!");
}

try (InputStream input = new FileInputStream(inputTemplateFile)) {
return prepareTemplateImpl(templateDocFormat.get(), input, inputTemplateFile, options);
try {
return (PreparedTemplate) ClojureHelper.findFunction("prepare-template").invoke(inputTemplateFile, options);
} catch (ParsingException e) {
throw e;
} catch (Exception e) {
throw ParsingException.wrapping("Could not parse template file!", e);
}
}

Expand Down Expand Up @@ -85,76 +85,4 @@ private static Set<String> fragmentNames(Map prepared) {
? unmodifiableSet(new HashSet<>((Collection<String>) prepared.get(ClojureHelper.Keywords.FRAGMENTS.kw)))
: emptySet();
}

@SuppressWarnings("unchecked")
private static PreparedTemplate prepareTemplateImpl(TemplateDocumentFormats templateDocFormat, InputStream input, File originalFile, PrepareOptions options) {
final IFn prepareFunction = ClojureHelper.findFunction("prepare-template");

final String format = templateDocFormat.name();
final Map<Keyword, Object> prepared;

try {
prepared = (Map<Keyword, Object>) prepareFunction.invoke(input, options);
} catch (ParsingException e) {
throw e;
} catch (Exception e) {
throw ParsingException.wrapping("Could not parse template file!", e);
}

final TemplateVariables vars = TemplateVariables.fromPaths(variableNames(prepared), fragmentNames(prepared));

final File zipDirResource = (File) prepared.get(ClojureHelper.Keywords.SOURCE_FOLDER.kw);
if (zipDirResource != null) {
forceDeleteOnExit(zipDirResource);
}

return new PreparedTemplate() {
final LocalDateTime now = LocalDateTime.now();
final AtomicBoolean valid = new AtomicBoolean(true);

@Override
public File getTemplateFile() {
return originalFile;
}

@Override
public TemplateDocumentFormats getTemplateFormat() {
return templateDocFormat;
}

@Override
public LocalDateTime creationDateTime() {
return now;
}

@Override
public Object getSecretObject() {
if (!valid.get()) {
throw new IllegalStateException("Can not render destroyed template!");
} else {
return prepared;
}
}

@Override
public TemplateVariables getVariables() {
return vars;
}

@Override
public void cleanup() {
if (valid.compareAndSet(true, false)) {
// deletes unused temporary zip directory
if (zipDirResource != null) {
FileHelper.forceDelete(zipDirResource);
}
}
}

@Override
public String toString() {
return "<Template from file " + originalFile + ">";
}
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public TemplateVariables getVariables() {
}

@Override
public void cleanup() {
public void close() {
// NOP

}
Expand Down
4 changes: 2 additions & 2 deletions src/stencil/api.clj
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,8 @@


(defn cleanup! [template]
(cond (instance? PreparedTemplate template) (.cleanup ^PreparedTemplate template)
(instance? PreparedFragment template) (.cleanup ^PreparedFragment template)
(cond (instance? PreparedTemplate template) (.close ^PreparedTemplate template)
(instance? PreparedFragment template) (.close ^PreparedFragment template)
:else (throw (ex-info "Unexpected object to clean up!" {:template template})))
template)

Expand Down
35 changes: 23 additions & 12 deletions src/stencil/process.clj
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
(ns stencil.process
"These functions are called from Java."
(:import [java.io InputStream]
(:import [java.io File InputStream]
[java.util.zip ZipEntry ZipOutputStream]
[io.github.erdos.stencil PrepareOptions]
[io.github.erdos.stencil PrepareOptions PreparedTemplate TemplateVariables]
[io.github.erdos.stencil.impl FileHelper ZipHelper])
(:require [clojure.java.io :as io]
[stencil.log :as log]
Expand All @@ -28,18 +28,29 @@
v (:variables (:executable x))] v)))))

;; Called from Java API
(defn prepare-template [^InputStream stream, ^PrepareOptions options]
(assert (instance? InputStream stream))
(defn prepare-template [^File template-file, ^PrepareOptions options]
(let [zip-dir (FileHelper/createNonexistentTempFile
(.getTemporaryDirectoryOverride options)
"stencil-" ".zip.contents")
options {:only-includes (.isOnlyIncludes options)}]
(with-open [zip-stream stream]
(ZipHelper/unzipStreamIntoDirectory zip-stream zip-dir))
(-> zip-dir
(model/load-template-model options)
merge-fragment-names
merge-variable-names)))
options {:only-includes (.isOnlyIncludes options)}
_ (with-open [zip-stream (io/input-stream template-file)]
(ZipHelper/unzipStreamIntoDirectory zip-stream zip-dir))
model (-> (model/load-template-model zip-dir options)
(merge-fragment-names)
(merge-variable-names)
(atom))
datetime (java.time.LocalDateTime/now)
variables (TemplateVariables/fromPaths (:variables @model) (:fragments @model))]
;; (FileHelper/forceDeleteOnExit zip-dir)
(reify PreparedTemplate
(getTemplateFile [_] template-file)
(creationDateTime [_] datetime)

Check warning on line 47 in src/stencil/process.clj

View check run for this annotation

Codecov / codecov/patch

src/stencil/process.clj#L47

Added line #L47 was not covered by tests
(getSecretObject [_]
(or @model (throw (IllegalStateException. "Template has already been cleared."))))
(close [_]
(reset! model nil)
(FileHelper/forceDelete zip-dir))
(getVariables [_] variables))))

;; Called from Java API
(defn prepare-fragment [input, ^PrepareOptions options]
Expand Down Expand Up @@ -70,4 +81,4 @@
(assert (:source-folder template))
(let [data (into {} data)
writers-map (model/template-model->writers-map template data function fragments)]
{:writer (partial render-writers-map writers-map)}))
{:writer (partial render-writers-map writers-map)}))

0 comments on commit 7a4fb1a

Please sign in to comment.