KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > varia > deployment > FoeDeployer


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.varia.deployment;
23
24 import java.io.File JavaDoc;
25 import java.io.FileInputStream JavaDoc;
26 import java.io.FileOutputStream JavaDoc;
27 import java.io.IOException JavaDoc;
28 import java.io.InputStream JavaDoc;
29 import java.io.OutputStream JavaDoc;
30
31 import java.net.URL JavaDoc;
32 import java.net.MalformedURLException JavaDoc;
33
34 import java.util.ArrayList JavaDoc;
35 import java.util.Collection JavaDoc;
36 import java.util.Iterator JavaDoc;
37 import java.util.List JavaDoc;
38 import java.util.ListIterator JavaDoc;
39 import java.util.Enumeration JavaDoc;
40 import java.util.HashMap JavaDoc;
41 import java.util.Map JavaDoc;
42 import java.util.jar.JarFile JavaDoc;
43 import java.util.jar.JarEntry JavaDoc;
44
45 import javax.management.MBeanServer JavaDoc;
46 import javax.management.MalformedObjectNameException JavaDoc;
47 import javax.management.ObjectName JavaDoc;
48
49 import org.jboss.deployment.DeploymentException;
50 import org.jboss.deployment.DeploymentInfo;
51 import org.jboss.deployment.MainDeployerMBean;
52 import org.jboss.deployment.SubDeployer;
53 import org.jboss.deployment.SubDeployerSupport;
54
55 import org.jboss.system.ServiceControllerMBean;
56 import org.jboss.system.server.ServerConfig;
57 import org.jboss.system.server.ServerConfigLocator;
58
59 import org.jboss.util.Counter;
60 import org.jboss.util.file.Files;
61 import org.jboss.util.file.JarUtils;
62 import org.jboss.mx.util.MBeanProxyExt;
63
64 import org.jboss.varia.deployment.convertor.Convertor;
65
66 /**
67  * This is the deployer for other vendor's applications
68  * with dynamic migration of vendor-specific DDs to
69  * JBoss specific DDs.
70  *
71  * @see org.jboss.varia.deployment.convertor.Convertor
72  *
73  * @author <a HREF="mailto:andreas@jboss.org">Andreas Schaefer</a>
74  * @version $Revision: 37459 $
75  *
76  * @jmx.mbean
77  * name="jboss.system:service=ServiceDeployer"
78  * extends="org.jboss.deployment.SubDeployerMBean"
79  */

80 public class FoeDeployer
81    extends SubDeployerSupport
82    implements SubDeployer, FoeDeployerMBean
83 {
84    // Attributes ----------------------------------------------------
85
/** A proxy to the ServiceControllerDeployer. */
86    private ServiceControllerMBean serviceController;
87
88    /** The deployers scratch directory. */
89    private File JavaDoc scratchDirectory;
90    
91    /** Contains the list of available converters */
92    private List JavaDoc converterList = new ArrayList JavaDoc();
93    
94    /** an increment for tmp files */
95    private final Counter id = Counter.makeSynchronized(new Counter(0));
96
97    /** map of exploaded deployment destionation in scratch directoy by DeploymentInfo */
98    private ThreadLocal JavaDoc destinationByDI = new ThreadLocal JavaDoc() {
99       protected Object JavaDoc initialValue()
100       {
101          return new HashMap JavaDoc();
102       }
103    };
104
105    // SubDeployerSupport overrides ----------------------------------
106
/**
107     * Returns true if the there is a converter available to convert
108     * the deployment unit.
109     *
110     * @jmx.managed-operation
111     */

112    public boolean accepts(DeploymentInfo di)
113    {
114       // delegate accepts to convertors
115
Iterator JavaDoc i = converterList.iterator();
116       while(i.hasNext())
117       {
118          Convertor converter = (Convertor)i.next();
119          if(converter.accepts(di.url))
120          {
121             return true;
122          }
123       }
124       return false;
125    }
126
127    /**
128     * Returns true if the there is a converter available to convert
129     * the deployment unit.
130     */

131    public boolean accepts(URL JavaDoc url)
132    {
133       // delegate accepts to convertors
134
Iterator JavaDoc i = converterList.iterator();
135       while(i.hasNext())
136       {
137          Convertor converter = (Convertor)i.next();
138          if(converter.accepts(url))
139          {
140             return true;
141          }
142       }
143       return false;
144    }
145
146    /**
147     * At the init phase the deployment unit and its subdeployment units are unpacked.
148     * @jmx.managed-operation
149     */

150    public void init(DeploymentInfo di)
151       throws DeploymentException
152    {
153       // Determine the destination for unpacking and save it in the ThreadLocal
154
Map JavaDoc destinations = (Map JavaDoc)destinationByDI.get();
155       File JavaDoc destination = (File JavaDoc)destinations.get(di.parent);
156       if(destination == null)
157       {
158          // Loop until for new destination
159
while(destination == null || destination.exists())
160             destination = new File JavaDoc(scratchDirectory, id.increment() + "." + di.shortName);
161       }
162       else
163       {
164          destination = new File JavaDoc(destination, di.shortName);
165       }
166       destinations.put(di, destination);
167       destinationByDI.set(destinations);
168
169       try
170       {
171          log.debug("unpacking to " + destination);
172          inflateJar(di.localUrl, destination);
173       }
174       catch(Exception JavaDoc e)
175       {
176          throw new DeploymentException("Unpacking failed: ", e);
177       }
178
179       // invoke super class' initialization
180
super.init(di);
181    }
182    
183    /**
184     * At the create phase, the conversion and packing is done.
185     * @jmx.managed-operation
186     */

187    public void create(DeploymentInfo di)
188       throws DeploymentException
189    {
190       try
191       {
192          // fetch the destionation of unpacked deployment from ThreadLocal
193
Map JavaDoc destinations = (Map JavaDoc)destinationByDI.get();
194          File JavaDoc inflateDest = (File JavaDoc)destinations.get(di);
195
196          // Look for the converter that accepts vendor specific deployment descriptors
197
// and let it convert them
198
Iterator JavaDoc i = converterList.iterator();
199          while(i.hasNext())
200          {
201             Convertor converter = (Convertor)i.next();
202             if(converter.accepts(di.url))
203             {
204                // Convert them to JBoss specific DDs
205
converter.convert(di, inflateDest);
206                // Now conversion is done and we can leave
207
break;
208             }
209          }
210
211          // deflate
212
File JavaDoc deflateDest = (File JavaDoc)destinations.get(di.parent);
213          if(deflateDest == null)
214             deflateDest = scratchDirectory;
215          String JavaDoc validName = null;
216          if(di.shortName.endsWith(".wl"))
217             validName = di.shortName.substring(0, di.shortName.length()-3);
218          else
219             validName = di.shortName.substring( 0, di.shortName.length() - 4 ) + "jar";
220          File JavaDoc convertedUnit = new File JavaDoc(deflateDest, validName);
221          log.debug("deflating to " + convertedUnit);
222          deflateJar(convertedUnit, inflateDest);
223
224          // remove unpacked deployment unit
225
Files.delete(inflateDest);
226
227          // copy the converted app back to the deployment directory
228
if(di.parent == null)
229             copyFile(convertedUnit, new File JavaDoc(di.url.getFile()).getParentFile());
230       }
231       catch(Exception JavaDoc e)
232       {
233          log.error("Conversion error: ", e);
234       }
235    }
236
237    /**
238     * This method stops this deployment because it is not of any
239     * use anymore (conversion is done)
240     * @jmx.managed-operation
241     */

242    public void start(DeploymentInfo di)
243       throws DeploymentException
244    {
245       stop(di);
246       destroy(di);
247    }
248
249    /**
250     * @jmx.managed-operation
251     */

252    public void stop(DeploymentInfo di)
253    {
254       log.debug("undeploying application: " + di.url);
255    }
256
257    /**
258     * @jmx.managed-operation
259     */

260    public void destroy(DeploymentInfo di)
261    {
262       List JavaDoc services = di.mbeans;
263       int lastService = services.size();
264       for(ListIterator JavaDoc i = services.listIterator(lastService); i.hasPrevious();)
265       {
266          ObjectName JavaDoc name = (ObjectName JavaDoc)i.previous();
267          log.debug( "destroying mbean " + name );
268          try
269          {
270             serviceController.destroy(name);
271          }
272          catch(Exception JavaDoc e)
273          {
274             log.error("Could not destroy mbean: " + name, e);
275          }
276       }
277
278       for(ListIterator JavaDoc i = services.listIterator(lastService); i.hasPrevious();)
279       {
280          ObjectName JavaDoc name = (ObjectName JavaDoc)i.previous();
281          log.debug("removing mbean " + name);
282          try
283          {
284             serviceController.remove( name );
285          }
286          catch(Exception JavaDoc e)
287          {
288             log.error("Could not remove mbean: " + name, e);
289          }
290       }
291    }
292
293    /**
294     * This method is called in SubDeployerSupport.processNestedDeployments()
295     * The method is overriden to deploy the deployments acceptable by FoeDeployer only.
296     */

297    protected void addDeployableJar(DeploymentInfo di, JarFile JavaDoc jarFile)
298       throws DeploymentException
299    {
300       String JavaDoc urlPrefix = "jar:" + di.localUrl.toString() + "!/";
301       for(Enumeration JavaDoc e = jarFile.entries(); e.hasMoreElements();)
302       {
303          JarEntry JavaDoc entry = (JarEntry JavaDoc)e.nextElement();
304          String JavaDoc name = entry.getName();
305          try
306          {
307             URL JavaDoc url = new URL JavaDoc(urlPrefix + name);
308             if(isDeployable(name, url))
309             {
310                // Obtain a jar url for the nested jar
311
// Append the ".wl" suffix to prevent other than FoeDeployer deployers'
312
// attempts to deploy the deployment unit
313
URL JavaDoc nestedURL = JarUtils.extractNestedJar(url, this.tempDeployDir);
314                File JavaDoc file = new File JavaDoc(nestedURL.getFile());
315                File JavaDoc wlFile = new File JavaDoc(nestedURL.getFile() + ".wl");
316                file.renameTo(wlFile);
317
318                if(accepts(wlFile.toURL()))
319                {
320                   deployUrl(di, wlFile.toURL(), name + ".wl");
321                }
322                else
323                {
324                   // if the deployment isn't accepted rename it back
325
wlFile.renameTo(new File JavaDoc(nestedURL.getFile()));
326                }
327             }
328          }
329          catch(MalformedURLException JavaDoc mue)
330          {
331             log.warn("Jar entry invalid; ignoring: " + name, mue);
332          }
333          catch(IOException JavaDoc ex)
334          {
335             log.warn("Failed to extract nested jar; ignoring: " + name, ex);
336          }
337       }
338    }
339
340    /**
341     * The startService method
342     * - gets the mbeanProxies for MainDeployer and ServiceController;
343     * - creates scratch directory for foe work.
344     *
345     * @exception Exception if an error occurs
346     */

347    protected void startService()
348       throws Exception JavaDoc
349    {
350       mainDeployer = (MainDeployerMBean) MBeanProxyExt.create(
351          MainDeployerMBean.class,
352          MainDeployerMBean.OBJECT_NAME,
353          server
354       );
355
356       // get the controller proxy
357
serviceController = (ServiceControllerMBean) MBeanProxyExt.create(
358          ServiceControllerMBean.class,
359          ServiceControllerMBean.OBJECT_NAME,
360          server
361       );
362
363       ServerConfig config = ServerConfigLocator.locate();
364
365       // build the scratch directory
366
File JavaDoc tempDirectory = config.getServerTempDir();
367       scratchDirectory = new File JavaDoc(tempDirectory, "foe");
368       if(!scratchDirectory.exists())
369          scratchDirectory.mkdirs();
370
371       // Note: this should go the last.
372
// scratch directory must be created before this call
373
super.startService();
374    }
375
376    /**
377     * Returns the ObjectName
378     */

379    protected ObjectName JavaDoc getObjectName(MBeanServer JavaDoc server, ObjectName JavaDoc name)
380       throws MalformedObjectNameException JavaDoc
381    {
382       return name == null ? OBJECT_NAME : name;
383    }
384
385    // FoeDeployerMBean implementation -------------------------------
386
/**
387     * Add a new conveter to the list. If the same converter is
388     * added, this new one won't be added, meaning everything stays the same.
389     * This method is normally called by a Converter to be
390     * called by this deployer to convert.
391     *
392     * @param converter New Converter to be added
393     *
394     * @jmx.managed-operation
395     */

396    public void addConvertor(Convertor converter)
397    {
398       converterList.add(converter);
399
400       // try to deploy waiting deployment units
401
// note: there is no need to synchronize, because MainDeployer
402
// returns a copy of waiting deployments
403
Collection JavaDoc waitingDeployments = mainDeployer.listWaitingForDeployer();
404       if((waitingDeployments != null) && (waitingDeployments.size() > 0))
405       {
406          for( Iterator JavaDoc iter = waitingDeployments.iterator(); iter.hasNext(); )
407          {
408             DeploymentInfo di = (DeploymentInfo)iter.next();
409
410             // check whether the converter accepts the deployment
411
if(!converter.accepts(di.url))
412                continue;
413             
414             log.debug("trying to deploy with new converter: " + di.shortName);
415             try
416             {
417                mainDeployer.redeploy(di);
418             }
419             catch (DeploymentException e)
420             {
421                log.error("DeploymentException while trying to deploy a package with new converter", e);
422             }
423          }
424       }
425    }
426
427    /**
428     * Removes a conveter from the list of converters. If the
429     * converter does not exist nothing happens.
430     * This method is normally called by a Converter to be removed
431     * from the list if not serving anymore.
432     *
433     * @param converter Conveter to be removed from the list
434     *
435     * @jmx.managed-operation
436     */

437    public void removeConvertor(Convertor converter)
438    {
439       converterList.remove(converter);
440    }
441
442    // Private --------------------------------------------------------
443
/**
444     * The <code>inflateJar</code> copies the jar entries
445     * from the jar url jarUrl to the directory destDir.
446     *
447     * @param fileURL URL pointing to the file to be inflated
448     * @param destinationDirectory Directory to which the content shall be inflated to
449     *
450     * @exception DeploymentException if an error occurs
451     * @exception IOException if an error occurs
452     */

453    protected void inflateJar( URL JavaDoc fileURL, File JavaDoc destinationDirectory )
454       throws DeploymentException, IOException JavaDoc
455    {
456       File JavaDoc destFile = new File JavaDoc(fileURL.getFile());
457       InputStream JavaDoc input = new FileInputStream JavaDoc(fileURL.getFile());
458       JarUtils.unjar(input, destinationDirectory);
459       // input is closed in unjar();
460
}
461
462    /**
463     * Deflate a given directory into a JAR file
464     *
465     * @param jarFile The JAR file to be created
466     * @param root Root directory of the files to be included (this directory
467     * will not be included in the path of the JAR content)
468     **/

469    private void deflateJar( File JavaDoc jarFile, File JavaDoc root )
470       throws Exception JavaDoc
471    {
472       OutputStream JavaDoc output = new FileOutputStream JavaDoc(jarFile);
473       JarUtils.jar(output, root.listFiles(), null, null, null);
474       output.close();
475    }
476
477    /**
478     * Copies the given File to a new destination with the same name
479     *
480     * @param source The source file to be copied
481     * @param destinationDirectory File pointing to the destination directory
482     **/

483    private void copyFile(File JavaDoc source, File JavaDoc destinationDirectory)
484       throws Exception JavaDoc
485    {
486       File JavaDoc target = new File JavaDoc( destinationDirectory, source.getName() );
487       // Move may fail if target is used (because it is deployed)
488
// Use Files.copy instead
489
Files.copy(source, target);
490    }
491 }
492
Popular Tags