1
16 package org.springframework.data.auditing;
17
18 import java.time.temporal.TemporalAccessor;
19 import java.util.Optional;
20
21 import org.joda.time.DateTime;
22 import org.slf4j.Logger;
23 import org.slf4j.LoggerFactory;
24 import org.springframework.aop.support.AopUtils;
25 import org.springframework.beans.factory.InitializingBean;
26 import org.springframework.data.domain.Auditable;
27 import org.springframework.data.domain.AuditorAware;
28 import org.springframework.data.mapping.PersistentEntity;
29 import org.springframework.data.mapping.PersistentProperty;
30 import org.springframework.data.mapping.context.MappingContext;
31 import org.springframework.data.mapping.context.PersistentEntities;
32 import org.springframework.util.Assert;
33
34
41 public class AuditingHandler implements InitializingBean {
42
43 private static final Logger LOGGER = LoggerFactory.getLogger(AuditingHandler.class);
44
45 private final DefaultAuditableBeanWrapperFactory factory;
46
47 private DateTimeProvider dateTimeProvider = CurrentDateTimeProvider.INSTANCE;
48 private Optional<AuditorAware<?>> auditorAware;
49 private boolean dateTimeForNow = true;
50 private boolean modifyOnCreation = true;
51
52
60 @Deprecated
61 public AuditingHandler(
62 MappingContext<? extends PersistentEntity<?, ?>, ? extends PersistentProperty<?>> mappingContext) {
63 this(PersistentEntities.of(mappingContext));
64 }
65
66
73 public AuditingHandler(PersistentEntities entities) {
74
75 Assert.notNull(entities, "PersistentEntities must not be null!");
76
77 this.factory = new MappingAuditableBeanWrapperFactory(entities);
78 this.auditorAware = Optional.empty();
79 }
80
81
86 public void setAuditorAware(AuditorAware<?> auditorAware) {
87
88 Assert.notNull(auditorAware, "AuditorAware must not be null!");
89 this.auditorAware = Optional.of(auditorAware);
90 }
91
92
99 public void setDateTimeForNow(boolean dateTimeForNow) {
100 this.dateTimeForNow = dateTimeForNow;
101 }
102
103
109 public void setModifyOnCreation(boolean modifyOnCreation) {
110 this.modifyOnCreation = modifyOnCreation;
111 }
112
113
118 public void setDateTimeProvider(DateTimeProvider dateTimeProvider) {
119 this.dateTimeProvider = dateTimeProvider == null ? CurrentDateTimeProvider.INSTANCE : dateTimeProvider;
120 }
121
122
127 public <T> T markCreated(T source) {
128
129 Assert.notNull(source, "Entity must not be null!");
130
131 return touch(source, true);
132 }
133
134
139 public <T> T markModified(T source) {
140
141 Assert.notNull(source, "Entity must not be null!");
142
143 return touch(source, false);
144 }
145
146
152 protected final boolean isAuditable(Object source) {
153
154 Assert.notNull(source, "Source must not be null!");
155
156 return factory.getBeanWrapperFor(source).isPresent();
157 }
158
159 private <T> T touch(T target, boolean isNew) {
160
161 Optional<AuditableBeanWrapper<T>> wrapper = factory.getBeanWrapperFor(target);
162
163 return wrapper.map(it -> {
164
165 Optional<Object> auditor = touchAuditor(it, isNew);
166 Optional<TemporalAccessor> now = dateTimeForNow ? touchDate(it, isNew) : Optional.empty();
167
168 if (LOGGER.isDebugEnabled()) {
169
170 Object defaultedNow = now.map(Object::toString).orElse("not set");
171 Object defaultedAuditor = auditor.map(Object::toString).orElse("unknown");
172
173 LOGGER.debug("Touched {} - Last modification at {} by {}", target, defaultedNow, defaultedAuditor);
174 }
175
176 return it.getBean();
177
178 }).orElse(target);
179 }
180
181
187 private Optional<Object> touchAuditor(AuditableBeanWrapper<?> wrapper, boolean isNew) {
188
189 Assert.notNull(wrapper, "AuditableBeanWrapper must not be null!");
190
191 return auditorAware.map(it -> {
192
193 Optional<?> auditor = it.getCurrentAuditor();
194
195 Assert.notNull(auditor,
196 () -> String.format("Auditor must not be null! Returned by: %s!", AopUtils.getTargetClass(it)));
197
198 auditor.filter(__ -> isNew).ifPresent(foo -> wrapper.setCreatedBy(foo));
199 auditor.filter(__ -> !isNew || modifyOnCreation).ifPresent(foo -> wrapper.setLastModifiedBy(foo));
200
201 return auditor;
202 });
203 }
204
205
211 private Optional<TemporalAccessor> touchDate(AuditableBeanWrapper<?> wrapper, boolean isNew) {
212
213 Assert.notNull(wrapper, "AuditableBeanWrapper must not be null!");
214
215 Optional<TemporalAccessor> now = dateTimeProvider.getNow();
216
217 Assert.notNull(now, () -> String.format("Now must not be null! Returned by: %s!", dateTimeProvider.getClass()));
218
219 now.filter(__ -> isNew).ifPresent(it -> wrapper.setCreatedDate(it));
220 now.filter(__ -> !isNew || modifyOnCreation).ifPresent(it -> wrapper.setLastModifiedDate(it));
221
222 return now;
223 }
224
225
229 public void afterPropertiesSet() {
230
231 if (!auditorAware.isPresent()) {
232 LOGGER.debug("No AuditorAware set! Auditing will not be applied!");
233 }
234 }
235 }
236