View Javadoc
1   package org.apache.fulcrum.yaafi.service.shutdown;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.security.MessageDigest;
24  
25  import org.apache.avalon.framework.activity.Disposable;
26  import org.apache.avalon.framework.activity.Initializable;
27  import org.apache.avalon.framework.activity.Startable;
28  import org.apache.avalon.framework.configuration.Configuration;
29  import org.apache.avalon.framework.configuration.ConfigurationException;
30  import org.apache.avalon.framework.configuration.Reconfigurable;
31  import org.apache.avalon.framework.context.Context;
32  import org.apache.avalon.framework.context.ContextException;
33  import org.apache.avalon.framework.context.Contextualizable;
34  import org.apache.avalon.framework.logger.AbstractLogEnabled;
35  import org.apache.avalon.framework.service.ServiceException;
36  import org.apache.avalon.framework.service.ServiceManager;
37  import org.apache.avalon.framework.service.Serviceable;
38  
39  /**
40   * Monitors the componentConfiguration.xml and triggers a reconfiguration if the
41   * content of the component configuration file has changed.
42   *
43   * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
44   */
45  
46  public class ShutdownServiceImpl extends AbstractLogEnabled implements ShutdownService, Serviceable, Contextualizable,
47  		Reconfigurable, Initializable, Runnable, Startable, Disposable {
48  	/** the interval between two checks in ms */
49  	private int interval;
50  
51  	/** shall the worker thread terminate immediately */
52  	private boolean terminateNow;
53  
54  	/** the worker thread polling the resource */
55  	private Thread workerThread;
56  
57  	/** the ServiceManager to use */
58  	private ServiceManager serviceManager;
59  
60  	/** the application directory */
61  	private File applicationDir;
62  
63  	/** our own and only shutdown entry */
64  	private ShutdownEntry shutdownEntry;
65  
66  	/////////////////////////////////////////////////////////////////////////
67  	// Avalon Service Lifecycle Implementation
68  	/////////////////////////////////////////////////////////////////////////
69  
70  	/**
71  	 * Constructor
72  	 */
73  	public ShutdownServiceImpl() {
74  		this.terminateNow = false;
75  	}
76  
77  	/**
78  	 * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
79  	 */
80  	public void service(ServiceManager manager) throws ServiceException {
81  		this.serviceManager = manager;
82  	}
83  
84  	/**
85  	 * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
86  	 */
87  	public void contextualize(Context context) throws ContextException {
88  		this.applicationDir = (File) context.get("urn:avalon:home");
89  	}
90  
91  	/**
92  	 * @see org.apache.avalon.framework.configuration.Configurable#configure(org.apache.avalon.framework.configuration.Configuration)
93  	 */
94  	public void configure(Configuration configuration) throws ConfigurationException {
95  		// limit to minimum interval of 1 second
96  
97  		this.interval = Math.max(configuration.getAttributeAsInteger("interval", 5000), 1000);
98  
99  		this.getLogger().debug("Monitoring the resources every " + this.interval + " ms");
100 
101 		if (configuration.getChild("entry", false) != null) {
102 			Configuration shutdownConfig = configuration.getChild("entry");
103 
104 			String shutdownEntryLocation = shutdownConfig.getChild("location").getValue();
105 
106 			this.shutdownEntry = new ShutdownEntry(this.getLogger(), this.applicationDir, shutdownEntryLocation,
107 					shutdownConfig.getChild("useSystemExit").getValueAsBoolean(false));
108 
109 			this.getLogger().debug("Using a shutdown entry : " + shutdownEntryLocation);
110 		} else {
111 			this.shutdownEntry = null;
112 			this.getLogger().debug("No shutdown entry defined");
113 		}
114 	}
115 
116 	/*
117 	 * (non-Javadoc)
118 	 * 
119 	 * @see org.apache.avalon.framework.activity.Initializable#initialize()
120 	 */
121 	public void initialize() throws Exception {
122 
123 		// request a SHA-1 to make sure that it is supported
124 		MessageDigest.getInstance("SHA1");
125 
126 		// check that the ServiceManager inplements Disposable
127 		if (this.serviceManager instanceof Disposable == false) {
128 			String msg = "The ServiceManager instance does not implement Disposable?!";
129 			throw new IllegalArgumentException(msg);
130 		}
131 
132 		// create the worker thread polling the target
133 		this.workerThread = new Thread(this, "ShutdownService");
134 	}
135 
136 	/*
137 	 * (non-Javadoc)
138 	 * 
139 	 * @see org.apache.avalon.framework.activity.Startable#start()
140 	 */
141 	public void start() throws Exception {
142 		this.getLogger().debug("Starting worker thread ...");
143 		this.workerThread.start();
144 	}
145 
146 	/**
147 	 * @see org.apache.avalon.framework.activity.Startable#stop()
148 	 */
149 	public void stop() throws Exception {
150 		this.getLogger().debug("Stopping worker thread ...");
151 		this.terminateNow = true;
152 		this.workerThread.interrupt();
153 		this.workerThread.join(10000);
154 	}
155 
156 	/**
157 	 * @see org.apache.avalon.framework.activity.Disposable#dispose()
158 	 */
159 	public void dispose() {
160 		this.terminateNow = false;
161 		this.applicationDir = null;
162 		this.workerThread = null;
163 		this.serviceManager = null;
164 	}
165 
166 	/**
167 	 * @see org.apache.avalon.framework.configuration.Reconfigurable#reconfigure(org.apache.avalon.framework.configuration.Configuration)
168 	 */
169 	public void reconfigure(Configuration configuration) throws ConfigurationException {
170 		this.configure(configuration);
171 	}
172 
173 	/////////////////////////////////////////////////////////////////////////
174 	// Service interface implementation
175 	/////////////////////////////////////////////////////////////////////////
176 
177 	/* (non-Javadoc)
178 	 * @see java.lang.Runnable#run()
179 	 */
180 	public void run() {
181 		while (this.terminateNow == false) {
182 			try {
183 				Thread.sleep(this.interval);
184 			} catch (InterruptedException e) {
185 				// nothing to do
186 			}
187 
188 			if (this.hasShutdownEntry() && this.getShutdownEntry().hasChanged()
189 					&& this.serviceManager instanceof Disposable) {
190 
191 				if (this.getShutdownEntry().isUseSystemExit()) {
192 					this.getLogger().warn("Forcing a shutdown using System.exit() ...");
193 				} else {
194 					this.getLogger().warn("Forcing a shutdown ...");
195 				}
196 
197 				// create a demon thread to shutdown the container
198 				Shutdown shutdown = new Shutdown((Disposable) this.serviceManager,
199 						this.getShutdownEntry().isUseSystemExit());
200 
201 				Thread shutdownThread = new Thread(shutdown, "ShutdownServiceThread");
202 				shutdownThread.setDaemon(true);
203 				shutdownThread.start();
204 			}
205 		}
206 	}
207 
208 	/////////////////////////////////////////////////////////////////////////
209 	// Service implementation
210 	/////////////////////////////////////////////////////////////////////////
211 
212 	/**
213 	 * @return Returns the shutdownEntry.
214 	 */
215 	private ShutdownEntry getShutdownEntry() {
216 		return this.shutdownEntry;
217 	}
218 
219 	/**
220 	 * @return Is a shutdown entry defined?
221 	 */
222 	private boolean hasShutdownEntry() {
223 		return (this.shutdownEntry != null ? true : false);
224 	}
225 }