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