KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > deployment > MainDeployer


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.deployment;
23
24 import java.io.BufferedInputStream JavaDoc;
25 import java.io.BufferedOutputStream JavaDoc;
26 import java.io.File JavaDoc;
27 import java.io.FileOutputStream JavaDoc;
28 import java.io.IOException JavaDoc;
29 import java.io.InputStream JavaDoc;
30 import java.io.OutputStream JavaDoc;
31 import java.net.MalformedURLException JavaDoc;
32 import java.net.URL JavaDoc;
33 import java.net.URLClassLoader JavaDoc;
34 import java.util.ArrayList JavaDoc;
35 import java.util.Collection JavaDoc;
36 import java.util.Collections JavaDoc;
37 import java.util.Comparator JavaDoc;
38 import java.util.HashMap JavaDoc;
39 import java.util.HashSet JavaDoc;
40 import java.util.Iterator JavaDoc;
41 import java.util.LinkedList JavaDoc;
42 import java.util.List JavaDoc;
43 import java.util.ListIterator JavaDoc;
44 import java.util.Map JavaDoc;
45 import java.util.Set JavaDoc;
46 import java.util.StringTokenizer JavaDoc;
47 import java.util.jar.Attributes JavaDoc;
48 import java.util.jar.Manifest JavaDoc;
49
50 import javax.management.JMException JavaDoc;
51 import javax.management.MBeanServer JavaDoc;
52 import javax.management.MalformedObjectNameException JavaDoc;
53 import javax.management.Notification JavaDoc;
54 import javax.management.ObjectName JavaDoc;
55
56 import org.jboss.deployers.plugins.structure.AbstractDeploymentContext;
57 import org.jboss.deployers.spi.structure.DeploymentContext;
58 import org.jboss.mx.util.JMXExceptionDecoder;
59 import org.jboss.system.ServiceContext;
60 import org.jboss.system.ServiceMBeanSupport;
61 import org.jboss.system.server.ServerConfig;
62 import org.jboss.system.server.ServerConfigLocator;
63 import org.jboss.util.file.Files;
64 import org.jboss.util.file.JarUtils;
65 import org.jboss.util.stream.Streams;
66 import org.jboss.virtual.VFS;
67 import org.jboss.virtual.VirtualFile;
68
69 /**
70  * The legacy component for deployer management. This now simply delegates to the
71  * Main
72  *
73  * @deprecated see org.jboss.deployers.spi.deployment.MainDeployer
74  *
75  * @author <a HREF="mailto:marc.fleury@jboss.org">Marc Fleury</a>
76  * @author <a HREF="mailto:scott.stark@jboss.org">Scott Stark</a>
77  * @author <a HREF="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
78  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>
79  * @version $Revision: 58278 $
80  */

81 public class MainDeployer extends ServiceMBeanSupport
82    implements Deployer, MainDeployerMBean
83 {
84    private org.jboss.deployers.spi.deployment.MainDeployer delegate;
85    private Map JavaDoc<URL JavaDoc, String JavaDoc> contextMap = Collections.synchronizedMap(new HashMap JavaDoc<URL JavaDoc, String JavaDoc>());
86
87    /**
88     * The variable <code>serviceController</code> is used by the
89     * checkIncompleteDeployments method to ask for lists of mbeans
90     * with deployment problems.
91     */

92    private ObjectName JavaDoc serviceController;
93
94    /** Deployers **/
95    private final LinkedList JavaDoc deployers = new LinkedList JavaDoc();
96
97    /** A Map of URL -> DeploymentInfo */
98    private final Map JavaDoc deploymentMap = Collections.synchronizedMap(new HashMap JavaDoc());
99
100    /** A list of all deployments that have deployers. */
101    private final List JavaDoc deploymentList = new ArrayList JavaDoc();
102
103    /** A list of all deployments that do not have deployers. */
104    private final List JavaDoc waitingDeployments = new ArrayList JavaDoc();
105
106    /** A helper for sorting deployment URLs. */
107    private final DeploymentSorter sorter = new DeploymentSorter();
108
109    /** A helper for sorting deploymentInfos */
110    private final Comparator JavaDoc infoSorter = new DeploymentInfoComparator(sorter);
111
112    /** Helper class handling the SuffixOrder and EnhancedSuffixOrder attributes */
113    private final SuffixOrderHelper suffixOrderHelper = new SuffixOrderHelper(sorter);
114    
115    /** Should local copies be made of resources on the local file system */
116    private boolean copyFiles = true;
117
118    /** The temporary directory for deployments. */
119    private File JavaDoc tempDir;
120
121    /** The string naming the tempDir **/
122    private String JavaDoc tempDirString;
123
124    /**
125     * Explict no-args contsructor for JMX.
126     */

127    public MainDeployer()
128    {
129       // Is there a better place to obtain startup information?
130
String JavaDoc localCopy = System.getProperty("jboss.deploy.localcopy");
131       if (localCopy != null && (
132           localCopy.equalsIgnoreCase("false") ||
133           localCopy.equalsIgnoreCase("no") ||
134           localCopy.equalsIgnoreCase("off")))
135       {
136          log.debug("Disabling local copies of file: urls");
137          copyFiles = false;
138       }
139    }
140
141    public org.jboss.deployers.spi.deployment.MainDeployer getKernelMainDeployer()
142    {
143       return delegate;
144    }
145    public void setKernelMainDeployer(org.jboss.deployers.spi.deployment.MainDeployer delegate)
146    {
147       this.delegate = delegate;
148    }
149    
150    /** Get the flag indicating whether directory content will be deployed
151     *
152     * @return the file copy flag
153     * @jmx.managed-attribute
154     */

155    public boolean getCopyFiles()
156    {
157       return copyFiles;
158    }
159    /** Set the flag indicating whether directory content will be deployed. The
160     * default value is taken from the jboss.deploy.localcopy system
161     * property.
162     *
163     * @param copyFiles the local copy flag value
164     * @jmx.managed-attribute
165     */

166    public void setCopyFiles(boolean copyFiles)
167    {
168       this.copyFiles = copyFiles;
169    }
170
171    /** Get the temp directory
172     *
173     * @return the path to the local tmp directory
174     * @jmx.managed-attribute
175     */

176    public File JavaDoc getTempDir()
177    {
178       return tempDir;
179    }
180    /** Set the temp directory
181     *
182     * @param tempDir the path to the local tmp directory
183     * @jmx.managed-attribute
184     */

185    public void setTempDir(File JavaDoc tempDir)
186    {
187       this.tempDir = tempDir;
188    }
189
190    /** Get the temp directory
191     *
192     * @return the path to the local tmp directory
193     * @jmx.managed-attribute
194     */

195    public String JavaDoc getTempDirString()
196    {
197       return tempDirString;
198    }
199
200    /** Get the ordering of the deployment suffixes
201     *
202     * @return the ordering of the deployment suffixes
203     * @jmx.managed-attribute
204     */

205    public String JavaDoc[] getSuffixOrder()
206    {
207       return suffixOrderHelper.getSuffixOrder();
208    }
209    
210    /** Get the enhanced suffix order
211     *
212     * @return the enhanced suffix order
213     * @jmx.managed-attribute
214     */

215    public String JavaDoc[] getEnhancedSuffixOrder()
216    {
217       return suffixOrderHelper.getEnhancedSuffixes();
218    }
219    
220    /** Set the enhanced suffix order
221     *
222     * @param enhancedSuffixOrder the enhanced suffix order
223     * @jmx.managed-attribute
224     */

225    public void setEnhancedSuffixOrder(String JavaDoc[] enhancedSuffixOrder)
226    {
227       suffixOrderHelper.setEnhancedSuffixes(enhancedSuffixOrder);
228    }
229   
230    /**
231     * Describe <code>setServiceController</code> method here.
232     *
233     * @param serviceController an <code>ObjectName</code> value
234     * @jmx.managed-attribute
235     */

236    public void setServiceController(final ObjectName JavaDoc serviceController)
237    {
238       this.serviceController = serviceController;
239    }
240
241    /**
242     * The <code>listDeployed</code> method returns a collection of DeploymemtInfo
243     * objects for the currently deployed packages.
244     *
245     * @return a <code>Collection</code> value
246     * @jmx.managed-operation
247     */

248    public Collection JavaDoc listDeployed()
249    {
250       synchronized (deploymentList)
251       {
252          log.debug("deployment list string: " + deploymentList);
253          return new ArrayList JavaDoc(deploymentList);
254       }
255    }
256
257    /**
258     * The <code>listDeployedModules</code> method returns a collection of
259     * SerializableDeploymentInfo objects for the currently deployed packages.
260     *
261     * @return a <code>Collection</code> value
262     * @jmx.managed-operation
263     */

264    public Collection JavaDoc listDeployedModules()
265    {
266       log.debug("listDeployedModules");
267
268       HashMap JavaDoc map = new HashMap JavaDoc();
269       synchronized (deploymentList)
270       {
271          Collection JavaDoc col = new ArrayList JavaDoc(deploymentList);
272
273          // create a map entry for each deployment
274
for (Iterator JavaDoc it = col.iterator(); it.hasNext();)
275          {
276             DeploymentInfo info = (DeploymentInfo) it.next();
277             map.put(info.url, new SerializableDeploymentInfo(info));
278             // assign parent and sub deployments
279
fillParentAndChildrenSDI(info, map);
280          }
281       }
282
283       // map.values is not serializable, so we copy
284
return new ArrayList JavaDoc(map.values());
285    }
286
287    /**
288     * Describe <code>listDeployedAsString</code> method here.
289     *
290     * @return a <code>String</code> value
291     * @jmx.managed-operation
292     */

293    public String JavaDoc listDeployedAsString()
294    {
295       return "<pre>" + listDeployed() + "</pre>";
296    }
297
298    /**
299     * The <code>listIncompletelyDeployed</code> method returns a list of packages that have
300     * not deployed completely. The toString method will include any exception in the status
301     * field.
302     *
303     * @return a <code>Collection</code> value
304     * @jmx.managed-operation
305     */

306    public Collection JavaDoc listIncompletelyDeployed()
307    {
308       List JavaDoc id = new ArrayList JavaDoc();
309       List JavaDoc copy;
310       synchronized (deploymentList)
311       {
312          copy = new ArrayList JavaDoc(deploymentList);
313       }
314       for (Iterator JavaDoc i = copy.iterator(); i.hasNext();)
315       {
316          DeploymentInfo di = (DeploymentInfo)i.next();
317          if (!"Deployed".equals(di.status) && !"Starting".equals(di.status))
318          {
319             id.add(di);
320          } // end of if ()
321

322       } // end of for ()
323
return id;
324    }
325
326    /**
327     * The <code>listWaitingForDeployer</code> method returns a collection
328     * of the packages that currently have no identified deployer.
329     *
330     * @return a <code>Collection</code> value
331     * @jmx.managed-operation
332     */

333    public Collection JavaDoc listWaitingForDeployer()
334    {
335       synchronized (waitingDeployments)
336       {
337          return new ArrayList JavaDoc(waitingDeployments);
338       }
339    }
340
341    /**
342     * The <code>addDeployer</code> method registers a deployer with the main deployer.
343     * Any waiting packages are tested to see if the new deployer will deploy them.
344     *
345     * @param deployer a <code>SubDeployer</code> value
346     * @jmx.managed-operation
347     */

348    public void addDeployer(final SubDeployer deployer)
349    {
350       log.debug("Adding deployer: " + deployer);
351       ObjectName JavaDoc deployerName = deployer.getServiceName();
352       
353       synchronized(deployers)
354       {
355          deployers.addFirst(deployer);
356          try
357          {
358             String JavaDoc[] suffixes = (String JavaDoc[]) server.getAttribute(deployerName, "EnhancedSuffixes");
359             suffixOrderHelper.addEnhancedSuffixes(suffixes);
360          }
361          catch(Exception JavaDoc e)
362          {
363             log.debug(deployerName + " does not support EnhancedSuffixes");
364             suffixOrderHelper.addSuffixes(deployer.getSuffixes(), deployer.getRelativeOrder());
365          }
366       }
367       
368       // Send a notification about the deployer addition
369
Notification JavaDoc msg = new Notification JavaDoc(ADD_DEPLOYER, this, getNextNotificationSequenceNumber());
370       msg.setUserData(deployerName);
371       sendNotification(msg);
372
373       synchronized (waitingDeployments)
374       {
375          List JavaDoc copy = new ArrayList JavaDoc(waitingDeployments);
376          waitingDeployments.clear();
377          for (Iterator JavaDoc i = copy.iterator(); i.hasNext();)
378          {
379             DeploymentInfo di = (DeploymentInfo)i.next();
380             log.debug("trying to deploy with new deployer: " + di.shortName);
381             try
382             {
383                di.setServer(server);
384                deploy(di);
385             }
386             catch (DeploymentException e)
387             {
388                log.error("DeploymentException while trying to deploy a package with a new deployer", e);
389             } // end of try-catch
390
} // end of for ()
391
}
392    }
393    
394    /**
395     * The <code>removeDeployer</code> method unregisters a deployer with the MainDeployer.
396     * Deployed packages deployed with this deployer are undeployed.
397     *
398     * @param deployer a <code>SubDeployer</code> value
399     * @jmx.managed-operation
400     */

401    public void removeDeployer(final SubDeployer deployer)
402    {
403       log.debug("Removing deployer: " + deployer);
404       ObjectName JavaDoc deployerName = deployer.getServiceName();
405       boolean removed = false;
406       
407       synchronized(deployers)
408       {
409          removed = deployers.remove(deployer);
410          try
411          {
412             String JavaDoc[] suffixes = (String JavaDoc[]) server.getAttribute(deployerName, "EnhancedSuffixes");
413             suffixOrderHelper.removeEnhancedSuffixes(suffixes);
414          }
415          catch(Exception JavaDoc e)
416          {
417             log.debug(deployerName + " does not support EnhancedSuffixes");
418             suffixOrderHelper.removeSuffixes(deployer.getSuffixes(), deployer.getRelativeOrder());
419          }
420       }
421       
422       // Send a notification about the deployer removal
423
if (removed)
424       {
425          Notification JavaDoc msg = new Notification JavaDoc(REMOVE_DEPLOYER, this, getNextNotificationSequenceNumber());
426          msg.setUserData(deployerName);
427          sendNotification(msg);
428       }
429
430       List JavaDoc copy;
431       synchronized (deploymentList)
432       {
433          copy = new ArrayList JavaDoc(deploymentList);
434       }
435       for (Iterator JavaDoc i = copy.iterator(); i.hasNext(); )
436       {
437          DeploymentInfo di = (DeploymentInfo)i.next();
438          if (di.deployer == deployer)
439          {
440             undeploy(di);
441             di.deployer = null;
442             synchronized (waitingDeployments)
443             {
444                waitingDeployments.add(di);
445             }
446          }
447       }
448    }
449
450    /**
451     * The <code>listDeployers</code> method returns a collection of ObjectNames of
452     * deployers registered with the MainDeployer.
453     *
454     * @return a <code>Collection<ObjectName></code> value
455     * @jmx.managed-operation
456     */

457    public Collection JavaDoc listDeployers()
458    {
459       ArrayList JavaDoc deployerNames = new ArrayList JavaDoc();
460       synchronized(deployers)
461       {
462          for(int n = 0; n < deployers.size(); n ++)
463          {
464             SubDeployer deployer = (SubDeployer) deployers.get(n);
465             ObjectName JavaDoc name = deployer.getServiceName();
466             deployerNames.add(name);
467          }
468       }
469       return deployerNames;
470    }
471
472    // ServiceMBeanSupport overrides ---------------------------------
473

474    protected ObjectName JavaDoc getObjectName(MBeanServer JavaDoc server, ObjectName JavaDoc name)
475       throws MalformedObjectNameException JavaDoc
476    {
477       return name == null ? OBJECT_NAME : name;
478    }
479
480    /**
481     * The <code>createService</code> method is one of the ServiceMBean lifecyle operations.
482     * (no jmx tag needed from superinterface)
483     * @exception Exception if an error occurs
484     */

485    protected void createService() throws Exception JavaDoc
486    {
487       ServerConfig config = ServerConfigLocator.locate();
488       // Get the temp directory location
489
File JavaDoc basedir = config.getServerTempDir();
490       // Set the local copy temp dir to tmp/deploy
491
tempDir = new File JavaDoc(basedir, "deploy");
492       // Delete any existing content
493
Files.delete(tempDir);
494       // Make sure the directory exists
495
tempDir.mkdirs();
496
497       // used in inLocalCopyDir
498
tempDirString = tempDir.toURL().toString();
499       
500       // handles SuffixOrder & RelativeSuffixOrder attributes
501
suffixOrderHelper.initialize();
502    }
503
504    /**
505     * The <code>shutdown</code> method undeploys all deployed packages in
506     * reverse order of their deployement.
507     *
508     * @jmx.managed-operation
509     */

510    public void shutdown()
511    {
512       // if we shutdown in the middle of a scan, it still might be possible that we try to redeploy
513
// things we are busy killing...
514
int deployCounter = 0;
515
516       // undeploy everything in sight
517
List JavaDoc copy;
518       synchronized (deploymentList)
519       {
520          copy = new ArrayList JavaDoc(deploymentList);
521       }
522       for (ListIterator JavaDoc i = copy.listIterator(copy.size()); i.hasPrevious(); )
523       {
524          try
525          {
526             undeploy((DeploymentInfo)i.previous(), true);
527             deployCounter++;
528          }
529          catch (Exception JavaDoc e)
530          {
531             log.info("exception trying to undeploy during shutdown", e);
532          }
533
534       }
535       // Help GC
536
this.deployers.clear();
537       this.deploymentMap.clear();
538       this.deploymentList.clear();
539       this.waitingDeployments.clear();
540       this.tempDir = null;
541       
542       log.debug("Undeployed " + deployCounter + " deployed packages");
543    }
544
545
546    /**
547     * Describe <code>redeploy</code> method here.
548     *
549     * @param urlspec a <code>String</code> value
550     * @exception DeploymentException if an error occurs
551     * @exception MalformedURLException if an error occurs
552     * @jmx.managed-operation
553     */

554    public void redeploy(String JavaDoc urlspec)
555       throws DeploymentException, MalformedURLException JavaDoc
556    {
557       redeploy(new URL JavaDoc(urlspec));
558    }
559
560    /**
561     * Describe <code>redeploy</code> method here.
562     *
563     * @param url an <code>URL</code> value
564     * @exception DeploymentException if an error occurs
565     * @jmx.managed-operation
566     */

567    public void redeploy(URL JavaDoc url) throws DeploymentException
568    {
569       undeploy(url);
570       deploy(url);
571    }
572
573    /**
574     * Describe <code>redeploy</code> method here.
575     *
576     * @param sdi a <code>DeploymentInfo</code> value
577     * @exception DeploymentException if an error occurs
578     * @jmx.managed-operation
579     */

580    public void redeploy(DeploymentInfo sdi) throws DeploymentException
581    {
582       try
583       {
584          undeploy(sdi);
585       }
586       catch (Throwable JavaDoc t)
587       {
588          log.info("Throwable from undeployment attempt: ", t);
589       } // end of try-catch
590
sdi.setServer(server);
591       deploy(sdi);
592    }
593
594    /**
595     * The <code>undeploy</code> method undeploys a package identified by a string
596     * representation of a URL.
597     *
598     * @param urlspec the stringfied url to undeploy
599     * @jmx.managed-operation
600     */

601    public void undeploy(String JavaDoc urlspec)
602       throws DeploymentException, MalformedURLException JavaDoc
603    {
604       undeploy(new URL JavaDoc(urlspec));
605    }
606    
607    /**
608     * The <code>undeploy</code> method undeploys a package identified by a URL
609     *
610     * @param url the url to undeploy
611     * @jmx.managed-operation
612     */

613    public void undeploy(URL JavaDoc url) throws DeploymentException
614    {
615       String JavaDoc deploymentName = contextMap.remove(url);
616       if (deploymentName != null)
617       {
618          try
619          {
620             delegate.removeDeploymentContext(deploymentName);
621             delegate.process();
622          }
623          catch(Exception JavaDoc e)
624          {
625             DeploymentException ex = new DeploymentException("Error during undeploy of: "+url, e);
626             throw ex;
627          }
628       }
629       else
630       {
631          log.warn("undeploy '" + url + "' : package not deployed");
632       }
633    }
634
635    /**
636     * The <code>undeploy</code> method undeploys a package represented by a
637     * DeploymentInfo object.
638     *
639     * @param di a <code>DeploymentInfo</code> value
640     * @jmx.managed-operation
641     */

642    public void undeploy(DeploymentInfo di)
643    {
644       undeploy(di, false);
645    }
646    protected void undeploy(DeploymentInfo di, boolean isShutdown)
647    {
648       log.debug("Undeploying "+di.url);
649       stop(di);
650       destroy(di);
651    }
652
653    /**
654     * The <code>stop</code> method is the first internal step of undeployment
655     *
656     * @param di a <code>DeploymentInfo</code> value
657     */

658    private void stop(DeploymentInfo di)
659    {
660       // Stop all sub-deployments
661
ArrayList JavaDoc reverseSortedSubs = new ArrayList JavaDoc(di.subDeployments);
662       Collections.sort(reverseSortedSubs, infoSorter);
663       Collections.reverse(reverseSortedSubs);
664       for (Iterator JavaDoc subs = reverseSortedSubs.iterator(); subs.hasNext();)
665       {
666          DeploymentInfo sub = (DeploymentInfo) subs.next();
667          log.debug("Stopping sub deployment: "+sub.url);
668          stop(sub);
669       }
670       // Lastly stop this deployment itself
671
try
672       {
673          // Tell the respective deployer to undeploy this one
674
if (di.deployer != null)
675          {
676             di.deployer.stop(di);
677             di.status="Stopped";
678             di.state = DeploymentState.STOPPED;
679          }
680       }
681       catch (Throwable JavaDoc t)
682       {
683          log.error("Deployer stop failed for: " + di.url, t);
684       }
685
686    }
687
688    /**
689     * The <code>destroy</code> method is the second and final internal undeployment step.
690     *
691     * @param di a <code>DeploymentInfo</code> value
692     */

693    private void destroy(DeploymentInfo di)
694    {
695       // Destroy all sub-deployments
696
ArrayList JavaDoc reverseSortedSubs = new ArrayList JavaDoc(di.subDeployments);
697       Collections.sort(reverseSortedSubs, infoSorter);
698       Collections.reverse(reverseSortedSubs);
699       for (Iterator JavaDoc subs = reverseSortedSubs.iterator(); subs.hasNext();)
700       {
701          DeploymentInfo sub = (DeploymentInfo) subs.next();
702          log.debug("Destroying sub deployment: "+sub.url);
703          destroy(sub);
704       }
705       // Lastly destroy the deployment itself
706
try
707       {
708          // Tell the respective deployer to undeploy this one
709
if (di.deployer != null)
710          {
711             di.deployer.destroy(di);
712             di.status="Destroyed";
713             di.state = DeploymentState.DESTROYED;
714          }
715       }
716       catch (Throwable JavaDoc t)
717       {
718          log.error("Deployer destroy failed for: " + di.url, t);
719          di.state = DeploymentState.FAILED;
720       }
721
722       try
723       {
724          // remove from local maps
725
synchronized (deploymentList)
726          {
727             deploymentMap.remove(di.url);
728             if (deploymentList.lastIndexOf(di) != -1)
729             {
730                deploymentList.remove(deploymentList.lastIndexOf(di));
731             }
732          }
733          synchronized (waitingDeployments)
734          {
735             waitingDeployments.remove(di);
736          }
737          // Nuke my stuff, this includes the class loader
738
di.cleanup();
739
740          log.debug("Undeployed "+di.url);
741       }
742       catch (Throwable JavaDoc t)
743       {
744          log.error("Undeployment cleanup failed: " + di.url, t);
745       }
746    }
747
748    /**
749     * The <code>deploy</code> method deploys a package identified by a
750     * string representation of a URL.
751     *
752     * @param urlspec a <code>String</code> value
753     * @exception MalformedURLException if an error occurs
754     * @jmx.managed-operation
755     */

756    public void deploy(String JavaDoc urlspec)
757       throws DeploymentException, MalformedURLException JavaDoc
758    {
759       if( server == null )
760          throw new DeploymentException("The MainDeployer has been unregistered");
761
762       URL JavaDoc url;
763       try
764       {
765          url = new URL JavaDoc(urlspec);
766       }
767       catch (MalformedURLException JavaDoc e)
768       {
769          File JavaDoc file = new File JavaDoc(urlspec);
770          url = file.toURL();
771       }
772
773       deploy(url);
774    }
775
776    /**
777     * The <code>deploy</code> method deploys a package identified by a URL
778     *
779     * @param url an <code>URL</code> value
780     * @jmx.managed-operation
781     */

782    public void deploy(URL JavaDoc url) throws DeploymentException
783    {
784       log.info("deploy, url="+url);
785       String JavaDoc deploymentName = contextMap.get(url);
786       // if it does not exist create a new deployment
787
if (deploymentName == null)
788       {
789          try
790          {
791             VirtualFile file = VFS.getRoot(url);
792             DeploymentContext deployment = new AbstractDeploymentContext(file);
793             delegate.addDeploymentContext(deployment);
794             deploymentName = deployment.getName();
795             delegate.process();
796             contextMap.put(url, deploymentName);
797          }
798          catch(Exception JavaDoc e)
799          {
800             log.warn("Failed to deploy: "+url, e);
801             DeploymentException ex = new DeploymentException("Failed to deploy: "+url, e);
802             throw ex;
803          }
804       }
805    }
806
807    /**
808     * The <code>deploy</code> method deploys a package represented by a DeploymentInfo object.
809     *
810     * @param deployment a <code>DeploymentInfo</code> value
811     * @exception DeploymentException if an error occurs
812     * @jmx.managed-operation
813     */

814    public void deploy(DeploymentInfo deployment)
815       throws DeploymentException
816    {
817       // If we are already deployed return
818
if (isDeployed(deployment.url))
819       {
820          log.info("Package: " + deployment.url + " is already deployed");
821          return;
822       }
823       log.debug("Starting deployment of package: " + deployment.url);
824
825       boolean inited = false;
826       try
827       {
828          inited = init(deployment);
829       }
830       catch (Throwable JavaDoc t)
831       {
832          log.error("Could not initialise deployment: " + deployment.url, t);
833          DeploymentException.rethrowAsDeploymentException("Could not initialise deployment: " + deployment.url, t);
834       }
835       if ( inited )
836       {
837          create(deployment);
838          start(deployment);
839          log.debug("Deployed package: " + deployment.url);
840       } // end of if ()
841
else
842       {
843          log.debug("Deployment of package: " + deployment.url + " is waiting for an appropriate deployer.");
844       } // end of else
845
}
846
847
848    /**
849     * The <code>init</code> method is the first internal deployment step.
850     * The tasks are to copy the code if necessary,
851     * set up classloaders, and identify the deployer for the package.
852     *
853     * @param deployment a <code>DeploymentInfo</code> value
854     * @throws DeploymentException if an error occurs
855     */

856    private boolean init(DeploymentInfo deployment) throws DeploymentException
857    {
858       // If we are already deployed return
859
if (isDeployed(deployment.url))
860       {
861          log.info("Package: " + deployment.url + " is already deployed");
862          return false;
863       }
864       log.debug("Starting deployment (init step) of package at: " + deployment.url);
865       try
866       {
867          // Create a local copy of that File, the sdi keeps track of the copy directory
868
if (deployment.localUrl == null)
869          {
870             makeLocalCopy(deployment);
871             URL JavaDoc[] localCl = new URL JavaDoc[]{deployment.localUrl};
872             deployment.localCl = new URLClassLoader JavaDoc(localCl);
873          }
874
875          // What deployer is able to deploy this file
876
findDeployer(deployment);
877
878          if(deployment.deployer == null)
879          {
880             deployment.state = DeploymentState.INIT_WAITING_DEPLOYER;
881             log.debug("deployment waiting for deployer: " + deployment.url);
882             synchronized (waitingDeployments)
883             {
884                if (waitingDeployments.contains(deployment) == false)
885                   waitingDeployments.add(deployment);
886             }
887             return false;
888          }
889          deployment.state = DeploymentState.INIT_DEPLOYER;
890