1// 2// ======================================================================== 3// Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. 4// ------------------------------------------------------------------------ 5// All rights reserved. This program and the accompanying materials 6// are made available under the terms of the Eclipse Public License v1.0 7// and Apache License v2.0 which accompanies this distribution. 8// 9// The Eclipse Public License is available at 10// http://www.eclipse.org/legal/epl-v10.html 11// 12// The Apache License v2.0 is available at 13// http://www.opensource.org/licenses/apache2.0.php 14// 15// You may elect to redistribute this code under either of these licenses. 16// ======================================================================== 17// 18 19package org.eclipse.jetty.servlet; 20 21import java.io.IOException; 22import java.util.ArrayList; 23import java.util.Arrays; 24import java.util.Collection; 25import java.util.Collections; 26import java.util.HashMap; 27import java.util.HashSet; 28import java.util.List; 29import java.util.Map; 30import java.util.Set; 31import java.util.Stack; 32 33import javax.servlet.MultipartConfigElement; 34import javax.servlet.Servlet; 35import javax.servlet.ServletConfig; 36import javax.servlet.ServletException; 37import javax.servlet.ServletRegistration; 38import javax.servlet.ServletContext; 39import javax.servlet.ServletRequest; 40import javax.servlet.ServletResponse; 41import javax.servlet.ServletSecurityElement; 42import javax.servlet.SingleThreadModel; 43import javax.servlet.UnavailableException; 44 45import org.eclipse.jetty.security.IdentityService; 46import org.eclipse.jetty.security.RunAsToken; 47import org.eclipse.jetty.server.Request; 48import org.eclipse.jetty.server.UserIdentity; 49import org.eclipse.jetty.server.handler.ContextHandler; 50import org.eclipse.jetty.util.Loader; 51import org.eclipse.jetty.util.log.Log; 52import org.eclipse.jetty.util.log.Logger; 53 54 55 56 57/* --------------------------------------------------------------------- */ 58/** Servlet Instance and Context Holder. 59 * Holds the name, params and some state of a javax.servlet.Servlet 60 * instance. It implements the ServletConfig interface. 61 * This class will organise the loading of the servlet when needed or 62 * requested. 63 * 64 * 65 */ 66public class ServletHolder extends Holder<Servlet> implements UserIdentity.Scope, Comparable 67{ 68 private static final Logger LOG = Log.getLogger(ServletHolder.class); 69 70 /* ---------------------------------------------------------------- */ 71 private int _initOrder; 72 private boolean _initOnStartup=false; 73 private Map<String, String> _roleMap; 74 private String _forcedPath; 75 private String _runAsRole; 76 private RunAsToken _runAsToken; 77 private IdentityService _identityService; 78 private ServletRegistration.Dynamic _registration; 79 80 81 private transient Servlet _servlet; 82 private transient Config _config; 83 private transient long _unavailable; 84 private transient boolean _enabled = true; 85 private transient UnavailableException _unavailableEx; 86 public static final Map<String,String> NO_MAPPED_ROLES = Collections.emptyMap(); 87 88 /* ---------------------------------------------------------------- */ 89 /** Constructor . 90 */ 91 public ServletHolder() 92 { 93 this(Source.EMBEDDED); 94 } 95 96 /* ---------------------------------------------------------------- */ 97 /** Constructor . 98 */ 99 public ServletHolder(Holder.Source creator) 100 { 101 super(creator); 102 } 103 104 /* ---------------------------------------------------------------- */ 105 /** Constructor for existing servlet. 106 */ 107 public ServletHolder(Servlet servlet) 108 { 109 this(Source.EMBEDDED); 110 setServlet(servlet); 111 } 112 113 /* ---------------------------------------------------------------- */ 114 /** Constructor for servlet class. 115 */ 116 public ServletHolder(String name, Class<? extends Servlet> servlet) 117 { 118 this(Source.EMBEDDED); 119 setName(name); 120 setHeldClass(servlet); 121 } 122 123 /* ---------------------------------------------------------------- */ 124 /** Constructor for servlet class. 125 */ 126 public ServletHolder(String name, Servlet servlet) 127 { 128 this(Source.EMBEDDED); 129 setName(name); 130 setServlet(servlet); 131 } 132 133 /* ---------------------------------------------------------------- */ 134 /** Constructor for servlet class. 135 */ 136 public ServletHolder(Class<? extends Servlet> servlet) 137 { 138 this(Source.EMBEDDED); 139 setHeldClass(servlet); 140 } 141 142 /* ---------------------------------------------------------------- */ 143 /** 144 * @return The unavailable exception or null if not unavailable 145 */ 146 public UnavailableException getUnavailableException() 147 { 148 return _unavailableEx; 149 } 150 151 /* ------------------------------------------------------------ */ 152 public synchronized void setServlet(Servlet servlet) 153 { 154 if (servlet==null || servlet instanceof SingleThreadModel) 155 throw new IllegalArgumentException(); 156 157 _extInstance=true; 158 _servlet=servlet; 159 setHeldClass(servlet.getClass()); 160 if (getName()==null) 161 setName(servlet.getClass().getName()+"-"+super.hashCode()); 162 } 163 164 /* ------------------------------------------------------------ */ 165 public int getInitOrder() 166 { 167 return _initOrder; 168 } 169 170 /* ------------------------------------------------------------ */ 171 /** Set the initialize order. 172 * Holders with order<0, are initialized on use. Those with 173 * order>=0 are initialized in increasing order when the handler 174 * is started. 175 */ 176 public void setInitOrder(int order) 177 { 178 _initOnStartup=true; 179 _initOrder = order; 180 } 181 182 public boolean isSetInitOrder() 183 { 184 return _initOnStartup; 185 } 186 187 /* ------------------------------------------------------------ */ 188 /** Comparitor by init order. 189 */ 190 public int compareTo(Object o) 191 { 192 if (o instanceof ServletHolder) 193 { 194 ServletHolder sh= (ServletHolder)o; 195 if (sh==this) 196 return 0; 197 if (sh._initOrder<_initOrder) 198 return 1; 199 if (sh._initOrder>_initOrder) 200 return -1; 201 202 int c=(_className!=null && sh._className!=null)?_className.compareTo(sh._className):0; 203 if (c==0) 204 c=_name.compareTo(sh._name); 205 return c; 206 } 207 return 1; 208 } 209 210 /* ------------------------------------------------------------ */ 211 public boolean equals(Object o) 212 { 213 return compareTo(o)==0; 214 } 215 216 /* ------------------------------------------------------------ */ 217 public int hashCode() 218 { 219 return _name==null?System.identityHashCode(this):_name.hashCode(); 220 } 221 222 /* ------------------------------------------------------------ */ 223 /** Link a user role. 224 * Translate the role name used by a servlet, to the link name 225 * used by the container. 226 * @param name The role name as used by the servlet 227 * @param link The role name as used by the container. 228 */ 229 public synchronized void setUserRoleLink(String name,String link) 230 { 231 if (_roleMap==null) 232 _roleMap=new HashMap<String, String>(); 233 _roleMap.put(name,link); 234 } 235 236 /* ------------------------------------------------------------ */ 237 /** get a user role link. 238 * @param name The name of the role 239 * @return The name as translated by the link. If no link exists, 240 * the name is returned. 241 */ 242 public String getUserRoleLink(String name) 243 { 244 if (_roleMap==null) 245 return name; 246 String link= _roleMap.get(name); 247 return (link==null)?name:link; 248 } 249 250 /* ------------------------------------------------------------ */ 251 public Map<String, String> getRoleMap() 252 { 253 return _roleMap == null? NO_MAPPED_ROLES : _roleMap; 254 } 255 256 /* ------------------------------------------------------------ */ 257 /** 258 * @return Returns the forcedPath. 259 */ 260 public String getForcedPath() 261 { 262 return _forcedPath; 263 } 264 265 /* ------------------------------------------------------------ */ 266 /** 267 * @param forcedPath The forcedPath to set. 268 */ 269 public void setForcedPath(String forcedPath) 270 { 271 _forcedPath = forcedPath; 272 } 273 274 public boolean isEnabled() 275 { 276 return _enabled; 277 } 278 279 280 public void setEnabled(boolean enabled) 281 { 282 _enabled = enabled; 283 } 284 285 286 /* ------------------------------------------------------------ */ 287 public void doStart() 288 throws Exception 289 { 290 _unavailable=0; 291 if (!_enabled) 292 return; 293 294 295 //check servlet has a class (ie is not a preliminary registration). If preliminary, fail startup. 296 try 297 { 298 super.doStart(); 299 } 300 catch (UnavailableException ue) 301 { 302 makeUnavailable(ue); 303 if (_servletHandler.isStartWithUnavailable()) 304 { 305 LOG.ignore(ue); 306 return; 307 } 308 else 309 throw ue; 310 } 311 312 313 //servlet is not an instance of javax.servlet.Servlet 314 try 315 { 316 checkServletType(); 317 } 318 catch (UnavailableException ue) 319 { 320 makeUnavailable(ue); 321 if (_servletHandler.isStartWithUnavailable()) 322 { 323 LOG.ignore(ue); 324 return; 325 } 326 else 327 throw ue; 328 } 329 330 331 _identityService = _servletHandler.getIdentityService(); 332 if (_identityService!=null && _runAsRole!=null) 333 _runAsToken=_identityService.newRunAsToken(_runAsRole); 334 335 _config=new Config(); 336 337 if (_class!=null && javax.servlet.SingleThreadModel.class.isAssignableFrom(_class)) 338 _servlet = new SingleThreadedWrapper(); 339 340 if (_extInstance || _initOnStartup) 341 { 342 try 343 { 344 initServlet(); 345 } 346 catch(Exception e) 347 { 348 if (_servletHandler.isStartWithUnavailable()) 349 LOG.ignore(e); 350 else 351 throw e; 352 } 353 } 354 } 355 356 /* ------------------------------------------------------------ */ 357 public void doStop() 358 throws Exception 359 { 360 Object old_run_as = null; 361 if (_servlet!=null) 362 { 363 try 364 { 365 if (_identityService!=null) 366 old_run_as=_identityService.setRunAs(_identityService.getSystemUserIdentity(),_runAsToken); 367 368 destroyInstance(_servlet); 369 } 370 catch (Exception e) 371 { 372 LOG.warn(e); 373 } 374 finally 375 { 376 if (_identityService!=null) 377 _identityService.unsetRunAs(old_run_as); 378 } 379 } 380 381 if (!_extInstance) 382 _servlet=null; 383 384 _config=null; 385 } 386 387 /* ------------------------------------------------------------ */ 388 public void destroyInstance (Object o) 389 throws Exception 390 { 391 if (o==null) 392 return; 393 Servlet servlet = ((Servlet)o); 394 getServletHandler().destroyServlet(servlet); 395 servlet.destroy(); 396 } 397 398 /* ------------------------------------------------------------ */ 399 /** Get the servlet. 400 * @return The servlet 401 */ 402 public synchronized Servlet getServlet() 403 throws ServletException 404 { 405 // Handle previous unavailability 406 if (_unavailable!=0) 407 { 408 if (_unavailable<0 || _unavailable>0 && System.currentTimeMillis()<_unavailable) 409 throw _unavailableEx; 410 _unavailable=0; 411 _unavailableEx=null; 412 } 413 414 if (_servlet==null) 415 initServlet(); 416 return _servlet; 417 } 418 419 /* ------------------------------------------------------------ */ 420 /** Get the servlet instance (no initialization done). 421 * @return The servlet or null 422 */ 423 public Servlet getServletInstance() 424 { 425 return _servlet; 426 } 427 428 /* ------------------------------------------------------------ */ 429 /** 430 * Check to ensure class of servlet is acceptable. 431 * @throws UnavailableException 432 */ 433 public void checkServletType () 434 throws UnavailableException 435 { 436 if (_class==null || !javax.servlet.Servlet.class.isAssignableFrom(_class)) 437 { 438 throw new UnavailableException("Servlet "+_class+" is not a javax.servlet.Servlet"); 439 } 440 } 441 442 /* ------------------------------------------------------------ */ 443 /** 444 * @return true if the holder is started and is not unavailable 445 */ 446 public boolean isAvailable() 447 { 448 if (isStarted()&& _unavailable==0) 449 return true; 450 try 451 { 452 getServlet(); 453 } 454 catch(Exception e) 455 { 456 LOG.ignore(e); 457 } 458 459 return isStarted()&& _unavailable==0; 460 } 461 462 /* ------------------------------------------------------------ */ 463 private void makeUnavailable(UnavailableException e) 464 { 465 if (_unavailableEx==e && _unavailable!=0) 466 return; 467 468 _servletHandler.getServletContext().log("unavailable",e); 469 470 _unavailableEx=e; 471 _unavailable=-1; 472 if (e.isPermanent()) 473 _unavailable=-1; 474 else 475 { 476 if (_unavailableEx.getUnavailableSeconds()>0) 477 _unavailable=System.currentTimeMillis()+1000*_unavailableEx.getUnavailableSeconds(); 478 else 479 _unavailable=System.currentTimeMillis()+5000; // TODO configure 480 } 481 } 482 483 /* ------------------------------------------------------------ */ 484 485 private void makeUnavailable(final Throwable e) 486 { 487 if (e instanceof UnavailableException) 488 makeUnavailable((UnavailableException)e); 489 else 490 { 491 ServletContext ctx = _servletHandler.getServletContext(); 492 if (ctx==null) 493 LOG.info("unavailable",e); 494 else 495 ctx.log("unavailable",e); 496 _unavailableEx=new UnavailableException(String.valueOf(e),-1) 497 { 498 { 499 initCause(e); 500 } 501 }; 502 _unavailable=-1; 503 } 504 } 505 506 /* ------------------------------------------------------------ */ 507 private void initServlet() 508 throws ServletException 509 { 510 Object old_run_as = null; 511 try 512 { 513 if (_servlet==null) 514 _servlet=newInstance(); 515 if (_config==null) 516 _config=new Config(); 517 518 // Handle run as 519 if (_identityService!=null) 520 { 521 old_run_as=_identityService.setRunAs(_identityService.getSystemUserIdentity(),_runAsToken); 522 } 523 524 // Handle configuring servlets that implement org.apache.jasper.servlet.JspServlet 525 if (isJspServlet()) 526 { 527 initJspServlet(); 528 } 529 530 initMultiPart(); 531 532 _servlet.init(_config); 533 } 534 catch (UnavailableException e) 535 { 536 makeUnavailable(e); 537 _servlet=null; 538 _config=null; 539 throw e; 540 } 541 catch (ServletException e) 542 { 543 makeUnavailable(e.getCause()==null?e:e.getCause()); 544 _servlet=null; 545 _config=null; 546 throw e; 547 } 548 catch (Exception e) 549 { 550 makeUnavailable(e); 551 _servlet=null; 552 _config=null; 553 throw new ServletException(this.toString(),e); 554 } 555 finally 556 { 557 // pop run-as role 558 if (_identityService!=null) 559 _identityService.unsetRunAs(old_run_as); 560 } 561 } 562 563 564 /* ------------------------------------------------------------ */ 565 /** 566 * @throws Exception 567 */ 568 protected void initJspServlet () throws Exception 569 { 570 ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler(); 571 572 /* Set the webapp's classpath for Jasper */ 573 ch.setAttribute("org.apache.catalina.jsp_classpath", ch.getClassPath()); 574 575 /* Set the system classpath for Jasper */ 576 setInitParameter("com.sun.appserv.jsp.classpath", Loader.getClassPath(ch.getClassLoader().getParent())); 577 578 /* Set up other classpath attribute */ 579 if ("?".equals(getInitParameter("classpath"))) 580 { 581 String classpath = ch.getClassPath(); 582 LOG.debug("classpath=" + classpath); 583 if (classpath != null) 584 setInitParameter("classpath", classpath); 585 } 586 } 587 588 /* ------------------------------------------------------------ */ 589 /** 590 * Register a ServletRequestListener that will ensure tmp multipart 591 * files are deleted when the request goes out of scope. 592 * 593 * @throws Exception 594 */ 595 protected void initMultiPart () throws Exception 596 { 597 //if this servlet can handle multipart requests, ensure tmp files will be 598 //cleaned up correctly 599 if (((Registration)getRegistration()).getMultipartConfig() != null) 600 { 601 //Register a listener to delete tmp files that are created as a result of this 602 //servlet calling Request.getPart() or Request.getParts() 603 ContextHandler ch = ((ContextHandler.Context)getServletHandler().getServletContext()).getContextHandler(); 604 ch.addEventListener(new Request.MultiPartCleanerListener()); 605 } 606 } 607 608 /* ------------------------------------------------------------ */ 609 /** 610 * @see org.eclipse.jetty.server.UserIdentity.Scope#getContextPath() 611 */ 612 public String getContextPath() 613 { 614 return _config.getServletContext().getContextPath(); 615 } 616 617 /* ------------------------------------------------------------ */ 618 /** 619 * @see org.eclipse.jetty.server.UserIdentity.Scope#getRoleRefMap() 620 */ 621 public Map<String, String> getRoleRefMap() 622 { 623 return _roleMap; 624 } 625 626 /* ------------------------------------------------------------ */ 627 public String getRunAsRole() 628 { 629 return _runAsRole; 630 } 631 632 /* ------------------------------------------------------------ */ 633 public void setRunAsRole(String role) 634 { 635 _runAsRole = role; 636 } 637 638 /* ------------------------------------------------------------ */ 639 /** Service a request with this servlet. 640 */ 641 public void handle(Request baseRequest, 642 ServletRequest request, 643 ServletResponse response) 644 throws ServletException, 645 UnavailableException, 646 IOException 647 { 648 if (_class==null) 649 throw new UnavailableException("Servlet Not Initialized"); 650 651 Servlet servlet=_servlet; 652 synchronized(this) 653 { 654 if (!isStarted()) 655 throw new UnavailableException("Servlet not initialized", -1); 656 if (_unavailable!=0 || !_initOnStartup) 657 servlet=getServlet(); 658 if (servlet==null) 659 throw new UnavailableException("Could not instantiate "+_class); 660 } 661 662 // Service the request 663 boolean servlet_error=true; 664 Object old_run_as = null; 665 boolean suspendable = baseRequest.isAsyncSupported(); 666 try 667 { 668 // Handle aliased path 669 if (_forcedPath!=null) 670 // TODO complain about poor naming to the Jasper folks 671 request.setAttribute("org.apache.catalina.jsp_file",_forcedPath); 672 673 // Handle run as 674 if (_identityService!=null) 675 old_run_as=_identityService.setRunAs(baseRequest.getResolvedUserIdentity(),_runAsToken); 676 677 if (!isAsyncSupported()) 678 baseRequest.setAsyncSupported(false); 679 680 MultipartConfigElement mpce = ((Registration)getRegistration()).getMultipartConfig(); 681 if (mpce != null) 682 request.setAttribute(Request.__MULTIPART_CONFIG_ELEMENT, mpce); 683 684 servlet.service(request,response); 685 servlet_error=false; 686 } 687 catch(UnavailableException e) 688 { 689 makeUnavailable(e); 690 throw _unavailableEx; 691 } 692 finally 693 { 694 baseRequest.setAsyncSupported(suspendable); 695 696 // pop run-as role 697 if (_identityService!=null) 698 _identityService.unsetRunAs(old_run_as); 699 700 // Handle error params. 701 if (servlet_error) 702 request.setAttribute("javax.servlet.error.servlet_name",getName()); 703 } 704 } 705 706 707 /* ------------------------------------------------------------ */ 708 private boolean isJspServlet () 709 { 710 if (_servlet == null) 711 return false; 712 713 Class c = _servlet.getClass(); 714 715 boolean result = false; 716 while (c != null && !result) 717 { 718 result = isJspServlet(c.getName()); 719 c = c.getSuperclass(); 720 } 721 722 return result; 723 } 724 725 726 /* ------------------------------------------------------------ */ 727 private boolean isJspServlet (String classname) 728 { 729 if (classname == null) 730 return false; 731 return ("org.apache.jasper.servlet.JspServlet".equals(classname)); 732 } 733 734 735 /* ------------------------------------------------------------ */ 736 /* ------------------------------------------------------------ */ 737 /* ------------------------------------------------------------ */ 738 protected class Config extends HolderConfig implements ServletConfig 739 { 740 /* -------------------------------------------------------- */ 741 public String getServletName() 742 { 743 return getName(); 744 } 745 746 } 747 748 /* -------------------------------------------------------- */ 749 /* -------------------------------------------------------- */ 750 /* -------------------------------------------------------- */ 751 public class Registration extends HolderRegistration implements ServletRegistration.Dynamic 752 { 753 protected MultipartConfigElement _multipartConfig; 754 755 public Set<String> addMapping(String... urlPatterns) 756 { 757 illegalStateIfContextStarted(); 758 Set<String> clash=null; 759 for (String pattern : urlPatterns) 760 { 761 ServletMapping mapping = _servletHandler.getServletMapping(pattern); 762 if (mapping!=null) 763 { 764 //if the servlet mapping was from a default descriptor, then allow it to be overridden 765 if (!mapping.isDefault()) 766 { 767 if (clash==null) 768 clash=new HashSet<String>(); 769 clash.add(pattern); 770 } 771 } 772 } 773 774 //if there were any clashes amongst the urls, return them 775 if (clash!=null) 776 return clash; 777 778 //otherwise apply all of them 779 ServletMapping mapping = new ServletMapping(); 780 mapping.setServletName(ServletHolder.this.getName()); 781 mapping.setPathSpecs(urlPatterns); 782 _servletHandler.addServletMapping(mapping); 783 784 return Collections.emptySet(); 785 } 786 787 public Collection<String> getMappings() 788 { 789 ServletMapping[] mappings =_servletHandler.getServletMappings(); 790 List<String> patterns=new ArrayList<String>(); 791 if (mappings!=null) 792 { 793 for (ServletMapping mapping : mappings) 794 { 795 if (!mapping.getServletName().equals(getName())) 796 continue; 797 String[] specs=mapping.getPathSpecs(); 798 if (specs!=null && specs.length>0) 799 patterns.addAll(Arrays.asList(specs)); 800 } 801 } 802 return patterns; 803 } 804 805 @Override 806 public String getRunAsRole() 807 { 808 return _runAsRole; 809 } 810 811 @Override 812 public void setLoadOnStartup(int loadOnStartup) 813 { 814 illegalStateIfContextStarted(); 815 ServletHolder.this.setInitOrder(loadOnStartup); 816 } 817 818 public int getInitOrder() 819 { 820 return ServletHolder.this.getInitOrder(); 821 } 822 823 @Override 824 public void setMultipartConfig(MultipartConfigElement element) 825 { 826 _multipartConfig = element; 827 } 828 829 public MultipartConfigElement getMultipartConfig() 830 { 831 return _multipartConfig; 832 } 833 834 @Override 835 public void setRunAsRole(String role) 836 { 837 _runAsRole = role; 838 } 839 840 @Override 841 public Set<String> setServletSecurity(ServletSecurityElement securityElement) 842 { 843 return _servletHandler.setServletSecurity(this, securityElement); 844 } 845 } 846 847 public ServletRegistration.Dynamic getRegistration() 848 { 849 if (_registration == null) 850 _registration = new Registration(); 851 return _registration; 852 } 853 854 /* -------------------------------------------------------- */ 855 /* -------------------------------------------------------- */ 856 /* -------------------------------------------------------- */ 857 private class SingleThreadedWrapper implements Servlet 858 { 859 Stack<Servlet> _stack=new Stack<Servlet>(); 860 861 public void destroy() 862 { 863 synchronized(this) 864 { 865 while(_stack.size()>0) 866 try { (_stack.pop()).destroy(); } catch (Exception e) { LOG.warn(e); } 867 } 868 } 869 870 public ServletConfig getServletConfig() 871 { 872 return _config; 873 } 874 875 public String getServletInfo() 876 { 877 return null; 878 } 879 880 public void init(ServletConfig config) throws ServletException 881 { 882 synchronized(this) 883 { 884 if(_stack.size()==0) 885 { 886 try 887 { 888 Servlet s = newInstance(); 889 s.init(config); 890 _stack.push(s); 891 } 892 catch (ServletException e) 893 { 894 throw e; 895 } 896 catch (Exception e) 897 { 898 throw new ServletException(e); 899 } 900 } 901 } 902 } 903 904 public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException 905 { 906 Servlet s; 907 synchronized(this) 908 { 909 if(_stack.size()>0) 910 s=(Servlet)_stack.pop(); 911 else 912 { 913 try 914 { 915 s = newInstance(); 916 s.init(_config); 917 } 918 catch (ServletException e) 919 { 920 throw e; 921 } 922 catch (Exception e) 923 { 924 throw new ServletException(e); 925 } 926 } 927 } 928 929 try 930 { 931 s.service(req,res); 932 } 933 finally 934 { 935 synchronized(this) 936 { 937 _stack.push(s); 938 } 939 } 940 } 941 } 942 943 /* ------------------------------------------------------------ */ 944 /** 945 * @return the newly created Servlet instance 946 * @throws ServletException 947 * @throws IllegalAccessException 948 * @throws InstantiationException 949 */ 950 protected Servlet newInstance() throws ServletException, IllegalAccessException, InstantiationException 951 { 952 try 953 { 954 ServletContext ctx = getServletHandler().getServletContext(); 955 if (ctx==null) 956 return getHeldClass().newInstance(); 957 return ((ServletContextHandler.Context)ctx).createServlet(getHeldClass()); 958 } 959 catch (ServletException se) 960 { 961 Throwable cause = se.getRootCause(); 962 if (cause instanceof InstantiationException) 963 throw (InstantiationException)cause; 964 if (cause instanceof IllegalAccessException) 965 throw (IllegalAccessException)cause; 966 throw se; 967 } 968 } 969} 970