| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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. |
| */ |
| package org.apache.myfaces.extensions.scripting.core.monitor; |
| |
| import org.apache.myfaces.extensions.scripting.core.api.ScriptingConst; |
| import org.apache.myfaces.extensions.scripting.core.api.WeavingContext; |
| import org.apache.myfaces.extensions.scripting.core.api.eventhandling.events.BeginLifecycle; |
| import org.apache.myfaces.extensions.scripting.core.api.eventhandling.events.EndLifecycle; |
| |
| import javax.servlet.ServletContext; |
| import java.lang.ref.WeakReference; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| /** |
| * Central daemon thread which watches the resources |
| * for changes and marks them as changed. |
| * This watchdog daemon is the central core |
| * of the entire scripting engine it runs asynchronously |
| * to your program and keeps an eye on the resources |
| * and their dependencies, once a file has changed |
| * all the referring dependencies are also marked |
| * as being to reloaded. |
| * |
| * @author Werner Punz (latest modification by $Author$) |
| * @version $Revision$ $Date$ |
| */ |
| public class ResourceMonitor extends Thread |
| { |
| |
| private static final String CONTEXT_KEY = "extscriptDaemon"; |
| |
| static ResourceMonitor _instance = null; |
| |
| |
| //Map<String, ClassResource> _classMap = new ConcurrentHashMap<String, ClassResource>(8, 0.75f, 1); |
| //ClassDependencies _dependencyMap = new ClassDependencies(); |
| |
| /** |
| * This map is a shortcut for the various scripting engines. |
| * It keeps track whether the engines source paths |
| * have dirty files or not and if true we enforce a recompile at the |
| * next refresh! |
| * <p> </p> |
| * We keep track on engine level to avoid to search the classMap for every refresh |
| * the classMap still is needed for various identification tasks which are reload |
| * related |
| */ |
| |
| boolean _running = false; |
| // boolean _contextInitialized = false; |
| Logger _log = Logger.getLogger(ResourceMonitor.class.getName()); |
| // ScriptingWeaver _weavers = null; |
| static WeakReference<ServletContext> _externalContext; |
| |
| public static synchronized void init(ServletContext externalContext) |
| { |
| |
| if (_externalContext != null) return; |
| _externalContext = new WeakReference<ServletContext>(externalContext); |
| if (getInstance() != null) return; |
| |
| //we currently keep it as singleton but in the long run we will move it into the context |
| //like everything else singleton-wise |
| |
| _instance = new ResourceMonitor(); |
| |
| /** |
| * daemon thread to allow forced |
| * shutdowns for web context restarts |
| */ |
| _instance.setDaemon(true); |
| _instance.setRunning(true); |
| //_instance.start(); |
| _externalContext.get().setAttribute(CONTEXT_KEY, _instance); |
| |
| } |
| |
| public static synchronized ResourceMonitor getInstance() |
| { |
| //we do it in this complicated manner because of find bugs |
| //practically this cannot really happen except for shutdown were it is not important anymore |
| if(_externalContext == null) return null; |
| ServletContext context = _externalContext.get(); |
| if (context != null) |
| { |
| return (ResourceMonitor) context.getAttribute(CONTEXT_KEY); |
| } |
| return null; |
| } |
| |
| /** |
| * Central run method |
| * which performs the entire scanning process |
| */ |
| public void run() |
| { |
| try { |
| //on Glassfish we have to defer the initial scan to avoid an NPE, for |
| //reasons not debuggable, TODO check for a concurrency issue there |
| //which causes the npe |
| Thread.sleep(3000); |
| } catch (InterruptedException ex) { |
| //removing the interrupted exception error handler because it can happen |
| //and should not log an error. |
| //Logger.getLogger(ResourceMonitor.class.getName()).log(Level.SEVERE, null, ex); |
| } |
| |
| while (!Thread.currentThread().isInterrupted()) |
| { |
| if (Thread.currentThread().isInterrupted()) break; |
| //we run the full scan on the classes to bring our data structures up to the task |
| performMonitoringTask(); |
| sleep(); |
| } |
| |
| if (_log.isLoggable(Level.INFO)) |
| { |
| _log.info("[EXT-SCRIPTING] Dynamic reloading watch daemon is shutting down"); |
| } |
| |
| } |
| |
| public void stopIt() |
| { |
| super.interrupt(); |
| _instance = null; |
| ServletContext context = _externalContext.get(); |
| context.setAttribute(CONTEXT_KEY, null); |
| _externalContext = null; |
| } |
| |
| public void performMonitoringTask() |
| { |
| synchronized(WeavingContext.getInstance().recompileLock) { |
| WeavingContext.getInstance().sendWeavingEvent(new BeginLifecycle()); |
| WeavingContext context = WeavingContext.getInstance(); |
| context.fullScan(); |
| |
| //we compile wherever needed, taints are now in place due to our scan already being performed |
| if (context.compile()) |
| { |
| //we now have to perform a full dependency scan to bring our dependency map to the latest state |
| context.scanDependencies(); |
| //we next retaint all classes according to our dependency graph |
| context.markTaintedDependends(); |
| } |
| WeavingContext.getInstance().sendWeavingEvent(new EndLifecycle()); |
| } |
| //context.annotationScan(); |
| |
| } |
| |
| |
| |
| private void sleep() |
| { |
| try |
| { |
| Thread.sleep(ScriptingConst.TAINT_INTERVAL); |
| } |
| catch (InterruptedException e) |
| { |
| //if the server shuts down while we are in sleep we get an error |
| //which we better should swallow |
| } |
| } |
| |
| public void setRunning(boolean running) |
| { |
| this._running = running; |
| } |
| |
| |
| } |
| |