Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.tomee.catalina.OpenEJBContextConfig Maven / Gradle / Ivy
/*
* 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.tomee.catalina;
import org.apache.catalina.Container;
import org.apache.catalina.Context;
import org.apache.catalina.Wrapper;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.core.StandardWrapper;
import org.apache.catalina.deploy.ApplicationListener;
import org.apache.catalina.deploy.ContextResource;
import org.apache.catalina.deploy.NamingResources;
import org.apache.catalina.deploy.WebXml;
import org.apache.catalina.realm.DataSourceRealm;
import org.apache.catalina.startup.ContextConfig;
import org.apache.naming.factory.Constants;
import org.apache.naming.resources.BaseDirContext;
import org.apache.naming.resources.DirContextURLConnection;
import org.apache.naming.resources.DirContextURLStreamHandler;
import org.apache.naming.resources.ProxyDirContext;
import org.apache.openejb.OpenEJBRuntimeException;
import org.apache.openejb.assembler.classic.AppInfo;
import org.apache.openejb.assembler.classic.ClassListInfo;
import org.apache.openejb.assembler.classic.OpenEjbConfiguration;
import org.apache.openejb.assembler.classic.ParamValueInfo;
import org.apache.openejb.assembler.classic.ResourceInfo;
import org.apache.openejb.assembler.classic.ServletInfo;
import org.apache.openejb.assembler.classic.WebAppBuilder;
import org.apache.openejb.assembler.classic.WebAppInfo;
import org.apache.openejb.config.ConfigurationFactory;
import org.apache.openejb.config.NewLoaderLogic;
import org.apache.openejb.config.ServiceUtils;
import org.apache.openejb.loader.IO;
import org.apache.openejb.loader.SystemInstance;
import org.apache.openejb.util.LogCategory;
import org.apache.openejb.util.Logger;
import org.apache.openejb.util.URLs;
import org.apache.openejb.util.reflection.Reflections;
import org.apache.tomcat.util.bcel.classfile.AnnotationEntry;
import org.apache.tomcat.util.bcel.classfile.ElementValuePair;
import org.apache.tomcat.util.digester.Digester;
import org.apache.tomee.catalina.realm.TomEEDataSourceRealm;
import org.apache.tomee.common.NamingUtil;
import org.apache.tomee.common.ResourceFactory;
import org.apache.tomee.loader.TomcatHelper;
import org.apache.xbean.finder.IAnnotationFinder;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServlet;
import javax.ws.rs.core.Application;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class OpenEJBContextConfig extends ContextConfig {
private static Logger logger = Logger.getInstance(LogCategory.OPENEJB, OpenEJBContextConfig.class);
private static final String MYFACES_TOMEEM_CONTAINER_INITIALIZER = "org.apache.tomee.myfaces.TomEEMyFacesContainerInitializer";
private static final String TOMEE_MYFACES_CONTEXT_LISTENER = "org.apache.tomee.myfaces.TomEEMyFacesContextListener";
private static final String ADJUST_DATASOURCE_JNDI_NAMES = SystemInstance.get().getProperty("tomee.resources.adjust-web-xml-jndi-name", "true");
private static final File BASE = SystemInstance.get().getBase().getDirectory();
private TomcatWebAppBuilder.StandardContextInfo info;
private IAnnotationFinder finder;
private ClassLoader tempLoader;
// processAnnotationXXX is called for each folder of WEB-INF
// since we store all classes in WEB-INF we will do it only once so use this boolean to avoid multiple processing
private boolean webInfClassesAnnotationsProcessed;
public OpenEJBContextConfig(final TomcatWebAppBuilder.StandardContextInfo standardContextInfo) {
logger.debug("OpenEJBContextConfig({0})", standardContextInfo.toString());
info = standardContextInfo;
}
public void finder(final IAnnotationFinder finder, final ClassLoader tmpLoader) {
this.finder = finder;
this.tempLoader = tmpLoader;
}
@Override
public void configureStart() {
super.configureStart();
adjustDataSourceNameIfNecessary(); // doing it here to potentially factorize resource id resolution
addAddedJAXWsServices();
cleanUpRestServlets();
}
private void addAddedJAXWsServices() {
final WebAppInfo webAppInfo = info.get();
final AppInfo appInfo = info.app();
if (webAppInfo == null || appInfo == null || "false".equalsIgnoreCase(appInfo.properties.getProperty("openejb.jaxws.add-missing-servlets", "true"))) {
return;
}
try { // if no jaxws classes are here don't try anything
OpenEJBContextConfig.class.getClassLoader().loadClass("org.apache.openejb.server.webservices.WsServlet");
} catch (final ClassNotFoundException e) {
return;
} catch (final NoClassDefFoundError e) {
return;
}
for (final ServletInfo servlet : webAppInfo.servlets) {
if (!servlet.mappings.iterator().hasNext()) { // no need to do anything
continue;
}
for (final ParamValueInfo pv : servlet.initParams) {
if ("openejb-internal".equals(pv.name) && "true".equals(pv.value)) {
if (context.findChild(servlet.servletName) == null) {
final Wrapper wrapper = context.createWrapper();
wrapper.setName(servlet.servletName);
wrapper.setServletClass("org.apache.openejb.server.webservices.WsServlet");
// add servlet to context
context.addChild(wrapper);
context.addServletMapping(servlet.mappings.iterator().next(), wrapper.getName());
}
break;
}
}
}
}
private void cleanUpRestServlets() {
final WebAppInfo webAppInfo = info.get();
final AppInfo appInfo = info.app();
if (webAppInfo == null || appInfo == null || "false".equalsIgnoreCase(appInfo.properties.getProperty("openejb.jaxrs.on", "true"))) {
return;
}
final Container[] children = context.findChildren();
final Map mappedChildren = new HashMap();
if (children != null) {
// index potential rest containers by class to cleanup applications defined as servlet
for (final Container c : children) {
if (!(c instanceof StandardWrapper)) {
continue;
}
final StandardWrapper wrapper = (StandardWrapper) c;
final String appSpec = wrapper.getInitParameter("javax.ws.rs.Application");
if (appSpec != null) {
mappedChildren.put(appSpec, c);
} else {
final String app = wrapper.getInitParameter(Application.class.getName());
if (app != null) {
mappedChildren.put(app, c);
} else if (wrapper.getServletClass() == null) {
try {
if (Application.class.isAssignableFrom(
context.getLoader().getClassLoader().loadClass(wrapper.getServletName()))) {
context.removeChild(c); // remove directly since it is not in restApplications
}
} catch (final Exception e) {
// no-op
}
}
}
}
// cleanup
for (final String clazz : webAppInfo.restApplications) {
final Container child = mappedChildren.get(clazz);
try { // remove only "fake" servlets to let users use their own stuff
if (child != null) {
final String servletClass = StandardWrapper.class.cast(child).getServletClass();
if ("org.apache.openejb.server.rest.OpenEJBRestServlet".equals(servletClass) || !HttpServlet.class.isAssignableFrom(info.loader().loadClass(servletClass))) {
context.removeChild(child);
}
}
} catch (final NoClassDefFoundError e) {
context.removeChild(child);
} catch (final ClassNotFoundException e) {
context.removeChild(child);
}
}
}
}
@Override
protected void processContextConfig(final Digester digester, final URL contextXml) {
try {
super.processContextConfig(digester, replaceKnownRealmsByTomEEOnes(contextXml));
} catch (final MalformedURLException e) {
super.processContextConfig(digester, contextXml);
}
}
private URL replaceKnownRealmsByTomEEOnes(final URL contextXml) throws MalformedURLException {
return new URL(contextXml.getProtocol(), contextXml.getHost(), contextXml.getPort(), contextXml.getFile(), new URLStreamHandler() {
@Override
protected URLConnection openConnection(final URL u) throws IOException {
final URLConnection c = contextXml.openConnection();
return new URLConnection(u) {
@Override
public void connect() throws IOException {
c.connect();
}
@Override
public InputStream getInputStream() throws IOException {
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
IO.copy(c.getInputStream(), baos);
return new ByteArrayInputStream(new String(baos.toByteArray())
.replace(DataSourceRealm.class.getName(), TomEEDataSourceRealm.class.getName()
).getBytes());
}
@Override
public String toString() {
return c.toString();
}
};
}
});
}
@Override
protected void contextConfig(final Digester digester) {
final NamingResources resources;
if (context != null) {
resources = context.getNamingResources();
} else {
resources = null;
}
if (resources instanceof OpenEJBNamingResource) {
((OpenEJBNamingResource) resources).setTomcatResource(true);
}
super.contextConfig(digester);
if (resources instanceof OpenEJBNamingResource) {
((OpenEJBNamingResource) resources).setTomcatResource(false);
}
}
private void adjustDataSourceNameIfNecessary() {
if (context == null || "false".equalsIgnoreCase(ADJUST_DATASOURCE_JNDI_NAMES)) {
return;
}
final NamingResources resources = context.getNamingResources();
if (resources == null) {
return;
}
final ContextResource[] foundResources = resources.findResources();
String[] ids = null;
if (foundResources != null) {
for (final ContextResource resource : foundResources) {
if ("javax.sql.DataSource".equals(resource.getType())
&& !ResourceFactory.class.getName().equals(resource.getProperty(Constants.FACTORY))) {
String jndiName = (String) resource.getProperty("mappedName");
if (jndiName == null) {
jndiName = resource.getName();
}
if (jndiName == null) {
continue;
}
if (ids == null) {
final Properties props = new Properties();
final OpenEjbConfiguration runningConfig = SystemInstance.get().getComponent(OpenEjbConfiguration.class);
final List resourceIds = new ArrayList();
if (runningConfig != null) {
for (final ResourceInfo resourceInfo : runningConfig.facilities.resources) {
if (ConfigurationFactory.isResourceType(resourceInfo.service, resourceInfo.types, "javax.sql.DataSource")
&& ServiceUtils.implies(props, resourceInfo.properties)) {
resourceIds.add(resourceInfo.id);
}
}
}
ids = resourceIds.toArray(new String[resourceIds.size()]);
}
String mostMatchingId = null;
for (final String id : ids) {
if (id.equals(jndiName)) {
mostMatchingId = jndiName;
break;
} else if (jndiName.endsWith("/" + id) && mostMatchingId == null) {
mostMatchingId = id;
} else if (id.endsWith("/" + jndiName) && mostMatchingId == null) {
mostMatchingId = "openejb/Resource/" + id;
}
}
if (mostMatchingId != null) {
resource.setProperty("mappedName", "java:" + mostMatchingId);
resource.setProperty(NamingUtil.RESOURCE_ID, "java:" + mostMatchingId);
resource.setProperty(Constants.FACTORY, ResourceFactory.class.getName());
}
}
}
}
}
@Override
protected WebXml createWebXml() {
String prefix = "";
if (context instanceof StandardContext) {
final StandardContext standardContext = (StandardContext) context;
prefix = standardContext.getEncodedPath();
if (prefix.startsWith("/")) {
prefix = prefix.substring(1);
}
}
return new OpenEJBWebXml(prefix);
}
public class OpenEJBWebXml extends WebXml {
public static final String OPENEJB_WEB_XML_MAJOR_VERSION_PROPERTY = "openejb.web.xml.major";
private String prefix;
public OpenEJBWebXml(final String prefix) {
this.prefix = prefix;
}
@Override
public int getMajorVersion() {
return SystemInstance.get().getOptions().get(prefix + "." + OPENEJB_WEB_XML_MAJOR_VERSION_PROPERTY,
SystemInstance.get().getOptions().get(OPENEJB_WEB_XML_MAJOR_VERSION_PROPERTY, super.getMajorVersion()));
}
}
@Override
protected void webConfig() {
TomcatHelper.configureJarScanner(context);
// read the real config
super.webConfig();
if (IgnoredStandardContext.class.isInstance(context)) { // no need of jsf
return;
}
final ClassLoader classLoader = context.getLoader().getClassLoader();
// add myfaces auto-initializer if mojarra is not present
try {
classLoader.loadClass("com.sun.faces.context.SessionMap");
return;
} catch (final Throwable ignored) {
// no-op
}
try {
final Class> myfacesInitializer = Class.forName(MYFACES_TOMEEM_CONTAINER_INITIALIZER, true, classLoader);
final ServletContainerInitializer instance = (ServletContainerInitializer) myfacesInitializer.newInstance();
context.addServletContainerInitializer(instance, getJsfClasses(context));
context.addApplicationListener(new ApplicationListener(TOMEE_MYFACES_CONTEXT_LISTENER, false)); // cleanup listener
} catch (final Exception ignored) {
// no-op
} catch (final NoClassDefFoundError error) {
// no-op
}
}
private Set> getJsfClasses(final Context context) {
final WebAppBuilder builder = SystemInstance.get().getComponent(WebAppBuilder.class);
final ClassLoader cl = context.getLoader().getClassLoader();
final Map> scanned = builder.getJsfClasses().get(cl);
if (scanned == null || scanned.isEmpty()) {
return null;
}
final Set> classes = new HashSet>();
for (final Set entry : scanned.values()) {
for (final String name : entry) {
try {
classes.add(cl.loadClass(name));
} catch (final ClassNotFoundException ignored) {
logger.warning("class '" + name + "' was found but can't be loaded as a JSF class");
}
}
}
return classes;
}
@Override // called before processAnnotationsFile so using it as hook to init webInfClassesAnnotationsProcessed
protected void processServletContainerInitializers(final ServletContext ctx) {
webInfClassesAnnotationsProcessed = false;
try {
super.processServletContainerInitializers(ctx);
final Iterator>>> iterator = initializerClassMap.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry>> entry = iterator.next();
final ServletContainerInitializer sci = entry.getKey();
final String classname = sci.getClass().getName();
if (classname.equals("org.apache.myfaces.ee6.MyFacesContainerInitializer")
|| classname.equals("org.springframework.web.SpringServletContainerInitializer")) {
for (final Map.Entry, Set> scanning : typeInitializerMap.entrySet()) {
final Set scis = scanning.getValue();
if (scis != null && scis.contains(sci)) {
scis.remove(sci);
}
}
iterator.remove();
}
}
final ClassLoader loader = context.getLoader().getClassLoader();
// spring-web (not scanned)
try {
final Class> initializer = Class.forName("org.springframework.web.SpringServletContainerInitializer", true, loader);
final ServletContainerInitializer instance = (ServletContainerInitializer) initializer.newInstance();
typeInitializerMap.put(Class.forName("org.springframework.web.WebApplicationInitializer", true, loader), Collections.singleton(instance));
initializerClassMap.put(instance, new HashSet>());
} catch (final Exception ignored) {
// no-op
} catch (final NoClassDefFoundError error) {
// no-op
}
// scanned SCIs
if (typeInitializerMap.size() > 0 && finder != null) {
for (final Map.Entry, Set> entry : typeInitializerMap.entrySet()) {
if (entry.getValue() == null || entry.getValue().isEmpty()) {
continue;
}
final Class> annotation = entry.getKey();
for (final ServletContainerInitializer sci : entry.getValue()) {
if (annotation.isAnnotation()) {
try {
final Class extends Annotation> reloadedAnnotation = Class.class.cast(tempLoader.loadClass(annotation.getName()));
addClassesWithRightLoader(loader, sci, finder.findAnnotatedClasses(reloadedAnnotation));
} catch (final Throwable th) {
// no-op
}
} else {
try {
final Class> reloadedClass = tempLoader.loadClass(annotation.getName());
final List> implementations;
if (annotation.isInterface()) {
implementations = List.class.cast(finder.findImplementations(reloadedClass));
} else {
implementations = List.class.cast(finder.findSubclasses(reloadedClass));
}
addClassesWithRightLoader(loader, sci, implementations);
} catch (final Throwable th) {
// no-op
}
}
}
}
}
// done
finder = null;
tempLoader = null;
} catch (final RuntimeException e) { // if exception occurs we have to clear the threadlocal
webInfClassesAnnotationsProcessed = false;
throw e;
}
}
@Override // called after processAnnotationsXX so using it as hook to reset webInfClassesAnnotationsProcessed
protected void processAnnotations(final Set fragments, final boolean handlesTypesOnly) {
webInfClassesAnnotationsProcessed = false;
super.processAnnotations(fragments, handlesTypesOnly);
}
@Override
protected void processAnnotationsFile(final File file, final WebXml fragment, final boolean handlesTypesOnly) {
try {
if (NewLoaderLogic.skip(file.toURI().toURL())) {
return;
}
} catch (final MalformedURLException e) {
// no-op: let it be
}
final WebAppInfo webAppInfo = info.get();
if (webAppInfo == null) {
super.processAnnotationsFile(file, fragment, handlesTypesOnly);
return;
}
internalProcessAnnotations(file, webAppInfo, fragment);
}
@Override
protected void processAnnotationsUrl(final URL currentUrl, final WebXml fragment, final boolean handlesTypeOnly) {
if (NewLoaderLogic.skip(currentUrl)) { // we potentially see all common loader urls
return;
}
final WebAppInfo webAppInfo = info.get();
if (webAppInfo == null) {
super.processAnnotationsUrl(currentUrl, fragment, handlesTypeOnly);
return;
}
File currentUrlAsFile;
try {
currentUrlAsFile = URLs.toFile(currentUrl);
} catch (final IllegalArgumentException iae) {
if ("jndi".equals(currentUrl.getProtocol())) {
String file = currentUrl.getFile();
try {
final URLConnection connection = currentUrl.openConnection();
if (connection instanceof DirContextURLConnection) {
final DirContextURLStreamHandler handler = DirContextURLStreamHandler.class.cast(Reflections.get(currentUrl, "handler"));
final ProxyDirContext dirContext = ProxyDirContext.class.cast(Reflections.get(handler, "context"));
final String host = String.class.cast(Reflections.get(dirContext, "hostName"));
final String contextPath = String.class.cast(Reflections.get(dirContext, "contextPath"));
final Object context = Reflections.get(dirContext, "dirContext");
if (BaseDirContext.class.isInstance(context)) {
file = file.replace("/" + host + contextPath, BaseDirContext.class.cast(context).getDocBase());
} else {
throw new OpenEJBRuntimeException("Context not supported: " + context);
}
currentUrlAsFile = new File(file);
} else {
throw new OpenEJBRuntimeException("can't find webapp [" + webAppInfo.contextRoot + "], connection is not a DirContextURLConnection " + connection);
}
} catch (final Exception ex) {
throw new OpenEJBRuntimeException("can't find webapp [" + webAppInfo.contextRoot + "]", ex);
}
} else {
throw new OpenEJBRuntimeException("protocol not supported '" + currentUrl.getProtocol() + "'");
}
}
internalProcessAnnotations(currentUrlAsFile, webAppInfo, fragment);
}
private void internalProcessAnnotations(final File currentUrlAsFile, final WebAppInfo webAppInfo, final WebXml fragment) {
for (final ClassListInfo webAnnotated : webAppInfo.webAnnotatedClasses) {
try {
if (!isIncludedIn(webAnnotated.name, currentUrlAsFile)) {
continue;
}
internalProcessAnnotationsStream(webAnnotated.list, fragment, false);
} catch (final MalformedURLException e) {
throw new IllegalArgumentException(e);
}
}
}
private void addClassesWithRightLoader(final ClassLoader loader, final ServletContainerInitializer sci, final List> implementations) throws ClassNotFoundException {
final Set> classes = initializerClassMap.get(sci);
for (final Class> c : implementations) {
classes.add(loader.loadClass(c.getName()));
}
}
private void internalProcessAnnotationsStream(final Collection urls, final WebXml fragment, final boolean handlesTypeOnly) {
for (final String url : urls) {
InputStream is = null;
try {
is = new URL(url).openStream();
processAnnotationsStream(is, fragment, handlesTypeOnly);
} catch (final MalformedURLException e) {
throw new IllegalArgumentException(e);
} catch (final IOException e) {
throw new IllegalArgumentException(e);
} finally {
IO.close(is);
}
}
}
@Override
protected void processAnnotationWebServlet(final String className, final AnnotationEntry ae, final WebXml fragment) {
try {
super.processAnnotationWebServlet(className, ae, fragment);
} catch (final IllegalArgumentException iae) {
// otherwise TCKs are not passing, hope to be able to let it with next TCK versions
String[] urlPatterns = null;
for (final ElementValuePair evp : ae.getElementValuePairs()) {
final String name = evp.getNameString();
if ("value".equals(name) || "urlPatterns".equals(name)) {
urlPatterns = processAnnotationsStringArray(evp.getValue());
break;
}
}
if (urlPatterns != null) {
for (final String pattern : urlPatterns) {
if (fragment.getServletMappings().containsKey(pattern)) {
logger.warning(iae.getMessage(), iae);
return;
}
}
}
throw iae;
}
}
private boolean isIncludedIn(final String filePath, final File classAsFile) throws MalformedURLException {
final File file = URLs.toFile(new URL(filePath));
File current = classAsFile;
while (current != null && current.exists()) {
if (current.equals(file)) {
final File parent = current.getParentFile();
if ("classes".equals(current.getName()) && parent != null && "WEB-INF".equals(parent.getName())) {
if (webInfClassesAnnotationsProcessed) {
return false;
}
webInfClassesAnnotationsProcessed = true;
return true;
}
return true;
}
current = current.getParentFile();
if (BASE.equals(current)) {
return false;
}
}
return false;
/* classAsFile s
if (current != null && current.isDirectory()) {
return false;
}
return (classAsFile == null
|| !classAsFile.getName().endsWith(".jar") || !file.getName().endsWith(".jar"))
&& !webInf;
*/
}
}