View Javadoc

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