001 package org.apache.fulcrum.yaafi.service.shutdown; 002 003 /* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022 import java.io.File; 023 import java.security.MessageDigest; 024 025 import org.apache.avalon.framework.activity.Disposable; 026 import org.apache.avalon.framework.activity.Initializable; 027 import org.apache.avalon.framework.activity.Startable; 028 import org.apache.avalon.framework.configuration.Configuration; 029 import org.apache.avalon.framework.configuration.ConfigurationException; 030 import org.apache.avalon.framework.configuration.Reconfigurable; 031 import org.apache.avalon.framework.context.Context; 032 import org.apache.avalon.framework.context.ContextException; 033 import org.apache.avalon.framework.context.Contextualizable; 034 import org.apache.avalon.framework.logger.AbstractLogEnabled; 035 import org.apache.avalon.framework.service.ServiceException; 036 import org.apache.avalon.framework.service.ServiceManager; 037 import org.apache.avalon.framework.service.Serviceable; 038 039 040 /** 041 * Monitors the componentConfiguration.xml and triggers a reconfiguration 042 * if the content of the component configuration file has changed. 043 * 044 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a> 045 */ 046 047 public class ShutdownServiceImpl 048 extends AbstractLogEnabled 049 implements ShutdownService, Serviceable, Contextualizable, 050 Reconfigurable, Initializable, Runnable, Startable, Disposable 051 { 052 /** the interval between two checks in ms */ 053 private int interval; 054 055 /** shall the worker thread terminate immediately */ 056 private boolean terminateNow; 057 058 /** the worker thread polling the resource */ 059 private Thread workerThread; 060 061 /** the ServiceManager to use */ 062 private ServiceManager serviceManager; 063 064 /** the application directory */ 065 private File applicationDir; 066 067 /** our own and only shutdown entry */ 068 private ShutdownEntry shutdownEntry; 069 070 ///////////////////////////////////////////////////////////////////////// 071 // Avalon Service Lifecycle Implementation 072 ///////////////////////////////////////////////////////////////////////// 073 074 /** 075 * Constructor 076 */ 077 public ShutdownServiceImpl() 078 { 079 this.terminateNow = false; 080 } 081 082 /** 083 * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager) 084 */ 085 public void service(ServiceManager manager) throws ServiceException 086 { 087 this.serviceManager = manager; 088 } 089 090 /** 091 * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context) 092 */ 093 public void contextualize(Context context) throws ContextException 094 { 095 this.applicationDir = (File) context.get("urn:avalon:home"); 096 } 097 098 /** 099 * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration) 100 */ 101 public void configure(Configuration configuration) throws ConfigurationException 102 { 103 // limit to minimum interval of 1 second 104 105 this.interval = Math.max( configuration.getAttributeAsInteger("interval",5000), 1000 ); 106 107 this.getLogger().debug( "Monitoring the resources every " + this.interval + " ms" ); 108 109 if( configuration.getChild("entry",false) != null ) 110 { 111 Configuration shutdownConfig = configuration.getChild("entry"); 112 113 String shutdownEntryLocation = shutdownConfig.getChild("location").getValue(); 114 115 this.shutdownEntry = new ShutdownEntry( 116 this.getLogger(), 117 this.applicationDir, 118 shutdownEntryLocation, 119 shutdownConfig.getChild("useSystemExit").getValueAsBoolean(false) 120 ); 121 122 this.getLogger().debug( "Using a shutdown entry : " + shutdownEntryLocation ); 123 } 124 else 125 { 126 this.shutdownEntry = null; 127 this.getLogger().debug( "No shutdown entry defined" ); 128 } 129 } 130 131 /** 132 * @see org.apache.avalon.framework.activity.Initializable#initialize() 133 */ 134 public void initialize() throws Exception 135 { 136 // request a SHA-1 to make sure that it is supported 137 138 MessageDigest.getInstance( "SHA1" ); 139 140 // check that the ServiceManager inplements Disposable 141 142 if( (this.serviceManager instanceof Disposable) == false ) 143 { 144 String msg = "The ServiceManager instance does not implement Disposable?!"; 145 throw new IllegalArgumentException( msg ); 146 } 147 148 // create the worker thread polling the target 149 150 this.workerThread = new Thread( this, "ShutdownService" ); 151 } 152 153 /** 154 * @see org.apache.avalon.framework.activity.Startable#start() 155 */ 156 public void start() throws Exception 157 { 158 this.getLogger().debug( "Starting worker thread ..." ); 159 this.workerThread.start(); 160 } 161 162 /** 163 * @see org.apache.avalon.framework.activity.Startable#stop() 164 */ 165 public void stop() throws Exception 166 { 167 this.getLogger().debug( "Stopping worker thread ..." ); 168 this.terminateNow = true; 169 this.workerThread.interrupt(); 170 this.workerThread.join( 10000 ); 171 } 172 173 /** 174 * @see org.apache.avalon.framework.activity.Disposable#dispose() 175 */ 176 public void dispose() 177 { 178 this.terminateNow = false; 179 this.applicationDir = null; 180 this.workerThread = null; 181 this.serviceManager = null; 182 } 183 184 /** 185 * @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration) 186 */ 187 public void reconfigure(Configuration configuration) 188 throws ConfigurationException 189 { 190 this.configure(configuration); 191 } 192 193 ///////////////////////////////////////////////////////////////////////// 194 // Service interface implementation 195 ///////////////////////////////////////////////////////////////////////// 196 197 /** 198 * @see java.lang.Runnable#run() 199 */ 200 public void run() 201 { 202 while( this.terminateNow == false ) 203 { 204 try 205 { 206 Thread.sleep( this.interval ); 207 } 208 catch (InterruptedException e) 209 { 210 // nothing to do 211 } 212 213 if( this.hasShutdownEntry() && this.getShutdownEntry().hasChanged() ) 214 { 215 if( this.serviceManager instanceof Disposable ) 216 { 217 if( this.getShutdownEntry().isUseSystemExit() ) 218 { 219 this.getLogger().warn( "Forcing a shutdown using System.exit() ..." ); 220 } 221 else 222 { 223 this.getLogger().warn( "Forcing a shutdown ..." ); 224 } 225 226 // create a demon thread to shutdown the container 227 228 Shutdown shutdown = new Shutdown( 229 (Disposable) this.serviceManager, 230 this.getShutdownEntry().isUseSystemExit() 231 ); 232 233 Thread shutdownThread = new Thread( shutdown, "ShutdownServiceThread" ); 234 shutdownThread.setDaemon(true); 235 shutdownThread.start(); 236 } 237 } 238 } 239 } 240 241 ///////////////////////////////////////////////////////////////////////// 242 // Service implementation 243 ///////////////////////////////////////////////////////////////////////// 244 245 /** 246 * @return Returns the shutdownEntry. 247 */ 248 private ShutdownEntry getShutdownEntry() 249 { 250 return this.shutdownEntry; 251 } 252 253 /** 254 * @return Is a shutdown entry defined? 255 */ 256 private boolean hasShutdownEntry() 257 { 258 return ( this.shutdownEntry != null ? true : false ); 259 } 260 }