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          //we have the deployer, continue deployment.
891
deployment.deployer.init(deployment);
892          // initialize the unified classloaders for this deployment
893
deployment.createClassLoaders();
894          deployment.state = DeploymentState.INITIALIZED;
895
896          // Add the deployment to the map so we can detect circular deployments
897
synchronized (deploymentList)
898          {
899             deploymentMap.put(deployment.url, deployment);
900          }
901
902          // create subdeployments as needed
903
parseManifestLibraries(deployment);
904
905          log.debug("found " + deployment.subDeployments.size() + " subpackages of " + deployment.url);
906          // get sorted subDeployments
907
ArrayList JavaDoc sortedSubs = new ArrayList JavaDoc(deployment.subDeployments);
908          Collections.sort(sortedSubs, infoSorter);
909          for (Iterator JavaDoc lt = sortedSubs.listIterator(); lt.hasNext();)
910          {
911             init((DeploymentInfo) lt.next());
912          }
913       }
914       catch (Exception JavaDoc e)
915       {
916          deployment.state = DeploymentState.FAILED;
917          DeploymentException.rethrowAsDeploymentException("exception in init of " + deployment.url, e);
918       }
919       finally
920       {
921          // whether you do it or not, for the autodeployer
922
try
923          {
924             URL JavaDoc url = deployment.localUrl == null ? deployment.url : deployment.localUrl;
925
926             long lastModified = -1;
927
928             if (url.getProtocol().equals("file"))
929                lastModified = new File JavaDoc(url.getFile()).lastModified();
930             else
931                lastModified = url.openConnection().getLastModified();
932
933             deployment.lastModified=lastModified;
934             deployment.lastDeployed=System.currentTimeMillis();
935          }
936          catch (IOException JavaDoc ignore)
937          {
938             deployment.lastModified=System.currentTimeMillis();
939             deployment.lastDeployed=System.currentTimeMillis();
940          }
941
942          synchronized (deploymentList)
943          {
944             // Do we watch it? Watch only urls outside our copy directory.
945
if (!inLocalCopyDir(deployment.url) && deploymentList.contains(deployment) == false)
946             {
947                deploymentList.add(deployment);
948                log.debug("Watching new file: " + deployment.url);
949             }
950          }
951       }
952       return true;
953    }
954
955    /**
956     * The <code>create</code> method is the second internal deployment step.
957     * It should set up all information not
958     * requiring other components. for instance, the ejb Container is created,
959     * and the proxy bound into jndi.
960     *
961     * @param deployment a <code>DeploymentInfo</code> value
962     * @throws DeploymentException if an error occurs
963     */

964    private void create(DeploymentInfo deployment) throws DeploymentException
965    {
966       log.debug("create step for deployment " + deployment.url);
967       try
968       {
969          ArrayList JavaDoc sortedSubs = new ArrayList JavaDoc(deployment.subDeployments);
970          Collections.sort(sortedSubs, infoSorter);
971          for (Iterator JavaDoc lt = sortedSubs.listIterator(); lt.hasNext();)
972          {
973             create((DeploymentInfo) lt.next());
974          }
975          deployment.state = DeploymentState.CREATE_SUBDEPLOYMENTS;
976
977          // Deploy this SDI, if it is a deployable type
978
if (deployment.deployer != null)
979          {
980             try
981             {
982                deployment.state = DeploymentState.CREATE_DEPLOYER;
983                deployment.deployer.create(deployment);
984                // See if all mbeans are created...
985
deployment.state = DeploymentState.CREATED;
986                deployment.status="Created";
987                log.debug("Done with create step of deploying " + deployment.shortName);
988             }
989             catch (Throwable JavaDoc t)
990             {
991                log.error("Could not create deployment: " + deployment.url, t);
992                throw t;
993             }
994          }
995          else
996          {
997             log.debug("Still no deployer for package in create step: " + deployment.shortName);
998          } // end of else
999
}
1000      catch (Throwable JavaDoc t)
1001      {
1002         log.trace("could not create deployment: " + deployment.url, t);
1003         deployment.status = "Deployment FAILED reason: " + t.getMessage();
1004         deployment.state = DeploymentState.FAILED;
1005         DeploymentException.rethrowAsDeploymentException("Could not create deployment: " + deployment.url, t);
1006      }
1007   }
1008
1009   /**
1010    * The <code>start</code> method is the third and final internal deployment step.
1011    * The purpose is to set up relationships between components.
1012    * for instance, ejb links are set up here.
1013    *
1014    * @param deployment a <code>DeploymentInfo</code> value
1015    * @throws DeploymentException if an error occurs
1016    */

1017   private void start(DeploymentInfo deployment) throws DeploymentException
1018   {
1019      deployment.status = "Starting";
1020      log.debug("Begin deployment start " + deployment.url);
1021      try
1022      {
1023         ArrayList JavaDoc sortedSubs = new ArrayList JavaDoc(deployment.subDeployments);
1024         Collections.sort(sortedSubs, infoSorter);
1025         for (Iterator JavaDoc lt = sortedSubs.listIterator(); lt.hasNext();)
1026         {
1027            start((DeploymentInfo) lt.next());
1028         }
1029         deployment.state = DeploymentState.START_SUBDEPLOYMENTS;
1030
1031         // Deploy this SDI, if it is a deployable type
1032
if (deployment.deployer != null)
1033         {
1034            try
1035            {
1036               deployment.state = DeploymentState.START_DEPLOYER;
1037               deployment.deployer.start(deployment);
1038               // See if all mbeans are started...
1039
Object JavaDoc[] args = {deployment, DeploymentState.STARTED};
1040               String JavaDoc[] sig = {"org.jboss.deployment.DeploymentInfo",
1041                  "org.jboss.deployment.DeploymentState"};
1042               server.invoke(serviceController, "validateDeploymentState",args, sig);
1043               deployment.status = "Deployed";
1044               log.debug("End deployment start on package: "+ deployment.shortName);
1045            }
1046            catch (Throwable JavaDoc t)
1047            {
1048               log.error("Could not start deployment: " + deployment.url, t);
1049               throw t;
1050            }
1051         }
1052         else
1053         {
1054            log.debug("Still no deployer for package in start step: " + deployment.shortName);
1055         } // end of else
1056
}
1057      catch (Throwable JavaDoc t)
1058      {
1059         log.trace("could not start deployment: " + deployment.url, t);
1060         deployment.state = DeploymentState.FAILED;
1061         deployment.status = "Deployment FAILED reason: " + t.getMessage();
1062         DeploymentException.rethrowAsDeploymentException("Could not create deployment: " + deployment.url, t);
1063      }
1064   }
1065
1066   /**
1067    * The <code>findDeployer</code> method attempts to find a deployer for the DeploymentInfo
1068    * supplied as a parameter.
1069    *
1070    * @param sdi a <code>DeploymentInfo</code> value
1071    */

1072   private void findDeployer(DeploymentInfo sdi)
1073   {
1074      // If there is already a deployer use it
1075
if( sdi.deployer != null )
1076      {
1077         log.debug("using existing deployer "+sdi.deployer);
1078         return;
1079      }
1080
1081      //
1082
// To deploy directories of beans one should just name the directory
1083
// mybean.ear/bla...bla, so that the directory gets picked up by the right deployer
1084
//
1085
synchronized(deployers)
1086      {
1087         for (Iterator JavaDoc iterator = deployers.iterator(); iterator.hasNext(); )
1088         {
1089            SubDeployer deployer = (SubDeployer) iterator.next();
1090            if (deployer.accepts(sdi))
1091            {
1092               sdi.deployer = deployer;
1093               log.debug("using deployer "+deployer);
1094               return;
1095            }
1096         }
1097      }
1098      log.debug("No deployer found for url: " + sdi.url);
1099   }
1100
1101   /**
1102    * The <code>parseManifestLibraries</code> method looks into the manifest for classpath
1103    * goo, and tries to deploy referenced packages.
1104    *
1105    * @param sdi a <code>DeploymentInfo</code> value
1106    */

1107   private void parseManifestLibraries(DeploymentInfo sdi)
1108   {
1109      String JavaDoc classPath = null;
1110
1111      Manifest JavaDoc mf = sdi.getManifest();
1112
1113      if( mf != null )
1114      {
1115         Attributes JavaDoc mainAttributes = mf.getMainAttributes();
1116         classPath = mainAttributes.getValue(Attributes.Name.CLASS_PATH);
1117      }
1118
1119      if (classPath != null)
1120      {
1121         StringTokenizer JavaDoc st = new StringTokenizer JavaDoc(classPath);
1122         log.debug("resolveLibraries: "+classPath);
1123
1124         while (st.hasMoreTokens())
1125         {
1126            URL JavaDoc lib = null;
1127            String JavaDoc tk = st.nextToken();
1128            log.debug("new manifest entry for sdi at "+sdi.shortName+" entry is "+tk);
1129
1130            try
1131            {
1132               if (sdi.isDirectory)
1133               {
1134                  File JavaDoc parentDir = new File JavaDoc(sdi.url.getPath()).getParentFile();
1135                  lib = new File JavaDoc(parentDir, tk).toURL();
1136               }
1137               else
1138               {
1139                  lib = new URL JavaDoc(sdi.url, tk);
1140               }
1141
1142               // Only deploy this if it is not already being deployed
1143
if ( deploymentMap.containsKey(lib) == false )
1144               {
1145                  /* Test that the only deployer for this is the JARDeployer.
1146                   Any other type of deployment cannot be initiated through
1147                   a manifest reference.
1148                  */

1149                  DeploymentInfo mfRef = new DeploymentInfo(lib, null, getServer());
1150                  makeLocalCopy(mfRef);
1151                  URL JavaDoc[] localURL = {mfRef.localUrl};
1152                  mfRef.localCl = new java.net.URLClassLoader JavaDoc(localURL);
1153                  findDeployer(mfRef);
1154                  SubDeployer deployer = mfRef.deployer;
1155                  if(deployer != null && (deployer instanceof JARDeployer) == false)
1156                  {
1157                     // Its a non-jar deployment that must be deployed seperately
1158
log.warn("Found non-jar deployer for " + tk + ": " + deployer);
1159                  }
1160
1161                  // add the library
1162
sdi.addLibraryJar(lib);
1163               }
1164            }
1165            catch (Exception JavaDoc ignore)
1166            {
1167               log.debug("The manifest entry in "+sdi.url+" references URL "+lib+
1168                  " which could not be opened, entry ignored", ignore);
1169            }
1170         }
1171      }
1172   }
1173
1174   /**
1175    * Downloads the jar file or directory the src URL points to.
1176    * In case of directory it becomes packed to a jar file.
1177    */

1178   private void makeLocalCopy(DeploymentInfo sdi)
1179   {
1180      try
1181      {
1182         if (sdi.url.getProtocol().equals("file") && (!copyFiles || sdi.isDirectory))
1183         {
1184            // If local copies have been disabled, do nothing
1185
sdi.localUrl = sdi.url;
1186            return;
1187         }
1188         // Are we already in the localCopyDir?
1189
else if (inLocalCopyDir(sdi.url))
1190         {
1191            sdi.localUrl = sdi.url;
1192            return;
1193         }
1194         else
1195         {
1196            String JavaDoc shortName = sdi.shortName;
1197            File JavaDoc localFile = File.createTempFile("tmp", shortName, tempDir);
1198            sdi.localUrl = localFile.toURL();
1199            copy(sdi.url, localFile);
1200         }
1201      }
1202      catch (Exception JavaDoc e)
1203      {
1204         log.error("Could not make local copy for " + sdi.url, e);
1205      }
1206   }
1207
1208   private boolean inLocalCopyDir(URL JavaDoc url)
1209   {
1210      int i = 0;
1211      String JavaDoc urlTest = url.toString();
1212      if( urlTest.startsWith("jar:") )
1213         i = 4;
1214
1215      return urlTest.startsWith(tempDirString, i);
1216   }
1217
1218   protected void copy(URL JavaDoc src, File JavaDoc dest) throws IOException JavaDoc
1219   {
1220      log.debug("Copying " + src + " -> " + dest);
1221      
1222      // Validate that the dest parent directory structure exists
1223
File JavaDoc dir = dest.getParentFile();
1224      if (!dir.exists())
1225      {
1226         boolean created = dir.mkdirs();
1227         if( created == false )
1228            throw new IOException JavaDoc("mkdirs failed for: "+dir.getAbsolutePath());
1229      }
1230
1231      // Remove any existing dest content
1232
if( dest.exists() == true )
1233      {
1234         boolean deleted = Files.delete(dest);
1235         if( deleted == false )
1236            throw new IOException JavaDoc("delete of previous content failed for: "+dest.getAbsolutePath());
1237      }
1238
1239      if (src.getProtocol().equals("file"))
1240      {
1241         File JavaDoc srcFile = new File JavaDoc(src.getFile());
1242         if (srcFile.isDirectory())
1243         {
1244            log.debug("Making zip copy of: " + srcFile);
1245            // make a jar archive of the directory
1246
OutputStream JavaDoc out = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(dest));
1247            JarUtils.jar(out, srcFile.listFiles());
1248            out.close();
1249            return;
1250         }
1251      }
1252
1253      InputStream JavaDoc in = new BufferedInputStream JavaDoc(src.openStream());
1254      OutputStream JavaDoc out = new BufferedOutputStream JavaDoc(new FileOutputStream JavaDoc(dest));
1255      Streams.copy(in, out);
1256      out.flush();
1257      out.close();
1258      in.close();
1259   }
1260
1261   /**
1262    * The <code>start</code> method starts a package identified by a URL
1263    *
1264    * @param urlspec an <code>URL</code> value
1265    * @jmx.managed-operation
1266    */

1267   public void start(String JavaDoc urlspec)
1268      throws DeploymentException, MalformedURLException JavaDoc
1269   {
1270      throw new DeploymentException("Not supported");
1271   }
1272
1273   /**
1274    * The <code>stop</code> method stops a package identified by a URL
1275    *
1276    * @param urlspec an <code>URL</code> value
1277    * @jmx.managed-operation
1278    */

1279   public void stop(String JavaDoc urlspec)
1280      throws DeploymentException, MalformedURLException JavaDoc
1281   {
1282      throw new DeploymentException("Not supported");
1283   }
1284
1285   /**
1286    * The <code>isDeployed</code> method tells you if a package identified by a string
1287    * representation of a URL is currently deployed.
1288    *
1289    * @param url a <code>String</code> value
1290    * @return a <code>boolean</code> value
1291    * @exception MalformedURLException if an error occurs
1292    * @jmx.managed-operation
1293    */

1294   public boolean isDeployed(String JavaDoc url)
1295      throws MalformedURLException JavaDoc
1296   {
1297      return isDeployed(new URL JavaDoc(url));
1298   }
1299
1300   /**
1301    * The <code>isDeployed</code> method tells you if a packaged identified by
1302    * a URL is deployed.
1303    * @param url an <code>URL</code> value
1304    * @return a <code>boolean</code> value
1305    * @jmx.managed-operation
1306    */

1307   public boolean isDeployed(URL JavaDoc url)
1308   {
1309      DeploymentContext di = delegate.getDeploymentContext(url.toString());
1310      if (di == null)
1311      {
1312         return false;
1313      } // end of if ()
1314
return di.getState() == org.jboss.deployers.spi.structure.DeploymentState.DEPLOYED;
1315   }
1316
1317   /**
1318    * The <code>getDeployment</code> method returns the DeploymentInfo
1319    * object for the URL supplied.
1320    *
1321    * @param url an <code>URL</code> value
1322    * @return a <code>DeploymentInfo</code> value
1323    * @jmx.managed-operation
1324    */

1325   public DeploymentContext getDeployment(URL JavaDoc url)
1326   {
1327      String JavaDoc name = contextMap.get(url);
1328      DeploymentContext dc = delegate.getDeploymentContext(name);
1329      log.info("getDeploymen, url="+url+", dc="+dc);
1330      return dc;
1331   }
1332
1333   /**
1334    * The <code>getWatchUrl</code> method returns the URL that, when modified,
1335    * indicates that a redeploy is needed.
1336    *
1337    * @param url an <code>URL</code> value
1338    * @return a <code>URL</code> value
1339    * @jmx.managed-operation
1340    */

1341   public URL JavaDoc getWatchUrl(URL JavaDoc url)
1342   {
1343      return url;
1344   }
1345
1346   /** Check the current deployment states and generate a IncompleteDeploymentException
1347    * if there are mbeans waiting for depedencies.
1348    * @exception IncompleteDeploymentException
1349    * @jmx.managed-operation
1350    */

1351   public void checkIncompleteDeployments() throws DeploymentException
1352   {
1353      try
1354      {
1355         Collection JavaDoc waitingForClasses = new HashSet JavaDoc();
1356         Collection JavaDoc waitingForDepends = (Collection JavaDoc)server.invoke(serviceController,
1357                                                      "listIncompletelyDeployed",
1358                                                      new Object JavaDoc[] {},
1359                                                      new String JavaDoc[] {});
1360         Collection JavaDoc allServices = (Collection JavaDoc) server.invoke(serviceController,
1361               "listDeployed",
1362               new Object JavaDoc[] {},
1363               new String JavaDoc[] {});
1364         
1365         // Weed services that are waiting for other deployments
1366
Collection JavaDoc rootCause = new HashSet JavaDoc(waitingForDepends);
1367         Collection JavaDoc missing = new HashSet JavaDoc();
1368         for (Iterator JavaDoc i = rootCause.iterator(); i.hasNext();)
1369         {
1370            ServiceContext ctx = (ServiceContext) i.next();
1371            for (Iterator JavaDoc j = ctx.iDependOn.iterator(); j.hasNext(); )
1372            {
1373               ServiceContext dependee = (ServiceContext) j.next();
1374               if (dependee.state != ServiceContext.RUNNING)
1375               {
1376                  // Add missing mbean
1377
if (allServices.contains(dependee) == false)
1378                     missing.add(dependee);
1379                  // We are not a root cause
1380
i.remove();
1381                  break;
1382               }
1383            }
1384         }
1385         // Add missing mbeans to the root cause
1386
rootCause.addAll(missing);
1387
1388         IncompleteDeploymentException ide = new IncompleteDeploymentException(
1389            waitingForClasses,
1390            waitingForDepends,
1391            rootCause,
1392            listIncompletelyDeployed(),
1393            listWaitingForDeployer());
1394         if (!ide.isEmpty())
1395         {
1396            throw ide;
1397         } // end of if ()
1398
}
1399      catch (JMException JavaDoc jme)
1400      {
1401         throw new DeploymentException(JMXExceptionDecoder.decode(jme));
1402      } // end of try-catch
1403
}
1404
1405   /**
1406    * @param parent
1407    * @param map
1408    */

1409   private void fillParentAndChildrenSDI(DeploymentInfo parent, Map JavaDoc map)
1410   {
1411      Set JavaDoc subDeployments = parent.subDeployments;
1412      Iterator JavaDoc it = subDeployments.iterator();
1413      while (it.hasNext())
1414      {
1415         DeploymentInfo child = (DeploymentInfo) it.next();
1416         SerializableDeploymentInfo sdichild = returnSDI(child, map);
1417         sdichild.parent = returnSDI(parent, map);
1418         sdichild.parent.subDeployments.add(sdichild);
1419         fillParentAndChildrenSDI(child, map);
1420      }
1421   }
1422
1423   private SerializableDeploymentInfo returnSDI(DeploymentInfo di, Map JavaDoc map)
1424   {
1425       SerializableDeploymentInfo sdi = (SerializableDeploymentInfo) map.get(di.url);
1426       if( sdi == null )
1427       {
1428           sdi = new SerializableDeploymentInfo(di);
1429           map.put(di.url, sdi);
1430        }
1431       return sdi;
1432   }
1433
1434}
1435
Popular Tags