# This patch file was generated by NetBeans IDE # Following Index: paths are relative to: /home/oleksiys/Projects/glassfish/3.1.2 # This patch can be applied using context Tools: Patch action on respective folder. # It uses platform neutral UTF-8 encoding and \n newlines. # Above lines and this line are ignored by the patching process. Index: core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ContainerMapper.java --- core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ContainerMapper.java Base (BASE) +++ core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/ContainerMapper.java Locally Modified (Based On LOCAL) @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2007-2011 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007-2012 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -50,6 +50,7 @@ import com.sun.grizzly.config.GrizzlyEmbeddedHttp; import com.sun.grizzly.config.ContextRootInfo; import com.sun.grizzly.config.FileCacheAware; +import com.sun.grizzly.config.dom.NetworkListener; import com.sun.grizzly.tcp.Adapter; import com.sun.grizzly.tcp.Request; import com.sun.grizzly.tcp.Response; @@ -65,6 +66,9 @@ import com.sun.grizzly.util.http.MimeType; import java.io.IOException; +import java.util.concurrent.Callable; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantReadWriteLock; import org.glassfish.api.container.Sniffer; import org.glassfish.api.deployment.ApplicationContainer; @@ -84,13 +88,15 @@ private final static String ROOT = ""; private Mapper mapper; private GrizzlyEmbeddedHttp grizzlyEmbeddedHttp; + private UDecoder urlDecoder; private String defaultHostName = "server"; - private final UDecoder urlDecoder; private final Habitat habitat; private final GrizzlyService grizzlyService; protected final static int MAPPING_DATA = 12; protected final static int MAPPED_ADAPTER = 13; + private final ReentrantReadWriteLock mapperLock; + // Make sure this value is always aligned with {@link org.apache.catalina.connector.CoyoteAdapter} // (@see org.apache.catalina.connector.CoyoteAdapter) private final static int MESSAGE_BYTES = 17; @@ -104,10 +110,12 @@ */ private boolean mapMultipleAdapter = false; - public ContainerMapper(GrizzlyService service, GrizzlyEmbeddedHttp embeddedHttp) { - grizzlyEmbeddedHttp = embeddedHttp; - urlDecoder = embeddedHttp.getUrlDecoder(); + public ContainerMapper(GrizzlyService service, + /*GrizzlyEmbeddedHttp embeddedHttp,*/ NetworkListener networkListener) { +// grizzlyEmbeddedHttp = embeddedHttp; +// urlDecoder = embeddedHttp.getUrlDecoder(); grizzlyService = service; + mapperLock = service.obtainMapperLock(networkListener.getName()); habitat = service.habitat; logger = GrizzlyEmbeddedHttp.logger(); @@ -117,14 +125,25 @@ } } + public void setEmbeddedHttp(GrizzlyEmbeddedHttp embeddedHttp) { + this.grizzlyEmbeddedHttp = embeddedHttp; + this.urlDecoder = embeddedHttp.getUrlDecoder(); + } + + /** * Set the default host that will be used when we map. * * @param defaultHost */ protected void setDefaultHost(String defaultHost) { + mapperLock.writeLock().lock(); + try { defaultHostName = defaultHost; + } finally { + mapperLock.writeLock().unlock(); } + } /** * Set the {@link V3Mapper} instance used for mapping the container and its associated {@link Adapter}. @@ -138,7 +157,10 @@ /** * Configure the {@link V3Mapper}. */ - protected synchronized void configureMapper() { + protected void configureMapper() { + mapperLock.writeLock().lock(); + + try { mapper.setDefaultHostName(defaultHostName); mapper.addHost(defaultHostName,new String[]{},null); mapper.addContext(defaultHostName,ROOT, @@ -146,7 +168,10 @@ new String[]{"index.html","index.htm"},null); // Container deployed have the right to override the default setting. Mapper.setAllowReplacement(true); + } finally { + mapperLock.writeLock().unlock(); } + } /** * Map the request to its associated {@link Adapter}. @@ -157,10 +182,38 @@ * @throws IOException */ @Override - public void service(Request req, Response res) throws Exception{ - MappingData mappingData = null; - try{ + public void service(Request req, Response res) throws Exception { + long transactionTimeout = grizzlyEmbeddedHttp.getTransactionTimeout(); + if (transactionTimeout < 0) { + transactionTimeout = Long.MAX_VALUE; + } + grizzlyService.getServerReadyFuture().get(transactionTimeout, TimeUnit.MILLISECONDS); + + try { + final Callable handler = lookupHandler(req, res); + handler.call(); + } catch (Exception ex) { + try { + res.setStatus(500); + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, "Internal Server error: " + req.decodedURI(), ex); + } + customizedErrorPage(req, res); + } catch (Exception ex2) { + if (logger.isLoggable(Level.WARNING)) { + logger.log(Level.WARNING, "Unable to error page", ex2); + } + } + } + } + + private Callable lookupHandler(final Request req, final Response res) throws Exception { + MappingData mappingData; + + mapperLock.readLock().lock(); + + try { // If we have only one Adapter deployed, invoke that Adapter // directly. // TODO: Not sure that will works with JRuby. @@ -169,10 +222,11 @@ // to be serviced directly by the WebContainer req.setNote(MAPPING_DATA, null); Adapter a = ((V3Mapper)mapper).getAdapter(); - if (a != null){ + if (a != null) { req.setNote(MAPPED_ADAPTER, a); - a.service(req, res); - return; + return new AdapterCallable(a, req, res); +// a.service(req, res); +// return; } } @@ -183,7 +237,7 @@ mappingData = new MappingData(); req.setNote(MAPPING_DATA, mappingData); } - Adapter adapter = null; + Adapter adapter; String uriEncoding = (String) grizzlyEmbeddedHttp.getProperty("uriEncoding"); HttpRequestURIDecoder.decode(decodedURI, urlDecoder, uriEncoding, null); @@ -206,8 +260,9 @@ mappingData.recycle(); adapter = mapUriWithSemicolon(req, decodedURI, semicolon, mappingData); } else { - super.service(req, res); - return; +// super.service(req, res); +// return; + return new SuperCallable(req, res); } } @@ -219,7 +274,8 @@ // The Adapter used for servicing static pages doesn't decode the // request by default, hence do not pass the undecoded request. if (adapter == null || adapter instanceof ContainerMapper) { - super.service(req, res); +// super.service(req, res); + return new SuperCallable(req, res); } else { req.setNote(MAPPED_ADAPTER, adapter); @@ -228,32 +284,79 @@ contextRootInfo = (ContextRootInfo) mappingData.context; } - if (contextRootInfo == null){ - adapter.service(req, res); + if (contextRootInfo == null) { +// adapter.service(req, res); + return new AdapterCallable(adapter, req, res); } else { ClassLoader cl = null; if (contextRootInfo.getContainer() instanceof ApplicationContainer){ cl = ((ApplicationContainer)contextRootInfo.getContainer()).getClassLoader(); } - hk2Dispatcher.dispath(adapter, cl, req, res); +// hk2Dispatcher.dispath(adapter, cl, req, res); + return new Hk2DispatcherCallable(adapter, cl, req, res); } } - } catch (Exception ex) { - try { - res.setStatus(500); - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Internal Server error: " + req.decodedURI(), ex); + } finally { + mapperLock.readLock().unlock(); } - customizedErrorPage(req, res); - } catch (Exception ex2) { - if (logger.isLoggable(Level.WARNING)) { - logger.log(Level.WARNING, "Unable to error page", ex2); } + + private final static class AdapterCallable implements Callable { + final Adapter adapter; + final Request req; + final Response res; + + public AdapterCallable(Adapter a, Request req, Response res) { + this.adapter = a; + this.req = req; + this.res = res; } + + @Override + public Object call() throws Exception { + adapter.service(req, res); + return null; } } - public synchronized void initializeFileURLPattern(String ext) { + private final class SuperCallable implements Callable { + final Request req; + final Response res; + + public SuperCallable(Request req, Response res) { + this.req = req; + this.res = res; + } + + @Override + public Object call() throws Exception { + ContainerMapper.super.service(req, res); + return null; + } + } + + private final class Hk2DispatcherCallable implements Callable { + final Adapter adapter; + final ClassLoader classloader; + final Request req; + final Response res; + + public Hk2DispatcherCallable(Adapter adapter, ClassLoader classloader, + Request req, Response res) { + this.adapter = adapter; + this.classloader = classloader; + this.req = req; + this.res = res; + } + + @Override + public Object call() throws Exception { + hk2Dispatcher.dispath(adapter, classloader, req, res); + return null; + } + } + + private void initializeFileURLPattern(String ext) { for (Sniffer sniffer : grizzlyService.habitat.getAllByContract(Sniffer.class)) { boolean match = false; if (sniffer.getURLPatterns() != null) { @@ -268,15 +371,23 @@ Adapter adapter = this; if (match) { adapter = grizzlyService.habitat.getComponent(SnifferAdapter.class); - ((SnifferAdapter)adapter).initialize(sniffer, this); - ContextRootInfo c= new ContextRootInfo(adapter, null); + ((SnifferAdapter) adapter).initialize(sniffer, this); + ContextRootInfo c = new ContextRootInfo(adapter, null); + mapperLock.readLock().unlock(); + mapperLock.writeLock().lock(); + try { for (String pattern : sniffer.getURLPatterns()) { - for (String host: grizzlyService.hosts ){ - mapper.addWrapper(host,ROOT, pattern,c, + for (String host : grizzlyService.hosts) { + mapper.addWrapper(host, ROOT, pattern, c, "*.jsp".equals(pattern) || "*.jspx".equals(pattern)); } } + } finally { + mapperLock.writeLock().unlock(); + mapperLock.readLock().lock(); + } + return; } } @@ -298,6 +409,9 @@ final Adapter mapUriWithSemicolon(final Request req, final MessageBytes decodedURI, int semicolonPos, final MappingData mappingData) throws Exception { + mapperLock.readLock().lock(); + + try { final CharChunk charChunk = decodedURI.getCharChunk(); final int oldEnd = charChunk.getEnd(); @@ -324,7 +438,10 @@ } finally { charChunk.setEnd(oldEnd); } + } finally { + mapperLock.readLock().unlock(); } + } Adapter map(Request req, MessageBytes decodedURI, MappingData mappingData) throws Exception { if (mappingData == null) { Index: core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java --- core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java Base (BASE) +++ core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyProxy.java Locally Modified (Based On LOCAL) @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2007-20120-2010 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007-2012 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -73,7 +73,7 @@ import java.util.logging.Logger; /** - * This clas is responsible for configuring Grizzly {@link SelectorThread}. + * This class is responsible for configuring Grizzly {@link SelectorThread}. * * @author Jerome Dochez * @author Jeanfrancois Arcand @@ -137,10 +137,22 @@ V3Mapper mapper = null; // mapper initialization now happens *before* the GrizzlyListener // is configured. This is necessary for WebSocket support (if enabled). + ContainerMapper adapter = null; if (httpProtocol != null) { + + // A bit dirty fix for issue GLASSFISH-18211 + // We have to initialize Mapper before adding it to Habitat + // @TODO rework the fix. mapper = new V3Mapper(logger); mapper.setPort(portNumber); mapper.setId(networkListener.getName()); + + adapter = new ContainerMapper( + grizzlyService, networkListener); + adapter.setMapper(mapper); + adapter.setDefaultHost(httpProtocol.getHttp().getDefaultVirtualServer() /*grizzlyListener.getDefaultVirtualServer()*/); + adapter.configureMapper(); + Inhabitant onePortMapper = new ExistingSingletonInhabitant(mapper); grizzlyService.getHabitat().addIndex(onePortMapper, Mapper.class.getName(), @@ -153,10 +165,7 @@ final GrizzlyEmbeddedHttp embeddedHttp = grizzlyListener.getEmbeddedHttp(); if (httpProtocol != null) { - final ContainerMapper adapter = new ContainerMapper(grizzlyService, embeddedHttp); - adapter.setMapper(mapper); - adapter.setDefaultHost(grizzlyListener.getDefaultVirtualServer()); - adapter.configureMapper(); + adapter.setEmbeddedHttp(embeddedHttp); embeddedHttp.setAdapter(adapter); String ct = httpProtocol.getHttp().getDefaultResponseType(); @@ -230,6 +239,7 @@ @Override public void stop() { grizzlyListener.stop(); + grizzlyService.removeMapperLock(networkListener.getName()); } @Override Index: core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java --- core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java Base (BASE) +++ core/kernel/src/main/java/com/sun/enterprise/v3/services/impl/GrizzlyService.java Locally Modified (Based On LOCAL) @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2007-2011 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2007-2012 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -52,6 +52,10 @@ import java.util.logging.Level; import java.util.logging.Logger; +import org.glassfish.api.event.EventListener; +import org.glassfish.api.event.EventTypes; +import org.glassfish.api.event.RestrictTo; + import com.sun.enterprise.config.serverbeans.Config; import com.sun.enterprise.config.serverbeans.HttpService; import com.sun.enterprise.config.serverbeans.IiopListener; @@ -68,15 +72,19 @@ import com.sun.grizzly.config.dom.NetworkListeners; import com.sun.grizzly.config.dom.Protocol; import com.sun.grizzly.tcp.Adapter; +import com.sun.grizzly.util.FutureImpl; import com.sun.grizzly.util.http.mapper.Mapper; import com.sun.logging.LogDomains; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.LinkedBlockingQueue; +import java.util.concurrent.locks.ReentrantReadWriteLock; import org.glassfish.api.FutureProvider; import org.glassfish.api.Startup; import org.glassfish.api.admin.ServerEnvironment; import org.glassfish.api.container.EndpointRegistrationException; import org.glassfish.api.container.RequestDispatcher; import org.glassfish.api.deployment.ApplicationContainer; +import org.glassfish.api.event.Events; import org.glassfish.flashlight.provider.ProbeProviderFactory; import org.jvnet.hk2.annotations.Inject; import org.jvnet.hk2.annotations.Scoped; @@ -100,7 +108,7 @@ */ @Service @Scoped(Singleton.class) -public class GrizzlyService implements Startup, RequestDispatcher, PostConstruct, PreDestroy, FutureProvider> { +public class GrizzlyService implements Startup, RequestDispatcher, PostConstruct, PreDestroy, EventListener, FutureProvider> { @Inject(name=ServerEnvironment.DEFAULT_INSTANCE_NAME) Config config; @@ -117,6 +125,9 @@ @Inject ProbeProviderFactory probeProviderFactory; + @Inject + Events events; + final Logger logger = LogDomains.getLogger(GrizzlyService.class, LogDomains.CORE_LOGGER); private final Collection proxies = new LinkedBlockingQueue(); @@ -136,6 +147,8 @@ private DynamicConfigListener configListener; + private FutureImpl serverReadyFuture = new FutureImpl(); + public GrizzlyService() { futures = new ArrayList>>(); monitoring = new GrizzlyMonitoring(); @@ -292,6 +305,30 @@ } } + private final ConcurrentHashMap mapperLockMap = + new ConcurrentHashMap(); + + private final ReentrantReadWriteLock mapperLock = new ReentrantReadWriteLock(); + + public ReentrantReadWriteLock obtainMapperLock(String name) { +// ReentrantReadWriteLock lock = mapperLockMap.get(name); +// +// if (lock == null) { +// final ReentrantReadWriteLock tmpLock = new ReentrantReadWriteLock(); +// lock = mapperLockMap.putIfAbsent(name, tmpLock); +// if (lock == null) { +// lock = tmpLock; +// } +// } +// +// return lock; + return mapperLock; + } + + void removeMapperLock(String name) { +// mapperLockMap.remove(name); + } + /** * Gets the logger. * @@ -315,6 +352,10 @@ return monitoring; } + final Future getServerReadyFuture() { + return serverReadyFuture; + } + /** * Returns the life expectency of the service * @@ -325,6 +366,12 @@ return Lifecycle.SERVER; } + @Override + public void event(@RestrictTo(EventTypes.SERVER_READY_NAME) Event event) { + if (event.is(EventTypes.SERVER_READY)) { + serverReadyFuture.setResult(Boolean.TRUE); + } + } /** * The component has been injected with any dependency and @@ -332,6 +379,8 @@ */ @Override public void postConstruct() { + events.register(this); + NetworkConfig networkConfig = config.getNetworkConfig(); configListener = new DynamicConfigListener(config); Index: web/web-glue/src/main/java/com/sun/enterprise/web/WebContainer.java --- web/web-glue/src/main/java/com/sun/enterprise/web/WebContainer.java Base (BASE) +++ web/web-glue/src/main/java/com/sun/enterprise/web/WebContainer.java Locally Modified (Based On LOCAL) @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 1997-2011 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved. * * The contents of this file are subject to the terms of either the GNU * General Public License Version 2 only ("GPL") or the Common Development @@ -125,6 +125,7 @@ import java.net.MalformedURLException; import java.text.MessageFormat; import java.util.*; +import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.logging.Level; import java.util.logging.Logger; @@ -381,6 +382,10 @@ public void postConstruct() { + ReentrantReadWriteLock mapperLock = grizzlyService.obtainMapperLock(null); + mapperLock.writeLock().lock(); + + try { createProbeProviders(); injectionMgr = habitat.getByContract(InjectionManager.class); @@ -605,7 +610,10 @@ // Restore original context classloader Thread.currentThread().setContextClassLoader(current); } + } finally { + mapperLock.writeLock().unlock(); } + } public void event(Event event) { if (event.is(Deployment.ALL_APPLICATIONS_PROCESSED)) {