Skip to content

Commit f21723b

Browse files
authored
Merge branch 'master' into TRUNK-5804
2 parents f976ef4 + 84d4740 commit f21723b

File tree

52 files changed

+752
-463
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

52 files changed

+752
-463
lines changed

api/src/main/java/org/openmrs/ConceptNumeric.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public ConceptNumeric() {
6666
* @param conceptId key for this numeric concept
6767
*/
6868
public ConceptNumeric(Integer conceptId) {
69+
this();
6970
setConceptId(conceptId);
7071
}
7172

api/src/main/java/org/openmrs/annotation/AuthorizedAnnotationAttributes.java

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
import java.util.HashSet;
1818
import java.util.Set;
1919

20+
import org.springframework.core.annotation.AnnotationUtils;
21+
2022
/**
2123
* Annotation attributes metadata implementation used for authorization method interception.
2224
* <p>
@@ -66,14 +68,12 @@ public class AuthorizedAnnotationAttributes {
6668
*/
6769
public Collection<String> getAttributes(Class<?> target) {
6870
Set<String> attributes = new HashSet<>();
69-
for (Annotation annotation : target.getAnnotations()) {
70-
// check for Secured annotations
71-
if (annotation instanceof Authorized) {
72-
Authorized attr = (Authorized) annotation;
73-
Collections.addAll(attributes, attr.value());
74-
break;
75-
}
71+
72+
Authorized authorized = AnnotationUtils.findAnnotation(target, Authorized.class);
73+
if (authorized != null) {
74+
Collections.addAll(attributes, authorized.value());
7675
}
76+
7777
return attributes;
7878
}
7979

@@ -85,15 +85,12 @@ public Collection<String> getAttributes(Class<?> target) {
8585
*/
8686
public Collection<String> getAttributes(Method method) {
8787
Set<String> attributes = new HashSet<>();
88-
89-
for (Annotation annotation : method.getAnnotations()) {
90-
// check for Secured annotations
91-
if (annotation instanceof Authorized) {
92-
Authorized attr = (Authorized) annotation;
93-
Collections.addAll(attributes, attr.value());
94-
break;
95-
}
88+
89+
Authorized authorized = AnnotationUtils.findAnnotation(method, Authorized.class);
90+
if (authorized != null) {
91+
Collections.addAll(attributes, authorized.value());
9692
}
93+
9794
return attributes;
9895
}
9996

@@ -106,12 +103,9 @@ public Collection<String> getAttributes(Method method) {
106103
* @see org.openmrs.annotation.Authorized#requireAll()
107104
*/
108105
public boolean getRequireAll(Class<?> target) {
109-
for (Annotation annotation : target.getAnnotations()) {
110-
// check for Secured annotations
111-
if (annotation instanceof Authorized) {
112-
Authorized attr = (Authorized) annotation;
113-
return attr.requireAll();
114-
}
106+
Authorized authorized = AnnotationUtils.findAnnotation(target, Authorized.class);
107+
if (authorized != null) {
108+
return authorized.requireAll();
115109
}
116110
return false;
117111
}
@@ -125,12 +119,9 @@ public boolean getRequireAll(Class<?> target) {
125119
* @see org.openmrs.annotation.Authorized#requireAll()
126120
*/
127121
public boolean getRequireAll(Method method) {
128-
for (Annotation annotation : method.getAnnotations()) {
129-
// check for Secured annotations
130-
if (annotation instanceof Authorized) {
131-
Authorized attr = (Authorized) annotation;
132-
return attr.requireAll();
133-
}
122+
Authorized authorized = AnnotationUtils.findAnnotation(method, Authorized.class);
123+
if (authorized != null) {
124+
return authorized.requireAll();
134125
}
135126
return false;
136127
}
@@ -142,14 +133,9 @@ public boolean getRequireAll(Method method) {
142133
* @return boolean true/false whether this method is annotated for OpenMRS
143134
*/
144135
public boolean hasAuthorizedAnnotation(Method method) {
145-
for (Annotation annotation : method.getAnnotations()) {
146-
// check for Secured annotations
147-
if (annotation instanceof Authorized) {
148-
return true;
149-
}
150-
}
151-
152-
return false;
136+
Authorized authorized = AnnotationUtils.findAnnotation(method, Authorized.class);
137+
138+
return (authorized != null);
153139
}
154140

155141
public Collection<?> getAttributes(Class<?> clazz, Class<?> filter) {
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/**
2+
* This Source Code Form is subject to the terms of the Mozilla Public License,
3+
* v. 2.0. If a copy of the MPL was not distributed with this file, You can
4+
* obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under
5+
* the terms of the Healthcare Disclaimer located at http://openmrs.org/license.
6+
*
7+
* Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS
8+
* graphic logo is a trademark of OpenMRS Inc.
9+
*/
10+
package org.openmrs.aop;
11+
12+
import java.lang.reflect.Method;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
16+
import org.aopalliance.aop.Advice;
17+
import org.springframework.aop.Advisor;
18+
import org.springframework.aop.support.StaticMethodMatcherPointcutAdvisor;
19+
import org.springframework.cache.annotation.Cacheable;
20+
import org.springframework.cache.annotation.EnableCaching;
21+
import org.springframework.cache.interceptor.CacheInterceptor;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.context.annotation.Configuration;
24+
import org.springframework.context.annotation.EnableAspectJAutoProxy;
25+
import org.springframework.stereotype.Service;
26+
import org.springframework.transaction.annotation.AnnotationTransactionAttributeSource;
27+
import org.springframework.transaction.annotation.EnableTransactionManagement;
28+
import org.springframework.transaction.annotation.Transactional;
29+
import org.springframework.transaction.interceptor.TransactionAttributeSource;
30+
31+
/**
32+
* AOPConfig registers AOP advisors used across the OpenMRS service layer. It enables method-level interception using
33+
* AspectJ-style pointcuts and integrates multiple aspects such as authorization, logging, required data handling, and caching.
34+
* <p>
35+
* The advisors apply to all classes annotated with {@link Service}.
36+
*
37+
* <p>
38+
* The configured advisors include:
39+
* <ul>
40+
* <li><b>AuthorizationAdvisor</b> – Ensures access control based on authorization annotations.</li>
41+
* <li><b>LoggingAdvisor</b> – Logs service method invocations and exceptions for auditing and debugging.</li>
42+
* <li><b>RequiredDataAdvisor</b> – Automatically sets required metadata like `creator`, `dateCreated`, etc.</li>
43+
* <li><b>CacheInterceptor</b> - Supports caching for methods annotated with
44+
* {@link Cacheable}</li>
45+
* <li><b>TransactionalInterceptor</b> - Supports transactions for methods annotated with
46+
* {@link Transactional}</li>
47+
* </ul>
48+
* <p>
49+
* In order to add advisors from a module create beans wrapped with {@link #createAdvisor(Advice, Integer)}, see e.g.
50+
* {@link #authorizationAdvisor(AuthorizationAdvice)}. Please note the order should be null or higher than 100 in order
51+
* not to interfere with core advisors.
52+
*
53+
* <p>
54+
* This configuration replaces the older XML-based AOP setup.
55+
*
56+
* @since 3.0.0
57+
*/
58+
@Configuration
59+
@EnableTransactionManagement(order = 5, proxyTargetClass = true)
60+
@EnableCaching(order = 4, proxyTargetClass = true)
61+
@EnableAspectJAutoProxy(proxyTargetClass = true)
62+
public class AOPConfig {
63+
64+
/**
65+
* Added for backwards compatibility with services defined in xml with TransactionProxyFactoryBean
66+
* @param authorizationAdvice
67+
* @param loggingAdvice
68+
* @param requiredDataAdvice
69+
* @param cacheInterceptor
70+
* @return serviceInterceptors
71+
* @deprecated since 3.0.0 use {@link Service} annotation instead
72+
*/
73+
@Bean
74+
public List<Advice> serviceInterceptors(AuthorizationAdvice authorizationAdvice,
75+
LoggingAdvice loggingAdvice, RequiredDataAdvice requiredDataAdvice,
76+
CacheInterceptor cacheInterceptor) {
77+
List<Advice> interceptors = new ArrayList<>();
78+
interceptors.add(authorizationAdvice);
79+
interceptors.add(loggingAdvice);
80+
interceptors.add(requiredDataAdvice);
81+
interceptors.add(cacheInterceptor);
82+
return interceptors;
83+
}
84+
85+
/**
86+
* Added for backwards compatibility with services defined in xml with TransactionProxyFactoryBean
87+
*
88+
* @return transactionAttributeSource
89+
* @deprecated since 3.0.0 use {@link Service} annotation instead
90+
*/
91+
@Bean
92+
public TransactionAttributeSource transactionAttributeSource() {
93+
return new AnnotationTransactionAttributeSource();
94+
}
95+
96+
@Bean
97+
public Advisor authorizationAdvisor(AuthorizationAdvice advice) {
98+
return createAdvisor(advice, 1);
99+
}
100+
101+
@Bean
102+
public Advisor loggingAdvisor(LoggingAdvice advice) {
103+
return createAdvisor(advice, 2);
104+
}
105+
106+
@Bean
107+
public Advisor requiredDataAdvisor(RequiredDataAdvice advice) {
108+
return createAdvisor(advice,3);
109+
}
110+
111+
public Advisor createAdvisor(Advice advice, Integer order) {
112+
StaticMethodMatcherPointcutAdvisor advisor = new StaticMethodMatcherPointcutAdvisor(advice) {
113+
@Override
114+
public boolean matches(Method method, Class<?> targetClass) {
115+
return targetClass.isAnnotationPresent(Service.class);
116+
}
117+
};
118+
if (order != null) {
119+
advisor.setOrder(order);
120+
}
121+
return advisor;
122+
}
123+
}

api/src/main/java/org/openmrs/aop/AuthorizationAdvice.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,15 @@
2222
import org.slf4j.Logger;
2323
import org.slf4j.LoggerFactory;
2424
import org.springframework.aop.MethodBeforeAdvice;
25+
import org.springframework.core.Ordered;
26+
import org.springframework.core.annotation.Order;
27+
import org.springframework.stereotype.Component;
2528

2629
/**
2730
* This class provides the authorization AOP advice performed before every service layer method
2831
* call.
2932
*/
33+
@Component("authorizationInterceptor")
3034
public class AuthorizationAdvice implements MethodBeforeAdvice {
3135

3236
/**

api/src/main/java/org/openmrs/aop/LoggingAdvice.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,15 @@
2222
import org.openmrs.util.OpenmrsUtil;
2323
import org.slf4j.Logger;
2424
import org.slf4j.LoggerFactory;
25+
import org.springframework.core.annotation.AnnotationUtils;
26+
import org.springframework.stereotype.Component;
2527

2628
/**
2729
* This class provides the log4j aop around advice for our service layer. This advice is placed on
2830
* all services and daos via the spring application context. See
2931
* /metadata/api/spring/applicationContext.xml
3032
*/
33+
@Component("loggingInterceptor")
3134
public class LoggingAdvice implements MethodInterceptor {
3235

3336
/**
@@ -67,7 +70,7 @@ public Object invoke(MethodInvocation invocation) throws Throwable {
6770
// check if this method has the logging annotation on it
6871
Logging loggingAnnotation = null;
6972
if (logGetter || logSetter) {
70-
loggingAnnotation = method.getAnnotation(Logging.class);
73+
loggingAnnotation = AnnotationUtils.findAnnotation(method, Logging.class);
7174
if (loggingAnnotation != null && loggingAnnotation.ignore()) {
7275
logGetter = false;
7376
logSetter = false;

api/src/main/java/org/openmrs/aop/RequiredDataAdvice.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
import org.openmrs.util.Reflect;
4040
import org.openmrs.validator.ValidateUtil;
4141
import org.springframework.aop.MethodBeforeAdvice;
42-
import org.springframework.transaction.annotation.Transactional;
42+
import org.springframework.stereotype.Component;
4343
import org.springframework.util.StringUtils;
4444

4545
/**
@@ -78,6 +78,7 @@
7878
* @see VoidHandler
7979
* @since 1.5
8080
*/
81+
@Component("requiredDataInterceptor")
8182
public class RequiredDataAdvice implements MethodBeforeAdvice {
8283

8384
private static final String UNABLE_GETTER_METHOD = "unable.getter.method";

0 commit comments

Comments
 (0)