Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
O
Openfire
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
Openfire
Commits
e828c22f
Commit
e828c22f
authored
Nov 04, 2016
by
Guus der Kinderen
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
OF-1227: Plugins should be able to have proper servlet filters.
parent
771bbab3
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1533 additions
and
89 deletions
+1533
-89
PluginFilter.java
src/java/org/jivesoftware/admin/PluginFilter.java
+213
-10
PluginClassLoader.java
...rg/jivesoftware/openfire/container/PluginClassLoader.java
+1
-0
PluginServlet.java
...va/org/jivesoftware/openfire/container/PluginServlet.java
+173
-79
PluginServletContext.java
...jivesoftware/openfire/container/PluginServletContext.java
+385
-0
WebXmlUtils.java
src/java/org/jivesoftware/util/WebXmlUtils.java
+302
-0
WebXmlUtilsTest.java
src/test/java/org/jivesoftware/util/WebXmlUtilsTest.java
+293
-0
test-web.xml
src/test/resources/org/jivesoftware/util/test-web.xml
+166
-0
No files found.
src/java/org/jivesoftware/admin/PluginFilter.java
View file @
e828c22f
...
@@ -20,63 +20,213 @@
...
@@ -20,63 +20,213 @@
package
org
.
jivesoftware
.
admin
;
package
org
.
jivesoftware
.
admin
;
import
org.apache.mina.util.CopyOnWriteMap
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
javax.servlet.*
;
import
javax.servlet.*
;
import
javax.servlet.http.HttpServletRequest
;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.util.ArrayList
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.CopyOnWriteArrayList
;
import
java.util.concurrent.CopyOnWriteArrayList
;
/**
/**
* A servlet filter that plugin classes can use to dynamically register and un-register
* A servlet filter that plugin classes can use to dynamically register and un-register filter logic.
* filter logic. The filter logic that each plugin can register is fairly limited;
*
* instead of having full control over the filter chain, each instance of
* The original, now deprecated, filter logic that each plugin can register was fairly limited; instead of having full
* {@link SimpleFilter} only has the ability to use the ServletRequest and ServletResponse
* control over the filter chain, each instance of {@link SimpleFilter} only has the ability to use the ServletRequest
* objects and then return <tt>true</tt> if further filters in the chain should be run.
* and ServletResponse objects and then return <tt>true</tt> if further filters in the chain should be run.
*
* The new, non-deprecated functionality allows for regular {@link Filter} instances to be registered with this class,
* which removes much of the limitations that was present in the SimpleFilter approach.
*
* This implementation assumes, but does not enforce, that filters installed by plugins are applied to URL patterns that
* match the plugin. When filters installed by different plugins are applied to the same URL, the behavior of this
* implementation is undetermined.
*
*
* @author Matt Tucker
* @author Matt Tucker
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
*/
public
class
PluginFilter
implements
Filter
{
public
class
PluginFilter
implements
Filter
{
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
PluginFilter
.
class
);
@Deprecated
private
static
List
<
SimpleFilter
>
pluginFilters
=
new
CopyOnWriteArrayList
<>();
private
static
List
<
SimpleFilter
>
pluginFilters
=
new
CopyOnWriteArrayList
<>();
private
static
Map
<
String
,
List
<
Filter
>>
filters
=
new
CopyOnWriteMap
<>();
/**
/**
* Adds a filter to the list of filters that will be run on every request.
* Adds a filter to the list of filters that will be run on every request.
* This method should be called by plugins when starting up.
* This method should be called by plugins when starting up.
*
*
* @param filter the filter.
* @param filter the filter.
* @deprecated Replaced by {@link #addPluginFilter(String, Filter)}
*/
*/
@Deprecated
public
static
void
addPluginFilter
(
SimpleFilter
filter
)
{
public
static
void
addPluginFilter
(
SimpleFilter
filter
)
{
pluginFilters
.
add
(
filter
);
pluginFilters
.
add
(
filter
);
}
}
/**
* Adds a filter to the list of filters that will be run on every request of which the URL matches the URL that
* is registered with this filter. More specifically, the request URL should be equal to, or start with, the filter
* URL.
*
* Multiple filters can be registered on the same URL, in which case they will be executed in the order in which
* they were added.
*
* Adding a filter does not initialize the plugin instance.
*
* @param filterUrl The URL pattern to which the filter is to be applied. Cannot be null nor an empty string.
* @param filter The filter. Cannot be null.
*/
public
static
void
addPluginFilter
(
String
filterUrl
,
Filter
filter
)
{
if
(
filterUrl
==
null
||
filterUrl
.
isEmpty
()
||
filter
==
null
)
{
throw
new
IllegalArgumentException
();
}
if
(
!
filters
.
containsKey
(
filterUrl
)
)
{
filters
.
put
(
filterUrl
,
new
ArrayList
<
Filter
>()
);
}
final
List
<
Filter
>
urlFilters
=
PluginFilter
.
filters
.
get
(
filterUrl
);
if
(
urlFilters
.
contains
(
filter
)
)
{
Log
.
warn
(
"Cannot add filter '{}' as it was already added for URL '{}'!"
,
filter
,
filterUrl
);
}
else
{
urlFilters
.
add
(
filter
);
Log
.
debug
(
"Added filter '{}' for URL '{}'"
,
filter
,
filterUrl
);
}
}
/**
/**
* Removes a filter from the list of filters that will be run on every request.
* Removes a filter from the list of filters that will be run on every request.
* This method should be called by plugins when shutting down.
* This method should be called by plugins when shutting down.
*
*
* @param filter the filter.
* @param filter the filter.
* @deprecated
*/
*/
@Deprecated
public
static
void
removePluginFilter
(
SimpleFilter
filter
)
{
public
static
void
removePluginFilter
(
SimpleFilter
filter
)
{
pluginFilters
.
remove
(
filter
);
pluginFilters
.
remove
(
filter
);
}
}
/**
* Removes a filter that is applied to a certain URL.
*
* Removing a filter does not destroy the plugin instance.
*
* @param filterUrl The URL pattern to which the filter is applied. Cannot be null nor an empty string.
* @param filterClassName The filter class name. Cannot be null or empty string.
* @return The filter instance that was removed, or null if the URL and name combination did not match a filter.
*/
public
static
Filter
removePluginFilter
(
String
filterUrl
,
String
filterClassName
)
{
if
(
filterUrl
==
null
||
filterUrl
.
isEmpty
()
||
filterClassName
==
null
||
filterClassName
.
isEmpty
()
)
{
throw
new
IllegalArgumentException
();
}
Filter
result
=
null
;
if
(
filters
.
containsKey
(
filterUrl
)
)
{
final
List
<
Filter
>
urlFilters
=
PluginFilter
.
filters
.
get
(
filterUrl
);
final
Iterator
<
Filter
>
iterator
=
urlFilters
.
iterator
();
while
(
iterator
.
hasNext
()
)
{
final
Filter
filter
=
iterator
.
next
();
if
(
filter
.
getClass
().
getName
().
equals
(
filterClassName
)
)
{
iterator
.
remove
();
result
=
filter
;
// assumed to be unique, but check the entire collection to avoid leaks.
}
}
if
(
urlFilters
.
isEmpty
()
)
{
filters
.
remove
(
filterUrl
);
}
}
if
(
result
==
null
)
{
Log
.
warn
(
"Unable to removed filter of class '{}' for URL '{}'. No such filter is present."
,
filterClassName
,
filterUrl
);
}
else
{
Log
.
debug
(
"Removed filter '{}' for URL '{}'"
,
result
,
filterUrl
);
}
return
result
;
}
@Override
@Override
public
void
init
(
FilterConfig
filterConfig
)
throws
ServletException
{
public
void
init
(
FilterConfig
filterConfig
)
throws
ServletException
{
}
}
/**
* This class is a Filter implementation itself. It acts as a dynamic proxy to filters that are registered by
* Openfire plugins.
*/
@Override
@Override
public
void
doFilter
(
ServletRequest
servletRequest
,
ServletResponse
servletResponse
,
public
void
doFilter
(
ServletRequest
servletRequest
,
ServletResponse
servletResponse
,
FilterChain
filterChain
)
throws
IOException
,
ServletException
FilterChain
filterChain
)
throws
IOException
,
ServletException
{
{
boolean
continueChain
=
true
;
boolean
continueChain
=
true
;
// Process each plugin filter.
// Process each of the (deprecated) SimplePlugin filters.
for
(
SimpleFilter
filter
:
pluginFilters
)
{
for
(
SimpleFilter
filter
:
pluginFilters
)
{
Log
.
trace
(
"(deprecated) Executing wrapped simple filter '{}'..."
,
filter
);
if
(!
filter
.
doFilter
(
servletRequest
,
servletResponse
))
{
if
(!
filter
.
doFilter
(
servletRequest
,
servletResponse
))
{
// The filter returned false so no further filters in the
Log
.
debug
(
"The simple filter returned false so no further filters in the chain should be run."
);
// chain should be run.
continueChain
=
false
;
continueChain
=
false
;
break
;
break
;
}
}
}
}
if
(
continueChain
)
{
// Process the 'regular' servlet filters.
if
(
continueChain
)
{
if
(
servletRequest
instanceof
HttpServletRequest
)
{
final
HttpServletRequest
httpServletRequest
=
(
HttpServletRequest
)
servletRequest
;
final
String
requestPath
=
(
httpServletRequest
.
getContextPath
()
+
httpServletRequest
.
getServletPath
()
+
httpServletRequest
.
getPathInfo
()
).
toLowerCase
();
final
List
<
Filter
>
applicableFilters
=
new
ArrayList
<>();
for
(
final
Map
.
Entry
<
String
,
List
<
Filter
>>
entry
:
filters
.
entrySet
()
)
{
String
filterUrl
=
entry
.
getKey
();
if
(
filterUrl
.
endsWith
(
"*"
))
{
filterUrl
=
filterUrl
.
substring
(
0
,
filterUrl
.
length
()
-
1
);
}
filterUrl
=
filterUrl
.
toLowerCase
();
if
(
requestPath
.
startsWith
(
filterUrl
)
)
{
for
(
final
Filter
filter
:
entry
.
getValue
()
)
{
applicableFilters
.
add
(
filter
);
}
}
}
if
(
!
applicableFilters
.
isEmpty
()
)
{
Log
.
debug
(
"Wrapping filter chain in order to run plugin-specific filters."
);
filterChain
=
new
FilterChainInjector
(
filterChain
,
applicableFilters
);
}
}
else
{
Log
.
warn
(
"ServletRequest is not an instance of an HttpServletRequest."
);
}
// Plugin filtering is done. Progress down the filter chain that was initially provided.
filterChain
.
doFilter
(
servletRequest
,
servletResponse
);
filterChain
.
doFilter
(
servletRequest
,
servletResponse
);
}
}
}
}
...
@@ -86,13 +236,17 @@ public class PluginFilter implements Filter {
...
@@ -86,13 +236,17 @@ public class PluginFilter implements Filter {
// If the destroy method is being called, the Openfire instance is being shutdown.
// If the destroy method is being called, the Openfire instance is being shutdown.
// Therefore, clear out the list of plugin filters.
// Therefore, clear out the list of plugin filters.
pluginFilters
.
clear
();
pluginFilters
.
clear
();
filters
.
clear
();
}
}
/**
/**
* A simplified version of a servlet filter. Instead of having full control
* A simplified version of a servlet filter. Instead of having full control
* over the filter chain, a simple filter can only control whether further
* over the filter chain, a simple filter can only control whether further
* filters in the chain are run.
* filters in the chain are run.
*
* @Deprecated Use {@link Filter} instead.
*/
*/
@Deprecated
public
interface
SimpleFilter
{
public
interface
SimpleFilter
{
/**
/**
...
@@ -117,4 +271,53 @@ public class PluginFilter implements Filter {
...
@@ -117,4 +271,53 @@ public class PluginFilter implements Filter {
throws
IOException
,
ServletException
;
throws
IOException
,
ServletException
;
}
}
/**
* A wrapper that can be used to inject a list of filters into an existing a filter chain.
*
* An instance of this class is expected to be created within the execution of a 'parent' filter chain. After
* instantiation, the caller is expected to invoke #doFilter once, after which all provided filters will be
* invoked. Afterwards, the original filter chain (as supplied in the constructor) will be resumed.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
private
static
class
FilterChainInjector
implements
FilterChain
{
private
static
final
Logger
Log
=
LoggerFactory
.
getLogger
(
FilterChainInjector
.
class
);
private
final
FilterChain
parentChain
;
private
final
List
<
Filter
>
filters
;
private
int
index
=
0
;
/**
* Creates a new instance.
*
* @param parentChain the chain to which the filters are to be appended (cannot be null).
* @param filters The filters to append (cannot be null, but can be empty).
*/
private
FilterChainInjector
(
FilterChain
parentChain
,
List
<
Filter
>
filters
)
{
if
(
parentChain
==
null
||
filters
==
null
)
{
throw
new
IllegalArgumentException
();
}
this
.
parentChain
=
parentChain
;
this
.
filters
=
filters
;
}
@Override
public
void
doFilter
(
ServletRequest
servletRequest
,
ServletResponse
servletResponse
)
throws
IOException
,
ServletException
{
if
(
index
<
filters
.
size
()
)
{
Log
.
trace
(
"Executing injected filter {} of {}..."
,
index
+
1
,
filters
.
size
()
);
filters
.
get
(
index
++
).
doFilter
(
servletRequest
,
servletResponse
,
this
);
}
else
{
Log
.
trace
(
"Executed all injected filters. Resuming original chain."
);
parentChain
.
doFilter
(
servletRequest
,
servletResponse
);
}
}
}
}
}
\ No newline at end of file
src/java/org/jivesoftware/openfire/container/PluginClassLoader.java
View file @
e828c22f
...
@@ -29,6 +29,7 @@ import java.net.URLClassLoader;
...
@@ -29,6 +29,7 @@ import java.net.URLClassLoader;
import
java.net.URLConnection
;
import
java.net.URLConnection
;
import
java.util.ArrayList
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.List
;
import
java.util.Set
;
import
org.jivesoftware.openfire.XMPPServer
;
import
org.jivesoftware.openfire.XMPPServer
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
...
...
src/java/org/jivesoftware/openfire/container/PluginServlet.java
View file @
e828c22f
...
@@ -25,26 +25,22 @@ import java.io.FileInputStream;
...
@@ -25,26 +25,22 @@ import java.io.FileInputStream;
import
java.io.IOException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStream
;
import
java.net.URL
;
import
java.net.URL
;
import
java.util.HashMap
;
import
java.util.*
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
import
javax.servlet.GenericServlet
;
import
javax.servlet.*
;
import
javax.servlet.ServletConfig
;
import
javax.servlet.ServletException
;
import
javax.servlet.ServletOutputStream
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServlet
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletRequest
;
import
javax.servlet.http.HttpServletResponse
;
import
javax.servlet.http.HttpServletResponse
;
import
org.apache.jasper.JasperException
;
import
org.apache.jasper.JasperException
;
import
org.apache.jasper.JspC
;
import
org.apache.jasper.JspC
;
import
org.dom4j.Document
;
import
org.dom4j.*
;
import
org.dom4j.Element
;
import
org.dom4j.io.SAXReader
;
import
org.dom4j.io.SAXReader
;
import
org.jivesoftware.admin.PluginFilter
;
import
org.jivesoftware.util.JiveGlobals
;
import
org.jivesoftware.util.JiveGlobals
;
import
org.jivesoftware.util.StringUtils
;
import
org.jivesoftware.util.StringUtils
;
import
org.jivesoftware.util.WebXmlUtils
;
import
org.slf4j.Logger
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.slf4j.LoggerFactory
;
import
org.xml.sax.SAXException
;
import
org.xml.sax.SAXException
;
...
@@ -132,62 +128,125 @@ public class PluginServlet extends HttpServlet {
...
@@ -132,62 +128,125 @@ public class PluginServlet extends HttpServlet {
* @param webXML the web.xml file containing JSP page names to servlet class file
* @param webXML the web.xml file containing JSP page names to servlet class file
* mappings.
* mappings.
*/
*/
public
static
void
registerServlets
(
PluginManager
manager
,
Plugin
plugin
,
File
webXML
)
{
public
static
void
registerServlets
(
PluginManager
manager
,
final
Plugin
plugin
,
File
webXML
)
{
pluginManager
=
manager
;
pluginManager
=
manager
;
if
(!
webXML
.
exists
())
{
Log
.
error
(
"Could not register plugin servlets, file "
+
webXML
.
getAbsolutePath
()
+
if
(
!
webXML
.
exists
()
)
" does not exist."
);
{
Log
.
error
(
"Could not register plugin servlets, file "
+
webXML
.
getAbsolutePath
()
+
" does not exist."
);
return
;
return
;
}
}
// Find the name of the plugin directory given that the webXML file
// lives in plugins/[pluginName]/web/web.xml
// Find the name of the plugin directory given that the webXML file lives in plugins/[pluginName]/web/web.xml
String
pluginName
=
webXML
.
getParentFile
().
getParentFile
().
getParentFile
().
getName
();
final
String
pluginName
=
webXML
.
getParentFile
().
getParentFile
().
getParentFile
().
getName
();
try
{
try
// Make the reader non-validating so that it doesn't try to resolve external
{
// DTD's. Trying to resolve external DTD's can break on some firewall configurations.
final
Document
webXmlDoc
=
WebXmlUtils
.
asDocument
(
webXML
);
SAXReader
saxReader
=
new
SAXReader
(
false
);
try
{
final
List
<
String
>
servletNames
=
WebXmlUtils
.
getServletNames
(
webXmlDoc
);
saxReader
.
setFeature
(
"http://apache.org/xml/features/nonvalidating/load-external-dtd"
,
for
(
final
String
servletName
:
servletNames
)
false
);
{
}
Log
.
debug
(
"Loading servlet '{}' of plugin '{}'..."
,
servletName
,
pluginName
);
catch
(
SAXException
e
)
{
Log
.
warn
(
"Error setting SAXReader feature"
,
e
);
final
String
className
=
WebXmlUtils
.
getServletClassName
(
webXmlDoc
,
servletName
);
}
if
(
className
==
null
||
className
.
isEmpty
()
)
Document
doc
=
saxReader
.
read
(
webXML
);
{
// Find all <servlet> entries to discover name to class mapping.
Log
.
warn
(
"Could not load servlet '{}' of plugin '{}'. web-xml does not define a class name for this servlet."
,
servletName
,
pluginName
);
List
classes
=
doc
.
getRootElement
().
elements
(
"servlet"
);
continue
;
Map
<
String
,
Class
>
classMap
=
new
HashMap
<>();
}
for
(
int
i
=
0
;
i
<
classes
.
size
();
i
++)
{
Element
servletElement
=
(
Element
)
classes
.
get
(
i
);
final
Class
theClass
=
manager
.
loadClass
(
plugin
,
className
);
String
name
=
servletElement
.
element
(
"servlet-name"
).
getTextTrim
();
String
className
=
servletElement
.
element
(
"servlet-class"
).
getTextTrim
();
final
Object
instance
=
theClass
.
newInstance
();
classMap
.
put
(
name
,
manager
.
loadClass
(
plugin
,
className
));
if
(
!(
instance
instanceof
GenericServlet
)
)
}
{
// Find all <servelt-mapping> entries to discover name to URL mapping.
Log
.
warn
(
"Could not load servlet '{}' of plugin '{}'. Its class ({}) is not an instance of javax.servlet.GenericServlet."
,
servletName
,
pluginName
,
className
);
List
names
=
doc
.
getRootElement
().
elements
(
"servlet-mapping"
);
for
(
int
i
=
0
;
i
<
names
.
size
();
i
++)
{
Element
nameElement
=
(
Element
)
names
.
get
(
i
);
String
name
=
nameElement
.
element
(
"servlet-name"
).
getTextTrim
();
String
url
=
nameElement
.
element
(
"url-pattern"
).
getTextTrim
();
// Register the servlet for the URL.
Class
servletClass
=
classMap
.
get
(
name
);
if
(
servletClass
==
null
)
{
Log
.
error
(
"Unable to load servlet, "
+
name
+
", servlet-class not found."
);
continue
;
continue
;
}
}
Object
instance
=
servletClass
.
newInstance
();
if
(
instance
instanceof
GenericServlet
)
{
Log
.
debug
(
"Initializing servlet '{}' of plugin '{}'..."
,
servletName
,
pluginName
);
// Initialize the servlet then add it to the map..
(
(
GenericServlet
)
instance
).
init
(
servletConfig
);
((
GenericServlet
)
instance
).
init
(
servletConfig
);
servlets
.
put
((
pluginName
+
url
).
toLowerCase
(),
(
GenericServlet
)
instance
);
Log
.
debug
(
"Registering servlet '{}' of plugin '{}' URL patterns."
,
servletName
,
pluginName
);
final
Set
<
String
>
urlPatterns
=
WebXmlUtils
.
getServletUrlPatterns
(
webXmlDoc
,
servletName
);
for
(
final
String
urlPattern
:
urlPatterns
)
{
servlets
.
put
(
(
pluginName
+
urlPattern
).
toLowerCase
(),
(
GenericServlet
)
instance
);
}
}
else
{
Log
.
debug
(
"Servlet '{}' of plugin '{}' loaded successfully."
,
servletName
,
pluginName
);
Log
.
warn
(
"Could not load "
+
(
pluginName
+
url
)
+
": not a servlet."
);
}
final
List
<
String
>
filterNames
=
WebXmlUtils
.
getFilterNames
(
webXmlDoc
);
for
(
final
String
filterName
:
filterNames
)
{
Log
.
debug
(
"Loading filter '{}' of plugin '{}'..."
,
filterName
,
pluginName
);
final
String
className
=
WebXmlUtils
.
getFilterClassName
(
webXmlDoc
,
filterName
);
if
(
className
==
null
||
className
.
isEmpty
()
)
{
Log
.
warn
(
"Could not load filter '{}' of plugin '{}'. web-xml does not define a class name for this filter."
,
filterName
,
pluginName
);
continue
;
}
}
final
Class
theClass
=
manager
.
loadClass
(
plugin
,
className
);
final
Object
instance
=
theClass
.
newInstance
();
if
(
!(
instance
instanceof
Filter
)
)
{
Log
.
warn
(
"Could not load filter '{}' of plugin '{}'. Its class ({}) is not an instance of javax.servlet.Filter."
,
filterName
,
pluginName
,
className
);
continue
;
}
Log
.
debug
(
"Initializing filter '{}' of plugin '{}'..."
,
filterName
,
pluginName
);
(
(
Filter
)
instance
).
init
(
new
FilterConfig
()
{
@Override
public
String
getFilterName
()
{
return
filterName
;
}
}
@Override
public
ServletContext
getServletContext
()
{
return
new
PluginServletContext
(
servletConfig
.
getServletContext
(),
pluginManager
,
plugin
);
}
}
catch
(
Throwable
e
)
{
Log
.
error
(
e
.
getMessage
(),
e
);
@Override
public
String
getInitParameter
(
String
s
)
{
final
Map
<
String
,
String
>
params
=
WebXmlUtils
.
getFilterInitParams
(
webXmlDoc
,
filterName
);
if
(
params
==
null
||
params
.
isEmpty
()
)
{
return
null
;
}
return
params
.
get
(
s
);
}
@Override
public
Enumeration
<
String
>
getInitParameterNames
()
{
final
Map
<
String
,
String
>
params
=
WebXmlUtils
.
getFilterInitParams
(
webXmlDoc
,
filterName
);;
if
(
params
==
null
||
params
.
isEmpty
()
)
{
return
Collections
.
emptyEnumeration
();
}
return
Collections
.
enumeration
(
params
.
keySet
()
);
}
}
);
Log
.
debug
(
"Registering filter '{}' of plugin '{}' URL patterns."
,
filterName
,
pluginName
);
final
Set
<
String
>
urlPatterns
=
WebXmlUtils
.
getFilterUrlPatterns
(
webXmlDoc
,
filterName
);
for
(
final
String
urlPattern
:
urlPatterns
)
{
PluginFilter
.
addPluginFilter
(
urlPattern
,
(
(
Filter
)
instance
)
);
}
Log
.
debug
(
"Filter '{}' of plugin '{}' loaded successfully."
,
filterName
,
pluginName
);
}
}
catch
(
Throwable
e
)
{
Log
.
error
(
"An unexpected problem occurred while attempting to register servlets for plugin '{}'."
,
plugin
,
e
);
}
}
}
}
...
@@ -197,39 +256,74 @@ public class PluginServlet extends HttpServlet {
...
@@ -197,39 +256,74 @@ public class PluginServlet extends HttpServlet {
* @param webXML the web.xml file containing JSP page names to servlet class file
* @param webXML the web.xml file containing JSP page names to servlet class file
* mappings.
* mappings.
*/
*/
public
static
void
unregisterServlets
(
File
webXML
)
{
public
static
void
unregisterServlets
(
File
webXML
)
if
(!
webXML
.
exists
())
{
{
Log
.
error
(
"Could not unregister plugin servlets, file "
+
webXML
.
getAbsolutePath
()
+
if
(
!
webXML
.
exists
()
)
" does not exist."
);
{
Log
.
error
(
"Could not unregister plugin servlets, file "
+
webXML
.
getAbsolutePath
()
+
" does not exist."
);
return
;
return
;
}
}
// Find the name of the plugin directory given that the webXML file
// lives in plugins/[pluginName]/web/web.xml
// Find the name of the plugin directory given that the webXML file lives in plugins/[pluginName]/web/web.xml
String
pluginName
=
webXML
.
getParentFile
().
getParentFile
().
getParentFile
().
getName
();
final
String
pluginName
=
webXML
.
getParentFile
().
getParentFile
().
getParentFile
().
getName
();
try
{
try
SAXReader
saxReader
=
new
SAXReader
(
false
);
{
saxReader
.
setFeature
(
"http://apache.org/xml/features/nonvalidating/load-external-dtd"
,
final
Document
webXmlDoc
=
WebXmlUtils
.
asDocument
(
webXML
);
false
);
Document
doc
=
saxReader
.
read
(
webXML
);
// Un-register and destroy all servlets.
// Find all <servlet-mapping> entries to discover name to URL mapping.
final
List
<
String
>
servletNames
=
WebXmlUtils
.
getServletNames
(
webXmlDoc
);
List
names
=
doc
.
getRootElement
().
elements
(
"servlet-mapping"
);
for
(
final
String
servletName
:
servletNames
)
for
(
int
i
=
0
;
i
<
names
.
size
();
i
++)
{
{
Element
nameElement
=
(
Element
)
names
.
get
(
i
);
Log
.
debug
(
"Unregistering servlet '{}' of plugin '{}'"
,
servletName
,
pluginName
);
String
url
=
nameElement
.
element
(
"url-pattern"
).
getTextTrim
();
final
Set
<
Servlet
>
toDestroy
=
new
HashSet
<>();
// Destroy the servlet than remove from servlets map.
final
Set
<
String
>
urlPatterns
=
WebXmlUtils
.
getServletUrlPatterns
(
webXmlDoc
,
servletName
);
GenericServlet
servlet
=
servlets
.
get
((
pluginName
+
url
).
toLowerCase
());
for
(
final
String
urlPattern
:
urlPatterns
)
if
(
servlet
!=
null
)
{
{
final
GenericServlet
servlet
=
servlets
.
remove
(
(
pluginName
+
urlPattern
).
toLowerCase
()
);
if
(
servlet
!=
null
)
{
toDestroy
.
add
(
servlet
);
}
}
for
(
final
Servlet
servlet
:
toDestroy
)
{
servlet
.
destroy
();
servlet
.
destroy
();
}
}
servlets
.
remove
((
pluginName
+
url
).
toLowerCase
());
servlet
=
null
;
Log
.
debug
(
"Servlet '{}' of plugin '{}' unregistered and destroyed successfully."
,
servletName
,
pluginName
);
}
}
// Un-register and destroy all servlet filters.
final
List
<
String
>
filterNames
=
WebXmlUtils
.
getFilterNames
(
webXmlDoc
);
for
(
final
String
filterName
:
filterNames
)
{
Log
.
debug
(
"Unregistering filter '{}' of plugin '{}'"
,
filterName
,
pluginName
);
final
Set
<
Filter
>
toDestroy
=
new
HashSet
<>();
final
String
className
=
WebXmlUtils
.
getFilterClassName
(
webXmlDoc
,
filterName
);
final
Set
<
String
>
urlPatterns
=
WebXmlUtils
.
getFilterUrlPatterns
(
webXmlDoc
,
filterName
);
for
(
final
String
urlPattern
:
urlPatterns
)
{
final
Filter
filter
=
PluginFilter
.
removePluginFilter
(
urlPattern
,
className
);
if
(
filter
!=
null
)
{
toDestroy
.
add
(
filter
);
}
}
catch
(
Throwable
e
)
{
Log
.
error
(
e
.
getMessage
(),
e
);
}
}
for
(
final
Filter
filter
:
toDestroy
)
{
filter
.
destroy
();
}
}
Log
.
debug
(
"Filter '{}' of plugin '{}' unregistered and destroyesd successfully."
,
filterName
,
pluginName
);
}
}
catch
(
Throwable
e
)
{
Log
.
error
(
"An unexpected problem occurred while attempting to unregister servlets."
,
e
);
}
}
/**
/**
* Registers a live servlet for a plugin programmatically, does not
* Registers a live servlet for a plugin programmatically, does not
...
...
src/java/org/jivesoftware/openfire/container/PluginServletContext.java
0 → 100644
View file @
e828c22f
/*
* Copyright 2016 IgniteRealtime.org
*
* 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
org
.
jivesoftware
.
openfire
.
container
;
import
javax.servlet.*
;
import
javax.servlet.descriptor.JspConfigDescriptor
;
import
java.io.InputStream
;
import
java.net.MalformedURLException
;
import
java.net.URL
;
import
java.util.*
;
/**
* A Servlet Context to be used by Openfire plugins.
*
* This implementation is used do load resources from the plugin classpath. Other functionality is delegated to a proxy
* implementation.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
public
class
PluginServletContext
implements
ServletContext
{
protected
final
ServletContext
proxy
;
private
final
PluginManager
pluginManager
;
private
final
Plugin
plugin
;
public
PluginServletContext
(
ServletContext
proxy
,
PluginManager
pluginManager
,
Plugin
plugin
)
{
this
.
proxy
=
proxy
;
this
.
pluginManager
=
pluginManager
;
this
.
plugin
=
plugin
;
}
/**
* The plugin classloader is an URL classloadeer, which will do lookups in directories with entries like these:
* jar:file:/home/guus/github/Openfire/target/openfire/plugins/oauthresourceserver/lib/plugin-oauthresourceserver.jar!/
* (note the trailing slash).
*
* To prevent lookup failures, strip any leading slash (which, when concatinated, would result "//").
*
* @param input A string (cannot be null)
* @return The string without the first leading slash.
*/
protected
static
String
stripLeadingSlash
(
String
input
)
{
if
(
input
.
startsWith
(
"/"
))
{
return
input
.
substring
(
1
);
}
else
{
return
input
;
}
}
@Override
public
String
getContextPath
()
{
return
proxy
.
getContextPath
();
}
@Override
public
ServletContext
getContext
(
String
s
)
{
return
proxy
.
getContext
(
s
);
}
@Override
public
int
getMajorVersion
()
{
return
proxy
.
getMajorVersion
();
}
@Override
public
int
getMinorVersion
()
{
return
proxy
.
getMinorVersion
();
}
@Override
public
int
getEffectiveMajorVersion
()
{
return
proxy
.
getEffectiveMajorVersion
();
}
@Override
public
int
getEffectiveMinorVersion
()
{
return
proxy
.
getEffectiveMinorVersion
();
}
@Override
public
String
getMimeType
(
String
s
)
{
return
proxy
.
getMimeType
(
s
);
}
@Override
public
Set
<
String
>
getResourcePaths
(
String
s
)
{
final
String
pluginPath
=
"/plugins/"
+
pluginManager
.
getName
(
plugin
)
+
"/"
;
final
Set
<
String
>
proxyResults
=
proxy
.
getResourcePaths
(
pluginPath
+
s
);
final
Set
<
String
>
results
=
new
HashSet
<>();
for
(
final
String
proxyResult
:
proxyResults
)
{
results
.
add
(
proxyResult
.
replaceFirst
(
pluginPath
,
""
)
);
}
return
results
;
}
@Override
public
URL
getResource
(
String
s
)
throws
MalformedURLException
{
return
pluginManager
.
getPluginClassloader
(
plugin
).
getResource
(
stripLeadingSlash
(
s
)
);
}
@Override
public
InputStream
getResourceAsStream
(
String
s
)
{
return
pluginManager
.
getPluginClassloader
(
plugin
).
getResourceAsStream
(
stripLeadingSlash
(
s
)
);
}
@Override
public
RequestDispatcher
getRequestDispatcher
(
String
s
)
{
return
proxy
.
getRequestDispatcher
(
s
);
}
@Override
public
RequestDispatcher
getNamedDispatcher
(
String
s
)
{
return
proxy
.
getNamedDispatcher
(
s
);
}
@Override
public
Servlet
getServlet
(
String
s
)
throws
ServletException
{
return
proxy
.
getServlet
(
s
);
}
@Override
public
Enumeration
<
Servlet
>
getServlets
()
{
return
proxy
.
getServlets
();
}
@Override
public
Enumeration
<
String
>
getServletNames
()
{
return
proxy
.
getServletNames
();
}
@Override
public
void
log
(
String
s
)
{
proxy
.
log
(
s
);
}
@Override
public
void
log
(
Exception
e
,
String
s
)
{
proxy
.
log
(
e
,
s
);
}
@Override
public
void
log
(
String
s
,
Throwable
throwable
)
{
proxy
.
log
(
s
,
throwable
);
}
@Override
public
String
getRealPath
(
String
s
)
{
return
null
;
}
@Override
public
String
getServerInfo
()
{
return
proxy
.
getServerInfo
();
}
@Override
public
String
getInitParameter
(
String
s
)
{
return
proxy
.
getInitParameter
(
s
);
}
@Override
public
Enumeration
<
String
>
getInitParameterNames
()
{
return
proxy
.
getInitParameterNames
();
}
@Override
public
boolean
setInitParameter
(
String
s
,
String
s1
)
{
return
proxy
.
setInitParameter
(
s
,
s1
);
}
@Override
public
Object
getAttribute
(
String
s
)
{
return
proxy
.
getAttribute
(
s
);
}
@Override
public
Enumeration
<
String
>
getAttributeNames
()
{
return
proxy
.
getAttributeNames
();
}
@Override
public
void
setAttribute
(
String
s
,
Object
o
)
{
proxy
.
setAttribute
(
s
,
o
);
}
@Override
public
void
removeAttribute
(
String
s
)
{
proxy
.
removeAttribute
(
s
);
}
@Override
public
String
getServletContextName
()
{
return
proxy
.
getServletContextName
();
}
@Override
public
ServletRegistration
.
Dynamic
addServlet
(
String
s
,
String
s1
)
{
return
proxy
.
addServlet
(
s
,
s1
);
}
@Override
public
ServletRegistration
.
Dynamic
addServlet
(
String
s
,
Servlet
servlet
)
{
return
proxy
.
addServlet
(
s
,
servlet
);
}
@Override
public
ServletRegistration
.
Dynamic
addServlet
(
String
s
,
Class
<?
extends
Servlet
>
aClass
)
{
return
proxy
.
addServlet
(
s
,
aClass
);
}
@Override
public
<
T
extends
Servlet
>
T
createServlet
(
Class
<
T
>
aClass
)
throws
ServletException
{
return
proxy
.
createServlet
(
aClass
);
}
@Override
public
ServletRegistration
getServletRegistration
(
String
s
)
{
return
proxy
.
getServletRegistration
(
s
);
}
@Override
public
Map
<
String
,
?
extends
ServletRegistration
>
getServletRegistrations
()
{
return
proxy
.
getServletRegistrations
();
}
@Override
public
FilterRegistration
.
Dynamic
addFilter
(
String
s
,
String
s1
)
{
return
proxy
.
addFilter
(
s
,
s1
);
}
@Override
public
FilterRegistration
.
Dynamic
addFilter
(
String
s
,
Filter
filter
)
{
return
proxy
.
addFilter
(
s
,
filter
);
}
@Override
public
FilterRegistration
.
Dynamic
addFilter
(
String
s
,
Class
<?
extends
Filter
>
aClass
)
{
return
proxy
.
addFilter
(
s
,
aClass
);
}
@Override
public
<
T
extends
Filter
>
T
createFilter
(
Class
<
T
>
aClass
)
throws
ServletException
{
return
proxy
.
createFilter
(
aClass
);
}
@Override
public
FilterRegistration
getFilterRegistration
(
String
s
)
{
return
proxy
.
getFilterRegistration
(
s
);
}
@Override
public
Map
<
String
,
?
extends
FilterRegistration
>
getFilterRegistrations
()
{
return
proxy
.
getFilterRegistrations
();
}
@Override
public
SessionCookieConfig
getSessionCookieConfig
()
{
return
proxy
.
getSessionCookieConfig
();
}
@Override
public
void
setSessionTrackingModes
(
Set
<
SessionTrackingMode
>
set
)
{
proxy
.
setSessionTrackingModes
(
set
);
}
@Override
public
Set
<
SessionTrackingMode
>
getDefaultSessionTrackingModes
()
{
return
proxy
.
getDefaultSessionTrackingModes
();
}
@Override
public
Set
<
SessionTrackingMode
>
getEffectiveSessionTrackingModes
()
{
return
proxy
.
getEffectiveSessionTrackingModes
();
}
@Override
public
void
addListener
(
String
s
)
{
proxy
.
addListener
(
s
);
}
@Override
public
<
T
extends
EventListener
>
void
addListener
(
T
t
)
{
proxy
.
addListener
(
t
);
}
@Override
public
void
addListener
(
Class
<?
extends
EventListener
>
aClass
)
{
proxy
.
addListener
(
aClass
);
}
@Override
public
<
T
extends
EventListener
>
T
createListener
(
Class
<
T
>
aClass
)
throws
ServletException
{
return
proxy
.
createListener
(
aClass
);
}
@Override
public
JspConfigDescriptor
getJspConfigDescriptor
()
{
return
proxy
.
getJspConfigDescriptor
();
}
@Override
public
ClassLoader
getClassLoader
()
{
return
pluginManager
.
getPluginClassloader
(
plugin
);
}
@Override
public
void
declareRoles
(
String
...
strings
)
{
proxy
.
declareRoles
(
strings
);
}
@Override
public
String
getVirtualServerName
()
{
return
proxy
.
getVirtualServerName
();
}
}
src/java/org/jivesoftware/util/WebXmlUtils.java
0 → 100644
View file @
e828c22f
package
org
.
jivesoftware
.
util
;
import
org.dom4j.Document
;
import
org.dom4j.DocumentException
;
import
org.dom4j.Element
;
import
org.dom4j.io.SAXReader
;
import
org.slf4j.Logger
;
import
org.slf4j.LoggerFactory
;
import
org.xml.sax.SAXException
;
import
java.io.File
;
import
java.util.*
;
/**
* Utilities to extract data from a web.xml file.
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
public
class
WebXmlUtils
{
private
final
static
Logger
Log
=
LoggerFactory
.
getLogger
(
WebXmlUtils
.
class
);
public
static
Document
asDocument
(
File
webXML
)
throws
DocumentException
{
// Make the reader non-validating so that it doesn't try to resolve external DTD's. Trying to resolve
// external DTD's can break on some firewall configurations.
SAXReader
saxReader
=
new
SAXReader
(
false
);
try
{
saxReader
.
setFeature
(
"http://apache.org/xml/features/nonvalidating/load-external-dtd"
,
false
);
}
catch
(
SAXException
e
)
{
Log
.
warn
(
"Error setting SAXReader feature"
,
e
);
}
return
saxReader
.
read
(
webXML
);
}
/**
* Retrieves the names of all servlets from a web.xml document.
*
* Returns a list that contains 'sessioncreate' and 'sessiondestroy' from this web.xml document:
* <servlet>
* <servlet-name>sessioncreate</servlet-name>
* <servlet-class>SessionCreateServlet</servlet-class>
* </servlet>
* <servlet>
* <servlet-name>sessiondestroy</servlet-name>
* <servlet-class>SessionDestroyServlet</servlet-class>
* </servlet>
*
* @param webXml web.xml document, parsed as XML (cannot be null)
* @return The name of the filter class, or null when no such class was defined.
*/
public
static
List
<
String
>
getServletNames
(
Document
webXml
)
{
return
getNames
(
"servlet"
,
webXml
);
}
/**
* Retrieves the names of all filters from a web.xml document.
*
* Returns a list that contains 'message' from this web.xml document:
* <filter>
* <filter-name>message</filter-name>
* <filter-class>com.acme.filter.MessageFilter</filter-class>
* </filter>
*
* @param webXml web.xml document, parsed as XML (cannot be null)
* @return The name of the filter class, or null when no such class was defined.
*/
public
static
List
<
String
>
getFilterNames
(
Document
webXml
)
{
return
getNames
(
"filter"
,
webXml
);
}
private
static
List
<
String
>
getNames
(
String
type
,
Document
webXml
)
{
final
List
<
String
>
result
=
new
ArrayList
<>();
final
List
<
Element
>
elements
=
webXml
.
getRootElement
().
elements
(
type
);
// all elements of 'type' (filter or servlet).
for
(
final
Element
element
:
elements
)
{
final
String
name
=
element
.
elementTextTrim
(
type
+
"-name"
);
if
(
name
!=
null
&&
!
name
.
isEmpty
()
)
{
result
.
add
(
name
);
}
}
return
result
;
}
/**
* Retrieves the class name for a particular servlet from a web.xml document.
*
* Returns 'SessionCreateServlet' for 'sessioncreate' of this web.xml document:
* <servlet>
* <servlet-name>sessioncreate</servlet-name>
* <servlet-class>SessionCreateServlet</servlet-class>
* </servlet>
* <servlet>
* <servlet-name>sessiondestroy</servlet-name>
* <servlet-class>SessionDestroyServlet</servlet-class>
* </servlet>
*
* @param webXml web.xml document, parsed as XML (cannot be null)
* @param servletName The name of the servlet (cannot be null or empty).
* @return The name of the filter class, or null when no such class was defined.
*/
public
static
String
getServletClassName
(
Document
webXml
,
String
servletName
)
{
return
getClassName
(
"servlet"
,
webXml
,
servletName
);
}
/**
* Retrieves the class name for a particular filter from a web.xml document.
*
* Returns 'com.acme.filter.MessageFilter' for 'message' of this web.xml document:
* <filter>
* <filter-name>message</filter-name>
* <filter-class>com.acme.filter.MessageFilter</filter-class>
* </filter>
*
* @param webXml web.xml document, parsed as XML (cannot be null)
* @param filterName The name of the filter (cannot be null or empty).
* @return The name of the filter class, or null when no such class was defined.
*/
public
static
String
getFilterClassName
(
Document
webXml
,
String
filterName
)
{
return
getClassName
(
"filter"
,
webXml
,
filterName
);
}
private
static
String
getClassName
(
String
type
,
Document
webXml
,
String
typeName
)
{
String
className
=
null
;
final
List
<
Element
>
elements
=
webXml
.
getRootElement
().
elements
(
type
);
// all elements of 'type' (filter or servlet).
for
(
final
Element
element
:
elements
)
{
final
String
name
=
element
.
elementTextTrim
(
type
+
"-name"
);
if
(
typeName
.
equals
(
name
)
)
{
className
=
element
.
elementTextTrim
(
type
+
"-class"
);
break
;
}
}
if
(
className
==
null
||
className
.
isEmpty
()
)
{
return
null
;
}
return
className
;
}
/**
* Retrieves a map of init param/values for a particular servlet from a web.xml document.
*
* For filter 'message' of this web.xml document, returns a map with two entries: foo-> bar, test->value.
* <servlet>
* <servlet-name>sessioncreate</servlet-name>
* <servlet-class>SessionCreateServlet</servlet-class>
* <init-param>
* <param-name>foo</param-name>
* <param-value>bar</param-value>
* </init-param>
* <init-param>
* <param-name>test</param-name>
* <param-value>value</param-value>
* </init-param>
* </servlet>
*
* Parameters with no or empty name are ignored. When multiple parameters have the same name, only one of them is
* returned.
*
* @param webXml web.xml document, parsed as XML (cannot be null)
* @param servletName The name of the servlet (cannot be null or empty).
* @return A map (possibly empty, but never null).
*/
public
static
Map
<
String
,
String
>
getServletInitParams
(
Document
webXml
,
String
servletName
)
{
return
getInitParams
(
"servlet"
,
webXml
,
servletName
);
}
/**
* Retrieves a map of init param/values for a particular filter from a web.xml document.
*
* For filter 'message' of this web.xml document, returns a map with two entries: foo-> bar, test->value.
* <filter>
* <filter-name>message</filter-name>
* <filter-class>com.acme.filter.MessageFilter</filter-class>
* <init-param>
* <param-name>foo</param-name>
* <param-value>bar</param-value>
* </init-param>
* <init-param>
* <param-name>test</param-name>
* <param-value>value</param-value>
* </init-param>
* </filter>
*
* Parameters with no or empty name are ignored. When multiple parameters have the same name, only one of them is
* returned.
*
* @param webXml web.xml document, parsed as XML (cannot be null)
* @param filterName The name of the filter (cannot be null or empty).
* @return A map (possibly empty, but never null).
*/
public
static
Map
<
String
,
String
>
getFilterInitParams
(
Document
webXml
,
String
filterName
)
{
return
getInitParams
(
"filter"
,
webXml
,
filterName
);
}
private
static
Map
<
String
,
String
>
getInitParams
(
String
type
,
Document
webXml
,
String
typeName
)
{
final
Map
<
String
,
String
>
result
=
new
HashMap
<>();
final
List
<
Element
>
elements
=
webXml
.
getRootElement
().
elements
(
type
);
// all elements of 'type' (filter or servlet).
for
(
final
Element
element
:
elements
)
{
final
String
name
=
element
.
elementTextTrim
(
type
+
"-name"
);
if
(
typeName
.
equals
(
name
)
)
{
final
List
<
Element
>
initParamElements
=
element
.
elements
(
"init-param"
);
for
(
final
Element
initParamElement
:
initParamElements
)
{
final
String
pName
=
initParamElement
.
elementTextTrim
(
"param-name"
);
final
String
pValue
=
initParamElement
.
elementTextTrim
(
"param-value"
);
if
(
pName
==
null
||
pName
.
isEmpty
()
)
{
Log
.
warn
(
"Unable to add init-param that has no name"
);
}
else
{
result
.
put
(
pName
,
pValue
);
}
}
}
}
return
result
;
}
/**
* Retrieves all URL patterns that apply to a specific servlet.
*
* @param webXml web.xml document, parsed as XML (cannot be null)
* @param servletName The name of the servlet (cannot be null or empty).
* @return A collection (possibly empty, but never null).
*/
public
static
Set
<
String
>
getServletUrlPatterns
(
Document
webXml
,
String
servletName
)
{
return
getUrlPatterns
(
"servlet"
,
webXml
,
servletName
);
}
/**
* Retrieves all URL patterns that apply to a specific filter.
*
* @param webXml web.xml document, parsed as XML (cannot be null)
* @param filterName The name of the filter (cannot be null or empty).
* @return A collection (possibly empty, but never null).
*/
public
static
Set
<
String
>
getFilterUrlPatterns
(
Document
webXml
,
String
filterName
)
{
return
getUrlPatterns
(
"filter"
,
webXml
,
filterName
);
}
private
static
Set
<
String
>
getUrlPatterns
(
String
type
,
Document
webXml
,
String
typeName
)
{
final
Set
<
String
>
result
=
new
HashSet
<>();
final
List
<
Element
>
elements
=
webXml
.
getRootElement
().
elements
(
type
+
"-mapping"
);
// all elements of 'type'-mapping (filter-mapping or servlet-mapping).
for
(
final
Element
element
:
elements
)
{
final
String
name
=
element
.
elementTextTrim
(
type
+
"-name"
);
if
(
typeName
.
equals
(
name
)
)
{
final
List
<
Element
>
urlPatternElements
=
element
.
elements
(
"url-pattern"
);
for
(
final
Element
urlPatternElement
:
urlPatternElements
)
{
final
String
urlPattern
=
urlPatternElement
.
getTextTrim
();
if
(
urlPattern
!=
null
)
{
result
.
add
(
urlPattern
);
}
}
// A filter can also be mapped to a servlet (by name). In that case, all url-patterns of the corresponding servlet-mapping should be used.
if
(
"filter"
.
equals
(
type
)
)
{
final
List
<
Element
>
servletNameElements
=
element
.
elements
(
"servlet-name"
);
for
(
final
Element
servletNameElement
:
servletNameElements
)
{
final
String
servletName
=
servletNameElement
.
getTextTrim
();
if
(
servletName
!=
null
)
{
result
.
addAll
(
getUrlPatterns
(
"servlet"
,
webXml
,
servletName
)
);
}
}
}
break
;
}
}
return
result
;
}
}
src/test/java/org/jivesoftware/util/WebXmlUtilsTest.java
0 → 100644
View file @
e828c22f
package
org
.
jivesoftware
.
util
;
import
org.dom4j.Document
;
import
org.junit.Test
;
import
java.io.File
;
import
java.util.Iterator
;
import
java.util.List
;
import
java.util.Map
;
import
java.util.Set
;
import
static
org
.
junit
.
Assert
.
assertEquals
;
import
static
org
.
junit
.
Assert
.*;
/**
* Unit tests for {@link WebXmlUtils}
*
* @author Guus der Kinderen, guus.der.kinderen@gmail.com
*/
public
class
WebXmlUtilsTest
{
@Test
public
void
testGetServletNames
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
// Execute system under test.
final
List
<
String
>
results
=
WebXmlUtils
.
getServletNames
(
webXml
);
// Verify result.
assertNotNull
(
results
);
final
Iterator
iterator
=
results
.
iterator
();
// Names should be reported in order.
assertEquals
(
"PluginServlet"
,
iterator
.
next
()
);
assertEquals
(
"FaviconServlet"
,
iterator
.
next
()
);
assertEquals
(
"dwr-invoker"
,
iterator
.
next
()
);
assertEquals
(
"PluginIconServlet"
,
iterator
.
next
()
);
assertFalse
(
iterator
.
hasNext
()
);
}
@Test
public
void
testGetFilterNames
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
// Execute system under test.
final
List
<
String
>
results
=
WebXmlUtils
.
getFilterNames
(
webXml
);
// Verify result.
assertNotNull
(
results
);
final
Iterator
iterator
=
results
.
iterator
();
// Names should be reported in order.
assertEquals
(
"AuthCheck"
,
iterator
.
next
()
);
assertEquals
(
"PluginFilter"
,
iterator
.
next
()
);
assertEquals
(
"Set Character Encoding"
,
iterator
.
next
()
);
assertEquals
(
"LocaleFilter"
,
iterator
.
next
()
);
assertEquals
(
"sitemesh"
,
iterator
.
next
()
);
assertFalse
(
iterator
.
hasNext
()
);
}
@Test
public
void
testGetServletClassName
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
servletName
=
"dwr-invoker"
;
// Execute system under test.
final
String
result
=
WebXmlUtils
.
getServletClassName
(
webXml
,
servletName
);
// Verify result.
assertEquals
(
"uk.ltd.getahead.dwr.DWRServlet"
,
result
);
}
@Test
public
void
testGetServletClassNameForNonExistingServlet
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
servletName
=
"This does not exist"
;
// Execute system under test.
final
String
result
=
WebXmlUtils
.
getServletClassName
(
webXml
,
servletName
);
// Verify result.
assertNull
(
result
);
}
@Test
public
void
testGetFilterClassName
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
filterName
=
"Set Character Encoding"
;
// Execute system under test.
final
String
result
=
WebXmlUtils
.
getFilterClassName
(
webXml
,
filterName
);
// Verify result.
assertEquals
(
"org.jivesoftware.util.SetCharacterEncodingFilter"
,
result
);
}
@Test
public
void
testGetFilterClassNameForNonExistingFilter
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
filterName
=
"This does not exist"
;
// Execute system under test.
final
String
result
=
WebXmlUtils
.
getFilterClassName
(
webXml
,
filterName
);
// Verify result.
assertNull
(
result
);
}
@Test
public
void
testGetServletInitParams
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
servletName
=
"FaviconServlet"
;
// Execute system under test.
final
Map
<
String
,
String
>
result
=
WebXmlUtils
.
getServletInitParams
(
webXml
,
servletName
);
// Verify result.
assertNotNull
(
result
);
assertEquals
(
2
,
result
.
size
()
);
assertEquals
(
"42"
,
result
.
get
(
"answer"
)
);
assertEquals
(
"fishes"
,
result
.
get
(
"thanks"
)
);
}
@Test
public
void
testGetServletInitParamsForServletWithoutParams
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
servletName
=
"PluginServlet"
;
// Execute system under test.
final
Map
<
String
,
String
>
result
=
WebXmlUtils
.
getServletInitParams
(
webXml
,
servletName
);
// Verify result.
assertNotNull
(
result
);
assertEquals
(
0
,
result
.
size
()
);
}
@Test
public
void
testGetServletInitParamsForNonExistingServlet
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
servletName
=
"This does not exist"
;
// Execute system under test.
final
Map
<
String
,
String
>
result
=
WebXmlUtils
.
getServletInitParams
(
webXml
,
servletName
);
// Verify result.
assertNotNull
(
result
);
assertEquals
(
0
,
result
.
size
()
);
}
@Test
public
void
testGetFilterInitParams
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
filterName
=
"AuthCheck"
;
// Execute system under test.
final
Map
<
String
,
String
>
result
=
WebXmlUtils
.
getFilterInitParams
(
webXml
,
filterName
);
// Verify result.
assertNotNull
(
result
);
assertEquals
(
1
,
result
.
size
()
);
assertEquals
(
"login.jsp,index.jsp?logout=true,setup/index.jsp,setup/setup-*,.gif,.png,error-serverdown.jsp"
,
result
.
get
(
"excludes"
)
);
}
@Test
public
void
testGetFilterInitParamsForFilterWithoutParams
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
filterName
=
"PluginFilter"
;
// Execute system under test.
final
Map
<
String
,
String
>
result
=
WebXmlUtils
.
getFilterInitParams
(
webXml
,
filterName
);
// Verify result.
assertNotNull
(
result
);
assertEquals
(
0
,
result
.
size
()
);
}
@Test
public
void
testGetFilterInitParamsForNonExistingFilter
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
filterName
=
"This does not exist"
;
// Execute system under test.
final
Map
<
String
,
String
>
result
=
WebXmlUtils
.
getFilterInitParams
(
webXml
,
filterName
);
// Verify result.
assertNotNull
(
result
);
assertEquals
(
0
,
result
.
size
()
);
}
@Test
public
void
testGetServletUrlPatterns
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
servletName
=
"dwr-invoker"
;
// Execute system under test.
final
Set
<
String
>
results
=
WebXmlUtils
.
getServletUrlPatterns
(
webXml
,
servletName
);
// Verify result.
assertNotNull
(
results
);
assertEquals
(
2
,
results
.
size
()
);
assertTrue
(
results
.
contains
(
"/dwr/*"
));
assertTrue
(
results
.
contains
(
"/more-dwr/*"
));
}
@Test
public
void
testGetServletUrlPatternsForNonExistingServlet
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
servletName
=
"This does not exist"
;
// Execute system under test.
final
Set
<
String
>
results
=
WebXmlUtils
.
getServletUrlPatterns
(
webXml
,
servletName
);
// Verify result.
assertNotNull
(
results
);
assertEquals
(
0
,
results
.
size
()
);
}
@Test
public
void
testGetFilterUrlPatterns
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
filterName
=
"LocaleFilter"
;
// Execute system under test.
final
Set
<
String
>
results
=
WebXmlUtils
.
getFilterUrlPatterns
(
webXml
,
filterName
);
// Verify result.
assertNotNull
(
results
);
assertEquals
(
2
,
results
.
size
()
);
assertTrue
(
results
.
contains
(
"*.jsp"
));
assertTrue
(
results
.
contains
(
"foo.bar"
));
}
@Test
public
void
testGetFilterUrlPatternsForNonExistingFilter
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
filterName
=
"This does not exist"
;
// Execute system under test.
final
Set
<
String
>
results
=
WebXmlUtils
.
getFilterUrlPatterns
(
webXml
,
filterName
);
// Verify result.
assertNotNull
(
results
);
assertEquals
(
0
,
results
.
size
()
);
}
@Test
public
void
testGetFilterUrlPatternsForFilterThatUsesServletMapping
()
throws
Exception
{
// Setup fixture.
final
Document
webXml
=
WebXmlUtils
.
asDocument
(
new
File
(
WebXmlUtilsTest
.
class
.
getResource
(
"/org/jivesoftware/util/test-web.xml"
).
toURI
()
)
);
final
String
filterName
=
"AuthCheck"
;
// Execute system under test.
final
Set
<
String
>
results
=
WebXmlUtils
.
getFilterUrlPatterns
(
webXml
,
filterName
);
// Verify result.
assertNotNull
(
results
);
assertEquals
(
3
,
results
.
size
()
);
assertTrue
(
results
.
contains
(
"test/*.jsp"
));
// from url pattern
assertTrue
(
results
.
contains
(
"/dwr/*"
));
// from servlet-mapping
assertTrue
(
results
.
contains
(
"/more-dwr/*"
));
// from servlet-mapping
}
}
src/test/resources/org/jivesoftware/util/test-web.xml
0 → 100644
View file @
e828c22f
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app
xmlns=
"http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi=
"http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version=
"3.1"
>
<display-name>
Openfire
</display-name>
<!-- OF-902 use HttpOnly for session cookie -->
<session-config>
<cookie-config>
<http-only>
true
</http-only>
</cookie-config>
</session-config>
<!-- prevent URL rewritting with jsessionid included, OF-669 -->
<context-param>
<param-name>
org.eclipse.jetty.servlet.SessionIdPathParameterName
</param-name>
<param-value>
none
</param-value>
</context-param>
<context-param>
<param-name>
javax.servlet.jsp.jstl.fmt.localizationContext
</param-name>
<param-value>
openfire_i18n
</param-value>
</context-param>
<context-param>
<param-name>
javax.servlet.jsp.jstl.fmt.locale
</param-name>
<param-value>
zh_CN
</param-value>
</context-param>
<filter>
<filter-name>
AuthCheck
</filter-name>
<filter-class>
org.jivesoftware.admin.AuthCheckFilter
</filter-class>
<init-param>
<param-name>
excludes
</param-name>
<param-value>
login.jsp,index.jsp?logout=true,setup/index.jsp,setup/setup-*,.gif,.png,error-serverdown.jsp
</param-value>
</init-param>
</filter>
<filter>
<filter-name>
PluginFilter
</filter-name>
<filter-class>
org.jivesoftware.admin.PluginFilter
</filter-class>
</filter>
<filter>
<filter-name>
Set Character Encoding
</filter-name>
<filter-class>
org.jivesoftware.util.SetCharacterEncodingFilter
</filter-class>
</filter>
<filter>
<filter-name>
LocaleFilter
</filter-name>
<filter-class>
org.jivesoftware.util.LocaleFilter
</filter-class>
</filter>
<filter>
<filter-name>
sitemesh
</filter-name>
<filter-class>
com.opensymphony.module.sitemesh.filter.PageFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>
PluginFilter
</filter-name>
<url-pattern>
*.jsp
</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>
Set Character Encoding
</filter-name>
<url-pattern>
*.jsp
</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>
LocaleFilter
</filter-name>
<url-pattern>
*.jsp
</url-pattern>
<url-pattern>
foo.bar
</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>
PluginFilter
</filter-name>
<servlet-name>
PluginServlet
</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>
sitemesh
</filter-name>
<url-pattern>
/*
</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>
AuthCheck
</filter-name>
<servlet-name>
dwr-invoker
</servlet-name>
<url-pattern>
test/*.jsp
</url-pattern>
</filter-mapping>
<listener>
<listener-class>
org.jivesoftware.openfire.XMPPContextListener
</listener-class>
</listener>
<servlet>
<servlet-name>
PluginServlet
</servlet-name>
<servlet-class>
org.jivesoftware.openfire.container.PluginServlet
</servlet-class>
<load-on-startup>
1
</load-on-startup>
</servlet>
<servlet>
<servlet-name>
FaviconServlet
</servlet-name>
<servlet-class>
org.jivesoftware.util.FaviconServlet
</servlet-class>
<init-param>
<param-name>
thanks
</param-name>
<param-value>
fishes
</param-value>
</init-param>
<init-param>
<param-name>
answer
</param-name>
<param-value>
42
</param-value>
</init-param>
<load-on-startup>
1
</load-on-startup>
</servlet>
<servlet>
<servlet-name>
dwr-invoker
</servlet-name>
<servlet-class>
uk.ltd.getahead.dwr.DWRServlet
</servlet-class>
</servlet>
<servlet>
<servlet-name>
PluginIconServlet
</servlet-name>
<servlet-class>
org.jivesoftware.openfire.container.PluginIconServlet
</servlet-class>
</servlet>
<!--<servlet>
<servlet-name>WebDAVLiteServlet</servlet-name>
<servlet-class>org.jivesoftware.openfire.webdav.WebDAVLiteServlet</servlet-class>
</servlet>-->
<!--@@JSPC-SERVLETS@@-->
<servlet-mapping>
<servlet-name>
PluginServlet
</servlet-name>
<url-pattern>
/plugins/*
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
FaviconServlet
</servlet-name>
<url-pattern>
/getFavicon
</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>
PluginIconServlet
</servlet-name>
<url-pattern>
/geticon
</url-pattern>
</servlet-mapping>
<!--<servlet-mapping>
<servlet-name>WebDAVLiteServlet</servlet-name>
<url-pattern>/webdav/*</url-pattern>
</servlet-mapping>-->
<servlet-mapping>
<servlet-name>
dwr-invoker
</servlet-name>
<url-pattern>
/dwr/*
</url-pattern>
<url-pattern>
/more-dwr/*
</url-pattern>
</servlet-mapping>
</web-app>
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment