Java tutorial
/* * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * Contributors: * Thierry Delprat */ package org.nuxeo.ecm.webapp.seam; import static org.jboss.seam.ScopeType.EVENT; import static org.jboss.seam.annotations.Install.FRAMEWORK; import java.io.IOException; import java.io.Serializable; import java.security.Principal; import javax.faces.context.FacesContext; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.jboss.seam.ScopeType; import org.jboss.seam.annotations.Factory; import org.jboss.seam.annotations.In; import org.jboss.seam.annotations.Install; import org.jboss.seam.annotations.Name; import org.jboss.seam.annotations.Observer; import org.jboss.seam.annotations.Scope; import org.jboss.seam.annotations.intercept.BypassInterceptors; import org.jboss.seam.core.Events; import org.nuxeo.ecm.core.api.NuxeoPrincipal; import org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants; import org.nuxeo.ecm.platform.ui.web.rest.api.URLPolicyService; import org.nuxeo.ecm.platform.ui.web.util.BaseURL; import org.nuxeo.ecm.webapp.helpers.EventNames; import org.nuxeo.runtime.api.Framework; import org.nuxeo.runtime.reload.ReloadService; import org.nuxeo.runtime.service.TimestampedService; /** * Simple Seam bean to control the Reload Action * * @author tiry */ @Name("seamReload") @Scope(EVENT) @Install(precedence = FRAMEWORK) public class NuxeoSeamHotReloader implements Serializable { private static final long serialVersionUID = 1L; private static final Log log = LogFactory.getLog(NuxeoSeamHotReloader.class); @In(required = false, create = true) private transient Principal currentUser; /** * Returns true if dev mode is set * * @since 5.6 * @see Framework#isDevModeSet() */ @Factory(value = "nxDevModeSet", scope = ScopeType.EVENT) public boolean isDevModeSet() { return Framework.isDevModeSet(); } @Factory(value = "seamHotReloadIsEnabled", scope = ScopeType.APPLICATION) public boolean isHotReloadEnabled() { return SeamHotReloadHelper.isHotReloadEnabled(); } /** * Returns true if dev mode is set and current user is an administrator. * * @since 5.6 * @return */ public boolean getCanTriggerFlush() { NuxeoPrincipal pal = null; if (currentUser instanceof NuxeoPrincipal) { pal = (NuxeoPrincipal) currentUser; } return isDevModeSet() && pal != null && pal.isAdministrator(); } /** * Calls the {@link ReloadService#flush()} method, that should trigger the reset of a bunch of caches shared by all * users, and sends a Seam event to propagate this to other Seam components. * <p> * Does nothing if not in dev mode. * <p> * The reload service flush method should already be triggerd by install/uninstall of modules. This method makes it * possible to force it again, and to propagate it to the Seam layer for current user. * * @see #resetSeamComponentsCaches() * @see #shouldResetCache(Long) * @see #shouldResetCache(TimestampedService, Long) * @since 5.6 */ public String doFlush() { if (Framework.isDevModeSet()) { FacesContext faces = FacesContext.getCurrentInstance(); String viewId = faces.getViewRoot().getViewId(); URLPolicyService service = Framework.getLocalService(URLPolicyService.class); String outcome = service.getOutcomeFromViewId(viewId, null); ReloadService srv = Framework.getLocalService(ReloadService.class); srv.flush(); Events.instance().raiseEvent(EventNames.FLUSH_EVENT); // return the current view id otherwise an error appears in logs // because navigation cache needs to be rebuilt after execution return outcome; } return null; } /** * Returns true if reload service has sent a runtime flush event since given timestamp. * * @since 5.6 * @param cacheTimestamp * @see ReloadService#lastFlushed() */ public boolean shouldResetCache(Long cacheTimestamp) { if (cacheTimestamp == null) { return true; } Long serviceTimestamp = getCurrentCacheTimestamp(); if (serviceTimestamp == null) { return false; } if (cacheTimestamp.compareTo(serviceTimestamp) < 0) { return true; } return false; } /** * Returns the last flush timestamp held by the {@link ReloadService}. * * @since 5.6 * @see ReloadService * @see TimestampedService */ public Long getCurrentCacheTimestamp() { ReloadService service = Framework.getService(ReloadService.class); return service.lastFlushed(); } /** * Returns true if given service has changed since given timestamp. * * @since 5.6 * @param service * @param cacheTimestamp * @see TimestampedService */ public boolean shouldResetCache(TimestampedService service, Long cacheTimestamp) { if (cacheTimestamp == null || service == null) { return true; } Long serviceTimestamp = service.getLastModified(); if (serviceTimestamp == null) { return false; } if (cacheTimestamp.compareTo(serviceTimestamp) < 0) { return true; } return false; } /** * Resets most caches of the Seam application. * <p> * This is useful when a change is detected on the reload service. * <p> * For compatibility and easier upgrade, this method listens to the {@link EventNames#FLUSH_EVENT}, and sends other * events to the Seam layer for other components to reset their own cache without needing to change their code. * <p> * In the future, this behaviour could be removed, so Seam component should reset their cache listening to the * {@link EventNames#FLUSH_EVENT} directly. * * @since 5.6 */ @Observer(value = { EventNames.FLUSH_EVENT }, create = false) @BypassInterceptors public void triggerResetOnSeamComponents() { String[] events = { EventNames.USER_ALL_DOCUMENT_TYPES_SELECTION_CHANGED, EventNames.LOCATION_SELECTION_CHANGED, EventNames.CONTENT_ROOT_SELECTION_CHANGED, EventNames.DOMAIN_SELECTION_CHANGED, EventNames.LOCAL_CONFIGURATION_CHANGED, }; Events seamEvents = Events.instance(); for (String event : events) { seamEvents.raiseEvent(event); } } /** * Triggers a full reload of Seam context and components. * <p> * Needs the Seam debug jar to be present and Seam debug mode to be enabled. */ public String doReload() { final FacesContext facesContext = FacesContext.getCurrentInstance(); if (facesContext == null) { return null; } HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse(); HttpServletRequest request = (HttpServletRequest) facesContext.getExternalContext().getRequest(); String url = BaseURL.getBaseURL(request); url += "restAPI/seamReload"; try { response.resetBuffer(); response.sendRedirect(url); response.flushBuffer(); request.setAttribute(NXAuthConstants.DISABLE_REDIRECT_REQUEST_KEY, Boolean.TRUE); facesContext.responseComplete(); } catch (IOException e) { log.error("Error during redirect", e); } return null; } }