Last active
January 17, 2017 20:13
-
-
Save danielbodart/5db4e6a162f6934e8bcf58d30aae23b0 to your computer and use it in GitHub Desktop.
Using Lagarto and csselly to do server composition (Support Server side as well as command line - for build time)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| package fun; | |
| import com.googlecode.totallylazy.Streams; | |
| import com.googlecode.totallylazy.io.Uri; | |
| import com.googlecode.utterlyidle.HttpHandler; | |
| import com.googlecode.utterlyidle.Request; | |
| import com.googlecode.utterlyidle.Response; | |
| import com.googlecode.utterlyidle.handlers.ClientHttpHandler; | |
| import com.googlecode.utterlyidle.html.RelativeUrlHandler; | |
| import jodd.lagarto.dom.*; | |
| import java.io.File; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import java.util.Map; | |
| import static com.googlecode.totallylazy.Strings.isEmpty; | |
| import static com.googlecode.totallylazy.collections.PersistentList.constructors.list; | |
| import static com.googlecode.totallylazy.io.Uri.uri; | |
| import static com.googlecode.utterlyidle.Request.get; | |
| public class HtmlHandler implements HttpHandler { | |
| private final HttpHandler handler; | |
| public HtmlHandler(HttpHandler handler) { | |
| this.handler = new RelativeUrlHandler(handler); | |
| } | |
| @Override | |
| public Response handle(Request request) throws Exception { | |
| Response response = handler.handle(request); | |
| if (!request.uri().path().endsWith(".html")) return response; | |
| if (request.uri().path().startsWith("/static/")) return response; | |
| Document parent = doc(response); | |
| process(parent); | |
| return response.entity(parent.getHtml()); | |
| } | |
| public static void main(String[] args) throws Exception { | |
| if (args.length != 1) { | |
| System.out.println("Please provide 1 argument 'path/to/src.html'"); | |
| System.exit(-1); | |
| } | |
| HttpHandler handler = new HtmlHandler(new ClientHttpHandler()); | |
| Response response = handler.handle(get(uri(new File(args[0])))); | |
| Streams.copyAndClose(response.entity().inputStream(), System.out); | |
| } | |
| public void process(Node parent) throws Exception { | |
| processIncludes(parent); | |
| processDecorators(parent); | |
| processStyle(parent); | |
| } | |
| private void processStyle(Node parent) throws Exception { | |
| for (Node tag : select(parent, "style[src]")) { | |
| Uri uri = uri(tag.getAttribute("src")); | |
| Response response = handler.handle(get(uri)); | |
| tag.removeAttribute("src"); | |
| tag.addChild(new Text(tag.getOwnerDocument(), response.entity().toString())); | |
| } | |
| } | |
| private void processIncludes(Node parent) throws Exception { | |
| processTag(parent, "include", (link, target) -> { | |
| // NO-OP | |
| }); | |
| } | |
| private void processDecorators(Node parent) throws Exception { | |
| processTag(parent, "decorator", (decorator, target) -> { | |
| String contentSelector = decorator.getAttribute("content"); | |
| if (isEmpty(contentSelector)) { | |
| replaceChildren(decorator, target); | |
| } else { | |
| select(target, contentSelector).forEach(content -> { | |
| replaceChildren(decorator, content); | |
| }); | |
| } | |
| }); | |
| } | |
| private void replaceChildren(Node decorator, Node content) { | |
| content.removeAllChilds(); | |
| content.addChild(decorator.getChildNodes()); | |
| } | |
| interface TagProcessor { | |
| void process(Node tag, Node target); | |
| } | |
| private void processTag(Node parent, String tagSelector, TagProcessor processor) throws Exception { | |
| for (Node tag : select(parent, tagSelector)) { | |
| Uri uri = uri(tag.getAttribute("src")); | |
| String selector = tag.getAttribute("selector"); | |
| Document childDoc = doc(uri); | |
| List<Node> childNodes = select(childDoc, selector); | |
| for (Node childNode : childNodes) { | |
| process(childNode); | |
| processor.process(tag, childNode); | |
| } | |
| replace(tag, childNodes); | |
| } | |
| } | |
| private void replace(Node old, List<Node> newNodes) { | |
| // Fix for siblingIndex not being correctly set by Lagarto | |
| Node parentNode = old.getParentNode(); | |
| int index = list(parentNode.getChildNodes()).indexOf(old); | |
| parentNode.insertChild(newNodes.toArray(new Node[newNodes.size()]), index + 1); | |
| parentNode.removeChild(index); | |
| } | |
| private List<Node> select(Node parent, String query) { | |
| if (isEmpty(query)) return list(parent); | |
| return new NodeSelector(parent).select(query); | |
| } | |
| private Map<Uri, Document> cache = new HashMap<>(); | |
| private Document doc(Uri uri) throws Exception { | |
| return cache.computeIfAbsent(uri, u -> { | |
| try { | |
| return doc(handler.handle(get(uri))); | |
| } catch (Exception e) { | |
| throw new RuntimeException(e); | |
| } | |
| }).clone(); | |
| } | |
| private Document doc(Response response) { | |
| LagartoDOMBuilder builder = new LagartoDOMBuilder(). | |
| enableHtmlMode(); | |
| builder.setConfig(builder.getConfig(). | |
| setCaseSensitive(true). | |
| setParseXmlTags(true)); | |
| return builder. | |
| parse(response.entity().toString()); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment