001/*
002 * (C) Copyright 2012 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 *     Anahide Tchertchian
018 */
019package org.nuxeo.ecm.webapp.seam;
020
021import static org.jboss.seam.annotations.Install.FRAMEWORK;
022
023import java.io.Serializable;
024
025import org.apache.commons.logging.Log;
026import org.apache.commons.logging.LogFactory;
027import org.jboss.seam.ScopeType;
028import org.jboss.seam.annotations.In;
029import org.jboss.seam.annotations.Install;
030import org.jboss.seam.annotations.Name;
031import org.jboss.seam.annotations.Scope;
032import org.jboss.seam.core.Events;
033import org.nuxeo.ecm.platform.ui.web.rest.RestfulPhaseListener;
034import org.nuxeo.ecm.webapp.helpers.EventNames;
035
036/**
037 * Conversation component that keeps the last update timestamp to handle hot reload when this timestamp changes.
038 * <p>
039 * Triggered by {@link RestfulPhaseListener} at the beginning of render response phase so that Seam components are not
040 * left in a strange state.
041 *
042 * @since 5.6
043 * @see RestfulPhaseListener
044 * @see NuxeoSeamHotReloader#shouldResetCache(Long)
045 * @see NuxeoSeamHotReloader#triggerResetOnSeamComponents()
046 */
047@Name("seamReloadContext")
048@Scope(ScopeType.CONVERSATION)
049@Install(precedence = FRAMEWORK)
050public class NuxeoSeamHotReloadContextKeeper implements Serializable {
051
052    private static final long serialVersionUID = 1L;
053
054    private static final Log log = LogFactory.getLog(NuxeoSeamHotReloader.class);
055
056    protected Long lastCacheKey;
057
058    @In(create = true)
059    protected NuxeoSeamHotReloader seamReload;
060
061    public void triggerReloadIdNeeded() {
062        if (lastCacheKey == null) {
063            doLog("No last cache key => no hot reload triggered");
064            lastCacheKey = Long.valueOf(System.currentTimeMillis());
065        } else {
066            if (seamReload.shouldResetCache(lastCacheKey)) {
067                doLog(String.format("Before reset, cache key=%s", lastCacheKey));
068                try {
069                    // trigger reset on Seam layer by raising the flush event
070                    Events.instance().raiseEvent(EventNames.FLUSH_EVENT);
071                } finally {
072                    // update cache key even if an error is triggered, to avoid
073                    // triggering cache reset over and over
074                    Long currentTimestamp = seamReload.getCurrentCacheTimestamp();
075                    if (currentTimestamp != null) {
076                        lastCacheKey = seamReload.getCurrentCacheTimestamp();
077                    }
078                }
079                doLog(String.format("After reset, cache key=%s", lastCacheKey));
080            } else {
081                doLog(String.format("No reset needed, cache key=%s", lastCacheKey));
082            }
083        }
084    }
085
086    protected void doLog(String message) {
087        if (log.isDebugEnabled()) {
088            log.debug(message);
089        }
090    }
091
092}