001 package org.javasimon.javaee;
002
003 import java.lang.reflect.InvocationTargetException;
004 import javax.servlet.FilterConfig;
005 import javax.servlet.http.HttpServletRequest;
006
007 import org.javasimon.Manager;
008 import org.javasimon.Stopwatch;
009 import org.javasimon.javaee.reqreporter.DefaultRequestReporter;
010 import org.javasimon.javaee.reqreporter.RequestReporter;
011 import org.javasimon.source.MonitorSource;
012 import org.javasimon.source.StopwatchSource;
013 import org.javasimon.utils.Replacer;
014 import org.javasimon.utils.SimonUtils;
015
016 /**
017 * Various supporting utility methods for {@link SimonServletFilter}.
018 *
019 * @author virgo47@gmail.com
020 */
021 public class SimonServletFilterUtils {
022 /**
023 * Regex replacer for any number of slashes or dots for a single dot.
024 */
025 private static final Replacer TO_DOT_PATTERN = new Replacer("[/.]+", ".");
026
027 /**
028 * Creates new replacer for unallowed characters in the URL. This inverts character group for name pattern
029 * ({@link SimonUtils#NAME_PATTERN_CHAR_CLASS_CONTENT}) and replaces its dot with slash too (dots are to be
030 * replaced, slashs preserved in this step of URL processing).
031 *
032 * @param replacement replacement string (for every unallowed character)
033 * @return compiled pattern matching characters to remove from the URL
034 */
035 static Replacer createUnallowedCharsReplacer(String replacement) {
036 return new Replacer("[^" + SimonUtils.NAME_PATTERN_CHAR_CLASS_CONTENT.replace('.', '/') + "]+", replacement);
037 }
038
039 /**
040 * Returns Simon name for the specified request (local name without any configured prefix). By default dots and all non-simon-name
041 * compliant characters are removed first, then all slashes are switched to dots (repeating slashes make one dot).
042 *
043 * @param uri request URI
044 * @param unallowedCharacterReplacer replacer for characters that are not allowed in Simon name
045 * @return local part of the Simon name for the request URI (without prefix)
046 */
047 public static String getSimonName(String uri, Replacer unallowedCharacterReplacer) {
048 if (uri.startsWith("/")) {
049 uri = uri.substring(1);
050 }
051 String name = unallowedCharacterReplacer.process(uri);
052 name = TO_DOT_PATTERN.process(name);
053 return name;
054 }
055
056 /**
057 * Create and initialize the stopwatch source depending on the filter init parameters. Both
058 * monitor source class ({@link SimonServletFilter#INIT_PARAM_STOPWATCH_SOURCE_CLASS} and whether
059 * to cache results ({@link SimonServletFilter#INIT_PARAM_STOPWATCH_SOURCE_CACHE}) can be adjusted.
060 *
061 * @param filterConfig Filter configuration
062 * @return Stopwatch source
063 */
064 protected static StopwatchSource<HttpServletRequest> initStopwatchSource(FilterConfig filterConfig, Manager manager) {
065 String stopwatchSourceClass = filterConfig.getInitParameter(SimonServletFilter.INIT_PARAM_STOPWATCH_SOURCE_CLASS);
066 StopwatchSource<HttpServletRequest> stopwatchSource = createMonitorSource(stopwatchSourceClass, manager);
067
068 injectSimonPrefixIntoMonitorSource(filterConfig, stopwatchSource);
069
070 String cache = filterConfig.getInitParameter(SimonServletFilter.INIT_PARAM_STOPWATCH_SOURCE_CACHE);
071 stopwatchSource = wrapMonitorSourceWithCacheIfNeeded(stopwatchSource, cache);
072
073 return stopwatchSource;
074 }
075
076 private static StopwatchSource<HttpServletRequest> createMonitorSource(String stopwatchSourceClass, Manager manager) {
077 if (stopwatchSourceClass == null) {
078 return new HttpStopwatchSource(manager);
079 } else {
080 return createMonitorForSourceSpecifiedClass(stopwatchSourceClass, manager);
081 }
082 }
083
084 private static void injectSimonPrefixIntoMonitorSource(FilterConfig filterConfig, MonitorSource<HttpServletRequest, Stopwatch> stopwatchSource) {
085 String simonPrefix = filterConfig.getInitParameter(SimonServletFilter.INIT_PARAM_PREFIX);
086 if (simonPrefix != null) {
087 if (stopwatchSource instanceof HttpStopwatchSource) {
088 HttpStopwatchSource httpStopwatchSource = (HttpStopwatchSource) stopwatchSource;
089 httpStopwatchSource.setPrefix(simonPrefix);
090 } else {
091 throw new IllegalArgumentException("Prefix init param is only compatible with HttpStopwatchSource");
092 }
093 }
094 }
095
096 private static StopwatchSource<HttpServletRequest> wrapMonitorSourceWithCacheIfNeeded(StopwatchSource<HttpServletRequest> stopwatchSource, String cache) {
097 if (cache != null && Boolean.parseBoolean(cache)) {
098 stopwatchSource = HttpStopwatchSource.newCacheStopwatchSource(stopwatchSource);
099 }
100 return stopwatchSource;
101 }
102
103 private static StopwatchSource<HttpServletRequest> createMonitorForSourceSpecifiedClass(String stopwatchSourceClass, Manager manager) {
104 try {
105 Class<?> monitorClass = Class.forName(stopwatchSourceClass);
106 return monitorSourceNewInstance(manager, monitorClass);
107 } catch (ClassNotFoundException e) {
108 throw new IllegalArgumentException("Invalid Stopwatch source class name", e);
109 } catch (ClassCastException e) {
110 throw new IllegalArgumentException("Invalid Stopwatch source class name", e);
111 } catch (InstantiationException e) {
112 throw new IllegalArgumentException("Invalid Stopwatch source class name", e);
113 } catch (IllegalAccessException e) {
114 throw new IllegalArgumentException("Invalid Stopwatch source class name", e);
115 }
116 }
117
118 @SuppressWarnings("unchecked")
119 private static StopwatchSource<HttpServletRequest> monitorSourceNewInstance(Manager manager, Class<?> monitorClass) throws InstantiationException, IllegalAccessException {
120 StopwatchSource<HttpServletRequest> stopwatchSource = null;
121 try {
122 stopwatchSource = (StopwatchSource<HttpServletRequest>) monitorClass.getConstructor(Manager.class).newInstance(manager);
123 } catch (NoSuchMethodException e) {
124 // safe to ignore here - we'll try default constructor + setter
125 } catch (InvocationTargetException e) {
126 // safe to ignore here
127 }
128 if (stopwatchSource == null) {
129 stopwatchSource = (StopwatchSource<HttpServletRequest>) monitorClass.newInstance();
130 try {
131 monitorClass.getMethod("setManager", Manager.class).invoke(stopwatchSource, manager);
132 } catch (NoSuchMethodException e) {
133 throw new IllegalArgumentException("Stopwatch source class must have public constructor or public setter with Manager argument (used class " + monitorClass.getName() + ")", e);
134 } catch (InvocationTargetException e) {
135 throw new IllegalArgumentException("Stopwatch source class must have public constructor or public setter with Manager argument (used class " + monitorClass.getName() + ")", e);
136 }
137 }
138 return stopwatchSource;
139 }
140
141 /**
142 * Returns RequestReporter for the class specified for context parameter {@link SimonServletFilter#INIT_PARAM_REQUEST_REPORTER_CLASS}.
143 */
144 public static RequestReporter initRequestReporter(FilterConfig filterConfig) {
145 String className = filterConfig.getInitParameter(SimonServletFilter.INIT_PARAM_REQUEST_REPORTER_CLASS);
146
147 if (className == null) {
148 return new DefaultRequestReporter();
149 } else {
150 try {
151 return (RequestReporter) Class.forName(className).newInstance();
152 } catch (ClassNotFoundException classNotFoundException) {
153 throw new IllegalArgumentException("Invalid Request reporter class name", classNotFoundException);
154 } catch (InstantiationException instantiationException) {
155 throw new IllegalArgumentException("Invalid Request reporter class name", instantiationException);
156 } catch (IllegalAccessException illegalAccessException) {
157 throw new IllegalArgumentException("Invalid Request reporter class name", illegalAccessException);
158 }
159 }
160 }
161 }