/* * 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.Lifecycle; import org.apache.catalina.LifecycleEvent; import org.apache.catalina.LifecycleListener; import org.apache.catalina.core.StandardServer; import org.apache.catalina.util.ServerInfo; import org.apache.openejb.classloader.ClassLoaderConfigurer; import org.apache.openejb.config.QuickJarsTxtParser; import org.apache.openejb.loader.IO; import org.apache.openejb.loader.ProvisioningUtil; import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.util.OpenEjbVersion; import org.apache.tomee.loader.TomcatHelper; import java.io.File; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Collection; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; import static java.util.Arrays.asList; // this listener is the real tomee one (the OpenEJBListener is more tomcat oriented) // so it even changes the server info public class ServerListener implements LifecycleListener { private static final Logger LOGGER = Logger.getLogger(ServerListener.class.getName()); private static final AtomicBoolean listenerInstalled = new AtomicBoolean(false); public void lifecycleEvent(final LifecycleEvent event) { if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType()) && StandardServer.class.isInstance(event.getSource())) { installServerInfo(); } synchronized (listenerInstalled) { // only install once if (listenerInstalled.get() || !Lifecycle.AFTER_INIT_EVENT.equals(event.getType())) { return; } if (!(event.getSource() instanceof StandardServer)) { return; } try { final StandardServer server = (StandardServer) event.getSource(); TomcatHelper.setServer(server); final Properties properties = new Properties(); System.getProperties().setProperty("openejb.embedder.source", getClass().getSimpleName()); properties.setProperty("openejb.embedder.source", getClass().getSimpleName()); // if SystemInstance is already initialized, then return if (SystemInstance.isInitialized()) { return; } // set the openejb.loader property to tomcat-system properties.setProperty("openejb.loader", "tomcat-system"); // Get the value of catalina.home and set it to openejb.home final String catalinaHome = System.getProperty("catalina.home"); properties.setProperty("openejb.home", catalinaHome); //Sets system property for openejb.home System.setProperty("openejb.home", catalinaHome); //get the value of catalina.base and set it to openejb.base final String catalinaBase = System.getProperty("catalina.base"); properties.setProperty("openejb.base", catalinaBase); //Sets system property for openejb.base System.setProperty("openejb.base", catalinaBase); // System.setProperty("tomcat.version", "x.y.z.w"); // System.setProperty("tomcat.built", "mmm dd yyyy hh:mm:ss"); // set the System properties, tomcat.version, tomcat.built final ClassLoader classLoader = ServerListener.class.getClassLoader(); try { final Properties tomcatServerInfo = IO.readProperties(classLoader.getResourceAsStream("org/apache/catalina/util/ServerInfo.properties"), new Properties()); String serverNumber = tomcatServerInfo.getProperty("server.number"); if (serverNumber == null) { // Tomcat5 only has server.info final String serverInfo = tomcatServerInfo.getProperty("server.info"); if (serverInfo != null) { final int slash = serverInfo.indexOf('/'); serverNumber = serverInfo.substring(slash + 1); } } if (serverNumber != null) { System.setProperty("tomcat.version", serverNumber); } final String serverBuilt = tomcatServerInfo.getProperty("server.built"); if (serverBuilt != null) { System.setProperty("tomcat.built", serverBuilt); } } catch (final Throwable e) { // no-op } final TomcatLoader loader = new TomcatLoader(); loader.initSystemInstance(properties); // manage additional libraries try { final Collection<URL> files = new ArrayList<>(); for (final File f : ProvisioningUtil.addAdditionalLibraries()) { files.add(f.toURI().toURL()); } final ClassLoaderConfigurer configurer = QuickJarsTxtParser.parse(SystemInstance.get().getConf(QuickJarsTxtParser.FILE_NAME)); if (configurer != null) { files.addAll(asList(configurer.additionalURLs())); } if (!files.isEmpty() && URLClassLoader.class.isInstance(classLoader)) { final URLClassLoader ucl = URLClassLoader.class.cast(classLoader); try { final Method addUrl = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); final boolean acc = addUrl.isAccessible(); try { for (final URL url : files) { addUrl(ucl, addUrl, url); } } finally { addUrl.setAccessible(acc); } } catch (final Exception e) { LOGGER.log(Level.SEVERE, e.getMessage(), e); } } } catch (final IOException ex) { LOGGER.log(Level.SEVERE, ex.getMessage(), ex); } loader.initialize(properties); listenerInstalled.set(true); } catch (final Exception e) { LOGGER.log(Level.SEVERE, "TomEE Listener can't start OpenEJB", e); // e.printStackTrace(System.err); } } } private static void addUrl(final URLClassLoader ucl, final Method addUrl, final URL url) throws IllegalAccessException, InvocationTargetException, MalformedURLException { if (!addUrl.isAccessible()) { // set it lazily addUrl.setAccessible(true); } addUrl.invoke(ucl, url); } private synchronized void installServerInfo() { if (SystemInstance.get().getOptions().get("tomee.keep-server-info", false)) { return; } // force static init final String value = ServerInfo.getServerInfo(); Field field = null; boolean acc = true; try { field = ServerInfo.class.getDeclaredField("serverInfo"); acc = field.isAccessible(); final int slash = value.indexOf('/'); field.setAccessible(true); final String tomeeVersion = OpenEjbVersion.get().getVersion(); final int modifiers = field.getModifiers(); if (Modifier.isFinal(modifiers)) { // this is a bit fragile, we can surely drop this feature at some point final Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, modifiers & ~Modifier.FINAL); } field.set(null, value.substring(0, slash) + " (TomEE)" + value.substring(slash) + " (" + tomeeVersion + ")"); } catch (final Exception e) { // no-op } finally { if (field != null) { field.setAccessible(acc); } } } }