From c32a7138d989ed08b1e3b4c808337a7756cd118d Mon Sep 17 00:00:00 2001 From: Nils Christian Ehmke <nie@informatik.uni-kiel.de> Date: Fri, 22 Jun 2012 20:31:16 +0200 Subject: [PATCH] Added Apache Shiro for test purposes; Replaced toString-IDs with Registry-IDs; Added the connections for presentation purposes to the analysis editor again; --- Kieker.WebGUI/pom.xml | 33 ++++- .../session/CurrentWorkSpaceProjectBean.java | 123 +++++++++--------- .../converter/MIPluginStringConverter.java | 9 +- .../converter/MIPortStringConverter.java | 9 +- .../MIRepositoryStringConverter.java | 9 +- .../src/main/webapp/AnalysisEditor.xhtml | 34 +++-- .../src/main/webapp/WEB-INF/shiro.ini | 17 +++ Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml | 21 ++- 8 files changed, 177 insertions(+), 78 deletions(-) create mode 100644 Kieker.WebGUI/src/main/webapp/WEB-INF/shiro.ini diff --git a/Kieker.WebGUI/pom.xml b/Kieker.WebGUI/pom.xml index 4db2b1b1..15ff01e6 100644 --- a/Kieker.WebGUI/pom.xml +++ b/Kieker.WebGUI/pom.xml @@ -25,7 +25,38 @@ </repository> </repositories> - <dependencies> + <dependencies> + <dependency> + <groupId>commons-logging</groupId> + <artifactId>commons-logging</artifactId> + <version>1.1.1</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>jcl-over-slf4j</artifactId> + <version>1.6.6</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-api</artifactId> + <version>1.6.6</version> + </dependency> + <dependency> + <groupId>org.slf4j</groupId> + <artifactId>slf4j-log4j12</artifactId> + <version>1.6.6</version> + </dependency> + <dependency> + <groupId>org.apache.shiro</groupId> + <artifactId>shiro-core</artifactId> + <version>1.2.0</version> + </dependency> + <dependency> + <groupId>org.apache.shiro</groupId> + <artifactId>shiro-web</artifactId> + <version>1.2.0</version> + </dependency> <dependency> <groupId>com.ocpsoft</groupId> <artifactId>prettyfaces-jsf2</artifactId> diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java index 8428d428..6a9bd3d0 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/beans/session/CurrentWorkSpaceProjectBean.java @@ -29,7 +29,6 @@ import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import javax.faces.application.FacesMessage; import javax.faces.application.FacesMessage.Severity; @@ -59,6 +58,7 @@ import kieker.analysis.repository.annotation.Repository; import kieker.common.configuration.Configuration; import kieker.common.logging.Log; import kieker.common.logging.LogFactory; +import kieker.monitoring.core.registry.Registry; import kieker.webgui.common.ConnectionFilterToFilter; import kieker.webgui.common.ConnectionFilterToRepository; import kieker.webgui.common.FSManager; @@ -121,17 +121,17 @@ public final class CurrentWorkSpaceProjectBean { */ private final List<Class<AbstractReaderPlugin>> availableReaders = Collections.synchronizedList(new ArrayList<Class<AbstractReaderPlugin>>()); /** - * This map contains the mapping between the plugins and the result of their toString-method. + * This map contains the mapping between the plugins and their ID. */ - private final ConcurrentHashMap<String, MIPlugin> pluginMap = new ConcurrentHashMap<String, MIPlugin>(); + private Registry<MIPlugin> pluginMap = new Registry<MIPlugin>(); /** - * This map contains the mapping between the ports and the result of their toString-method. + * This map contains the mapping between the ports and their ID. */ - private final ConcurrentHashMap<String, MIPort> portMap = new ConcurrentHashMap<String, MIPort>(); + private Registry<MIPort> portMap = new Registry<MIPort>(); /** - * This map contains the mapping between the repositories and the result of their toString-method. + * This map contains the mapping between the repositories and their ID. */ - private final ConcurrentHashMap<String, MIRepository> repositoryMap = new ConcurrentHashMap<String, MIRepository>(); + private Registry<MIRepository> repositoryMap = new Registry<MIRepository>(); /** * This field contains the currently selected plugin. */ @@ -213,26 +213,26 @@ public final class CurrentWorkSpaceProjectBean { private void intializeHashMaps() { synchronized (this) { // Clear all maps - this.pluginMap.clear(); - this.portMap.clear(); - this.repositoryMap.clear(); + this.pluginMap = new Registry<MIPlugin>(); + this.portMap = new Registry<MIPort>(); + this.repositoryMap = new Registry<MIRepository>(); // Initialize the plugin map... for (final MIPlugin plugin : this.project.getPlugins()) { - this.pluginMap.put(plugin.toString(), plugin); + this.pluginMap.get(plugin); // ..and the port map for (final MIPort port : plugin.getOutputPorts()) { - this.portMap.put(port.toString(), port); + this.portMap.get(port); } if (plugin instanceof MIFilter) { for (final MIPort port : ((MIFilter) plugin).getInputPorts()) { - this.portMap.put(port.toString(), port); + this.portMap.get(port); } } } // Now initialize the repository map for (final MIRepository repository : this.project.getRepositories()) { - this.repositoryMap.put(repository.toString(), repository); + this.repositoryMap.get(repository); } } } @@ -365,7 +365,9 @@ public final class CurrentWorkSpaceProjectBean { this.availableFilters.clear(); this.availableReaders.clear(); this.availableRepositories.clear(); - this.pluginMap.clear(); + this.pluginMap = new Registry<MIPlugin>(); + this.portMap = new Registry<MIPort>(); + this.repositoryMap = new Registry<MIRepository>(); this.filter2filterConnections.clear(); this.filter2repositoryConnections.clear(); } @@ -698,7 +700,7 @@ public final class CurrentWorkSpaceProjectBean { synchronized (this) { // Add it to the project this.project.getRepositories().add(repository); - this.repositoryMap.put(repository.toString(), repository); + this.repositoryMap.get(repository); } } @@ -726,13 +728,13 @@ public final class CurrentWorkSpaceProjectBean { synchronized (this) { // Add it to the project and don't forget to add the ports. this.project.getPlugins().add(plugin); - this.pluginMap.put(plugin.toString(), plugin); + this.pluginMap.get(plugin); for (final MIPort port : plugin.getOutputPorts()) { - this.portMap.put(port.toString(), port); + this.portMap.get(port); } if (plugin instanceof MIFilter) { for (final MIPort port : ((MIFilter) plugin).getInputPorts()) { - this.portMap.put(port.toString(), port); + this.portMap.get(port); } } @@ -753,8 +755,15 @@ public final class CurrentWorkSpaceProjectBean { public void removeRepository(final MIRepository repository) { synchronized (this) { this.project.getRepositories().remove(repository); - // Remove the repository from the map - this.repositoryMap.remove(repository.toString()); + + // Remove the corresponding connections + final List<ConnectionFilterToRepository> fRDelList = new ArrayList<ConnectionFilterToRepository>(); + for (final ConnectionFilterToRepository conn : this.filter2repositoryConnections) { + if (conn.getDestination() == repository) { + fRDelList.add(conn); + } + } + this.filter2repositoryConnections.removeAll(fRDelList); if (this.selectedRepository == repository) { this.selectedRepository = null; // NOPMD @@ -771,16 +780,23 @@ public final class CurrentWorkSpaceProjectBean { public void removePlugin(final MIPlugin plugin) { synchronized (this) { this.project.getPlugins().remove(plugin); - // Remove the plugin and its ports from the map - this.pluginMap.remove(plugin.toString()); - for (final MIPort port : plugin.getOutputPorts()) { - this.portMap.remove(port.toString(), port); + + // Remove the corresponding connections + final List<ConnectionFilterToFilter> ffDelList = new ArrayList<ConnectionFilterToFilter>(); + for (final ConnectionFilterToFilter conn : this.filter2filterConnections) { + if ((conn.getSource() == plugin) || (conn.getDestination() == plugin)) { + ffDelList.add(conn); + } } - if (plugin instanceof MIFilter) { - for (final MIPort port : ((MIFilter) plugin).getInputPorts()) { - this.portMap.remove(port.toString(), port); + this.filter2filterConnections.removeAll(ffDelList); + + final List<ConnectionFilterToRepository> fRDelList = new ArrayList<ConnectionFilterToRepository>(); + for (final ConnectionFilterToRepository conn : this.filter2repositoryConnections) { + if (conn.getSource() == plugin) { + fRDelList.add(conn); } } + this.filter2repositoryConnections.removeAll(fRDelList); if (this.selectedPlugin == plugin) { this.selectedPlugin = null; // NOPMD @@ -945,33 +961,6 @@ public final class CurrentWorkSpaceProjectBean { } } - /** - * Sets the name of the currently selected plugin/repository. This is only necessary for the correct renaming of the components. - * - * @param newName - * The new name of the plugin/repository. - */ - public void setCurrentPluginName(final String newName) { - synchronized (this) { - // Rename the plugin/repository and get the old name for the hash map - if (this.selectedPlugin != null) { - final String oldName = this.selectedPlugin.toString(); - final MIPlugin plugin = this.pluginMap.get(oldName); - this.selectedPlugin.setName(newName); - - // Update the hash map - this.pluginMap.put(plugin.toString(), plugin); - } else { - final String oldName = this.selectedRepository.toString(); - final MIRepository repository = this.repositoryMap.get(oldName); - this.selectedRepository.setName(newName); - - // Update the hash map - this.repositoryMap.put(repository.toString(), repository); - } - } - } - /** * Delivers the valid connections (between the filters) within the current main project. * @@ -1030,6 +1019,18 @@ public final class CurrentWorkSpaceProjectBean { FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(severity, "", msg)); } + public int getPluginID(final MIPlugin plugin) { + return this.pluginMap.get(plugin); + } + + public int getRepositoryID(final MIRepository repository) { + return this.repositoryMap.get(repository); + } + + public int getPortID(final MIPort port) { + return this.portMap.get(port); + } + /** * This method searches a plugin by name (the name should be delivered using the toString-method of the object). * @@ -1037,8 +1038,8 @@ public final class CurrentWorkSpaceProjectBean { * The name of the plugin. * @return The plugin with the given name if it exists, null otherwise. */ - public MIPlugin getPluginByName(final String string) { - return this.pluginMap.get(string); + public MIPlugin getPluginByID(final String string) { + return this.pluginMap.get(Integer.parseInt(string)); } /** @@ -1048,8 +1049,8 @@ public final class CurrentWorkSpaceProjectBean { * The name of the port. * @return The port with the given name if it exists, null otherwise. */ - public MIPort getPortByName(final String string) { - return this.portMap.get(string); + public MIPort getPortByID(final String string) { + return this.portMap.get(Integer.parseInt(string)); } /** @@ -1059,7 +1060,7 @@ public final class CurrentWorkSpaceProjectBean { * The name of the repository. * @return The plugin with the given name if it exists, null otherwise. */ - public MIRepository getRepositoryByName(final String string) { - return this.repositoryMap.get(string); + public MIRepository getRepositoryByID(final String string) { + return this.repositoryMap.get(Integer.parseInt(string)); } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginStringConverter.java index bd9a3f9a..25bbaa1b 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginStringConverter.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPluginStringConverter.java @@ -26,6 +26,7 @@ import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.FacesConverter; +import kieker.analysis.model.analysisMetaModel.MIPlugin; import kieker.webgui.beans.session.CurrentWorkSpaceProjectBean; /** @@ -54,15 +55,19 @@ public class MIPluginStringConverter implements Converter { final CurrentWorkSpaceProjectBean bean = (CurrentWorkSpaceProjectBean) el.getValue(FacesContext.getCurrentInstance().getELContext(), null, "currentWorkSpaceProjectBean"); - return bean.getPluginByName(string); + return bean.getPluginByID(string); } @Override public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { + final ELResolver el = FacesContext.getCurrentInstance().getApplication().getELResolver(); + final CurrentWorkSpaceProjectBean bean = (CurrentWorkSpaceProjectBean) el.getValue(FacesContext.getCurrentInstance().getELContext(), null, + "currentWorkSpaceProjectBean"); + if (o == null) { return ""; } else { - return o.toString(); + return Integer.toString(bean.getPluginID((MIPlugin) o)); } } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortStringConverter.java index 3f43960a..e8325d8f 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortStringConverter.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIPortStringConverter.java @@ -26,6 +26,7 @@ import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.FacesConverter; +import kieker.analysis.model.analysisMetaModel.MIPort; import kieker.webgui.beans.session.CurrentWorkSpaceProjectBean; /** @@ -54,15 +55,19 @@ public class MIPortStringConverter implements Converter { final CurrentWorkSpaceProjectBean bean = (CurrentWorkSpaceProjectBean) el.getValue(FacesContext.getCurrentInstance() .getELContext(), null, "currentWorkSpaceProjectBean"); - return bean.getPortByName(string); + return bean.getPortByID(string); } @Override public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { + final ELResolver el = FacesContext.getCurrentInstance().getApplication().getELResolver(); + final CurrentWorkSpaceProjectBean bean = (CurrentWorkSpaceProjectBean) el.getValue(FacesContext.getCurrentInstance().getELContext(), null, + "currentWorkSpaceProjectBean"); + if (o == null) { return ""; } else { - return o.toString(); + return Integer.toString(bean.getPortID((MIPort) o)); } } } diff --git a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIRepositoryStringConverter.java b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIRepositoryStringConverter.java index 51b25e76..60a515c2 100644 --- a/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIRepositoryStringConverter.java +++ b/Kieker.WebGUI/src/main/java/kieker/webgui/converter/MIRepositoryStringConverter.java @@ -26,6 +26,7 @@ import javax.faces.context.FacesContext; import javax.faces.convert.Converter; import javax.faces.convert.FacesConverter; +import kieker.analysis.model.analysisMetaModel.MIRepository; import kieker.webgui.beans.session.CurrentWorkSpaceProjectBean; /** @@ -54,15 +55,19 @@ public class MIRepositoryStringConverter implements Converter { final CurrentWorkSpaceProjectBean bean = (CurrentWorkSpaceProjectBean) el.getValue(FacesContext.getCurrentInstance() .getELContext(), null, "currentWorkSpaceProjectBean"); - return bean.getRepositoryByName(string); + return bean.getRepositoryByID(string); } @Override public String getAsString(final FacesContext fc, final UIComponent uic, final Object o) { + final ELResolver el = FacesContext.getCurrentInstance().getApplication().getELResolver(); + final CurrentWorkSpaceProjectBean bean = (CurrentWorkSpaceProjectBean) el.getValue(FacesContext.getCurrentInstance().getELContext(), null, + "currentWorkSpaceProjectBean"); + if (o == null) { return ""; } else { - return o.toString(); + return Integer.toString(bean.getRepositoryID((MIRepository) o)); } } } diff --git a/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml b/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml index 3603add5..d7179a7b 100644 --- a/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml +++ b/Kieker.WebGUI/src/main/webapp/AnalysisEditor.xhtml @@ -4,7 +4,8 @@ xmlns:h="http://java.sun.com/jsf/html" xmlns:ui="http://java.sun.com/jsf/facelets" xmlns:f="http://java.sun.com/jsf/core" - xmlns:p="http://primefaces.org/ui"> + xmlns:p="http://primefaces.org/ui" + xmlns:c="http://java.sun.com/jsp/jstl/core"> <h:head> <title>Kieker.WebGUI</title> @@ -13,12 +14,12 @@ <script type="text/javascript" src="../js/js-graph-it.js"/> <link rel="stylesheet" type="text/css" href="../css/js-graph-it.css"/> <style> - .canvas { - font-family: tahoma; - } .block { position: absolute; } + .connector { + background-color: #FF9900; + } </style> </h:head> @@ -32,9 +33,9 @@ <h:outputText styleClass="kieker-title" value="Kieker » #{stringBean.shortenLongName(currentWorkSpaceProjectBean.projectName, 30)}"/> </p:toolbarGroup> <p:toolbarGroup align="right"> - <p:commandButton styleClass="perspective-button" icon="ui-icon-home" disabled="true" /> + <p:commandButton styleClass="perspective-button" icon="ui-icon-home" /> <p:separator/> - <p:commandButton styleClass="perspective-button" icon="ui-icon-wrench" value="Analysis Editor" style="white-space: none" ajax="false" action="#{currentWorkSpaceProjectBean.setProject(projectsBean.openProject(project), project)}"/> + <p:commandButton styleClass="perspective-button" icon="ui-icon-wrench" value="Analysis Editor" style="white-space: none" disabled="true" ajax="false" action="#{currentWorkSpaceProjectBean.setProject(projectsBean.openProject(project), project)}"/> <p:commandButton styleClass="perspective-button" icon="ui-icon-circle-triangle-e" value="Analysis" ajax="false" action="#{currentControllerBean.setProject(projectsBean.openProject(project), project)}" /> <p:separator/> <p:commandButton styleClass="perspective-button" icon="ui-icon-wrench" value="Cockpit Editor" ajax="false" action="#{currentCockpitEditorBean.setProject(projectsBean.openProject(project), project)}" /> @@ -75,7 +76,7 @@ <ui:repeat value="#{currentWorkSpaceProjectBean.project.plugins}" var="plugin" varStatus="counter"> <p:remoteCommand name="setPlugin#{counter.index}" action="#{currentWorkSpaceProjectBean.setSelectedPlugin(plugin)}" update=":propertiesForm"/> <!-- Netbeans reports an error here, but the code does still work though... --> - <div onclick="setPlugin#{counter.index}();" style="left: #{counter.index * 90}px; top: #{counter.index * 70}px; position: absolute" class="ui-panel ui-widget ui-widget-content ui-corner-all block draggable" id="#{stringToIDBean.stringToID(plugin)}" > + <div onclick="setPlugin#{counter.index}();" style="left: #{counter.index * 90}px; top: #{counter.index * 70}px; position: absolute" class="ui-panel ui-widget ui-widget-content ui-corner-all block draggable" id="plugin#{currentWorkSpaceProjectBean.getPluginID(plugin)}" > <div class="ui-panel-titlebar ui-widget-header ui-corner-all"> <h:outputText style="font-weight: bold" value="#{plugin.getName()}"/> </div> @@ -85,13 +86,28 @@ <ui:repeat value="#{currentWorkSpaceProjectBean.project.repositories}" var="repository" varStatus="counter"> <p:remoteCommand name="setRepository#{counter.index}" action="#{currentWorkSpaceProjectBean.setSelectedRepository(repository)}" update=":propertiesForm"/> <!-- Netbeans reports an error here, but the code does still work though... --> - <div onclick="setRepository#{counter.index}();" style="left: #{(currentWorkSpaceProjectBean.project.plugins.size() + counter.index) * 90}px; top: #{counter.index * 70}px; position: absolute" class="ui-panel ui-widget ui-widget-content ui-corner-all block draggable" id="#{stringToIDBean.stringToID(repository)}" > + <div onclick="setRepository#{counter.index}();" style="left: #{(currentWorkSpaceProjectBean.project.plugins.size() + counter.index) * 90}px; top: #{counter.index * 70}px; position: absolute" class="ui-panel ui-widget ui-widget-content ui-corner-all block draggable" id="repository#{currentWorkSpaceProjectBean.getRepositoryID(repository)}" > <div class="ui-panel-titlebar ui-widget-header ui-corner-all"> <h:outputText style="font-weight: bold" value="#{repository.getName()}"/> </div> <p:commandLink ajax="true" value="Remove" action="#{currentWorkSpaceProjectBean.removeRepository(repository)}" update=":propertiesForm :centerForm"/> </div> </ui:repeat> + + <ui:repeat value="#{currentWorkSpaceProjectBean.filterConnections}" var="connection"> + <div class="connector plugin#{currentWorkSpaceProjectBean.getPluginID(connection.source)} plugin#{currentWorkSpaceProjectBean.getPluginID(connection.destination)}"> + <label class="source-label"><h:outputText value="#{connection.outputPort.getName()}"/></label> + <label class="destination-label"><h:outputText value="#{connection.inputPort.getName()}"/></label> + <img src="../img/arrow.gif" class="connector-end"/> + </div> + </ui:repeat> + + <ui:repeat value="#{currentWorkSpaceProjectBean.repoConnections}" var="connection"> + <div class="connector plugin#{currentWorkSpaceProjectBean.getPluginID(connection.source)} repository#{currentWorkSpaceProjectBean.getRepositoryID(connection.destination)}"> + <label class="source-label"><h:outputText value="#{connection.outputPort.getName()}"/></label> + <img src="../img/arrow.gif" class="connector-end"/> + </div> + </ui:repeat> </div> </h:form> </p:layoutUnit> @@ -112,7 +128,7 @@ </f:facet> <f:facet name="input"> <h:inputText value="#{property.value}" rendered="#{not stringBean.checkString(property)}"/> - <h:inputText value="#{currentWorkSpaceProjectBean.currentPluginName}" rendered="#{stringBean.checkString(property)}"/> + <h:inputText value="#{currentWorkSpaceProjectBean.selectedPlugin.name}" rendered="#{stringBean.checkString(property)}"/> </f:facet> </p:cellEditor> </p:column> diff --git a/Kieker.WebGUI/src/main/webapp/WEB-INF/shiro.ini b/Kieker.WebGUI/src/main/webapp/WEB-INF/shiro.ini new file mode 100644 index 00000000..d9c8f025 --- /dev/null +++ b/Kieker.WebGUI/src/main/webapp/WEB-INF/shiro.ini @@ -0,0 +1,17 @@ +# ======================= +# Shiro INI configuration +# ======================= + +[main] + +authc.loginUrl = /Kieker.WebGUI/login + +securityManager.rememberMeManager.cookie.name = KiekerWebGuiLoginCookie +securityManager.rememberMeManager.cookie.maxAge = 10000 + +[users] +Nils = kieker + +[roles] + +[urls] diff --git a/Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml b/Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml index e19427b2..3f5fc4d3 100644 --- a/Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml +++ b/Kieker.WebGUI/src/main/webapp/WEB-INF/web.xml @@ -26,7 +26,7 @@ </filter-mapping> <!-- This here makes sure that the theme chooser of PrimeFaces will work. --> - <context-param> + <context-param> <param-name>primefaces.THEME</param-name> <param-value>#{currentThemeBean.theme}</param-value> </context-param> @@ -70,4 +70,23 @@ <dispatcher>ERROR</dispatcher> </filter-mapping> + <!-- The following is necessary for Apache Shiro. --> + <listener> + <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class> + </listener> + + <filter> + <filter-name>ShiroFilter</filter-name> + <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class> + </filter> + + <filter-mapping> + <filter-name>ShiroFilter</filter-name> + <url-pattern>/*</url-pattern> + <dispatcher>REQUEST</dispatcher> + <dispatcher>FORWARD</dispatcher> + <dispatcher>INCLUDE</dispatcher> + <dispatcher>ERROR</dispatcher> + </filter-mapping> + </web-app> -- GitLab