View Javadoc

1   /*
2    * $Id: DefaultMuleDeployer.java 20719 2010-12-14 19:23:28Z aperepel $
3    * --------------------------------------------------------------------------------------
4    * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
5    *
6    * The software in this package is published under the terms of the CPAL v1.0
7    * license, a copy of which has been included with this distribution in the
8    * LICENSE.txt file.
9    */
10  
11  package org.mule.module.launcher;
12  
13  import org.mule.config.i18n.MessageFactory;
14  import org.mule.module.launcher.application.Application;
15  import org.mule.module.reboot.MuleContainerBootstrapUtils;
16  import org.mule.util.FileUtils;
17  import org.mule.util.FilenameUtils;
18  
19  import java.beans.Introspector;
20  import java.io.File;
21  import java.io.IOException;
22  import java.net.URISyntaxException;
23  import java.net.URL;
24  import java.util.concurrent.TimeUnit;
25  import java.util.concurrent.locks.ReentrantLock;
26  
27  import org.apache.commons.logging.Log;
28  import org.apache.commons.logging.LogFactory;
29  
30  public class DefaultMuleDeployer implements MuleDeployer
31  {
32  
33      protected transient final Log logger = LogFactory.getLog(getClass());
34      protected DeploymentService deploymentService;
35  
36  
37      public DefaultMuleDeployer(DeploymentService deploymentService)
38      {
39          this.deploymentService = deploymentService;
40      }
41  
42      public void deploy(Application app)
43      {
44          final ReentrantLock lock = deploymentService.getLock();
45          try
46          {
47              if (!lock.tryLock(0, TimeUnit.SECONDS))
48              {
49                  return;
50              }
51              app.install();
52              app.init();
53              app.start();
54          }
55          catch (InterruptedException e)
56          {
57              Thread.currentThread().interrupt();
58              return;
59          }
60          catch (Throwable t)
61          {
62              if (t instanceof DeploymentException)
63              {
64                  // re-throw as is
65                  throw ((DeploymentException) t);
66              }
67  
68              final String msg = String.format("Failed to deploy application [%s]", app.getAppName());
69              throw new DeploymentException(MessageFactory.createStaticMessage(msg), t);
70          }
71          finally
72          {
73              if (lock.isHeldByCurrentThread())
74              {
75                  lock.unlock();
76              }
77          }
78      }
79  
80      public void undeploy(Application app)
81      {
82          final ReentrantLock lock = deploymentService.getLock();
83          try
84          {
85              if (!lock.tryLock(0, TimeUnit.SECONDS))
86              {
87                  return;
88              }
89  
90              app.stop();
91              app.dispose();
92              final File appDir = new File(MuleContainerBootstrapUtils.getMuleAppsDir(), app.getAppName());
93              FileUtils.deleteDirectory(appDir);
94              // remove a marker, harmless, but a tidy app dir is always better :)
95              File marker = new File(MuleContainerBootstrapUtils.getMuleAppsDir(), String.format("%s-anchor.txt", app.getAppName()));
96              marker.delete();
97              Introspector.flushCaches();
98          }
99          catch (InterruptedException e)
100         {
101             Thread.currentThread().interrupt();
102             return;
103         }
104         catch (Throwable t)
105         {
106             // TODO logging
107             t.printStackTrace();
108         }
109         finally
110         {
111             if (lock.isHeldByCurrentThread())
112             {
113                 lock.unlock();
114             }
115         }
116     }
117 
118     public Application installFromAppDir(String packedMuleAppFileName) throws IOException
119     {
120         final ReentrantLock lock = deploymentService.getLock();
121         try
122         {
123             if (!lock.tryLock(0, TimeUnit.SECONDS))
124             {
125                 throw new IOException("Another deployment operation is in progress");
126             }
127 
128             final File appsDir = MuleContainerBootstrapUtils.getMuleAppsDir();
129             File appFile = new File(appsDir, packedMuleAppFileName);
130             // basic security measure: outside apps dir use installFrom(url) and go through any
131             // restrictions applied to it
132             if (!appFile.getParentFile().equals(appsDir))
133             {
134                 throw new SecurityException("installFromAppDir() can only deploy from $MULE_HOME/apps. Use installFrom(url) instead.");
135             }
136             return installFrom(appFile.toURL());
137         }
138         catch (InterruptedException e)
139         {
140             Thread.currentThread().interrupt();
141             throw new IOException("Install operation has been interrupted");
142         }
143         finally
144         {
145             if (lock.isHeldByCurrentThread())
146             {
147                 lock.unlock();
148             }
149         }
150     }
151 
152     public Application installFrom(URL url) throws IOException
153     {
154         // TODO plug in app-bloodhound/validator here?
155         if (!url.toString().endsWith(".zip"))
156         {
157             throw new IllegalArgumentException("Invalid Mule application archive: " + url);
158         }
159 
160         final String baseName = FilenameUtils.getBaseName(url.toString());
161         if (baseName.contains("%20"))
162         {
163             throw new DeploymentInitException(
164                     MessageFactory.createStaticMessage("Mule application name may not contain spaces: " + baseName));
165         }
166 
167         final ReentrantLock lock = deploymentService.getLock();
168 
169         String appName;
170         File appDir = null;
171         boolean errorEncountered = false;
172         try
173         {
174             if (!lock.tryLock(0, TimeUnit.SECONDS))
175             {
176                 throw new IOException("Another deployment operation is in progress");
177             }
178 
179             final File appsDir = MuleContainerBootstrapUtils.getMuleAppsDir();
180 
181             final String fullPath = url.toURI().toString();
182 
183             if (logger.isInfoEnabled())
184             {
185                 logger.info("Exploding a Mule application archive: " + fullPath);
186             }
187 
188             appName = FilenameUtils.getBaseName(fullPath);
189             appDir = new File(appsDir, appName);
190             // normalize the full path + protocol to make unzip happy
191             final File source = new File(url.toURI());
192             
193             FileUtils.unzip(source, appDir);
194             if ("file".equals(url.getProtocol()))
195             {
196                 FileUtils.deleteQuietly(source);
197             }
198         }
199         catch (URISyntaxException e)
200         {
201             errorEncountered = true;
202             final IOException ex = new IOException(e.getMessage());
203             ex.fillInStackTrace();
204             throw ex;
205         }
206         catch (InterruptedException e)
207         {
208             errorEncountered = true;
209             Thread.currentThread().interrupt();
210             throw new IOException("Install operation has been interrupted");
211         }
212         catch (IOException e)
213         {
214             errorEncountered = true;
215             // re-throw
216             throw e;
217         }
218         catch (Throwable t)
219         {
220             errorEncountered = true;
221             final String msg = "Failed to install app from URL: " + url;
222             throw new DeploymentInitException(MessageFactory.createStaticMessage(msg), t);
223         }
224         finally {
225             // delete an app dir, as it's broken
226             if (errorEncountered && appDir != null && appDir.exists())
227             {
228                 final boolean couldNotDelete = FileUtils.deleteTree(appDir);
229                 /*
230                 if (couldNotDelete)
231                 {
232                     final String msg = String.format("Couldn't delete app directory '%s' after it failed to install", appDir);
233                     logger.error(msg);
234                 }
235                 */
236             }
237             if (lock.isHeldByCurrentThread())
238             {
239                 lock.unlock();
240             }
241         }
242 
243         // appname is never null by now
244         return deploymentService.getAppFactory().createApp(appName);
245     }
246 }