diff --git a/core/src/main/java/org/acegisecurity/config/LogoutFilterBeanDefinitionParser.java b/core/src/main/java/org/acegisecurity/config/LogoutFilterBeanDefinitionParser.java
new file mode 100644
index 0000000000..246aa513b2
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/config/LogoutFilterBeanDefinitionParser.java
@@ -0,0 +1,69 @@
+/**
+ *
+ */
+package org.acegisecurity.config;
+
+import org.acegisecurity.ui.logout.LogoutFilter;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.config.BeanDefinitionHolder;
+import org.springframework.beans.factory.support.AbstractBeanDefinition;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
+import org.springframework.beans.factory.xml.ParserContext;
+import org.springframework.util.StringUtils;
+import org.w3c.dom.Element;
+
+/**
+ * @author vpuri
+ * @since
+ */
+public class LogoutFilterBeanDefinitionParser extends AbstractBeanDefinitionParser {
+
+ // ~ Instance fields
+ // ================================================================================================
+ private static final String REDIRECT_AFTER_LOGOUT_URL = "redirectAfterLogoutUrl";
+
+ private static final String LOGOUT_URL = "logoutUrl";
+
+ // ~ Methods
+ // ================================================================================================
+
+ protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
+
+ // add the properties
+ RootBeanDefinition definition = new RootBeanDefinition(LogoutFilter.class);
+ setConstructorArgumentIfAvailable(0, element, REDIRECT_AFTER_LOGOUT_URL, "logoutSuccessUrl", definition);
+ // setPropertyIfAvailable(element,
+ // element.getAttribute(REDIRECT_AFTER_LOGOUT_URL), "logoutSuccessUrl",
+ // definition);
+ setPropertyIfAvailable(element, LOGOUT_URL, "filterProcessesUrl", definition);
+
+ // register BFPP to check if LogoutFilter does not have setHandlers
+ // populated, introspect app ctx for LogoutHandlers, using Ordered (if
+ // present, otherwise assume Integer.MAX_VALUE)
+ RootBeanDefinition bfpp = new RootBeanDefinition(LogoutHandlerOrderResolver.class);
+ parserContext.getReaderContext().registerWithGeneratedName(bfpp);
+
+ return definition;
+ }
+
+ private void setConstructorArgumentIfAvailable(int index, Element element, String attribute, String property,
+ RootBeanDefinition definition) {
+ String propertyValue = element.getAttribute(attribute);
+ if (StringUtils.hasText(propertyValue)) {
+ definition.getConstructorArgumentValues().addIndexedArgumentValue(index, propertyValue);
+ }
+ }
+
+ private void setPropertyIfAvailable(Element element, String attribute, String property,
+ RootBeanDefinition definition) {
+ String propertyValue = element.getAttribute(attribute);
+ if (StringUtils.hasText(propertyValue)) {
+ definition.getPropertyValues().addPropertyValue(property, propertyValue);
+ }
+ }
+
+ //
+
+}
diff --git a/core/src/main/java/org/acegisecurity/config/LogoutHandlerOrderResolver.java b/core/src/main/java/org/acegisecurity/config/LogoutHandlerOrderResolver.java
new file mode 100644
index 0000000000..04037c21a3
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/config/LogoutHandlerOrderResolver.java
@@ -0,0 +1,89 @@
+/**
+ *
+ */
+package org.acegisecurity.config;
+
+import java.util.Collections;
+import java.util.List;
+
+import org.acegisecurity.ui.logout.LogoutFilter;
+import org.acegisecurity.ui.logout.LogoutHandler;
+import org.acegisecurity.ui.logout.SecurityContextLogoutHandler;
+import org.acegisecurity.ui.rememberme.TokenBasedRememberMeServices;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
+import org.springframework.beans.factory.support.ManagedList;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.core.OrderComparator;
+import org.springframework.core.Ordered;
+
+/**
+ * @author vpuri
+ * @since
+ */
+public class LogoutHandlerOrderResolver implements BeanFactoryPostProcessor {
+
+ // ~ Methods
+ // ================================================================================================
+
+ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
+ // If LogoutFilter does not have setHandlers populated, introspect app
+ // ctx for LogoutHandlers, using Ordered (if present, otherwise assume
+ // Integer.MAX_VALUE)
+ String[] names = beanFactory.getBeanNamesForType(LogoutFilter.class);
+ RootBeanDefinition definition = (RootBeanDefinition) beanFactory.getBeanDefinition(names[0]);
+ ValueHolder holder = getHandlersIfConfigured(beanFactory, definition);
+ if (holder == null) {
+ // intropect the appcontext for registerd LogoutHandler
+ List logoutHandlers = retrieveAllLogoutHandlers(beanFactory);
+ definition.getConstructorArgumentValues().addIndexedArgumentValue(1, logoutHandlers);
+ }
+ }
+
+ /**
+ *
+ * @param beanFactory
+ * @param definition
+ * @return
+ */
+ private ValueHolder getHandlersIfConfigured(ConfigurableListableBeanFactory beanFactory,
+ RootBeanDefinition definition) {
+ // there should be only one LogoutFilter
+ return definition.getConstructorArgumentValues().getArgumentValue(1, null);
+
+ }
+
+ /**
+ *
+ * @param beanFactory
+ * @return
+ */
+ private List retrieveAllLogoutHandlers(ConfigurableListableBeanFactory beanFactory) {
+ String[] names = beanFactory.getBeanNamesForType(LogoutHandler.class);
+ ManagedList list = new ManagedList();
+
+ for (int i = 0, n = names.length; i < n; i++) {
+ RootBeanDefinition definition = (RootBeanDefinition) beanFactory.getBeanDefinition(names[i]);
+
+ if (Ordered.class.isAssignableFrom(definition.getBeanClass())) {
+ definition.getPropertyValues().addPropertyValue("order", getOrder(definition.getBeanClass()));
+ list.add(definition);
+ }
+ }
+ Collections.sort(list, new OrderComparator());
+ return list;
+ }
+
+ private int getOrder(Class clazz) {
+ if (clazz.getName().equals(TokenBasedRememberMeServices.class.getName())) {
+ return 0;
+ }
+ if (clazz.getName().equals(SecurityContextLogoutHandler.class.getName())) {
+ return 1;
+ }
+ return Integer.MAX_VALUE;
+ }
+
+}
diff --git a/core/src/test/java/org/acegisecurity/config/PrincipalRepositoryNamespaceTests.java b/core/src/test/java/org/acegisecurity/config/PrincipalRepositoryNamespaceTests.java
new file mode 100644
index 0000000000..3640d936e4
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/config/PrincipalRepositoryNamespaceTests.java
@@ -0,0 +1,66 @@
+/**
+ *
+ */
+package org.acegisecurity.config;
+
+import junit.framework.TestCase;
+
+import org.acegisecurity.GrantedAuthority;
+import org.acegisecurity.GrantedAuthorityImpl;
+import org.acegisecurity.userdetails.User;
+import org.acegisecurity.userdetails.UserDetailsService;
+import org.acegisecurity.userdetails.memory.InMemoryDaoImpl;
+import org.acegisecurity.userdetails.memory.UserMap;
+import org.springframework.beans.PropertyValue;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.beans.factory.support.RootBeanDefinition;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+/**
+ * @author vpuri
+ *
+ */
+public class PrincipalRepositoryNamespaceTests extends TestCase {
+
+ public void testParserWithUserDefinition() {
+ ApplicationContext context = new ClassPathXmlApplicationContext(
+ "org/acegisecurity/config/principal-repository-user-map.xml");
+
+ ConfigurableListableBeanFactory clbf = (ConfigurableListableBeanFactory) context
+ .getAutowireCapableBeanFactory();
+
+ String[] names = clbf.getBeanNamesForType(UserDetailsService.class);
+ assertEquals(1, names.length);
+
+ RootBeanDefinition definition = (RootBeanDefinition) clbf.getBeanDefinition(names[0]);
+ assertEquals(InMemoryDaoImpl.class, definition.getBeanClass());
+
+ UserMap map = new UserMap();
+
+ GrantedAuthority[] authotities = { new GrantedAuthorityImpl("ROLE_YO"), new GrantedAuthorityImpl("ROLE_YOYO") };
+
+ User user = new User("vishal", "nottellingya", true, true, true, true, authotities);
+
+ map.addUser(user);
+
+ assertPropertyValues(map, definition, "userMap");
+
+ }
+
+ private void assertPropertyValues(UserMap assertionValue, RootBeanDefinition definition, String property) {
+ PropertyValue propertyValue = definition.getPropertyValues().getPropertyValue(property);
+ assertNotNull(propertyValue);
+ assertTrue(propertyValue.getValue() instanceof UserMap);
+ UserMap users = (UserMap) propertyValue.getValue();
+ assertTrue(assertionValue.getUserCount() == users.getUserCount());
+ assertEquals(assertionValue.getUser("vishal"), users.getUser("vishal"));
+ assertTrue(users.getUser("vishal").isEnabled());
+ assertTrue(users.getUser("vishal").isAccountNonExpired());
+ assertTrue(users.getUser("vishal").isAccountNonLocked());
+ assertTrue(users.getUser("vishal").isCredentialsNonExpired());
+ assertEquals(2, users.getUser("vishal").getAuthorities().length);
+ assertEquals(new GrantedAuthorityImpl("ROLE_YO"), users.getUser("vishal").getAuthorities()[0]);
+ assertEquals(new GrantedAuthorityImpl("ROLE_YOYO"), users.getUser("vishal").getAuthorities()[1]);
+ }
+}
diff --git a/core/src/test/resources/org/acegisecurity/config/logout-filter-with-handlers.xml b/core/src/test/resources/org/acegisecurity/config/logout-filter-with-handlers.xml
new file mode 100644
index 0000000000..977261e59d
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/logout-filter-with-handlers.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/test/resources/org/acegisecurity/config/principal-repository.xml b/core/src/test/resources/org/acegisecurity/config/principal-repository-jdbc.xml
similarity index 88%
rename from core/src/test/resources/org/acegisecurity/config/principal-repository.xml
rename to core/src/test/resources/org/acegisecurity/config/principal-repository-jdbc.xml
index d417826faf..543b986f32 100644
--- a/core/src/test/resources/org/acegisecurity/config/principal-repository.xml
+++ b/core/src/test/resources/org/acegisecurity/config/principal-repository-jdbc.xml
@@ -14,8 +14,11 @@ http://www.springframework.org/schema/security file:/Users/vpuri/interface21/ace
+
+
+
-
+
-
+
\ No newline at end of file
diff --git a/core/src/test/resources/org/acegisecurity/config/principal-repository-properties.xml b/core/src/test/resources/org/acegisecurity/config/principal-repository-properties.xml
new file mode 100644
index 0000000000..dfe21d29e4
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/principal-repository-properties.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/test/resources/org/acegisecurity/config/principal-repository-user-map.xml b/core/src/test/resources/org/acegisecurity/config/principal-repository-user-map.xml
new file mode 100644
index 0000000000..4e035ff1d6
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/principal-repository-user-map.xml
@@ -0,0 +1,28 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/core/src/test/resources/org/acegisecurity/config/user.properties b/core/src/test/resources/org/acegisecurity/config/user.properties
new file mode 100644
index 0000000000..cd5f8e8b31
--- /dev/null
+++ b/core/src/test/resources/org/acegisecurity/config/user.properties
@@ -0,0 +1,2 @@
+vishal=ity,ROLE_ADMIN
+ity=vishal,ROLE_TELLER