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  /**
41   * Monitors the componentConfiguration.xml and triggers a reconfiguration
42   * if the content of the component configuration file  has changed.
43   *
44   * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
45   */
46  
47  public class ShutdownServiceImpl
48      extends AbstractLogEnabled
49      implements ShutdownService, Serviceable, Contextualizable,
50          Reconfigurable, Initializable, Runnable, Startable, Disposable
51  {
52      /** the interval between two checks in ms */
53      private int interval;
54  
55      /** shall the worker thread terminate immediately */
56      private boolean terminateNow;
57  
58      /** the worker thread polling the resource */
59      private Thread workerThread;
60  
61      /** the ServiceManager to use */
62      private ServiceManager serviceManager;
63  
64      /** the application directory */
65      private File applicationDir;
66  
67      /** our own and only shutdown entry */
68      private ShutdownEntry shutdownEntry;
69  
70      /////////////////////////////////////////////////////////////////////////
71      // Avalon Service Lifecycle Implementation
72      /////////////////////////////////////////////////////////////////////////
73  
74      /**
75       * Constructor
76       */
77      public ShutdownServiceImpl()
78      {
79          this.terminateNow = false;
80      }
81  
82      /**
83       * @see org.apache.avalon.framework.service.Serviceable#service(org.apache.avalon.framework.service.ServiceManager)
84       */
85      public void service(ServiceManager manager) throws ServiceException
86      {
87          this.serviceManager = manager;
88      }
89  
90      /**
91       * @see org.apache.avalon.framework.context.Contextualizable#contextualize(org.apache.avalon.framework.context.Context)
92       */
93      public void contextualize(Context context) throws ContextException
94      {
95          this.applicationDir  = (File) context.get("urn:avalon:home");
96      }
97  
98      /**
99       * @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 }