1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.eclipse.jetty.overlays;
20
21 import java.io.File;
22 import java.io.IOException;
23 import java.net.InetAddress;
24 import java.net.MalformedURLException;
25 import java.net.URI;
26 import java.net.URL;
27 import java.net.URLClassLoader;
28 import java.net.UnknownHostException;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Enumeration;
32 import java.util.HashMap;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Properties;
37 import java.util.Set;
38 import java.util.Timer;
39 import java.util.concurrent.ConcurrentHashMap;
40 import java.util.concurrent.atomic.AtomicBoolean;
41 import java.util.regex.Pattern;
42
43 import javax.servlet.ServletContextEvent;
44 import javax.servlet.ServletContextListener;
45
46 import org.eclipse.jetty.deploy.App;
47 import org.eclipse.jetty.deploy.AppProvider;
48 import org.eclipse.jetty.deploy.ConfigurationManager;
49 import org.eclipse.jetty.deploy.DeploymentManager;
50 import org.eclipse.jetty.jndi.java.javaRootURLContext;
51 import org.eclipse.jetty.jndi.local.localContextRoot;
52 import org.eclipse.jetty.server.ResourceCache;
53 import org.eclipse.jetty.server.Server;
54 import org.eclipse.jetty.server.handler.ContextHandler;
55 import org.eclipse.jetty.servlet.Holder;
56 import org.eclipse.jetty.servlet.ServletHandler;
57 import org.eclipse.jetty.util.IO;
58 import org.eclipse.jetty.util.Scanner;
59 import org.eclipse.jetty.util.component.AbstractLifeCycle;
60 import org.eclipse.jetty.util.log.Logger;
61 import org.eclipse.jetty.util.resource.JarResource;
62 import org.eclipse.jetty.util.resource.Resource;
63 import org.eclipse.jetty.util.resource.ResourceCollection;
64 import org.eclipse.jetty.webapp.JettyWebXmlConfiguration;
65 import org.eclipse.jetty.webapp.WebAppClassLoader;
66 import org.eclipse.jetty.webapp.WebAppContext;
67 import org.eclipse.jetty.xml.XmlConfiguration;
68 import org.xml.sax.SAXException;
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157 public class OverlayedAppProvider extends AbstractLifeCycle implements AppProvider
158 {
159 private final static Logger __log=org.eclipse.jetty.util.log.Log.getLogger("OverlayedAppProvider");
160
161
162
163 public final static String OVERLAYS_DIR="overlays.dir";
164
165
166
167 public final static String OVERLAY_WEBAPP="overlay.webapp";
168
169
170
171 public final static String OVERLAY_TEMPLATE="overlay.template";
172
173
174
175 public final static String OVERLAY_TEMPLATE_NAME="overlay.template.name";
176
177
178
179 public final static String OVERLAY_TEMPLATE_CLASSIFIER="overlay.template.classifier";
180
181
182
183 public final static String OVERLAY_NODE="overlay.node";
184
185
186
187 public final static String OVERLAY_INSTANCE="overlay.instance";
188
189
190
191 public final static String OVERLAY_INSTANCE_CLASSIFIER="overlay.instance.classifier";
192
193 public final static String WEBAPPS="webapps";
194 public final static String TEMPLATES="templates";
195 public final static String NODES="nodes";
196 public final static String INSTANCES="instances";
197
198 public final static String LIB="WEB-INF/lib-overlay";
199 public final static String WEBAPP=".";
200 public final static String OVERLAY_XML="WEB-INF/overlay.xml";
201 public final static String TEMPLATE_XML="WEB-INF/template.xml";
202 public final static String WEB_DEFAULT_XML="WEB-INF/web-default.xml";
203 public final static String WEB_FRAGMENT_XML="WEB-INF/web-overlay.xml";
204
205 enum Monitor { WEBAPPS,TEMPLATES,NODES,INSTANCES} ;
206
207 public final static List<Pattern> __scanPatterns = new ArrayList<Pattern>();
208
209 static
210 {
211 List<String> regexes = new ArrayList<String>();
212
213 for (String s:new String[] {".war",".jar","/WEB-INF/syslib/[^/]*","/WEB-INF/lib/[^/]*","/WEB-INF/classes/[^/]*","/WEB-INF/[^/]*\\.xml",})
214 {
215 regexes.add(WEBAPPS+"/[^/]*"+s);
216 regexes.add(TEMPLATES+"/[^/]*"+s);
217 regexes.add(NODES+"/[^/]*"+s);
218 regexes.add(INSTANCES+"/[^/]*"+s);
219 }
220
221 for (String s: regexes)
222 __scanPatterns.add(Pattern.compile(s,Pattern.CASE_INSENSITIVE));
223 };
224
225 private String _nodeName;
226 private File _scanDir;
227 private File _tmpDir;
228 private String _scanDirURI;
229 private long _loading;
230 private Node _node;
231 private final Map<String,Webapp> _webapps = new HashMap<String,Webapp>();
232 private final Map<String,Template> _templates = new HashMap<String,Template>();
233 private final Map<String,Instance> _instances = new HashMap<String,Instance>();
234 private final Map<String,OverlayedApp> _deployed = new HashMap<String,OverlayedApp>();
235 private final Map<String,TemplateContext> _shared = new HashMap<String, TemplateContext>();
236 private boolean _copydir=false;
237 private DeploymentManager _deploymentManager;
238 private ConfigurationManager _configurationManager;
239 private String _serverID="Server";
240 private final Set<Layer> _removedLayers = new HashSet<Layer>();
241 private Timer _sessionScavenger = new Timer();
242
243 private final Scanner _scanner = new Scanner();
244 private final Scanner.BulkListener _listener = new Scanner.BulkListener()
245 {
246 public void filesChanged(List<String> filenames) throws Exception
247 {
248 __log.debug("Changed {}",filenames);
249
250 Set<String> changes = new HashSet<String>();
251 for (String filename:filenames)
252 {
253
254 File file=new File(filename);
255 if (file.getName().startsWith(".") || file.getName().endsWith(".swp"))
256 continue;
257
258 String relname=file.toURI().getPath().substring(_scanDirURI.length());
259
260 File rel = new File(relname);
261
262 String dir=null;
263 String name=null;
264 String parent=rel.getParent();
265 while (parent!=null)
266 {
267 name=rel.getName();
268 dir=parent;
269 rel=rel.getParentFile();
270 parent=rel.getParent();
271 }
272
273 String uri=dir+"/"+name;
274
275 for (Pattern p : __scanPatterns)
276 {
277 if (p.matcher(relname).matches())
278 {
279 __log.debug("{} == {}",relname,p.pattern());
280 changes.add(uri);
281 }
282 else
283 __log.debug("{} != {}",relname,p.pattern());
284 }
285 }
286
287 if (changes.size()>0)
288 OverlayedAppProvider.this.updateLayers(changes);
289 }
290 };
291
292
293
294 public OverlayedAppProvider()
295 {
296 try
297 {
298 _nodeName=InetAddress.getLocalHost().getHostName();
299 }
300 catch(UnknownHostException e)
301 {
302 __log.debug(e);
303 _nodeName="unknown";
304 }
305 }
306
307
308
309
310 public void setDeploymentManager(DeploymentManager deploymentManager)
311 {
312 _deploymentManager=deploymentManager;
313 }
314
315
316 public DeploymentManager getDeploymentManager()
317 {
318 return _deploymentManager;
319 }
320
321
322 public ConfigurationManager getConfigurationManager()
323 {
324 return _configurationManager;
325 }
326
327
328
329
330
331 public void setConfigurationManager(ConfigurationManager configurationManager)
332 {
333 _configurationManager = configurationManager;
334 }
335
336
337
338
339
340 public String getServerID()
341 {
342 return _serverID;
343 }
344
345
346
347
348
349 public void setServerID(String serverID)
350 {
351 _serverID = serverID;
352 }
353
354
355
356
357
358
359
360
361 public synchronized ContextHandler createContextHandler(App app) throws Exception
362 {
363 final OverlayedApp overlayed = (OverlayedApp)app;
364 final String origin = overlayed.getOriginId();
365 final Instance instance = overlayed.getInstance();
366 final Template template = instance.getTemplate();
367 final Webapp webapp = template.getWebapp();
368 final Node node = _node;
369
370
371 ClassLoader orig_loader = Thread.currentThread().getContextClassLoader();
372 try
373 {
374
375 String key=(node==null?"":node.getLoadedKey())+template.getLoadedKey()+(webapp==null?"":webapp.getLoadedKey());
376 instance.setSharedKey(key);
377
378 TemplateContext shared=_shared.get(key);
379
380 if (shared==null)
381 shared=createTemplateContext(key,webapp,template,node,orig_loader);
382
383
384 ClassLoader shared_loader = shared.getWebappLoader()!=null?shared.getWebappLoader():(shared.getLibLoader()!=null?shared.getLibLoader():orig_loader);
385 ClassLoader loader = shared_loader;
386 Resource instance_lib = instance.getResource(LIB);
387 if (instance_lib.exists())
388 {
389 List<URL> libs = new ArrayList<URL>();
390 for (String jar :instance_lib.list())
391 {
392 if (!jar.toLowerCase().endsWith(".jar"))
393 continue;
394 libs.add(instance_lib.addPath(jar).getURL());
395 }
396
397 __log.debug("{}: libs={}",origin,libs);
398 loader = URLClassLoader.newInstance(libs.toArray(new URL[]{}),loader);
399 }
400
401
402 Thread.currentThread().setContextClassLoader(loader);
403
404
405 Map<String,Object> idMap = new HashMap<String,Object>();
406 idMap.putAll(shared.getIdMap());
407 idMap.put(_serverID,getDeploymentManager().getServer());
408
409
410 ContextHandler context=null;
411
412 Resource template_context_xml = template.getResource(OVERLAY_XML);
413 if (template_context_xml.exists())
414 {
415 __log.debug("{}: overlay.xml={}",origin,template_context_xml);
416 XmlConfiguration xmlc = newXmlConfiguration(template_context_xml.getURL(),idMap,template,instance);
417 context=(ContextHandler)xmlc.configure();
418 idMap=xmlc.getIdMap();
419 }
420 else if (webapp==null)
421
422 context=new ContextHandler();
423 else
424
425 context=new WebAppContext();
426
427
428 final Resource instance_webapp = instance.getResource(WEBAPP);
429 if (instance_webapp.exists())
430 {
431 context.setBaseResource(new ResourceCollection(instance_webapp,shared.getBaseResource()));
432
433
434 ResourceCache cache = new ResourceCache(shared.getResourceCache(),instance_webapp,context.getMimeTypes(),false,false);
435 context.setAttribute(ResourceCache.class.getCanonicalName(),cache);
436 }
437 else
438 {
439 context.setBaseResource(shared.getBaseResource());
440 context.setAttribute(ResourceCache.class.getCanonicalName(),shared.getResourceCache());
441 }
442 __log.debug("{}: baseResource={}",origin,context.getResourceBase());
443
444
445 context.setAttribute("org.eclipse.jetty.server.session.timer", _sessionScavenger);
446
447
448 for (Resource context_xml : getLayeredResources(OVERLAY_XML,node,instance))
449 {
450 __log.debug("{}: overlay.xml={}",origin,context_xml);
451 XmlConfiguration xmlc = newXmlConfiguration(context_xml.getURL(),idMap,template,instance);
452 xmlc.getIdMap().put("Cache",context.getAttribute(ResourceCache.class.getCanonicalName()));
453 xmlc.configure(context);
454 idMap=xmlc.getIdMap();
455 }
456
457
458 if (context instanceof WebAppContext)
459 {
460 final WebAppContext webappcontext = (WebAppContext)context;
461
462 if (Arrays.asList(((WebAppContext)context).getServerClasses()).toString().equals(Arrays.asList(WebAppContext.__dftServerClasses).toString()))
463 {
464 __log.debug("clear server classes");
465 webappcontext.setServerClasses(null);
466 }
467
468
469 webappcontext.setCopyWebDir(false);
470 webappcontext.setCopyWebInf(false);
471 webappcontext.setExtractWAR(false);
472
473 if (instance_webapp.exists())
474 {
475 final Resource classes=instance_webapp.addPath("WEB-INF/classes");
476 final Resource lib=instance_webapp.addPath("WEB-INF/lib");
477
478 if (classes.exists()||lib.exists())
479 {
480 final AtomicBoolean locked =new AtomicBoolean(false);
481
482 WebAppClassLoader webapp_loader=new WebAppClassLoader(loader,webappcontext)
483 {
484 @Override
485 public void addClassPath(Resource resource) throws IOException
486 {
487 if (!locked.get())
488 super.addClassPath(resource);
489 }
490
491 @Override
492 public void addClassPath(String classPath) throws IOException
493 {
494 if (!locked.get())
495 super.addClassPath(classPath);
496 }
497
498 @Override
499 public void addJars(Resource lib)
500 {
501 if (!locked.get())
502 super.addJars(lib);
503 }
504 };
505
506 if (classes.exists())
507 webapp_loader.addClassPath(classes);
508 if (lib.exists())
509 webapp_loader.addJars(lib);
510 locked.set(true);
511
512 loader=webapp_loader;
513 }
514 }
515
516
517 if (loader==shared_loader)
518 loader = new URLClassLoader(new URL[]{},shared_loader);
519
520
521 List<Resource> webdefaults=getLayeredResources(WEB_DEFAULT_XML,instance,node,template);
522 if (webdefaults.size()>0)
523 {
524 Resource webdefault = webdefaults.get(0);
525 __log.debug("{}: defaultweb={}",origin,webdefault);
526 webappcontext.setDefaultsDescriptor(webdefault.toString());
527 }
528
529
530 for (Resource override : getLayeredResources(WEB_FRAGMENT_XML,template,node,instance))
531 {
532 __log.debug("{}: web override={}",origin,override);
533 webappcontext.addOverrideDescriptor(override.toString());
534 }
535 }
536
537 context.setClassLoader(loader);
538
539 __log.debug("{}: baseResource={}",origin,context.getBaseResource());
540
541 Resource jetty_web_xml = context.getResource("/WEB-INF/"+JettyWebXmlConfiguration.JETTY_WEB_XML);
542 if (jetty_web_xml!=null && jetty_web_xml.exists())
543 context.setAttribute(JettyWebXmlConfiguration.XML_CONFIGURATION,newXmlConfiguration(jetty_web_xml.getURL(),idMap,template,instance));
544
545
546 Map<String,String> params = new HashMap<String,String>();
547 populateParameters(params,template,instance);
548 context.addEventListener(new ParameterExpander(params,context));
549
550 System.err.println("created:\n"+context.dump());
551
552 return context;
553 }
554 finally
555 {
556 Thread.currentThread().setContextClassLoader(orig_loader);
557 }
558 }
559
560
561 private XmlConfiguration newXmlConfiguration(URL url, Map<String, Object> idMap, Template template, Instance instance) throws SAXException, IOException
562 {
563 XmlConfiguration xmlc = new XmlConfiguration(url);
564 populateParameters(xmlc.getProperties(),template,instance);
565 xmlc.getIdMap().putAll(idMap);
566
567 return xmlc;
568 }
569
570
571 private void populateParameters(Map<String,String> params,Template template, Instance instance)
572 {
573 try
574 {
575 params.put(OVERLAYS_DIR,_scanDir.getCanonicalPath());
576 if (template!=null)
577 {
578 params.put(OVERLAY_TEMPLATE,template.getName());
579 params.put(OVERLAY_TEMPLATE_NAME,template.getTemplateName());
580 params.put(OVERLAY_TEMPLATE_CLASSIFIER,template.getClassifier());
581 params.put(OVERLAY_WEBAPP,template.getWebapp()==null?null:template.getWebapp().getName());
582 }
583 if (_node!=null)
584 params.put(OVERLAY_NODE,_node.getName());
585 if (instance!=null)
586 {
587 params.put(OVERLAY_INSTANCE,instance.getName());
588 params.put(OVERLAY_INSTANCE_CLASSIFIER,instance.getClassifier());
589 }
590 if (getConfigurationManager()!=null)
591 params.putAll(getConfigurationManager().getProperties());
592 }
593 catch(Exception e)
594 {
595 throw new RuntimeException(e);
596 }
597 }
598
599
600
601 private TemplateContext createTemplateContext(final String key, Webapp webapp, Template template, Node node, ClassLoader parent) throws Exception
602 {
603 __log.info("created {}",key);
604
605
606
607
608 List<URL> libs = new ArrayList<URL>();
609 for (Resource lib : getLayeredResources(LIB,node,template))
610 {
611 for (String jar :lib.list())
612 {
613 if (!jar.toLowerCase().endsWith(".jar"))
614 continue;
615 libs.add(lib.addPath(jar).getURL());
616 }
617 }
618 final ClassLoader libLoader;
619 if (libs.size()>0)
620 {
621 __log.debug("{}: libs={}",key,libs);
622 libLoader=new URLClassLoader(libs.toArray(new URL[]{}),parent)
623 {
624 public String toString() {return "libLoader@"+Long.toHexString(hashCode())+"-lib-"+key;}
625 };
626
627 }
628 else
629 libLoader=parent;
630
631 Thread.currentThread().setContextClassLoader(libLoader);
632
633
634
635 List<Resource> bases = new ArrayList<Resource>();
636 for (Resource wa : getLayers(node,template))
637 bases.add(wa);
638 if (webapp!=null)
639 bases.add(webapp.getBaseResource());
640 Resource baseResource = bases.size()==1?bases.get(0):new ResourceCollection(bases.toArray(new Resource[bases.size()]));
641 __log.debug("{}: baseResource={}",key,baseResource);
642
643
644
645 TemplateContext shared = new TemplateContext(key,getDeploymentManager().getServer(),baseResource,libLoader);
646 _shared.put(key,shared);
647
648
649
650 Map<String,Object> idMap = new HashMap<String,Object>();
651 idMap.put(_serverID,getDeploymentManager().getServer());
652
653
654
655
656
657
658
659 for (Resource template_xml : getLayeredResources(TEMPLATE_XML,template,node))
660 {
661 __log.debug("{}: template.xml={}",key,template_xml);
662 XmlConfiguration xmlc = newXmlConfiguration(template_xml.getURL(),idMap,template,null);
663 xmlc.getIdMap().putAll(idMap);
664 xmlc.configure(shared);
665 idMap=xmlc.getIdMap();
666 }
667
668 shared.setIdMap(idMap);
669 shared.start();
670
671 return shared;
672 }
673
674
675
676
677
678 public String getNodeName()
679 {
680 return _nodeName;
681 }
682
683
684
685
686
687 public void setNodeName(String nodeName)
688 {
689 _nodeName = nodeName;
690 }
691
692
693
694
695
696 public File getScanDir()
697 {
698 return _scanDir;
699 }
700
701
702
703
704
705 public void setScanDir(File scanDir)
706 {
707 _scanDir = scanDir;
708 }
709
710
711
712
713
714 public void setTmpDir(File tmpDir)
715 {
716 _tmpDir=tmpDir;
717 }
718
719
720
721
722
723 public File getTmpDir()
724 {
725 return _tmpDir;
726 }
727
728
729
730
731
732
733 public int getScanInterval()
734 {
735 return _scanner.getScanInterval();
736 }
737
738
739
740
741
742
743 public void setScanInterval(int scanInterval)
744 {
745 _scanner.setScanInterval(scanInterval);
746 }
747
748
749
750
751
752 public void scan()
753 {
754 _scanner.scan();
755 }
756
757
758
759
760
761 @Override
762 protected void doStart() throws Exception
763 {
764 __log.info("Node={} Scan=",_nodeName,_scanDir);
765 if (_scanDir==null || !_scanDir.exists())
766 throw new IllegalStateException("!scandir");
767
768 _scanDirURI=_scanDir.toURI().getPath();
769 _scanner.setScanDepth(6);
770 List<File> dirs = Arrays.asList(new File[]
771 {
772 new File(_scanDir,WEBAPPS),
773 new File(_scanDir,TEMPLATES),
774 new File(_scanDir,NODES),
775 new File(_scanDir,INSTANCES)
776 });
777 for (File file : dirs)
778 {
779 if (!file.exists() && !file.isDirectory())
780 __log.warn("No directory: "+file.getAbsolutePath());
781 }
782 _scanner.setScanDirs(dirs);
783 _scanner.addListener(_listener);
784 _scanner.start();
785
786 super.doStart();
787 }
788
789
790
791
792
793 @Override
794 protected void doStop() throws Exception
795 {
796 _scanner.removeListener(_listener);
797 _scanner.stop();
798
799 if (_deploymentManager.isRunning())
800 {
801 for (App app: _deployed.values())
802 _deploymentManager.removeApp(app);
803 }
804 _deployed.clear();
805
806 for (Layer layer : _webapps.values())
807 layer.release();
808 _webapps.clear();
809 for (Layer layer : _templates.values())
810 layer.release();
811 _templates.clear();
812 if (_node!=null)
813 _node.release();
814 for (Layer layer : _instances.values())
815 layer.release();
816 _instances.clear();
817
818 super.doStop();
819 }
820
821
822 protected synchronized void updateLayers(Set<String> layerURIs)
823 {
824 _loading=System.currentTimeMillis();
825 for (String ruri: layerURIs)
826 {
827 try
828 {
829
830 File directory;
831 File archive;
832 File origin = new File(new URI(_scanDir.toURI()+ruri));
833 String name=origin.getName();
834
835 Monitor monitor = Monitor.valueOf(origin.getParentFile().getName().toUpperCase());
836
837 String ext=".war";
838
839
840 if (origin.isDirectory() || !origin.exists() && !ruri.toLowerCase().endsWith(ext))
841 {
842
843 directory=origin;
844 archive=new File(directory.toString()+ext);
845 }
846 else
847 {
848
849 if (!ruri.toLowerCase().endsWith(ext))
850 continue;
851
852 name=name.substring(0,name.length()-4);
853 archive=origin;
854 directory=new File(new URI(_scanDir.toURI()+ruri.substring(0,ruri.length()-4)));
855
856
857 if (directory.exists())
858 {
859 __log.info("Directory exists, ignoring change to {}",ruri);
860 continue;
861 }
862 }
863
864 Layer layer=null;
865
866 switch(monitor)
867 {
868 case WEBAPPS:
869 if (origin.exists())
870 layer=loadWebapp(name,origin);
871 else
872 {
873 removeWebapp(name);
874 if (origin==directory && archive.exists())
875 layer=loadWebapp(name,archive);
876 }
877
878 break;
879
880 case TEMPLATES:
881 if (origin.exists())
882 layer=loadTemplate(name,origin);
883 else
884 {
885 removeTemplate(name);
886 if (origin==directory && archive.exists())
887 layer=loadTemplate(name,archive);
888 }
889 break;
890
891 case NODES:
892 if (name.equalsIgnoreCase(_nodeName))
893 {
894 if (origin.exists())
895 layer=loadNode(origin);
896 else
897 {
898 removeNode();
899 if (origin==directory && archive.exists())
900 layer=loadNode(archive);
901 }
902 }
903 break;
904
905 case INSTANCES:
906 if (origin.exists())
907 layer=loadInstance(name,origin);
908 else
909 {
910 removeInstance(name);
911 if (origin==directory && archive.exists())
912 layer=loadInstance(name,archive);
913 }
914 break;
915
916 }
917
918 if (layer!=null)
919 __log.info("loaded {}",layer.getLoadedKey());
920 }
921 catch(Exception e)
922 {
923 __log.warn(e);
924 }
925 }
926
927 redeploy();
928
929
930 for (Layer layer : _removedLayers)
931 {
932 if (layer!=null)
933 {
934 __log.info("unload {}",layer.getLoadedKey());
935 layer.release();
936 }
937 }
938 _removedLayers.clear();
939
940 if (__log.isDebugEnabled())
941 {
942 System.err.println("updated:");
943 System.err.println("java:"+javaRootURLContext.getRoot().dump());
944 System.err.println("local:"+localContextRoot.getRoot().dump());
945 if (getDeploymentManager()!=null && getDeploymentManager().getServer()!=null)
946 System.err.println(getDeploymentManager().getServer().dump());
947 }
948 }
949
950
951 protected File tmpdir(String name,String suffix) throws IOException
952 {
953 File dir=_tmpDir;
954 if (dir==null || !dir.isDirectory() || !dir.canWrite())
955 {
956 dir=new File(_scanDir,"tmp");
957 if (!dir.isDirectory() || !dir.canWrite())
958 dir=null;
959 }
960
961 File tmp = File.createTempFile(name+"_","."+suffix,dir);
962 tmp=tmp.getCanonicalFile();
963 if (tmp.exists())
964 IO.delete(tmp);
965 tmp.mkdir();
966 tmp.deleteOnExit();
967 return tmp;
968 }
969
970
971
972
973
974
975 protected void redeploy()
976 {
977 Map<String,Template> templates = new ConcurrentHashMap<String,Template>();
978
979
980 for (Template template : _templates.values())
981 {
982 Template other=templates.get(template.getTemplateName());
983 if (other!=null)
984 {
985 __log.warn("Multiple Templates: {} & {}",template.getName(),other.getName());
986 if (other.getName().compareToIgnoreCase(template.getName())<=0)
987 continue;
988 }
989 templates.put(template.getTemplateName(),template);
990 }
991
992
993 for (Template template : templates.values())
994 {
995 String webappname=template.getClassifier();
996
997 if (webappname==null)
998 continue;
999
1000 Webapp webapp = _webapps.get(webappname);
1001
1002 if (webapp==null)
1003 {
1004 __log.warn("No webapp found for template: {}",template.getName());
1005 templates.remove(template.getTemplateName());
1006 }
1007 else
1008 {
1009 template.setWebapp(webapp);
1010 }
1011 }
1012
1013
1014 Set<String> deployed = new HashSet<String>();
1015 List<Instance> deploy = new ArrayList<Instance>();
1016
1017 for (Instance instance : _instances.values())
1018 {
1019 Template template=templates.get(instance.getTemplateName());
1020 instance.setTemplate(template);
1021 if (template!=null)
1022 {
1023 String key=instance.getInstanceKey();
1024 App app = _deployed.get(key);
1025 if (app==null)
1026 deploy.add(instance);
1027 else
1028 deployed.add(key);
1029 }
1030 }
1031
1032
1033 List<String> undeploy = new ArrayList<String>();
1034 for (String key : _deployed.keySet())
1035 {
1036 if (!deployed.contains(key))
1037 undeploy.add(key);
1038 }
1039
1040
1041 for (String key : undeploy)
1042 {
1043 App app = _deployed.remove(key);
1044 if (app!=null)
1045 {
1046 __log.info("Undeploy {}",key);
1047 _deploymentManager.removeApp(app);
1048 }
1049 }
1050
1051
1052 for (Instance instance : deploy)
1053 {
1054 String key=instance.getInstanceKey();
1055 OverlayedApp app = new OverlayedApp(_deploymentManager,this,key,instance);
1056 _deployed.put(key,app);
1057 }
1058
1059
1060 Set<String> sharedKeys = new HashSet<String>(_shared.keySet());
1061 for (OverlayedApp app : _deployed.values())
1062 {
1063 Instance instance = app.getInstance();
1064 sharedKeys.remove(instance.getSharedKey());
1065 }
1066 for (String sharedKey: sharedKeys)
1067 {
1068 __log.debug("Remove "+sharedKey);
1069 TemplateContext shared=_shared.remove(sharedKey);
1070 if (shared!=null)
1071 {
1072 try
1073 {
1074 shared.stop();
1075 }
1076 catch(Exception e)
1077 {
1078 __log.warn(e);
1079 }
1080 shared.destroy();
1081 }
1082 }
1083
1084
1085 for (Instance instance : deploy)
1086 {
1087 String key=instance.getInstanceKey();
1088 OverlayedApp app = _deployed.get(key);
1089 __log.info("Deploy {}",key);
1090 _deploymentManager.addApp(app);
1091 }
1092
1093
1094 }
1095
1096
1097 protected void removeInstance(String name)
1098 {
1099 _removedLayers.add(_instances.remove(name));
1100 }
1101
1102
1103 protected Instance loadInstance(String name, File origin)
1104 throws IOException
1105 {
1106 Instance instance=new Instance(name,origin);
1107 _removedLayers.add(_instances.put(name,instance));
1108 return instance;
1109 }
1110
1111
1112 protected void removeNode()
1113 {
1114 if (_node!=null)
1115 _removedLayers.add(_node);
1116 _node=null;
1117 }
1118
1119
1120 protected Node loadNode(File origin)
1121 throws IOException
1122 {
1123 if (_node!=null)
1124 _removedLayers.add(_node);
1125 _node=new Node(_nodeName,origin);
1126 return _node;
1127 }
1128
1129
1130 protected void removeTemplate(String name)
1131 {
1132 _removedLayers.add(_templates.remove(name));
1133 }
1134
1135
1136 protected Template loadTemplate(String name, File origin)
1137 throws IOException
1138 {
1139 Template template=new Template(name,origin);
1140 _removedLayers.add(_templates.put(name,template));
1141 return template;
1142 }
1143
1144 protected void removeWebapp(String name)
1145 {
1146 _removedLayers.add(_webapps.remove(name));
1147 }
1148
1149
1150 protected Webapp loadWebapp(String name, File origin)
1151 throws IOException
1152 {
1153 Webapp webapp = new Webapp(name,origin);
1154 _removedLayers.add(_webapps.put(name,webapp));
1155 return webapp;
1156 }
1157
1158
1159 private static List<Resource> getLayers(Layer... layers)
1160 {
1161 List<Resource> resources = new ArrayList<Resource>();
1162 for (Layer layer: layers)
1163 {
1164 if (layer==null)
1165 continue;
1166 Resource resource = layer.getBaseResource();
1167 if (resource.exists())
1168 resources.add(resource);
1169 }
1170 return resources;
1171 }
1172
1173
1174 private static List<Resource> getLayeredResources(String path, Layer... layers)
1175 {
1176 List<Resource> resources = new ArrayList<Resource>();
1177 for (Layer layer: layers)
1178 {
1179 if (layer==null)
1180 continue;
1181 Resource resource = layer.getResource(path);
1182 if (resource.exists())
1183 resources.add(resource);
1184 }
1185 return resources;
1186 }
1187
1188
1189
1190
1191 class Layer
1192 {
1193 private final String _name;
1194 private final File _origin;
1195 private final long _loaded=_loading;
1196 private final Resource _resourceBase;
1197 private final boolean _resourceBaseIsCopy;
1198
1199 public Layer(String name, File origin)
1200 throws IOException
1201 {
1202 super();
1203 _name = name;
1204 _origin = origin;
1205
1206 Resource resource = Resource.newResource(origin.toURI());
1207
1208 if (resource.isDirectory())
1209 {
1210 if (_copydir)
1211 {
1212 File tmp=tmpdir(name,"extract");
1213 __log.info("Extract {} to {}",origin,tmp);
1214 IO.copyDir(origin,tmp);
1215 _resourceBase=Resource.newResource(tmp.toURI());
1216 _resourceBaseIsCopy=true;
1217 }
1218 else
1219 {
1220 _resourceBase=resource;
1221 _resourceBaseIsCopy=false;
1222 }
1223 }
1224 else
1225 {
1226 Resource jar = JarResource.newJarResource(resource);
1227 File tmp=tmpdir(name,"extract");
1228 __log.info("Extract {} to {}",jar,tmp);
1229 jar.copyTo(tmp);
1230 _resourceBase=Resource.newResource(tmp.toURI());
1231 _resourceBaseIsCopy=true;
1232 }
1233 }
1234
1235 public String getName()
1236 {
1237 return _name;
1238 }
1239
1240 public File getOrigin()
1241 {
1242 return _origin;
1243 }
1244
1245 public long getLoaded()
1246 {
1247 return _loaded;
1248 }
1249
1250 public Resource getBaseResource()
1251 {
1252 return _resourceBase;
1253 }
1254
1255 public Resource getResource(String path)
1256 {
1257 try
1258 {
1259 return getBaseResource().addPath(path);
1260 }
1261 catch(Exception e)
1262 {
1263 __log.warn(e);
1264 }
1265 return null;
1266 }
1267
1268 public String getLoadedKey()
1269 {
1270 return _name+"@"+_loaded;
1271 }
1272
1273 public void release()
1274 {
1275 if (_resourceBaseIsCopy)
1276 {
1277 try
1278 {
1279 File file = _resourceBase.getFile();
1280 if (file!=null)
1281 IO.delete(file);
1282 }
1283 catch(Exception e)
1284 {
1285 __log.warn(e);
1286 }
1287 }
1288 }
1289
1290 public String toString()
1291 {
1292 return getLoadedKey();
1293 }
1294 }
1295
1296 class Webapp extends Layer
1297 {
1298 public Webapp(String name, File origin) throws IOException
1299 {
1300 super(name,origin);
1301 }
1302 }
1303
1304 class Overlay extends Layer
1305 {
1306 public Overlay(String name, File origin) throws IOException
1307 {
1308 super(name,origin);
1309 }
1310
1311 public Resource getContext()
1312 {
1313 return getResource(OVERLAY_XML);
1314 }
1315 }
1316
1317
1318
1319
1320 class Node extends Overlay
1321 {
1322 public Node(String name, File origin) throws IOException
1323 {
1324 super(name,origin);
1325 }
1326 }
1327
1328
1329
1330
1331
1332 class ClassifiedOverlay extends Overlay
1333 {
1334 private final String _templateName;
1335 private final String _classifier;
1336
1337 public ClassifiedOverlay(String name, File origin) throws IOException
1338 {
1339 super(name,origin);
1340
1341 int l=1;
1342 int e=name.indexOf('=');
1343 if (e<0)
1344 {
1345 l=2;
1346 e=name.indexOf("--");
1347 }
1348 _templateName=e>=0?name.substring(0,e):name;
1349 _classifier=e>=0?name.substring(e+l):null;
1350 }
1351
1352 public String getTemplateName()
1353 {
1354 return _templateName;
1355 }
1356
1357 public String getClassifier()
1358 {
1359 return _classifier;
1360 }
1361 }
1362
1363
1364
1365
1366 class Template extends ClassifiedOverlay
1367 {
1368 private Webapp _webapp;
1369
1370 public Webapp getWebapp()
1371 {
1372 return _webapp;
1373 }
1374
1375 public void setWebapp(Webapp webapp)
1376 {
1377 _webapp = webapp;
1378 }
1379
1380 public Template(String name, File origin) throws IOException
1381 {
1382 super(name,origin);
1383 }
1384 }
1385
1386
1387
1388
1389 class Instance extends ClassifiedOverlay
1390 {
1391 Template _template;
1392 String _sharedKey;
1393
1394 public Instance(String name, File origin) throws IOException
1395 {
1396 super(name,origin);
1397 if (getClassifier()==null)
1398 throw new IllegalArgumentException("Instance without '=':"+name);
1399 }
1400
1401 public void setSharedKey(String key)
1402 {
1403 _sharedKey=key;
1404 }
1405
1406 public String getSharedKey()
1407 {
1408 return _sharedKey;
1409 }
1410
1411 public void setTemplate(Template template)
1412 {
1413 _template=template;
1414 }
1415
1416 public Template getTemplate()
1417 {
1418 return _template;
1419 }
1420
1421 public String getInstanceKey()
1422 {
1423 return
1424 (_template.getWebapp()==null?"":_template.getWebapp().getLoadedKey())+"|"+
1425 _template.getLoadedKey()+"|"+
1426 (_node==null?"":_node.getLoadedKey())+"|"+
1427 getLoadedKey();
1428 }
1429 }
1430
1431
1432
1433
1434 static class OverlayedApp extends App
1435 {
1436 final Instance _instance;
1437
1438 public OverlayedApp(DeploymentManager manager, AppProvider provider, String originId, Instance instance)
1439 {
1440 super(manager,provider,originId);
1441 _instance=instance;
1442 }
1443
1444 public Instance getInstance()
1445 {
1446 return _instance;
1447 }
1448 }
1449
1450
1451
1452
1453
1454 private final class ParameterExpander implements ServletContextListener
1455 {
1456 private final Map<String, String> _params;
1457 private final ContextHandler _ctx;
1458
1459 private ParameterExpander(Map<String, String> params, ContextHandler ctx)
1460 {
1461 _params = params;
1462 _ctx = ctx;
1463 }
1464
1465 public void contextInitialized(ServletContextEvent sce)
1466 {
1467 Enumeration<String> e=_ctx.getInitParameterNames();
1468 while (e.hasMoreElements())
1469 {
1470 String name = e.nextElement();
1471 _ctx.setInitParameter(name,expandParameter(_ctx.getInitParameter(name)));
1472 }
1473
1474 ServletHandler servletHandler = _ctx.getChildHandlerByClass(ServletHandler.class);
1475 if (servletHandler!=null)
1476 {
1477 List<Holder<?>> holders = new ArrayList<Holder<?>>();
1478 if (servletHandler.getFilters()!=null)
1479 holders.addAll(Arrays.asList(servletHandler.getFilters()));
1480 if (servletHandler.getHandler()!=null)
1481 holders.addAll(Arrays.asList(servletHandler.getServlets()));
1482 for (Holder<?> holder: holders)
1483 {
1484 e=holder.getInitParameterNames();
1485 while (e.hasMoreElements())
1486 {
1487 String name = e.nextElement();
1488 holder.setInitParameter(name,expandParameter(holder.getInitParameter(name)));
1489 }
1490 }
1491 }
1492 }
1493
1494 private String expandParameter(String value)
1495 {
1496 int i=0;
1497 while (true)
1498 {
1499 int open=value.indexOf("${",i);
1500 if (open<0)
1501 return value;
1502 int close=value.indexOf("}",open);
1503 if (close<0)
1504 return value;
1505
1506 String param = value.substring(open+2,close);
1507 if (_params.containsKey(param))
1508 {
1509 String tmp=value.substring(0,open)+_params.get(param);
1510 i=tmp.length();
1511 value=tmp+value.substring(close+1);
1512 }
1513 else
1514 i=close+1;
1515 }
1516 }
1517
1518 public void contextDestroyed(ServletContextEvent sce)
1519 {
1520 }
1521 }
1522 }