Skip to content

Commit 6fd45a1

Browse files
authored
Merge pull request #112 from derjust/Issue_40
Auditing Support with Tests
2 parents c8a16ff + 6d2b887 commit 6fd45a1

File tree

18 files changed

+921
-5
lines changed

18 files changed

+921
-5
lines changed

pom.xml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,12 +241,12 @@
241241
<limit>
242242
<counter>BRANCH</counter>
243243
<value>COVEREDRATIO</value>
244-
<minimum>0.39</minimum>
244+
<minimum>0.47</minimum>
245245
</limit>
246246
<limit>
247247
<counter>LINE</counter>
248248
<value>COVEREDRATIO</value>
249-
<minimum>0.40</minimum>
249+
<minimum>0.55</minimum>
250250
</limit>
251251
</limits>
252252
</rule>
@@ -338,6 +338,7 @@
338338
<table>src/test/resources/feeduser_table.json</table>
339339
<table>src/test/resources/customerhistory_table.json</table>
340340
<table>src/test/resources/installation_table.json</table>
341+
<table>src/test/resources/auditable_user_table.json</table>
341342
</tables>
342343
<port>${dynamodblocal.port}</port>
343344
<dist>${project.build.directory}/dynamodb-dist</dist>
@@ -515,6 +516,10 @@
515516
<name>Michael Wyraz</name>
516517
<url>https://github.com/micw</url>
517518
</contributor>
519+
<contributor>
520+
<name>Vito Limandibhrata</name>
521+
<url>https://github.com/vitolimandibhrata</url>
522+
</contributor>
518523
</contributors>
519524

520525

src/changes/changes.xml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
</properties>
88
<body>
99
<release version="5.0.2" date="" description="Maintenance release">
10-
10+
<action dev="vitolimandibhrata" issue="40" type="add" date="2017-01-07">
11+
Added support for Auditing
12+
</action>
1113
</release>
1214
<release version="5.0.1" date="2018-01-06" description="Maintenance release">
1315
<action dev="derjust" issue="68" type="fix" date="2017-12-01" >
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/*
2+
* Copyright 2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.socialsignin.spring.data.dynamodb.config;
17+
18+
import com.amazonaws.auth.AWSCredentials;
19+
import com.amazonaws.services.dynamodbv2.AmazonDynamoDB;
20+
import com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBTable;
21+
import org.slf4j.Logger;
22+
import org.slf4j.LoggerFactory;
23+
import org.socialsignin.spring.data.dynamodb.mapping.DynamoDBMappingContext;
24+
import org.springframework.beans.factory.config.BeanDefinition;
25+
import org.springframework.context.annotation.Bean;
26+
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
27+
import org.springframework.context.annotation.Configuration;
28+
import org.springframework.core.type.filter.AnnotationTypeFilter;
29+
import org.springframework.util.ClassUtils;
30+
import org.springframework.util.StringUtils;
31+
32+
import java.util.HashSet;
33+
import java.util.Set;
34+
35+
/**
36+
* Base class for Spring Data DynamoDB configuration using JavaConfig.
37+
*
38+
* @author Vito Limandibhrata
39+
*/
40+
@Configuration
41+
public abstract class AbstractDynamoDBConfiguration {
42+
43+
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractDynamoDBConfiguration.class);
44+
45+
public abstract AmazonDynamoDB amazonDynamoDB();
46+
47+
public abstract AWSCredentials amazonAWSCredentials();
48+
49+
/**
50+
* Return the base packages to scan for mapped {@link DynamoDBTable}s. Will return the package name of the configuration
51+
* class' (the concrete class, not this one here) by default. So if you have a {@code com.acme.AppConfig} extending
52+
* {@link AbstractDynamoDBConfiguration} the base package will be considered {@code com.acme} unless the method is
53+
* overriden to implement alternate behaviour.
54+
*
55+
* @return the base package to scan for mapped {@link DynamoDBTable} classes or {@literal null} to not enable scanning for
56+
* entities.
57+
*/
58+
protected String[] getMappingBasePackages() {
59+
60+
Package mappingBasePackage = getClass().getPackage();
61+
String basePackage = mappingBasePackage == null ? null : mappingBasePackage.getName();
62+
63+
return new String[]{basePackage};
64+
}
65+
66+
/**
67+
* Creates a {@link DynamoDBMappingContext} equipped with entity classes scanned from the mapping base package.
68+
*
69+
* @see #getMappingBasePackages()
70+
* @return
71+
* @throws ClassNotFoundException
72+
*/
73+
@Bean
74+
public DynamoDBMappingContext dynamoDBMappingContext() throws ClassNotFoundException {
75+
76+
DynamoDBMappingContext mappingContext = new DynamoDBMappingContext();
77+
mappingContext.setInitialEntitySet(getInitialEntitySet());
78+
79+
return mappingContext;
80+
}
81+
82+
/**
83+
* Scans the mapping base package for classes annotated with {@link DynamoDBTable}.
84+
*
85+
* @see #getMappingBasePackages()
86+
* @return
87+
* @throws ClassNotFoundException
88+
*/
89+
protected Set<Class<?>> getInitialEntitySet() throws ClassNotFoundException {
90+
91+
Set<Class<?>> initialEntitySet = new HashSet<Class<?>>();
92+
93+
String[] basePackages = getMappingBasePackages();
94+
95+
for (String basePackage:basePackages) {
96+
LOGGER.trace("getInitialEntitySet. basePackage: {}", basePackage);
97+
98+
if (StringUtils.hasText(basePackage)) {
99+
ClassPathScanningCandidateComponentProvider componentProvider = new ClassPathScanningCandidateComponentProvider(
100+
false);
101+
componentProvider.addIncludeFilter(new AnnotationTypeFilter(DynamoDBTable.class));
102+
103+
for (BeanDefinition candidate : componentProvider.findCandidateComponents(basePackage)) {
104+
LOGGER.trace("getInitialEntitySet. candidate: {}", candidate.getBeanClassName());
105+
initialEntitySet.add(ClassUtils.forName(candidate.getBeanClassName(),
106+
AbstractDynamoDBConfiguration.class.getClassLoader()));
107+
}
108+
}
109+
}
110+
111+
return initialEntitySet;
112+
}
113+
114+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.socialsignin.spring.data.dynamodb.config;
17+
18+
/**
19+
* Constants to declare bean names used by the namespace configuration.
20+
*
21+
* @author Vito Limandibhrata
22+
*/
23+
public abstract class BeanNames {
24+
25+
public static final String MAPPING_CONTEXT_BEAN_NAME = "dynamoDBMappingContext";
26+
27+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright 2016 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.socialsignin.spring.data.dynamodb.config;
17+
18+
import org.socialsignin.spring.data.dynamodb.mapping.DynamoDBMappingContext;
19+
import org.socialsignin.spring.data.dynamodb.mapping.event.AuditingEventListener;
20+
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
21+
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
22+
import org.springframework.beans.factory.support.RootBeanDefinition;
23+
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
24+
import org.springframework.beans.factory.xml.ParserContext;
25+
import org.springframework.data.auditing.config.IsNewAwareAuditingHandlerBeanDefinitionParser;
26+
import org.springframework.util.StringUtils;
27+
import org.w3c.dom.Element;
28+
29+
import static org.socialsignin.spring.data.dynamodb.config.BeanNames.MAPPING_CONTEXT_BEAN_NAME;
30+
import static org.springframework.data.config.ParsingUtils.getObjectFactoryBeanDefinition;
31+
32+
/**
33+
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} to register a {@link AuditingEventListener} to transparently set auditing information on
34+
* an entity.
35+
*
36+
* @author Vito Limandibhrata
37+
*/
38+
public class DynamoDBAuditingBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
39+
40+
/*
41+
* (non-Javadoc)
42+
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#getBeanClass(org.w3c.dom.Element)
43+
*/
44+
@Override
45+
protected Class<?> getBeanClass(Element element) {
46+
return AuditingEventListener.class;
47+
}
48+
49+
/*
50+
* (non-Javadoc)
51+
* @see org.springframework.beans.factory.xml.AbstractBeanDefinitionParser#shouldGenerateId()
52+
*/
53+
@Override
54+
protected boolean shouldGenerateId() {
55+
return true;
56+
}
57+
58+
/*
59+
* (non-Javadoc)
60+
* @see org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser#doParse(org.w3c.dom.Element, org.springframework.beans.factory.xml.ParserContext, org.springframework.beans.factory.support.BeanDefinitionBuilder)
61+
*/
62+
@Override
63+
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
64+
65+
String mappingContextRef = element.getAttribute("mapping-context-ref");
66+
67+
if (!StringUtils.hasText(mappingContextRef)) {
68+
69+
BeanDefinitionRegistry registry = parserContext.getRegistry();
70+
71+
if (!registry.containsBeanDefinition(MAPPING_CONTEXT_BEAN_NAME)) {
72+
registry.registerBeanDefinition(MAPPING_CONTEXT_BEAN_NAME, new RootBeanDefinition(DynamoDBMappingContext.class));
73+
}
74+
75+
mappingContextRef = MAPPING_CONTEXT_BEAN_NAME;
76+
}
77+
78+
IsNewAwareAuditingHandlerBeanDefinitionParser parser = new IsNewAwareAuditingHandlerBeanDefinitionParser(
79+
mappingContextRef);
80+
parser.parse(element, parserContext);
81+
82+
builder.addConstructorArgValue(getObjectFactoryBeanDefinition(parser.getResolvedBeanName(),
83+
parserContext.extractSource(element)));
84+
}
85+
}

0 commit comments

Comments
 (0)