All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jetty.ee8.quickstart.QuickStartDescriptorProcessor Maven / Gradle / Ivy

There is a newer version: 2.0.31
Show newest version
//
// ========================================================================
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License v. 2.0 which is available at
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
//
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
// ========================================================================
//
package org.eclipse.jetty.ee8.quickstart;

import java.io.Closeable;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletContext;
import org.eclipse.jetty.ee8.annotations.AnnotationConfiguration;
import org.eclipse.jetty.ee8.servlet.ServletContainerInitializerHolder;
import org.eclipse.jetty.ee8.servlet.ServletMapping;
import org.eclipse.jetty.ee8.webapp.DefaultsDescriptor;
import org.eclipse.jetty.ee8.webapp.Descriptor;
import org.eclipse.jetty.ee8.webapp.IterativeDescriptorProcessor;
import org.eclipse.jetty.ee8.webapp.MetaInfConfiguration;
import org.eclipse.jetty.ee8.webapp.WebAppContext;
import org.eclipse.jetty.util.IO;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.resource.AttributeNormalizer;
import org.eclipse.jetty.util.resource.Resource;
import org.eclipse.jetty.util.resource.ResourceFactory;
import org.eclipse.jetty.util.resource.Resources;
import org.eclipse.jetty.xml.XmlParser;

/**
 * QuickStartDescriptorProcessor
 *
 * Handle  extended elements for quickstart-web.xml
 */
public class QuickStartDescriptorProcessor extends IterativeDescriptorProcessor implements Closeable {

    private String _originAttributeName = null;

    // possibly mounted resources that need to be cleaned up eventually
    private ResourceFactory.Closeable _resourceFactory = ResourceFactory.closeable();

    /**
     */
    public QuickStartDescriptorProcessor() {
        try {
            registerVisitor("context-param", this.getClass().getMethod("visitContextParam", __signature));
            registerVisitor("servlet-mapping", this.getClass().getMethod("visitServletMapping", __signature));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }

    @Override
    public void start(WebAppContext context, Descriptor descriptor) {
        _originAttributeName = context.getInitParameter(QuickStartGeneratorConfiguration.ORIGIN);
    }

    @Override
    public void end(WebAppContext context, Descriptor descriptor) {
        _originAttributeName = null;
    }

    @Override
    public void close() {
        IO.close(_resourceFactory);
        _resourceFactory = null;
    }

    /**
     * Process a servlet-mapping element
     *
     * @param context the webapp
     * @param descriptor the xml file to process
     * @param node the servlet-mapping element in the xml file to process
     */
    public void visitServletMapping(WebAppContext context, Descriptor descriptor, XmlParser.Node node) {
        String servletName = node.getString("servlet-name", false, true);
        ServletMapping mapping = null;
        ServletMapping[] mappings = context.getServletHandler().getServletMappings();
        if (mappings != null) {
            for (ServletMapping m : mappings) {
                if (servletName.equals(m.getServletName())) {
                    mapping = m;
                    break;
                }
            }
        }
        if (mapping != null && _originAttributeName != null) {
            String origin = node.getAttribute(_originAttributeName);
            if (!StringUtil.isBlank(origin) && origin.startsWith(DefaultsDescriptor.class.getSimpleName()))
                mapping.setFromDefaultDescriptor(true);
        }
    }

    /**
     * Process a context-param element
     *
     * @param context the webapp
     * @param descriptor the xml file to process
     * @param node the context-param node in the xml file
     * @throws Exception if some resources cannot be read
     */
    public void visitContextParam(WebAppContext context, Descriptor descriptor, XmlParser.Node node) throws Exception {
        String name = node.getString("param-name", false, true);
        String value = node.getString("param-value", false, true);
        List values = new ArrayList<>();
        // extract values
        switch(name) {
            case QuickStartGeneratorConfiguration.ORIGIN ->
                {
                    //value already contains what we need
                }
            case ServletContext.ORDERED_LIBS, AnnotationConfiguration.CONTAINER_INITIALIZERS, MetaInfConfiguration.METAINF_TLDS, MetaInfConfiguration.METAINF_RESOURCES ->
                {
                    context.removeAttribute(name);
                    for (Iterator i = QuotedStringTokenizer.CSV.tokenize(value); i.hasNext(); ) {
                        values.add(i.next());
                    }
                }
            default ->
                values.add(value);
        }
        AttributeNormalizer normalizer = new AttributeNormalizer(context.getBaseResource());
        // handle values
        switch(name) {
            case QuickStartGeneratorConfiguration.ORIGIN ->
                context.setAttribute(QuickStartGeneratorConfiguration.ORIGIN, value);
            case ServletContext.ORDERED_LIBS ->
                {
                    List libs = new ArrayList<>();
                    Object o = context.getAttribute(ServletContext.ORDERED_LIBS);
                    if (o instanceof Collection)
                        libs.addAll((Collection) o);
                    libs.addAll(values);
                    if (libs.size() > 0)
                        context.setAttribute(ServletContext.ORDERED_LIBS, libs);
                }
            case AnnotationConfiguration.CONTAINER_INITIALIZERS ->
                {
                    for (String s : values) {
                        visitServletContainerInitializerHolder(context, ServletContainerInitializerHolder.fromString(Thread.currentThread().getContextClassLoader(), s));
                    }
                }
            case MetaInfConfiguration.METAINF_TLDS ->
                {
                    List tlds = new ArrayList<>();
                    Object o = context.getAttribute(MetaInfConfiguration.METAINF_TLDS);
                    if (o instanceof Collection)
                        tlds.addAll((Collection) o);
                    for (String i : values) {
                        String entry = normalizer.expand(i);
                        tlds.add(context.getResourceFactory().newResource(entry).getURI().toURL());
                    }
                    //empty list signals that tlds were prescanned but none found.
                    //a missing METAINF_TLDS attribute means that prescanning was not done.
                    context.setAttribute(MetaInfConfiguration.METAINF_TLDS, tlds);
                }
            case MetaInfConfiguration.METAINF_RESOURCES ->
                {
                    List uris = values.stream().map(normalizer::expand).map(context.getResourceFactory()::newResource).map(Resource::getURI).toList();
                    for (URI uri : uris) {
                        Resource r = _resourceFactory.newResource(uri);
                        if (Resources.missing(r))
                            throw new IllegalArgumentException("Resource not found: " + r);
                        visitMetaInfResource(context, r);
                    }
                }
            default ->
                {
                }
        }
    }

    /**
     * Ensure the ServletContainerInitializerHolder will be started by adding it to the context.
     *
     * @param context the context to which to add the ServletContainerInitializerHolder
     * @param sciHolder the ServletContainerInitializerHolder
     */
    public void visitServletContainerInitializerHolder(WebAppContext context, ServletContainerInitializerHolder sciHolder) {
        if (sciHolder == null)
            return;
        context.addServletContainerInitializer(sciHolder);
    }

    @SuppressWarnings("unchecked")
    public void visitMetaInfResource(WebAppContext context, Resource dir) {
        Collection metaInfResources = (Collection) context.getAttribute(MetaInfConfiguration.METAINF_RESOURCES);
        if (metaInfResources == null) {
            metaInfResources = new HashSet();
            context.setAttribute(MetaInfConfiguration.METAINF_RESOURCES, metaInfResources);
        }
        metaInfResources.add(dir);
        //also add to base resource of webapp
        List collection = new ArrayList<>();
        collection.add(context.getBaseResource());
        collection.addAll(metaInfResources);
        context.setBaseResource(ResourceFactory.combine(collection));
    }
}