diff --git a/changelog.txt b/changelog.txt
index 243552eff7..902b08b125 100644
--- a/changelog.txt
+++ b/changelog.txt
@@ -1,3 +1,8 @@
+Changes in version 0.7 (2004-xx-xx)
+-----------------------------------
+
+* Added MethodDefinitionSourceAdvisor for performance and autoproxying
+
Changes in version 0.6.1 (2004-09-25)
-------------------------------------
diff --git a/core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionSourceAdvisor.java b/core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionSourceAdvisor.java
new file mode 100644
index 0000000000..f347e3dd42
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/intercept/method/MethodDefinitionSourceAdvisor.java
@@ -0,0 +1,120 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * 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 net.sf.acegisecurity.intercept.method;
+
+import org.aopalliance.intercept.MethodInvocation;
+
+import org.springframework.aop.framework.AopConfigException;
+import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Method;
+
+
+/**
+ * Advisor driven by a {@link MethodDefinitionSource}, used to exclude a {@link
+ * MethodSecurityInterceptor} from public (ie non-secure) methods.
+ *
+ *
+ * Because the AOP framework caches advice calculations, this is normally
+ * faster than just letting the MethodSecurityInterceptor
run and
+ * find out itself that it has no work to do.
+ *
+ *
+ *
+ * This class also allows the use of Spring's
+ * DefaultAdvisorAutoProxyCreator
, which makes configuration
+ * easier than setup a ProxyFactoryBean
for each object requiring
+ * security. Note that autoproxying is not supported for BeanFactory
+ * implementations, as post-processing is automatic only for application
+ * contexts.
+ *
+ *
+ *
+ * Based on Spring's TransactionAttributeSourceAdvisor.
+ *
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MethodDefinitionSourceAdvisor
+ extends StaticMethodMatcherPointcutAdvisor {
+ //~ Instance fields ========================================================
+
+ private MethodDefinitionSource transactionAttributeSource;
+
+ //~ Constructors ===========================================================
+
+ public MethodDefinitionSourceAdvisor(MethodSecurityInterceptor advice) {
+ super(advice);
+
+ if (advice.getObjectDefinitionSource() == null) {
+ throw new AopConfigException(
+ "Cannot construct a MethodDefinitionSourceAdvisor using a "
+ + "MethodSecurityInterceptor that has no ObjectDefinitionSource configured");
+ }
+
+ this.transactionAttributeSource = advice.getObjectDefinitionSource();
+ }
+
+ //~ Methods ================================================================
+
+ public boolean matches(Method m, Class targetClass) {
+ MethodInvocation methodInvocation = new InternalMethodInvocation(m);
+
+ return (this.transactionAttributeSource.getAttributes(methodInvocation) != null);
+ }
+
+ //~ Inner Classes ==========================================================
+
+ /**
+ * Represents a MethodInvocation
.
+ *
+ *
+ * Required as MethodDefinitionSource
only supports lookup of
+ * configuration attributes for MethodInvocation
s.
+ *
+ */
+ private class InternalMethodInvocation implements MethodInvocation {
+ Method method;
+
+ public InternalMethodInvocation(Method method) {
+ this.method = method;
+ }
+
+ private InternalMethodInvocation() {}
+
+ public Object[] getArguments() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Method getMethod() {
+ return this.method;
+ }
+
+ public AccessibleObject getStaticPart() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getThis() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object proceed() throws Throwable {
+ throw new UnsupportedOperationException();
+ }
+ }
+}
diff --git a/core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionSourceAdvisorTests.java b/core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionSourceAdvisorTests.java
new file mode 100644
index 0000000000..4e6154bad9
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/intercept/method/MethodDefinitionSourceAdvisorTests.java
@@ -0,0 +1,98 @@
+/* Copyright 2004 Acegi Technology Pty Limited
+ *
+ * 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 net.sf.acegisecurity.intercept.method;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.TargetObject;
+
+import org.springframework.aop.framework.AopConfigException;
+
+import java.lang.reflect.Method;
+
+
+/**
+ * Tests {@link MethodDefinitionSourceAdvisor}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MethodDefinitionSourceAdvisorTests extends TestCase {
+ //~ Constructors ===========================================================
+
+ public MethodDefinitionSourceAdvisorTests() {
+ super();
+ }
+
+ public MethodDefinitionSourceAdvisorTests(String arg0) {
+ super(arg0);
+ }
+
+ //~ Methods ================================================================
+
+ public final void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(MethodDefinitionSourceAdvisorTests.class);
+ }
+
+ public void testAdvisorReturnsFalseWhenMethodInvocationNotDefined()
+ throws Exception {
+ Class clazz = TargetObject.class;
+ Method method = clazz.getMethod("makeLowerCase",
+ new Class[] {String.class});
+
+ MethodDefinitionSourceAdvisor advisor = new MethodDefinitionSourceAdvisor(getInterceptor());
+ assertFalse(advisor.matches(method, clazz));
+ }
+
+ public void testAdvisorReturnsTrueWhenMethodInvocationIsDefined()
+ throws Exception {
+ Class clazz = TargetObject.class;
+ Method method = clazz.getMethod("countLength",
+ new Class[] {String.class});
+
+ MethodDefinitionSourceAdvisor advisor = new MethodDefinitionSourceAdvisor(getInterceptor());
+ assertTrue(advisor.matches(method, clazz));
+ }
+
+ public void testDetectsImproperlyConfiguredAdvice() {
+ MethodSecurityInterceptor msi = new MethodSecurityInterceptor();
+
+ try {
+ new MethodDefinitionSourceAdvisor(msi);
+ fail(
+ "Should have detected null ObjectDefinitionSource and thrown AopConfigException");
+ } catch (AopConfigException expected) {
+ assertTrue(true);
+ }
+ }
+
+ private MethodSecurityInterceptor getInterceptor() {
+ MethodDefinitionSourceEditor editor = new MethodDefinitionSourceEditor();
+ editor.setAsText(
+ "net.sf.acegisecurity.TargetObject.countLength=ROLE_NOT_USED");
+
+ MethodDefinitionMap map = (MethodDefinitionMap) editor.getValue();
+
+ MethodSecurityInterceptor msi = new MethodSecurityInterceptor();
+ msi.setObjectDefinitionSource(map);
+
+ return msi;
+ }
+}
diff --git a/samples/attributes/src/applicationContext.xml b/samples/attributes/src/applicationContext.xml
index f8e0150755..643223e8a7 100644
--- a/samples/attributes/src/applicationContext.xml
+++ b/samples/attributes/src/applicationContext.xml
@@ -75,20 +75,23 @@
-
-
-
-
- securityInterceptor
-
-
+
+
+
-
-
-
-
-
-
-
+
+
+