init
This commit is contained in:
131
java/org/apache/catalina/util/CharsetMapper.java
Normal file
131
java/org/apache/catalina/util/CharsetMapper.java
Normal file
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Utility class that attempts to map from a Locale to the corresponding
|
||||
* character set to be used for interpreting input text (or generating
|
||||
* output text) when the Content-Type header does not include one. You
|
||||
* can customize the behavior of this class by modifying the mapping data
|
||||
* it loads, or by subclassing it (to change the algorithm) and then using
|
||||
* your own version for a particular web application.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class CharsetMapper {
|
||||
|
||||
|
||||
// ---------------------------------------------------- Manifest Constants
|
||||
|
||||
|
||||
/**
|
||||
* Default properties resource name.
|
||||
*/
|
||||
public static final String DEFAULT_RESOURCE =
|
||||
"/org/apache/catalina/util/CharsetMapperDefault.properties";
|
||||
|
||||
|
||||
// ---------------------------------------------------------- Constructors
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new CharsetMapper using the default properties resource.
|
||||
*/
|
||||
public CharsetMapper() {
|
||||
this(DEFAULT_RESOURCE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new CharsetMapper using the specified properties resource.
|
||||
*
|
||||
* @param name Name of a properties resource to be loaded
|
||||
*
|
||||
* @exception IllegalArgumentException if the specified properties
|
||||
* resource could not be loaded for any reason.
|
||||
*/
|
||||
public CharsetMapper(String name) {
|
||||
try (InputStream stream = this.getClass().getResourceAsStream(name)) {
|
||||
map.load(stream);
|
||||
} catch (Throwable t) {
|
||||
ExceptionUtils.handleThrowable(t);
|
||||
throw new IllegalArgumentException(t.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* The mapping properties that have been initialized from the specified or
|
||||
* default properties resource.
|
||||
*/
|
||||
private Properties map = new Properties();
|
||||
|
||||
|
||||
// ------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Calculate the name of a character set to be assumed, given the specified
|
||||
* Locale and the absence of a character set specified as part of the
|
||||
* content type header.
|
||||
*
|
||||
* @param locale The locale for which to calculate a character set
|
||||
* @return the charset name
|
||||
*/
|
||||
public String getCharset(Locale locale) {
|
||||
// Match full language_country_variant first, then language_country,
|
||||
// then language only
|
||||
String charset = map.getProperty(locale.toString());
|
||||
if (charset == null) {
|
||||
charset = map.getProperty(locale.getLanguage() + "_"
|
||||
+ locale.getCountry());
|
||||
if (charset == null) {
|
||||
charset = map.getProperty(locale.getLanguage());
|
||||
}
|
||||
}
|
||||
return charset;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The deployment descriptor can have a
|
||||
* locale-encoding-mapping-list element which describes the
|
||||
* webapp's desired mapping from locale to charset. This method
|
||||
* gets called when processing the web.xml file for a context
|
||||
*
|
||||
* @param locale The locale for a character set
|
||||
* @param charset The charset to be associated with the locale
|
||||
*/
|
||||
public void addCharsetMappingFromDeploymentDescriptor(String locale, String charset) {
|
||||
map.put(locale, charset);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
# 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.
|
||||
|
||||
en=ISO-8859-1
|
||||
fr=ISO-8859-1
|
||||
79
java/org/apache/catalina/util/ConcurrentDateFormat.java
Normal file
79
java/org/apache/catalina/util/ConcurrentDateFormat.java
Normal file
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Queue;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
/**
|
||||
* A thread safe wrapper around {@link SimpleDateFormat} that does not make use
|
||||
* of ThreadLocal and - broadly - only creates enough SimpleDateFormat objects
|
||||
* to satisfy the concurrency requirements.
|
||||
*
|
||||
* @deprecated Unused. This will be removed in Tomcat 10.
|
||||
* Use {@link org.apache.tomcat.util.http.ConcurrentDateFormat}
|
||||
*/
|
||||
@Deprecated
|
||||
public class ConcurrentDateFormat {
|
||||
|
||||
private final String format;
|
||||
private final Locale locale;
|
||||
private final TimeZone timezone;
|
||||
private final Queue<SimpleDateFormat> queue = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public static final String RFC1123_DATE = "EEE, dd MMM yyyy HH:mm:ss zzz";
|
||||
public static final TimeZone GMT = TimeZone.getTimeZone("GMT");
|
||||
|
||||
private static final ConcurrentDateFormat FORMAT_RFC1123;
|
||||
|
||||
static {
|
||||
FORMAT_RFC1123 = new ConcurrentDateFormat(RFC1123_DATE, Locale.US, GMT);
|
||||
}
|
||||
|
||||
public static String formatRfc1123(Date date) {
|
||||
return FORMAT_RFC1123.format(date);
|
||||
}
|
||||
|
||||
public ConcurrentDateFormat(String format, Locale locale,
|
||||
TimeZone timezone) {
|
||||
this.format = format;
|
||||
this.locale = locale;
|
||||
this.timezone = timezone;
|
||||
SimpleDateFormat initial = createInstance();
|
||||
queue.add(initial);
|
||||
}
|
||||
|
||||
public String format(Date date) {
|
||||
SimpleDateFormat sdf = queue.poll();
|
||||
if (sdf == null) {
|
||||
sdf = createInstance();
|
||||
}
|
||||
String result = sdf.format(date);
|
||||
queue.add(sdf);
|
||||
return result;
|
||||
}
|
||||
|
||||
private SimpleDateFormat createInstance() {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat(format, locale);
|
||||
sdf.setTimeZone(timezone);
|
||||
return sdf;
|
||||
}
|
||||
}
|
||||
176
java/org/apache/catalina/util/ContextName.java
Normal file
176
java/org/apache/catalina/util/ContextName.java
Normal file
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Utility class to manage context names so there is one place where the
|
||||
* conversions between baseName, path and version take place.
|
||||
*/
|
||||
public final class ContextName {
|
||||
public static final String ROOT_NAME = "ROOT";
|
||||
private static final String VERSION_MARKER = "##";
|
||||
private static final String FWD_SLASH_REPLACEMENT = "#";
|
||||
|
||||
private final String baseName;
|
||||
private final String path;
|
||||
private final String version;
|
||||
private final String name;
|
||||
|
||||
|
||||
/**
|
||||
* Creates an instance from a context name, display name, base name,
|
||||
* directory name, WAR name or context.xml name.
|
||||
*
|
||||
* @param name The name to use as the basis for this object
|
||||
* @param stripFileExtension If a .war or .xml file extension is present
|
||||
* at the end of the provided name should it be
|
||||
* removed?
|
||||
*/
|
||||
public ContextName(String name, boolean stripFileExtension) {
|
||||
|
||||
String tmp1 = name;
|
||||
|
||||
// Convert Context names and display names to base names
|
||||
|
||||
// Strip off any leading "/"
|
||||
if (tmp1.startsWith("/")) {
|
||||
tmp1 = tmp1.substring(1);
|
||||
}
|
||||
|
||||
// Replace any remaining /
|
||||
tmp1 = tmp1.replaceAll("/", FWD_SLASH_REPLACEMENT);
|
||||
|
||||
// Insert the ROOT name if required
|
||||
if (tmp1.startsWith(VERSION_MARKER) || "".equals(tmp1)) {
|
||||
tmp1 = ROOT_NAME + tmp1;
|
||||
}
|
||||
|
||||
// Remove any file extensions
|
||||
if (stripFileExtension &&
|
||||
(tmp1.toLowerCase(Locale.ENGLISH).endsWith(".war") ||
|
||||
tmp1.toLowerCase(Locale.ENGLISH).endsWith(".xml"))) {
|
||||
tmp1 = tmp1.substring(0, tmp1.length() -4);
|
||||
}
|
||||
|
||||
baseName = tmp1;
|
||||
|
||||
String tmp2;
|
||||
// Extract version number
|
||||
int versionIndex = baseName.indexOf(VERSION_MARKER);
|
||||
if (versionIndex > -1) {
|
||||
version = baseName.substring(versionIndex + 2);
|
||||
tmp2 = baseName.substring(0, versionIndex);
|
||||
} else {
|
||||
version = "";
|
||||
tmp2 = baseName;
|
||||
}
|
||||
|
||||
if (ROOT_NAME.equals(tmp2)) {
|
||||
path = "";
|
||||
} else {
|
||||
path = "/" + tmp2.replaceAll(FWD_SLASH_REPLACEMENT, "/");
|
||||
}
|
||||
|
||||
if (versionIndex > -1) {
|
||||
this.name = path + VERSION_MARKER + version;
|
||||
} else {
|
||||
this.name = path;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct an instance from a path and version.
|
||||
*
|
||||
* @param path Context path to use
|
||||
* @param version Context version to use
|
||||
*/
|
||||
public ContextName(String path, String version) {
|
||||
// Path should never be null, '/' or '/ROOT'
|
||||
if (path == null || "/".equals(path) || "/ROOT".equals(path)) {
|
||||
this.path = "";
|
||||
} else {
|
||||
this.path = path;
|
||||
}
|
||||
|
||||
// Version should never be null
|
||||
if (version == null) {
|
||||
this.version = "";
|
||||
} else {
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
// Name is path + version
|
||||
if ("".equals(this.version)) {
|
||||
name = this.path;
|
||||
} else {
|
||||
name = this.path + VERSION_MARKER + this.version;
|
||||
}
|
||||
|
||||
// Base name is converted path + version
|
||||
StringBuilder tmp = new StringBuilder();
|
||||
if ("".equals(this.path)) {
|
||||
tmp.append(ROOT_NAME);
|
||||
} else {
|
||||
tmp.append(this.path.substring(1).replaceAll("/",
|
||||
FWD_SLASH_REPLACEMENT));
|
||||
}
|
||||
if (this.version.length() > 0) {
|
||||
tmp.append(VERSION_MARKER);
|
||||
tmp.append(this.version);
|
||||
}
|
||||
this.baseName = tmp.toString();
|
||||
}
|
||||
|
||||
public String getBaseName() {
|
||||
return baseName;
|
||||
}
|
||||
|
||||
public String getPath() {
|
||||
return path;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDisplayName() {
|
||||
StringBuilder tmp = new StringBuilder();
|
||||
if ("".equals(path)) {
|
||||
tmp.append('/');
|
||||
} else {
|
||||
tmp.append(path);
|
||||
}
|
||||
|
||||
if (!"".equals(version)) {
|
||||
tmp.append(VERSION_MARKER);
|
||||
tmp.append(version);
|
||||
}
|
||||
|
||||
return tmp.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getDisplayName();
|
||||
}
|
||||
}
|
||||
194
java/org/apache/catalina/util/CustomObjectInputStream.java
Normal file
194
java/org/apache/catalina/util/CustomObjectInputStream.java
Normal file
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InvalidClassException;
|
||||
import java.io.ObjectInputStream;
|
||||
import java.io.ObjectStreamClass;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Custom subclass of <code>ObjectInputStream</code> that loads from the
|
||||
* class loader for this web application. This allows classes defined only
|
||||
* with the web application to be found correctly.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Bip Thelin
|
||||
*/
|
||||
public final class CustomObjectInputStream extends ObjectInputStream {
|
||||
|
||||
private static final StringManager sm = StringManager.getManager(CustomObjectInputStream.class);
|
||||
|
||||
private static final WeakHashMap<ClassLoader, Set<String>> reportedClassCache =
|
||||
new WeakHashMap<>();
|
||||
|
||||
/**
|
||||
* The class loader we will use to resolve classes.
|
||||
*/
|
||||
private final ClassLoader classLoader;
|
||||
private final Set<String> reportedClasses;
|
||||
private final Log log;
|
||||
|
||||
private final Pattern allowedClassNamePattern;
|
||||
private final String allowedClassNameFilter;
|
||||
private final boolean warnOnFailure;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new instance of CustomObjectInputStream without any filtering
|
||||
* of deserialized classes.
|
||||
*
|
||||
* @param stream The input stream we will read from
|
||||
* @param classLoader The class loader used to instantiate objects
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
public CustomObjectInputStream(InputStream stream, ClassLoader classLoader) throws IOException {
|
||||
this(stream, classLoader, null, null, false);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new instance of CustomObjectInputStream with filtering of
|
||||
* deserialized classes.
|
||||
*
|
||||
* @param stream The input stream we will read from
|
||||
* @param classLoader The class loader used to instantiate objects
|
||||
* @param log The logger to use to report any issues. It may only be null if
|
||||
* the filterMode does not require logging
|
||||
* @param allowedClassNamePattern The regular expression to use to filter
|
||||
* deserialized classes. The fully qualified
|
||||
* class name must match this pattern for
|
||||
* deserialization to be allowed if filtering
|
||||
* is enabled.
|
||||
* @param warnOnFailure Should any failures be logged?
|
||||
*
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
public CustomObjectInputStream(InputStream stream, ClassLoader classLoader,
|
||||
Log log, Pattern allowedClassNamePattern, boolean warnOnFailure)
|
||||
throws IOException {
|
||||
super(stream);
|
||||
if (log == null && allowedClassNamePattern != null && warnOnFailure) {
|
||||
throw new IllegalArgumentException(
|
||||
sm.getString("customObjectInputStream.logRequired"));
|
||||
}
|
||||
this.classLoader = classLoader;
|
||||
this.log = log;
|
||||
this.allowedClassNamePattern = allowedClassNamePattern;
|
||||
if (allowedClassNamePattern == null) {
|
||||
this.allowedClassNameFilter = null;
|
||||
} else {
|
||||
this.allowedClassNameFilter = allowedClassNamePattern.toString();
|
||||
}
|
||||
this.warnOnFailure = warnOnFailure;
|
||||
|
||||
Set<String> reportedClasses;
|
||||
synchronized (reportedClassCache) {
|
||||
reportedClasses = reportedClassCache.get(classLoader);
|
||||
}
|
||||
if (reportedClasses == null) {
|
||||
reportedClasses = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>());
|
||||
synchronized (reportedClassCache) {
|
||||
Set<String> original = reportedClassCache.get(classLoader);
|
||||
if (original == null) {
|
||||
reportedClassCache.put(classLoader, reportedClasses);
|
||||
} else {
|
||||
// Concurrent attempts to create the new Set. Make sure all
|
||||
// threads use the first successfully added Set.
|
||||
reportedClasses = original;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.reportedClasses = reportedClasses;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the local class equivalent of the specified stream class
|
||||
* description, by using the class loader assigned to this Context.
|
||||
*
|
||||
* @param classDesc Class description from the input stream
|
||||
*
|
||||
* @exception ClassNotFoundException if this class cannot be found
|
||||
* @exception IOException if an input/output error occurs
|
||||
*/
|
||||
@Override
|
||||
public Class<?> resolveClass(ObjectStreamClass classDesc)
|
||||
throws ClassNotFoundException, IOException {
|
||||
|
||||
String name = classDesc.getName();
|
||||
if (allowedClassNamePattern != null) {
|
||||
boolean allowed = allowedClassNamePattern.matcher(name).matches();
|
||||
if (!allowed) {
|
||||
boolean doLog = warnOnFailure && reportedClasses.add(name);
|
||||
String msg = sm.getString("customObjectInputStream.nomatch", name, allowedClassNameFilter);
|
||||
if (doLog) {
|
||||
log.warn(msg);
|
||||
} else if (log.isDebugEnabled()) {
|
||||
log.debug(msg);
|
||||
}
|
||||
throw new InvalidClassException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return Class.forName(name, false, classLoader);
|
||||
} catch (ClassNotFoundException e) {
|
||||
try {
|
||||
// Try also the superclass because of primitive types
|
||||
return super.resolveClass(classDesc);
|
||||
} catch (ClassNotFoundException e2) {
|
||||
// Rethrow original exception, as it can have more information
|
||||
// about why the class was not found. BZ 48007
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return a proxy class that implements the interfaces named in a proxy
|
||||
* class descriptor. Do this using the class loader assigned to this
|
||||
* Context.
|
||||
*/
|
||||
@Override
|
||||
protected Class<?> resolveProxyClass(String[] interfaces)
|
||||
throws IOException, ClassNotFoundException {
|
||||
|
||||
Class<?>[] cinterfaces = new Class[interfaces.length];
|
||||
for (int i = 0; i < interfaces.length; i++) {
|
||||
cinterfaces[i] = classLoader.loadClass(interfaces[i]);
|
||||
}
|
||||
|
||||
try {
|
||||
return Proxy.getProxyClass(classLoader, cinterfaces);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ClassNotFoundException(null, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
266
java/org/apache/catalina/util/DOMWriter.java
Normal file
266
java/org/apache/catalina/util/DOMWriter.java
Normal file
@@ -0,0 +1,266 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.io.Writer;
|
||||
|
||||
import org.w3c.dom.Attr;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.NamedNodeMap;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
|
||||
/**
|
||||
* A sample DOM writer. This sample program illustrates how to traverse a DOM
|
||||
* tree in order to print a document that is parsed.
|
||||
*/
|
||||
public class DOMWriter {
|
||||
|
||||
/** Default Encoding */
|
||||
private static final String PRINTWRITER_ENCODING = "UTF8";
|
||||
|
||||
/** Print writer.
|
||||
*
|
||||
* @deprecated Will be made private in Tomcat 9.
|
||||
*/
|
||||
@Deprecated
|
||||
protected final PrintWriter out;
|
||||
|
||||
/** Canonical output.
|
||||
*
|
||||
* @deprecated Will be made private in Tomcat 9.
|
||||
*/
|
||||
@Deprecated
|
||||
protected final boolean canonical;
|
||||
|
||||
|
||||
public DOMWriter(Writer writer) {
|
||||
this (writer, true);
|
||||
}
|
||||
|
||||
|
||||
@Deprecated
|
||||
public DOMWriter(Writer writer, boolean canonical) {
|
||||
out = new PrintWriter(writer);
|
||||
this.canonical = canonical;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @deprecated Unused. Will be removed in Tomcat 9.
|
||||
*
|
||||
* @return Always <code>UTF-8</code>
|
||||
*/
|
||||
@Deprecated
|
||||
public static String getWriterEncoding() {
|
||||
return (PRINTWRITER_ENCODING);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Prints the specified node, recursively.
|
||||
* @param node The node to output
|
||||
*/
|
||||
public void print(Node node) {
|
||||
|
||||
// is there anything to do?
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
int type = node.getNodeType();
|
||||
switch (type) {
|
||||
// print document
|
||||
case Node.DOCUMENT_NODE:
|
||||
if (!canonical) {
|
||||
out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
|
||||
}
|
||||
print(((Document) node).getDocumentElement());
|
||||
out.flush();
|
||||
break;
|
||||
|
||||
// print element with attributes
|
||||
case Node.ELEMENT_NODE:
|
||||
out.print('<');
|
||||
out.print(node.getLocalName());
|
||||
Attr attrs[] = sortAttributes(node.getAttributes());
|
||||
for (int i = 0; i < attrs.length; i++) {
|
||||
Attr attr = attrs[i];
|
||||
out.print(' ');
|
||||
out.print(attr.getLocalName());
|
||||
|
||||
out.print("=\"");
|
||||
out.print(normalize(attr.getNodeValue()));
|
||||
out.print('"');
|
||||
}
|
||||
out.print('>');
|
||||
printChildren(node);
|
||||
break;
|
||||
|
||||
// handle entity reference nodes
|
||||
case Node.ENTITY_REFERENCE_NODE:
|
||||
if (canonical) {
|
||||
printChildren(node);
|
||||
} else {
|
||||
out.print('&');
|
||||
out.print(node.getLocalName());
|
||||
out.print(';');
|
||||
}
|
||||
break;
|
||||
|
||||
// print cdata sections
|
||||
case Node.CDATA_SECTION_NODE:
|
||||
if (canonical) {
|
||||
out.print(normalize(node.getNodeValue()));
|
||||
} else {
|
||||
out.print("<![CDATA[");
|
||||
out.print(node.getNodeValue());
|
||||
out.print("]]>");
|
||||
}
|
||||
break;
|
||||
|
||||
// print text
|
||||
case Node.TEXT_NODE:
|
||||
out.print(normalize(node.getNodeValue()));
|
||||
break;
|
||||
|
||||
// print processing instruction
|
||||
case Node.PROCESSING_INSTRUCTION_NODE:
|
||||
out.print("<?");
|
||||
out.print(node.getLocalName());
|
||||
|
||||
String data = node.getNodeValue();
|
||||
if (data != null && data.length() > 0) {
|
||||
out.print(' ');
|
||||
out.print(data);
|
||||
}
|
||||
out.print("?>");
|
||||
break;
|
||||
}
|
||||
|
||||
if (type == Node.ELEMENT_NODE) {
|
||||
out.print("</");
|
||||
out.print(node.getLocalName());
|
||||
out.print('>');
|
||||
}
|
||||
|
||||
out.flush();
|
||||
|
||||
} // print(Node)
|
||||
|
||||
|
||||
private void printChildren(Node node) {
|
||||
NodeList children = node.getChildNodes();
|
||||
if (children != null) {
|
||||
int len = children.getLength();
|
||||
for (int i = 0; i < len; i++) {
|
||||
print(children.item(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns a sorted list of attributes.
|
||||
* @param attrs The map to sort
|
||||
* @return a sorted attribute array
|
||||
*
|
||||
* @deprecated Will be made private in Tomcat 9.
|
||||
*/
|
||||
@Deprecated
|
||||
protected Attr[] sortAttributes(NamedNodeMap attrs) {
|
||||
if (attrs == null) {
|
||||
return new Attr[0];
|
||||
}
|
||||
|
||||
int len = attrs.getLength();
|
||||
Attr array[] = new Attr[len];
|
||||
for (int i = 0; i < len; i++) {
|
||||
array[i] = (Attr) attrs.item(i);
|
||||
}
|
||||
for (int i = 0; i < len - 1; i++) {
|
||||
String name = null;
|
||||
name = array[i].getLocalName();
|
||||
int index = i;
|
||||
for (int j = i + 1; j < len; j++) {
|
||||
String curName = null;
|
||||
curName = array[j].getLocalName();
|
||||
if (curName.compareTo(name) < 0) {
|
||||
name = curName;
|
||||
index = j;
|
||||
}
|
||||
}
|
||||
if (index != i) {
|
||||
Attr temp = array[i];
|
||||
array[i] = array[index];
|
||||
array[index] = temp;
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalizes the given string.
|
||||
* @param s The string to escape
|
||||
* @return the escaped string
|
||||
*
|
||||
* @deprecated Will be made private in Tomcat 9.
|
||||
*/
|
||||
@Deprecated
|
||||
protected String normalize(String s) {
|
||||
if (s == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder str = new StringBuilder();
|
||||
|
||||
int len = s.length();
|
||||
for (int i = 0; i < len; i++) {
|
||||
char ch = s.charAt(i);
|
||||
switch (ch) {
|
||||
case '<':
|
||||
str.append("<");
|
||||
break;
|
||||
case '>':
|
||||
str.append(">");
|
||||
break;
|
||||
case '&':
|
||||
str.append("&");
|
||||
break;
|
||||
case '"':
|
||||
str.append(""");
|
||||
break;
|
||||
case '\r':
|
||||
case '\n':
|
||||
if (canonical) {
|
||||
str.append("&#");
|
||||
str.append(Integer.toString(ch));
|
||||
str.append(';');
|
||||
break;
|
||||
}
|
||||
// else, default append char
|
||||
//$FALL-THROUGH$
|
||||
default:
|
||||
str.append(ch);
|
||||
}
|
||||
}
|
||||
|
||||
return str.toString();
|
||||
}
|
||||
}
|
||||
108
java/org/apache/catalina/util/ErrorPageSupport.java
Normal file
108
java/org/apache/catalina/util/ErrorPageSupport.java
Normal file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import org.apache.tomcat.util.descriptor.web.ErrorPage;
|
||||
|
||||
/**
|
||||
* Provides support for tracking per exception type and per HTTP status code
|
||||
* error pages.
|
||||
*/
|
||||
public class ErrorPageSupport {
|
||||
|
||||
// Fully qualified class name to error page
|
||||
private ConcurrentMap<String, ErrorPage> exceptionPages = new ConcurrentHashMap<>();
|
||||
|
||||
// HTTP status code to error page
|
||||
private ConcurrentMap<Integer, ErrorPage> statusPages = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
public void add(ErrorPage errorPage) {
|
||||
String exceptionType = errorPage.getExceptionType();
|
||||
if (exceptionType == null) {
|
||||
statusPages.put(Integer.valueOf(errorPage.getErrorCode()), errorPage);
|
||||
} else {
|
||||
exceptionPages.put(exceptionType, errorPage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void remove(ErrorPage errorPage) {
|
||||
String exceptionType = errorPage.getExceptionType();
|
||||
if (exceptionType == null) {
|
||||
statusPages.remove(Integer.valueOf(errorPage.getErrorCode()), errorPage);
|
||||
} else {
|
||||
exceptionPages.remove(exceptionType, errorPage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ErrorPage find(int statusCode) {
|
||||
return statusPages.get(Integer.valueOf(statusCode));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find the ErrorPage, if any, for the named exception type.
|
||||
*
|
||||
* @param exceptionType The fully qualified class name of the exception type
|
||||
*
|
||||
* @return The ErrorPage for the named exception type, or {@code null} if
|
||||
* none is configured
|
||||
*
|
||||
* @deprecated Unused. Will be removed in Tomcat 10.
|
||||
* Use {@link #find(Throwable)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
public ErrorPage find(String exceptionType) {
|
||||
return exceptionPages.get(exceptionType);
|
||||
}
|
||||
|
||||
|
||||
public ErrorPage find(Throwable exceptionType) {
|
||||
if (exceptionType == null) {
|
||||
return null;
|
||||
}
|
||||
Class<?> clazz = exceptionType.getClass();
|
||||
String name = clazz.getName();
|
||||
while (!Object.class.equals(clazz)) {
|
||||
ErrorPage errorPage = exceptionPages.get(name);
|
||||
if (errorPage != null) {
|
||||
return errorPage;
|
||||
}
|
||||
clazz = clazz.getSuperclass();
|
||||
if (clazz == null) {
|
||||
break;
|
||||
}
|
||||
name = clazz.getName();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
public ErrorPage[] findAll() {
|
||||
Set<ErrorPage> errorPages = new HashSet<>();
|
||||
errorPages.addAll(exceptionPages.values());
|
||||
errorPages.addAll(statusPages.values());
|
||||
return errorPages.toArray(new ErrorPage[errorPages.size()]);
|
||||
}
|
||||
}
|
||||
299
java/org/apache/catalina/util/Extension.java
Normal file
299
java/org/apache/catalina/util/Extension.java
Normal file
@@ -0,0 +1,299 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
|
||||
/**
|
||||
* Utility class that represents either an available "Optional Package"
|
||||
* (formerly known as "Standard Extension") as described in the manifest
|
||||
* of a JAR file, or the requirement for such an optional package. It is
|
||||
* used to support the requirements of the Servlet Specification, version
|
||||
* 2.3, related to providing shared extensions to all webapps.
|
||||
* <p>
|
||||
* In addition, static utility methods are available to scan a manifest
|
||||
* and return an array of either available or required optional modules
|
||||
* documented in that manifest.
|
||||
* <p>
|
||||
* For more information about optional packages, see the document
|
||||
* <em>Optional Package Versioning</em> in the documentation bundle for your
|
||||
* Java2 Standard Edition package, in file
|
||||
* <code>guide/extensions/versioning.html</code>.
|
||||
*
|
||||
* @author Craig McClanahan
|
||||
* @author Justyna Horwat
|
||||
* @author Greg Murray
|
||||
*/
|
||||
public final class Extension {
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
|
||||
/**
|
||||
* The name of the optional package being made available, or required.
|
||||
*/
|
||||
private String extensionName = null;
|
||||
|
||||
|
||||
public String getExtensionName() {
|
||||
return this.extensionName;
|
||||
}
|
||||
|
||||
public void setExtensionName(String extensionName) {
|
||||
this.extensionName = extensionName;
|
||||
}
|
||||
|
||||
/**
|
||||
* The URL from which the most recent version of this optional package
|
||||
* can be obtained if it is not already installed.
|
||||
*/
|
||||
private String implementationURL = null;
|
||||
|
||||
public String getImplementationURL() {
|
||||
return this.implementationURL;
|
||||
}
|
||||
|
||||
public void setImplementationURL(String implementationURL) {
|
||||
this.implementationURL = implementationURL;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The name of the company or organization that produced this
|
||||
* implementation of this optional package.
|
||||
*/
|
||||
private String implementationVendor = null;
|
||||
|
||||
public String getImplementationVendor() {
|
||||
return this.implementationVendor;
|
||||
}
|
||||
|
||||
public void setImplementationVendor(String implementationVendor) {
|
||||
this.implementationVendor = implementationVendor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The unique identifier of the company that produced the optional
|
||||
* package contained in this JAR file.
|
||||
*/
|
||||
private String implementationVendorId = null;
|
||||
|
||||
public String getImplementationVendorId() {
|
||||
return this.implementationVendorId;
|
||||
}
|
||||
|
||||
public void setImplementationVendorId(String implementationVendorId) {
|
||||
this.implementationVendorId = implementationVendorId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The version number (dotted decimal notation) for this implementation
|
||||
* of the optional package.
|
||||
*/
|
||||
private String implementationVersion = null;
|
||||
|
||||
public String getImplementationVersion() {
|
||||
return this.implementationVersion;
|
||||
}
|
||||
|
||||
public void setImplementationVersion(String implementationVersion) {
|
||||
this.implementationVersion = implementationVersion;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The name of the company or organization that originated the
|
||||
* specification to which this optional package conforms.
|
||||
*/
|
||||
private String specificationVendor = null;
|
||||
|
||||
public String getSpecificationVendor() {
|
||||
return this.specificationVendor;
|
||||
}
|
||||
|
||||
public void setSpecificationVendor(String specificationVendor) {
|
||||
this.specificationVendor = specificationVendor;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The version number (dotted decimal notation) of the specification
|
||||
* to which this optional package conforms.
|
||||
*/
|
||||
private String specificationVersion = null;
|
||||
|
||||
public String getSpecificationVersion() {
|
||||
return this.specificationVersion;
|
||||
}
|
||||
|
||||
public void setSpecificationVersion(String specificationVersion) {
|
||||
this.specificationVersion = specificationVersion;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* fulfilled is true if all the required extension dependencies have been
|
||||
* satisfied
|
||||
*/
|
||||
private boolean fulfilled = false;
|
||||
|
||||
public void setFulfilled(boolean fulfilled) {
|
||||
this.fulfilled = fulfilled;
|
||||
}
|
||||
|
||||
public boolean isFulfilled() {
|
||||
return fulfilled;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if the specified <code>Extension</code>
|
||||
* (which represents an optional package required by this application)
|
||||
* is satisfied by this <code>Extension</code> (which represents an
|
||||
* optional package that is already installed. Otherwise, return
|
||||
* <code>false</code>.
|
||||
*
|
||||
* @param required Extension of the required optional package
|
||||
* @return <code>true</code> if the extension is satisfied
|
||||
*/
|
||||
public boolean isCompatibleWith(Extension required) {
|
||||
|
||||
// Extension Name must match
|
||||
if (extensionName == null)
|
||||
return false;
|
||||
if (!extensionName.equals(required.getExtensionName()))
|
||||
return false;
|
||||
|
||||
// If specified, available specification version must be >= required
|
||||
if (required.getSpecificationVersion() != null) {
|
||||
if (!isNewer(specificationVersion,
|
||||
required.getSpecificationVersion()))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If specified, Implementation Vendor ID must match
|
||||
if (required.getImplementationVendorId() != null) {
|
||||
if (implementationVendorId == null)
|
||||
return false;
|
||||
if (!implementationVendorId.equals(required
|
||||
.getImplementationVendorId()))
|
||||
return false;
|
||||
}
|
||||
|
||||
// If specified, Implementation version must be >= required
|
||||
if (required.getImplementationVersion() != null) {
|
||||
if (!isNewer(implementationVersion,
|
||||
required.getImplementationVersion()))
|
||||
return false;
|
||||
}
|
||||
|
||||
// This available optional package satisfies the requirements
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("Extension[");
|
||||
sb.append(extensionName);
|
||||
if (implementationURL != null) {
|
||||
sb.append(", implementationURL=");
|
||||
sb.append(implementationURL);
|
||||
}
|
||||
if (implementationVendor != null) {
|
||||
sb.append(", implementationVendor=");
|
||||
sb.append(implementationVendor);
|
||||
}
|
||||
if (implementationVendorId != null) {
|
||||
sb.append(", implementationVendorId=");
|
||||
sb.append(implementationVendorId);
|
||||
}
|
||||
if (implementationVersion != null) {
|
||||
sb.append(", implementationVersion=");
|
||||
sb.append(implementationVersion);
|
||||
}
|
||||
if (specificationVendor != null) {
|
||||
sb.append(", specificationVendor=");
|
||||
sb.append(specificationVendor);
|
||||
}
|
||||
if (specificationVersion != null) {
|
||||
sb.append(", specificationVersion=");
|
||||
sb.append(specificationVersion);
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Private Methods
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Return <code>true</code> if the first version number is greater than
|
||||
* or equal to the second; otherwise return <code>false</code>.
|
||||
*
|
||||
* @param first First version number (dotted decimal)
|
||||
* @param second Second version number (dotted decimal)
|
||||
*
|
||||
* @exception NumberFormatException on a malformed version number
|
||||
*/
|
||||
private boolean isNewer(String first, String second)
|
||||
throws NumberFormatException {
|
||||
|
||||
if ((first == null) || (second == null))
|
||||
return false;
|
||||
if (first.equals(second))
|
||||
return true;
|
||||
|
||||
StringTokenizer fTok = new StringTokenizer(first, ".", true);
|
||||
StringTokenizer sTok = new StringTokenizer(second, ".", true);
|
||||
int fVersion = 0;
|
||||
int sVersion = 0;
|
||||
while (fTok.hasMoreTokens() || sTok.hasMoreTokens()) {
|
||||
if (fTok.hasMoreTokens())
|
||||
fVersion = Integer.parseInt(fTok.nextToken());
|
||||
else
|
||||
fVersion = 0;
|
||||
if (sTok.hasMoreTokens())
|
||||
sVersion = Integer.parseInt(sTok.nextToken());
|
||||
else
|
||||
sVersion = 0;
|
||||
if (fVersion < sVersion)
|
||||
return false;
|
||||
else if (fVersion > sVersion)
|
||||
return true;
|
||||
if (fTok.hasMoreTokens()) // Swallow the periods
|
||||
fTok.nextToken();
|
||||
if (sTok.hasMoreTokens())
|
||||
sTok.nextToken();
|
||||
}
|
||||
|
||||
return true; // Exact match
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
365
java/org/apache/catalina/util/ExtensionValidator.java
Normal file
365
java/org/apache/catalina/util/ExtensionValidator.java
Normal file
@@ -0,0 +1,365 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Locale;
|
||||
import java.util.StringTokenizer;
|
||||
import java.util.jar.JarInputStream;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.WebResource;
|
||||
import org.apache.catalina.WebResourceRoot;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
|
||||
/**
|
||||
* Ensures that all extension dependencies are resolved for a WEB application
|
||||
* are met. This class builds a master list of extensions available to an
|
||||
* application and then validates those extensions.
|
||||
*
|
||||
* See http://docs.oracle.com/javase/1.4.2/docs/guide/extensions/spec.html
|
||||
* for a detailed explanation of the extension mechanism in Java.
|
||||
*
|
||||
* @author Greg Murray
|
||||
* @author Justyna Horwat
|
||||
*/
|
||||
public final class ExtensionValidator {
|
||||
|
||||
private static final Log log = LogFactory.getLog(ExtensionValidator.class);
|
||||
|
||||
/**
|
||||
* The string resources for this package.
|
||||
*/
|
||||
private static final StringManager sm =
|
||||
StringManager.getManager("org.apache.catalina.util");
|
||||
|
||||
private static volatile ArrayList<Extension> containerAvailableExtensions =
|
||||
null;
|
||||
private static final ArrayList<ManifestResource> containerManifestResources =
|
||||
new ArrayList<>();
|
||||
|
||||
|
||||
// ----------------------------------------------------- Static Initializer
|
||||
|
||||
|
||||
/**
|
||||
* This static initializer loads the container level extensions that are
|
||||
* available to all web applications. This method scans all extension
|
||||
* directories available via the "java.ext.dirs" System property.
|
||||
*
|
||||
* The System Class-Path is also scanned for jar files that may contain
|
||||
* available extensions.
|
||||
*/
|
||||
static {
|
||||
|
||||
// check for container level optional packages
|
||||
String systemClasspath = System.getProperty("java.class.path");
|
||||
|
||||
StringTokenizer strTok = new StringTokenizer(systemClasspath,
|
||||
File.pathSeparator);
|
||||
|
||||
// build a list of jar files in the classpath
|
||||
while (strTok.hasMoreTokens()) {
|
||||
String classpathItem = strTok.nextToken();
|
||||
if (classpathItem.toLowerCase(Locale.ENGLISH).endsWith(".jar")) {
|
||||
File item = new File(classpathItem);
|
||||
if (item.isFile()) {
|
||||
try {
|
||||
addSystemResource(item);
|
||||
} catch (IOException e) {
|
||||
log.error(sm.getString
|
||||
("extensionValidator.failload", item), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add specified folders to the list
|
||||
addFolderList("java.ext.dirs");
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Runtime validation of a Web Application.
|
||||
*
|
||||
* This method uses JNDI to look up the resources located under a
|
||||
* <code>DirContext</code>. It locates Web Application MANIFEST.MF
|
||||
* file in the /META-INF/ directory of the application and all
|
||||
* MANIFEST.MF files in each JAR file located in the WEB-INF/lib
|
||||
* directory and creates an <code>ArrayList</code> of
|
||||
* <code>ManifestResource</code> objects. These objects are then passed
|
||||
* to the validateManifestResources method for validation.
|
||||
*
|
||||
* @param resources The resources configured for this Web Application
|
||||
* @param context The context from which the Logger and path to the
|
||||
* application
|
||||
*
|
||||
* @return true if all required extensions satisfied
|
||||
* @throws IOException Error reading resources needed for validation
|
||||
*/
|
||||
public static synchronized boolean validateApplication(
|
||||
WebResourceRoot resources,
|
||||
Context context)
|
||||
throws IOException {
|
||||
|
||||
String appName = context.getName();
|
||||
ArrayList<ManifestResource> appManifestResources = new ArrayList<>();
|
||||
|
||||
// Web application manifest
|
||||
WebResource resource = resources.getResource("/META-INF/MANIFEST.MF");
|
||||
if (resource.isFile()) {
|
||||
try (InputStream inputStream = resource.getInputStream()) {
|
||||
Manifest manifest = new Manifest(inputStream);
|
||||
ManifestResource mre = new ManifestResource
|
||||
(sm.getString("extensionValidator.web-application-manifest"),
|
||||
manifest, ManifestResource.WAR);
|
||||
appManifestResources.add(mre);
|
||||
}
|
||||
}
|
||||
|
||||
// Web application library manifests
|
||||
WebResource[] manifestResources =
|
||||
resources.getClassLoaderResources("/META-INF/MANIFEST.MF");
|
||||
for (WebResource manifestResource : manifestResources) {
|
||||
if (manifestResource.isFile()) {
|
||||
// Primarily used for error reporting
|
||||
String jarName = manifestResource.getURL().toExternalForm();
|
||||
Manifest jmanifest = manifestResource.getManifest();
|
||||
if (jmanifest != null) {
|
||||
ManifestResource mre = new ManifestResource(jarName,
|
||||
jmanifest, ManifestResource.APPLICATION);
|
||||
appManifestResources.add(mre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return validateManifestResources(appName, appManifestResources);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks to see if the given system JAR file contains a MANIFEST, and adds
|
||||
* it to the container's manifest resources.
|
||||
*
|
||||
* @param jarFile The system JAR whose manifest to add
|
||||
* @throws IOException Error reading JAR file
|
||||
*/
|
||||
public static void addSystemResource(File jarFile) throws IOException {
|
||||
try (InputStream is = new FileInputStream(jarFile)) {
|
||||
Manifest manifest = getManifest(is);
|
||||
if (manifest != null) {
|
||||
ManifestResource mre = new ManifestResource(jarFile.getAbsolutePath(), manifest,
|
||||
ManifestResource.SYSTEM);
|
||||
containerManifestResources.add(mre);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Private Methods
|
||||
|
||||
|
||||
/**
|
||||
* Validates a <code>ArrayList</code> of <code>ManifestResource</code>
|
||||
* objects. This method requires an application name (which is the
|
||||
* context root of the application at runtime).
|
||||
*
|
||||
* <code>false</false> is returned if the extension dependencies
|
||||
* represented by any given <code>ManifestResource</code> objects
|
||||
* is not met.
|
||||
*
|
||||
* This method should also provide static validation of a Web Application
|
||||
* if provided with the necessary parameters.
|
||||
*
|
||||
* @param appName The name of the Application that will appear in the
|
||||
* error messages
|
||||
* @param resources A list of <code>ManifestResource</code> objects
|
||||
* to be validated.
|
||||
*
|
||||
* @return true if manifest resource file requirements are met
|
||||
*/
|
||||
private static boolean validateManifestResources(String appName,
|
||||
ArrayList<ManifestResource> resources) {
|
||||
boolean passes = true;
|
||||
int failureCount = 0;
|
||||
ArrayList<Extension> availableExtensions = null;
|
||||
|
||||
for (ManifestResource mre : resources) {
|
||||
ArrayList<Extension> requiredList = mre.getRequiredExtensions();
|
||||
if (requiredList == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// build the list of available extensions if necessary
|
||||
if (availableExtensions == null) {
|
||||
availableExtensions = buildAvailableExtensionsList(resources);
|
||||
}
|
||||
|
||||
// load the container level resource map if it has not been built
|
||||
// yet
|
||||
if (containerAvailableExtensions == null) {
|
||||
containerAvailableExtensions
|
||||
= buildAvailableExtensionsList(containerManifestResources);
|
||||
}
|
||||
|
||||
// iterate through the list of required extensions
|
||||
for (Extension requiredExt : requiredList) {
|
||||
boolean found = false;
|
||||
// check the application itself for the extension
|
||||
if (availableExtensions != null) {
|
||||
for (Extension targetExt : availableExtensions) {
|
||||
if (targetExt.isCompatibleWith(requiredExt)) {
|
||||
requiredExt.setFulfilled(true);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// check the container level list for the extension
|
||||
if (!found && containerAvailableExtensions != null) {
|
||||
for (Extension targetExt : containerAvailableExtensions) {
|
||||
if (targetExt.isCompatibleWith(requiredExt)) {
|
||||
requiredExt.setFulfilled(true);
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found) {
|
||||
// Failure
|
||||
log.info(sm.getString(
|
||||
"extensionValidator.extension-not-found-error",
|
||||
appName, mre.getResourceName(),
|
||||
requiredExt.getExtensionName()));
|
||||
passes = false;
|
||||
failureCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!passes) {
|
||||
log.info(sm.getString(
|
||||
"extensionValidator.extension-validation-error", appName,
|
||||
failureCount + ""));
|
||||
}
|
||||
|
||||
return passes;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build this list of available extensions so that we do not have to
|
||||
* re-build this list every time we iterate through the list of required
|
||||
* extensions. All available extensions in all of the
|
||||
* <code>ManifestResource</code> objects will be added to a
|
||||
* <code>HashMap</code> which is returned on the first dependency list
|
||||
* processing pass.
|
||||
*
|
||||
* The key is the name + implementation version.
|
||||
*
|
||||
* NOTE: A list is built only if there is a dependency that needs
|
||||
* to be checked (performance optimization).
|
||||
*
|
||||
* @param resources A list of <code>ManifestResource</code> objects
|
||||
*
|
||||
* @return HashMap Map of available extensions
|
||||
*/
|
||||
private static ArrayList<Extension> buildAvailableExtensionsList(
|
||||
ArrayList<ManifestResource> resources) {
|
||||
|
||||
ArrayList<Extension> availableList = null;
|
||||
|
||||
for (ManifestResource mre : resources) {
|
||||
ArrayList<Extension> list = mre.getAvailableExtensions();
|
||||
if (list != null) {
|
||||
for (Extension ext : list) {
|
||||
if (availableList == null) {
|
||||
availableList = new ArrayList<>();
|
||||
availableList.add(ext);
|
||||
} else {
|
||||
availableList.add(ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return availableList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the Manifest from a jar file or war file
|
||||
*
|
||||
* @param inStream Input stream to a WAR or JAR file
|
||||
* @return The WAR's or JAR's manifest
|
||||
*/
|
||||
private static Manifest getManifest(InputStream inStream) throws IOException {
|
||||
Manifest manifest = null;
|
||||
try (JarInputStream jin = new JarInputStream(inStream)) {
|
||||
manifest = jin.getManifest();
|
||||
}
|
||||
return manifest;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add the JARs specified to the extension list.
|
||||
*/
|
||||
private static void addFolderList(String property) {
|
||||
|
||||
// get the files in the extensions directory
|
||||
String extensionsDir = System.getProperty(property);
|
||||
if (extensionsDir != null) {
|
||||
StringTokenizer extensionsTok
|
||||
= new StringTokenizer(extensionsDir, File.pathSeparator);
|
||||
while (extensionsTok.hasMoreTokens()) {
|
||||
File targetDir = new File(extensionsTok.nextToken());
|
||||
if (!targetDir.isDirectory()) {
|
||||
continue;
|
||||
}
|
||||
File[] files = targetDir.listFiles();
|
||||
if (files == null) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (files[i].getName().toLowerCase(Locale.ENGLISH).endsWith(".jar") &&
|
||||
files[i].isFile()) {
|
||||
try {
|
||||
addSystemResource(files[i]);
|
||||
} catch (IOException e) {
|
||||
log.error
|
||||
(sm.getString
|
||||
("extensionValidator.failload", files[i]), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
110
java/org/apache/catalina/util/IOTools.java
Normal file
110
java/org/apache/catalina/util/IOTools.java
Normal file
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.Writer;
|
||||
|
||||
|
||||
/**
|
||||
* Contains commonly needed I/O-related methods
|
||||
*
|
||||
* @author Dan Sandberg
|
||||
*/
|
||||
public class IOTools {
|
||||
protected static final int DEFAULT_BUFFER_SIZE=4*1024; //4k
|
||||
|
||||
private IOTools() {
|
||||
//Ensure non-instantiability
|
||||
}
|
||||
|
||||
/**
|
||||
* Read input from reader and write it to writer until there is no more
|
||||
* input from reader.
|
||||
*
|
||||
* @param reader the reader to read from.
|
||||
* @param writer the writer to write to.
|
||||
* @param buf the char array to use as a buffer
|
||||
* @throws IOException IO error
|
||||
*/
|
||||
public static void flow( Reader reader, Writer writer, char[] buf )
|
||||
throws IOException {
|
||||
int numRead;
|
||||
while ( (numRead = reader.read(buf) ) >= 0) {
|
||||
writer.write(buf, 0, numRead);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read input from reader and write it to writer until there is no more
|
||||
* input from reader.
|
||||
*
|
||||
* @param reader the reader to read from.
|
||||
* @param writer the writer to write to.
|
||||
* @throws IOException IO error
|
||||
* @see #flow( Reader, Writer, char[] )
|
||||
*/
|
||||
public static void flow( Reader reader, Writer writer )
|
||||
throws IOException {
|
||||
char[] buf = new char[DEFAULT_BUFFER_SIZE];
|
||||
flow( reader, writer, buf );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read input from input stream and write it to output stream until there is
|
||||
* no more input from input stream using a new buffer of the default size
|
||||
* (4kB).
|
||||
*
|
||||
* @param is input stream the input stream to read from.
|
||||
* @param os output stream the output stream to write to.
|
||||
*
|
||||
* @throws IOException If an I/O error occurs during the copy
|
||||
*/
|
||||
public static void flow(InputStream is, OutputStream os) throws IOException {
|
||||
byte[] buf = new byte[DEFAULT_BUFFER_SIZE];
|
||||
int numRead;
|
||||
while ( (numRead = is.read(buf) ) >= 0) {
|
||||
if (os != null) {
|
||||
os.write(buf, 0, numRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read until EOF or the buffer is filled.
|
||||
*
|
||||
* @param is The source to read from
|
||||
* @param buf The buffer to write to
|
||||
*
|
||||
* @return The number of bytes read
|
||||
*
|
||||
* @throws IOException If an I/O error occurs during the read
|
||||
*/
|
||||
public static int readFully(InputStream is, byte[] buf) throws IOException {
|
||||
int bytesRead = 0;
|
||||
int read;
|
||||
while (bytesRead < buf.length && ((read = is.read(buf, bytesRead, buf.length - bytesRead)) >= 0)) {
|
||||
bytesRead += read;
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
}
|
||||
192
java/org/apache/catalina/util/Introspection.java
Normal file
192
java/org/apache/catalina/util/Introspection.java
Normal file
@@ -0,0 +1,192 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.beans.Introspector;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.security.AccessController;
|
||||
import java.security.PrivilegedAction;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
import org.apache.catalina.Globals;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Provides introspection utilities that either require knowledge of Tomcat
|
||||
* internals or are solely used by Tomcat internals.
|
||||
*/
|
||||
public class Introspection {
|
||||
|
||||
private static final StringManager sm =
|
||||
StringManager.getManager("org.apache.catalina.util");
|
||||
|
||||
|
||||
/**
|
||||
* Extract the Java Bean property name from the setter name.
|
||||
*
|
||||
* Note: This method assumes that the method name has already been checked
|
||||
* for correctness.
|
||||
* @param setter The setter method
|
||||
* @return the bean property name
|
||||
*/
|
||||
public static String getPropertyName(Method setter) {
|
||||
return Introspector.decapitalize(setter.getName().substring(3));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines if a method has a valid name and signature for a Java Bean
|
||||
* setter.
|
||||
*
|
||||
* @param method The method to test
|
||||
*
|
||||
* @return <code>true</code> if the method does have a valid name and
|
||||
* signature, else <code>false</code>
|
||||
*/
|
||||
public static boolean isValidSetter(Method method) {
|
||||
if (method.getName().startsWith("set")
|
||||
&& method.getName().length() > 3
|
||||
&& method.getParameterTypes().length == 1
|
||||
&& method.getReturnType().getName().equals("void")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if a method is a valid lifecycle callback method.
|
||||
*
|
||||
* @param method
|
||||
* The method to test
|
||||
*
|
||||
* @return <code>true</code> if the method is a valid lifecycle callback
|
||||
* method, else <code>false</code>
|
||||
*/
|
||||
public static boolean isValidLifecycleCallback(Method method) {
|
||||
if (method.getParameterTypes().length != 0
|
||||
|| Modifier.isStatic(method.getModifiers())
|
||||
|| method.getExceptionTypes().length > 0
|
||||
|| !method.getReturnType().getName().equals("void")) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the declared fields for a class taking account of any security
|
||||
* manager that may be configured.
|
||||
* @param clazz The class to introspect
|
||||
* @return the class fields as an array
|
||||
*/
|
||||
public static Field[] getDeclaredFields(final Class<?> clazz) {
|
||||
Field[] fields = null;
|
||||
if (Globals.IS_SECURITY_ENABLED) {
|
||||
fields = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Field[]>(){
|
||||
@Override
|
||||
public Field[] run(){
|
||||
return clazz.getDeclaredFields();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
fields = clazz.getDeclaredFields();
|
||||
}
|
||||
return fields;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the declared methods for a class taking account of any security
|
||||
* manager that may be configured.
|
||||
* @param clazz The class to introspect
|
||||
* @return the class methods as an array
|
||||
*/
|
||||
public static Method[] getDeclaredMethods(final Class<?> clazz) {
|
||||
Method[] methods = null;
|
||||
if (Globals.IS_SECURITY_ENABLED) {
|
||||
methods = AccessController.doPrivileged(
|
||||
new PrivilegedAction<Method[]>(){
|
||||
@Override
|
||||
public Method[] run(){
|
||||
return clazz.getDeclaredMethods();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
methods = clazz.getDeclaredMethods();
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Attempt to load a class using the given Container's class loader. If the
|
||||
* class cannot be loaded, a debug level log message will be written to the
|
||||
* Container's log and null will be returned.
|
||||
* @param context The class loader of this context will be used to attempt
|
||||
* to load the class
|
||||
* @param className The class name
|
||||
* @return the loaded class or <code>null</code> if loading failed
|
||||
*/
|
||||
public static Class<?> loadClass(Context context, String className) {
|
||||
ClassLoader cl = context.getLoader().getClassLoader();
|
||||
Log log = context.getLogger();
|
||||
Class<?> clazz = null;
|
||||
try {
|
||||
clazz = cl.loadClass(className);
|
||||
} catch (ClassNotFoundException | NoClassDefFoundError | ClassFormatError e) {
|
||||
log.debug(sm.getString("introspection.classLoadFailed", className), e);
|
||||
} catch (Throwable t) {
|
||||
ExceptionUtils.handleThrowable(t);
|
||||
log.debug(sm.getString("introspection.classLoadFailed", className), t);
|
||||
}
|
||||
return clazz;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts the primitive type to its corresponding wrapper.
|
||||
*
|
||||
* @param clazz
|
||||
* Class that will be evaluated
|
||||
* @return if the parameter is a primitive type returns its wrapper;
|
||||
* otherwise returns the same class
|
||||
*/
|
||||
public static Class<?> convertPrimitiveType(Class<?> clazz) {
|
||||
if (clazz.equals(char.class)) {
|
||||
return Character.class;
|
||||
} else if (clazz.equals(int.class)) {
|
||||
return Integer.class;
|
||||
} else if (clazz.equals(boolean.class)) {
|
||||
return Boolean.class;
|
||||
} else if (clazz.equals(double.class)) {
|
||||
return Double.class;
|
||||
} else if (clazz.equals(byte.class)) {
|
||||
return Byte.class;
|
||||
} else if (clazz.equals(short.class)) {
|
||||
return Short.class;
|
||||
} else if (clazz.equals(long.class)) {
|
||||
return Long.class;
|
||||
} else if (clazz.equals(float.class)) {
|
||||
return Float.class;
|
||||
} else {
|
||||
return clazz;
|
||||
}
|
||||
}
|
||||
}
|
||||
447
java/org/apache/catalina/util/LifecycleBase.java
Normal file
447
java/org/apache/catalina/util/LifecycleBase.java
Normal file
@@ -0,0 +1,447 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import org.apache.catalina.Lifecycle;
|
||||
import org.apache.catalina.LifecycleEvent;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.LifecycleListener;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Base implementation of the {@link Lifecycle} interface that implements the
|
||||
* state transition rules for {@link Lifecycle#start()} and
|
||||
* {@link Lifecycle#stop()}
|
||||
*/
|
||||
public abstract class LifecycleBase implements Lifecycle {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LifecycleBase.class);
|
||||
|
||||
private static final StringManager sm = StringManager.getManager(LifecycleBase.class);
|
||||
|
||||
|
||||
/**
|
||||
* The list of registered LifecycleListeners for event notifications.
|
||||
*/
|
||||
private final List<LifecycleListener> lifecycleListeners = new CopyOnWriteArrayList<>();
|
||||
|
||||
|
||||
/**
|
||||
* The current state of the source component.
|
||||
*/
|
||||
private volatile LifecycleState state = LifecycleState.NEW;
|
||||
|
||||
|
||||
private boolean throwOnFailure = true;
|
||||
|
||||
|
||||
/**
|
||||
* Will a {@link LifecycleException} thrown by a sub-class during
|
||||
* {@link #initInternal()}, {@link #startInternal()},
|
||||
* {@link #stopInternal()} or {@link #destroyInternal()} be re-thrown for
|
||||
* the caller to handle or will it be logged instead?
|
||||
*
|
||||
* @return {@code true} if the exception will be re-thrown, otherwise
|
||||
* {@code false}
|
||||
*/
|
||||
public boolean getThrowOnFailure() {
|
||||
return throwOnFailure;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Configure if a {@link LifecycleException} thrown by a sub-class during
|
||||
* {@link #initInternal()}, {@link #startInternal()},
|
||||
* {@link #stopInternal()} or {@link #destroyInternal()} will be re-thrown
|
||||
* for the caller to handle or if it will be logged instead.
|
||||
*
|
||||
* @param throwOnFailure {@code true} if the exception should be re-thrown,
|
||||
* otherwise {@code false}
|
||||
*/
|
||||
public void setThrowOnFailure(boolean throwOnFailure) {
|
||||
this.throwOnFailure = throwOnFailure;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void addLifecycleListener(LifecycleListener listener) {
|
||||
lifecycleListeners.add(listener);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public LifecycleListener[] findLifecycleListeners() {
|
||||
return lifecycleListeners.toArray(new LifecycleListener[0]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void removeLifecycleListener(LifecycleListener listener) {
|
||||
lifecycleListeners.remove(listener);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allow sub classes to fire {@link Lifecycle} events.
|
||||
*
|
||||
* @param type Event type
|
||||
* @param data Data associated with event.
|
||||
*/
|
||||
protected void fireLifecycleEvent(String type, Object data) {
|
||||
LifecycleEvent event = new LifecycleEvent(this, type, data);
|
||||
for (LifecycleListener listener : lifecycleListeners) {
|
||||
listener.lifecycleEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public final synchronized void init() throws LifecycleException {
|
||||
if (!state.equals(LifecycleState.NEW)) {
|
||||
invalidTransition(Lifecycle.BEFORE_INIT_EVENT);
|
||||
}
|
||||
|
||||
try {
|
||||
setStateInternal(LifecycleState.INITIALIZING, null, false);
|
||||
initInternal();
|
||||
setStateInternal(LifecycleState.INITIALIZED, null, false);
|
||||
} catch (Throwable t) {
|
||||
handleSubClassException(t, "lifecycleBase.initFail", toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sub-classes implement this method to perform any instance initialisation
|
||||
* required.
|
||||
*
|
||||
* @throws LifecycleException If the initialisation fails
|
||||
*/
|
||||
protected abstract void initInternal() throws LifecycleException;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final synchronized void start() throws LifecycleException {
|
||||
|
||||
if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) ||
|
||||
LifecycleState.STARTED.equals(state)) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
Exception e = new LifecycleException();
|
||||
log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e);
|
||||
} else if (log.isInfoEnabled()) {
|
||||
log.info(sm.getString("lifecycleBase.alreadyStarted", toString()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.equals(LifecycleState.NEW)) {
|
||||
init();
|
||||
} else if (state.equals(LifecycleState.FAILED)) {
|
||||
stop();
|
||||
} else if (!state.equals(LifecycleState.INITIALIZED) &&
|
||||
!state.equals(LifecycleState.STOPPED)) {
|
||||
invalidTransition(Lifecycle.BEFORE_START_EVENT);
|
||||
}
|
||||
|
||||
try {
|
||||
setStateInternal(LifecycleState.STARTING_PREP, null, false);
|
||||
startInternal();
|
||||
if (state.equals(LifecycleState.FAILED)) {
|
||||
// This is a 'controlled' failure. The component put itself into the
|
||||
// FAILED state so call stop() to complete the clean-up.
|
||||
stop();
|
||||
} else if (!state.equals(LifecycleState.STARTING)) {
|
||||
// Shouldn't be necessary but acts as a check that sub-classes are
|
||||
// doing what they are supposed to.
|
||||
invalidTransition(Lifecycle.AFTER_START_EVENT);
|
||||
} else {
|
||||
setStateInternal(LifecycleState.STARTED, null, false);
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
// This is an 'uncontrolled' failure so put the component into the
|
||||
// FAILED state and throw an exception.
|
||||
handleSubClassException(t, "lifecycleBase.startFail", toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sub-classes must ensure that the state is changed to
|
||||
* {@link LifecycleState#STARTING} during the execution of this method.
|
||||
* Changing state will trigger the {@link Lifecycle#START_EVENT} event.
|
||||
*
|
||||
* If a component fails to start it may either throw a
|
||||
* {@link LifecycleException} which will cause it's parent to fail to start
|
||||
* or it can place itself in the error state in which case {@link #stop()}
|
||||
* will be called on the failed component but the parent component will
|
||||
* continue to start normally.
|
||||
*
|
||||
* @throws LifecycleException Start error occurred
|
||||
*/
|
||||
protected abstract void startInternal() throws LifecycleException;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public final synchronized void stop() throws LifecycleException {
|
||||
|
||||
if (LifecycleState.STOPPING_PREP.equals(state) || LifecycleState.STOPPING.equals(state) ||
|
||||
LifecycleState.STOPPED.equals(state)) {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
Exception e = new LifecycleException();
|
||||
log.debug(sm.getString("lifecycleBase.alreadyStopped", toString()), e);
|
||||
} else if (log.isInfoEnabled()) {
|
||||
log.info(sm.getString("lifecycleBase.alreadyStopped", toString()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.equals(LifecycleState.NEW)) {
|
||||
state = LifecycleState.STOPPED;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.equals(LifecycleState.STARTED) && !state.equals(LifecycleState.FAILED)) {
|
||||
invalidTransition(Lifecycle.BEFORE_STOP_EVENT);
|
||||
}
|
||||
|
||||
try {
|
||||
if (state.equals(LifecycleState.FAILED)) {
|
||||
// Don't transition to STOPPING_PREP as that would briefly mark the
|
||||
// component as available but do ensure the BEFORE_STOP_EVENT is
|
||||
// fired
|
||||
fireLifecycleEvent(BEFORE_STOP_EVENT, null);
|
||||
} else {
|
||||
setStateInternal(LifecycleState.STOPPING_PREP, null, false);
|
||||
}
|
||||
|
||||
stopInternal();
|
||||
|
||||
// Shouldn't be necessary but acts as a check that sub-classes are
|
||||
// doing what they are supposed to.
|
||||
if (!state.equals(LifecycleState.STOPPING) && !state.equals(LifecycleState.FAILED)) {
|
||||
invalidTransition(Lifecycle.AFTER_STOP_EVENT);
|
||||
}
|
||||
|
||||
setStateInternal(LifecycleState.STOPPED, null, false);
|
||||
} catch (Throwable t) {
|
||||
handleSubClassException(t, "lifecycleBase.stopFail", toString());
|
||||
} finally {
|
||||
if (this instanceof Lifecycle.SingleUse) {
|
||||
// Complete stop process first
|
||||
setStateInternal(LifecycleState.STOPPED, null, false);
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sub-classes must ensure that the state is changed to
|
||||
* {@link LifecycleState#STOPPING} during the execution of this method.
|
||||
* Changing state will trigger the {@link Lifecycle#STOP_EVENT} event.
|
||||
*
|
||||
* @throws LifecycleException Stop error occurred
|
||||
*/
|
||||
protected abstract void stopInternal() throws LifecycleException;
|
||||
|
||||
|
||||
@Override
|
||||
public final synchronized void destroy() throws LifecycleException {
|
||||
if (LifecycleState.FAILED.equals(state)) {
|
||||
try {
|
||||
// Triggers clean-up
|
||||
stop();
|
||||
} catch (LifecycleException e) {
|
||||
// Just log. Still want to destroy.
|
||||
log.error(sm.getString("lifecycleBase.destroyStopFail", toString()), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (LifecycleState.DESTROYING.equals(state) || LifecycleState.DESTROYED.equals(state)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
Exception e = new LifecycleException();
|
||||
log.debug(sm.getString("lifecycleBase.alreadyDestroyed", toString()), e);
|
||||
} else if (log.isInfoEnabled() && !(this instanceof Lifecycle.SingleUse)) {
|
||||
// Rather than have every component that might need to call
|
||||
// destroy() check for SingleUse, don't log an info message if
|
||||
// multiple calls are made to destroy()
|
||||
log.info(sm.getString("lifecycleBase.alreadyDestroyed", toString()));
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!state.equals(LifecycleState.STOPPED) && !state.equals(LifecycleState.FAILED) &&
|
||||
!state.equals(LifecycleState.NEW) && !state.equals(LifecycleState.INITIALIZED)) {
|
||||
invalidTransition(Lifecycle.BEFORE_DESTROY_EVENT);
|
||||
}
|
||||
|
||||
try {
|
||||
setStateInternal(LifecycleState.DESTROYING, null, false);
|
||||
destroyInternal();
|
||||
setStateInternal(LifecycleState.DESTROYED, null, false);
|
||||
} catch (Throwable t) {
|
||||
handleSubClassException(t, "lifecycleBase.destroyFail", toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sub-classes implement this method to perform any instance destruction
|
||||
* required.
|
||||
*
|
||||
* @throws LifecycleException If the destruction fails
|
||||
*/
|
||||
protected abstract void destroyInternal() throws LifecycleException;
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public LifecycleState getState() {
|
||||
return state;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public String getStateName() {
|
||||
return getState().toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides a mechanism for sub-classes to update the component state.
|
||||
* Calling this method will automatically fire any associated
|
||||
* {@link Lifecycle} event. It will also check that any attempted state
|
||||
* transition is valid for a sub-class.
|
||||
*
|
||||
* @param state The new state for this component
|
||||
* @throws LifecycleException when attempting to set an invalid state
|
||||
*/
|
||||
protected synchronized void setState(LifecycleState state) throws LifecycleException {
|
||||
setStateInternal(state, null, true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Provides a mechanism for sub-classes to update the component state.
|
||||
* Calling this method will automatically fire any associated
|
||||
* {@link Lifecycle} event. It will also check that any attempted state
|
||||
* transition is valid for a sub-class.
|
||||
*
|
||||
* @param state The new state for this component
|
||||
* @param data The data to pass to the associated {@link Lifecycle} event
|
||||
* @throws LifecycleException when attempting to set an invalid state
|
||||
*/
|
||||
protected synchronized void setState(LifecycleState state, Object data)
|
||||
throws LifecycleException {
|
||||
setStateInternal(state, data, true);
|
||||
}
|
||||
|
||||
|
||||
private synchronized void setStateInternal(LifecycleState state, Object data, boolean check)
|
||||
throws LifecycleException {
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(sm.getString("lifecycleBase.setState", this, state));
|
||||
}
|
||||
|
||||
if (check) {
|
||||
// Must have been triggered by one of the abstract methods (assume
|
||||
// code in this class is correct)
|
||||
// null is never a valid state
|
||||
if (state == null) {
|
||||
invalidTransition("null");
|
||||
// Unreachable code - here to stop eclipse complaining about
|
||||
// a possible NPE further down the method
|
||||
return;
|
||||
}
|
||||
|
||||
// Any method can transition to failed
|
||||
// startInternal() permits STARTING_PREP to STARTING
|
||||
// stopInternal() permits STOPPING_PREP to STOPPING and FAILED to
|
||||
// STOPPING
|
||||
if (!(state == LifecycleState.FAILED ||
|
||||
(this.state == LifecycleState.STARTING_PREP &&
|
||||
state == LifecycleState.STARTING) ||
|
||||
(this.state == LifecycleState.STOPPING_PREP &&
|
||||
state == LifecycleState.STOPPING) ||
|
||||
(this.state == LifecycleState.FAILED &&
|
||||
state == LifecycleState.STOPPING))) {
|
||||
// No other transition permitted
|
||||
invalidTransition(state.name());
|
||||
}
|
||||
}
|
||||
|
||||
this.state = state;
|
||||
String lifecycleEvent = state.getLifecycleEvent();
|
||||
if (lifecycleEvent != null) {
|
||||
fireLifecycleEvent(lifecycleEvent, data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void invalidTransition(String type) throws LifecycleException {
|
||||
String msg = sm.getString("lifecycleBase.invalidTransition", type, toString(), state);
|
||||
throw new LifecycleException(msg);
|
||||
}
|
||||
|
||||
|
||||
private void handleSubClassException(Throwable t, String key, Object... args) throws LifecycleException {
|
||||
setStateInternal(LifecycleState.FAILED, null, false);
|
||||
ExceptionUtils.handleThrowable(t);
|
||||
String msg = sm.getString(key, args);
|
||||
if (getThrowOnFailure()) {
|
||||
if (!(t instanceof LifecycleException)) {
|
||||
t = new LifecycleException(msg, t);
|
||||
}
|
||||
throw (LifecycleException) t;
|
||||
} else {
|
||||
log.error(msg, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
247
java/org/apache/catalina/util/LifecycleMBeanBase.java
Normal file
247
java/org/apache/catalina/util/LifecycleMBeanBase.java
Normal file
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import javax.management.InstanceNotFoundException;
|
||||
import javax.management.MBeanRegistrationException;
|
||||
import javax.management.MBeanServer;
|
||||
import javax.management.MalformedObjectNameException;
|
||||
import javax.management.ObjectName;
|
||||
|
||||
import org.apache.catalina.Globals;
|
||||
import org.apache.catalina.JmxEnabled;
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.modeler.Registry;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
public abstract class LifecycleMBeanBase extends LifecycleBase
|
||||
implements JmxEnabled {
|
||||
|
||||
private static final Log log = LogFactory.getLog(LifecycleMBeanBase.class);
|
||||
|
||||
private static final StringManager sm =
|
||||
StringManager.getManager("org.apache.catalina.util");
|
||||
|
||||
|
||||
/* Cache components of the MBean registration. */
|
||||
private String domain = null;
|
||||
private ObjectName oname = null;
|
||||
protected MBeanServer mserver = null;
|
||||
|
||||
/**
|
||||
* Sub-classes wishing to perform additional initialization should override
|
||||
* this method, ensuring that super.initInternal() is the first call in the
|
||||
* overriding method.
|
||||
*/
|
||||
@Override
|
||||
protected void initInternal() throws LifecycleException {
|
||||
// If oname is not null then registration has already happened via
|
||||
// preRegister().
|
||||
if (oname == null) {
|
||||
mserver = Registry.getRegistry(null, null).getMBeanServer();
|
||||
|
||||
oname = register(this, getObjectNameKeyProperties());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sub-classes wishing to perform additional clean-up should override this
|
||||
* method, ensuring that super.destroyInternal() is the last call in the
|
||||
* overriding method.
|
||||
*/
|
||||
@Override
|
||||
protected void destroyInternal() throws LifecycleException {
|
||||
unregister(oname);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the domain under which this component should be registered. Used
|
||||
* with components that cannot (easily) navigate the component hierarchy to
|
||||
* determine the correct domain to use.
|
||||
*/
|
||||
@Override
|
||||
public final void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the domain under which this component will be / has been
|
||||
* registered.
|
||||
*/
|
||||
@Override
|
||||
public final String getDomain() {
|
||||
if (domain == null) {
|
||||
domain = getDomainInternal();
|
||||
}
|
||||
|
||||
if (domain == null) {
|
||||
domain = Globals.DEFAULT_MBEAN_DOMAIN;
|
||||
}
|
||||
|
||||
return domain;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method implemented by sub-classes to identify the domain in which MBeans
|
||||
* should be registered.
|
||||
*
|
||||
* @return The name of the domain to use to register MBeans.
|
||||
*/
|
||||
protected abstract String getDomainInternal();
|
||||
|
||||
|
||||
/**
|
||||
* Obtain the name under which this component has been registered with JMX.
|
||||
*/
|
||||
@Override
|
||||
public final ObjectName getObjectName() {
|
||||
return oname;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allow sub-classes to specify the key properties component of the
|
||||
* {@link ObjectName} that will be used to register this component.
|
||||
*
|
||||
* @return The string representation of the key properties component of the
|
||||
* desired {@link ObjectName}
|
||||
*/
|
||||
protected abstract String getObjectNameKeyProperties();
|
||||
|
||||
|
||||
/**
|
||||
* Utility method to enable sub-classes to easily register additional
|
||||
* components that don't implement {@link JmxEnabled} with an MBean server.
|
||||
* <br>
|
||||
* Note: This method should only be used once {@link #initInternal()} has
|
||||
* been called and before {@link #destroyInternal()} has been called.
|
||||
*
|
||||
* @param obj The object the register
|
||||
* @param objectNameKeyProperties The key properties component of the
|
||||
* object name to use to register the
|
||||
* object
|
||||
*
|
||||
* @return The name used to register the object
|
||||
*/
|
||||
protected final ObjectName register(Object obj,
|
||||
String objectNameKeyProperties) {
|
||||
|
||||
// Construct an object name with the right domain
|
||||
StringBuilder name = new StringBuilder(getDomain());
|
||||
name.append(':');
|
||||
name.append(objectNameKeyProperties);
|
||||
|
||||
ObjectName on = null;
|
||||
|
||||
try {
|
||||
on = new ObjectName(name.toString());
|
||||
Registry.getRegistry(null, null).registerComponent(obj, on, null);
|
||||
} catch (MalformedObjectNameException e) {
|
||||
log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name),
|
||||
e);
|
||||
} catch (Exception e) {
|
||||
log.warn(sm.getString("lifecycleMBeanBase.registerFail", obj, name),
|
||||
e);
|
||||
}
|
||||
|
||||
return on;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Utility method to enable sub-classes to easily unregister additional
|
||||
* components that don't implement {@link JmxEnabled} with an MBean server.
|
||||
* <br>
|
||||
* Note: This method should only be used once {@link #initInternal()} has
|
||||
* been called and before {@link #destroyInternal()} has been called.
|
||||
*
|
||||
* @param on The name of the component to unregister
|
||||
*/
|
||||
protected final void unregister(ObjectName on) {
|
||||
|
||||
// If null ObjectName, just return without complaint
|
||||
if (on == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the MBeanServer is null, log a warning & return
|
||||
if (mserver == null) {
|
||||
log.warn(sm.getString("lifecycleMBeanBase.unregisterNoServer", on));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
mserver.unregisterMBean(on);
|
||||
} catch (MBeanRegistrationException e) {
|
||||
log.warn(sm.getString("lifecycleMBeanBase.unregisterFail", on), e);
|
||||
} catch (InstanceNotFoundException e) {
|
||||
log.warn(sm.getString("lifecycleMBeanBase.unregisterFail", on), e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Not used - NOOP.
|
||||
*/
|
||||
@Override
|
||||
public final void postDeregister() {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Not used - NOOP.
|
||||
*/
|
||||
@Override
|
||||
public final void postRegister(Boolean registrationDone) {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Not used - NOOP.
|
||||
*/
|
||||
@Override
|
||||
public final void preDeregister() throws Exception {
|
||||
// NOOP
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allows the object to be registered with an alternative
|
||||
* {@link MBeanServer} and/or {@link ObjectName}.
|
||||
*/
|
||||
@Override
|
||||
public final ObjectName preRegister(MBeanServer server, ObjectName name)
|
||||
throws Exception {
|
||||
|
||||
this.mserver = server;
|
||||
this.oname = name;
|
||||
this.domain = name.getDomain().intern();
|
||||
|
||||
return oname;
|
||||
}
|
||||
|
||||
}
|
||||
58
java/org/apache/catalina/util/LocalStrings.properties
Normal file
58
java/org/apache/catalina/util/LocalStrings.properties
Normal file
@@ -0,0 +1,58 @@
|
||||
# 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.
|
||||
|
||||
SecurityUtil.doAsPrivilege=An exception occurs when running the PrivilegedExceptionAction block.
|
||||
|
||||
customObjectInputStream.logRequired=A valid logger is required for class name filtering with logging
|
||||
customObjectInputStream.nomatch=The class [{0}] did not match the regular expression [{1}] for classes allowed to be deserialized
|
||||
|
||||
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension [{2}] not found.
|
||||
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Failed to find [{1}] required extension(s).
|
||||
extensionValidator.failload=Failure loading extension [{0}]
|
||||
extensionValidator.web-application-manifest=Web Application Manifest
|
||||
|
||||
hexUtil.bad=Bad hexadecimal digit
|
||||
hexUtil.odd=Odd number of hexadecimal digits
|
||||
|
||||
introspection.classLoadFailed=Failed to load class [{0}]
|
||||
|
||||
lifecycleBase.alreadyDestroyed=The destroy() method was called on component [{0}] after destroy() had already been called. The second call will be ignored.
|
||||
lifecycleBase.alreadyStarted=The start() method was called on component [{0}] after start() had already been called. The second call will be ignored.
|
||||
lifecycleBase.alreadyStopped=The stop() method was called on component [{0}] after stop() had already been called. The second call will be ignored.
|
||||
lifecycleBase.destroyFail=Failed to destroy component [{0}]
|
||||
lifecycleBase.destroyStopFail=Called stop() on failed component [{0}] to trigger clean-up but it failed too
|
||||
lifecycleBase.initFail=Failed to initialize component [{0}]
|
||||
lifecycleBase.invalidTransition=An invalid Lifecycle transition was attempted ([{0}]) for component [{1}] in state [{2}]
|
||||
lifecycleBase.setState=Setting state for [{0}] to [{1}]
|
||||
lifecycleBase.startFail=Failed to start component [{0}]
|
||||
lifecycleBase.stopFail=Failed to stop component [{0}]
|
||||
|
||||
lifecycleMBeanBase.registerFail=Failed to register object [{0}] with name [{1}] during component initialisation
|
||||
lifecycleMBeanBase.unregisterFail=Failed to unregister MBean with name [{0}] during component destruction
|
||||
lifecycleMBeanBase.unregisterNoServer=No MBean server was available to unregister the MBean [{0}]
|
||||
|
||||
netmask.cidrNegative=The CIDR [{0}] is negative
|
||||
netmask.cidrNotNumeric=The CIDR [{0}] is not numeric
|
||||
netmask.cidrTooBig=The CIDR [{0}] is greater than the address length [{1}]
|
||||
netmask.invalidAddress=The address [{0}] is not valid
|
||||
|
||||
parameterMap.locked=No modifications are allowed to a locked ParameterMap
|
||||
|
||||
resourceSet.locked=No modifications are allowed to a locked ResourceSet
|
||||
|
||||
sessionIdGeneratorBase.createRandom=Creation of SecureRandom instance for session ID generation using [{0}] took [{1}] milliseconds.
|
||||
sessionIdGeneratorBase.random=Exception initializing random number generator of class [{0}]. Falling back to java.secure.SecureRandom
|
||||
sessionIdGeneratorBase.randomAlgorithm=Exception initializing random number generator using algorithm [{0}]
|
||||
sessionIdGeneratorBase.randomProvider=Exception initializing random number generator using provider [{0}]
|
||||
29
java/org/apache/catalina/util/LocalStrings_de.properties
Normal file
29
java/org/apache/catalina/util/LocalStrings_de.properties
Normal file
@@ -0,0 +1,29 @@
|
||||
# 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.
|
||||
|
||||
customObjectInputStream.logRequired=Ein gültiger Logger ist für Klassennamenfilterung mit Loggen nötig
|
||||
customObjectInputStream.nomatch=Die Klasse [{0}] wird nicht mit dem regulären Ausdruck [{1}] gefunden, der erlaubte deserialisierte Klassen bestimmt.
|
||||
|
||||
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Benötigte Erweiterung [{2}] nicht gefunden
|
||||
|
||||
introspection.classLoadFailed=Konnte Klasse [{0}] nicht laden
|
||||
|
||||
lifecycleBase.initFail=Konnte Komponente [{0}] nicht initialisieren
|
||||
lifecycleBase.setState=Setze Status für [{0}] auf [{1}]
|
||||
|
||||
netmask.cidrNegative=Die CIDR [{0}] ist negativ
|
||||
netmask.invalidAddress=Die Adresse [{0}] ist nicht gültig
|
||||
|
||||
sessionIdGeneratorBase.randomProvider=Während der Zufallsgenerator mit Hilfe des Providers [{0}] initialisiert wurde, trat eine Exception auf
|
||||
39
java/org/apache/catalina/util/LocalStrings_es.properties
Normal file
39
java/org/apache/catalina/util/LocalStrings_es.properties
Normal file
@@ -0,0 +1,39 @@
|
||||
# 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.
|
||||
|
||||
SecurityUtil.doAsPrivilege=Una excepción se ha producido durante la ejecución del bloque PrivilegedExceptionAction.
|
||||
|
||||
customObjectInputStream.logRequired=Se requiere un logeador váliso para el nombre de la clase filtrado con logeo
|
||||
customObjectInputStream.nomatch=La clase [{0}] no concuerda con la expresión regular [{1}] para clases que tienen permitido el deserializamiento
|
||||
|
||||
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: La extensión no encuentra el [{2}] requerido.
|
||||
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Imposible de hallar la(s) extension(es) [{1}] requerida(s).
|
||||
extensionValidator.failload=No pude cargar la extensión [{0}]
|
||||
extensionValidator.web-application-manifest=Manifiesto de Aplicación Web
|
||||
|
||||
hexUtil.bad=Dígito hexadecimal incorrecto
|
||||
hexUtil.odd=Número de dígitos hexadecimales impar
|
||||
|
||||
introspection.classLoadFailed=Fallo al cargar la clase [{0}]
|
||||
|
||||
lifecycleBase.initFail=Fallo al iniciar el componente [{0}]
|
||||
|
||||
netmask.cidrNegative=El CIDR [{0}] es negativo
|
||||
|
||||
parameterMap.locked=No se permiten modificaciones en un ParameterMap bloqueado
|
||||
|
||||
resourceSet.locked=No se permiten modificaciones en un ResourceSet bloqueado
|
||||
|
||||
sessionIdGeneratorBase.random=Excepción inicializando generador de números aleatorios de clase [{0}]
|
||||
56
java/org/apache/catalina/util/LocalStrings_fr.properties
Normal file
56
java/org/apache/catalina/util/LocalStrings_fr.properties
Normal file
@@ -0,0 +1,56 @@
|
||||
# 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.
|
||||
|
||||
SecurityUtil.doAsPrivilege=Une exception s'est produite lors de l'execution du bloc PrivilegedExceptionAction.
|
||||
|
||||
customObjectInputStream.logRequired=Un enregistreur ("logger") valide est requis pour filtrer par nom de classe
|
||||
customObjectInputStream.nomatch=La classe [{0}] n''est pas acceptée par l''expression régulière [{1}] qui autorise la désérialisation
|
||||
|
||||
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: L''extension requise [{2}] est introuvable.
|
||||
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: Impossible de trouver [{1}] extension(s) requise(s).
|
||||
extensionValidator.failload=Erreur de chargement de l''extension [{0}]
|
||||
extensionValidator.web-application-manifest=Web Application Manifest
|
||||
|
||||
hexUtil.bad=Mauvais digit hexadecimal
|
||||
hexUtil.odd=Nombre impair de digits hexadecimaux
|
||||
|
||||
introspection.classLoadFailed=Echec du chargement de la classe [{0}]
|
||||
|
||||
lifecycleBase.alreadyDestroyed=La méthode destroy() a été appelée sur le composant [{0}] après que destroy() ait déjà été appelé, le deuxième appel sera ignoré
|
||||
lifecycleBase.alreadyStarted=La méthode start() a été appelée sur le composant [{0}] après que start() ait déjà été appelé, le deuxième appel sera ignoré
|
||||
lifecycleBase.alreadyStopped=La méthode stop() a été appelée sur le composant [{0}] après que stop() ait déjà été appelé, le deuxième appel sera ignoré
|
||||
lifecycleBase.destroyFail=Echec de la destruction du composant [{0}]
|
||||
lifecycleBase.destroyStopFail=L''appel de stop() sur le composant en échec [{0}] pour causer un nettoyage a échoué
|
||||
lifecycleBase.initFail=Echec d''initialisation du composant [{0}]
|
||||
lifecycleBase.invalidTransition=Un transition de Lifecycle invalide a été tentée ([{0}]) pour le composant [{1}] dans l''état [{2}]
|
||||
lifecycleBase.setState=Fixe l''état pour [{0}] à [{1}]
|
||||
lifecycleBase.startFail=Echec de démarrage du composant [{0}]
|
||||
lifecycleBase.stopFail=Echec de l''arrêt du composant [{0}]
|
||||
|
||||
lifecycleMBeanBase.registerFail=Echec de l''enregistrement de l''objet [{0}] avec le nom [{1}] pendant l''initialisation du composant
|
||||
|
||||
netmask.cidrNegative=Le CIDR [{0}] est négatif
|
||||
netmask.cidrNotNumeric=Le CIDR [{0}] n''est pas un nombre
|
||||
netmask.cidrTooBig=Le CIDR [{0}] est plus grand que la longueur de l''adresse [{1}]
|
||||
netmask.invalidAddress=L''adresse [{0}] est invalide
|
||||
|
||||
parameterMap.locked=Aucune modification n'est autorisée sur un ParameterMap verrouillé
|
||||
|
||||
resourceSet.locked=Aucune modification n'est autorisée sur un ResourceSet verrouillé
|
||||
|
||||
sessionIdGeneratorBase.createRandom=La création de l''instance de SecureRandom pour le générateur d''id de session en utilisant [{0}] a pris [{1}] millisecondes
|
||||
sessionIdGeneratorBase.random=Exception durant l''initialisation de la classe du générateur de nombre aléatoire [{0}]
|
||||
sessionIdGeneratorBase.randomAlgorithm=Erreur lors de l''initialisation du générateur de nombres aléatoires en utilisant l''algorithme [{0}]
|
||||
sessionIdGeneratorBase.randomProvider=Exception lors de l''initialisation du générateur de nombres aléatoires utilisant le fournisseur [{0}]
|
||||
56
java/org/apache/catalina/util/LocalStrings_ja.properties
Normal file
56
java/org/apache/catalina/util/LocalStrings_ja.properties
Normal file
@@ -0,0 +1,56 @@
|
||||
# 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.
|
||||
|
||||
SecurityUtil.doAsPrivilege=PrivilegedExceptionActionブロックを実行中に例外が発生しました。
|
||||
|
||||
customObjectInputStream.logRequired=ロギングによるクラス名のフィルタリングには有効なロガーが必要です
|
||||
customObjectInputStream.nomatch=クラス [{0}] はデシリアライズの許可されたクラス名の正規表現 [{1}] にマッチしません。
|
||||
|
||||
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: 必要な拡張 [{2}] が見つかりません。
|
||||
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: 必要な拡張 [{1}] が見つかりません。
|
||||
extensionValidator.failload=拡張 [{0}] のロードに失敗しました
|
||||
extensionValidator.web-application-manifest=Webアプリケーションマニフェスト
|
||||
|
||||
hexUtil.bad=無効な16進数値です
|
||||
hexUtil.odd=奇数桁の16進数値です
|
||||
|
||||
introspection.classLoadFailed=クラス [{0}] の読み込みに失敗しました。
|
||||
|
||||
lifecycleBase.alreadyDestroyed=destroy()メソッドが既に呼び出された後で、コンポーネント[{0}]に対して呼び出されました。 2番目の呼び出しは無視されます。
|
||||
lifecycleBase.alreadyStarted=以前に start() を呼び出したコンポーネント [{0}] の start() を呼び出しました。二度目の呼び出しは無視します。
|
||||
lifecycleBase.alreadyStopped=stop()メソッドが既にコールされた後、コンポーネント[{0}]に対して呼び出されました。 2番目の呼び出しは無視されます。
|
||||
lifecycleBase.destroyFail=コンポーネント [{0}] を破棄できません。
|
||||
lifecycleBase.destroyStopFail=失敗したコンポーネント[{0}]に対してstop()を呼び出してクリーンアップをトリガーしましたが、失敗しました。
|
||||
lifecycleBase.initFail=コンポーネント[{0}] の初期化に失敗しました。
|
||||
lifecycleBase.invalidTransition=状態[{2}]のコンポーネント[{1}]の無効なライフサイクル遷移が試みられました([{0}])。
|
||||
lifecycleBase.setState=[{0}]の状態を[{1}]に設定します
|
||||
lifecycleBase.startFail=コンポーネント[{0}]の開始に失敗しました。
|
||||
lifecycleBase.stopFail=コンポーネント [{0}] を停止できません。
|
||||
|
||||
lifecycleMBeanBase.registerFail=コンポーネントの初期化時にオブジェクト [{0}] を名前 [{1}] で登録できませんでした。
|
||||
|
||||
netmask.cidrNegative=CIDR [{0}] に負の値が指定されています。
|
||||
netmask.cidrNotNumeric=CIDR [{0}]は数値ではありません
|
||||
netmask.cidrTooBig=CIDR [{0}] はアドレス範囲 [{1}] を越えています。
|
||||
netmask.invalidAddress=アドレス[{0}]は無効です
|
||||
|
||||
parameterMap.locked=ロックされたParameterMapは変更が許されません
|
||||
|
||||
resourceSet.locked=ロックされたResourceSetは変更が許されません
|
||||
|
||||
sessionIdGeneratorBase.createRandom=セッション ID を生成するための SecureRandom インスタンスの作成に [{1}] ミリ秒かかりました。アルゴリズムは [{1}] です。
|
||||
sessionIdGeneratorBase.random=クラス [{0}] の乱数発生器の初期化の例外です
|
||||
sessionIdGeneratorBase.randomAlgorithm=アルゴリズム[{0}]を使用して乱数ジェネレータを初期化する際の例外
|
||||
sessionIdGeneratorBase.randomProvider=プロバイダ[{0}]を使用して乱数ジェネレータを初期化中に例外が発生しました
|
||||
53
java/org/apache/catalina/util/LocalStrings_ko.properties
Normal file
53
java/org/apache/catalina/util/LocalStrings_ko.properties
Normal file
@@ -0,0 +1,53 @@
|
||||
# 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.
|
||||
|
||||
SecurityUtil.doAsPrivilege=PrivilegedExceptionAction 블록을 실행하는 동안 예외가 발생했습니다.
|
||||
|
||||
customObjectInputStream.logRequired=로그를 남기면서 클래스 이름을 필터링 하기 위해서는 유효한 Logger가 필요합니다.
|
||||
customObjectInputStream.nomatch=클래스 [{0}]은(는), 역직렬화 되도록 허용된 클래스들의 정규식 패턴 [{1}]과(와) 부합되지 않습니다.
|
||||
|
||||
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}] : 필수 extension [{2}]을(를) 찾을 수 없습니다.
|
||||
extensionValidator.extension-validation-error=ExtensionValidator[{0}]: 필수 extension(들)을 찾는 과정에서 [{1}]번의 실패 발생
|
||||
extensionValidator.failload=Extension [{0}]을(를) 로드하는 중 실패
|
||||
extensionValidator.web-application-manifest=웹 애플리케이션 Manifest
|
||||
|
||||
introspection.classLoadFailed=클래스 [{0}]을(를) 로드하지 못했습니다.
|
||||
|
||||
lifecycleBase.alreadyDestroyed=이미 destroy() 메소드가 호출되었던 구성요소 [{0}]에서, 다시 destroy()가 호출되었습니다. 두번째 호출은 무시될 것입니다.
|
||||
lifecycleBase.alreadyStarted=start()가 이미 호출된 후에, 구성요소 [{0}]에 start() 메소드가 호출되었습니다. 두번째 호출은 무시될 것입니다.
|
||||
lifecycleBase.alreadyStopped=stop()이 이미 호출된 후에, 구성요소 [{0}]에 대해 stop() 메소드가 호출되었습니다. 두번째 호출은 무시될 것입니다.
|
||||
lifecycleBase.destroyFail=구성요소 [{0}]을(를) 소멸시키지 못했습니다.
|
||||
lifecycleBase.destroyStopFail=실패한 구성요소 [{0}]에 대해, clean-up을 개시하기 위해 stop()을 호출했으나, 이 호출 또한 실패했습니다.
|
||||
lifecycleBase.initFail=구성요소 [{0}]을(를) 초기화하지 못했습니다.
|
||||
lifecycleBase.invalidTransition=상태 [{2}]에 있는 구성 요소 [{1}]에 대해, 유효하지 않은 Lifecycle 전환이 시도되었습니다 ([{0}]).
|
||||
lifecycleBase.setState=[{0}]을(를) 위한 상태를 [{1}](으)로 설정합니다.
|
||||
lifecycleBase.startFail=구성요소 [{0}]을(를) 시작하지 못했습니다.
|
||||
lifecycleBase.stopFail=구성요소 [{0}]을(를) 중지시키지 못했습니다.
|
||||
|
||||
lifecycleMBeanBase.registerFail=구성요소 초기화 중, [{1}](이)라는 이름을 가진 객체 [{0}]을(를) 등록하지 못했습니다.
|
||||
|
||||
netmask.cidrNegative=CIDR [{0}]이(가) 음수입니다.
|
||||
netmask.cidrNotNumeric=CIDR [{0}]이(가) 숫자가 아닙니다.
|
||||
netmask.cidrTooBig=CIDR [{0}]이(가) 주소 길이 [{1}]보다 큽니다.
|
||||
netmask.invalidAddress=주소 [{0}]은(는) 유효하지 않습니다.
|
||||
|
||||
parameterMap.locked=잠금 상태인 ParameterMap에 대한 변경이 허용되지 않습니다.
|
||||
|
||||
resourceSet.locked=잠금 상태인 ResourceSet에 대한 변경은 허용되지 않습니다.
|
||||
|
||||
sessionIdGeneratorBase.createRandom=[{0}] 알고리즘을 사용하여, 세션 ID를 생성하기 위한 SecureRandom 객체를 생성하는데, [{1}] 밀리초가 소요됐습니다.
|
||||
sessionIdGeneratorBase.random=클래스 [{0}]의 난수 발생기를 초기화하는 중 예외 발생. java.secure.SecureRandom으로 대체합니다.
|
||||
sessionIdGeneratorBase.randomAlgorithm=알고리즘 [{0}]을(를) 사용하여 난수 발생기를 초기화하는 중 오류 발생
|
||||
sessionIdGeneratorBase.randomProvider=Provider [{0}]을(를) 사용하여, 난수 발생기를 초기화하는 중 예외 발생
|
||||
16
java/org/apache/catalina/util/LocalStrings_ru.properties
Normal file
16
java/org/apache/catalina/util/LocalStrings_ru.properties
Normal file
@@ -0,0 +1,16 @@
|
||||
# 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.
|
||||
|
||||
introspection.classLoadFailed=Не возможно закрузить класс [{0}]
|
||||
37
java/org/apache/catalina/util/LocalStrings_zh_CN.properties
Normal file
37
java/org/apache/catalina/util/LocalStrings_zh_CN.properties
Normal file
@@ -0,0 +1,37 @@
|
||||
# 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.
|
||||
|
||||
SecurityUtil.doAsPrivilege=运行PrivilegedExceptionAction块时发生异常。
|
||||
|
||||
customObjectInputStream.logRequired=使用日志记录进行类名过滤需要一个有效的日志记录器
|
||||
customObjectInputStream.nomatch=类不能匹配合适的表达式,因为类被允许反序列化
|
||||
|
||||
extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: 请求的拓展[{2}]未找到。
|
||||
extensionValidator.web-application-manifest=web 应用程序清单
|
||||
|
||||
introspection.classLoadFailed=加载 class [{0}] 失败
|
||||
|
||||
lifecycleBase.alreadyStarted=在调用start()之后,在组件[{0}]上调用start()方法。第二个电话将被忽略。
|
||||
lifecycleBase.destroyStopFail=在失败组件[{0}]上调用Stop()以触发清理,但也失败了
|
||||
lifecycleBase.initFail=初始化组件[{0}]失败。
|
||||
lifecycleBase.setState=设置状态从[{0}]到[{1}]
|
||||
|
||||
lifecycleMBeanBase.registerFail=在组件初始化期间,无法注册名为{1}的对象{0}]
|
||||
|
||||
netmask.cidrNegative=CIDR [{0}]为负数。
|
||||
netmask.invalidAddress=地址 [{0}] 无效
|
||||
|
||||
sessionIdGeneratorBase.randomAlgorithm=使用算法[{0}]初始化随机数生成器时发生异常
|
||||
sessionIdGeneratorBase.randomProvider=使用程序提供的初始化随机数生成器异常[{0}]
|
||||
607
java/org/apache/catalina/util/MIME2Java.java
Normal file
607
java/org/apache/catalina/util/MIME2Java.java
Normal file
@@ -0,0 +1,607 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* MIME2Java is a convenience class which handles conversions between MIME charset names
|
||||
* and Java encoding names.
|
||||
* <p>The supported XML encodings are the intersection of XML-supported code sets and those
|
||||
* supported in JDK 1.1.
|
||||
* <p>MIME charset names are used on <var>xmlEncoding</var> parameters to methods such
|
||||
* as <code>TXDocument#setEncoding</code> and <code>DTD#setEncoding</code>.
|
||||
* <p>Java encoding names are used on <var>encoding</var> parameters to
|
||||
* methods such as <code>TXDocument#printWithFormat</code> and <code>DTD#printExternal</code>.
|
||||
* <TABLE>
|
||||
* <caption>MIME charset name to Java encoding name mapping</caption>
|
||||
* <TR>
|
||||
* <TD>
|
||||
* <P><B>Common Name</B>
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P><B>Use this name in XML files</B>
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P><B>Name Type</B>
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P><B>Xerces converts to this Java Encoder Name</B>
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>8 bit Unicode</TD>
|
||||
* <TD>
|
||||
* <P>UTF-8
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>UTF8
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin 1</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-1
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-1
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin 2</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-2
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-2
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin 3</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-3
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-3
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin 4</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-4
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-4
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin Cyrillic</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-5
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-5
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin Arabic</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-6
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-6
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin Greek</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-7
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-7
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin Hebrew</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-8
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-8
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>ISO Latin 5</TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-9
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>ISO-8859-9
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: US</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-us
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp037
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Canada</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-ca
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp037
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Netherlands</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-nl
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp037
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Denmark</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-dk
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp277
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Norway</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-no
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp277
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Finland</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-fi
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp278
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Sweden</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-se
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp278
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Italy</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-it
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp280
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Spain, Latin America</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-es
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp284
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Great Britain</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-gb
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp285
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: France</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-fr
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp297
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Arabic</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-ar1
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp420
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Hebrew</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-he
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp424
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Switzerland</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-ch
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp500
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Roece</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-roece
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp870
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Yogoslavia</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-yu
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp870
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Iceland</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-is
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp871
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>EBCDIC: Urdu</TD>
|
||||
* <TD>
|
||||
* <P>ebcdic-cp-ar2
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>IANA
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>cp918
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Chinese for PRC, mixed 1/2 byte</TD>
|
||||
* <TD>
|
||||
* <P>gb2312
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>GB2312
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Extended Unix Code, packed for Japanese</TD>
|
||||
* <TD>
|
||||
* <P>euc-jp
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>eucjis
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Japanese: iso-2022-jp</TD>
|
||||
* <TD>
|
||||
* <P>iso-2020-jp
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>JIS
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Japanese: Shift JIS</TD>
|
||||
* <TD>
|
||||
* <P>Shift_JIS
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>SJIS
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Chinese: Big5</TD>
|
||||
* <TD>
|
||||
* <P>Big5
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>Big5
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Extended Unix Code, packed for Korean</TD>
|
||||
* <TD>
|
||||
* <P>euc-kr
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>iso2022kr
|
||||
* </TD>
|
||||
* </TR>
|
||||
* <TR>
|
||||
* <TD>Cyrillic</TD>
|
||||
* <TD>
|
||||
* <P>koi8-r
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>MIME
|
||||
* </TD>
|
||||
* <TD>
|
||||
* <P>koi8-r
|
||||
* </TD>
|
||||
* </TR>
|
||||
* </TABLE>
|
||||
*
|
||||
* @author TAMURA Kent <kent@trl.ibm.co.jp>
|
||||
*
|
||||
* @deprecated Unused. Will be removed in Tomcat 9.
|
||||
*/
|
||||
@Deprecated
|
||||
public class MIME2Java {
|
||||
|
||||
private static final Map<String,String> s_enchash;
|
||||
private static final Map<String,String> s_revhash;
|
||||
|
||||
static {
|
||||
s_enchash = new HashMap<>();
|
||||
// <preferred MIME name>, <Java encoding name>
|
||||
s_enchash.put("UTF-8", "UTF8");
|
||||
s_enchash.put("US-ASCII", "8859_1"); // ?
|
||||
s_enchash.put("ISO-8859-1", "8859_1");
|
||||
s_enchash.put("ISO-8859-2", "8859_2");
|
||||
s_enchash.put("ISO-8859-3", "8859_3");
|
||||
s_enchash.put("ISO-8859-4", "8859_4");
|
||||
s_enchash.put("ISO-8859-5", "8859_5");
|
||||
s_enchash.put("ISO-8859-6", "8859_6");
|
||||
s_enchash.put("ISO-8859-7", "8859_7");
|
||||
s_enchash.put("ISO-8859-8", "8859_8");
|
||||
s_enchash.put("ISO-8859-9", "8859_9");
|
||||
s_enchash.put("ISO-2022-JP", "JIS");
|
||||
s_enchash.put("SHIFT_JIS", "SJIS");
|
||||
s_enchash.put("EUC-JP", "EUCJIS");
|
||||
s_enchash.put("GB2312", "GB2312");
|
||||
s_enchash.put("BIG5", "Big5");
|
||||
s_enchash.put("EUC-KR", "KSC5601");
|
||||
s_enchash.put("ISO-2022-KR", "ISO2022KR");
|
||||
s_enchash.put("KOI8-R", "KOI8_R");
|
||||
|
||||
s_enchash.put("EBCDIC-CP-US", "CP037");
|
||||
s_enchash.put("EBCDIC-CP-CA", "CP037");
|
||||
s_enchash.put("EBCDIC-CP-NL", "CP037");
|
||||
s_enchash.put("EBCDIC-CP-DK", "CP277");
|
||||
s_enchash.put("EBCDIC-CP-NO", "CP277");
|
||||
s_enchash.put("EBCDIC-CP-FI", "CP278");
|
||||
s_enchash.put("EBCDIC-CP-SE", "CP278");
|
||||
s_enchash.put("EBCDIC-CP-IT", "CP280");
|
||||
s_enchash.put("EBCDIC-CP-ES", "CP284");
|
||||
s_enchash.put("EBCDIC-CP-GB", "CP285");
|
||||
s_enchash.put("EBCDIC-CP-FR", "CP297");
|
||||
s_enchash.put("EBCDIC-CP-AR1", "CP420");
|
||||
s_enchash.put("EBCDIC-CP-HE", "CP424");
|
||||
s_enchash.put("EBCDIC-CP-CH", "CP500");
|
||||
s_enchash.put("EBCDIC-CP-ROECE", "CP870");
|
||||
s_enchash.put("EBCDIC-CP-YU", "CP870");
|
||||
s_enchash.put("EBCDIC-CP-IS", "CP871");
|
||||
s_enchash.put("EBCDIC-CP-AR2", "CP918");
|
||||
|
||||
// j:CNS11643 -> EUC-TW?
|
||||
// ISO-2022-CN? ISO-2022-CN-EXT?
|
||||
|
||||
s_revhash = new HashMap<>();
|
||||
// <Java encoding name>, <preferred MIME name>
|
||||
s_revhash.put("UTF8", "UTF-8");
|
||||
//s_revhash.put("8859_1", "US-ASCII"); // ?
|
||||
s_revhash.put("8859_1", "ISO-8859-1");
|
||||
s_revhash.put("8859_2", "ISO-8859-2");
|
||||
s_revhash.put("8859_3", "ISO-8859-3");
|
||||
s_revhash.put("8859_4", "ISO-8859-4");
|
||||
s_revhash.put("8859_5", "ISO-8859-5");
|
||||
s_revhash.put("8859_6", "ISO-8859-6");
|
||||
s_revhash.put("8859_7", "ISO-8859-7");
|
||||
s_revhash.put("8859_8", "ISO-8859-8");
|
||||
s_revhash.put("8859_9", "ISO-8859-9");
|
||||
s_revhash.put("JIS", "ISO-2022-JP");
|
||||
s_revhash.put("SJIS", "Shift_JIS");
|
||||
s_revhash.put("EUCJIS", "EUC-JP");
|
||||
s_revhash.put("GB2312", "GB2312");
|
||||
s_revhash.put("BIG5", "Big5");
|
||||
s_revhash.put("KSC5601", "EUC-KR");
|
||||
s_revhash.put("ISO2022KR", "ISO-2022-KR");
|
||||
s_revhash.put("KOI8_R", "KOI8-R");
|
||||
|
||||
s_revhash.put("CP037", "EBCDIC-CP-US");
|
||||
s_revhash.put("CP037", "EBCDIC-CP-CA");
|
||||
s_revhash.put("CP037", "EBCDIC-CP-NL");
|
||||
s_revhash.put("CP277", "EBCDIC-CP-DK");
|
||||
s_revhash.put("CP277", "EBCDIC-CP-NO");
|
||||
s_revhash.put("CP278", "EBCDIC-CP-FI");
|
||||
s_revhash.put("CP278", "EBCDIC-CP-SE");
|
||||
s_revhash.put("CP280", "EBCDIC-CP-IT");
|
||||
s_revhash.put("CP284", "EBCDIC-CP-ES");
|
||||
s_revhash.put("CP285", "EBCDIC-CP-GB");
|
||||
s_revhash.put("CP297", "EBCDIC-CP-FR");
|
||||
s_revhash.put("CP420", "EBCDIC-CP-AR1");
|
||||
s_revhash.put("CP424", "EBCDIC-CP-HE");
|
||||
s_revhash.put("CP500", "EBCDIC-CP-CH");
|
||||
s_revhash.put("CP870", "EBCDIC-CP-ROECE");
|
||||
s_revhash.put("CP870", "EBCDIC-CP-YU");
|
||||
s_revhash.put("CP871", "EBCDIC-CP-IS");
|
||||
s_revhash.put("CP918", "EBCDIC-CP-AR2");
|
||||
}
|
||||
|
||||
private MIME2Java() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a MIME charset name, also known as an XML encoding name, to a Java encoding name.
|
||||
* @param mimeCharsetName Case insensitive MIME charset name: <code>UTF-8, US-ASCII, ISO-8859-1,
|
||||
* ISO-8859-2, ISO-8859-3, ISO-8859-4, ISO-8859-5, ISO-8859-6,
|
||||
* ISO-8859-7, ISO-8859-8, ISO-8859-9, ISO-2022-JP, Shift_JIS,
|
||||
* EUC-JP, GB2312, Big5, EUC-KR, ISO-2022-KR, KOI8-R,
|
||||
* EBCDIC-CP-US, EBCDIC-CP-CA, EBCDIC-CP-NL, EBCDIC-CP-DK,
|
||||
* EBCDIC-CP-NO, EBCDIC-CP-FI, EBCDIC-CP-SE, EBCDIC-CP-IT,
|
||||
* EBCDIC-CP-ES, EBCDIC-CP-GB, EBCDIC-CP-FR, EBCDIC-CP-AR1,
|
||||
* EBCDIC-CP-HE, EBCDIC-CP-CH, EBCDIC-CP-ROECE, EBCDIC-CP-YU,
|
||||
* EBCDIC-CP-IS and EBCDIC-CP-AR2</code>.
|
||||
* @return Java encoding name, or <var>null</var> if <var>mimeCharsetName</var>
|
||||
* is unknown.
|
||||
* @see #reverse
|
||||
*/
|
||||
public static String convert(String mimeCharsetName) {
|
||||
return s_enchash.get(mimeCharsetName.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a Java encoding name to MIME charset name.
|
||||
* Available values of <i>encoding</i> are "UTF8", "8859_1", "8859_2", "8859_3", "8859_4",
|
||||
* "8859_5", "8859_6", "8859_7", "8859_8", "8859_9", "JIS", "SJIS", "EUCJIS",
|
||||
* "GB2312", "BIG5", "KSC5601", "ISO2022KR", "KOI8_R", "CP037", "CP277", "CP278",
|
||||
* "CP280", "CP284", "CP285", "CP297", "CP420", "CP424", "CP500", "CP870", "CP871" and "CP918".
|
||||
* @param encoding Case insensitive Java encoding name: <code>UTF8, 8859_1, 8859_2, 8859_3,
|
||||
* 8859_4, 8859_5, 8859_6, 8859_7, 8859_8, 8859_9, JIS, SJIS, EUCJIS,
|
||||
* GB2312, BIG5, KSC5601, ISO2022KR, KOI8_R, CP037, CP277, CP278,
|
||||
* CP280, CP284, CP285, CP297, CP420, CP424, CP500, CP870, CP871
|
||||
* and CP918</code>.
|
||||
* @return MIME charset name, or <var>null</var> if <var>encoding</var> is unknown.
|
||||
* @see #convert
|
||||
*/
|
||||
public static String reverse(String encoding) {
|
||||
return s_revhash.get(encoding.toUpperCase(Locale.ENGLISH));
|
||||
}
|
||||
}
|
||||
227
java/org/apache/catalina/util/ManifestResource.java
Normal file
227
java/org/apache/catalina/util/ManifestResource.java
Normal file
@@ -0,0 +1,227 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.jar.Attributes;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
/**
|
||||
* Representation of a Manifest file and its available extensions and
|
||||
* required extensions
|
||||
*
|
||||
* @author Greg Murray
|
||||
* @author Justyna Horwat
|
||||
*/
|
||||
public class ManifestResource {
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
// These are the resource types for determining effect error messages
|
||||
public static final int SYSTEM = 1;
|
||||
public static final int WAR = 2;
|
||||
public static final int APPLICATION = 3;
|
||||
|
||||
private ArrayList<Extension> availableExtensions = null;
|
||||
private ArrayList<Extension> requiredExtensions = null;
|
||||
|
||||
private final String resourceName;
|
||||
private final int resourceType;
|
||||
|
||||
public ManifestResource(String resourceName, Manifest manifest,
|
||||
int resourceType) {
|
||||
this.resourceName = resourceName;
|
||||
this.resourceType = resourceType;
|
||||
processManifest(manifest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name of the resource
|
||||
*
|
||||
* @return The name of the resource
|
||||
*/
|
||||
public String getResourceName() {
|
||||
return resourceName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of available extensions
|
||||
*
|
||||
* @return List of available extensions
|
||||
*/
|
||||
public ArrayList<Extension> getAvailableExtensions() {
|
||||
return availableExtensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of required extensions
|
||||
*
|
||||
* @return List of required extensions
|
||||
*/
|
||||
public ArrayList<Extension> getRequiredExtensions() {
|
||||
return requiredExtensions;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
/**
|
||||
* Gets the number of available extensions
|
||||
*
|
||||
* @return The number of available extensions
|
||||
*/
|
||||
public int getAvailableExtensionCount() {
|
||||
return (availableExtensions != null) ? availableExtensions.size() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of required extensions
|
||||
*
|
||||
* @return The number of required extensions
|
||||
*/
|
||||
public int getRequiredExtensionCount() {
|
||||
return (requiredExtensions != null) ? requiredExtensions.size() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if all required extension dependencies
|
||||
* have been meet for this <code>ManifestResource</code> object.
|
||||
*
|
||||
* @return boolean true if all extension dependencies have been satisfied
|
||||
*/
|
||||
public boolean isFulfilled() {
|
||||
if (requiredExtensions == null) {
|
||||
return true;
|
||||
}
|
||||
for (Extension ext : requiredExtensions) {
|
||||
if (!ext.isFulfilled()) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("ManifestResource[");
|
||||
sb.append(resourceName);
|
||||
|
||||
sb.append(", isFulfilled=");
|
||||
sb.append(isFulfilled() +"");
|
||||
sb.append(", requiredExtensionCount =");
|
||||
sb.append(getRequiredExtensionCount());
|
||||
sb.append(", availableExtensionCount=");
|
||||
sb.append(getAvailableExtensionCount());
|
||||
switch (resourceType) {
|
||||
case SYSTEM : sb.append(", resourceType=SYSTEM"); break;
|
||||
case WAR : sb.append(", resourceType=WAR"); break;
|
||||
case APPLICATION : sb.append(", resourceType=APPLICATION"); break;
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------- Private Methods
|
||||
|
||||
private void processManifest(Manifest manifest) {
|
||||
availableExtensions = getAvailableExtensions(manifest);
|
||||
requiredExtensions = getRequiredExtensions(manifest);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of <code>Extension</code> objects representing optional
|
||||
* packages that are required by the application associated with the
|
||||
* specified <code>Manifest</code>.
|
||||
*
|
||||
* @param manifest Manifest to be parsed
|
||||
*
|
||||
* @return List of required extensions, or null if the application
|
||||
* does not require any extensions
|
||||
*/
|
||||
private ArrayList<Extension> getRequiredExtensions(Manifest manifest) {
|
||||
|
||||
Attributes attributes = manifest.getMainAttributes();
|
||||
String names = attributes.getValue("Extension-List");
|
||||
if (names == null)
|
||||
return null;
|
||||
|
||||
ArrayList<Extension> extensionList = new ArrayList<>();
|
||||
names += " ";
|
||||
|
||||
while (true) {
|
||||
|
||||
int space = names.indexOf(' ');
|
||||
if (space < 0)
|
||||
break;
|
||||
String name = names.substring(0, space).trim();
|
||||
names = names.substring(space + 1);
|
||||
|
||||
String value =
|
||||
attributes.getValue(name + "-Extension-Name");
|
||||
if (value == null)
|
||||
continue;
|
||||
Extension extension = new Extension();
|
||||
extension.setExtensionName(value);
|
||||
extension.setImplementationURL
|
||||
(attributes.getValue(name + "-Implementation-URL"));
|
||||
extension.setImplementationVendorId
|
||||
(attributes.getValue(name + "-Implementation-Vendor-Id"));
|
||||
String version = attributes.getValue(name + "-Implementation-Version");
|
||||
extension.setImplementationVersion(version);
|
||||
extension.setSpecificationVersion
|
||||
(attributes.getValue(name + "-Specification-Version"));
|
||||
extensionList.add(extension);
|
||||
}
|
||||
return extensionList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the set of <code>Extension</code> objects representing optional
|
||||
* packages that are bundled with the application associated with the
|
||||
* specified <code>Manifest</code>.
|
||||
*
|
||||
* @param manifest Manifest to be parsed
|
||||
*
|
||||
* @return List of available extensions, or null if the web application
|
||||
* does not bundle any extensions
|
||||
*/
|
||||
private ArrayList<Extension> getAvailableExtensions(Manifest manifest) {
|
||||
|
||||
Attributes attributes = manifest.getMainAttributes();
|
||||
String name = attributes.getValue("Extension-Name");
|
||||
if (name == null)
|
||||
return null;
|
||||
|
||||
ArrayList<Extension> extensionList = new ArrayList<>();
|
||||
|
||||
Extension extension = new Extension();
|
||||
extension.setExtensionName(name);
|
||||
extension.setImplementationURL(
|
||||
attributes.getValue("Implementation-URL"));
|
||||
extension.setImplementationVendor(
|
||||
attributes.getValue("Implementation-Vendor"));
|
||||
extension.setImplementationVendorId(
|
||||
attributes.getValue("Implementation-Vendor-Id"));
|
||||
extension.setImplementationVersion(
|
||||
attributes.getValue("Implementation-Version"));
|
||||
extension.setSpecificationVersion(
|
||||
attributes.getValue("Specification-Version"));
|
||||
|
||||
extensionList.add(extension);
|
||||
|
||||
return extensionList;
|
||||
}
|
||||
|
||||
}
|
||||
241
java/org/apache/catalina/util/NetMask.java
Normal file
241
java/org/apache/catalina/util/NetMask.java
Normal file
@@ -0,0 +1,241 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* A class representing a CIDR netmask.
|
||||
*
|
||||
* <p>
|
||||
* The constructor takes a string as an argument which represents a netmask, as
|
||||
* per the CIDR notation -- whether this netmask be IPv4 or IPv6. It then
|
||||
* extracts the network address (before the /) and the CIDR prefix (after the
|
||||
* /), and tells through the #matches() method whether a candidate
|
||||
* {@link InetAddress} object fits in the recorded range.
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* As byte arrays as returned by <code>InetAddress.getByName()</code> are always
|
||||
* in network byte order, finding a match is therefore as simple as testing
|
||||
* whether the n first bits (where n is the CIDR) are the same in both byte
|
||||
* arrays (the one of the network address and the one of the candidate address).
|
||||
* We do that by first doing byte comparisons, then testing the last bits if any
|
||||
* (that is, if the remainder of the integer division of the CIDR by 8 is not
|
||||
* 0).
|
||||
* </p>
|
||||
*
|
||||
* <p>
|
||||
* As a bonus, if no '/' is found in the input, it is assumed that an exact
|
||||
* address match is required.
|
||||
* </p>
|
||||
*/
|
||||
public final class NetMask {
|
||||
|
||||
private static final StringManager sm = StringManager.getManager(NetMask.class);
|
||||
|
||||
/**
|
||||
* The argument to the constructor, used for .toString()
|
||||
*/
|
||||
private final String expression;
|
||||
|
||||
/**
|
||||
* The byte array representing the address extracted from the expression
|
||||
*/
|
||||
private final byte[] netaddr;
|
||||
|
||||
/**
|
||||
* The number of bytes to test for equality (CIDR / 8)
|
||||
*/
|
||||
private final int nrBytes;
|
||||
|
||||
/**
|
||||
* The right shift to apply to the last byte if CIDR % 8 is not 0; if it is
|
||||
* 0, this variable is set to 0
|
||||
*/
|
||||
private final int lastByteShift;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param input the CIDR netmask
|
||||
* @throws IllegalArgumentException if the netmask is not correct (invalid
|
||||
* address specification, malformed CIDR prefix, etc)
|
||||
*/
|
||||
public NetMask(final String input) {
|
||||
|
||||
expression = input;
|
||||
|
||||
final int idx = input.indexOf("/");
|
||||
|
||||
/*
|
||||
* Handle the "IP only" case first
|
||||
*/
|
||||
if (idx == -1) {
|
||||
try {
|
||||
netaddr = InetAddress.getByName(input).getAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
throw new IllegalArgumentException(sm.getString("netmask.invalidAddress", input));
|
||||
}
|
||||
nrBytes = netaddr.length;
|
||||
lastByteShift = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we do have a netmask specified, so let's extract both the address
|
||||
* and the CIDR.
|
||||
*/
|
||||
|
||||
final String addressPart = input.substring(0, idx), cidrPart = input.substring(idx + 1);
|
||||
|
||||
try {
|
||||
/*
|
||||
* The address first...
|
||||
*/
|
||||
netaddr = InetAddress.getByName(addressPart).getAddress();
|
||||
} catch (UnknownHostException e) {
|
||||
throw new IllegalArgumentException(sm.getString("netmask.invalidAddress", addressPart));
|
||||
}
|
||||
|
||||
final int addrlen = netaddr.length * 8;
|
||||
final int cidr;
|
||||
|
||||
try {
|
||||
/*
|
||||
* And then the CIDR.
|
||||
*/
|
||||
cidr = Integer.parseInt(cidrPart);
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException(sm.getString("netmask.cidrNotNumeric", cidrPart));
|
||||
}
|
||||
|
||||
/*
|
||||
* We don't want a negative CIDR, nor do we want a CIDR which is greater
|
||||
* than the address length (consider 0.0.0.0/33, or ::/129)
|
||||
*/
|
||||
if (cidr < 0) {
|
||||
throw new IllegalArgumentException(sm.getString("netmask.cidrNegative", cidrPart));
|
||||
}
|
||||
if (cidr > addrlen) {
|
||||
throw new IllegalArgumentException(
|
||||
sm.getString("netmask.cidrTooBig", cidrPart, Integer.valueOf(addrlen)));
|
||||
}
|
||||
|
||||
nrBytes = cidr / 8;
|
||||
|
||||
/*
|
||||
* These last two lines could be shortened to:
|
||||
*
|
||||
* lastByteShift = (8 - (cidr % 8)) & 7;
|
||||
*
|
||||
* But... It's not worth it. In fact, explaining why it could work would
|
||||
* be too long to be worth the trouble, so let's do it the simple way...
|
||||
*/
|
||||
|
||||
final int remainder = cidr % 8;
|
||||
|
||||
lastByteShift = (remainder == 0) ? 0 : 8 - remainder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test if a given address matches this netmask.
|
||||
*
|
||||
* @param addr The {@link java.net.InetAddress} to test
|
||||
* @return true on match, false otherwise
|
||||
*/
|
||||
public boolean matches(final InetAddress addr) {
|
||||
final byte[] candidate = addr.getAddress();
|
||||
|
||||
/*
|
||||
* OK, remember that a CIDR prefix tells the number of BITS which should
|
||||
* be equal between this NetMask's recorded address (netaddr) and the
|
||||
* candidate address. One byte is 8 bits, no matter what, and IP
|
||||
* addresses, whether they be IPv4 or IPv6, are big endian, aka MSB,
|
||||
* Most Significant Byte (first).
|
||||
*
|
||||
* We therefore need to get the byte array of the candidate address,
|
||||
* compare as many bytes of the candidate address with the recorded
|
||||
* address as the CIDR prefix tells us to (that is, CIDR / 8), and then
|
||||
* deal with the remaining bits -- if any.
|
||||
*
|
||||
* But prior to that, a simple test can be done: we deal with IP
|
||||
* addresses here, which means IPv4 and IPv6. IPv4 addresses are encoded
|
||||
* on 4 bytes, IPv6 addresses are encoded on 16 bytes. If the candidate
|
||||
* address length is different than this NetMask's address, we don't
|
||||
* have a match.
|
||||
*/
|
||||
if (candidate.length != netaddr.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Now do the byte-compare. The constructor has recorded the number of
|
||||
* bytes to compare in nrBytes, use that. If any of the byte we have to
|
||||
* compare is different than what we expect, we don't have a match.
|
||||
*
|
||||
* If, on the opposite, after this loop, all bytes have been deemed
|
||||
* equal, then the loop variable i will point to the byte right after
|
||||
* that -- which we will need...
|
||||
*/
|
||||
int i = 0;
|
||||
for (; i < nrBytes; i++) {
|
||||
if (netaddr[i] != candidate[i]) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ... if there are bits left to test. There aren't any if lastByteShift
|
||||
* is set to 0.
|
||||
*/
|
||||
if (lastByteShift == 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* If it is not 0, however, we must test for the relevant bits in the
|
||||
* next byte (whatever is in the bytes after that doesn't matter). We do
|
||||
* it this way (remember that lastByteShift contains the amount of bits
|
||||
* we should _right_ shift the last byte):
|
||||
*
|
||||
* - grab both bytes at index i, both from the netmask address and the
|
||||
* candidate address; - xor them both.
|
||||
*
|
||||
* After the xor, it means that all the remaining bits of the CIDR
|
||||
* should be set to 0...
|
||||
*/
|
||||
final int lastByte = netaddr[i] ^ candidate[i];
|
||||
|
||||
/*
|
||||
* ... Which means that right shifting by lastByteShift should be 0.
|
||||
*/
|
||||
return lastByte >> lastByteShift == 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return expression;
|
||||
}
|
||||
}
|
||||
256
java/org/apache/catalina/util/ParameterMap.java
Normal file
256
java/org/apache/catalina/util/ParameterMap.java
Normal file
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
/**
|
||||
* Implementation of <strong>java.util.Map</strong> that includes a
|
||||
* <code>locked</code> property. This class can be used to safely expose
|
||||
* Catalina internal parameter map objects to user classes without having
|
||||
* to clone them in order to avoid modifications. When first created, a
|
||||
* <code>ParmaeterMap</code> instance is not locked.
|
||||
*
|
||||
* @param <K> The type of Key
|
||||
* @param <V> The type of Value
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public final class ParameterMap<K,V> implements Map<K,V>, Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
private final Map<K,V> delegatedMap;
|
||||
|
||||
private final Map<K,V> unmodifiableDelegatedMap;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new, empty map with the default initial capacity and
|
||||
* load factor.
|
||||
*/
|
||||
public ParameterMap() {
|
||||
delegatedMap = new LinkedHashMap<>();
|
||||
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new, empty map with the specified initial capacity and
|
||||
* default load factor.
|
||||
*
|
||||
* @param initialCapacity The initial capacity of this map
|
||||
*/
|
||||
public ParameterMap(int initialCapacity) {
|
||||
delegatedMap = new LinkedHashMap<>(initialCapacity);
|
||||
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new, empty map with the specified initial capacity and
|
||||
* load factor.
|
||||
*
|
||||
* @param initialCapacity The initial capacity of this map
|
||||
* @param loadFactor The load factor of this map
|
||||
*/
|
||||
public ParameterMap(int initialCapacity, float loadFactor) {
|
||||
delegatedMap = new LinkedHashMap<>(initialCapacity, loadFactor);
|
||||
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new map with the same mappings as the given map.
|
||||
*
|
||||
* @param map Map whose contents are duplicated in the new map
|
||||
*/
|
||||
public ParameterMap(Map<K,V> map) {
|
||||
delegatedMap = new LinkedHashMap<>(map);
|
||||
unmodifiableDelegatedMap = Collections.unmodifiableMap(delegatedMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The current lock state of this parameter map.
|
||||
*/
|
||||
private boolean locked = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return the locked state of this parameter map.
|
||||
*/
|
||||
public boolean isLocked() {
|
||||
return locked;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the locked state of this parameter map.
|
||||
*
|
||||
* @param locked The new locked state
|
||||
*/
|
||||
public void setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
private static final StringManager sm = StringManager.getManager("org.apache.catalina.util");
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @exception IllegalStateException if this map is currently locked
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
checkLocked();
|
||||
delegatedMap.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @exception IllegalStateException if this map is currently locked
|
||||
*/
|
||||
@Override
|
||||
public V put(K key, V value) {
|
||||
checkLocked();
|
||||
return delegatedMap.put(key, value);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @exception IllegalStateException if this map is currently locked
|
||||
*/
|
||||
@Override
|
||||
public void putAll(Map<? extends K,? extends V> map) {
|
||||
checkLocked();
|
||||
delegatedMap.putAll(map);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @exception IllegalStateException if this map is currently locked
|
||||
*/
|
||||
@Override
|
||||
public V remove(Object key) {
|
||||
checkLocked();
|
||||
return delegatedMap.remove(key);
|
||||
}
|
||||
|
||||
|
||||
private void checkLocked() {
|
||||
if (locked) {
|
||||
throw new IllegalStateException(sm.getString("parameterMap.locked"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return delegatedMap.size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isEmpty() {
|
||||
return delegatedMap.isEmpty();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean containsKey(Object key) {
|
||||
return delegatedMap.containsKey(key);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean containsValue(Object value) {
|
||||
return delegatedMap.containsValue(value);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public V get(Object key) {
|
||||
return delegatedMap.get(key);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Returns an <strong>unmodifiable</strong> {@link Set} view of the keys
|
||||
* contained in this map if it is locked.
|
||||
*/
|
||||
@Override
|
||||
public Set<K> keySet() {
|
||||
if (locked) {
|
||||
return unmodifiableDelegatedMap.keySet();
|
||||
}
|
||||
|
||||
return delegatedMap.keySet();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Returns an <strong>unmodifiable</strong> {@link Collection} view of the
|
||||
* values contained in this map if it is locked.
|
||||
*/
|
||||
@Override
|
||||
public Collection<V> values() {
|
||||
if (locked) {
|
||||
return unmodifiableDelegatedMap.values();
|
||||
}
|
||||
|
||||
return delegatedMap.values();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
* <p>
|
||||
* Returns an <strong>unmodifiable</strong> {@link Set} view of the mappings
|
||||
* contained in this map if it is locked.
|
||||
*/
|
||||
@Override
|
||||
public Set<java.util.Map.Entry<K, V>> entrySet() {
|
||||
if (locked) {
|
||||
return unmodifiableDelegatedMap.entrySet();
|
||||
}
|
||||
|
||||
return delegatedMap.entrySet();
|
||||
}
|
||||
}
|
||||
68
java/org/apache/catalina/util/RequestUtil.java
Normal file
68
java/org/apache/catalina/util/RequestUtil.java
Normal file
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
/**
|
||||
* General purpose request parsing and encoding utility methods.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Tim Tye
|
||||
*/
|
||||
public final class RequestUtil {
|
||||
|
||||
/**
|
||||
* Filter the specified message string for characters that are sensitive
|
||||
* in HTML. This avoids potential attacks caused by including JavaScript
|
||||
* codes in the request URL that is often reported in error messages.
|
||||
*
|
||||
* @param message The message string to be filtered
|
||||
*
|
||||
* @return the filtered message
|
||||
*
|
||||
* @deprecated This method will be removed in Tomcat 9
|
||||
*/
|
||||
@Deprecated
|
||||
public static String filter(String message) {
|
||||
|
||||
if (message == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
char content[] = new char[message.length()];
|
||||
message.getChars(0, message.length(), content, 0);
|
||||
StringBuilder result = new StringBuilder(content.length + 50);
|
||||
for (int i = 0; i < content.length; i++) {
|
||||
switch (content[i]) {
|
||||
case '<':
|
||||
result.append("<");
|
||||
break;
|
||||
case '>':
|
||||
result.append(">");
|
||||
break;
|
||||
case '&':
|
||||
result.append("&");
|
||||
break;
|
||||
case '"':
|
||||
result.append(""");
|
||||
break;
|
||||
default:
|
||||
result.append(content[i]);
|
||||
}
|
||||
}
|
||||
return result.toString();
|
||||
}
|
||||
}
|
||||
181
java/org/apache/catalina/util/ResourceSet.java
Normal file
181
java/org/apache/catalina/util/ResourceSet.java
Normal file
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
|
||||
/**
|
||||
* Extended implementation of <strong>HashSet</strong> that includes a
|
||||
* <code>locked</code> property. This class can be used to safely expose
|
||||
* resource path sets to user classes without having to clone them in order
|
||||
* to avoid modifications. When first created, a <code>ResourceMap</code>
|
||||
* is not locked.
|
||||
*
|
||||
* @param <T> The type of elements in the Set
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public final class ResourceSet<T> extends HashSet<T> {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// ----------------------------------------------------------- Constructors
|
||||
/**
|
||||
* Construct a new, empty set with the default initial capacity and
|
||||
* load factor.
|
||||
*/
|
||||
public ResourceSet() {
|
||||
|
||||
super();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new, empty set with the specified initial capacity and
|
||||
* default load factor.
|
||||
*
|
||||
* @param initialCapacity The initial capacity of this set
|
||||
*/
|
||||
public ResourceSet(int initialCapacity) {
|
||||
|
||||
super(initialCapacity);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new, empty set with the specified initial capacity and
|
||||
* load factor.
|
||||
*
|
||||
* @param initialCapacity The initial capacity of this set
|
||||
* @param loadFactor The load factor of this set
|
||||
*/
|
||||
public ResourceSet(int initialCapacity, float loadFactor) {
|
||||
|
||||
super(initialCapacity, loadFactor);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new set with the same contents as the existing collection.
|
||||
*
|
||||
* @param coll The collection whose contents we should copy
|
||||
*/
|
||||
public ResourceSet(Collection<T> coll) {
|
||||
|
||||
super(coll);
|
||||
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------------- Properties
|
||||
|
||||
|
||||
/**
|
||||
* The current lock state of this parameter map.
|
||||
*/
|
||||
private boolean locked = false;
|
||||
|
||||
|
||||
/**
|
||||
* @return the locked state of this parameter map.
|
||||
*/
|
||||
public boolean isLocked() {
|
||||
return this.locked;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the locked state of this parameter map.
|
||||
*
|
||||
* @param locked The new locked state
|
||||
*/
|
||||
public void setLocked(boolean locked) {
|
||||
this.locked = locked;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The string manager for this package.
|
||||
*/
|
||||
private static final StringManager sm =
|
||||
StringManager.getManager("org.apache.catalina.util");
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Add the specified element to this set if it is not already present.
|
||||
* Return <code>true</code> if the element was added.
|
||||
*
|
||||
* @param o The object to be added
|
||||
*
|
||||
* @exception IllegalStateException if this ResourceSet is locked
|
||||
*/
|
||||
@Override
|
||||
public boolean add(T o) {
|
||||
if (locked)
|
||||
throw new IllegalStateException
|
||||
(sm.getString("resourceSet.locked"));
|
||||
return super.add(o);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove all of the elements from this set.
|
||||
*
|
||||
* @exception IllegalStateException if this ResourceSet is locked
|
||||
*/
|
||||
@Override
|
||||
public void clear() {
|
||||
|
||||
if (locked)
|
||||
throw new IllegalStateException
|
||||
(sm.getString("resourceSet.locked"));
|
||||
super.clear();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Remove the given element from this set if it is present.
|
||||
* Return <code>true</code> if the element was removed.
|
||||
*
|
||||
* @param o The object to be removed
|
||||
*
|
||||
* @exception IllegalStateException if this ResourceSet is locked
|
||||
*/
|
||||
@Override
|
||||
public boolean remove(Object o) {
|
||||
if (locked)
|
||||
throw new IllegalStateException
|
||||
(sm.getString("resourceSet.locked"));
|
||||
return super.remove(o);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
124
java/org/apache/catalina/util/ServerInfo.java
Normal file
124
java/org/apache/catalina/util/ServerInfo.java
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.apache.tomcat.util.ExceptionUtils;
|
||||
|
||||
|
||||
/**
|
||||
* Simple utility module to make it easy to plug in the server identifier
|
||||
* when integrating Tomcat.
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
*/
|
||||
public class ServerInfo {
|
||||
|
||||
|
||||
// ------------------------------------------------------- Static Variables
|
||||
|
||||
|
||||
/**
|
||||
* The server information String with which we identify ourselves.
|
||||
*/
|
||||
private static final String serverInfo;
|
||||
|
||||
/**
|
||||
* The server built String.
|
||||
*/
|
||||
private static final String serverBuilt;
|
||||
|
||||
/**
|
||||
* The server's version number String.
|
||||
*/
|
||||
private static final String serverNumber;
|
||||
|
||||
static {
|
||||
|
||||
String info = null;
|
||||
String built = null;
|
||||
String number = null;
|
||||
|
||||
Properties props = new Properties();
|
||||
try (InputStream is = ServerInfo.class.getResourceAsStream
|
||||
("/org/apache/catalina/util/ServerInfo.properties")) {
|
||||
props.load(is);
|
||||
info = props.getProperty("server.info");
|
||||
built = props.getProperty("server.built");
|
||||
number = props.getProperty("server.number");
|
||||
} catch (Throwable t) {
|
||||
ExceptionUtils.handleThrowable(t);
|
||||
}
|
||||
if (info == null)
|
||||
info = "Apache Tomcat 8.5.x-dev";
|
||||
if (built == null)
|
||||
built = "unknown";
|
||||
if (number == null)
|
||||
number = "8.5.x";
|
||||
|
||||
serverInfo = info;
|
||||
serverBuilt = built;
|
||||
serverNumber = number;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* @return the server identification for this version of Tomcat.
|
||||
*/
|
||||
public static String getServerInfo() {
|
||||
return serverInfo;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the server built time for this version of Tomcat.
|
||||
*/
|
||||
public static String getServerBuilt() {
|
||||
return serverBuilt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the server's version number.
|
||||
*/
|
||||
public static String getServerNumber() {
|
||||
return serverNumber;
|
||||
}
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("Server version: " + getServerInfo());
|
||||
System.out.println("Server built: " + getServerBuilt());
|
||||
System.out.println("Server number: " + getServerNumber());
|
||||
System.out.println("OS Name: " +
|
||||
System.getProperty("os.name"));
|
||||
System.out.println("OS Version: " +
|
||||
System.getProperty("os.version"));
|
||||
System.out.println("Architecture: " +
|
||||
System.getProperty("os.arch"));
|
||||
System.out.println("JVM Version: " +
|
||||
System.getProperty("java.runtime.version"));
|
||||
System.out.println("JVM Vendor: " +
|
||||
System.getProperty("java.vm.vendor"));
|
||||
}
|
||||
|
||||
}
|
||||
18
java/org/apache/catalina/util/ServerInfo.properties
Normal file
18
java/org/apache/catalina/util/ServerInfo.properties
Normal file
@@ -0,0 +1,18 @@
|
||||
# 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.
|
||||
|
||||
server.info=Apache Tomcat/@VERSION@
|
||||
server.number=@VERSION_NUMBER@
|
||||
server.built=@VERSION_BUILT@
|
||||
128
java/org/apache/catalina/util/SessionConfig.java
Normal file
128
java/org/apache/catalina/util/SessionConfig.java
Normal file
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import javax.servlet.SessionCookieConfig;
|
||||
|
||||
import org.apache.catalina.Context;
|
||||
|
||||
public class SessionConfig {
|
||||
|
||||
private static final String DEFAULT_SESSION_COOKIE_NAME = "JSESSIONID";
|
||||
private static final String DEFAULT_SESSION_PARAMETER_NAME = "jsessionid";
|
||||
|
||||
/**
|
||||
* Determine the name to use for the session cookie for the provided
|
||||
* context.
|
||||
* @param context The context
|
||||
* @return the cookie name for the context
|
||||
*/
|
||||
public static String getSessionCookieName(Context context) {
|
||||
|
||||
String result = getConfiguredSessionCookieName(context);
|
||||
|
||||
if (result == null) {
|
||||
result = DEFAULT_SESSION_COOKIE_NAME;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the name to use for the session path parameter for the provided
|
||||
* context.
|
||||
* @param context The context
|
||||
* @return the parameter name for the session
|
||||
*/
|
||||
public static String getSessionUriParamName(Context context) {
|
||||
|
||||
String result = getConfiguredSessionCookieName(context);
|
||||
|
||||
if (result == null) {
|
||||
result = DEFAULT_SESSION_PARAMETER_NAME;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
private static String getConfiguredSessionCookieName(Context context) {
|
||||
|
||||
// Priority is:
|
||||
// 1. Cookie name defined in context
|
||||
// 2. Cookie name configured for app
|
||||
// 3. Default defined by spec
|
||||
if (context != null) {
|
||||
String cookieName = context.getSessionCookieName();
|
||||
if (cookieName != null && cookieName.length() > 0) {
|
||||
return cookieName;
|
||||
}
|
||||
|
||||
SessionCookieConfig scc =
|
||||
context.getServletContext().getSessionCookieConfig();
|
||||
cookieName = scc.getName();
|
||||
if (cookieName != null && cookieName.length() > 0) {
|
||||
return cookieName;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine the value to use for the session cookie path for the provided
|
||||
* context.
|
||||
*
|
||||
* @param context The context
|
||||
* @return the parameter name for the session
|
||||
*/
|
||||
public static String getSessionCookiePath(Context context) {
|
||||
|
||||
SessionCookieConfig scc = context.getServletContext().getSessionCookieConfig();
|
||||
|
||||
String contextPath = context.getSessionCookiePath();
|
||||
if (contextPath == null || contextPath.length() == 0) {
|
||||
contextPath = scc.getPath();
|
||||
}
|
||||
if (contextPath == null || contextPath.length() == 0) {
|
||||
contextPath = context.getEncodedPath();
|
||||
}
|
||||
if (context.getSessionCookiePathUsesTrailingSlash()) {
|
||||
// Handle special case of ROOT context where cookies require a path of
|
||||
// '/' but the servlet spec uses an empty string
|
||||
// Also ensure the cookies for a context with a path of /foo don't get
|
||||
// sent for requests with a path of /foobar
|
||||
if (!contextPath.endsWith("/")) {
|
||||
contextPath = contextPath + "/";
|
||||
}
|
||||
} else {
|
||||
// Only handle special case of ROOT context where cookies require a
|
||||
// path of '/' but the servlet spec uses an empty string
|
||||
if (contextPath.length() == 0) {
|
||||
contextPath = "/";
|
||||
}
|
||||
}
|
||||
|
||||
return contextPath;
|
||||
}
|
||||
|
||||
|
||||
private SessionConfig() {
|
||||
// Utility class. Hide default constructor.
|
||||
}
|
||||
}
|
||||
306
java/org/apache/catalina/util/SessionIdGeneratorBase.java
Normal file
306
java/org/apache/catalina/util/SessionIdGeneratorBase.java
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.NoSuchProviderException;
|
||||
import java.security.SecureRandom;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.LifecycleState;
|
||||
import org.apache.catalina.SessionIdGenerator;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
import org.apache.tomcat.util.res.StringManager;
|
||||
|
||||
public abstract class SessionIdGeneratorBase extends LifecycleBase
|
||||
implements SessionIdGenerator {
|
||||
|
||||
private final Log log = LogFactory.getLog(SessionIdGeneratorBase.class); // must not be static
|
||||
|
||||
|
||||
private static final StringManager sm =
|
||||
StringManager.getManager("org.apache.catalina.util");
|
||||
|
||||
|
||||
/**
|
||||
* Queue of random number generator objects to be used when creating session
|
||||
* identifiers. If the queue is empty when a random number generator is
|
||||
* required, a new random number generator object is created. This is
|
||||
* designed this way since random number generators use a sync to make them
|
||||
* thread-safe and the sync makes using a single object slow(er).
|
||||
*/
|
||||
private final Queue<SecureRandom> randoms = new ConcurrentLinkedQueue<>();
|
||||
|
||||
private String secureRandomClass = null;
|
||||
|
||||
private String secureRandomAlgorithm = "SHA1PRNG";
|
||||
|
||||
private String secureRandomProvider = null;
|
||||
|
||||
|
||||
/** Node identifier when in a cluster. Defaults to the empty string. */
|
||||
private String jvmRoute = "";
|
||||
|
||||
|
||||
/** Number of bytes in a session ID. Defaults to 16. */
|
||||
private int sessionIdLength = 16;
|
||||
|
||||
|
||||
/**
|
||||
* Get the class name of the {@link SecureRandom} implementation used to
|
||||
* generate session IDs.
|
||||
*
|
||||
* @return The fully qualified class name. {@code null} indicates that the
|
||||
* JRE provided {@link SecureRandom} implementation will be used
|
||||
*/
|
||||
public String getSecureRandomClass() {
|
||||
return secureRandomClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify a non-default {@link SecureRandom} implementation to use. The
|
||||
* implementation must be self-seeding and have a zero-argument constructor.
|
||||
* If not specified, an instance of {@link SecureRandom} will be generated.
|
||||
*
|
||||
* @param secureRandomClass The fully-qualified class name
|
||||
*/
|
||||
public void setSecureRandomClass(String secureRandomClass) {
|
||||
this.secureRandomClass = secureRandomClass;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the algorithm used to create the {@link SecureRandom}
|
||||
* instances which generate new session IDs.
|
||||
*
|
||||
* @return The name of the algorithm. {@code null} or the empty string means
|
||||
* that platform default will be used
|
||||
*/
|
||||
public String getSecureRandomAlgorithm() {
|
||||
return secureRandomAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify a non-default algorithm to use to create instances of
|
||||
* {@link SecureRandom} which are used to generate session IDs. If no
|
||||
* algorithm is specified, SHA1PRNG is used. To use the platform default
|
||||
* (which may be SHA1PRNG), specify {@code null} or the empty string. If an
|
||||
* invalid algorithm and/or provider is specified the {@link SecureRandom}
|
||||
* instances will be created using the defaults for this
|
||||
* {@link SessionIdGenerator} implementation. If that fails, the
|
||||
* {@link SecureRandom} instances will be created using platform defaults.
|
||||
*
|
||||
* @param secureRandomAlgorithm The name of the algorithm
|
||||
*/
|
||||
public void setSecureRandomAlgorithm(String secureRandomAlgorithm) {
|
||||
this.secureRandomAlgorithm = secureRandomAlgorithm;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the provider used to create the {@link SecureRandom}
|
||||
* instances which generate new session IDs.
|
||||
*
|
||||
* @return The name of the provider. {@code null} or the empty string means
|
||||
* that platform default will be used
|
||||
*/
|
||||
public String getSecureRandomProvider() {
|
||||
return secureRandomProvider;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify a non-default provider to use to create instances of
|
||||
* {@link SecureRandom} which are used to generate session IDs. If no
|
||||
* provider is specified, the platform default is used. To use the platform
|
||||
* default specify {@code null} or the empty string. If an invalid algorithm
|
||||
* and/or provider is specified the {@link SecureRandom} instances will be
|
||||
* created using the defaults for this {@link SessionIdGenerator}
|
||||
* implementation. If that fails, the {@link SecureRandom} instances will be
|
||||
* created using platform defaults.
|
||||
*
|
||||
* @param secureRandomProvider The name of the provider
|
||||
*/
|
||||
public void setSecureRandomProvider(String secureRandomProvider) {
|
||||
this.secureRandomProvider = secureRandomProvider;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the node identifier associated with this node which will be
|
||||
* included in the generated session ID.
|
||||
*/
|
||||
@Override
|
||||
public String getJvmRoute() {
|
||||
return jvmRoute;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the node identifier associated with this node which will be
|
||||
* included in the generated session ID.
|
||||
*
|
||||
* @param jvmRoute The node identifier
|
||||
*/
|
||||
@Override
|
||||
public void setJvmRoute(String jvmRoute) {
|
||||
this.jvmRoute = jvmRoute;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Return the number of bytes for a session ID
|
||||
*/
|
||||
@Override
|
||||
public int getSessionIdLength() {
|
||||
return sessionIdLength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Specify the number of bytes for a session ID
|
||||
*
|
||||
* @param sessionIdLength Number of bytes
|
||||
*/
|
||||
@Override
|
||||
public void setSessionIdLength(int sessionIdLength) {
|
||||
this.sessionIdLength = sessionIdLength;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Generate and return a new session identifier.
|
||||
*/
|
||||
@Override
|
||||
public String generateSessionId() {
|
||||
return generateSessionId(jvmRoute);
|
||||
}
|
||||
|
||||
|
||||
protected void getRandomBytes(byte bytes[]) {
|
||||
|
||||
SecureRandom random = randoms.poll();
|
||||
if (random == null) {
|
||||
random = createSecureRandom();
|
||||
}
|
||||
random.nextBytes(bytes);
|
||||
randoms.add(random);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a new random number generator instance we should use for
|
||||
* generating session identifiers.
|
||||
*/
|
||||
private SecureRandom createSecureRandom() {
|
||||
|
||||
SecureRandom result = null;
|
||||
|
||||
long t1 = System.currentTimeMillis();
|
||||
if (secureRandomClass != null) {
|
||||
try {
|
||||
// Construct and seed a new random number generator
|
||||
Class<?> clazz = Class.forName(secureRandomClass);
|
||||
result = (SecureRandom) clazz.getConstructor().newInstance();
|
||||
} catch (Exception e) {
|
||||
log.error(sm.getString("sessionIdGeneratorBase.random",
|
||||
secureRandomClass), e);
|
||||
}
|
||||
}
|
||||
|
||||
boolean error = false;
|
||||
if (result == null) {
|
||||
// No secureRandomClass or creation failed. Use SecureRandom.
|
||||
try {
|
||||
if (secureRandomProvider != null &&
|
||||
secureRandomProvider.length() > 0) {
|
||||
result = SecureRandom.getInstance(secureRandomAlgorithm,
|
||||
secureRandomProvider);
|
||||
} else if (secureRandomAlgorithm != null &&
|
||||
secureRandomAlgorithm.length() > 0) {
|
||||
result = SecureRandom.getInstance(secureRandomAlgorithm);
|
||||
}
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
error = true;
|
||||
log.error(sm.getString("sessionIdGeneratorBase.randomAlgorithm",
|
||||
secureRandomAlgorithm), e);
|
||||
} catch (NoSuchProviderException e) {
|
||||
error = true;
|
||||
log.error(sm.getString("sessionIdGeneratorBase.randomProvider",
|
||||
secureRandomProvider), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null && error) {
|
||||
// Invalid provider / algorithm
|
||||
try {
|
||||
result = SecureRandom.getInstance("SHA1PRNG");
|
||||
} catch (NoSuchAlgorithmException e) {
|
||||
log.error(sm.getString("sessionIdGeneratorBase.randomAlgorithm",
|
||||
secureRandomAlgorithm), e);
|
||||
}
|
||||
}
|
||||
|
||||
if (result == null) {
|
||||
// Nothing works - use platform default
|
||||
result = new SecureRandom();
|
||||
}
|
||||
|
||||
// Force seeding to take place
|
||||
result.nextInt();
|
||||
|
||||
long t2 = System.currentTimeMillis();
|
||||
if ((t2 - t1) > 100) {
|
||||
log.warn(sm.getString("sessionIdGeneratorBase.createRandom",
|
||||
result.getAlgorithm(), Long.valueOf(t2 - t1)));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void initInternal() throws LifecycleException {
|
||||
// NO-OP
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void startInternal() throws LifecycleException {
|
||||
// Ensure SecureRandom has been initialised
|
||||
generateSessionId();
|
||||
|
||||
setState(LifecycleState.STARTING);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void stopInternal() throws LifecycleException {
|
||||
setState(LifecycleState.STOPPING);
|
||||
randoms.clear();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void destroyInternal() throws LifecycleException {
|
||||
// NO-OP
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
public class StandardSessionIdGenerator extends SessionIdGeneratorBase {
|
||||
|
||||
@Override
|
||||
public String generateSessionId(String route) {
|
||||
|
||||
byte random[] = new byte[16];
|
||||
int sessionIdLength = getSessionIdLength();
|
||||
|
||||
// Render the result as a String of hexadecimal digits
|
||||
// Start with enough space for sessionIdLength and medium route size
|
||||
StringBuilder buffer = new StringBuilder(2 * sessionIdLength + 20);
|
||||
|
||||
int resultLenBytes = 0;
|
||||
|
||||
while (resultLenBytes < sessionIdLength) {
|
||||
getRandomBytes(random);
|
||||
for (int j = 0;
|
||||
j < random.length && resultLenBytes < sessionIdLength;
|
||||
j++) {
|
||||
byte b1 = (byte) ((random[j] & 0xf0) >> 4);
|
||||
byte b2 = (byte) (random[j] & 0x0f);
|
||||
if (b1 < 10)
|
||||
buffer.append((char) ('0' + b1));
|
||||
else
|
||||
buffer.append((char) ('A' + (b1 - 10)));
|
||||
if (b2 < 10)
|
||||
buffer.append((char) ('0' + b2));
|
||||
else
|
||||
buffer.append((char) ('A' + (b2 - 10)));
|
||||
resultLenBytes++;
|
||||
}
|
||||
}
|
||||
|
||||
if (route != null && route.length() > 0) {
|
||||
buffer.append('.').append(route);
|
||||
} else {
|
||||
String jvmRoute = getJvmRoute();
|
||||
if (jvmRoute != null && jvmRoute.length() > 0) {
|
||||
buffer.append('.').append(jvmRoute);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
||||
253
java/org/apache/catalina/util/Strftime.java
Normal file
253
java/org/apache/catalina/util/Strftime.java
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.TimeZone;
|
||||
|
||||
/**
|
||||
* Converts dates to strings using the same format specifiers as strftime
|
||||
*
|
||||
* Note: This does not mimic strftime perfectly. Certain strftime commands,
|
||||
* are not supported, and will convert as if they were literals.
|
||||
*
|
||||
* Certain complicated commands, like those dealing with the week of the year
|
||||
* probably don't have exactly the same behavior as strftime.
|
||||
*
|
||||
* These limitations are due to use SimpleDateTime. If the conversion was done
|
||||
* manually, all these limitations could be eliminated.
|
||||
*
|
||||
* The interface looks like a subset of DateFormat. Maybe someday someone will make this class
|
||||
* extend DateFormat.
|
||||
*
|
||||
* @author Bip Thelin
|
||||
* @author Dan Sandberg
|
||||
*/
|
||||
public class Strftime {
|
||||
protected static final Properties translate;
|
||||
protected final SimpleDateFormat simpleDateFormat;
|
||||
|
||||
/**
|
||||
* Initialize our pattern translation
|
||||
*/
|
||||
static {
|
||||
translate = new Properties();
|
||||
translate.put("a","EEE");
|
||||
translate.put("A","EEEE");
|
||||
translate.put("b","MMM");
|
||||
translate.put("B","MMMM");
|
||||
translate.put("c","EEE MMM d HH:mm:ss yyyy");
|
||||
|
||||
//There's no way to specify the century in SimpleDateFormat. We don't want to hard-code
|
||||
//20 since this could be wrong for the pre-2000 files.
|
||||
//translate.put("C", "20");
|
||||
translate.put("d","dd");
|
||||
translate.put("D","MM/dd/yy");
|
||||
translate.put("e","dd"); //will show as '03' instead of ' 3'
|
||||
translate.put("F","yyyy-MM-dd");
|
||||
translate.put("g","yy");
|
||||
translate.put("G","yyyy");
|
||||
translate.put("H","HH");
|
||||
translate.put("h","MMM");
|
||||
translate.put("I","hh");
|
||||
translate.put("j","DDD");
|
||||
translate.put("k","HH"); //will show as '07' instead of ' 7'
|
||||
translate.put("l","hh"); //will show as '07' instead of ' 7'
|
||||
translate.put("m","MM");
|
||||
translate.put("M","mm");
|
||||
translate.put("n","\n");
|
||||
translate.put("p","a");
|
||||
translate.put("P","a"); //will show as pm instead of PM
|
||||
translate.put("r","hh:mm:ss a");
|
||||
translate.put("R","HH:mm");
|
||||
//There's no way to specify this with SimpleDateFormat
|
||||
//translate.put("s","seconds since epoch");
|
||||
translate.put("S","ss");
|
||||
translate.put("t","\t");
|
||||
translate.put("T","HH:mm:ss");
|
||||
//There's no way to specify this with SimpleDateFormat
|
||||
//translate.put("u","day of week ( 1-7 )");
|
||||
|
||||
//There's no way to specify this with SimpleDateFormat
|
||||
//translate.put("U","week in year with first Sunday as first day...");
|
||||
|
||||
translate.put("V","ww"); //I'm not sure this is always exactly the same
|
||||
|
||||
//There's no way to specify this with SimpleDateFormat
|
||||
//translate.put("W","week in year with first Monday as first day...");
|
||||
|
||||
//There's no way to specify this with SimpleDateFormat
|
||||
//translate.put("w","E");
|
||||
translate.put("X","HH:mm:ss");
|
||||
translate.put("x","MM/dd/yy");
|
||||
translate.put("y","yy");
|
||||
translate.put("Y","yyyy");
|
||||
translate.put("Z","z");
|
||||
translate.put("z","Z");
|
||||
translate.put("%","%");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create an instance of this date formatting class
|
||||
*
|
||||
* @param origFormat the strftime-style formatting string
|
||||
* @param locale the locale to use for locale-specific conversions
|
||||
*/
|
||||
public Strftime( String origFormat, Locale locale ) {
|
||||
String convertedFormat = convertDateFormat( origFormat );
|
||||
simpleDateFormat = new SimpleDateFormat( convertedFormat, locale );
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the date according to the strftime-style string given in the constructor.
|
||||
*
|
||||
* @param date the date to format
|
||||
* @return the formatted date
|
||||
*/
|
||||
public String format( Date date ) {
|
||||
return simpleDateFormat.format( date );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the timezone used for formatting conversions
|
||||
*
|
||||
* @return the timezone
|
||||
*/
|
||||
public TimeZone getTimeZone() {
|
||||
return simpleDateFormat.getTimeZone();
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the timezone used to format dates
|
||||
*
|
||||
* @param timeZone The new time zone
|
||||
* @see SimpleDateFormat#setTimeZone
|
||||
*/
|
||||
public void setTimeZone( TimeZone timeZone ) {
|
||||
simpleDateFormat.setTimeZone( timeZone );
|
||||
}
|
||||
|
||||
/**
|
||||
* Search the provided pattern and get the C standard
|
||||
* Date/Time formatting rules and convert them to the
|
||||
* Java equivalent.
|
||||
*
|
||||
* @param pattern The pattern to search
|
||||
* @return The modified pattern
|
||||
*/
|
||||
protected String convertDateFormat( String pattern ) {
|
||||
boolean inside = false;
|
||||
boolean mark = false;
|
||||
boolean modifiedCommand = false;
|
||||
|
||||
StringBuilder buf = new StringBuilder();
|
||||
|
||||
for(int i = 0; i < pattern.length(); i++) {
|
||||
char c = pattern.charAt(i);
|
||||
|
||||
if ( c=='%' && !mark ) {
|
||||
mark=true;
|
||||
} else {
|
||||
if ( mark ) {
|
||||
if ( modifiedCommand ) {
|
||||
//don't do anything--we just wanted to skip a char
|
||||
modifiedCommand = false;
|
||||
mark = false;
|
||||
} else {
|
||||
inside = translateCommand( buf, pattern, i, inside );
|
||||
//It's a modifier code
|
||||
if ( c=='O' || c=='E' ) {
|
||||
modifiedCommand = true;
|
||||
} else {
|
||||
mark=false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( !inside && c != ' ' ) {
|
||||
//We start a literal, which we need to quote
|
||||
buf.append("'");
|
||||
inside = true;
|
||||
}
|
||||
|
||||
buf.append(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( buf.length() > 0 ) {
|
||||
char lastChar = buf.charAt( buf.length() - 1 );
|
||||
|
||||
if( lastChar!='\'' && inside ) {
|
||||
buf.append('\'');
|
||||
}
|
||||
}
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
protected String quote( String str, boolean insideQuotes ) {
|
||||
String retVal = str;
|
||||
if ( !insideQuotes ) {
|
||||
retVal = '\'' + retVal + '\'';
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to get the Java Date/Time formatting associated with
|
||||
* the C standard provided.
|
||||
*
|
||||
* @param buf The buffer
|
||||
* @param pattern The date/time pattern
|
||||
* @param index The char index
|
||||
* @param oldInside Flag value
|
||||
* @return True if new is inside buffer
|
||||
*/
|
||||
protected boolean translateCommand( StringBuilder buf, String pattern, int index, boolean oldInside ) {
|
||||
char firstChar = pattern.charAt( index );
|
||||
boolean newInside = oldInside;
|
||||
|
||||
//O and E are modifiers, they mean to present an alternative representation of the next char
|
||||
//we just handle the next char as if the O or E wasn't there
|
||||
if ( firstChar == 'O' || firstChar == 'E' ) {
|
||||
if ( index + 1 < pattern.length() ) {
|
||||
newInside = translateCommand( buf, pattern, index + 1, oldInside );
|
||||
} else {
|
||||
buf.append( quote("%" + firstChar, oldInside ) );
|
||||
}
|
||||
} else {
|
||||
String command = translate.getProperty( String.valueOf( firstChar ) );
|
||||
|
||||
//If we don't find a format, treat it as a literal--That's what apache does
|
||||
if ( command == null ) {
|
||||
buf.append( quote( "%" + firstChar, oldInside ) );
|
||||
} else {
|
||||
//If we were inside quotes, close the quotes
|
||||
if ( oldInside ) {
|
||||
buf.append( '\'' );
|
||||
}
|
||||
buf.append( command );
|
||||
newInside = false;
|
||||
}
|
||||
}
|
||||
return newInside;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
|
||||
import org.apache.catalina.Lifecycle;
|
||||
import org.apache.catalina.LifecycleEvent;
|
||||
import org.apache.catalina.LifecycleListener;
|
||||
import org.apache.tomcat.util.digester.Digester;
|
||||
|
||||
|
||||
/**
|
||||
* Helper class used to do property replacement on system properties.
|
||||
* @deprecated No longer used. Will be removed in Tomcat 9.
|
||||
*/
|
||||
@Deprecated
|
||||
public class SystemPropertyReplacerListener
|
||||
implements LifecycleListener {
|
||||
|
||||
|
||||
// ---------------------------------------------- LifecycleListener Methods
|
||||
|
||||
|
||||
@Override
|
||||
public void lifecycleEvent(LifecycleEvent event) {
|
||||
if (Lifecycle.BEFORE_INIT_EVENT.equals(event.getType())) {
|
||||
Digester.replaceSystemProperties();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
43
java/org/apache/catalina/util/TLSUtil.java
Normal file
43
java/org/apache/catalina/util/TLSUtil.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import org.apache.catalina.Globals;
|
||||
import org.apache.tomcat.util.net.SSLSupport;
|
||||
|
||||
public class TLSUtil {
|
||||
|
||||
/**
|
||||
* Determines if the named request attribute is used to pass information
|
||||
* about the TLS configuration of the connection to the application. Both
|
||||
* the standard request attributes defined by the Servlet specification and
|
||||
* Tomcat specific attributes are supported.
|
||||
*
|
||||
* @param name The attribute name to test
|
||||
*
|
||||
* @return {@code true} if the attribute is used to pass TLS configuration
|
||||
* information, otherwise {@code false}
|
||||
*/
|
||||
public static boolean isTLSRequestAttribute(String name) {
|
||||
return Globals.CERTIFICATES_ATTR.equals(name) ||
|
||||
Globals.CIPHER_SUITE_ATTR.equals(name) ||
|
||||
Globals.KEY_SIZE_ATTR.equals(name) ||
|
||||
Globals.SSL_SESSION_ID_ATTR.equals(name) ||
|
||||
Globals.SSL_SESSION_MGR_ATTR.equals(name) ||
|
||||
SSLSupport.PROTOCOL_VERSION_KEY.equals(name);
|
||||
}
|
||||
}
|
||||
34
java/org/apache/catalina/util/TomcatCSS.java
Normal file
34
java/org/apache/catalina/util/TomcatCSS.java
Normal file
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
|
||||
public class TomcatCSS {
|
||||
|
||||
public static final String TOMCAT_CSS =
|
||||
"body {font-family:Tahoma,Arial,sans-serif;} " +
|
||||
"h1, h2, h3, b {color:white;background-color:#525D76;} " +
|
||||
"h1 {font-size:22px;} " +
|
||||
"h2 {font-size:16px;} " +
|
||||
"h3 {font-size:14px;} " +
|
||||
"p {font-size:12px;} " +
|
||||
"a {color:black;} " +
|
||||
".line {height:1px;background-color:#525D76;border:none;}";
|
||||
|
||||
}
|
||||
235
java/org/apache/catalina/util/URLEncoder.java
Normal file
235
java/org/apache/catalina/util/URLEncoder.java
Normal file
@@ -0,0 +1,235 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.BitSet;
|
||||
|
||||
import org.apache.tomcat.util.buf.B2CConverter;
|
||||
|
||||
/**
|
||||
*
|
||||
* This class is very similar to the java.net.URLEncoder class.
|
||||
*
|
||||
* Unfortunately, with java.net.URLEncoder there is no way to specify to the
|
||||
* java.net.URLEncoder which characters should NOT be encoded.
|
||||
*
|
||||
* This code was moved from DefaultServlet.java
|
||||
*
|
||||
* @author Craig R. McClanahan
|
||||
* @author Remy Maucherat
|
||||
*/
|
||||
public final class URLEncoder implements Cloneable {
|
||||
|
||||
private static final char[] hexadecimal =
|
||||
{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
|
||||
|
||||
public static final URLEncoder DEFAULT = new URLEncoder();
|
||||
public static final URLEncoder QUERY = new URLEncoder();
|
||||
|
||||
static {
|
||||
/*
|
||||
* Encoder for URI paths, so from the spec:
|
||||
*
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
*
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
*
|
||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
* / "*" / "+" / "," / ";" / "="
|
||||
*/
|
||||
// ALPHA and DIGIT are always treated as safe characters
|
||||
// Add the remaining unreserved characters
|
||||
DEFAULT.addSafeCharacter('-');
|
||||
DEFAULT.addSafeCharacter('.');
|
||||
DEFAULT.addSafeCharacter('_');
|
||||
DEFAULT.addSafeCharacter('~');
|
||||
// Add the sub-delims
|
||||
DEFAULT.addSafeCharacter('!');
|
||||
DEFAULT.addSafeCharacter('$');
|
||||
DEFAULT.addSafeCharacter('&');
|
||||
DEFAULT.addSafeCharacter('\'');
|
||||
DEFAULT.addSafeCharacter('(');
|
||||
DEFAULT.addSafeCharacter(')');
|
||||
DEFAULT.addSafeCharacter('*');
|
||||
DEFAULT.addSafeCharacter('+');
|
||||
DEFAULT.addSafeCharacter(',');
|
||||
DEFAULT.addSafeCharacter(';');
|
||||
DEFAULT.addSafeCharacter('=');
|
||||
// Add the remaining literals
|
||||
DEFAULT.addSafeCharacter(':');
|
||||
DEFAULT.addSafeCharacter('@');
|
||||
// Add '/' so it isn't encoded when we encode a path
|
||||
DEFAULT.addSafeCharacter('/');
|
||||
|
||||
/*
|
||||
* Encoder for query strings
|
||||
* https://www.w3.org/TR/html5/forms.html#application/x-www-form-urlencoded-encoding-algorithm
|
||||
* 0x20 ' ' -> '+'
|
||||
* 0x2A, 0x2D, 0x2E, 0x30 to 0x39, 0x41 to 0x5A, 0x5F, 0x61 to 0x7A as-is
|
||||
* '*', '-', '.', '0' to '9', 'A' to 'Z', '_', 'a' to 'z'
|
||||
* Also '=' and '&' are not encoded
|
||||
* Everything else %nn encoded
|
||||
*/
|
||||
// Special encoding for space
|
||||
QUERY.setEncodeSpaceAsPlus(true);
|
||||
// Alpha and digit are safe by default
|
||||
// Add the other permitted characters
|
||||
QUERY.addSafeCharacter('*');
|
||||
QUERY.addSafeCharacter('-');
|
||||
QUERY.addSafeCharacter('.');
|
||||
QUERY.addSafeCharacter('_');
|
||||
QUERY.addSafeCharacter('=');
|
||||
QUERY.addSafeCharacter('&');
|
||||
}
|
||||
|
||||
//Array containing the safe characters set.
|
||||
private final BitSet safeCharacters;
|
||||
|
||||
private boolean encodeSpaceAsPlus = false;
|
||||
|
||||
|
||||
public URLEncoder() {
|
||||
this(new BitSet(256));
|
||||
|
||||
for (char i = 'a'; i <= 'z'; i++) {
|
||||
addSafeCharacter(i);
|
||||
}
|
||||
for (char i = 'A'; i <= 'Z'; i++) {
|
||||
addSafeCharacter(i);
|
||||
}
|
||||
for (char i = '0'; i <= '9'; i++) {
|
||||
addSafeCharacter(i);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private URLEncoder(BitSet safeCharacters) {
|
||||
this.safeCharacters = safeCharacters;
|
||||
}
|
||||
|
||||
|
||||
public void addSafeCharacter(char c) {
|
||||
safeCharacters.set(c);
|
||||
}
|
||||
|
||||
|
||||
public void removeSafeCharacter(char c) {
|
||||
safeCharacters.clear(c);
|
||||
}
|
||||
|
||||
|
||||
public void setEncodeSpaceAsPlus(boolean encodeSpaceAsPlus) {
|
||||
this.encodeSpaceAsPlus = encodeSpaceAsPlus;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* URL encodes the provided path using UTF-8.
|
||||
*
|
||||
* @param path The path to encode
|
||||
*
|
||||
* @return The encoded path
|
||||
*
|
||||
* @deprecated Use {@link #encode(String, String)}
|
||||
*/
|
||||
@Deprecated
|
||||
public String encode(String path) {
|
||||
return encode(path, "UTF-8");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* URL encodes the provided path using the given encoding.
|
||||
*
|
||||
* @param path The path to encode
|
||||
* @param encoding The encoding to use to convert the path to bytes
|
||||
*
|
||||
* @return The encoded path
|
||||
*
|
||||
* @deprecated This will be removed in Tomcat 9.0.x
|
||||
*/
|
||||
@Deprecated
|
||||
public String encode(String path, String encoding) {
|
||||
Charset charset;
|
||||
try {
|
||||
charset = B2CConverter.getCharset(encoding);
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
charset = Charset.defaultCharset();
|
||||
}
|
||||
return encode(path, charset);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* URL encodes the provided path using the given character set.
|
||||
*
|
||||
* @param path The path to encode
|
||||
* @param charset The character set to use to convert the path to bytes
|
||||
*
|
||||
* @return The encoded path
|
||||
*/
|
||||
public String encode(String path, Charset charset) {
|
||||
|
||||
int maxBytesPerChar = 10;
|
||||
StringBuilder rewrittenPath = new StringBuilder(path.length());
|
||||
ByteArrayOutputStream buf = new ByteArrayOutputStream(maxBytesPerChar);
|
||||
OutputStreamWriter writer = new OutputStreamWriter(buf, charset);
|
||||
|
||||
for (int i = 0; i < path.length(); i++) {
|
||||
int c = path.charAt(i);
|
||||
if (safeCharacters.get(c)) {
|
||||
rewrittenPath.append((char)c);
|
||||
} else if (encodeSpaceAsPlus && c == ' ') {
|
||||
rewrittenPath.append('+');
|
||||
} else {
|
||||
// convert to external encoding before hex conversion
|
||||
try {
|
||||
writer.write((char)c);
|
||||
writer.flush();
|
||||
} catch(IOException e) {
|
||||
buf.reset();
|
||||
continue;
|
||||
}
|
||||
byte[] ba = buf.toByteArray();
|
||||
for (int j = 0; j < ba.length; j++) {
|
||||
// Converting each byte in the buffer
|
||||
byte toEncode = ba[j];
|
||||
rewrittenPath.append('%');
|
||||
int low = toEncode & 0x0f;
|
||||
int high = (toEncode & 0xf0) >> 4;
|
||||
rewrittenPath.append(hexadecimal[high]);
|
||||
rewrittenPath.append(hexadecimal[low]);
|
||||
}
|
||||
buf.reset();
|
||||
}
|
||||
}
|
||||
return rewrittenPath.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object clone() {
|
||||
URLEncoder result = new URLEncoder((BitSet) safeCharacters.clone());
|
||||
result.setEncodeSpaceAsPlus(encodeSpaceAsPlus);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
222
java/org/apache/catalina/util/XMLWriter.java
Normal file
222
java/org/apache/catalina/util/XMLWriter.java
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
* 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.catalina.util;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.Writer;
|
||||
|
||||
/**
|
||||
* XMLWriter helper class.
|
||||
*/
|
||||
public class XMLWriter {
|
||||
|
||||
|
||||
// -------------------------------------------------------------- Constants
|
||||
|
||||
|
||||
/**
|
||||
* Opening tag.
|
||||
*/
|
||||
public static final int OPENING = 0;
|
||||
|
||||
|
||||
/**
|
||||
* Closing tag.
|
||||
*/
|
||||
public static final int CLOSING = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Element with no content.
|
||||
*/
|
||||
public static final int NO_CONTENT = 2;
|
||||
|
||||
|
||||
// ----------------------------------------------------- Instance Variables
|
||||
|
||||
|
||||
/**
|
||||
* Buffer.
|
||||
*/
|
||||
protected StringBuilder buffer = new StringBuilder();
|
||||
|
||||
|
||||
/**
|
||||
* Writer.
|
||||
*/
|
||||
protected final Writer writer;
|
||||
|
||||
|
||||
// ----------------------------------------------------------- Constructors
|
||||
|
||||
|
||||
/**
|
||||
* New XML writer utility that will store its data in an internal buffer.
|
||||
*/
|
||||
public XMLWriter() {
|
||||
this(null);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* New XML writer utility that will store its data in an internal buffer
|
||||
* and can write it to the specified writer.
|
||||
* <p>
|
||||
* See {@link #sendData()}
|
||||
*
|
||||
* @param writer The writer to use
|
||||
*/
|
||||
public XMLWriter(Writer writer) {
|
||||
this.writer = writer;
|
||||
}
|
||||
|
||||
|
||||
// --------------------------------------------------------- Public Methods
|
||||
|
||||
|
||||
/**
|
||||
* Retrieve generated XML.
|
||||
*
|
||||
* @return String containing the generated XML
|
||||
*/
|
||||
@Override
|
||||
public String toString() {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write property to the XML.
|
||||
*
|
||||
* @param namespace Namespace
|
||||
* @param name Property name
|
||||
* @param value Property value
|
||||
*/
|
||||
public void writeProperty(String namespace, String name, String value) {
|
||||
writeElement(namespace, name, OPENING);
|
||||
buffer.append(value);
|
||||
writeElement(namespace, name, CLOSING);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write an element.
|
||||
*
|
||||
* @param name Element name
|
||||
* @param namespace Namespace abbreviation
|
||||
* @param type Element type
|
||||
*/
|
||||
public void writeElement(String namespace, String name, int type) {
|
||||
writeElement(namespace, null, name, type);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write an element.
|
||||
*
|
||||
* @param namespace Namespace abbreviation
|
||||
* @param namespaceInfo Namespace info
|
||||
* @param name Element name
|
||||
* @param type Element type
|
||||
*/
|
||||
public void writeElement(String namespace, String namespaceInfo,
|
||||
String name, int type) {
|
||||
if ((namespace != null) && (namespace.length() > 0)) {
|
||||
switch (type) {
|
||||
case OPENING:
|
||||
if (namespaceInfo != null) {
|
||||
buffer.append("<" + namespace + ":" + name + " xmlns:"
|
||||
+ namespace + "=\""
|
||||
+ namespaceInfo + "\">");
|
||||
} else {
|
||||
buffer.append("<" + namespace + ":" + name + ">");
|
||||
}
|
||||
break;
|
||||
case CLOSING:
|
||||
buffer.append("</" + namespace + ":" + name + ">\n");
|
||||
break;
|
||||
case NO_CONTENT:
|
||||
default:
|
||||
if (namespaceInfo != null) {
|
||||
buffer.append("<" + namespace + ":" + name + " xmlns:"
|
||||
+ namespace + "=\""
|
||||
+ namespaceInfo + "\"/>");
|
||||
} else {
|
||||
buffer.append("<" + namespace + ":" + name + "/>");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (type) {
|
||||
case OPENING:
|
||||
buffer.append("<" + name + ">");
|
||||
break;
|
||||
case CLOSING:
|
||||
buffer.append("</" + name + ">\n");
|
||||
break;
|
||||
case NO_CONTENT:
|
||||
default:
|
||||
buffer.append("<" + name + "/>");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write text.
|
||||
*
|
||||
* @param text Text to append
|
||||
*/
|
||||
public void writeText(String text) {
|
||||
buffer.append(text);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write data.
|
||||
*
|
||||
* @param data Data to append
|
||||
*/
|
||||
public void writeData(String data) {
|
||||
buffer.append("<![CDATA[" + data + "]]>");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write XML Header.
|
||||
*/
|
||||
public void writeXMLHeader() {
|
||||
buffer.append("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send data and reinitializes buffer, if a writer has been specified.
|
||||
* @throws IOException Error writing XML data
|
||||
*/
|
||||
public void sendData()
|
||||
throws IOException {
|
||||
if (writer != null) {
|
||||
writer.write(buffer.toString());
|
||||
buffer = new StringBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user