Package de.innovationgate.wgpublisher

Source Code of de.innovationgate.wgpublisher.WGPDeployer

/*******************************************************************************
* Copyright 2009, 2010 Innovation Gate GmbH. All Rights Reserved.
*
* This file is part of the OpenWGA server platform.
*
* OpenWGA is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* In addition, a special exception is granted by the copyright holders
* of OpenWGA called "OpenWGA plugin exception". You should have received
* a copy of this exception along with OpenWGA in file COPYING.
* If not, see <http://www.openwga.com/gpl-plugin-exception>.
*
* OpenWGA is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with OpenWGA in file COPYING.
* If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
package de.innovationgate.wgpublisher;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.LineNumberReader;
import java.io.StringReader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;

import org.apache.commons.transaction.locking.GenericLock;
import org.apache.commons.transaction.locking.GenericLockManager;
import org.apache.commons.transaction.locking.LockManager;
import org.apache.commons.transaction.locking.MultiLevelLock;
import org.apache.commons.transaction.util.Log4jLogger;
import org.apache.log4j.Logger;

import de.innovationgate.utils.ReplaceProcessor;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGDatabaseEventListener;
import de.innovationgate.webgate.api.WGDocument;
import de.innovationgate.webgate.api.WGTMLModule;
import de.innovationgate.wga.common.Constants;
import de.innovationgate.wga.common.beans.csconfig.v1.MediaKey;
import de.innovationgate.wga.config.DesignReference;
import de.innovationgate.wgpublisher.design.WGADesignManager;
import de.innovationgate.wgpublisher.design.db.DBDesignSource;

public class WGPDeployer implements WGACoreEventListener {

    public class TMLTagsPreProcessor implements ReplaceProcessor {

        private int lineNumber = 0;

        /*
         * (Kein Javadoc)
         *
         * @see
         * de.innovationgate.utils.ReplaceProcessor#replace(java.lang.String,
         * int, int, java.io.Writer)
         */
        public int replace(String text, int from, int to, Writer out) throws IOException {

            // Find end position of tagname
            int tagnameEndPos;
            int nextSpacePos = text.indexOf(" ", from);
            int closeTagPos = text.indexOf(">", from);
            int closeEndTagPos = text.indexOf("/>", from);

            tagnameEndPos = Integer.MAX_VALUE;

            if (nextSpacePos != -1 && nextSpacePos < tagnameEndPos) {
                tagnameEndPos = nextSpacePos;
            }

            if (closeTagPos != -1 && closeTagPos < tagnameEndPos) {
                tagnameEndPos = closeTagPos;
            }
            if (closeEndTagPos != -1 && closeEndTagPos < tagnameEndPos) {
                tagnameEndPos = closeEndTagPos;
            }

            // if no end found (maybe syntax error) just put anything out
            if (tagnameEndPos == Integer.MAX_VALUE) {
                out.write("<tml:");
                return to;
            }

            // Look if we have the shortened tml:include syntax
            String tagname = text.substring(from, tagnameEndPos);
            String localName = tagname.substring(5);
            String refName = null;
            String designdbName = null;
            if (localName.startsWith("[") && localName.endsWith("]")) {
                refName = localName.substring(1, localName.length() - 1);
                int slashPos = refName.indexOf("/");
                if (slashPos != -1) {
                    designdbName = refName.substring(0, slashPos);
                    refName = refName.substring(slashPos + 1);
                }
                tagname = "<tml:include";
            }

            // Write tagname and additional attributes
            out.write(tagname);
            out.write(" sourceline=\"");
            out.write(String.valueOf(lineNumber));
            out.write("\"");
            if (refName != null) {
                out.write(" ref=\"");
                out.write(refName);
                out.write("\"");
            }

            if (designdbName != null) {
                out.write(" designdb=\"");
                out.write(designdbName);
                out.write("\"");
            }

            return tagnameEndPos;

        }

        /**
         * @return
         */
        public int getLineNumber() {
            return lineNumber;
        }

        /**
         * @param i
         */
        public void setLineNumber(int i) {
            lineNumber = i;
        }

    }

    public class TMLCloseTagsPreProcessor implements ReplaceProcessor {

        public int replace(String text, int from, int to, Writer out) throws IOException {

            // Find end position of tagname
            int tagnameEndPos = text.indexOf(">", from);

            // if no end found (maybe syntax error) just put the source string
            // out
            if (tagnameEndPos == -1) {
                out.write("</tml:");
                return to;
            }

            // Look if we have the shortened tml:include syntax
            String tagname = text.substring(from, tagnameEndPos);
            String localName = tagname.substring(6);
            String refName = null;
            if (localName.startsWith("[") && localName.endsWith("]")) {
                tagname = "</tml:include";
            }

            // Write tagname and additional attributes
            out.write(tagname);
            return tagnameEndPos;
        }

    }

    class DeployJob {

        private WGDatabase _db;

        private boolean _initialBuild;

        private boolean _done = false;

        public DeployJob(WGDatabase db, boolean initialBuild) {
            _db = db;
            _initialBuild = initialBuild;
        }

        /**
         * @return
         */
        public WGDatabase getDb() {
            return _db;
        }

        /**
         * @return
         */
        public boolean isInitialBuild() {
            return _initialBuild;
        }

        /**
         * @return
         */
        public boolean isDone() {
            return _done;
        }

        /**
         * @param b
         */
        public void setDone(boolean b) {
            _done = b;
        }

    }

    class PPTagsPreProcessor implements ReplaceProcessor {

        private WGDatabase _db;

        private WGACore _core;

        private WGTMLModule _mod;

        private boolean _enabled = true;

        public PPTagsPreProcessor(WGACore core, WGTMLModule mod) {
            _core = core;
            _db = mod.getDatabase();
            _mod = mod;
        }

        /**
         * @see de.innovationgate.utils.ReplaceProcessor#replace(String, int,
         *      int, Writer)
         */
        public int replace(String text, int from, int to, Writer out) throws IOException {

            // First get all data
            int endPos = text.indexOf("%}", to);
            if (endPos == -1) {
                out.write(text);
                return text.length();
            }

            // If disabled, simply put code out
            if (_enabled == false) {
                out.write(text.substring(from, to));
                return to;
            }

            String call = text.substring(from + 2, endPos);
            int nameDelimiterPos = call.indexOf(":");
            String name = null;
            List<Object> params = new ArrayList<Object>();
            if (nameDelimiterPos != -1) {
                name = call.substring(0, nameDelimiterPos).trim().toLowerCase();
                params.addAll(WGUtils.deserializeCollection(call.substring(nameDelimiterPos + 1), ";"));
            }
            else {
                name = call;
            }

            // Preprocessor commands
            if (name.equals("disablePP")) {
                _enabled = false;
            }
            else if (name.equals("label")) {
                out.write("<tml:label key=\"" + params.get(0) + "\"/>");
            }

            return endPos + 2;

        }

    }

    public static final String FOLDER_DYNAMIC_RESOURCES = "dynamic";

    private WGACore _core;
   
    private LockManager _lockManager = new GenericLockManager(1, new Log4jLogger(Logger.getLogger("wga.deployer.locking")));

    protected static final Logger LOG = Logger.getLogger("wga.deployer");

    private Map<String, DeployedLayout> _layoutMappings = new ConcurrentHashMap<String, DeployedLayout>();

    private Map<String, DeployedLayout> _layoutsByFileName = new ConcurrentHashMap<String, DeployedLayout>();

    private File _resourcesFolder;

    public WGPDeployer(WGACore core) {
        _core = core;
    }

    public void shutdown() {

        if (_resourcesFolder.exists()) {
            LOG.info("Deleting deployed TML modules");
            WGUtils.delTree(_resourcesFolder);
            _resourcesFolder = null;
        }

        _core.removeEventListener(this);
    }

    private synchronized DeployedLayout deployTML(WGTMLModule tmlLib) throws DeployerException {

        if (tmlLib == null) {
            throw new DeployerException("Tried to deploy tml module \"null\". Maybe a tml module is not accessible");
        }
       
        DesignReference ref;
        try {
            ref = WGADesignManager.createDesignReference(tmlLib);
        }
        catch (WGAPIException e1) {
            throw new DeployerException("Error retrieving design reference for "  + tmlLib.getDocumentKey(), e1);
        }
        String databaseKey = (String) tmlLib.getDatabase().getDbReference();
        String layoutKey = ref.toString();
        String mediaKey = null;
        String resourceName = null;

       
        try {
            if (tmlLib.isVariant()) {
                layoutKey = layoutKey + "//" + databaseKey;
            }
       
            mediaKey = tmlLib.getMediaKey().toLowerCase();
            if (_core.isMediaKeyDefined(mediaKey) == false) {
                _core.addMediaMapping(new MediaKey(mediaKey, "text/html", false, false), false);
            }

            // Build complete code
            StringBuffer tmlCode = new StringBuffer();
            tmlCode.append("<%@ taglib uri=\"http://www.innovationgate.de/wgpublisher/webtml/2.2\" prefix=\"tml\" %>");
            tmlCode.append("<%@ page ");

            // F000037B2
            if (_core.getCharacterEncoding() != null) {
                tmlCode.append(" pageEncoding=\"" + _core.getCharacterEncoding() + "\" ");
            }
            tmlCode.append(" buffer=\"" + _core.tmlBuffer + "kb\" autoFlush=\"true\" isThreadSafe=\"true\" session=\"true\" errorPage=\"../error.jsp\" %>");
            tmlCode.append("<%@ page import=\"de.innovationgate.wgpublisher.jsputils.*\"%>");
            tmlCode.append(_core.tmlHeader);
           
            tmlCode.append("<tml:root ref=\"" + layoutKey + "\" resource=\"" + tmlLib.getName() + " (" + tmlLib.getMediaKey() + ")\" modulename=\"" + tmlLib.getName() + "\" modulemediakey=\""
                    + tmlLib.getMediaKey() + "\">");
            tmlCode.append(preprocessCode(tmlLib));
            tmlCode.append("</tml:root>");


            DeployedLayout layout = _layoutMappings.get(layoutKey);
            if (layout != null) {
                // use existing layout obj
                layout.init(tmlLib, layoutKey, _resourcesFolder, _core.getCharacterEncoding());
            }
            else {
                // create new
                layout = new DeployedLayout(tmlLib, layoutKey, _resourcesFolder, _core.getCharacterEncoding());
            }

            // deploy
            resourceName = tmlLib.getName().toLowerCase();
            LOG.info("Deploying tml " + mediaKey + "/" + resourceName + " (" + ref.getDesignProviderReference().toString() + ")");
            layout.deploy(tmlCode.toString());

            // Map deployed layout
            _layoutMappings.put(layoutKey, layout);
            _layoutsByFileName.put(layout.getFile().getName(), layout);
            _lastDeployments.put(tmlLib.getDatabase().getDbReference(), new Date());

            return layout;

        }
        catch (Exception e) {
            throw new DeployerException("Error deploying tml " + databaseKey + "/" + resourceName + " (" + mediaKey + ")", e);
        }
    }

    public String filenameToTMLModuleName(String filename) {
        DeployedLayout layout = _layoutsByFileName.get(filename);
        if (layout != null) {
            return layout.getMainLibKey();
        }
        else {
            return null;
        }
    }

    public String locateTmlResource(WGTMLModule tmlLib) throws WGAPIException, DeployerException {

        DesignReference ref = WGADesignManager.createDesignReference(tmlLib);
               
        DeployedLayout layout = getDeployedLayout(tmlLib, ref);
        if (layout == null) {
            MultiLevelLock lock = _lockManager.atomicGetOrCreateLock(ref.toString());
            try {
                try {
                    lock.acquire(Thread.currentThread(), 1,  true, true, Long.MAX_VALUE);
                }
                catch (InterruptedException e) {
                }
               
                layout = getDeployedLayout(tmlLib, ref);
                if (layout == null) {
                    layout = deployTML(tmlLib);
                }
            }
            finally {
                lock.release(Thread.currentThread());
            }
        }

        String resourcePath = "/" + FOLDER_DYNAMIC_RESOURCES + "/" + layout.getFile().getName();
        return resourcePath;

    }

    private DeployedLayout getDeployedLayout(WGTMLModule mod, DesignReference ref) throws WGAPIException {
       
        String layoutKey = ref.toString();
       
        // On design variants we must append the database key to the layout key, since different database may use different data
        if (mod.isVariant()) {
            layoutKey = layoutKey + "//" + mod.getDatabase().getDbReference();
        }
       
        DeployedLayout layout = this._layoutMappings.get(layoutKey);
        if (layout == null) {
            return null;
        }

        if (layout.needsUpdate(mod)) {
            return null;
        }
        else {
            return layout;
        }
    }

    /**
     * @see WGDatabaseEventListener#isTemporary()
     */
    public boolean isTemporary() {
        return false;
    }

    public Map<String, DeployedLayout> getLayoutMappings() {
        return this._layoutMappings;
    }

    public void removeLayouts(WGDatabase db) {

        String key = (String) db.getAttribute(WGACore.DBATTRIB_DBKEY);
        Set<String> layoutsSet = this._layoutMappings.keySet();
        synchronized (this._layoutMappings) {
            Iterator<String> layouts = layoutsSet.iterator();
            while (layouts.hasNext()) {
                String layoutKey = layouts.next();
                if (layoutKey.startsWith(key + "/")) {
                    DeployedLayout layout = _layoutMappings.get(layoutKey);
                    if (layout != null) {
                        _layoutsByFileName.remove(layout.getFile().getName());
                    }
                    layouts.remove();
                }
            }
        }

    }

    public String preprocessCode(WGTMLModule mod) throws WGAPIException {

        String result = mod.getCode();

        // First pass. Process preprocessor tags
        try {
            PPTagsPreProcessor preProcessor = new PPTagsPreProcessor(_core, mod);
            result = WGUtils.strReplace(result, "{%", preProcessor, true);
        }
        catch (RuntimeException e) {
            LOG.error("Error preprocessing WebTML module " + mod.getDocumentKey(), e);
        }

        // Second pass. Process WebTML tags
        int codeOffset = mod.getCodeOffset();
        LineNumberReader reader = new LineNumberReader(new StringReader(result));
        StringBuffer out = new StringBuffer();
        TMLTagsPreProcessor linePreProcessor = new TMLTagsPreProcessor();
        String line;
        boolean firstLine = true;
        try {
            while ((line = reader.readLine()) != null) {
                if (!firstLine) {
                    out.append("\n");
                }
                else {
                    firstLine = false;
                }
                linePreProcessor.setLineNumber(codeOffset + reader.getLineNumber());
                out.append(WGUtils.strReplace(line, "<tml:", linePreProcessor, true));
            }
            result = out.toString();
        }
        catch (IOException e) {
            LOG.error("Error adding line numbers to WebTML code", e);
        }

        // Third pass. Process WebTML close tags
        result = WGUtils.strReplace(result, "</tml:", new TMLCloseTagsPreProcessor(), true);

        return result;
    }

    public void startup() {

        // Create folder for dynamic resource
        _resourcesFolder = new File(_core.getServletContext().getRealPath("/"), FOLDER_DYNAMIC_RESOURCES);
        if (_resourcesFolder.exists()) {
            _core.getLog().info("Deleting deployed tmls from previous instance");
            WGUtils.delTree(_resourcesFolder);
        }
        _resourcesFolder.mkdir();

        // Register for core events
        _core.addEventListener(this);

    }

    private Map<String,Date> _lastDeployments = new HashMap<String,Date>();

    public Date getLastChangedOrDeployed(WGDatabase db) {

        String designDBKey = _core.getDesignDatabaseKey(db);

        Date lastDeployed = _lastDeployments.get(designDBKey);
        Date lastChanged = db.getLastChanged();
        if (lastDeployed == null || lastChanged.after(lastDeployed)) {
            return lastChanged;
        }
        else {
            return lastDeployed;
        }

    }

    /**
     *
     * @param domainConfig
     * @return
     * @throws IOException
     */
    public String deployErrorPage(String code) throws IOException {

        File errJsp = File.createTempFile("err", ".jsp", _resourcesFolder);
        FileWriter out = new FileWriter(errJsp);
        out.write(code);
        out.flush();
        out.close();

        return "/" + _resourcesFolder.getName() + "/" + errJsp.getName();

    }

    public void contentStoreConnected(WGACoreEvent event) {
    }

    public void contentStoreDisconnected(WGACoreEvent event) {

        WGDatabase db = event.getDatabase();
        String dbkey = (String) db.getAttribute(WGACore.DBATTRIB_DBKEY);
        _lastDeployments.remove(dbkey);

    }

    public void shutdownPostDisconnect(WGACoreEvent event) {
    }

    public void shutdownPreDisconnect(WGACoreEvent event) {
    }

    public void startupPostConnect(WGACoreEvent event) {
    }

    public void startupPreConnect(WGACoreEvent event) {
    }
   


}
TOP

Related Classes of de.innovationgate.wgpublisher.WGPDeployer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.