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

org.eclipse.jetty.quickstart.QuickStartDescriptorGenerator Maven / Gradle / Ivy

//
//  ========================================================================
//  Copyright (c) 1995-2022 Mort Bay Consulting Pty Ltd and others.
//  ------------------------------------------------------------------------
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

package org.eclipse.jetty.quickstart;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.servlet.DispatcherType;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletContext;
import javax.servlet.SessionCookieConfig;
import javax.servlet.SessionTrackingMode;
import javax.servlet.descriptor.JspPropertyGroupDescriptor;
import javax.servlet.descriptor.TaglibDescriptor;

import org.eclipse.jetty.annotations.AnnotationConfiguration;
import org.eclipse.jetty.http.MimeTypes;
import org.eclipse.jetty.plus.annotation.LifeCycleCallback;
import org.eclipse.jetty.plus.annotation.LifeCycleCallbackCollection;
import org.eclipse.jetty.security.ConstraintAware;
import org.eclipse.jetty.security.ConstraintMapping;
import org.eclipse.jetty.security.SecurityHandler;
import org.eclipse.jetty.security.authentication.FormAuthenticator;
import org.eclipse.jetty.servlet.ErrorPageErrorHandler;
import org.eclipse.jetty.servlet.FilterHolder;
import org.eclipse.jetty.servlet.FilterMapping;
import org.eclipse.jetty.servlet.ListenerHolder;
import org.eclipse.jetty.servlet.ServletContextHandler.JspConfig;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.eclipse.jetty.servlet.ServletMapping;
import org.eclipse.jetty.util.QuotedStringTokenizer;
import org.eclipse.jetty.util.StringUtil;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;
import org.eclipse.jetty.util.security.Constraint;
import org.eclipse.jetty.webapp.MetaData;
import org.eclipse.jetty.webapp.MetaData.OriginInfo;
import org.eclipse.jetty.webapp.MetaInfConfiguration;
import org.eclipse.jetty.webapp.WebAppContext;
import org.eclipse.jetty.xml.XmlAppendable;

/**
 * QuickStartDescriptorGenerator
 * 

* Generate an effective web.xml from a WebAppContext, including all components * from web.xml, web-fragment.xmls annotations etc. *

* If generating quickstart for a different java platform than the current running * platform, then the org.eclipse.jetty.annotations.javaTargetPlatform attribute * should be set on the Context with the platform number of the target JVM (eg 8). */ public class QuickStartDescriptorGenerator { private static final Logger LOG = Log.getLogger(QuickStartDescriptorGenerator.class); public static final String ORIGIN = "org.eclipse.jetty.originAttribute"; public static final String DEFAULT_QUICKSTART_DESCRIPTOR_NAME = "quickstart-web.xml"; public static final String DEFAULT_ORIGIN_ATTRIBUTE_NAME = "origin"; protected WebAppContext _webApp; protected String _extraXML; protected String _originAttribute; protected boolean _generateOrigin; protected int _count; /** * @param w the source WebAppContext * @param extraXML any extra xml snippet to append * @param originAttribute param value to use for the context param origin attribute * @param generateOrigin true to generate the origin attribute */ public QuickStartDescriptorGenerator(WebAppContext w, String extraXML, String originAttribute, boolean generateOrigin) { _webApp = w; _extraXML = extraXML; _originAttribute = (StringUtil.isBlank(originAttribute) ? DEFAULT_ORIGIN_ATTRIBUTE_NAME : originAttribute); _generateOrigin = generateOrigin || LOG.isDebugEnabled(); _count = 0; } /** * Perform the generation of the xml file * * @param stream the stream to generate the quickstart-web.xml to * @throws IOException if unable to generate the quickstart-web.xml * @throws FileNotFoundException if unable to find the file */ public void generateQuickStartWebXml(OutputStream stream) throws FileNotFoundException, IOException { if (_webApp == null) throw new IllegalStateException("No webapp for quickstart generation"); if (stream == null) throw new IllegalStateException("No output for quickstart generation"); _webApp.getMetaData().getOrigins(); if (_webApp.getBaseResource() == null) throw new IllegalArgumentException("No base resource for " + this); LOG.info("Quickstart generating"); XmlAppendable out = new XmlAppendable(stream, "UTF-8"); MetaData md = _webApp.getMetaData(); Map webappAttr = new HashMap<>(); webappAttr.put("xmlns", "http://xmlns.jcp.org/xml/ns/javaee"); webappAttr.put("xmlns:xsi", "http://www.w3.org/2001/XMLSchema-instance"); webappAttr.put("xsi:schemaLocation", "http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"); webappAttr.put("metadata-complete", "true"); webappAttr.put("version", "3.1"); out.openTag("web-app", webappAttr); if (_webApp.getDisplayName() != null) out.tag("display-name", _webApp.getDisplayName()); // Set some special context parameters // The location of the war file on disk AttributeNormalizer normalizer = new AttributeNormalizer(_webApp.getBaseResource()); // The library order addContextParamFromAttribute(out, ServletContext.ORDERED_LIBS); //the servlet container initializers addContextParamFromAttribute(out, AnnotationConfiguration.CONTAINER_INITIALIZERS); //the tlds discovered addContextParamFromAttribute(out, MetaInfConfiguration.METAINF_TLDS, normalizer); //the META-INF/resources discovered addContextParamFromAttribute(out, MetaInfConfiguration.METAINF_RESOURCES, normalizer); //add the name of the origin attribute, if it is being used if (_generateOrigin) { out.openTag("context-param") .tag("param-name", ORIGIN) .tag("param-value", _originAttribute) .closeTag(); } // init params for (String p : _webApp.getInitParams().keySet()) { out.openTag("context-param", origin(md, "context-param." + p)) .tag("param-name", p) .tag("param-value", _webApp.getInitParameter(p)) .closeTag(); } if (_webApp.getServletHandler().getListeners() != null) for (ListenerHolder e : _webApp.getServletHandler().getListeners()) { out.openTag("listener", origin(md, e.getClassName() + ".listener")) .tag("listener-class", e.getClassName()) .closeTag(); } ServletHandler servlets = _webApp.getServletHandler(); if (servlets.getFilters() != null) { for (FilterHolder holder : servlets.getFilters()) { outholder(out, md, holder); } } if (servlets.getFilterMappings() != null) { for (FilterMapping mapping : servlets.getFilterMappings()) { out.openTag("filter-mapping"); out.tag("filter-name", mapping.getFilterName()); if (mapping.getPathSpecs() != null) for (String s : mapping.getPathSpecs()) { out.tag("url-pattern", s); } if (mapping.getServletNames() != null) for (String n : mapping.getServletNames()) { out.tag("servlet-name", n); } if (!mapping.isDefaultDispatches()) { if (mapping.appliesTo(DispatcherType.REQUEST)) out.tag("dispatcher", "REQUEST"); if (mapping.appliesTo(DispatcherType.ASYNC)) out.tag("dispatcher", "ASYNC"); if (mapping.appliesTo(DispatcherType.ERROR)) out.tag("dispatcher", "ERROR"); if (mapping.appliesTo(DispatcherType.FORWARD)) out.tag("dispatcher", "FORWARD"); if (mapping.appliesTo(DispatcherType.INCLUDE)) out.tag("dispatcher", "INCLUDE"); } out.closeTag(); } } if (servlets.getServlets() != null) { for (ServletHolder holder : servlets.getServlets()) { outholder(out, md, holder); } } if (servlets.getServletMappings() != null) { for (ServletMapping mapping : servlets.getServletMappings()) { out.openTag("servlet-mapping", origin(md, mapping.getServletName() + ".servlet.mappings")); out.tag("servlet-name", mapping.getServletName()); if (mapping.getPathSpecs() != null) for (String s : mapping.getPathSpecs()) { out.tag("url-pattern", s); } out.closeTag(); } } // Security elements SecurityHandler security = _webApp.getSecurityHandler(); if (security != null && (security.getRealmName() != null || security.getAuthMethod() != null)) { out.openTag("login-config"); if (security.getAuthMethod() != null) out.tag("auth-method", origin(md, "auth-method"), security.getAuthMethod()); if (security.getRealmName() != null) out.tag("realm-name", origin(md, "realm-name"), security.getRealmName()); if (Constraint.__FORM_AUTH.equalsIgnoreCase(security.getAuthMethod())) { out.openTag("form-login-config"); out.tag("form-login-page", origin(md, "form-login-page"), security.getInitParameter(FormAuthenticator.__FORM_LOGIN_PAGE)); out.tag("form-error-page", origin(md, "form-error-page"), security.getInitParameter(FormAuthenticator.__FORM_ERROR_PAGE)); out.closeTag(); } out.closeTag(); } if (security instanceof ConstraintAware) { ConstraintAware ca = (ConstraintAware)security; for (String r : ca.getRoles()) { out.openTag("security-role") .tag("role-name", r) .closeTag(); } for (ConstraintMapping m : ca.getConstraintMappings()) { out.openTag("security-constraint"); out.openTag("web-resource-collection"); { if (m.getConstraint().getName() != null) out.tag("web-resource-name", m.getConstraint().getName()); if (m.getPathSpec() != null) out.tag("url-pattern", origin(md, "constraint.url." + m.getPathSpec()), m.getPathSpec()); if (m.getMethod() != null) out.tag("http-method", m.getMethod()); if (m.getMethodOmissions() != null) for (String o : m.getMethodOmissions()) { out.tag("http-method-omission", o); } out.closeTag(); } if (m.getConstraint().getAuthenticate()) { String[] roles = m.getConstraint().getRoles(); if (roles != null && roles.length > 0) { out.openTag("auth-constraint"); if (m.getConstraint().getRoles() != null) for (String r : m.getConstraint().getRoles()) { out.tag("role-name", r); } out.closeTag(); } else out.tag("auth-constraint"); } switch (m.getConstraint().getDataConstraint()) { case Constraint.DC_NONE: out.openTag("user-data-constraint").tag("transport-guarantee", "NONE").closeTag(); break; case Constraint.DC_INTEGRAL: out.openTag("user-data-constraint").tag("transport-guarantee", "INTEGRAL").closeTag(); break; case Constraint.DC_CONFIDENTIAL: out.openTag("user-data-constraint").tag("transport-guarantee", "CONFIDENTIAL").closeTag(); break; default: break; } out.closeTag(); } } if (_webApp.getWelcomeFiles() != null) { out.openTag("welcome-file-list"); for (String welcomeFile : _webApp.getWelcomeFiles()) { out.tag("welcome-file", welcomeFile); } out.closeTag(); } Map localeEncodings = _webApp.getLocaleEncodings(); if (localeEncodings != null && !localeEncodings.isEmpty()) { out.openTag("locale-encoding-mapping-list"); for (Map.Entry entry : localeEncodings.entrySet()) { out.openTag("locale-encoding-mapping", origin(md, "locale-encoding." + entry.getKey())); out.tag("locale", entry.getKey()); out.tag("encoding", entry.getValue()); out.closeTag(); } out.closeTag(); } //session-config if (_webApp.getSessionHandler() != null) { out.openTag("session-config"); int maxInactiveSec = _webApp.getSessionHandler().getMaxInactiveInterval(); out.tag("session-timeout", (maxInactiveSec == 0 ? "0" : Integer.toString(maxInactiveSec / 60))); //cookie-config SessionCookieConfig cookieConfig = _webApp.getSessionHandler().getSessionCookieConfig(); if (cookieConfig != null) { out.openTag("cookie-config"); if (cookieConfig.getName() != null) out.tag("name", origin(md, "cookie-config.name"), cookieConfig.getName()); if (cookieConfig.getDomain() != null) out.tag("domain", origin(md, "cookie-config.domain"), cookieConfig.getDomain()); if (cookieConfig.getPath() != null) out.tag("path", origin(md, "cookie-config.path"), cookieConfig.getPath()); if (cookieConfig.getComment() != null) out.tag("comment", origin(md, "cookie-config.comment"), cookieConfig.getComment()); out.tag("http-only", origin(md, "cookie-config.http-only"), Boolean.toString(cookieConfig.isHttpOnly())); out.tag("secure", origin(md, "cookie-config.secure"), Boolean.toString(cookieConfig.isSecure())); out.tag("max-age", origin(md, "cookie-config.max-age"), Integer.toString(cookieConfig.getMaxAge())); out.closeTag(); } // tracking-modes Set modes = _webApp.getSessionHandler().getEffectiveSessionTrackingModes(); if (modes != null) { for (SessionTrackingMode mode : modes) { out.tag("tracking-mode", mode.toString()); } } out.closeTag(); } //error-pages Map errorPages = ((ErrorPageErrorHandler)_webApp.getErrorHandler()).getErrorPages(); if (errorPages != null) { for (Map.Entry entry : errorPages.entrySet()) { out.openTag("error-page", origin(md, "error." + entry.getKey())); //a global or default error page has no code or exception if (!ErrorPageErrorHandler.GLOBAL_ERROR_PAGE.equals(entry.getKey())) { if (entry.getKey().matches("\\d{3}")) out.tag("error-code", entry.getKey()); else out.tag("exception-type", entry.getKey()); } out.tag("location", entry.getValue()); out.closeTag(); } } //mime-types MimeTypes mimeTypes = _webApp.getMimeTypes(); if (mimeTypes != null) { for (Map.Entry entry : mimeTypes.getMimeMap().entrySet()) { out.openTag("mime-mapping"); out.tag("extension", origin(md, "extension." + entry.getKey()), entry.getKey()); out.tag("mime-type", entry.getValue()); out.closeTag(); } } //jsp-config JspConfig jspConfig = (JspConfig)_webApp.getServletContext().getJspConfigDescriptor(); if (jspConfig != null) { out.openTag("jsp-config"); Collection tlds = jspConfig.getTaglibs(); if (tlds != null && !tlds.isEmpty()) { for (TaglibDescriptor tld : tlds) { out.openTag("taglib"); out.tag("taglib-uri", tld.getTaglibURI()); out.tag("taglib-location", tld.getTaglibLocation()); out.closeTag(); } } Collection jspPropertyGroups = jspConfig.getJspPropertyGroups(); if (jspPropertyGroups != null && !jspPropertyGroups.isEmpty()) { for (JspPropertyGroupDescriptor jspPropertyGroup : jspPropertyGroups) { out.openTag("jsp-property-group"); Collection strings = jspPropertyGroup.getUrlPatterns(); if (strings != null && !strings.isEmpty()) { for (String urlPattern : strings) { out.tag("url-pattern", urlPattern); } } if (jspPropertyGroup.getElIgnored() != null) out.tag("el-ignored", jspPropertyGroup.getElIgnored()); if (jspPropertyGroup.getPageEncoding() != null) out.tag("page-encoding", jspPropertyGroup.getPageEncoding()); if (jspPropertyGroup.getScriptingInvalid() != null) out.tag("scripting-invalid", jspPropertyGroup.getScriptingInvalid()); if (jspPropertyGroup.getIsXml() != null) out.tag("is-xml", jspPropertyGroup.getIsXml()); if (jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral() != null) out.tag("deferred-syntax-allowed-as-literal", jspPropertyGroup.getDeferredSyntaxAllowedAsLiteral()); if (jspPropertyGroup.getTrimDirectiveWhitespaces() != null) out.tag("trim-directive-whitespaces", jspPropertyGroup.getTrimDirectiveWhitespaces()); if (jspPropertyGroup.getDefaultContentType() != null) out.tag("default-content-type", jspPropertyGroup.getDefaultContentType()); if (jspPropertyGroup.getBuffer() != null) out.tag("buffer", jspPropertyGroup.getBuffer()); if (jspPropertyGroup.getErrorOnUndeclaredNamespace() != null) out.tag("error-on-undeclared-namespace", jspPropertyGroup.getErrorOnUndeclaredNamespace()); strings = jspPropertyGroup.getIncludePreludes(); if (strings != null && !strings.isEmpty()) { for (String prelude : strings) { out.tag("include-prelude", prelude); } } strings = jspPropertyGroup.getIncludeCodas(); if (strings != null && !strings.isEmpty()) { for (String coda : strings) { out.tag("include-coda", coda); } } out.closeTag(); } } out.closeTag(); } //lifecycle: post-construct, pre-destroy LifeCycleCallbackCollection lifecycles = ((LifeCycleCallbackCollection)_webApp.getAttribute(LifeCycleCallbackCollection.LIFECYCLE_CALLBACK_COLLECTION)); if (lifecycles != null) { Collection tmp = lifecycles.getPostConstructCallbacks(); for (LifeCycleCallback c : tmp) { out.openTag("post-construct"); out.tag("lifecycle-callback-class", c.getTargetClassName()); out.tag("lifecycle-callback-method", c.getMethodName()); out.closeTag(); } tmp = lifecycles.getPreDestroyCallbacks(); for (LifeCycleCallback c : tmp) { out.openTag("pre-destroy"); out.tag("lifecycle-callback-class", c.getTargetClassName()); out.tag("lifecycle-callback-method", c.getMethodName()); out.closeTag(); } } out.literal(_extraXML); out.closeTag(); } /** * Turn attribute into context-param to store. */ private void addContextParamFromAttribute(XmlAppendable out, String attribute) throws IOException { Object o = _webApp.getAttribute(attribute); if (o == null) return; Collection c = (o instanceof Collection) ? (Collection)o : Collections.singletonList(o); StringBuilder v = new StringBuilder(); for (Object i : c) { if (i != null) { if (v.length() > 0) v.append(",\n "); else v.append("\n "); QuotedStringTokenizer.quote(v, i.toString()); } } out.openTag("context-param") .tag("param-name", attribute) .tagCDATA("param-value", v.toString()) .closeTag(); } /** * Turn context attribute into context-param to store. */ private void addContextParamFromAttribute(XmlAppendable out, String attribute, AttributeNormalizer normalizer) throws IOException { Object o = _webApp.getAttribute(attribute); if (o == null) return; Collection c = (o instanceof Collection) ? (Collection)o : Collections.singletonList(o); StringBuilder v = new StringBuilder(); for (Object i : c) { if (i != null) { if (v.length() > 0) v.append(",\n "); else v.append("\n "); QuotedStringTokenizer.quote(v, normalizer.normalize(i)); } } out.openTag("context-param") .tag("param-name", attribute) .tagCDATA("param-value", v.toString()) .closeTag(); } /** * Generate xml for a Holder (Filter/Servlet) */ private void outholder(XmlAppendable out, MetaData md, FilterHolder holder) throws IOException { if (LOG.isDebugEnabled()) out.openTag("filter", Collections.singletonMap("source", holder.getSource().toString())); else out.openTag("filter"); String n = holder.getName(); out.tag("filter-name", n); String ot = n + ".filter."; if (holder instanceof FilterHolder) { out.tag("filter-class", origin(md, ot + "filter-class"), holder.getClassName()); out.tag("async-supported", origin(md, ot + "async-supported"), holder.isAsyncSupported() ? "true" : "false"); } for (String p : holder.getInitParameters().keySet()) { out.openTag("init-param", origin(md, ot + "init-param." + p)) .tag("param-name", p) .tag("param-value", holder.getInitParameter(p)) .closeTag(); } out.closeTag(); } private void outholder(XmlAppendable out, MetaData md, ServletHolder holder) throws IOException { if (LOG.isDebugEnabled()) out.openTag("servlet", Collections.singletonMap("source", holder.getSource().toString())); else out.openTag("servlet"); String n = holder.getName(); out.tag("servlet-name", n); String ot = n + ".servlet."; ServletHolder s = holder; if (s.getForcedPath() != null && s.getClassName() == null) out.tag("jsp-file", s.getForcedPath()); else out.tag("servlet-class", origin(md, ot + "servlet-class"), s.getClassName()); for (String p : holder.getInitParameters().keySet()) { if ("jsp".equalsIgnoreCase(n) && "scratchdir".equalsIgnoreCase(p)) //don't preconfigure the temp dir for jsp output continue; out.openTag("init-param", origin(md, ot + "init-param." + p)) .tag("param-name", p) .tag("param-value", holder.getInitParameter(p)) .closeTag(); } if (s.getInitOrder() >= 0) out.tag("load-on-startup", Integer.toString(s.getInitOrder())); if (!s.isEnabled()) out.tag("enabled", origin(md, ot + "enabled"), "false"); out.tag("async-supported", origin(md, ot + "async-supported"), holder.isAsyncSupported() ? "true" : "false"); if (s.getRunAsRole() != null) out.openTag("run-as", origin(md, ot + "run-as")) .tag("role-name", s.getRunAsRole()) .closeTag(); Map roles = s.getRoleRefMap(); if (roles != null) { for (Map.Entry e : roles.entrySet()) { out.openTag("security-role-ref", origin(md, ot + "role-name." + e.getKey())) .tag("role-name", e.getKey()) .tag("role-link", e.getValue()) .closeTag(); } } //multipart-config MultipartConfigElement multipartConfig = ((ServletHolder.Registration)s.getRegistration()).getMultipartConfig(); if (multipartConfig != null) { out.openTag("multipart-config", origin(md, s.getName() + ".servlet.multipart-config")); if (multipartConfig.getLocation() != null) out.tag("location", multipartConfig.getLocation()); out.tag("max-file-size", Long.toString(multipartConfig.getMaxFileSize())); out.tag("max-request-size", Long.toString(multipartConfig.getMaxRequestSize())); out.tag("file-size-threshold", Long.toString(multipartConfig.getFileSizeThreshold())); out.closeTag(); } out.closeTag(); } /** * Find the origin (web.xml, fragment, annotation etc) of a web artifact from MetaData. * * @param md the metadata * @param name the name * @return the origin map */ public Map origin(MetaData md, String name) { if (!_generateOrigin) return Collections.emptyMap(); if (name == null) return Collections.emptyMap(); OriginInfo origin = md.getOriginInfo(name); if (LOG.isDebugEnabled()) LOG.debug("origin of " + name + " is " + origin); if (origin == null) return Collections.emptyMap(); return Collections.singletonMap(_originAttribute, origin.toString() + ":" + (_count++)); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy