class JettyPlugin {
    private static AgentLogger LOGGER = AgentLogger.getLogger(JettyPlugin.class);

    @Init
    PluginConfiguration pluginConfiguration;

    /**
     * Plugin initialization step needs to be fine tuned. It can be intialized only AFTER the classloader
     * already knows about hotswap-agent.properties file (i.e. after webapp basic path is added to the classloader),
     * but BEFORE first servlet is initialized.
     *
     * WebXmlConfiguration seems to be good place which should work in most setups. The plugin is intialized before
     * web.xml file is processed - basic paths should be known, but nothing is processed yet.
     *
     * Application classloader is processed during plugin initialization. It means that other plugins triggered
     * on plugin init should fire as well - for jetty is important core watchResources plugin, which will handle
     * extraClassPath and watchResources configuration properties (jetty fortunately depends only on basic
     * URLClassLoader behaviour which is handled by that plugin).
     */
    @OnClassLoadEvent(classNameRegexp = "org.eclipse.jetty.webapp.WebXmlConfiguration")
    public static void patchWebXmlConfiguration(CtClass ctClass) throws NotFoundException, CannotCompileException, ClassNotFoundException {

        try {
            // after application context initialized, but before processing started
            CtMethod doStart = ctClass.getDeclaredMethod("configure");

            // init the plugin
            String src = PluginManagerInvoker.buildInitializePlugin(JettyPlugin.class, "context.getClassLoader()");
            src += PluginManagerInvoker.buildCallPluginMethod("context.getClassLoader()", JettyPlugin.class,
                    "init", "context", "java.lang.Object");

            doStart.insertBefore(src);
        } catch (NotFoundException e) {
            LOGGER.warning("org.eclipse.jetty.webapp.WebAppContext does not contain startContext method. Jetty plugin will be disabled.\n" +
                    "*** This is Ok, Jetty plugin handles only special properties ***");
            return;
        }
    }

    // same as above for older jetty versions
    @OnClassLoadEvent(classNameRegexp = "org.mortbay.jetty.webapp.WebXmlConfiguration")
    public static void patchWebXmlConfiguration6x(CtClass ctClass) throws NotFoundException, CannotCompileException, ClassNotFoundException {
        try {
            // after application context initialized, but before processing started
            CtMethod doStart = ctClass.getDeclaredMethod("configureWebApp");

            // init the plugin
            String src = PluginManagerInvoker.buildInitializePlugin(JettyPlugin.class, "getWebAppContext().getClassLoader()");
            src += PluginManagerInvoker.buildCallPluginMethod("getWebAppContext().getClassLoader()", JettyPlugin.class,
                    "init", "getWebAppContext()", "java.lang.Object");

            doStart.insertBefore(src);
        } catch (NotFoundException e) {
            LOGGER.warning("org.mortbay.jetty.webapp.WebXmlConfiguration does not contain startContext method. Jetty plugin will be disabled.\n" +
                    "*** This is Ok, Jetty plugin handles only special properties ***");
            return;
        }
    }

    /**
     * Before app context is stopped, clean the classloader (and associated plugin instance).
     */
    @OnClassLoadEvent(classNameRegexp = "(org.mortbay.jetty.webapp.WebAppContext)|(org.eclipse.jetty.webapp.WebAppContext)")
    public static void patchContextHandler6x(CtClass ctClass) throws NotFoundException, CannotCompileException, ClassNotFoundException {


        try {
            ctClass.getDeclaredMethod("doStop").insertBefore(
                    PluginManagerInvoker.buildCallCloseClassLoader("getClassLoader()")
            );
        } catch (NotFoundException e) {
            LOGGER.debug("org.eclipse.jetty.webapp.WebAppContext does not contain doStop() method. Hotswap agent will not be able to free Jetty plugin resources.");
        }
    }

    /**
     * Actual plugin initialization write plugin info and handle webappDir property.
     *
     * If the webappDir property is set, call:
     * <pre>
     *      contextHandler.setBaseResource(new ResourceCollection(
     *          new FileResource(webappDir),
     *          contextHandler.getBaseResource()
     *      ));
     *</pre>
     * @param contextHandler instance of ContextHandler - main jetty class for webapp.
     */
    public void init(Object contextHandler) {<FILL_FUNCTION_BODY>}
}


        // resolve jetty classes
        ClassLoader loader = contextHandler.getClass().getClassLoader();
        Class contextHandlerClass;
        Class resourceClass;
        Class fileResourceClass;
        Class resourceCollectionClass;

        try {
            contextHandlerClass = loader.loadClass("org.eclipse.jetty.server.handler.ContextHandler");
            resourceClass = loader.loadClass("org.eclipse.jetty.util.resource.Resource");
            fileResourceClass = loader.loadClass("org.eclipse.jetty.util.resource.FileResource");
            resourceCollectionClass = loader.loadClass("org.eclipse.jetty.util.resource.ResourceCollection");
        } catch (ClassNotFoundException e) {
            try {
                contextHandlerClass = loader.loadClass("org.mortbay.jetty.handler.ContextHandler");
                resourceClass = loader.loadClass("org.mortbay.resource.Resource");
                fileResourceClass = loader.loadClass("org.mortbay.resource.FileResource");
                resourceCollectionClass = loader.loadClass("org.mortbay.resource.ResourceCollection");
            } catch (ClassNotFoundException e1) {
                LOGGER.error("Unable to load ContextHandler class from contextHandler {} classloader", contextHandler);
                return;
            }
        }

        String version;
        // find version in Servlet package (http://docs.codehaus.org/display/JETTY/How+to+find+out+the+version+of+Jetty)
        try {
            Object server = ReflectionHelper.invoke(contextHandler, contextHandlerClass, "getServer", new Class[]{});
            version = server.getClass().getPackage().getImplementationVersion();
        } catch (Exception e) {
            version = "unknown [" + e.getMessage() + "]";
        }

        // set different resource
        URL[] webappDir = pluginConfiguration.getWebappDir();
        if (webappDir.length > 0) {
            try {
                Object originalBaseResource = ReflectionHelper.invoke(contextHandler, contextHandlerClass,
                        "getBaseResource", new Class[] {});
                Object resourceArray = Array.newInstance(resourceClass, webappDir.length + 1);
                for (int i = 0; i < webappDir.length; i++) {
                    LOGGER.debug("Watching 'webappDir' for changes: {} in Jetty webapp: {}", webappDir[i],
                            contextHandler);
                    Object fileResource = fileResourceClass.getDeclaredConstructor(URL.class).newInstance(webappDir[i]);
                    Array.set(resourceArray, i, fileResource);
                }
                Array.set(resourceArray, webappDir.length, originalBaseResource);
                Object resourceCollection = resourceCollectionClass.getDeclaredConstructor(resourceArray.getClass())
                        .newInstance(resourceArray);

                ReflectionHelper.invoke(contextHandler, contextHandlerClass, "setBaseResource",
                        new Class[] { resourceClass }, resourceCollection);
            } catch (Exception e) {
                LOGGER.error(
                        "Unable to set webappDir to directory '{}' for Jetty webapp {}. This configuration will not work.",
                        e, webappDir[0], contextHandler);
            }
        }

        LOGGER.info("Jetty plugin initialized - Jetty version '{}', context {}", version, contextHandler);
    
<no_super_class>