You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@struts.apache.org by lu...@apache.org on 2015/06/17 23:09:32 UTC
[32/57] [partial] struts git commit: Merges xwork packages into struts
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/location/LocationAttributes.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/location/LocationAttributes.java b/core/src/main/java/com/opensymphony/xwork2/util/location/LocationAttributes.java
new file mode 100644
index 0000000..5ca0934
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/location/LocationAttributes.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.location;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.AttributesImpl;
+
+/**
+ * A class to handle location information stored in attributes.
+ * These attributes are typically setup using {@link com.opensymphony.xwork2.util.location.LocationAttributes.Pipe}
+ * which augments the SAX stream with additional attributes, e.g.:
+ * <pre>
+ * <root xmlns:loc="http://struts.apache.org/xwork/location"
+ * loc:src="file://path/to/file.xml"
+ * loc:line="1" loc:column="1">
+ * <foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/>
+ * </root>
+ * </pre>
+ *
+ * @see com.opensymphony.xwork2.util.location.LocationAttributes.Pipe
+ * @since 2.1.8
+ * @version $Id$
+ */
+public class LocationAttributes {
+ /** Prefix for the location namespace */
+ public static final String PREFIX = "loc";
+ /** Namespace URI for location attributes */
+ public static final String URI = "http://struts.apache.org/xwork/location";
+
+ /** Attribute name for the location URI */
+ public static final String SRC_ATTR = "src";
+ /** Attribute name for the line number */
+ public static final String LINE_ATTR = "line";
+ /** Attribute name for the column number */
+ public static final String COL_ATTR = "column";
+
+ /** Attribute qualified name for the location URI */
+ public static final String Q_SRC_ATTR = "loc:src";
+ /** Attribute qualified name for the line number */
+ public static final String Q_LINE_ATTR = "loc:line";
+ /** Attribute qualified name for the column number */
+ public static final String Q_COL_ATTR = "loc:column";
+
+ // Private constructor, we only have static methods
+ private LocationAttributes() {
+ // Nothing
+ }
+
+ /**
+ * Add location attributes to a set of SAX attributes.
+ *
+ * @param locator the <code>Locator</code> (can be null)
+ * @param attrs the <code>Attributes</code> where locator information should be added
+ * @return Location enabled Attributes.
+ */
+ public static Attributes addLocationAttributes(Locator locator, Attributes attrs) {
+ if (locator == null || attrs.getIndex(URI, SRC_ATTR) != -1) {
+ // No location information known, or already has it
+ return attrs;
+ }
+
+ // Get an AttributeImpl so that we can add new attributes.
+ AttributesImpl newAttrs = attrs instanceof AttributesImpl ?
+ (AttributesImpl)attrs : new AttributesImpl(attrs);
+
+ newAttrs.addAttribute(URI, SRC_ATTR, Q_SRC_ATTR, "CDATA", locator.getSystemId());
+ newAttrs.addAttribute(URI, LINE_ATTR, Q_LINE_ATTR, "CDATA", Integer.toString(locator.getLineNumber()));
+ newAttrs.addAttribute(URI, COL_ATTR, Q_COL_ATTR, "CDATA", Integer.toString(locator.getColumnNumber()));
+
+ return newAttrs;
+ }
+
+ /**
+ * Returns the {@link Location} of an element (SAX flavor).
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @param description a description for the location (can be null)
+ * @return a {@link Location} object
+ */
+ public static Location getLocation(Attributes attrs, String description) {
+ String src = attrs.getValue(URI, SRC_ATTR);
+ if (src == null) {
+ return Location.UNKNOWN;
+ }
+
+ return new LocationImpl(description, src, getLine(attrs), getColumn(attrs));
+ }
+
+ /**
+ * Returns the location of an element (SAX flavor). If the location is to be kept
+ * into an object built from this element, consider using {@link #getLocation(Attributes, String)}
+ * and the {@link Locatable} interface.
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @return a location string as defined by {@link Location}.
+ */
+ public static String getLocationString(Attributes attrs) {
+ String src = attrs.getValue(URI, SRC_ATTR);
+ if (src == null) {
+ return LocationUtils.UNKNOWN_STRING;
+ }
+
+ return src + ":" + attrs.getValue(URI, LINE_ATTR) + ":" + attrs.getValue(URI, COL_ATTR);
+ }
+
+ /**
+ * Returns the URI of an element (SAX flavor)
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @return the element's URI or "<code>[unknown location]</code>" if <code>attrs</code>
+ * has no location information.
+ */
+ public static String getURI(Attributes attrs) {
+ String src = attrs.getValue(URI, SRC_ATTR);
+ return src != null ? src : LocationUtils.UNKNOWN_STRING;
+ }
+
+ /**
+ * Returns the line number of an element (SAX flavor)
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @return the element's line number or <code>-1</code> if <code>attrs</code>
+ * has no location information.
+ */
+ public static int getLine(Attributes attrs) {
+ String line = attrs.getValue(URI, LINE_ATTR);
+ return line != null ? Integer.parseInt(line) : -1;
+ }
+
+ /**
+ * Returns the column number of an element (SAX flavor)
+ *
+ * @param attrs the element's attributes that hold the location information
+ * @return the element's column number or <code>-1</code> if <code>attrs</code>
+ * has no location information.
+ */
+ public static int getColumn(Attributes attrs) {
+ String col = attrs.getValue(URI, COL_ATTR);
+ return col != null ? Integer.parseInt(col) : -1;
+ }
+
+ /**
+ * Returns the {@link Location} of an element (DOM flavor).
+ *
+ * @param elem the element that holds the location information
+ * @param description a description for the location (if <code>null</code>, the element's name is used)
+ * @return a {@link Location} object
+ */
+ public static Location getLocation(Element elem, String description) {
+ Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+ if (srcAttr == null) {
+ return Location.UNKNOWN;
+ }
+
+ return new LocationImpl(description == null ? elem.getNodeName() : description,
+ srcAttr.getValue(), getLine(elem), getColumn(elem));
+ }
+
+ /**
+ * Same as <code>getLocation(elem, null)</code>.
+ */
+ public static Location getLocation(Element elem) {
+ return getLocation(elem, null);
+ }
+
+
+ /**
+ * Returns the location of an element that has been processed by this pipe (DOM flavor).
+ * If the location is to be kept into an object built from this element, consider using
+ * {@link #getLocation(Element)} and the {@link Locatable} interface.
+ *
+ * @param elem the element that holds the location information
+ * @return a location string as defined by {@link Location}.
+ */
+ public static String getLocationString(Element elem) {
+ Attr srcAttr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+ if (srcAttr == null) {
+ return LocationUtils.UNKNOWN_STRING;
+ }
+
+ return srcAttr.getValue() + ":" + elem.getAttributeNS(URI, LINE_ATTR) + ":" + elem.getAttributeNS(URI, COL_ATTR);
+ }
+
+ /**
+ * Returns the URI of an element (DOM flavor)
+ *
+ * @param elem the element that holds the location information
+ * @return the element's URI or "<code>[unknown location]</code>" if <code>elem</code>
+ * has no location information.
+ */
+ public static String getURI(Element elem) {
+ Attr attr = elem.getAttributeNodeNS(URI, SRC_ATTR);
+ return attr != null ? attr.getValue() : LocationUtils.UNKNOWN_STRING;
+ }
+
+ /**
+ * Returns the line number of an element (DOM flavor)
+ *
+ * @param elem the element that holds the location information
+ * @return the element's line number or <code>-1</code> if <code>elem</code>
+ * has no location information.
+ */
+ public static int getLine(Element elem) {
+ Attr attr = elem.getAttributeNodeNS(URI, LINE_ATTR);
+ return attr != null ? Integer.parseInt(attr.getValue()) : -1;
+ }
+
+ /**
+ * Returns the column number of an element (DOM flavor)
+ *
+ * @param elem the element that holds the location information
+ * @return the element's column number or <code>-1</code> if <code>elem</code>
+ * has no location information.
+ */
+ public static int getColumn(Element elem) {
+ Attr attr = elem.getAttributeNodeNS(URI, COL_ATTR);
+ return attr != null ? Integer.parseInt(attr.getValue()) : -1;
+ }
+
+ /**
+ * Remove the location attributes from a DOM element.
+ *
+ * @param elem the element to remove the location attributes from.
+ * @param recurse if <code>true</code>, also remove location attributes on descendant elements.
+ */
+ public static void remove(Element elem, boolean recurse) {
+ elem.removeAttributeNS(URI, SRC_ATTR);
+ elem.removeAttributeNS(URI, LINE_ATTR);
+ elem.removeAttributeNS(URI, COL_ATTR);
+ if (recurse) {
+ NodeList children = elem.getChildNodes();
+ for (int i = 0; i < children.getLength(); i++) {
+ Node child = children.item(i);
+ if (child.getNodeType() == Node.ELEMENT_NODE) {
+ remove((Element)child, recurse);
+ }
+ }
+ }
+ }
+
+ /**
+ * A SAX filter that adds the information available from the <code>Locator</code> as attributes.
+ * The purpose of having location as attributes is to allow this information to survive transformations
+ * of the document (an XSL could copy these attributes over) or conversion of SAX events to a DOM.
+ * <p>
+ * The location is added as 3 attributes in a specific namespace to each element.
+ * <pre>
+ * <root xmlns:loc="http://opensymphony.com/xwork/location"
+ * loc:src="file://path/to/file.xml"
+ * loc:line="1" loc:column="1">
+ * <foo loc:src="file://path/to/file.xml" loc:line="2" loc:column="3"/>
+ * </root>
+ * </pre>
+ * <strong>Note:</strong> Although this adds a lot of information to the serialized form of the document,
+ * the overhead in SAX events is not that big, as attribute names are interned, and all <code>src</code>
+ * attributes point to the same string.
+ *
+ * @see com.opensymphony.xwork2.util.location.LocationAttributes
+ */
+ public static class Pipe implements ContentHandler {
+
+ private Locator locator;
+
+ private ContentHandler nextHandler;
+
+ /**
+ * Create a filter. It has to be chained to another handler to be really useful.
+ */
+ public Pipe() {
+ }
+
+ /**
+ * Create a filter that is chained to another handler.
+ * @param next the next handler in the chain.
+ */
+ public Pipe(ContentHandler next) {
+ nextHandler = next;
+ }
+
+ public void setDocumentLocator(Locator locator) {
+ this.locator = locator;
+ nextHandler.setDocumentLocator(locator);
+ }
+
+ public void startDocument() throws SAXException {
+ nextHandler.startDocument();
+ nextHandler.startPrefixMapping(LocationAttributes.PREFIX, LocationAttributes.URI);
+ }
+
+ public void endDocument() throws SAXException {
+ endPrefixMapping(LocationAttributes.PREFIX);
+ nextHandler.endDocument();
+ }
+
+ public void startElement(String uri, String loc, String raw, Attributes attrs) throws SAXException {
+ // Add location attributes to the element
+ nextHandler.startElement(uri, loc, raw, LocationAttributes.addLocationAttributes(locator, attrs));
+ }
+
+ public void endElement(String arg0, String arg1, String arg2) throws SAXException {
+ nextHandler.endElement(arg0, arg1, arg2);
+ }
+
+ public void startPrefixMapping(String arg0, String arg1) throws SAXException {
+ nextHandler.startPrefixMapping(arg0, arg1);
+ }
+
+ public void endPrefixMapping(String arg0) throws SAXException {
+ nextHandler.endPrefixMapping(arg0);
+ }
+
+ public void characters(char[] arg0, int arg1, int arg2) throws SAXException {
+ nextHandler.characters(arg0, arg1, arg2);
+ }
+
+ public void ignorableWhitespace(char[] arg0, int arg1, int arg2) throws SAXException {
+ nextHandler.ignorableWhitespace(arg0, arg1, arg2);
+ }
+
+ public void processingInstruction(String arg0, String arg1) throws SAXException {
+ nextHandler.processingInstruction(arg0, arg1);
+ }
+
+ public void skippedEntity(String arg0) throws SAXException {
+ nextHandler.skippedEntity(arg0);
+ }
+ }
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/location/LocationImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/location/LocationImpl.java b/core/src/main/java/com/opensymphony/xwork2/util/location/LocationImpl.java
new file mode 100644
index 0000000..ca101ca
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/location/LocationImpl.java
@@ -0,0 +1,216 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.location;
+
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Serializable;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A simple immutable and serializable implementation of {@link Location}.
+ */
+public class LocationImpl implements Location, Serializable {
+
+ private final String uri;
+ private final int line;
+ private final int column;
+ private final String description;
+
+ // Package private: outside this package, use Location.UNKNOWN.
+ static final LocationImpl UNKNOWN = new LocationImpl(null, null, -1, -1);
+
+ /**
+ * Build a location for a given URI, with unknown line and column numbers.
+ *
+ * @param uri the resource URI
+ */
+ public LocationImpl(String description, String uri) {
+ this(description, uri, -1, -1);
+ }
+
+ /**
+ * Build a location for a given URI and line and column numbers.
+ *
+ * @param uri the resource URI
+ * @param line the line number (starts at 1)
+ * @param column the column number (starts at 1)
+ */
+ public LocationImpl(String description, String uri, int line, int column) {
+ if (StringUtils.isEmpty(uri)) {
+ this.uri = null;
+ this.line = -1;
+ this.column = -1;
+ } else {
+ this.uri = uri;
+ this.line = line;
+ this.column = column;
+ }
+ this.description = StringUtils.trimToNull(description);
+ }
+
+ /**
+ * Copy constructor.
+ *
+ * @param location the location to be copied
+ */
+ public LocationImpl(Location location) {
+ this(location.getDescription(), location.getURI(), location.getLineNumber(), location.getColumnNumber());
+ }
+
+ /**
+ * Create a location from an existing one, but with a different description
+ */
+ public LocationImpl(String description, Location location) {
+ this(description, location.getURI(), location.getLineNumber(), location.getColumnNumber());
+ }
+
+ /**
+ * Obtain a <code>LocationImpl</code> from a {@link Location}. If <code>location</code> is
+ * already a <code>LocationImpl</code>, it is returned, otherwise it is copied.
+ * <p>
+ * This method is useful when an immutable and serializable location is needed, such as in locatable
+ * exceptions.
+ *
+ * @param location the location
+ * @return an immutable and serializable version of <code>location</code>
+ */
+ public static LocationImpl get(Location location) {
+ if (location instanceof LocationImpl) {
+ return (LocationImpl)location;
+ } else if (location == null) {
+ return UNKNOWN;
+ } else {
+ return new LocationImpl(location);
+ }
+ }
+
+ /**
+ * Get the description of this location
+ *
+ * @return the description (can be <code>null</code>)
+ */
+ public String getDescription() {
+ return this.description;
+ }
+
+ /**
+ * Get the URI of this location
+ *
+ * @return the URI (<code>null</code> if unknown).
+ */
+ public String getURI() {
+ return this.uri;
+ }
+
+ /**
+ * Get the line number of this location
+ *
+ * @return the line number (<code>-1</code> if unknown)
+ */
+ public int getLineNumber() {
+ return this.line;
+ }
+
+ /**
+ * Get the column number of this location
+ *
+ * @return the column number (<code>-1</code> if unknown)
+ */
+ public int getColumnNumber() {
+ return this.column;
+ }
+
+ /**
+ * Gets a source code snippet with the default padding
+ *
+ * @param padding The amount of lines before and after the error to include
+ */
+ public List<String> getSnippet(int padding) {
+ List<String> snippet = new ArrayList<>();
+ if (getLineNumber() > 0) {
+ try {
+ InputStream in = new URL(getURI()).openStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(in));
+
+ int lineno = 0;
+ int errno = getLineNumber();
+ String line;
+ while ((line = reader.readLine()) != null) {
+ lineno++;
+ if (lineno >= errno - padding && lineno <= errno + padding) {
+ snippet.add(line);
+ }
+ }
+ } catch (Exception ex) {
+ // ignoring as snippet not available isn't a big deal
+ }
+ }
+ return snippet;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+
+ if (obj instanceof Location) {
+ Location other = (Location)obj;
+ return this.line == other.getLineNumber() && this.column == other.getColumnNumber()
+ && testEquals(this.uri, other.getURI())
+ && testEquals(this.description, other.getDescription());
+ }
+
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int hash = line ^ column;
+ if (uri != null) hash ^= uri.hashCode();
+ if (description != null) hash ^= description.hashCode();
+
+ return hash;
+ }
+
+ @Override
+ public String toString() {
+ return LocationUtils.toString(this);
+ }
+
+ /**
+ * Ensure serialized unknown location resolve to {@link Location#UNKNOWN}.
+ */
+ private Object readResolve() {
+ return this.equals(Location.UNKNOWN) ? Location.UNKNOWN : this;
+ }
+
+ private boolean testEquals(Object object1, Object object2) {
+ if (object1 == object2) {
+ return true;
+ }
+ if ((object1 == null) || (object2 == null)) {
+ return false;
+ }
+ return object1.equals(object2);
+ }
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/location/LocationUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/location/LocationUtils.java b/core/src/main/java/com/opensymphony/xwork2/util/location/LocationUtils.java
new file mode 100644
index 0000000..892d3c7
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/location/LocationUtils.java
@@ -0,0 +1,305 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.location;
+
+import com.opensymphony.xwork2.util.ClassLoaderUtil;
+import org.w3c.dom.Element;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXParseException;
+
+import javax.xml.transform.SourceLocator;
+import javax.xml.transform.TransformerException;
+import java.lang.ref.WeakReference;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Location-related utility methods.
+ */
+public class LocationUtils {
+
+ /**
+ * The string representation of an unknown location: "<code>[unknown location]</code>".
+ */
+ public static final String UNKNOWN_STRING = "[unknown location]";
+
+ private static List<WeakReference<LocationFinder>> finders = new ArrayList<>();
+
+ /**
+ * An finder or object locations
+ */
+ public interface LocationFinder {
+ /**
+ * Get the location of an object
+ * @param obj the object for which to find a location
+ * @param description and optional description to be added to the object's location
+ * @return the object's location or <code>null</code> if object's class isn't handled
+ * by this finder.
+ */
+ Location getLocation(Object obj, String description);
+ }
+
+ private LocationUtils() {
+ // Forbid instanciation
+ }
+
+ /**
+ * Builds a string representation of a location, in the
+ * "<code><em>descripton</em> - <em>uri</em>:<em>line</em>:<em>column</em></code>"
+ * format (e.g. "<code>foo - file://path/to/file.xml:3:40</code>"). For {@link Location#UNKNOWN an unknown location}, returns
+ * {@link #UNKNOWN_STRING}.
+ *
+ * @return the string representation
+ */
+ public static String toString(Location location) {
+ StringBuilder result = new StringBuilder();
+
+ String description = location.getDescription();
+ if (description != null) {
+ result.append(description).append(" - ");
+ }
+
+ String uri = location.getURI();
+ if (uri != null) {
+ result.append(uri).append(':').append(location.getLineNumber()).append(':').append(location.getColumnNumber());
+ } else {
+ result.append(UNKNOWN_STRING);
+ }
+
+ return result.toString();
+ }
+
+ /**
+ * Parse a location string of the form "<code><em>uri</em>:<em>line</em>:<em>column</em></code>" (e.g.
+ * "<code>path/to/file.xml:3:40</code>") to a Location object. Additionally, a description may
+ * also optionally be present, separated with an hyphen (e.g. "<code>foo - path/to/file.xml:3.40</code>").
+ *
+ * @param text the text to parse
+ * @return the location (possibly <code>null</code> if text was null or in an incorrect format)
+ */
+ public static LocationImpl parse(String text) throws IllegalArgumentException {
+ if (text == null || text.length() == 0) {
+ return null;
+ }
+
+ // Do we have a description?
+ String description;
+ int uriStart = text.lastIndexOf(" - "); // lastIndexOf to allow the separator to be in the description
+ if (uriStart > -1) {
+ description = text.substring(0, uriStart);
+ uriStart += 3; // strip " - "
+ } else {
+ description = null;
+ uriStart = 0;
+ }
+
+ try {
+ int colSep = text.lastIndexOf(':');
+ if (colSep > -1) {
+ int column = Integer.parseInt(text.substring(colSep + 1));
+
+ int lineSep = text.lastIndexOf(':', colSep - 1);
+ if (lineSep > -1) {
+ int line = Integer.parseInt(text.substring(lineSep + 1, colSep));
+ return new LocationImpl(description, text.substring(uriStart, lineSep), line, column);
+ }
+ } else {
+ // unkonwn?
+ if (text.endsWith(UNKNOWN_STRING)) {
+ return LocationImpl.UNKNOWN;
+ }
+ }
+ } catch(Exception e) {
+ // Ignore: handled below
+ }
+
+ return LocationImpl.UNKNOWN;
+ }
+
+ /**
+ * Checks if a location is known, i.e. it is not null nor equal to {@link Location#UNKNOWN}.
+ *
+ * @param location the location to check
+ * @return <code>true</code> if the location is known
+ */
+ public static boolean isKnown(Location location) {
+ return location != null && !Location.UNKNOWN.equals(location);
+ }
+
+ /**
+ * Checks if a location is unknown, i.e. it is either null or equal to {@link Location#UNKNOWN}.
+ *
+ * @param location the location to check
+ * @return <code>true</code> if the location is unknown
+ */
+ public static boolean isUnknown(Location location) {
+ return location == null || Location.UNKNOWN.equals(location);
+ }
+
+ /**
+ * Add a {@link LocationFinder} to the list of finders that will be queried for an object's
+ * location by {@link #getLocation(Object, String)}.
+ * <p>
+ * <b>Important:</b> LocationUtils internally stores a weak reference to the finder. This
+ * avoids creating strong links between the classloader holding this class and the finder's
+ * classloader, which can cause some weird memory leaks if the finder's classloader is to
+ * be reloaded. Therefore, you <em>have</em> to keep a strong reference to the finder in the
+ * calling code, e.g.:
+ * <pre>
+ * private static LocationUtils.LocationFinder myFinder =
+ * new LocationUtils.LocationFinder() {
+ * public Location getLocation(Object obj, String desc) {
+ * ...
+ * }
+ * };
+ *
+ * static {
+ * LocationUtils.addFinder(myFinder);
+ * }
+ * </pre>
+ *
+ * @param finder the location finder to add
+ */
+ public static void addFinder(LocationFinder finder) {
+ if (finder == null) {
+ return;
+ }
+
+ synchronized(LocationFinder.class) {
+ // Update a clone of the current finder list to avoid breaking
+ // any iteration occuring in another thread.
+ List<WeakReference<LocationFinder>> newFinders = new ArrayList<>(finders);
+ newFinders.add(new WeakReference<LocationFinder>(finder));
+ finders = newFinders;
+ }
+ }
+
+ /**
+ * Get the location of an object. Some well-known located classes built in the JDK are handled
+ * by this method. Handling of other located classes can be handled by adding new location finders.
+ *
+ * @param obj the object of which to get the location
+ * @return the object's location, or {@link Location#UNKNOWN} if no location could be found
+ */
+ public static Location getLocation(Object obj) {
+ return getLocation(obj, null);
+ }
+
+ /**
+ * Get the location of an object. Some well-known located classes built in the JDK are handled
+ * by this method. Handling of other located classes can be handled by adding new location finders.
+ *
+ * @param obj the object of which to get the location
+ * @param description an optional description of the object's location, used if a Location object
+ * has to be created.
+ * @return the object's location, or {@link Location#UNKNOWN} if no location could be found
+ */
+ public static Location getLocation(Object obj, String description) {
+ if (obj instanceof Location) {
+ return (Location) obj;
+ }
+
+ if (obj instanceof Locatable) {
+ return ((Locatable)obj).getLocation();
+ }
+
+ // Check some well-known locatable exceptions
+ if (obj instanceof SAXParseException) {
+ SAXParseException spe = (SAXParseException)obj;
+ if (spe.getSystemId() != null) {
+ return new LocationImpl(description, spe.getSystemId(), spe.getLineNumber(), spe.getColumnNumber());
+ } else {
+ return Location.UNKNOWN;
+ }
+ }
+
+ if (obj instanceof TransformerException) {
+ TransformerException ex = (TransformerException)obj;
+ SourceLocator locator = ex.getLocator();
+ if (locator != null && locator.getSystemId() != null) {
+ return new LocationImpl(description, locator.getSystemId(), locator.getLineNumber(), locator.getColumnNumber());
+ } else {
+ return Location.UNKNOWN;
+ }
+ }
+
+ if (obj instanceof Locator) {
+ Locator locator = (Locator)obj;
+ if (locator.getSystemId() != null) {
+ return new LocationImpl(description, locator.getSystemId(), locator.getLineNumber(), locator.getColumnNumber());
+ } else {
+ return Location.UNKNOWN;
+ }
+ }
+
+ if (obj instanceof Element) {
+ return LocationAttributes.getLocation((Element)obj);
+ }
+
+ List<WeakReference<LocationFinder>> currentFinders = finders; // Keep the current list
+ int size = currentFinders.size();
+ for (int i = 0; i < size; i++) {
+ WeakReference<LocationFinder> ref = currentFinders.get(i);
+ LocationFinder finder = ref.get();
+ if (finder == null) {
+ // This finder was garbage collected: update finders
+ synchronized(LocationFinder.class) {
+ // Update a clone of the current list to avoid breaking current iterations
+ List<WeakReference<LocationFinder>> newFinders = new ArrayList<>(finders);
+ newFinders.remove(ref);
+ finders = newFinders;
+ }
+ } else {
+ Location result = finder.getLocation(obj, description);
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+
+ if (obj instanceof Throwable) {
+ Throwable t = (Throwable) obj;
+ StackTraceElement[] stack = t.getStackTrace();
+ if (stack != null && stack.length > 0) {
+ StackTraceElement trace = stack[0];
+ if (trace.getLineNumber() >= 0) {
+ String uri = trace.getClassName();
+ if (trace.getFileName() != null) {
+ uri = uri.replace('.','/');
+ uri = uri.substring(0, uri.lastIndexOf('/') + 1);
+ uri = uri + trace.getFileName();
+ URL url = ClassLoaderUtil.getResource(uri, LocationUtils.class);
+ if (url != null) {
+ uri = url.toString();
+ }
+ }
+ if (description == null) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("Class: ").append(trace.getClassName()).append("\n");
+ sb.append("File: ").append(trace.getFileName()).append("\n");
+ sb.append("Method: ").append(trace.getMethodName()).append("\n");
+ sb.append("Line: ").append(trace.getLineNumber());
+ description = sb.toString();
+ }
+ return new LocationImpl(description, uri, trace.getLineNumber(), -1);
+ }
+ }
+ }
+
+ return Location.UNKNOWN;
+ }
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/location/package.html
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/location/package.html b/core/src/main/java/com/opensymphony/xwork2/util/location/package.html
new file mode 100644
index 0000000..840814b
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/location/package.html
@@ -0,0 +1,3 @@
+<html>
+ <body>Classes and utilities used to track location information.</body>
+</html>
\ No newline at end of file
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/Logger.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/Logger.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/Logger.java
new file mode 100644
index 0000000..e7da798
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/Logger.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging;
+
+/**
+ * Main logger interface for logging things
+ */
+@Deprecated
+public interface Logger {
+
+ void trace(String msg, String... args);
+
+ void trace(String msg, Object... args);
+
+ void trace(String msg, Throwable ex, String... args);
+
+ boolean isTraceEnabled();
+
+ void debug(String msg, String... args);
+
+ void debug(String msg, Object... args);
+
+ void debug(String msg, Throwable ex, String... args);
+
+ boolean isDebugEnabled();
+
+ void info(String msg, String... args);
+
+ void info(String msg, Throwable ex, String... args);
+
+ boolean isInfoEnabled();
+
+ void warn(String msg, String... args);
+
+ void warn(String msg, Object... args);
+
+ void warn(String msg, Throwable ex, String... args);
+
+ boolean isWarnEnabled();
+
+ void error(String msg, String... args);
+
+ void error(String msg, Object... args);
+
+ void error(String msg, Throwable ex, String... args);
+
+ boolean isErrorEnabled();
+
+ void fatal(String msg, String... args);
+
+ void fatal(String msg, Throwable ex, String... args);
+
+ boolean isFatalEnabled();
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/LoggerFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/LoggerFactory.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/LoggerFactory.java
new file mode 100644
index 0000000..29b70df
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/LoggerFactory.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging;
+
+import com.opensymphony.xwork2.XWorkConstants;
+import com.opensymphony.xwork2.XWorkException;
+import com.opensymphony.xwork2.util.logging.commons.CommonsLoggerFactory;
+import com.opensymphony.xwork2.util.logging.jdk.JdkLoggerFactory;
+import com.opensymphony.xwork2.util.logging.log4j2.Log4j2LoggerFactory;
+import com.opensymphony.xwork2.util.logging.slf4j.Slf4jLoggerFactory;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.concurrent.locks.ReadWriteLock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+
+/**
+ * Creates loggers. Static accessor will lazily try to decide on the best factory if none specified.
+ */
+@Deprecated
+public abstract class LoggerFactory {
+
+ private static final ReadWriteLock lock = new ReentrantReadWriteLock();
+ private static LoggerFactory factory;
+
+ private static final List<LoggerClass> loggers = new LinkedList<LoggerClass>(){
+ {
+ add(new LoggerClass<CommonsLoggerFactory>("org.apache.commons.logging.LogFactory", CommonsLoggerFactory.class));
+ add(new LoggerClass<Slf4jLoggerFactory>("org.slf4j.LoggerFactory", Slf4jLoggerFactory.class));
+ add(new LoggerClass<Log4j2LoggerFactory>("org.apache.logging.log4j.LogManager", Log4j2LoggerFactory.class));
+ }
+ };
+
+ public static void setLoggerFactory(LoggerFactory factory) {
+ lock.writeLock().lock();
+ try {
+ LoggerFactory.factory = factory;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ public static Logger getLogger(Class<?> cls) {
+ return getLoggerFactory().getLoggerImpl(cls);
+ }
+
+ public static Logger getLogger(String name) {
+ return getLoggerFactory().getLoggerImpl(name);
+ }
+
+ protected static LoggerFactory getLoggerFactory() {
+ lock.readLock().lock();
+ try {
+ if (factory != null) {
+ return factory;
+ }
+ } finally {
+ lock.readLock().unlock();
+ }
+ lock.writeLock().lock();
+ try {
+ if (factory == null) {
+ createLoggerFactory();
+ }
+ return factory;
+ } finally {
+ lock.writeLock().unlock();
+ }
+ }
+
+ private static void createLoggerFactory() {
+ String userLoggerFactory = System.getProperty(XWorkConstants.XWORK_LOGGER_FACTORY);
+ if (userLoggerFactory != null) {
+ try {
+ Class clazz = Class.forName(userLoggerFactory);
+ factory = (LoggerFactory) clazz.newInstance();
+ } catch (Exception e) {
+ throw new XWorkException("System property [" + XWorkConstants.XWORK_LOGGER_FACTORY +
+ "] was defined as [" + userLoggerFactory + "] but there is a problem to use that LoggerFactory!", e);
+ }
+ } else {
+ factory = new JdkLoggerFactory();
+ for (LoggerClass logger : loggers) {
+ if (logger.isSupported()) {
+ factory = logger.createInstance();
+ break;
+ }
+ }
+ }
+ }
+
+ protected abstract Logger getLoggerImpl(Class<?> cls);
+
+ protected abstract Logger getLoggerImpl(String name);
+
+ private static class LoggerClass<T extends LoggerFactory> {
+
+ private final String loggerClazzName;
+ private final Class<T> loggerImplClazz;
+
+ public LoggerClass(String loggerClazzName, Class<T> loggerImplClazz) {
+ this.loggerClazzName = loggerClazzName;
+ this.loggerImplClazz = loggerImplClazz;
+ }
+
+ public boolean isSupported() {
+ try {
+ Class.forName(loggerClazzName);
+ return true;
+ } catch (ClassNotFoundException ignore) {
+ return false;
+ }
+ }
+
+ public LoggerFactory createInstance() {
+ try {
+ return loggerImplClazz.newInstance();
+ } catch (Exception e) {
+ throw new XWorkException(e);
+ }
+ }
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/LoggerUtils.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/LoggerUtils.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/LoggerUtils.java
new file mode 100644
index 0000000..a513ed2
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/LoggerUtils.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging;
+
+import java.util.LinkedList;
+import java.util.List;
+
+/**
+ * Logging utility methods
+ */
+@Deprecated
+public class LoggerUtils {
+
+ /**
+ * Formats messages using parameters. For example, the call:
+ *
+ * <pre>
+ * format("foo #0 #1", "bob", "joe");
+ * </pre>
+ *
+ * will return:
+ * <pre>
+ * foo bob joe
+ * </pre>
+ *
+ * @param msg The message
+ * @param args A list of arguments. A maximum of 10 are supported.
+ * @return The formatted string
+ */
+ public static String format(String msg, String... args) {
+ if (msg != null && msg.length() > 0 && msg.indexOf('#') > -1) {
+ StringBuilder sb = new StringBuilder();
+ boolean isArg = false;
+ for (int x = 0; x < msg.length(); x++) {
+ char c = msg.charAt(x);
+ if (isArg) {
+ isArg = false;
+ if (Character.isDigit(c)) {
+ int val = Character.getNumericValue(c);
+ if (val >= 0 && val < args.length) {
+ sb.append(args[val]);
+ continue;
+ }
+ }
+ sb.append('#');
+ }
+ if (c == '#') {
+ isArg = true;
+ continue;
+ }
+ sb.append(c);
+ }
+
+ if (isArg) {
+ sb.append('#');
+ }
+ return sb.toString();
+ }
+ return msg;
+
+ }
+
+ public static String format(String msg, Object[] args) {
+ List<String> strArgs = new LinkedList<String>();
+ for (Object arg : args) {
+ strArgs.add(arg != null ? arg.toString() : "(null)");
+ }
+ return format(msg, strArgs.toArray(new String[strArgs.size()]));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/commons/CommonsLogger.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/commons/CommonsLogger.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/commons/CommonsLogger.java
new file mode 100644
index 0000000..6ee4e0f
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/commons/CommonsLogger.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging.commons;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerUtils;
+import org.apache.commons.logging.Log;
+
+/**
+ * Simple logger that delegates to commons logging
+ */
+@Deprecated
+public class CommonsLogger implements Logger {
+
+ private Log log;
+
+ public CommonsLogger(Log log) {
+ this.log = log;
+ }
+
+ public void error(String msg, String... args) {
+ log.error(LoggerUtils.format(msg, args));
+ }
+
+ public void error(String msg, Object... args) {
+ log.error(LoggerUtils.format(msg, args));
+ }
+
+ public void error(String msg, Throwable ex, String... args) {
+ log.error(LoggerUtils.format(msg, args), ex);
+ }
+
+ public void info(String msg, String... args) {
+ log.info(LoggerUtils.format(msg, args));
+ }
+
+ public void info(String msg, Throwable ex, String... args) {
+ log.info(LoggerUtils.format(msg, args), ex);
+ }
+
+
+
+ public boolean isInfoEnabled() {
+ return log.isInfoEnabled();
+ }
+
+ public void warn(String msg, String... args) {
+ log.warn(LoggerUtils.format(msg, args));
+ }
+
+ public void warn(String msg, Object... args) {
+ log.warn(LoggerUtils.format(msg, args));
+ }
+
+ public void warn(String msg, Throwable ex, String... args) {
+ log.warn(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isDebugEnabled() {
+ return log.isDebugEnabled();
+ }
+
+ public void debug(String msg, String... args) {
+ log.debug(LoggerUtils.format(msg, args));
+ }
+
+ public void debug(String msg, Object... args) {
+ log.debug(LoggerUtils.format(msg, args));
+ }
+
+ public void debug(String msg, Throwable ex, String... args) {
+ log.debug(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isTraceEnabled() {
+ return log.isTraceEnabled();
+ }
+
+ public void trace(String msg, String... args) {
+ log.trace(LoggerUtils.format(msg, args));
+ }
+
+ public void trace(String msg, Object... args) {
+ log.trace(LoggerUtils.format(msg, args));
+ }
+
+ public void trace(String msg, Throwable ex, String... args) {
+ log.trace(LoggerUtils.format(msg, args), ex);
+ }
+
+
+ public void fatal(String msg, String... args) {
+ log.fatal(LoggerUtils.format(msg, args));
+ }
+
+ public void fatal(String msg, Throwable ex, String... args) {
+ log.fatal(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isErrorEnabled() {
+ return log.isErrorEnabled();
+ }
+
+ public boolean isFatalEnabled() {
+ return log.isFatalEnabled();
+ }
+
+ public boolean isWarnEnabled() {
+ return log.isWarnEnabled();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/commons/CommonsLoggerFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/commons/CommonsLoggerFactory.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/commons/CommonsLoggerFactory.java
new file mode 100644
index 0000000..0e02293
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/commons/CommonsLoggerFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging.commons;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * Creates commons-logging-backed loggers
+ */
+@Deprecated
+public class CommonsLoggerFactory extends LoggerFactory {
+
+ @Override
+ protected Logger getLoggerImpl(Class<?> cls) {
+ return new CommonsLogger(LogFactory.getLog(cls));
+ }
+
+ @Override
+ protected Logger getLoggerImpl(String name) {
+ return new CommonsLogger(LogFactory.getLog(name));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/jdk/JdkLogger.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/jdk/JdkLogger.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/jdk/JdkLogger.java
new file mode 100644
index 0000000..1a11346
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/jdk/JdkLogger.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging.jdk;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerUtils;
+
+import java.util.logging.Level;
+
+/**
+ * Delegates to jdk logger. Maps fatal to Level.SEVERE along with error.
+ */
+@Deprecated
+public class JdkLogger implements Logger {
+
+ private java.util.logging.Logger log;
+
+ public JdkLogger(java.util.logging.Logger log) {
+ this.log = log;
+ }
+
+ public void error(String msg, String... args) {
+ log.log(Level.SEVERE, LoggerUtils.format(msg, args));
+ }
+
+ public void error(String msg, Object... args) {
+ log.log(Level.SEVERE, LoggerUtils.format(msg, args));
+ }
+
+ public void error(String msg, Throwable ex, String... args) {
+ log.log(Level.SEVERE, LoggerUtils.format(msg, args), ex);
+ }
+
+ public void fatal(String msg, String... args) {
+ log.log(Level.SEVERE, LoggerUtils.format(msg, args));
+ }
+
+ public void fatal(String msg, Throwable ex, String... args) {
+ log.log(Level.SEVERE, LoggerUtils.format(msg, args), ex);
+ }
+
+ public void info(String msg, String... args) {
+ log.log(Level.INFO, LoggerUtils.format(msg, args));
+ }
+
+ public void info(String msg, Throwable ex, String... args) {
+ log.log(Level.INFO, LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isInfoEnabled() {
+ return log.isLoggable(Level.INFO);
+ }
+
+ public void warn(String msg, String... args) {
+ log.log(Level.WARNING, LoggerUtils.format(msg, args));
+ }
+
+ public void warn(String msg, Object... args) {
+ log.log(Level.WARNING, LoggerUtils.format(msg, args));
+ }
+
+ public void warn(String msg, Throwable ex, String... args) {
+ log.log(Level.WARNING, LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isDebugEnabled() {
+ return log.isLoggable(Level.FINE);
+ }
+
+ public void debug(String msg, String... args) {
+ log.log(Level.FINE, LoggerUtils.format(msg, args));
+ }
+
+ public void debug(String msg, Object... args) {
+ log.log(Level.FINE, LoggerUtils.format(msg, args));
+ }
+
+ public void debug(String msg, Throwable ex, String... args) {
+ log.log(Level.FINE, LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isTraceEnabled() {
+ return log.isLoggable(Level.FINEST);
+ }
+
+ public void trace(String msg, String... args) {
+ log.log(Level.FINEST, LoggerUtils.format(msg, args));
+ }
+
+ public void trace(String msg, Object... args) {
+ log.log(Level.FINEST, LoggerUtils.format(msg, args));
+ }
+
+ public void trace(String msg, Throwable ex, String... args) {
+ log.log(Level.FINEST, LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isErrorEnabled() {
+ return log.isLoggable(Level.SEVERE);
+ }
+
+ public boolean isFatalEnabled() {
+ return log.isLoggable(Level.SEVERE);
+ }
+
+ public boolean isWarnEnabled() {
+ return log.isLoggable(Level.WARNING);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/jdk/JdkLoggerFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/jdk/JdkLoggerFactory.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/jdk/JdkLoggerFactory.java
new file mode 100644
index 0000000..dbf719c
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/jdk/JdkLoggerFactory.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging.jdk;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+/**
+ * Creates jdk loggers
+ */
+@Deprecated
+public class JdkLoggerFactory extends LoggerFactory {
+
+ @Override
+ protected Logger getLoggerImpl(Class<?> cls) {
+ return new JdkLogger(java.util.logging.Logger.getLogger(cls.getName()));
+ }
+
+ @Override
+ protected Logger getLoggerImpl(String name) {
+ return new JdkLogger(java.util.logging.Logger.getLogger(name));
+ }
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/log4j2/Log4j2Logger.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/log4j2/Log4j2Logger.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/log4j2/Log4j2Logger.java
new file mode 100644
index 0000000..228a860
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/log4j2/Log4j2Logger.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging.log4j2;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerUtils;
+
+/**
+ * Simple logger that delegates to log4j2 logging
+ */
+@Deprecated
+public class Log4j2Logger implements Logger {
+
+ private org.apache.logging.log4j.Logger log;
+
+ public Log4j2Logger(org.apache.logging.log4j.Logger log) {
+ this.log = log;
+ }
+
+ public void error(String msg, String... args) {
+ log.error(LoggerUtils.format(msg, args));
+ }
+
+ public void error(String msg, Object... args) {
+ log.error(LoggerUtils.format(msg, args));
+ }
+
+ public void error(String msg, Throwable ex, String... args) {
+ log.error(LoggerUtils.format(msg, args), ex);
+ }
+
+ public void info(String msg, String... args) {
+ log.info(LoggerUtils.format(msg, args));
+ }
+
+ public void info(String msg, Throwable ex, String... args) {
+ log.info(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isInfoEnabled() {
+ return log.isInfoEnabled();
+ }
+
+ public void warn(String msg, String... args) {
+ log.warn(LoggerUtils.format(msg, args));
+ }
+
+ public void warn(String msg, Object... args) {
+ log.warn(LoggerUtils.format(msg, args));
+ }
+
+ public void warn(String msg, Throwable ex, String... args) {
+ log.warn(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isDebugEnabled() {
+ return log.isDebugEnabled();
+ }
+
+ public void debug(String msg, String... args) {
+ log.debug(LoggerUtils.format(msg, args));
+ }
+
+ public void debug(String msg, Object... args) {
+ log.debug(LoggerUtils.format(msg, args));
+ }
+
+ public void debug(String msg, Throwable ex, String... args) {
+ log.debug(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isTraceEnabled() {
+ return log.isTraceEnabled();
+ }
+
+ public void trace(String msg, String... args) {
+ log.trace(LoggerUtils.format(msg, args));
+ }
+
+ public void trace(String msg, Object... args) {
+ log.trace(LoggerUtils.format(msg, args));
+ }
+
+ public void trace(String msg, Throwable ex, String... args) {
+ log.trace(LoggerUtils.format(msg, args), ex);
+ }
+
+
+ public void fatal(String msg, String... args) {
+ log.fatal(LoggerUtils.format(msg, args));
+ }
+
+ public void fatal(String msg, Throwable ex, String... args) {
+ log.fatal(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isErrorEnabled() {
+ return log.isErrorEnabled();
+ }
+
+ public boolean isFatalEnabled() {
+ return log.isFatalEnabled();
+ }
+
+ public boolean isWarnEnabled() {
+ return log.isWarnEnabled();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/log4j2/Log4j2LoggerFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/log4j2/Log4j2LoggerFactory.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/log4j2/Log4j2LoggerFactory.java
new file mode 100644
index 0000000..dd2799d
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/log4j2/Log4j2LoggerFactory.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging.log4j2;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+/**
+ * Creates log4j2-logging-backed loggers
+ *
+ * You can use the same to explicit tell the framework which implementation to use and don't depend on class discovery:
+ * <pre>
+ * -Dxwork.loggerFactory=com.opensymphony.xwork2.util.logging.log4j2.Log4j2LoggerFactory
+ * </pre>
+ */
+@Deprecated
+public class Log4j2LoggerFactory extends LoggerFactory {
+
+ @Override
+ protected Logger getLoggerImpl(Class<?> cls) {
+ return new Log4j2Logger(org.apache.logging.log4j.LogManager.getLogger(cls));
+ }
+
+ @Override
+ protected Logger getLoggerImpl(String name) {
+ return new Log4j2Logger(org.apache.logging.log4j.LogManager.getLogger(name));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/slf4j/Slf4jLogger.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/slf4j/Slf4jLogger.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/slf4j/Slf4jLogger.java
new file mode 100644
index 0000000..a303032
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/slf4j/Slf4jLogger.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging.slf4j;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerUtils;
+
+/**
+ * Simple logger that delegates to slf4j logging
+ */
+@Deprecated
+public class Slf4jLogger implements Logger {
+
+ private org.slf4j.Logger log;
+
+ public Slf4jLogger(org.slf4j.Logger log) {
+ this.log = log;
+ }
+
+ public void error(String msg, String... args) {
+ log.error(LoggerUtils.format(msg, args));
+ }
+
+ public void error(String msg, Object... args) {
+ log.error(LoggerUtils.format(msg, args));
+ }
+
+ public void error(String msg, Throwable ex, String... args) {
+ log.error(LoggerUtils.format(msg, args), ex);
+ }
+
+ public void info(String msg, String... args) {
+ log.info(LoggerUtils.format(msg, args));
+ }
+
+ public void info(String msg, Throwable ex, String... args) {
+ log.info(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isInfoEnabled() {
+ return log.isInfoEnabled();
+ }
+
+ public void warn(String msg, String... args) {
+ log.warn(LoggerUtils.format(msg, args));
+ }
+
+ public void warn(String msg, Object... args) {
+ log.warn(LoggerUtils.format(msg, args));
+ }
+
+ public void warn(String msg, Throwable ex, String... args) {
+ log.warn(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isDebugEnabled() {
+ return log.isDebugEnabled();
+ }
+
+ public void debug(String msg, String... args) {
+ log.debug(LoggerUtils.format(msg, args));
+ }
+
+ public void debug(String msg, Object... args) {
+ log.debug(LoggerUtils.format(msg, args));
+ }
+
+ public void debug(String msg, Throwable ex, String... args) {
+ log.debug(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isTraceEnabled() {
+ return log.isTraceEnabled();
+ }
+
+ public void trace(String msg, String... args) {
+ log.trace(LoggerUtils.format(msg, args));
+ }
+
+ public void trace(String msg, Object... args) {
+ log.trace(LoggerUtils.format(msg, args));
+ }
+
+ public void trace(String msg, Throwable ex, String... args) {
+ log.trace(LoggerUtils.format(msg, args), ex);
+ }
+
+
+ public void fatal(String msg, String... args) {
+ log.error(LoggerUtils.format(msg, args));
+ }
+
+ public void fatal(String msg, Throwable ex, String... args) {
+ log.error(LoggerUtils.format(msg, args), ex);
+ }
+
+ public boolean isErrorEnabled() {
+ return log.isErrorEnabled();
+ }
+
+ /** Fatal is not support by Slf4j */
+ public boolean isFatalEnabled() {
+ return log.isErrorEnabled();
+ }
+
+ public boolean isWarnEnabled() {
+ return log.isWarnEnabled();
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/logging/slf4j/Slf4jLoggerFactory.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/logging/slf4j/Slf4jLoggerFactory.java b/core/src/main/java/com/opensymphony/xwork2/util/logging/slf4j/Slf4jLoggerFactory.java
new file mode 100644
index 0000000..6e3e6d5
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/logging/slf4j/Slf4jLoggerFactory.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002-2006,2009 The Apache Software Foundation.
+ *
+ * Licensed 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 com.opensymphony.xwork2.util.logging.slf4j;
+
+import com.opensymphony.xwork2.util.logging.Logger;
+import com.opensymphony.xwork2.util.logging.LoggerFactory;
+
+/**
+ * Creates slf4j-logging-backed loggers
+ *
+ * You can use the same to explicit tell the framework which implementation to use and don't depend on class discovery:
+ * <pre>
+ * -Dxwork.loggerFactory=com.opensymphony.xwork2.util.logging.slf4j.Slf4jLoggerFactory
+ * </pre>
+ */
+@Deprecated
+public class Slf4jLoggerFactory extends LoggerFactory {
+
+ @Override
+ protected Logger getLoggerImpl(Class<?> cls) {
+ return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(cls));
+ }
+
+ @Override
+ protected Logger getLoggerImpl(String name) {
+ return new Slf4jLogger(org.slf4j.LoggerFactory.getLogger(name));
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/package.html
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/package.html b/core/src/main/java/com/opensymphony/xwork2/util/package.html
new file mode 100644
index 0000000..e400bf9
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/package.html
@@ -0,0 +1 @@
+<body>XWork util classes.</body>
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/profiling/ObjectProfiler.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/profiling/ObjectProfiler.java b/core/src/main/java/com/opensymphony/xwork2/util/profiling/ObjectProfiler.java
new file mode 100644
index 0000000..7438113
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/profiling/ObjectProfiler.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2002-2003, Atlassian Software Systems Pty Ltd All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Atlassian Software Systems Pty Ltd nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.opensymphony.xwork2.util.profiling;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
+/**
+ * @author <a href="mailto:scott@atlassian.com">Scott Farquhar</a>
+ */
+public class ObjectProfiler {
+
+ /**
+ * Given a class, and an interface that it implements, return a proxied version of the class that implements
+ * the interface.
+ * <p/>
+ * The usual use of this is to profile methods from Factory objects:
+ * <pre>
+ * public PersistenceManager getPersistenceManager()
+ * {
+ * return new DefaultPersistenceManager();
+ * }
+ *
+ * instead write:
+ * public PersistenceManager getPersistenceManager()
+ * {
+ * return ObjectProfiler.getProfiledObject(PersistenceManager.class, new DefaultPersistenceManager());
+ * }
+ * </pre>
+ * <p/>
+ * A side effect of this is that you will no longer be able to downcast to DefaultPersistenceManager. This is probably a *good* thing.
+ *
+ * @param interfaceClazz The interface to implement.
+ * @param o The object to proxy
+ * @return A proxied object, or the input object if the interfaceClazz wasn't an interface.
+ */
+ public static Object getProfiledObject(Class interfaceClazz, Object o) {
+ //if we are not active - then do nothing
+ if (!UtilTimerStack.isActive()) {
+ return o;
+ }
+
+ //this should always be true - you shouldn't be passing something that isn't an interface
+ if (interfaceClazz.isInterface()) {
+ InvocationHandler timerHandler = new TimerInvocationHandler(o);
+ return Proxy.newProxyInstance(interfaceClazz.getClassLoader(),
+ new Class[]{interfaceClazz}, timerHandler);
+ } else {
+ return o;
+ }
+ }
+
+ /**
+ * A profiled call {@link Method#invoke(java.lang.Object, java.lang.Object[])}. If {@link UtilTimerStack#isActive() }
+ * returns false, then no profiling is performed.
+ */
+ public static Object profiledInvoke(Method target, Object value, Object[] args) throws IllegalAccessException, InvocationTargetException {
+ //if we are not active - then do nothing
+ if (!UtilTimerStack.isActive()) {
+ return target.invoke(value, args);
+ }
+
+ String logLine = new String(getTrimmedClassName(target) + "." + target.getName() + "()");
+
+ UtilTimerStack.push(logLine);
+ try {
+ Object returnValue = target.invoke(value, args);
+
+ //if the return value is an interface then we should also proxy it!
+ if (returnValue != null && target.getReturnType().isInterface()) {
+ InvocationHandler timerHandler = new TimerInvocationHandler(returnValue);
+ return Proxy.newProxyInstance(returnValue.getClass().getClassLoader(),
+ new Class[]{target.getReturnType()}, timerHandler);
+ } else {
+ return returnValue;
+ }
+ } finally {
+ UtilTimerStack.pop(logLine);
+ }
+ }
+
+ /**
+ * Given a method, get the Method name, with no package information.
+ */
+ public static String getTrimmedClassName(Method method) {
+ String classname = method.getDeclaringClass().getName();
+ return classname.substring(classname.lastIndexOf('.') + 1);
+ }
+
+}
+
+class TimerInvocationHandler implements InvocationHandler {
+ protected Object target;
+
+ public TimerInvocationHandler(Object target) {
+ if (target == null) {
+ throw new IllegalArgumentException("Target Object passed to timer cannot be null");
+ }
+ this.target = target;
+ }
+
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+ return ObjectProfiler.profiledInvoke(method, target, args);
+ }
+
+}
http://git-wip-us.apache.org/repos/asf/struts/blob/31af5842/core/src/main/java/com/opensymphony/xwork2/util/profiling/ProfilingTimerBean.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/com/opensymphony/xwork2/util/profiling/ProfilingTimerBean.java b/core/src/main/java/com/opensymphony/xwork2/util/profiling/ProfilingTimerBean.java
new file mode 100644
index 0000000..a475c62
--- /dev/null
+++ b/core/src/main/java/com/opensymphony/xwork2/util/profiling/ProfilingTimerBean.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2002-2003, Atlassian Software Systems Pty Ltd All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation and/or
+ * other materials provided with the distribution.
+ * * Neither the name of Atlassian Software Systems Pty Ltd nor the names of
+ * its contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.opensymphony.xwork2.util.profiling;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Bean to contain information about the pages profiled
+ *
+ * @author <a href="mailto:mike@atlassian.com">Mike Cannon-Brookes</a>
+ * @author <a href="mailto:scott@atlassian.com">Scott Farquhar</a>
+ * @version $Date$ $Id$
+ */
+public class ProfilingTimerBean implements java.io.Serializable {
+
+ private static final long serialVersionUID = -6180672043920208784L;
+
+ List<ProfilingTimerBean> children = new ArrayList<>();
+ ProfilingTimerBean parent = null;
+
+ String resource;
+
+ long startTime;
+ long totalTime;
+
+ public ProfilingTimerBean(String resource) {
+ this.resource = resource;
+ }
+
+ protected void addParent(ProfilingTimerBean parent) {
+ this.parent = parent;
+ }
+
+ public ProfilingTimerBean getParent() {
+ return parent;
+ }
+
+
+ public void addChild(ProfilingTimerBean child) {
+ children.add(child);
+ child.addParent(this);
+ }
+
+
+ public void setStartTime() {
+ this.startTime = System.currentTimeMillis();
+ }
+
+ public void setEndTime() {
+ this.totalTime = System.currentTimeMillis() - startTime;
+ }
+
+ public String getResource() {
+ return resource;
+ }
+
+ /**
+ * Get a formatted string representing all the methods that took longer than a specified time.
+ */
+
+ public String getPrintable(long minTime) {
+ return getPrintable("", minTime);
+ }
+
+ protected String getPrintable(String indent, long minTime) {
+ //only print the value if we are larger or equal to the min time.
+ if (totalTime >= minTime) {
+ StringBuilder buffer = new StringBuilder();
+ buffer.append(indent);
+ buffer.append("[" + totalTime + "ms] - " + resource);
+ buffer.append("\n");
+
+ for (ProfilingTimerBean aChildren : children) {
+ buffer.append((aChildren).getPrintable(indent + " ", minTime));
+ }
+
+ return buffer.toString();
+ } else
+ return "";
+ }
+}
+