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 void handleEvent(Event event) {
052        if (NuxeoSeamWebGate.isInitialized() == false) {
053            return;
054        }
055        String id = event.getId();
056        if (ReloadEventNames.FLUSH_SEAM_EVENT_ID.equals(id)) {
057            SeamHotReloadHelper.flush();
058            try {
059                invalidateWebSessions();
060            } catch (IOException e) {
061                log.error("Cannot invalidate seam web sessions", e);
062            }
063        } else if (ReloadEventNames.RELOAD_SEAM_EVENT_ID.equals(id)) {
064            try {
065                if (postSeamReload() == false) {
066                    log.error("Cannot post hot-reload seam components on loopback url");
067                }
068            } catch (IOException e) {
069                log.error("Cannot hot-reload seam components", e);
070            }
071        }
072    }
073
074    protected boolean postSeamReload() throws IOException {
075        String loopbackURL = Framework.getProperty("nuxeo.loopback.url");
076        URL location = new URL(loopbackURL + "/restAPI/seamReload");
077        HttpURLConnection uc = (HttpURLConnection) location.openConnection();
078        uc.setRequestMethod("POST");
079        return uc.getResponseCode() == HttpURLConnection.HTTP_OK;
080    }
081
082    @MXBean
083    public interface WebSessionFlusher {
084
085        String listSessionIds();
086
087        void expireSession(String id);
088
089    }
090
091    protected void invalidateWebSessions() throws IOException {
092        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
093        ObjectName name;
094        try {
095            name = new ObjectName("Catalina:type=Manager,context=/nuxeo,host=*");
096        } catch (MalformedObjectNameException e) {
097            throw new IOException(e);
098        }
099        for (ObjectInstance oi : mbs.queryMBeans(name, null)) {
100            WebSessionFlusher flusher = JMX.newMBeanProxy(mbs, oi.getObjectName(), WebSessionFlusher.class);
101            StringTokenizer tokenizer = new StringTokenizer(flusher.listSessionIds(), " ");
102            while (tokenizer.hasMoreTokens()) {
103                String id = tokenizer.nextToken();
104                flusher.expireSession(id);
105            }
106        }
107    }
108
109}