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