001/*
002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the GNU Lesser General Public License
006 * (LGPL) version 2.1 which accompanies this distribution, and is available at
007 * http://www.gnu.org/licenses/lgpl.html
008 *
009 * This library is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * Contributors:
015 *     Razvan Caraghin
016 *     Olivier Grisel
017 *     Thierry Delprat
018 *     Florent Guillaume
019 */
020
021package org.nuxeo.ecm.webapp.delegate;
022
023import static org.jboss.seam.ScopeType.CONVERSATION;
024
025import java.io.Serializable;
026import java.util.HashMap;
027import java.util.Map;
028import java.util.Map.Entry;
029
030import javax.annotation.security.PermitAll;
031import javax.security.auth.login.LoginContext;
032import javax.security.auth.login.LoginException;
033
034import org.apache.commons.logging.Log;
035import org.apache.commons.logging.LogFactory;
036import org.jboss.seam.Component;
037import org.jboss.seam.annotations.Destroy;
038import org.jboss.seam.annotations.Name;
039import org.jboss.seam.annotations.Scope;
040import org.jboss.seam.annotations.Unwrap;
041import org.jboss.seam.contexts.Lifecycle;
042import org.nuxeo.ecm.core.api.CoreInstance;
043import org.nuxeo.ecm.core.api.CoreSession;
044import org.nuxeo.ecm.core.api.repository.Repository;
045import org.nuxeo.ecm.platform.util.RepositoryLocation;
046import org.nuxeo.runtime.api.Framework;
047
048/**
049 * Acquires a {@link CoreSession} connection.
050 *
051 * @author Razvan Caraghin
052 * @author Olivier Grisel
053 * @author Thierry Delprat
054 * @author Florent Guillaume
055 */
056@Name("documentManager")
057@Scope(CONVERSATION)
058public class DocumentManagerBusinessDelegate implements Serializable {
059
060    private static final long serialVersionUID = 1L;
061
062    private static final Log log = LogFactory.getLog(DocumentManagerBusinessDelegate.class);
063
064    /**
065     * Map holding the open session for each repository location.
066     */
067    protected final Map<RepositoryLocation, CoreSession> sessions = new HashMap<RepositoryLocation, CoreSession>();
068
069    public void initialize() {
070        log.debug("Seam component initialized...");
071    }
072
073    @Unwrap
074    public CoreSession getDocumentManager() {
075        /*
076         * Explicit lookup, as this method is the only user of the Seam component. Also, in some cases (Seam remoting),
077         * it seems that the injection is not done correctly.
078         */
079        RepositoryLocation currentServerLocation = (RepositoryLocation) Component.getInstance("currentServerLocation");
080        return getDocumentManager(currentServerLocation);
081    }
082
083    public CoreSession getDocumentManager(RepositoryLocation serverLocation) {
084
085        if (serverLocation == null) {
086            /*
087             * currentServerLocation (factory in ServerContextBean) is set through navigationContext, which itself
088             * injects documentManager, so it will be null the first time.
089             */
090            return null;
091        }
092
093        CoreSession session = sessions.get(serverLocation);
094        if (session == null) {
095            if (Lifecycle.isDestroying()) {
096                /*
097                 * During Seam component destroy phases, we don't want to recreate a core session just for injection.
098                 * This happens during logout when the session context is destroyed; we don't want to cause EJB calls in
099                 * this case as the authentication wouldn't work.
100                 */
101                return null;
102            }
103            String serverName = serverLocation.getName();
104            session = CoreInstance.openCoreSession(serverName);
105            log.debug("Opened session for repository " + serverName);
106            sessions.put(serverLocation, session);
107        }
108        return session;
109    }
110
111    @Destroy
112    @PermitAll
113    public void remove() {
114        LoginContext lc = null;
115        try {
116            try {
117                if (Framework.getRuntime() != null) {
118                    lc = Framework.login();
119                }
120            } catch (LoginException le) {
121                log.error("Unable to login as System", le);
122                log.warn("...try to feed CoreSession(s) without system login ...");
123            }
124            for (Entry<RepositoryLocation, CoreSession> entry : sessions.entrySet()) {
125                String serverName = entry.getKey().getName();
126                CoreSession session = entry.getValue();
127                session.close();
128                log.debug("Closed session for repository " + serverName);
129            }
130        } finally {
131            if (lc != null) {
132                try {
133                    lc.logout();
134                } catch (LoginException lo) {
135                    log.error("Error when logout", lo);
136                }
137            }
138            sessions.clear();
139        }
140    }
141}