Package de.innovationgate.wgpublisher

Source Code of de.innovationgate.wgpublisher.SystemContainerManager

/*******************************************************************************
* 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.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.zip.ZipInputStream;

import org.apache.log4j.Logger;

import de.innovationgate.utils.DynamicClassLoadingChain;
import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGACL;
import de.innovationgate.webgate.api.WGACLEntry;
import de.innovationgate.webgate.api.WGACLEntryFlags;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGAuthorisationException;
import de.innovationgate.webgate.api.WGBackendException;
import de.innovationgate.webgate.api.WGCSSJSModule;
import de.innovationgate.webgate.api.WGDatabase;
import de.innovationgate.webgate.api.WGDatabaseConnectListener;
import de.innovationgate.webgate.api.WGDatabaseEvent;
import de.innovationgate.webgate.api.WGDatabaseEventListener;
import de.innovationgate.webgate.api.WGDesignChangeEvent;
import de.innovationgate.webgate.api.WGDesignChangeListener;
import de.innovationgate.webgate.api.WGDocument;
import de.innovationgate.webgate.api.WGFactory;
import de.innovationgate.webgate.api.WGFileContainer;
import de.innovationgate.webgate.api.WGHierarchicalDatabase;
import de.innovationgate.webgate.api.WGScriptModule;
import de.innovationgate.webgate.api.jdbc.FileContainer;
import de.innovationgate.webgate.api.schemadef.WGSchemaDefinition;
import de.innovationgate.webgate.api.utils.MasterSessionTask;
import de.innovationgate.wga.common.beans.csconfig.v1.ACLRole;
import de.innovationgate.wga.common.beans.csconfig.v1.CSConfig;
import de.innovationgate.wga.common.beans.csconfig.v1.InvalidCSConfigVersionException;
import de.innovationgate.wga.common.beans.csconfig.v1.PluginConfig;
import de.innovationgate.wga.common.beans.csconfig.v1.PluginID;
import de.innovationgate.wga.common.beans.csconfig.v1.PublisherOption;
import de.innovationgate.wga.common.beans.csconfig.v1.Version;
import de.innovationgate.wgpublisher.WGACore.DomainConfiguration;
import de.innovationgate.wgpublisher.design.db.DBDesignProvider;
import de.innovationgate.wgpublisher.design.fs.FileSystemDesignProvider;
import de.innovationgate.wgpublisher.expressions.ExpressionEngine;
import de.innovationgate.wgpublisher.expressions.ExpressionEngineFactory;
import de.innovationgate.wgpublisher.expressions.ExpressionResult;
import de.innovationgate.wgpublisher.hdb.HDBModel;
import de.innovationgate.wgpublisher.plugins.WGAPlugin;
import de.innovationgate.wgpublisher.plugins.WGAPluginSet;
import de.innovationgate.wgpublisher.webtml.utils.TMLContext;

public class SystemContainerManager implements WGDatabaseEventListener, WGDesignChangeListener, WGDatabaseConnectListener {

   
    public static final String INITDUMP_CS = "init.wgacs";
    public static final String INITDUMP_PLUGIN = "plugin-init.wgacs";
    public static final String CSCONFIG_FILE = "csconfig.xml";
    public static final String SCHEMA_FILE = "schema.xml";
    public static final String CSCONFIG_PATH = "files/system/" + CSCONFIG_FILE;
    public static final String SCHEMA_PATH = "files/system/" + SCHEMA_FILE;
    public static final String LICENSE_PATH = "files/system/license.txt";
   
    class SystemContainerContext {
       
        private ContainerInfo _info;
        private boolean _initACL;
        private WGDatabase _db;
        private boolean _initDisabled;
        private WGAPlugin _plugin;

        public SystemContainerContext(WGDatabase db, ContainerInfo info, WGAPlugin plugin, boolean initACL) {
            _db = db;
            _info = info;
            _plugin = plugin;
            _initACL = initACL;
           
            _initDisabled = false;
            if (_db.getDbReference().startsWith(PluginConfig.PLUGIN_DBKEY_PREFIX)) {
                if (_info != null && _info.getCsConfig() != null && _info.getCsConfig().getPluginConfig() != null) {
                    PluginConfig pc = _info.getCsConfig().getPluginConfig();
                    if (pc instanceof de.innovationgate.wga.common.beans.csconfig.v3.PluginConfig) {
                        _initDisabled = ((de.innovationgate.wga.common.beans.csconfig.v3.PluginConfig) pc).isDisablePluginInit();
                    }
                }
            }
        }
       
        public void performInitialisation() {
          performInitialisation(null);
        }
       
        public void performInitialisation(Boolean dbIsEmptyContent) {
            try {
                WGFileContainer fc = _db.getFileContainer("system");
               
                // Build shortcuts so they are available in setup scripts
                _core.buildDesignShortcuts(_db);
               
                // Actions to perform on an db with empty acl (this will not be disabled with _initDisabled since even design provider plugins need general access)
                if (_info != null && _info.getCsConfig() != null && _initACL) {
                    doEmptyACLActions(_db, _info.getCsConfig());
                }
               
                // Actions to bypass if initialisation is disabled
                if (!_initDisabled) {
                   
                    // Actions to perform on a content-empty db
                    boolean isEmptyContent = _db.isContentEmpty();
                    if (dbIsEmptyContent != null) {
                        isEmptyContent = dbIsEmptyContent.booleanValue();
                    }

                    // Process init dump
                    if (fc != null && isEmptyContent) {

                        String initDump;
                        if (_db.hasAttribute(WGACore.DBATTRIB_PLUGIN_VERSION) && fc.hasFile(INITDUMP_PLUGIN)) {
                            initDump = INITDUMP_PLUGIN;
                        }
                        else {
                            initDump = INITDUMP_CS;
                        }
                       
                        if (fc.getFileNames().contains(initDump)) {
                            _log.info("Importing initial data for empty database '" + _db.getDbReference() + "'");
                            _core.importContentStoreDump(new ZipInputStream(fc.getFileData(initDump)), _db);
                        }
                    }
                   
                   
                    // We directly init HDB for this database if the system file container has a hdb model descriptor file
                    // So following scripts can use implicit model containers
                    if (fc != null && fc.hasFile(HDBModel.MODEL_FILE)) {
                        WGHierarchicalDatabase.getOrCreateInstance(_db);
                    }
                   
                    // Process schema
                    if (_info != null && _info.getSchema() != null) {
                        _db.enforceSchema(_info.getSchema());
                    }

                    // Process init script
                    if (fc != null && isEmptyContent) {

                        if (_info.getCsConfig() != null && !WGUtils.isEmpty(_info.getCsConfig().getInitScript())) {
                            try {
                                WGCSSJSModule mod = _db.getCSSJSModule(_info.getCsConfig().getInitScript(), WGScriptModule.CODETYPE_TMLSCRIPT);
                                if (mod != null) {
                                    _log.info("Running initialisation script of database '" + _db.getDbReference() + "'");
                                    TMLContext context = new TMLContext(_db.getDummyContent(null), _core, null, null);
                                    ExpressionResult result = ExpressionEngineFactory.getTMLScriptEngine().evaluateExpression(mod.getCode(), context, ExpressionEngine.TYPE_SCRIPT, null);
                                    if (result.isError()) {
                                        _log.error("Error running initialisation script '" + _info.getCsConfig().getInitScript() + "' of db '" + _db.getDbReference() + "'", result.getException());
                                    }
                                }
                                else {
                                    _log.error("Initialisiation script '" + _info.getCsConfig().getInitScript() + "' not found in database '" + _db.getDbReference() + "'");
                                }
                            }
                            catch (WGAPIException e) {
                                _log.error("Error initialising database '" + _db.getDbReference() + "'", e);
                            }
                        }
                       
                        // Re-evaluate the default language
                        _db.onConnect(_core.new ValidateDefaultLanguageAction());
                    }

                   
                    // Connection script
                    if (_info != null && _info.getCsConfig() != null) {
                        execConnectionScript(_db, _info.getCsConfig());
                    }
                   
                }
           
               
                // Add as database event listener to get updates for csconfig.xml
                if (_db.getDesignProvider() != null) {
                    _db.getDesignProvider().addDesignChangeListener(SystemContainerManager.this);
                }
                else {
                    _db.addDatabaseEventListener(SystemContainerManager.this);
                }
            }
            catch (Exception e) {
                _log.error("Error adding database for system container processing", e);
            }
        }
       
        public void performDisconnection() {
           
            try {
                if (_db.isSessionOpen()) {
                    _db.reopenSession(null, null);
                }
                else {
                    _db.openSession();
                }
               
                // Disconnection script
                if (_info != null && _info.getCsConfig() != null && _info.getCsConfig() instanceof de.innovationgate.wga.common.beans.csconfig.v3.CSConfig && !_initDisabled) {
                    de.innovationgate.wga.common.beans.csconfig.v3.CSConfig v3Config = (de.innovationgate.wga.common.beans.csconfig.v3.CSConfig) _info.getCsConfig();
                    if (!WGUtils.isEmpty(v3Config.getDisconnectionScript())) {
                        execDisconnectionScript(_db, v3Config);
                    }
                }
            }
            catch (Exception e) {
                _log.error("Error removing database from system container processing", e);
            }
           
        }
       
        public void putPublisherOptions(Map<String, String> optionsTarget) {
           
            if (_info == null || _info.getCsConfig() == null) {
                return;
    }
   
            List publisherOptions = _info.getCsConfig().getPublisherOptions();
            Iterator options = publisherOptions.iterator();
            while (options.hasNext()) {
                PublisherOption option = (PublisherOption) options.next();
                optionsTarget.put(option.getName(), option.getValue());
            }

        }
       
    }
   

    class ContainerInfo {
       
        private Date _lastModified;
        private File _deploymentDir;
        private boolean _deleteDeploymentDirOnFinalize = true;
        private File _javaClassesDir = null;
        private boolean _fromProviderDB = false;
        private boolean _enfordedLibraryUpdate = false;
        private CSConfig _csConfig = null;
        private Set _enforcedMediaMappings = new HashSet();
        private Set _enforcedElementMappings = new HashSet();
        private Set _enforcedJobDefinitions = new HashSet();
        private Set _enforcedEncoderMappings = new HashSet();
        private Map<String,Date> _deployedJARDates = new HashMap<String,Date>();
        private String _dbkey;
        private WGSchemaDefinition _schema = null;
        public ContainerInfo(WGFileContainer con, ContainerInfo oldInfo) throws WGAPIException, IOException, InvalidCSConfigVersionException {
           
            // Determine if this system file container originates from another DB
            // which means we can bypass many operations for this DB, since the provider DB already enforced them
            WGDatabase db = con.getDatabase();
            _dbkey = db.getDbReference();
            if (db.getDesignProvider() != null && db.getDesignProvider() instanceof DBDesignProvider) {
                _fromProviderDB = true;
            }
           
            // Create the deployment dir where to put JARs that are to be loaded to classpath
            if (!_fromProviderDB) {
                _deploymentDir = createDeploymentDir(con, oldInfo);
            }
           
            // Look for a Java directory in the design provider
            if (db.getDesignProvider() instanceof FileSystemDesignProvider) {
                FileSystemDesignProvider fsProvider = (FileSystemDesignProvider) db.getDesignProvider();
                if (fsProvider.getJavaClassesPath() != null) {
                    _javaClassesDir = new File(fsProvider.getJavaClassesPath());
                }
            }
           
            _lastModified = con.getLastModified();
           
            if (con.getFileNames().contains(CSCONFIG_FILE)) {
                InputStream in = con.getFileData(CSCONFIG_FILE);
                _csConfig = CSConfig.load(in, true);
            }
            if (con.getFileNames().contains(SCHEMA_FILE)) {
                InputStream in = con.getFileData(SCHEMA_FILE);
                try {
                    _schema  = WGSchemaDefinition.read(in);
                }
                catch (Exception e) {
                    _core.getLog().error("Exception reading schema definition of datababase " + _dbkey, e);
                }
                in.close();
            }

        }
        public File getDeploymentDir() {
            return _deploymentDir;
        }
        public Date getLastModified() {
            return _lastModified;
        }
        protected void finalize() {
           
            if (!isStaticClasspath() && _deploymentDir != null && _deploymentDir.exists() && _deleteDeploymentDirOnFinalize) {
                WGUtils.delTree(_deploymentDir);
                _deploymentDir = null;
            }
        }
        public List<URL> getJARURLs() {
          List<URL> jars = new ArrayList<URL>();
            if (_deploymentDir != null) {           
              File[] files = _deploymentDir.listFiles();
              if (files != null) {             
                for (int i = 0; i < files.length; i++) {
                    File file = files[i];
                    if (file.getName().endsWith(".jar")) {
                        try {
                            jars.add(file.toURL());
                        }
                        catch (MalformedURLException e) {
                            _log.error("Error creating URL for custom jar", e);
                        }
                    }
                }
              }             
              // Sort the URLs so this version can be compared to previous version
              Collections.sort(jars, URLStringComparator.INSTANCE);
            }           
            return jars;           
        }
        public CSConfig getCsConfig() {
            return _csConfig;
        }
        public Set getEnforcedElementMappings() {
            return _enforcedElementMappings;
        }
        public Set getEnforcedEncoderMappings() {
            return _enforcedEncoderMappings;
        }
        public Set getEnforcedJobDefinitions() {
            return _enforcedJobDefinitions;
        }
        public Set getEnforcedMediaMappings() {
            return _enforcedMediaMappings;
        }
        public void setCsConfig(CSConfig csConfig) {
            _csConfig = csConfig;
        }
        public void setDeploymentDir(File deploymentDir) {
            _deploymentDir = deploymentDir;
        }
        public void setLastModified(Date lastModified) {
            _lastModified = lastModified;
        }
        public boolean isFromProviderDB() {
            return _fromProviderDB;
        }
        public Collection<String> getJARDescriptions() {
           
            if (_deploymentDir == null) {
                return Collections.emptyList();
            }
           
            List<String> jars = new ArrayList<String>();
            File[] files = _deploymentDir.listFiles();
            if (files == null) {
                return Collections.emptyList();
            }
           
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
                if (file.getName().endsWith(".jar")) {
                    jars.add(_dbkey + " / " + file.getName());
                }
            }
           
            if (getJavaClassesDir() != null) {
                jars.add(_dbkey + " / java classes directory in design");
            }
           
            return jars;
           
        }
        public boolean isEnfordedLibraryUpdate() {
            return _enfordedLibraryUpdate;
        }
        public void setEnfordedLibraryUpdate(boolean enfordedLibraryUpdate) {
            _enfordedLibraryUpdate = enfordedLibraryUpdate;
        }
        public File getJavaClassesDir() {
            return _javaClassesDir;
        }
        private File createDeploymentDir(WGFileContainer con, ContainerInfo oldInfo) throws IOException, WGAPIException {
           
           
            // First collect jar files
            List<String> jars = new ArrayList<String>();
            Iterator fileNames = con.getFileNames().iterator();
            while (fileNames.hasNext()) {
                String fileName = (String) fileNames.next();
               
                // Filter out jars
                if (fileName.endsWith(".jar")) {
                    jars.add(fileName);
                }
            }
           
            // If we have no jars we dont need a deployment dir
            if (jars.size() == 0) {
                return null;
            }

            // If we have on old ContainerInfo we can determine if anything has changed since last JAR deployment

            if (oldInfo != null && jars.size() ==  oldInfo._deployedJARDates.size()) {
                boolean keepDeployment = true;
               
                // We only may recreate the deployment if the classpath is dynamic - If it is static we always keep it.
                if (!isStaticClasspath()) {
                    Iterator<Map.Entry<String,Date>> oldJARs = oldInfo._deployedJARDates.entrySet().iterator();
                    while (oldJARs.hasNext()) {
                        Map.Entry<java.lang.String, java.util.Date> entry = (Map.Entry<java.lang.String, java.util.Date>) oldJARs.next();
                        if (!jars.contains(entry.getKey())) {
                            keepDeployment = false;
                            break;
                        }
                        if (!entry.getValue().equals(con.getFileLastModified(entry.getKey()))) {
                            keepDeployment = false;
                            break;
                        }
                    }
                }
               
                // If nothing changed we can take the old deployment dir and continue to use it (this will keep us from updating the lib loader)               
                if (keepDeployment) {
                    oldInfo._deleteDeploymentDirOnFinalize = false;
                    return oldInfo._deploymentDir;
                }
               
            }
           
            // Create deployment dir for this container
            File deploymentDir = File.createTempFile("fcd", ".tmp", _deploymentBase);
            deploymentDir.delete();
            deploymentDir.mkdir();
           
            // Copy jars into it
            Iterator<String> jarsIt = jars.iterator();
            while (jarsIt.hasNext()) {
                String jarName = jarsIt.next();
               
                // Copy jar data to deployment dir
                InputStream dataIn = con.getFileData(jarName);
                OutputStream dataOut = new FileOutputStream(new File(deploymentDir, jarName));
                WGUtils.inToOut(dataIn, dataOut, 2048);
                dataIn.close();
                dataOut.close();
                _deployedJARDates.put(jarName, con.getFileLastModified(jarName));
            }
           
            return deploymentDir;
           
        }
        public String getDbkey() {
            return _dbkey;
        }
        public boolean isStaticClasspath() {
            if (_csConfig != null && _csConfig instanceof de.innovationgate.wga.common.beans.csconfig.v3.CSConfig) {
                return ((de.innovationgate.wga.common.beans.csconfig.v3.CSConfig) _csConfig).isStaticClasspath();
            }
            else {
                return false;
            }
        }
        public WGSchemaDefinition getSchema() {
            return _schema;
        }
    }
   
    private WGACore _core;
    private Map<String, ContainerInfo> _containerInfos = new ConcurrentHashMap<String, ContainerInfo>();
    private File _deploymentBase;
    private Logger _log = Logger.getLogger("wga.fcsystem");

    public SystemContainerManager(WGACore core) {
        _core = core;
       
        _deploymentBase = new File(WGFactory.getTempDir(), "scdeployment");
        _deploymentBase.mkdir();
       
    }

    public SystemContainerContext addDatabase(WGDatabase db, WGAPlugin plugin, boolean initACL) throws InvalidCSConfigVersionException {
       
        if (!db.isDesignRole()) {
            return null;
        }
       
        if (!db.isConnected()) {
            db.addDatabaseConnectListener(this);
            return null;
        }
       
        try {
               
            // retrieve and set container info
            ContainerInfo info = checkForUpdates(db);
           
            // Validate design and database version
            if (info != null && info.getCsConfig() != null && CSConfig.VERSIONCOMPLIANCE_WGA50.equals(info.getCsConfig().getVersionCompliance())) {
                if (db.getContentStoreVersion() < WGDatabase.CSVERSION_WGA5) {
                    _log.error("Database " + db.getDbReference() + " is a content store of version " + db.getContentStoreVersion() + " while it's design needs a content store of version 5. The design may not work correctly.");
                }
            }
           
           
            return new SystemContainerContext(db, info, plugin, initACL);
           
        }
        catch (InvalidCSConfigVersionException e) {
            throw e;
        }
        catch (Exception e) {
            _log.error("Error adding database for system container processing", e);
            return null;
        }
    }
   
    public SystemContainerContext addDatabase(WGDatabase db, boolean initACL) throws InvalidCSConfigVersionException {
        return addDatabase(db, null, initACL);
    }
   


    private void execConnectionScript(WGDatabase db, CSConfig csConfig) {

        String script = csConfig.getConnectionScript();
       
        if (WGUtils.isEmpty(script)) {
            return;
        }
       
        try {
            WGCSSJSModule mod = db.getCSSJSModule(script, WGScriptModule.CODETYPE_TMLSCRIPT);
            if (mod != null) {
                _log.info("Running connection script of '" + db.getDbReference() + "'");
                TMLContext context = new TMLContext(db.getDummyContent(null), _core, null, null);
                ExpressionResult result = ExpressionEngineFactory.getTMLScriptEngine().evaluateExpression(mod.getCode(), context, ExpressionEngine.TYPE_SCRIPT, null);
                if (result.isError()) {
                    _log.error("Error running connection script '" + csConfig.getConnectionScript() + "' of '" + db.getDbReference() + "'", result.getException());
                }
            }
            else {
                _log.error("Connection script '" + csConfig.getConnectionScript() + "' not found in design of '" + db.getDbReference() + "'");
            }
        }
        catch (WGAPIException e) {
            _log.error("Exception processing connection script of '" + db.getDbReference() + "'", e);
        }
       
    }
   
    private void execDisconnectionScript(WGDatabase db, de.innovationgate.wga.common.beans.csconfig.v3.CSConfig csConfig) {

        String script = csConfig.getDisconnectionScript();
        if (WGUtils.isEmpty(script)) {
            return;
        }
       
        try {
           
            WGCSSJSModule mod = db.getCSSJSModule(script, WGScriptModule.CODETYPE_TMLSCRIPT);
            if (mod != null) {
                _log.info("Running disconnection script of '" + db.getDbReference() + "'");
                TMLContext context = new TMLContext(db.getDummyContent(null), _core, null, null);
                ExpressionResult result = ExpressionEngineFactory.getTMLScriptEngine().evaluateExpression(mod.getCode(), context, ExpressionEngine.TYPE_SCRIPT, null);
                if (result.isError()) {
                    _log.error("Error running disconnection script '" + script + "' of '" + db.getDbReference() + "'", result.getException());
                }
            }
            else {
                _log.error("Disconnection script '" + script + "' not found in design of '" + db.getDbReference() + "'");
            }
        }
        catch (WGAPIException e) {
            _log.error("Exception processing disconnection script of '" + db.getDbReference() + "'", e);
        }
       
    }

    private void doEmptyACLActions(WGDatabase db, CSConfig csConfig) throws WGAuthorisationException, WGBackendException, WGAPIException {
       
        WGACL acl = db.getACL();
        if (acl == null) {
            _log.warn("Unable to retrieve ACL of database '" + db.getDbReference() + "' although database has ACL management feature");
            return;
        }
       
        if (csConfig.getAnonymousAccessLevel() != -1) {
            _log.info("Adding anonymous access level to ACL");
            acl.createUserEntry(WGDatabase.ANONYMOUS_USER, csConfig.getAnonymousAccessLevel());
        }
       
        if (csConfig.getDefaultAccessLevel() != -1) {
            _log.info("Adding default access level to ACL");
            acl.createUserEntry("*", csConfig.getDefaultAccessLevel());
        }
       
        Iterator roles = csConfig.getRoles().iterator();
        while (roles.hasNext()) {
            ACLRole role = (ACLRole) roles.next();
            _log.info("Adding role '" + role.getName() + "' to ACL");
            acl.createRoleEntry(role.getName());
            if (role.isDefaultManagerRole()) {
                assingRoleToDefaultManager(db, acl, role);
            }
        }
       
    }

    private void assingRoleToDefaultManager(WGDatabase db, WGACL acl, ACLRole role) {

        try {
            // Retrieve default manager
            DomainConfiguration domain = _core.getDomainConfigForDatabase(db);
            if (domain == null || domain.getDefaultManager() == null) {
                return;
            }
           
            // Retrieve ACL entry for default manager
            WGACLEntry aclEntry = acl.getEntry(domain.getDefaultManager());
            if (aclEntry == null) {
                acl.createUserEntry(domain.getDefaultManager(), WGDatabase.ACCESSLEVEL_MANAGER);
            }
           
            // Modify flags to include role and store
            WGACLEntryFlags flags = acl.parseFlags(aclEntry);
            if (!flags.getRoles().contains(role.getName())) {
                flags.getRoles().add(role.getName());
            }
            aclEntry.setFlags(flags.toString());
            acl.save(aclEntry);
           
        }
        catch (WGAPIException e) {
           _log.error("Error assigning role '" + role.getName() + "' to default manager for database '" + db.getDbReference() + "'", e);
        }
       
    }


   
   
    public void removeDatabase(WGDatabase db) {
        if (!db.isDesignRole()) {
            return;
        }
       
        if (db.getDesignProvider() != null) {
            db.getDesignProvider().removeDesignChangeListener(this);
        }
        else {
            db.removeDatabaseEventListener(this);
        }
       
        ContainerInfo info = _containerInfos.remove(db.getDbReference());
        if (info != null) {
            WGAPlugin plugin = null;
            PluginID pluginID = (PluginID) db.getAttribute(WGACore.DBATTRIB_PLUGIN_ID);
            if (pluginID != null) {
                plugin = _core.getPluginSet().getPluginByID(pluginID);
            }
           
            SystemContainerContext scContext = new SystemContainerContext(db, info, plugin, false);
            scContext.performDisconnection();
            _core.removeCSConfig(db, info, true);
        }
    }

    public void databaseUpdate(WGDatabaseEvent event) {
        try {
            WGDocument doc = event.getEditedDocument();
            if (doc != null) {
                if (doc instanceof WGFileContainer) {
                    WGFileContainer con = (WGFileContainer) doc;
                    if (con.getName().equals("system")) {
                        checkForUpdates(event.getDatabase());
                    }
                }
            }
            else {
                checkForUpdates(event.getDatabase());

            }
        }
        catch (Exception e) {
            _log.error("Error checking for system container update", e);
        }
    }

    protected ContainerInfo checkForUpdates(WGDatabase database) throws WGAPIException, IOException, InvalidCSConfigVersionException {

        // Load container and old container info
        WGFileContainer con = database.getFileContainer("system");
        ContainerInfo info = _containerInfos.get(database.getDbReference());
       
        // Double checked locking check for update need
        if (needsUpdate(database, con, info)) {
           
            synchronized (this) {
       
                // Update container info when container exists
                if (needsUpdate(database, con, info)) {
                   
                    // Remove old info
                    if (info !=null) {
                       _core.removeCSConfig(database, info, false);
                       _containerInfos.remove(database.getDbReference());
                    }
                   
                    if (con != null) {
                        // Create new info and store
                        info = new ContainerInfo(con, info);
                        _containerInfos.put(database.getDbReference(), info);
           
                        if (info.getCsConfig() != null) {
                            database.setAttribute(WGACore.DBATTRIB_CSCONFIG, info.getCsConfig());
                        }
                        else {
                            database.removeAttribute(WGACore.DBATTRIB_CSCONFIG);
                        }
                       
                        // Process new info for complete WGA runtime
                        _core.enforceCSConfig(database, info);
                       
                        // Process new info for specific database. We can only do this after the database has been fully connected
                        if (database.getAttribute(WGACore.DBATTRIB_FULLY_CONNECTED) != null) {
                            _core.updateFieldMappings(database, null);
                        }
                    }
                   
                }
           
            }
        }
       
       
        return info;
       
    }

    private boolean needsUpdate(WGDatabase database, WGFileContainer con, ContainerInfo info) throws WGAPIException {
       
        // Both dont exist
        if (con == null && info == null) {
            return false;
        }
        // No container but info exists: We must update to remove the info
        else if (con == null && info != null) {
            return true;
        }
        // Container exists but no info yet
        else if (con != null && info == null) {
            return true;
        }
        // Info and container exist: Compare change dates, return false if equal
        else  {
            if (info.getLastModified().equals(con.getLastModified())) {
                return false;
            }
            else {
                return true;
            }
        }
    }

    public boolean isTemporary() {
        return false;
    }

    public synchronized URL[] getJARURLs() {
       
        List<URL> urls = new ArrayList<URL>();
       
        Iterator<ContainerInfo> infos = _containerInfos.values().iterator();
        while (infos.hasNext()) {
            ContainerInfo info = infos.next();
            urls.addAll(info.getJARURLs());
           
            if (info.getJavaClassesDir() != null) {
                try {
                    URL javaClassesURL = info.getJavaClassesDir().toURL();
                    if (!urls.contains(javaClassesURL)) {
                        urls.add(javaClassesURL);
                    }
                }
                catch (MalformedURLException e) {
                    _log.error("Exception registering java classes directory " + info.getJavaClassesDir().getPath(), e);
                }
            }
        }

        // Sort the URLs so this version can be compared to previous version
        Collections.sort(urls, URLStringComparator.INSTANCE);
       
        return urls.toArray(new URL[urls.size()]);
       
    }
   
    public List<String> getJARDescriptions() {
       
        List<String> urls = new ArrayList<String>();
       
        Iterator<ContainerInfo> infos = _containerInfos.values().iterator();
        while (infos.hasNext()) {
            ContainerInfo info = infos.next();
            urls.addAll(info.getJARDescriptions());
        }
               
        return urls;
    }

    public void designChanged(WGDesignChangeEvent event) {
       
        // In case of a design changed event by a design provider we must spawn
        // the processing to a separate thread, bc. we cannot be sure that the
        // consumer db that uses the provider was opened, yet we cannot open it
        // in the same thread bc. this might be a security leak
       
        MasterSessionTask task = new MasterSessionTask(event.getDatabase()) {
            protected void exec(WGDatabase db) throws Throwable {
                try {
                    checkForUpdates(db);
                }
                catch (Exception e) {
                    _log.error("Error checking for system container update", e);
                }
            }
        };
        task.run();
               
    }

    public void databaseConnected(WGDatabaseEvent event) {
        try {
        SystemContainerContext scc = addDatabase(event.getDatabase(), false);
        if (scc != null) {
           
            // Put publisher options from design now. Remove those that are reset as first level options
            Map<String, String> publisherOptions = new HashMap<String, String>();
            scc.putPublisherOptions(publisherOptions);
            Set firstLevelPublisherOptions = (Set) event.getDatabase().getAttribute(WGACore.DBATTRIB_FIRSTLEVELPUBLISHEROPTIONS);
            if (firstLevelPublisherOptions != null) {
                Iterator flOptions = firstLevelPublisherOptions.iterator();
                while (flOptions.hasNext()) {
                    String option = (String) flOptions.next();
                    publisherOptions.remove(option);
                }
            }
           
            // Put publisher options. Convert to appropriate type if necessary
            Iterator<String> optionKeys = publisherOptions.keySet().iterator();
            while (optionKeys.hasNext()) {
                String optionName = optionKeys.next();
                String optionValue = publisherOptions.get(optionName);
                event.getDatabase().setAttribute(optionName, optionValue);
            }
           
            scc.performInitialisation();
        }
    }
        catch (InvalidCSConfigVersionException e) {
            _log.error("The design of application '" + event.getDatabase().getDbReference() + "' was developed for a higher WGA version: " + e.getTargetVersion());
        }
    }

    public void databaseConnectionError(WGDatabaseEvent event) {
    }

    public void updateLibraryLoader(DynamicClassLoadingChain libraryLoader) {
       
        Iterator<ContainerInfo> infos = _containerInfos.values().iterator();
        while (infos.hasNext()) {
            ContainerInfo info = infos.next();
           
            // Collect urls for this design
            List<URL> urlList = info.getJARURLs();
            if (info.getJavaClassesDir() != null) {
                try {
                    URL javaClassesURL = info.getJavaClassesDir().toURL();
                    if (!urlList.contains(javaClassesURL)) {
                        urlList.add(javaClassesURL);
                    }
                }
                catch (MalformedURLException e) {
                    _log.error("Exception registering java classes directory " + info.getJavaClassesDir().getPath(), e);
                }
            }
           
            if (urlList.size() == 0) {
                continue;
            }
           
            // Look if it changed, if so, update the library loader with it
            URL[] urls = urlList.toArray(new URL[urlList.size()]);
            URL[] oldUrls = libraryLoader.getSubLoaderURLs(info.getDbkey());
            if (oldUrls == null || !Arrays.equals(urls, oldUrls)) {
               
                if (oldUrls == null || !info.isStaticClasspath()) {
                    try {
                        libraryLoader.updateSubLoader(info.getDbkey(), urls, info.isStaticClasspath());
                        _core.getLog().info("Updating WGA java library loader for design of application '" + info.getDbkey() + "' containing " + urls.length + " java libraries" + (info.isStaticClasspath() ? " (static classpath)" : ""));
                    }
                    catch (IllegalStateException e) {
                        _core.getLog().warn("Java libraries for application '" + info.getDbkey() + "' have changed but WGA java library loader will not be updated because the old db design was marked static");
                    }
                }
                else {
                    _core.getLog().warn("Java libraries for application '" + info.getDbkey() + "' have changed but WGA java library loader will not be updated because the db design is marked static");
                }

            }
           
        }
       
    }
   
}
TOP

Related Classes of de.innovationgate.wgpublisher.SystemContainerManager

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.