blob: a716a6952d26fcf3028f2e4aa81b2faa5932e0a9 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.catalina.connector;
import org.apache.catalina.Container;
import org.apache.catalina.ContainerEvent;
import org.apache.catalina.ContainerListener;
import org.apache.catalina.Context;
import org.apache.catalina.Engine;
import org.apache.catalina.Host;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.LifecycleListener;
import org.apache.catalina.LifecycleState;
import org.apache.catalina.Wrapper;
import org.apache.catalina.util.LifecycleMBeanBase;
import org.apache.juli.logging.Log;
import org.apache.juli.logging.LogFactory;
import org.apache.tomcat.util.http.mapper.Mapper;
import org.apache.tomcat.util.res.StringManager;
/**
* Mapper listener.
*
* @author Remy Maucherat
* @author Costin Manolache
*/
public class MapperListener extends LifecycleMBeanBase
implements ContainerListener, LifecycleListener {
private static final Log log = LogFactory.getLog(MapperListener.class);
// ----------------------------------------------------- Instance Variables
/**
* Associated mapper.
*/
private Mapper mapper = null;
/**
* Associated connector
*/
private Connector connector = null;
/**
* The string manager for this package.
*/
private static final StringManager sm =
StringManager.getManager(Constants.Package);
/**
* The domain (effectively the engine) this mapper is associated with
*/
private String domain = null;
// ----------------------------------------------------------- Constructors
/**
* Create mapper listener.
*/
public MapperListener(Mapper mapper, Connector connector) {
this.mapper = mapper;
this.connector = connector;
}
// --------------------------------------------------------- Public Methods
public String getConnectorName() {
return this.connector.toString();
}
// ------------------------------------------------------- Lifecycle Methods
@Override
public void startInternal() throws LifecycleException {
setState(LifecycleState.STARTING);
// Find any components that have already been initialized since the
// MBean listener won't be notified as those components will have
// already registered their MBeans
findDefaultHost();
Engine engine = (Engine) connector.getService().getContainer();
addListeners(engine);
Container[] conHosts = engine.findChildren();
for (Container conHost : conHosts) {
Host host = (Host) conHost;
if (!LifecycleState.NEW.equals(host.getState())) {
// Registering the host will register the context and wrappers
registerHost(host);
}
}
}
@Override
public void stopInternal() throws LifecycleException {
setState(LifecycleState.STOPPING);
}
@Override
protected String getDomainInternal() {
// Should be the same as the connector
return connector.getDomainInternal();
}
@Override
protected String getObjectNameKeyProperties() {
// Same as connector but Mapper rather than Connector
return connector.createObjectNameKeyProperties("Mapper");
}
// --------------------------------------------- Container Listener methods
@Override
public void containerEvent(ContainerEvent event) {
if (event.getType() == Container.ADD_CHILD_EVENT) {
Container child = (Container) event.getData();
addListeners(child);
// If child is started then it is too late for life-cycle listener
// to register the child so register it here
if (child.getState().isAvailable()) {
if (child instanceof Host) {
registerHost((Host) child);
} else if (child instanceof Context) {
registerContext((Context) child);
} else if (child instanceof Wrapper) {
registerWrapper((Wrapper) child);
}
}
} else if (event.getType() == Container.REMOVE_CHILD_EVENT) {
Container child = (Container) event.getData();
removeListeners(child);
// No need to unregister - life-cycle listener will handle this when
// the child stops
} else if (event.getType() == Host.ADD_ALIAS_EVENT) {
// Handle dynamically adding host aliases
mapper.addHostAlias(((Host) event.getSource()).getName(),
event.getData().toString());
} else if (event.getType() == Host.REMOVE_ALIAS_EVENT) {
// Handle dynamically removing host aliases
mapper.removeHostAlias(event.getData().toString());
} else if (event.getType() == Wrapper.ADD_MAPPING_EVENT) {
// Handle dynamically adding wrappers
Wrapper wrapper = (Wrapper) event.getSource();
Context context = (Context) wrapper.getParent();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String version = ((Context) wrapper.getParent()).getWebappVersion();
String hostName = context.getParent().getName();
String wrapperName = wrapper.getName();
String mapping = (String) event.getData();
boolean jspWildCard = ("jsp".equals(wrapperName)
&& mapping.endsWith("/*"));
mapper.addWrapper(hostName, contextPath, version, mapping, wrapper,
jspWildCard, context.isResourceOnlyServlet(wrapperName));
} else if (event.getType() == Wrapper.REMOVE_MAPPING_EVENT) {
// Handle dynamically removing wrappers
Wrapper wrapper = (Wrapper) event.getSource();
String contextPath = ((Context) wrapper.getParent()).getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String version = ((Context) wrapper.getParent()).getWebappVersion();
String hostName = wrapper.getParent().getParent().getName();
String mapping = (String) event.getData();
mapper.removeWrapper(hostName, contextPath, version, mapping);
} else if (event.getType() == Context.ADD_WELCOME_FILE_EVENT) {
// Handle dynamically adding welcome files
Context context = (Context) event.getSource();
String hostName = context.getParent().getName();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String welcomeFile = (String) event.getData();
mapper.addWelcomeFile(hostName, contextPath,
context.getWebappVersion(), welcomeFile);
} else if (event.getType() == Context.REMOVE_WELCOME_FILE_EVENT) {
// Handle dynamically removing welcome files
Context context = (Context) event.getSource();
String hostName = context.getParent().getName();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String welcomeFile = (String) event.getData();
mapper.removeWelcomeFile(hostName, contextPath,
context.getWebappVersion(), welcomeFile);
} else if (event.getType() == Context.CLEAR_WELCOME_FILES_EVENT) {
// Handle dynamically clearing welcome files
Context context = (Context) event.getSource();
String hostName = context.getParent().getName();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
mapper.clearWelcomeFiles(hostName, contextPath,
context.getWebappVersion());
}
}
// ------------------------------------------------------ Protected Methods
private void findDefaultHost() {
Engine engine = (Engine) connector.getService().getContainer();
String defaultHost = engine.getDefaultHost();
boolean found = false;
if (defaultHost != null && defaultHost.length() >0) {
Container[] containers = engine.findChildren();
for (Container container : containers) {
Host host = (Host) container;
if (defaultHost.equalsIgnoreCase(host.getName())) {
found = true;
break;
}
String[] aliases = host.findAliases();
for (String alias : aliases) {
if (defaultHost.equalsIgnoreCase(alias)) {
found = true;
break;
}
}
}
}
if(found) {
mapper.setDefaultHostName(defaultHost);
} else {
log.warn(sm.getString("mapperListener.unknownDefaultHost",
defaultHost, connector));
}
}
/**
* Register host.
*/
private void registerHost(Host host) {
String[] aliases = host.findAliases();
mapper.addHost(host.getName(), aliases, host);
for (Container container : host.findChildren()) {
if (container.getState().isAvailable()) {
registerContext((Context) container);
}
}
if(log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerHost",
host.getName(), domain, connector));
}
}
/**
* Unregister host.
*/
private void unregisterHost(Host host) {
String hostname = host.getName();
mapper.removeHost(hostname);
if(log.isDebugEnabled())
log.debug(sm.getString("mapperListener.unregisterHost", hostname,
domain, connector));
}
/**
* Unregister wrapper.
*/
private void unregisterWrapper(Wrapper wrapper) {
String contextPath = ((Context) wrapper.getParent()).getPath();
String wrapperName = wrapper.getName();
if ("/".equals(contextPath)) {
contextPath = "";
}
String version = ((Context) wrapper.getParent()).getWebappVersion();
String hostName = wrapper.getParent().getParent().getName();
String[] mappings = wrapper.findMappings();
for (String mapping : mappings) {
mapper.removeWrapper(hostName, contextPath, version, mapping);
}
if(log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.unregisterWrapper",
wrapperName, contextPath, connector));
}
}
/**
* Register context.
*/
private void registerContext(Context context) {
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
Container host = context.getParent();
javax.naming.Context resources = context.getResources();
String[] welcomeFiles = context.findWelcomeFiles();
mapper.addContextVersion(host.getName(), host, contextPath,
context.getWebappVersion(), context, welcomeFiles, resources);
for (Container container : context.findChildren()) {
registerWrapper((Wrapper) container);
}
if(log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerContext",
contextPath, connector));
}
}
/**
* Unregister context.
*/
private void unregisterContext(Context context) {
// Don't un-map a context that is paused
if (context.getPaused()){
return;
}
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String hostName = context.getParent().getName();
if(log.isDebugEnabled())
log.debug(sm.getString("mapperListener.unregisterContext",
contextPath, connector));
mapper.removeContextVersion(hostName, contextPath,
context.getWebappVersion());
}
/**
* Register wrapper.
*/
private void registerWrapper(Wrapper wrapper) {
String wrapperName = wrapper.getName();
Context context = (Context) wrapper.getParent();
String contextPath = context.getPath();
if ("/".equals(contextPath)) {
contextPath = "";
}
String version = ((Context) wrapper.getParent()).getWebappVersion();
String hostName = context.getParent().getName();
String[] mappings = wrapper.findMappings();
for (String mapping : mappings) {
boolean jspWildCard = (wrapperName.equals("jsp")
&& mapping.endsWith("/*"));
mapper.addWrapper(hostName, contextPath, version, mapping, wrapper,
jspWildCard,
context.isResourceOnlyServlet(wrapperName));
}
if(log.isDebugEnabled()) {
log.debug(sm.getString("mapperListener.registerWrapper",
wrapperName, contextPath, connector));
}
}
@Override
public void lifecycleEvent(LifecycleEvent event) {
if (event.getType() == Lifecycle.AFTER_START_EVENT) {
Object obj = event.getSource();
if (obj instanceof Wrapper) {
registerWrapper((Wrapper) obj);
} else if (obj instanceof Context) {
registerContext((Context) obj);
} else if (obj instanceof Host) {
registerHost((Host) obj);
}
} else if (event.getType() == Lifecycle.BEFORE_STOP_EVENT) {
Object obj = event.getSource();
if (obj instanceof Wrapper) {
unregisterWrapper((Wrapper) obj);
} else if (obj instanceof Context) {
unregisterContext((Context) obj);
} else if (obj instanceof Host) {
unregisterHost((Host) obj);
}
}
}
/**
* Add this mapper to the container and all child containers
*
* @param container
*/
private void addListeners(Container container) {
container.addContainerListener(this);
container.addLifecycleListener(this);
for (Container child : container.findChildren()) {
addListeners(child);
}
}
/**
* Remove this mapper from the container and all child containers
*
* @param container
*/
private void removeListeners(Container container) {
container.removeContainerListener(this);
container.removeLifecycleListener(this);
for (Container child : container.findChildren()) {
removeListeners(child);
}
}
}