All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.astamuse.asta4d.template.TemplateUtil Maven / Gradle / Ivy

Go to download

core functionalities of asta4d framework, including template and snippt implemention

There is a newer version: 1.2-M2
Show newest version
/*
 * Copyright 2012 astamuse company,Ltd.
 * 
 * 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.
 * 
 */

package com.astamuse.asta4d.template;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.jsoup.helper.StringUtil;
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.nodes.Node;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.astamuse.asta4d.Configuration;
import com.astamuse.asta4d.extnode.ExtNode;
import com.astamuse.asta4d.extnode.ExtNodeConstants;
import com.astamuse.asta4d.extnode.GroupNode;
import com.astamuse.asta4d.util.IdGenerator;
import com.astamuse.asta4d.util.SelectorUtil;

public class TemplateUtil {

    private static class SnippetNode extends ExtNode {

        /**
         * 
         * @param renderer
         *            a plain text renderer declaration
         */
        public SnippetNode(String renderer) {
            super(ExtNodeConstants.SNIPPET_NODE_TAG);
            this.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS, ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS_READY);
            this.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_RENDER, renderer);
        }

    }

    private final static Logger logger = LoggerFactory.getLogger(TemplateUtil.class);

    public final static void regulateElement(String path, Document doc) throws TemplateException, TemplateNotFoundException {
        // disabled. see {@link #loadStaticEmebed}
        // load static embed at first
        // loadStaticEmebed(doc);

        regulateSnippets(path, doc);
        regulateMsgs(path, doc);
        regulateEmbed(doc);
    }

    private final static String createSnippetRef() {
        return "sn-" + IdGenerator.createId();
    }

    private final static void regulateMsgs(String path, Document doc) {
        List msgElems = doc.select(ExtNodeConstants.MSG_NODE_TAG_SELECTOR);
        for (Element element : msgElems) {
            // record template path
            if (!element.hasAttr(ExtNodeConstants.ATTR_TEMPLATE_PATH)) {
                element.attr(ExtNodeConstants.ATTR_TEMPLATE_PATH, path);
            }
        }
    }

    private final static void regulateSnippets(String path, Document doc) {

        // find nodes emebed with snippet attribute
        String snippetSelector = SelectorUtil.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_RENDER_WITH_NS);
        snippetSelector = SelectorUtil.not(snippetSelector, ExtNodeConstants.SNIPPET_NODE_TAG_SELECTOR);

        List embedSnippets = new ArrayList<>(doc.select(snippetSelector));
        // Element
        // Node parent;
        SnippetNode fakedSnippetNode;
        String render;
        for (Element element : embedSnippets) {

            render = element.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_RENDER_WITH_NS);
            fakedSnippetNode = new SnippetNode(render);
            fakedSnippetNode.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE, ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE_FAKE);

            // move the original node under the faked node
            element.after(fakedSnippetNode);
            element.remove();
            fakedSnippetNode.appendChild(element);
            element.removeAttr(ExtNodeConstants.SNIPPET_NODE_ATTR_RENDER_WITH_NS);

            // set parallel type
            if (element.hasAttr(ExtNodeConstants.SNIPPET_NODE_ATTR_PARALLEL_WITH_NS)) {
                fakedSnippetNode.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_PARALLEL, "");
                element.removeAttr(ExtNodeConstants.SNIPPET_NODE_ATTR_PARALLEL_WITH_NS);
            }
        }

        /*
         * set all the nodes without status attribute or with an illegal status 
         * value to ready 
         */

        // first, we regulate the snippets to legal form
        List snippetNodes = doc.select(ExtNodeConstants.SNIPPET_NODE_TAG_SELECTOR);
        String status;
        for (Element sn : snippetNodes) {
            // record template path
            if (!sn.hasAttr(ExtNodeConstants.ATTR_TEMPLATE_PATH)) {
                sn.attr(ExtNodeConstants.ATTR_TEMPLATE_PATH, path);
            }
            // regulate status
            if (sn.hasAttr(ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS)) {
                status = sn.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS);
                switch (status) {
                case ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS_READY:
                case ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS_WAITING:
                case ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS_FINISHED:
                    // do nothing;
                    break;
                default:
                    sn.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS, ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS_READY);
                }
            } else {
                sn.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS, ExtNodeConstants.SNIPPET_NODE_ATTR_STATUS_READY);
            }
            // regulate id
            if (!sn.hasAttr(ExtNodeConstants.ATTR_SNIPPET_REF)) {
                sn.attr(ExtNodeConstants.ATTR_SNIPPET_REF, createSnippetRef());
            }
            // regulate type
            if (!sn.hasAttr(ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE)) {
                sn.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE, ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE_USERDEFINE);
            }
            switch (sn.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE)) {
            case ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE_FAKE:
            case ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE_USERDEFINE:
                // do nothing;
                break;
            default:
                // we do not allow snippet node has user customized type
                // attribute
                sn.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE, ExtNodeConstants.SNIPPET_NODE_ATTR_TYPE_USERDEFINE);
            }
        }

        // then let us check the nested relation for nodes without block attr
        snippetSelector = SelectorUtil.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_BLOCK);
        snippetSelector = SelectorUtil.not(ExtNodeConstants.SNIPPET_NODE_TAG_SELECTOR, snippetSelector);
        snippetNodes = doc.select(snippetSelector);
        setBlockingParentSnippetId(snippetNodes);
    }

    private final static void regulateEmbed(Document doc) throws TemplateException, TemplateNotFoundException {
        // check nodes without block attr for blocking parent snippets
        String selector = SelectorUtil.attr(ExtNodeConstants.EMBED_NODE_ATTR_BLOCK);
        selector = SelectorUtil.not(ExtNodeConstants.EMBED_NODE_TAG_SELECTOR, selector);
        List embedElemes = doc.select(selector);
        setBlockingParentSnippetId(embedElemes);
    }

    /**
     * Disabled static embed at 2014.09.26.
     * 
     * Developers would like to use different snippets to render a same static embed file as following:
     * 
     * 
     *   <afd:snippet render="SomeSnippet">
     *      <afd:embed target="/someEmbed.html" static/>
     *   </afd:snippet>
     * 
* * Which confuses rendering logic and makes bad source smell, thus we decide to disable this feature. * * @param doc * @throws TemplateException * @throws TemplateNotFoundException */ @SuppressWarnings("unused") @Deprecated private final static void loadStaticEmebed(Document doc) throws TemplateException, TemplateNotFoundException { String selector = SelectorUtil.attr(SelectorUtil.tag(ExtNodeConstants.EMBED_NODE_TAG_SELECTOR), ExtNodeConstants.EMBED_NODE_ATTR_STATIC, null); int embedNodeListCount; do { List embedNodeList = doc.select(selector); embedNodeListCount = embedNodeList.size(); Iterator embedNodeIterator = embedNodeList.iterator(); Element embed; Element embedContent; while (embedNodeIterator.hasNext()) { embed = embedNodeIterator.next(); embedContent = getEmbedNodeContent(embed); mergeBlock(doc, embedContent); embed.before(embedContent); embed.remove(); } } while (embedNodeListCount > 0); } private final static void setBlockingParentSnippetId(List elems) { Element searchElem; String blockingParentId; for (Element elem : elems) { searchElem = elem.parent(); blockingParentId = ""; while (searchElem != null) { if (searchElem.tagName().equals(ExtNodeConstants.SNIPPET_NODE_TAG)) { blockingParentId = searchElem.attr(ExtNodeConstants.ATTR_SNIPPET_REF); break; } else { searchElem = searchElem.parent(); } } elem.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_BLOCK, blockingParentId); // TODO should we replace the blocked element to a dummy place // holder element to avoid being rendered by parent snippets } } public final static void resetSnippetRefs(Element elem) { String snippetRefSelector = SelectorUtil.attr(ExtNodeConstants.ATTR_SNIPPET_REF); List snippets = new ArrayList<>(elem.select(snippetRefSelector)); String oldRef, newRef; String blockedSnippetSelector; List blockedSnippets; for (Element element : snippets) { oldRef = element.attr(ExtNodeConstants.ATTR_SNIPPET_REF); newRef = createSnippetRef(); // find blocked snippet blockedSnippetSelector = SelectorUtil.attr(ExtNodeConstants.SNIPPET_NODE_TAG_SELECTOR, ExtNodeConstants.SNIPPET_NODE_ATTR_BLOCK, oldRef); blockedSnippets = new ArrayList<>(elem.select(blockedSnippetSelector)); // find blocked embed blockedSnippetSelector = SelectorUtil.attr(ExtNodeConstants.EMBED_NODE_TAG_SELECTOR, ExtNodeConstants.SNIPPET_NODE_ATTR_BLOCK, oldRef); blockedSnippets.addAll(elem.select(blockedSnippetSelector)); for (Element be : blockedSnippets) { be.attr(ExtNodeConstants.SNIPPET_NODE_ATTR_BLOCK, newRef); } element.attr(ExtNodeConstants.ATTR_SNIPPET_REF, newRef); } } public final static Element getEmbedNodeContent(Element elem) throws TemplateException { String target; Configuration conf = Configuration.getConfiguration(); TemplateResolver templateResolver = conf.getTemplateResolver(); target = elem.attr(ExtNodeConstants.EMBED_NODE_ATTR_TARGET); if (target == null || target.isEmpty()) { String message = "Target not defined[" + elem.toString() + "]"; throw new TemplateException(message); } Template embedTarget; try { embedTarget = templateResolver.findTemplate(target); } catch (TemplateNotFoundException e) { throw new TemplateException(e); } // TODO all of the following process should be merged into template // analyze process and be cached. Document embedDoc = embedTarget.getDocumentClone(); /* Elements children = embedDoc.body().children(); Element wrappingNode = ElementUtil.wrapElementsToSingleNode(children); */ Element wrappingNode = new GroupNode(ExtNodeConstants.GROUP_NODE_ATTR_TYPE_EMBED_WRAPPER); // retrieve all the blocks that misincluded into head Element head = embedDoc.head(); Elements headChildren = head.children(); for (Element child : headChildren) { if (StringUtil.in(child.tagName(), "script", "link", ExtNodeConstants.BLOCK_NODE_TAG)) { child.remove(); wrappingNode.appendChild(child); } } Element body = embedDoc.body(); Elements bodyChildren = body.children(); wrappingNode.insertChildren(-1, bodyChildren); // copy all the attrs to the wrapping group node Iterator attrs = elem.attributes().iterator(); Attribute attr; while (attrs.hasNext()) { attr = attrs.next(); wrappingNode.attr(attr.getKey(), attr.getValue()); } // a embed template file may by included many times in same parent // template, so we have to avoid duplicated snippet refs resetSnippetRefs(wrappingNode); return wrappingNode; } public final static void mergeBlock(Document doc, Element content) { Iterator blockIterator = content.select(ExtNodeConstants.BLOCK_NODE_TAG_SELECTOR).iterator(); Element block, targetBlock; String blockTarget, blockType; List childNodes; while (blockIterator.hasNext()) { block = blockIterator.next(); if (block.hasAttr(ExtNodeConstants.BLOCK_NODE_ATTR_OVERRIDE)) { blockType = ExtNodeConstants.BLOCK_NODE_ATTR_OVERRIDE; } else if (block.hasAttr(ExtNodeConstants.BLOCK_NODE_ATTR_APPEND)) { blockType = ExtNodeConstants.BLOCK_NODE_ATTR_APPEND; } else if (block.hasAttr(ExtNodeConstants.BLOCK_NODE_ATTR_INSERT)) { blockType = ExtNodeConstants.BLOCK_NODE_ATTR_INSERT; } else if (!block.hasAttr("id")) { // TODO I want a approach to logging out template file path here logger.warn("The block does not declare its action or id correctlly.[{}]", block.toString()); continue; } else { continue; } blockTarget = block.attr(blockType); if (blockTarget == null || blockTarget.isEmpty()) { // TODO I want a approach to logging out template file path here logger.warn("The block does not declare its target action correctlly.[{}]", block.toString()); continue; } targetBlock = doc.select(SelectorUtil.id(ExtNodeConstants.BLOCK_NODE_TAG_SELECTOR, blockTarget)).first(); if (targetBlock == null) { // TODO I want a approach to logging out template file path here logger.warn("The block declares a not existed target block.[{}]", block.toString()); continue; } childNodes = new ArrayList<>(block.childNodes()); switch (blockType) { case ExtNodeConstants.BLOCK_NODE_ATTR_OVERRIDE: targetBlock.empty(); targetBlock.insertChildren(-1, childNodes); break; case ExtNodeConstants.BLOCK_NODE_ATTR_APPEND: targetBlock.insertChildren(-1, childNodes); break; case ExtNodeConstants.BLOCK_NODE_ATTR_INSERT: targetBlock.insertChildren(0, childNodes); break; } block.remove(); } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy