001/*
002 * Copyright (c) 2006-2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 *
009 * Contributors:
010 *     bstefanescu
011 */
012package org.nuxeo.ecm.webengine.jaxrs.session.impl;
013
014import java.util.concurrent.locks.ReentrantLock;
015
016import javax.security.auth.login.LoginContext;
017import javax.security.auth.login.LoginException;
018import javax.servlet.http.HttpServletRequest;
019import javax.servlet.http.HttpSession;
020import javax.servlet.http.HttpSessionBindingEvent;
021import javax.servlet.http.HttpSessionBindingListener;
022
023import org.apache.commons.logging.Log;
024import org.apache.commons.logging.LogFactory;
025import org.nuxeo.ecm.core.api.CoreSession;
026import org.nuxeo.ecm.webengine.jaxrs.session.CoreSessionProvider;
027import org.nuxeo.ecm.webengine.jaxrs.session.SessionFactory;
028import org.nuxeo.ecm.webengine.jaxrs.session.SessionRef;
029import org.nuxeo.ecm.webengine.jaxrs.session.impl.PerSessionCoreProvider.Ref;
030import org.nuxeo.runtime.api.Framework;
031
032/**
033 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
034 */
035public class PerSessionCoreProvider extends CoreSessionProvider<Ref> implements HttpSessionBindingListener {
036
037    private static final Log log = LogFactory.getLog(PerSessionCoreProvider.class);
038
039    public static class Ref implements SessionRef {
040        protected CoreSession session;
041
042        protected ReentrantLock lock;
043
044        public Ref(CoreSession session) {
045            this.session = session;
046            this.lock = new ReentrantLock();
047        }
048
049        @Override
050        public CoreSession get() {
051            lock.lock();
052            return session;
053        }
054
055        @Override
056        public void unget() {
057            // unlock only if the current thread holds the lock otherwise ignore.
058            try {
059                lock.unlock();
060            } catch (IllegalMonitorStateException e) {
061                // do nothing
062            }
063        }
064
065        @Override
066        public void destroy() {
067            try {
068                session.close();
069            } finally {
070                session = null;
071                lock = null;
072            }
073        }
074
075    }
076
077    public static synchronized void install(HttpServletRequest request) {
078        HttpSession s = request.getSession(true);
079        if (s.getAttribute(SessionFactory.SESSION_FACTORY_KEY) == null) {
080            s.setAttribute(SessionFactory.SESSION_FACTORY_KEY, new PerSessionCoreProvider());
081        }
082    }
083
084    @Override
085    protected Ref createSessionRef(CoreSession session) {
086        return new Ref(session);
087    }
088
089    @Override
090    public void onRequestDone(HttpServletRequest request) {
091        // unlock sessions if any was locked
092        for (SessionRef ref : getSessions()) {
093            ref.unget();
094        }
095    }
096
097    @Override
098    public void valueBound(HttpSessionBindingEvent event) {
099        // do nothing
100    }
101
102    @Override
103    public void valueUnbound(HttpSessionBindingEvent event) {
104        // destroy all sessions
105        if (!hasSessions()) {
106            destroy();
107            return;
108        }
109
110        LoginContext lc = null;
111        try {
112            lc = Framework.login();
113            destroy();
114        } catch (LoginException e) {
115            log.error(e, e);
116        } finally {
117            if (lc != null) {
118                try {
119                    lc.logout();
120                } catch (LoginException e) {
121                    log.error(e, e);
122                }
123            }
124        }
125    }
126
127    @Override
128    public synchronized SessionRef[] getSessions() {
129        return super.getSessions();
130    }
131
132    @Override
133    public synchronized SessionRef getSessionRef(HttpServletRequest request, String repoName) {
134        return super.getSessionRef(request, repoName);
135    }
136
137    @Override
138    public synchronized boolean hasSessions() {
139        return super.hasSessions();
140    }
141
142    @Override
143    protected synchronized void destroy() {
144        super.destroy();
145    }
146
147}