KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > server > deploy > ExpandDeployGenerator


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.server.deploy;
31
32 import com.caucho.config.ConfigException;
33 import com.caucho.config.types.FileSetType;
34 import com.caucho.config.types.Period;
35 import com.caucho.loader.Environment;
36 import com.caucho.log.Log;
37 import com.caucho.util.Alarm;
38 import com.caucho.util.AlarmListener;
39 import com.caucho.util.L10N;
40 import com.caucho.util.WeakAlarm;
41 import com.caucho.vfs.Path;
42
43 import java.io.IOException JavaDoc;
44 import java.util.ArrayList JavaDoc;
45 import java.util.Set JavaDoc;
46 import java.util.TreeSet JavaDoc;
47 import java.util.logging.Level JavaDoc;
48 import java.util.logging.Logger JavaDoc;
49
50 /**
51  * The generator for the deploy
52  */

53 abstract public class ExpandDeployGenerator<E extends ExpandDeployController>
54   extends DeployGenerator<E>
55   implements AlarmListener
56 {
57   private static final Logger JavaDoc log = Log.open(ExpandDeployGenerator.class);
58   private static final L10N L = new L10N(ExpandDeployGenerator.class);
59
60   private static final long MIN_CRON_INTERVAL = 5000L;
61
62   private Path _path; // default path
63

64   private Path _containerRootDirectory;
65   private Path _archiveDirectory;
66   private Path _expandDirectory;
67
68   private String JavaDoc _extension = ".jar";
69   
70   private String JavaDoc _expandPrefix = "";
71   private String JavaDoc _expandSuffix = "";
72   
73   private ArrayList JavaDoc<String JavaDoc> _requireFiles = new ArrayList JavaDoc<String JavaDoc>();
74
75   private TreeSet JavaDoc<String JavaDoc> _controllerNames = new TreeSet JavaDoc<String JavaDoc>();
76
77   private FileSetType _expandCleanupFileSet;
78
79   private Alarm _alarm;
80   private long _cronInterval;
81
82   private volatile long _lastCheckTime;
83   private volatile boolean _isChecking;
84   private long _checkInterval = 1000L;
85   private long _digest;
86   private volatile boolean _isModified;
87   private volatile boolean _isDeploying;
88
89   /**
90    * Creates the deploy.
91    */

92   public ExpandDeployGenerator(DeployContainer<E> container, Path containerRootDirectory)
93   {
94     super(container);
95
96     _containerRootDirectory = containerRootDirectory;
97
98     _alarm = new WeakAlarm(this);
99
100     _cronInterval = Environment.getDependencyCheckInterval();
101     if (_cronInterval < MIN_CRON_INTERVAL)
102       _cronInterval = MIN_CRON_INTERVAL;
103   }
104
105   Path getContainerRootDirectory()
106   {
107     return _containerRootDirectory;
108   }
109
110   /**
111    * Gets the default path.
112    */

113   public Path getPath()
114   {
115     return _path;
116   }
117
118   /**
119    * Sets the deploy directory.
120    */

121   public void setPath(Path path)
122   {
123     _path = path;
124   }
125
126   /**
127    * Sets the war expand dir to check for new applications.
128    */

129   public void setExpandPath(Path path)
130   {
131     log.config("Use <expand-directory> instead of <expand-path>. <expand-path> is deprecated.");
132
133     setExpandDirectory(path);
134   }
135
136   /**
137    * Sets the war expand dir to check for new applications.
138    */

139   public void setExpandDirectory(Path path)
140   {
141     _expandDirectory = path;
142   }
143
144   /**
145    * Gets the war expand directory.
146    */

147   public Path getExpandDirectory()
148   {
149     if (_expandDirectory != null)
150       return _expandDirectory;
151     else
152       return _path;
153   }
154
155   /**
156    * Returns the location of an expanded archive, or null if no archive with
157    * the passed name is deployed.
158    *
159    * @param name a name, without an extension
160    */

161   public Path getExpandPath(String JavaDoc name)
162   {
163     if (!isDeployedKey(nameToEntryName(name)))
164       return null;
165
166     return getExpandDirectory().lookup(getExpandName(name));
167   }
168
169   /**
170    * Returns the combination of prefix, name, and suffix used for expanded
171    * archives.
172    *
173    * @return
174    */

175   protected String JavaDoc getExpandName(String JavaDoc name)
176   {
177     return getExpandPrefix() + name + getExpandSuffix();
178   }
179
180   /**
181    * Sets the war expand dir to check for new archive files.
182    */

183   public void setArchiveDirectory(Path path)
184   {
185     _archiveDirectory = path;
186   }
187
188   /**
189    * Gets the war expand directory.
190    */

191   public Path getArchiveDirectory()
192   {
193     if (_archiveDirectory != null)
194       return _archiveDirectory;
195     else
196       return _path;
197   }
198
199   /**
200    * Returns the location for deploying an archive with the specified name.
201    *
202    * @param name a name, without an extension
203    */

204   public Path getArchivePath(String JavaDoc name)
205   {
206     return getArchiveDirectory().lookup(name + getExtension());
207   }
208
209   /**
210    * Sets the dependency check interval.
211    */

212   public void setDependencyCheckInterval(Period period)
213   {
214     _cronInterval = period.getPeriod();
215
216     if (_cronInterval < 0)
217       _cronInterval = Period.INFINITE;
218     else if (_cronInterval < MIN_CRON_INTERVAL)
219       _cronInterval = MIN_CRON_INTERVAL;
220   }
221
222   public long getDependencyCheckInterval()
223   {
224     return _cronInterval;
225   }
226
227   /**
228    * Sets the expand remove file set.
229    */

230   public void setExpandCleanupFileset(FileSetType fileSet)
231   {
232     _expandCleanupFileSet = fileSet;
233   }
234
235   /**
236    * Sets the extension.
237    */

238   public void setExtension(String JavaDoc extension)
239     throws ConfigException
240   {
241     if (! extension.startsWith("."))
242       throw new ConfigException(L.l("deployment extension '{0}' must begin with '.'",
243                     extension));
244
245     _extension = extension;
246   }
247
248   /**
249    * Returns the extension.
250    */

251   public String JavaDoc getExtension()
252   {
253     return _extension;
254   }
255
256   /**
257    * Sets the expand prefix to check for new applications.
258    */

259   public void setExpandPrefix(String JavaDoc prefix)
260     throws ConfigException
261   {
262     if (! prefix.equals("") &&
263     ! prefix.startsWith("_") &&
264     ! prefix.startsWith("."))
265       throw new ConfigException(L.l("expand-prefix '{0}' must start with '.' or '_'.",
266                     prefix));
267                    
268     _expandPrefix = prefix;
269   }
270
271   /**
272    * Gets the expand prefix.
273    */

274   public String JavaDoc getExpandPrefix()
275   {
276     return _expandPrefix;
277   }
278
279   /**
280    * Sets the expand suffix to check for new applications.
281    */

282   public void setExpandSuffix(String JavaDoc suffix)
283     throws ConfigException
284   {
285     _expandSuffix = suffix;
286   }
287
288   /**
289    * Gets the expand suffix.
290    */

291   public String JavaDoc getExpandSuffix()
292   {
293     return _expandSuffix;
294   }
295
296   /**
297    * Adds a required file in the expansion.
298    */

299   public void addRequireFile(String JavaDoc file)
300     throws ConfigException
301   {
302     _requireFiles.add(file);
303   }
304
305   /**
306    * Returns the log.
307    */

308   protected Logger JavaDoc getLog()
309   {
310     return log;
311   }
312
313   /**
314    * Returns true if the deployment has modified.
315    */

316   public boolean isModified()
317   {
318     synchronized (this) {
319       long now = Alarm.getCurrentTime();
320       
321       if (now < _lastCheckTime + _checkInterval || _isChecking) {
322     return _isModified;
323       }
324
325       _isChecking = true;
326       _lastCheckTime = Alarm.getCurrentTime();
327     }
328
329     try {
330       long digest = getDigest();
331
332       _isModified = _digest != digest;
333
334       return _isModified;
335     } catch (Exception JavaDoc e) {
336       log.log(Level.FINE, e.toString(), e);
337       
338       return false;
339     } finally {
340       _isChecking = false;
341     }
342   }
343
344   /**
345    * Configuration checks on init.
346    */

347   @Override JavaDoc
348   protected void initImpl()
349     throws ConfigException
350   {
351     super.initImpl();
352
353     if (getExpandDirectory() == null)
354       throw new ConfigException(L.l("<expand-directory> must be specified for deployment of archive expansion."));
355
356     if (getArchiveDirectory() == null)
357       throw new ConfigException(L.l("<archive-directory> must be specified for deployment of archive expansion."));
358   }
359
360   /**
361    * Starts the deploy.
362    */

363   @Override JavaDoc
364   protected void startImpl()
365   {
366     super.startImpl();
367
368     handleAlarm(_alarm);
369   }
370
371   /**
372    * Returns the deployed keys.
373    */

374   protected void fillDeployedKeys(Set JavaDoc<String JavaDoc> keys)
375   {
376     if (isModified()) {
377       try {
378     deploy();
379       } catch (Throwable JavaDoc e) {
380     log.log(Level.WARNING, e.toString(), e);
381       }
382     }
383
384     for (String JavaDoc name : _controllerNames) {
385       keys.add(name);
386     }
387   }
388
389   /**
390    * Return true for a matching key.
391    */

392   protected boolean isDeployedKey(String JavaDoc key)
393   {
394     return _controllerNames.contains(key);
395   }
396
397   /**
398    * Forces an update.
399    */

400   public void update()
401   {
402     // force modify check
403
_lastCheckTime = 0;
404
405     request();
406   }
407   
408
409   /**
410    * Redeploys if modified.
411    */

412   public void request()
413   {
414     if (isModified()) {
415       try {
416     deploy();
417       } catch (Throwable JavaDoc e) {
418     log.log(Level.WARNING, e.toString(), e);
419       }
420     }
421   }
422
423   /**
424    * Deploys the objects.
425    */

426   private void deploy()
427     throws Exception JavaDoc
428   {
429     boolean isDeploying = false;
430     
431     log.finer(this + " redeploy " + _isDeploying);
432
433     try {
434       ArrayList JavaDoc<String JavaDoc> updatedNames = null;
435
436       synchronized (this) {
437     if (_isDeploying)
438       return;
439     else {
440       _isDeploying = true;
441       isDeploying = true;
442     }
443       
444     TreeSet JavaDoc<String JavaDoc> entryNames = findEntryNames();
445
446     _digest = getDigest();
447
448     if (! _controllerNames.equals(entryNames)) {
449       updatedNames = new ArrayList JavaDoc<String JavaDoc>();
450       
451       for (String JavaDoc name : _controllerNames) {
452         if (! entryNames.contains(name))
453           updatedNames.add(name);
454       }
455
456       for (String JavaDoc name : entryNames) {
457         if (! _controllerNames.contains(name))
458           updatedNames.add(name);
459       }
460
461       _controllerNames = entryNames;
462     }
463       }
464
465       for (int i = 0; updatedNames != null && i < updatedNames.size(); i++) {
466     String JavaDoc name = updatedNames.get(i);
467
468     getDeployContainer().update(name);
469       }
470     } finally {
471       if (isDeploying) {
472     _isModified = false;
473     _isDeploying = false;
474       }
475     }
476   }
477
478   /**
479    * Finds the matching entry.
480    */

481   public E generateController(String JavaDoc name)
482   {
483     request();
484
485     Thread JavaDoc thread = Thread.currentThread();
486     ClassLoader JavaDoc oldLoader = thread.getContextClassLoader();
487     try {
488       thread.setContextClassLoader(getParentClassLoader());
489     
490       E controller = createController(name);
491
492       if (controller != null) {
493     controller.setExpandCleanupFileSet(_expandCleanupFileSet);
494
495     _controllerNames.add(name); // server/1d19
496
}
497
498       return controller;
499     } finally {
500       thread.setContextClassLoader(oldLoader);
501     }
502   }
503
504   /**
505    * Returns the digest of the expand and archive directories.
506    */

507   private long getDigest()
508   {
509     long archiveDigest = 0;
510     
511     Path archiveDirectory = getArchiveDirectory();
512     if (archiveDirectory != null)
513       archiveDigest = archiveDirectory.getCrc64();
514     
515     long expandDigest = 0;
516     
517     Path expandDirectory = getExpandDirectory();
518     if (expandDirectory != null)
519       expandDigest = expandDirectory.getCrc64();
520
521     return archiveDigest * 65521 + expandDigest;
522   }
523   
524   /**
525    * Return the entry names for all deployed objects.
526    */

527   private TreeSet JavaDoc<String JavaDoc> findEntryNames()
528     throws IOException JavaDoc
529   {
530     TreeSet JavaDoc<String JavaDoc> entryNames = new TreeSet JavaDoc<String JavaDoc>();
531
532     Path archiveDirectory = getArchiveDirectory();
533     Path expandDirectory = getExpandDirectory();
534
535     if (archiveDirectory == null || expandDirectory == null)
536       return entryNames;
537
538     String JavaDoc []entryList = archiveDirectory.list();
539
540     // collect all the new entrys
541
loop:
542     for (int i = 0; i < entryList.length; i++) {
543       String JavaDoc archiveName = entryList[i];
544
545       Path archivePath = archiveDirectory.lookup(archiveName);
546
547       String JavaDoc entryName = null;
548       
549       if (! archivePath.canRead())
550         continue;
551       else
552     entryName = archiveNameToEntryName(archiveName);
553
554       if (entryName != null)
555     entryNames.add(entryName);
556     }
557     
558     String JavaDoc []entryExpandList = expandDirectory.list();
559
560     // collect all the new war expand directories
561
loop:
562     for (int i = 0; i < entryExpandList.length; i++) {
563       String JavaDoc pathName = entryExpandList[i];
564
565       /* XXX: this used to be needed to solve issues with NT
566       if (CauchoSystem.isCaseInsensitive())
567         pathName = pathName.toLowerCase();
568       */

569
570       Path rootDirectory = expandDirectory.lookup(pathName);
571       
572       String JavaDoc entryName = pathNameToEntryName(pathName);
573
574       if (entryName == null)
575     continue;
576       else if (entryName.endsWith(getExtension()))
577     continue;
578
579       if (! isValidDirectory(rootDirectory, pathName))
580     continue;
581
582       if (! entryNames.contains(entryName))
583     entryNames.add(entryName);
584     }
585
586     return entryNames;
587   }
588
589   protected boolean isValidDirectory(Path rootDirectory, String JavaDoc pathName)
590   {
591     
592     if (! rootDirectory.isDirectory() || pathName.startsWith(".")) {
593       return false;
594     }
595
596     if (pathName.equalsIgnoreCase("web-inf") ||
597     pathName.equalsIgnoreCase("meta-inf"))
598       return false;
599
600     for (int j = 0; j < _requireFiles.size(); j++) {
601       String JavaDoc file = _requireFiles.get(j);
602
603       if (! rootDirectory.lookup(file).canRead())
604     return false;
605     }
606
607     return true;
608   }
609
610   /**
611    * Converts the expand-path name to the entry name, returns null if
612    * the path name is not valid.
613    */

614   protected String JavaDoc pathNameToEntryName(String JavaDoc name)
615   {
616     if (_expandPrefix == null) {
617     }
618     else if (_expandPrefix.equals("") &&
619          (name.startsWith("_") ||
620           name.startsWith(".") ||
621           name.equalsIgnoreCase("META-INF") ||
622           name.equalsIgnoreCase("WEB-INF"))) {
623       return null;
624     }
625     else if (name.startsWith(_expandPrefix)) {
626       name = name.substring(_expandPrefix.length());
627     }
628     else
629       return null;
630
631     if (_expandSuffix == null)
632       return name;
633     else if (name.endsWith(_expandSuffix))
634       return name.substring(0, name.length() - _expandSuffix.length());
635     else
636       return null;
637   }
638
639   /**
640    * Converts the archive name to the entry name, returns null if
641    * the archive name is not valid.
642    */

643   protected String JavaDoc entryNameToArchiveName(String JavaDoc entryName)
644   {
645     return entryName + getExtension();
646   }
647
648   /**
649    * Converts the entry name to the archive name, returns null if
650    * the entry name is not valid.
651    */

652   protected String JavaDoc archiveNameToEntryName(String JavaDoc archiveName)
653   {
654     if (! archiveName.endsWith(_extension))
655       return null;
656     else {
657       int sublen = archiveName.length() - _extension.length();
658       return pathNameToEntryName(archiveName.substring(0, sublen));
659     }
660   }
661
662   /**
663    * Creates a new entry.
664    */

665   abstract protected E createController(String JavaDoc name);
666
667   private String JavaDoc nameToEntryName(String JavaDoc name)
668   {
669     return archiveNameToEntryName(name + getExtension());
670   }
671
672   private String JavaDoc entryNameToName(String JavaDoc name)
673   {
674     String JavaDoc archiveName = entryNameToArchiveName(name);
675
676     if (archiveName == null)
677       return null;
678     else
679       return archiveName.substring(0, archiveName.length() - getExtension().length());
680   }
681
682   public String JavaDoc[] getNames()
683   {
684     String JavaDoc[] names = new String JavaDoc[_controllerNames.size()];
685
686     int i = 0;
687
688     for (String JavaDoc controllerName : _controllerNames) {
689       names[i++] = entryNameToName(controllerName);
690     }
691
692     return names;
693   }
694
695   private String JavaDoc getNamesAsString()
696   {
697     StringBuilder JavaDoc builder = new StringBuilder JavaDoc();
698
699     for (String JavaDoc name : getNames()) {
700       if (builder.length() > 0)
701         builder.append(", ");
702
703       builder.append(name);
704     }
705
706     builder.insert(0, '[');
707     builder.append(']');
708
709     return builder.toString();
710   }
711
712   /**
713    * Start the archive.
714    */

715   public boolean start(String JavaDoc name)
716   {
717     DeployController controller = getDeployContainer().findController(nameToEntryName(name));
718
719     if (controller == null) {
720       if (log.isLoggable(Level.FINE))
721         log.log(Level.FINE, L.l("unknown name `{0}'", name));
722
723       if (log.isLoggable(Level.FINER))
724         log.log(Level.FINER, L.l("known names are {0}", getNamesAsString()));
725
726       return false;
727     }
728
729     controller.start();
730     return true;
731   }
732
733   /**
734    * Returns an exception for the named archive or null if there is no exception
735    */

736   public Throwable JavaDoc getConfigException(String JavaDoc name)
737   {
738     DeployController controller = getDeployContainer().findController(nameToEntryName(name));
739
740     if (controller == null) {
741       if (log.isLoggable(Level.FINE))
742         log.log(Level.FINE, L.l("unknown name `{0}'", name));
743
744       if (log.isLoggable(Level.FINER))
745         log.log(Level.FINER, L.l("known names are {0}", getNamesAsString()));
746
747       return new ConfigException(L.l("unknown name `{0}'", name));
748     }
749
750     return controller.getConfigException();
751   }
752   /**
753    * Stop the archive.
754    */

755   public boolean stop(String JavaDoc name)
756   {
757     DeployController controller = getDeployContainer().findController(nameToEntryName(name));
758
759     if (controller == null) {
760       if (log.isLoggable(Level.FINE))
761         log.log(Level.FINE, L.l("unknown name `{0}'", name));
762
763       if (log.isLoggable(Level.FINER))
764         log.log(Level.FINER, L.l("known names are {0}", getNamesAsString()));
765
766       return false;
767     }
768
769     controller.stop();
770     return true;
771   }
772
773   /**
774    * Undeploy the archive.
775    */

776   public boolean undeploy(String JavaDoc name)
777   {
778     DeployController controller = getDeployContainer().findController(nameToEntryName(name));
779
780     if (controller == null) {
781       if (log.isLoggable(Level.FINE))
782         log.log(Level.FINE, L.l("unknown name `{0}'", name));
783
784       if (log.isLoggable(Level.FINER))
785         log.log(Level.FINER, L.l("known names are {0}", getNamesAsString()));
786
787       return false;
788     }
789
790     Path archivePath = getArchivePath(name);
791     Path expandPath = getExpandPath(name);
792
793     controller.stop();
794
795     try {
796       if (log.isLoggable(Level.FINEST))
797         log.log(Level.FINEST, L.l("deleting {0}", archivePath));
798
799       archivePath.removeAll();
800     }
801     catch (IOException JavaDoc ex) {
802       if (log.isLoggable(Level.FINE))
803         log.log(Level.FINE, ex.toString(), ex);
804     }
805
806     try {
807       if (expandPath != null) {
808         if (log.isLoggable(Level.FINEST))
809           log.log(Level.FINEST, L.l("deleting {0}", expandPath));
810
811         expandPath.removeAll();
812       }
813     }
814     catch (IOException JavaDoc ex) {
815       if (log.isLoggable(Level.FINE))
816         log.log(Level.FINE, ex.toString(), ex);
817     }
818
819     getDeployContainer().update(nameToEntryName(name));
820
821     return true;
822   }
823
824
825   /**
826    * Checks for updates.
827    */

828   public void handleAlarm(Alarm alarm)
829   {
830     if (! isActive())
831       return;
832     
833     try {
834       request();
835     } catch (Exception JavaDoc e) {
836       log.log(Level.WARNING, e.toString(), e);
837     } finally {
838       _alarm.queue(_cronInterval);
839     }
840   }
841
842   /**
843    * Stops the deploy.
844    */

845   @Override JavaDoc
846   protected void stopImpl()
847   {
848     _alarm.dequeue();
849
850     super.stopImpl();
851   }
852
853   /**
854    * Tests for equality.
855    */

856   public boolean equals(Object JavaDoc o)
857   {
858     if (o == null || ! getClass().equals(o.getClass()))
859       return false;
860
861     ExpandDeployGenerator deploy = (ExpandDeployGenerator) o;
862
863     Path expandDirectory = getExpandDirectory();
864     Path deployExpandDirectory = deploy.getExpandDirectory();
865
866     if (expandDirectory != deployExpandDirectory &&
867     (expandDirectory == null ||
868      ! expandDirectory.equals(deployExpandDirectory)))
869       return false;
870
871     return true;
872   }
873
874   public String JavaDoc toString()
875   {
876     String JavaDoc name = getClass().getName();
877     int p = name.lastIndexOf('.');
878     if (p > 0)
879       name = name.substring(p + 1);
880     
881     return name + "[" + getExpandDirectory() + "]";
882   }
883
884 }
885
Popular Tags