Package de.innovationgate.wgpublisher.design.db

Source Code of de.innovationgate.wgpublisher.design.db.DBDesignProvider

/*******************************************************************************
* 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.design.db;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import de.innovationgate.utils.WGUtils;
import de.innovationgate.webgate.api.WGAPIException;
import de.innovationgate.webgate.api.WGAuthorisationException;
import de.innovationgate.webgate.api.WGConfigurableTypeDesignProvider;
import de.innovationgate.webgate.api.WGCreationException;
import de.innovationgate.webgate.api.WGDatabase;
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.WGDesignDocument;
import de.innovationgate.webgate.api.WGDocument;
import de.innovationgate.webgate.api.WGDocumentCore;
import de.innovationgate.webgate.api.WGDocumentKey;
import de.innovationgate.webgate.api.WGException;
import de.innovationgate.webgate.api.WGFactory;
import de.innovationgate.webgate.api.WGInvalidDatabaseException;
import de.innovationgate.webgate.api.WGSessionContext;
import de.innovationgate.webgate.api.WGUnavailableException;
import de.innovationgate.webgate.api.WGUpdateLog;
import de.innovationgate.webgate.api.utils.MasterSessionTask;
import de.innovationgate.wga.common.WGAXML;
import de.innovationgate.wga.common.beans.DesignConfiguration;
import de.innovationgate.wga.config.DesignReference;
import de.innovationgate.wgpublisher.WGACore;
import de.innovationgate.wgpublisher.WGACoreEvent;
import de.innovationgate.wgpublisher.WGACoreEventListener;
import de.innovationgate.wgpublisher.design.DesignProviderCoreWrapper;
import de.innovationgate.wgpublisher.design.WGADesignProvider;

public class DBDesignProvider extends WGConfigurableTypeDesignProvider implements WGADesignProvider, WGDatabaseEventListener, WGDesignChangeListener, WGACoreEventListener {

    public static final String OPTION_CROSSLOGINMODE = "crossloginmode";
    protected WGDatabase _designDB = null;
    private String _designDBKey;
    private WGDatabase _slaveDB;
    private WGACore _core;
    private boolean _cacheFailedLookups = true;
    private Set _failedLookups = new HashSet();
    private Set _designChangeListeners = new HashSet();
    private Comparable _designDBLastChanged;
    private String _crossLoginMode;
    private boolean _notifying = false;
   

    private boolean _lookupVariants;
    private DesignReference _designReference;
    private String _variantSuffix;


    public DBDesignProvider(DesignReference ref, WGACore core, WGDatabase slaveDB, String dbkey, Map<String,String> options) {
       
        _designReference = ref;
       
        List<Integer> providerTypesList = null;
        String optionProviderTypes = (String) slaveDB.getCreationOptions().get(WGDatabase.COPTION_DESIGNPROVIDERTYPES);
        if (optionProviderTypes != null) {
            providerTypesList = new ArrayList<Integer>();
            Iterator<String> providerTypes = WGUtils.deserializeCollection(optionProviderTypes, ",", true).iterator();
            while (providerTypes.hasNext()) {
                String providerTypeName = (String) providerTypes.next();
                int providerType = WGDocument.doctypeNameToNumber(providerTypeName);
                if (providerType != 0) {
                    providerTypesList.add(new Integer(providerType));
                }
            }
        }
        initProviderTypes(providerTypesList);
       
        _core = core;
        _slaveDB = slaveDB;
        _designDBKey = dbkey;
        _crossLoginMode = WGUtils.getValueOrDefault(options.get(OPTION_CROSSLOGINMODE), WGAXML.DESIGNSHARING_MODE_ANONYMOUS);
        _lookupVariants = WGUtils.getBooleanMapValue(options, OPTION_DESIGNVARIANTS, false);
        _variantSuffix = "." + slaveDB.getDbReference();
        _core.addEventListener(this);
       
        // Try to register with design db immediately
        try {
            if (!registerDesignDB()) {
                core.getLog().warn("Unable to register design consumer '" + slaveDB.getDbReference() + "' with design provider '" + _designDBKey + "' immediately. Disabling design caching because of unknown design provider type.");
            }
        }
        catch (WGException e) {
            core.getLog().error("Exception registering design consumer '" + slaveDB.getDbReference() + "' with design provider '" + _designDBKey + "'", e);
        }
    }
   
    public List<WGDocumentCore> getDesignObjects(int type) {
        try {
            WGDatabase db = getDesignDB();
            if (db.getDesignProvider() != null) {
                return wrapCores(db.getDesignProvider().getDesignObjects(type));
            }
            else {
                return wrapCores(db.getCore().getDesignObjects(type));
            }
        }
        catch (WGException e) {
            WGFactory.getLogger().error("Error retrieving design from design database '" + _designDBKey + "'", e);
            return null;
        }
    }

    private List<WGDocumentCore> wrapCores(List designObjects) throws WGAPIException {
       
        if (designObjects == null) {
            return null;
        }
       
        Iterator designsIt = designObjects.iterator();
        Set<String> addedNames = new HashSet<String>();
        WGDocumentCore core;
        List<WGDocumentCore> newList = new ArrayList<WGDocumentCore>();
        while (designsIt.hasNext()) {
            core = wrapVariantCore((WGDocumentCore) designsIt.next());
           
            // Filter out base versions of variants
            if (_lookupVariants) {
                String coreName = (String) core.getMetaData(WGDesignDocument.META_NAME);
               
                // If we try to add a doc that already has been added and is NO variant, we know that this is the base version which was
                // overwritten by a variant. So we skip it.
                if (addedNames.contains(coreName) && !Boolean.TRUE.equals(core.getMetaData(WGDesignDocument.META_VARIANT))) {
                    continue;
                }
                else {
                    addedNames.add(coreName);
                }
            }
           
           
            newList.add(core);
        }
       
        return newList;
    }

    public WGDocumentCore getDesignObject(int type, String name, String mediaKey) {
        try {
            WGDatabase db = getDesignDB();
           
            if (_lookupVariants) {
                WGDocumentCore core = fetchDesignObject(db, type, name + "." + _slaveDB.getDbReference(), mediaKey);
                if (core != null) {
                    return wrapVariantCore(core);
                }
            }
           
            return fetchDesignObject(db, type, name, mediaKey);
        }
        catch (WGException e) {
            WGFactory.getLogger().error("Error retrieving design from design database '" + _designDBKey + "'", e);
            return null;
        }
    }

    private WGDocumentCore fetchDesignObject(WGDatabase db, int type, String name, String mediaKey) throws WGAPIException {
       
        String failedKey = new WGDocumentKey(type, name, mediaKey).toString();
        if (_cacheFailedLookups && _failedLookups.contains(failedKey)) {
            return null;
        }
       
        WGDocumentCore core = null;
        if (db.getDesignProvider() != null && db.getDesignProvider().providesType(type)) {
            core = db.getDesignProvider().getDesignObject(type, name, mediaKey);
        }
        else {
            core = db.getCore().getDesignObject(type, name, mediaKey);
        }
       
        if (core == null) {
            if (_cacheFailedLookups) {
                _failedLookups.add(failedKey);
            }
        }
        else {
            core = new DesignProviderCoreWrapper(core, this, false, false);
        }
       
        return core;
    }



    public String getName() {
        return "DB design provider, providing design of database '" + _designDBKey + "'";
    }

    public WGDocumentCore createDesignDocument(int type, String name, String mediaKey) throws WGCreationException {
        throw new WGCreationException("This database uses the design of database '" + _designDBKey + "'");
    }
   
    private boolean registerDesignDB() throws WGUnavailableException, WGAuthorisationException, WGInvalidDatabaseException {
       
           WGDatabase currentDesignDB = (WGDatabase) _core.getContentdbs().get(_designDBKey);
           if (currentDesignDB != null && currentDesignDB != _designDB) {
               _designDB = currentDesignDB;
              
               // Since lazy connections on a design provider DB won't work well, we issue a warning here
               // We also open a session to connect the database and init its potential design provider
               if (!_designDB.isConnected() && _designDB.getDesignProvider() != null) {
                   _core.getLog().warn("You configured design provider db '" + _designDB.getDbReference() + "', which itself has a design provider, as lazily connected.");
                   _core.getLog().warn("This is not supported since this may lead to delays in design serving, resulting in design documents not being immediately ready for the design consumer db.");
               }
               
               // Register as listener for the database itself or its own design provider
               if (_designDB.getDesignProvider() != null) {
                   _notifying = _designDB.getDesignProvider().isNotifying();
                   if (_designDB.getDesignProvider().isNotifying()) {
                       _designDB.getDesignProvider().addDesignChangeListener(this);
                   }
                   else {
                       _cacheFailedLookups = false;
                   }
               }
               else {
                   _designDBLastChanged = _designDB.getRevision();
                   _designDB.addDatabaseEventListener(this);
                   _notifying = true;
               }
              
               // Clear the cache of the slave db
               if (_slaveDB != null && _slaveDB.isConnected()) {
                   MasterSessionTask task = new MasterSessionTask(_slaveDB) {
                       protected void exec(WGDatabase db) throws Throwable {
                           fireUpdateChangeEvent(new WGDesignChangeEvent(DBDesignProvider.this, db, new ArrayList()));
                           db.refresh();
                       }
                   };
                   task.run();
               }
               return true;
    
           }
           else {
               return false;
           }
       
    }

    /**
     * @return Returns the designDBKey.
     */
    public String getDesignDBKey() {
        return _designDBKey;
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.WGDatabaseEventListener#databaseUpdate(de.innovationgate.webgate.api.WGDatabaseEvent)
     */
    public synchronized void databaseUpdate(WGDatabaseEvent event) {
       
        try {
      _failedLookups.clear();
          WGDatabase db = event.getDatabase();
          Comparable currentLastChanged = db.getRevision();
          if (currentLastChanged.compareTo(_designDBLastChanged) > 0) {
              List updateLogs = db.getUpdatedDocumentsSince(_designDBLastChanged);
              updateLogs = filterLogs(updateLogs);
              if (updateLogs.size() == 0) {
                  return;
              }
              WGDesignChangeEvent designEvent = new WGDesignChangeEvent(this, _slaveDB, updateLogs);
              fireUpdateChangeEvent(designEvent);
              _designDBLastChanged = currentLastChanged;
          }
        }
        catch (WGAPIException e) {
            _core.getLog().error("Unable to process databaseUpdate event.", e);
        }
       
    }

    private List filterLogs(List updateLogs) {
      
        List newLogs = new ArrayList();
        Iterator logs = updateLogs.iterator();
        while (logs.hasNext()) {
            WGUpdateLog log = (WGUpdateLog) logs.next();
            if (log.getDocumentKey().startsWith("$")) {
                continue;
            }
           
            WGDocumentKey docKey = new WGDocumentKey(log.getDocumentKey());
            if (docKey.getTypename().equals(WGDocument.TYPENAME_TML) ||
                docKey.getTypename().equals(WGDocument.TYPENAME_CSSJS) ||
                docKey.getTypename().equals(WGDocument.TYPENAME_FILECONTAINER)) {
               
                // If lookup variants have changed (and feature is active) we need to change the log to use the base name
                // So the correct caches are cleared
                if (_lookupVariants == true && _slaveDB != null) {
                    String suffix = "." + _slaveDB.getDbReference();
                    if (docKey.getName().endsWith(suffix)) {
                        String newName = DesignProviderCoreWrapper.cutoffVariantSuffix(docKey.getName(), suffix);
                        WGDocumentKey newKey = new WGDocumentKey(docKey.getTypename(), newName, docKey.getMediakey());
                        log = new WGUpdateLog(log.getType(), log.getDate(), log.getUser(), newKey.toString());
                    }
                }
               
                newLogs.add(log);
            }
        }
        return newLogs;
       
    }

    private synchronized void fireUpdateChangeEvent(WGDesignChangeEvent designEvent) {
        Iterator listeners = _designChangeListeners.iterator();
        while (listeners.hasNext()) {
            WGDesignChangeListener listener = (WGDesignChangeListener) listeners.next();
            listener.designChanged(designEvent);
        }
    }

    private void crossLogin(WGDatabase sourceDB, WGDatabase targetDB) throws WGAPIException {
       
        if (targetDB.isSessionOpen()) {
            return;
        }
       
        String user = WGDatabase.ANONYMOUS_USER;
        String pwd = null;
        if (_crossLoginMode.equals(WGAXML.DESIGNSHARING_MODE_PARALLEL)) {
            if (!sourceDB.isSessionOpen()) {
                throw new WGAuthorisationException("Unable to do cross login in parallel mode while both databases have no session open");
            }
            if (sourceDB.getSessionContext().isMasterSession()) {
                user = null;
                pwd = null;
            }
            else {
                user = sourceDB.getSessionContext().getUser();
                pwd = sourceDB.getSessionContext().getPassword();
            }
        }
              
        int accLevel = targetDB.openSession(user, pwd);
        
        if (accLevel <= WGDatabase.ACCESSLEVEL_NOACCESS) {
            if (_crossLoginMode.equals(WGAXML.DESIGNSHARING_MODE_PARALLEL)) {
                throw new WGAuthorisationException("Design sharing databases do not support neccessary logins. Database '" + targetDB.getDbReference() + "' denies access for username '" + user + "' which is accepted by database '" + sourceDB.getDbReference() + "' (or has a different password).");
            }
            else {
                throw new WGAuthorisationException("Design sharing databases do not support neccessary logins. Database '" + targetDB.getDbReference() + "' does not accept anonymous access.");
            }
        }
       
       
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.WGDatabaseEventListener#isTemporary()
     */
    public boolean isTemporary() {
        return false;
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.WGDesignProvider#addDesignChangeListener(de.innovationgate.webgate.api.WGDesignChangeListener)
     */
    public void addDesignChangeListener(WGDesignChangeListener changeListener) {
        _designChangeListeners.add(changeListener);
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.WGDesignProvider#removeDesignChangeListener(de.innovationgate.webgate.api.WGDesignChangeListener)
     */
    public void removeDesignChangeListener(WGDesignChangeListener changeListener) {
         _designChangeListeners.remove(changeListener);
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.WGDesignChangeListener#designChanged(de.innovationgate.webgate.api.WGDesignChangeEvent)
     */
    public void designChanged(WGDesignChangeEvent event) {

        _failedLookups.clear();
        WGDesignChangeEvent designEvent = new WGDesignChangeEvent(this, _slaveDB, filterLogs(event.getUpdateLogs()));
        fireUpdateChangeEvent(designEvent);
       
    }

    /* (non-Javadoc)
     * @see de.innovationgate.webgate.api.WGDesignProvider#dispose()
     */
    public void dispose() {
        _designChangeListeners.clear();
        _core.removeEventListener(this);
        _core = null;
        _slaveDB = null;       
    }

    public void contentStoreConnected(WGACoreEvent event) {
        try {
            registerDesignDB();
        }
        catch (WGException e) {
        }
    }

    public void contentStoreDisconnected(WGACoreEvent event) {
    }

    private WGDatabase getDesignDB() throws WGAPIException {
       
            if (_designDB == null) {
                throw new WGInvalidDatabaseException("The configured design database '" + _designDBKey + "' is not connected");
            }
       
            if (!_designDB.isSessionOpen()) {
                crossLogin(_slaveDB, _designDB);
            }
                      
            return _designDB;
       
    }

    public boolean isLookupVariants() {
        return _lookupVariants;
    }

    public WGDatabase getSlaveDB() {
        return _slaveDB;
    }

    public void shutdownPostDisconnect(WGACoreEvent event) {
    }

    public void shutdownPreDisconnect(WGACoreEvent event) {
    }

    public void startupPostConnect(WGACoreEvent event) {
    }

    public void startupPreConnect(WGACoreEvent event) {
    }
   
    public boolean isProviderCore(WGDocumentCore core) {
        return (core instanceof DesignProviderCoreWrapper);
    }

    public boolean isNotifying() {
        return _notifying;
    }

    public WGDatabase getConsumerDatabase() {
        return getSlaveDB();
    }

    public void closeSession() {
    }

    public void openSession(WGSessionContext context) {
    }

    public int designHashCode() {
        return _designDB.hashCode();
    }

    public WGDocumentCore wrapVariantCore(WGDocumentCore core) throws WGAPIException {
       
        if (_lookupVariants) {
            String name = (String) core.getMetaData(WGDesignDocument.META_NAME);
            if (name.endsWith(_variantSuffix)) {
                return new DesignProviderCoreWrapper(core, this, true, false);
            }
            else {
                return new DesignProviderCoreWrapper(core, this, false, false);
            }
        }
        else {
            return new DesignProviderCoreWrapper(core, this, false, false);
        }
       
    }
}

TOP

Related Classes of de.innovationgate.wgpublisher.design.db.DBDesignProvider

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.