001/*
002 * (C) Copyright 2011 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     matic
018 */
019package org.nuxeo.ecm.webapp.seam;
020
021import java.io.IOException;
022import java.lang.management.ManagementFactory;
023import java.net.HttpURLConnection;
024import java.net.URL;
025import java.util.StringTokenizer;
026
027import javax.management.JMX;
028import javax.management.MBeanServer;
029import javax.management.MXBean;
030import javax.management.MalformedObjectNameException;
031import javax.management.ObjectInstance;
032import javax.management.ObjectName;
033
034import org.apache.commons.logging.Log;
035import org.apache.commons.logging.LogFactory;
036import org.nuxeo.runtime.api.Framework;
037import org.nuxeo.runtime.reload.ReloadEventNames;
038import org.nuxeo.runtime.services.event.Event;
039import org.nuxeo.runtime.services.event.EventListener;
040
041/**
042 * @author matic
043 * @since 5.5
044 */
045// TODO: protect methods by checking if seam hot reload is enabled (?)
046public class NuxeoSeamFlusher implements EventListener {
047
048    protected Log log = LogFactory.getLog(NuxeoSeamFlusher.class);
049
050    @Override
051    public boolean aboutToHandleEvent(Event event) {
052        return true;
053    }
054
055    @Override
056    public void handleEvent(Event event) {
057        if (NuxeoSeamWebGate.isInitialized() == false) {
058            return;
059        }
060        String id = event.getId();
061        if (ReloadEventNames.FLUSH_SEAM_EVENT_ID.equals(id)) {
062            SeamHotReloadHelper.flush();
063            try {
064                invalidateWebSessions();
065            } catch (IOException e) {
066                log.error("Cannot invalidate seam web sessions", e);
067            }
068        } else if (ReloadEventNames.RELOAD_SEAM_EVENT_ID.equals(id)) {
069            try {
070                if (postSeamReload() == false) {
071                    log.error("Cannot post hot-reload seam components on loopback url");
072                }
073            } catch (IOException e) {
074                log.error("Cannot hot-reload seam components", e);
075            }
076        }
077    }
078
079    protected boolean postSeamReload() throws IOException {
080        String loopbackURL = Framework.getProperty("nuxeo.loopback.url");
081        URL location = new URL(loopbackURL + "/restAPI/seamReload");
082        HttpURLConnection uc = (HttpURLConnection) location.openConnection();
083        uc.setRequestMethod("POST");
084        return uc.getResponseCode() == HttpURLConnection.HTTP_OK;
085    }
086
087    @MXBean
088    public interface WebSessionFlusher {
089
090        String listSessionIds();
091
092        void expireSession(String id);
093
094    }
095
096    protected void invalidateWebSessions() throws IOException {
097        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
098        ObjectName name;
099        try {
100            name = new ObjectName("Catalina:type=Manager,context=/nuxeo,host=*");
101        } catch (MalformedObjectNameException e) {
102            throw new IOException(e);
103        }
104        for (ObjectInstance oi : mbs.queryMBeans(name, null)) {
105            WebSessionFlusher flusher = JMX.newMBeanProxy(mbs, oi.getObjectName(), WebSessionFlusher.class);
106            StringTokenizer tokenizer = new StringTokenizer(flusher.listSessionIds(), " ");
107            while (tokenizer.hasMoreTokens()) {
108                String id = tokenizer.nextToken();
109                flusher.expireSession(id);
110            }
111        }
112    }
113
114}