Project

General

Profile

« Previous | Next » 

Revision 3dd6c00e

Added by Andreas Müller over 8 years ago

Upgrade to hibernate 5 with persistence tests running #4716

View differences:

cdmlib-services/src/main/java/eu/etaxonomy/cdm/api/validation/batch/BatchValidator.java
1
// $Id$
2
/**
3
 * Copyright (C) 2015 EDIT
4
 * European Distributed Institute of Taxonomy
5
 * http://www.e-taxonomy.eu
6
 *
7
 * The contents of this file are subject to the Mozilla Public License Version 1.1
8
 * See LICENSE.TXT at the top of this package for the full license terms.
9
 */
10
package eu.etaxonomy.cdm.api.validation.batch;
11

  
12
import java.util.List;
13
import java.util.Set;
14

  
15
import javax.validation.ConstraintViolation;
16
import javax.validation.Validation;
17
import javax.validation.Validator;
18
import javax.validation.ValidatorFactory;
19

  
20
import org.apache.log4j.Logger;
21
import org.hibernate.validator.HibernateValidator;
22
import org.hibernate.validator.HibernateValidatorConfiguration;
23
import org.springframework.context.ApplicationContext;
24
import org.springframework.context.ApplicationContextAware;
25
import org.springframework.orm.hibernate4.HibernateTransactionManager;
26
import org.springframework.stereotype.Component;
27
import org.springframework.transaction.PlatformTransactionManager;
28
import org.springframework.transaction.TransactionDefinition;
29
import org.springframework.transaction.TransactionStatus;
30
import org.springframework.transaction.support.DefaultTransactionDefinition;
31

  
32
import eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration;
33
import eu.etaxonomy.cdm.api.service.ICommonService;
34
import eu.etaxonomy.cdm.api.service.IEntityValidationService;
35
import eu.etaxonomy.cdm.api.service.IService;
36
import eu.etaxonomy.cdm.model.common.CdmBase;
37
import eu.etaxonomy.cdm.model.common.ICdmBase;
38
import eu.etaxonomy.cdm.model.validation.CRUDEventType;
39
import eu.etaxonomy.cdm.persistence.dao.jdbc.validation.EntityValidationCrudJdbcImpl;
40
import eu.etaxonomy.cdm.validation.Level2;
41
import eu.etaxonomy.cdm.validation.Level3;
42

  
43
/**
44
 * @author ayco_holleman
45
 * @author a.mueller
46
 * @date 27 jan. 2015
47
 *
48
 */
49
@Component("batchValidator")
50
public class BatchValidator implements Runnable, ApplicationContextAware {
51

  
52
    static final Class<?>[] DEFAULT_VALIDATION_GROUPS = new Class<?>[] { Level2.class, Level3.class };
53

  
54
    private static final Logger logger = Logger.getLogger(BatchValidator.class);
55

  
56

  
57
    private ICdmApplicationConfiguration repository;
58

  
59
    private ApplicationContext appContext;
60

  
61
    private Validator validator;
62
    private Class<?>[] validationGroups;
63

  
64

  
65
    @Override
66
    public void setApplicationContext(ApplicationContext appContext) {
67
        this.appContext = appContext;
68
    }
69

  
70
    @Override
71
    public void run() {
72
        Thread.currentThread().setPriority(1);
73
        initValidator();
74
        validate();
75
    }
76

  
77
    /**
78
     *
79
     */
80
    private void initValidator() {
81
        if (getValidator() == null){
82
            HibernateValidatorConfiguration config = Validation.byProvider(HibernateValidator.class).configure();
83
            ValidatorFactory factory = config.buildValidatorFactory();
84
            setValidator(factory.getValidator());
85
        }
86
        if (validationGroups == null) {
87
            validationGroups = DEFAULT_VALIDATION_GROUPS;
88
        }
89
    }
90

  
91

  
92

  
93
    private <T extends ICdmBase, S extends T> void validate() {
94
        logger.info("Starting batch validation");
95

  
96
       // Get service for saving errors to database
97
//        IEntityValidationService validationResultService = context.getEntityValidationService();
98
        IEntityValidationService entityValidationService = appContext.getBean(IEntityValidationService.class);
99

  
100
        EntityValidationCrudJdbcImpl jdbcPersister = appContext.getBean(EntityValidationCrudJdbcImpl.class);
101

  
102
        // Get all services dealing with "real" entities
103
        List<Class<CdmBase>> classesToValidate = BatchValidationUtil.getClassesToValidate();
104

  
105
        for (Class<CdmBase> entityClass : classesToValidate) {
106
            //TODO currently this seems to work only on the exact class, we may move it down
107
            //to single entity validation again but cache the information for each class
108
            if (true || BatchValidationUtil.isConstrainedEntityClass(validator, entityClass)){
109

  
110
    //          ICommonService commonService = repository.getCommonService();
111
                ICommonService commonService = appContext.getBean(ICommonService.class);
112
                logger.info("Loading entities of type " + entityClass.getName());
113
                //false for saving validation results
114
                //TODO can we handle results in a different transaction?
115
                boolean readOnly = false;
116
                TransactionStatus txStatus =  startTransaction(readOnly);
117
                handleSingleClass(commonService, entityClass, entityValidationService, jdbcPersister);
118
                commitTransaction(txStatus);
119
            }
120
        }
121

  
122
        logger.info("Batch validation complete");
123
    }
124

  
125
    /**
126
     * @param txStatus
127
     */
128
    private void commitTransaction(TransactionStatus txStatus) {
129
        PlatformTransactionManager txManager = getTransactionManager();
130
        txManager.commit(txStatus);
131

  
132
    }
133

  
134
    /**
135
     * @param readOnly
136
     * @return
137
     *
138
     */
139
    private TransactionStatus startTransaction(boolean readOnly) {
140
        PlatformTransactionManager txManager = getTransactionManager();
141

  
142
        DefaultTransactionDefinition defaultTxDef = new DefaultTransactionDefinition();
143
        defaultTxDef.setReadOnly(readOnly);
144
        TransactionDefinition txDef = defaultTxDef;
145
        TransactionStatus txStatus = txManager.getTransaction(txDef);
146
        return txStatus;
147
    }
148

  
149
    /**
150
     * @return
151
     */
152
    private PlatformTransactionManager getTransactionManager() {
153
        PlatformTransactionManager txManager = appContext.getBean(HibernateTransactionManager.class);
154
        return txManager;
155
    }
156

  
157
    private void handleSingleClass(ICommonService commonService, Class<CdmBase> entityClass, IEntityValidationService entityValidationService, EntityValidationCrudJdbcImpl jdbcPersister) {
158
        int n = commonService.count(entityClass);
159
        int pageSize = 1000;
160
        for (int page = 0; page < n ; page = page + pageSize ){
161
            handlePage(commonService, entityClass, entityValidationService, jdbcPersister,
162
                    page/pageSize, pageSize);
163
        }
164
    }
165

  
166

  
167
    /**
168
     * @param commonService
169
     * @param entityClass
170
     * @param entityValidationService
171
     * @param jdbcPersister
172
     *
173
     */
174
    private void handlePage(ICommonService commonService, Class<CdmBase> entityClass, IEntityValidationService entityValidationService, EntityValidationCrudJdbcImpl jdbcPersister, int start, int pageSize) {
175

  
176
        List<CdmBase> entities;
177

  
178
        try {
179
//            commonService.count()
180
            entities = commonService.list(entityClass, pageSize, 0, null, null);
181
        } catch (Throwable t) {
182
            //TODO handle exception
183
            logger.error("Failed to load entities", t);
184
            return;
185
        }
186
        for (CdmBase entity : entities) {
187
            try {
188
                Set<ConstraintViolation<CdmBase>> errors = getValidator().validate(entity, getValidationGroups());
189
                if (errors.size() != 0) {
190
                    if (logger.isInfoEnabled()){logger.info(errors.size() + " constraint violation(s) detected in entity " + entity.toString());}
191
//                    entityValidationService.saveEntityValidation(entity, errors, CRUDEventType.NONE,
192
//                            getValidationGroups());
193

  
194
                    jdbcPersister.saveEntityValidation(entity, errors, CRUDEventType.NONE, getValidationGroups());
195
                }
196
            } catch (Exception e) {
197
                // TODO Exception handling
198
                e.printStackTrace();
199
            }
200
        }
201

  
202
    }
203

  
204
    private <T extends ICdmBase, S extends T> void validate_old() {
205
        logger.info("Starting batch validation");
206

  
207
        if (validationGroups == null) {
208
            validationGroups = DEFAULT_VALIDATION_GROUPS;
209
        }
210

  
211
        // Get service for saving errors to database
212
        IEntityValidationService validationResultService = repository.getEntityValidationService();
213

  
214
        // Get all services dealing with "real" entities
215
        List<EntityValidationUnit<T, S>> validationUnits = BatchValidationUtil.getAvailableServices(repository);
216

  
217
        for (EntityValidationUnit<T, S> unit : validationUnits) {
218
            Class<S> entityClass = unit.getEntityClass();
219
            IService<T> entityLoader = unit.getEntityLoader();
220
            logger.info("Loading entities of type " + entityClass.getName());
221
            List<S> entities;
222
            try {
223
                entities = entityLoader.list(entityClass, 0, 0, null, null);
224
            } catch (Throwable t) {
225
                logger.error("Failed to load entities", t);
226
                continue;
227
            }
228
            for (S entity : entities) {
229
                if (BatchValidationUtil.isConstrainedEntityClass(getValidator(), entity.getClass())) {
230
                    Set<ConstraintViolation<S>> errors = getValidator().validate(entity, validationGroups);
231
                    if (errors.size() != 0) {
232
                        logger.warn(errors.size() + " error(s) detected in entity " + entity.toString());
233
                        validationResultService.saveEntityValidation(entity, errors, CRUDEventType.NONE,
234
                                validationGroups);
235
                    }
236
                }
237
            }
238
        }
239

  
240
        logger.info("Batch validation complete");
241
    }
242

  
243
    /**
244
     * Get the application context that will provide the services that will, on
245
     * their turn, provide the entities to be validated.
246
     *
247
     * @return The application context
248
     */
249
    public ICdmApplicationConfiguration getAppController() {
250
        return repository;
251
    }
252

  
253
    /**
254
     * Set the application context.
255
     *
256
     * @param context
257
     *            The application context
258
     */
259
    public void setAppController(ICdmApplicationConfiguration context) {
260
        this.repository = context;
261
    }
262

  
263
    /**
264
     * Get the {@code Validator} instance that will carry out the validations.
265
     *
266
     * @return The {@code Validator}
267
     */
268
    public Validator getValidator() {
269
        return validator;
270
    }
271

  
272
    /**
273
     * Set the {@code Validator} instance that will carry out the validations.
274
     *
275
     * @param validator
276
     *            The {@code Validator}
277
     */
278
    public void setValidator(Validator validator) {
279
        this.validator = validator;
280
    }
281

  
282
    /**
283
     * Get the validation groups to be applied by the {@code Validator}.
284
     *
285
     * @return The validation groups
286
     */
287
    public Class<?>[] getValidationGroups() {
288
        return validationGroups;
289
    }
290

  
291
    /**
292
     * Set the validation groups to be applied by the {@code Validator}. By
293
     * default all Level2 and Level3 will be checked. So if that is what you
294
     * want, you do not need to call this method before calling {@link #run()}.
295
     *
296
     * @param validationGroups
297
     *            The validation groups
298
     */
299
    public void setValidationGroups(Class<?>... validationGroups) {
300
        this.validationGroups = validationGroups;
301
    }
302

  
303
}
1
// $Id$
2
/**
3
 * Copyright (C) 2015 EDIT
4
 * European Distributed Institute of Taxonomy
5
 * http://www.e-taxonomy.eu
6
 *
7
 * The contents of this file are subject to the Mozilla Public License Version 1.1
8
 * See LICENSE.TXT at the top of this package for the full license terms.
9
 */
10
package eu.etaxonomy.cdm.api.validation.batch;
11

  
12
import java.util.List;
13
import java.util.Set;
14

  
15
import javax.validation.ConstraintViolation;
16
import javax.validation.Validation;
17
import javax.validation.Validator;
18
import javax.validation.ValidatorFactory;
19

  
20
import org.apache.log4j.Logger;
21
import org.hibernate.validator.HibernateValidator;
22
import org.hibernate.validator.HibernateValidatorConfiguration;
23
import org.springframework.context.ApplicationContext;
24
import org.springframework.context.ApplicationContextAware;
25
import org.springframework.orm.hibernate5.HibernateTransactionManager;
26
import org.springframework.stereotype.Component;
27
import org.springframework.transaction.PlatformTransactionManager;
28
import org.springframework.transaction.TransactionDefinition;
29
import org.springframework.transaction.TransactionStatus;
30
import org.springframework.transaction.support.DefaultTransactionDefinition;
31

  
32
import eu.etaxonomy.cdm.api.application.ICdmApplicationConfiguration;
33
import eu.etaxonomy.cdm.api.service.ICommonService;
34
import eu.etaxonomy.cdm.api.service.IEntityValidationService;
35
import eu.etaxonomy.cdm.api.service.IService;
36
import eu.etaxonomy.cdm.model.common.CdmBase;
37
import eu.etaxonomy.cdm.model.common.ICdmBase;
38
import eu.etaxonomy.cdm.model.validation.CRUDEventType;
39
import eu.etaxonomy.cdm.persistence.dao.jdbc.validation.EntityValidationCrudJdbcImpl;
40
import eu.etaxonomy.cdm.validation.Level2;
41
import eu.etaxonomy.cdm.validation.Level3;
42

  
43
/**
44
 * @author ayco_holleman
45
 * @author a.mueller
46
 * @date 27 jan. 2015
47
 *
48
 */
49
@Component("batchValidator")
50
public class BatchValidator implements Runnable, ApplicationContextAware {
51

  
52
    static final Class<?>[] DEFAULT_VALIDATION_GROUPS = new Class<?>[] { Level2.class, Level3.class };
53

  
54
    private static final Logger logger = Logger.getLogger(BatchValidator.class);
55

  
56

  
57
    private ICdmApplicationConfiguration repository;
58

  
59
    private ApplicationContext appContext;
60

  
61
    private Validator validator;
62
    private Class<?>[] validationGroups;
63

  
64

  
65
    @Override
66
    public void setApplicationContext(ApplicationContext appContext) {
67
        this.appContext = appContext;
68
    }
69

  
70
    @Override
71
    public void run() {
72
        Thread.currentThread().setPriority(1);
73
        initValidator();
74
        validate();
75
    }
76

  
77
    /**
78
     *
79
     */
80
    private void initValidator() {
81
        if (getValidator() == null){
82
            HibernateValidatorConfiguration config = Validation.byProvider(HibernateValidator.class).configure();
83
            ValidatorFactory factory = config.buildValidatorFactory();
84
            setValidator(factory.getValidator());
85
        }
86
        if (validationGroups == null) {
87
            validationGroups = DEFAULT_VALIDATION_GROUPS;
88
        }
89
    }
90

  
91

  
92

  
93
    private <T extends ICdmBase, S extends T> void validate() {
94
        logger.info("Starting batch validation");
95

  
96
       // Get service for saving errors to database
97
//        IEntityValidationService validationResultService = context.getEntityValidationService();
98
        IEntityValidationService entityValidationService = appContext.getBean(IEntityValidationService.class);
99

  
100
        EntityValidationCrudJdbcImpl jdbcPersister = appContext.getBean(EntityValidationCrudJdbcImpl.class);
101

  
102
        // Get all services dealing with "real" entities
103
        List<Class<CdmBase>> classesToValidate = BatchValidationUtil.getClassesToValidate();
104

  
105
        for (Class<CdmBase> entityClass : classesToValidate) {
106
            //TODO currently this seems to work only on the exact class, we may move it down
107
            //to single entity validation again but cache the information for each class
108
            if (true || BatchValidationUtil.isConstrainedEntityClass(validator, entityClass)){
109

  
110
    //          ICommonService commonService = repository.getCommonService();
111
                ICommonService commonService = appContext.getBean(ICommonService.class);
112
                logger.info("Loading entities of type " + entityClass.getName());
113
                //false for saving validation results
114
                //TODO can we handle results in a different transaction?
115
                boolean readOnly = false;
116
                TransactionStatus txStatus =  startTransaction(readOnly);
117
                handleSingleClass(commonService, entityClass, entityValidationService, jdbcPersister);
118
                commitTransaction(txStatus);
119
            }
120
        }
121

  
122
        logger.info("Batch validation complete");
123
    }
124

  
125
    /**
126
     * @param txStatus
127
     */
128
    private void commitTransaction(TransactionStatus txStatus) {
129
        PlatformTransactionManager txManager = getTransactionManager();
130
        txManager.commit(txStatus);
131

  
132
    }
133

  
134
    /**
135
     * @param readOnly
136
     * @return
137
     *
138
     */
139
    private TransactionStatus startTransaction(boolean readOnly) {
140
        PlatformTransactionManager txManager = getTransactionManager();
141

  
142
        DefaultTransactionDefinition defaultTxDef = new DefaultTransactionDefinition();
143
        defaultTxDef.setReadOnly(readOnly);
144
        TransactionDefinition txDef = defaultTxDef;
145
        TransactionStatus txStatus = txManager.getTransaction(txDef);
146
        return txStatus;
147
    }
148

  
149
    /**
150
     * @return
151
     */
152
    private PlatformTransactionManager getTransactionManager() {
153
        PlatformTransactionManager txManager = appContext.getBean(HibernateTransactionManager.class);
154
        return txManager;
155
    }
156

  
157
    private void handleSingleClass(ICommonService commonService, Class<CdmBase> entityClass, IEntityValidationService entityValidationService, EntityValidationCrudJdbcImpl jdbcPersister) {
158
        int n = commonService.count(entityClass);
159
        int pageSize = 1000;
160
        for (int page = 0; page < n ; page = page + pageSize ){
161
            handlePage(commonService, entityClass, entityValidationService, jdbcPersister,
162
                    page/pageSize, pageSize);
163
        }
164
    }
165

  
166

  
167
    /**
168
     * @param commonService
169
     * @param entityClass
170
     * @param entityValidationService
171
     * @param jdbcPersister
172
     *
173
     */
174
    private void handlePage(ICommonService commonService, Class<CdmBase> entityClass, IEntityValidationService entityValidationService, EntityValidationCrudJdbcImpl jdbcPersister, int start, int pageSize) {
175

  
176
        List<CdmBase> entities;
177

  
178
        try {
179
//            commonService.count()
180
            entities = commonService.list(entityClass, pageSize, 0, null, null);
181
        } catch (Throwable t) {
182
            //TODO handle exception
183
            logger.error("Failed to load entities", t);
184
            return;
185
        }
186
        for (CdmBase entity : entities) {
187
            try {
188
                Set<ConstraintViolation<CdmBase>> errors = getValidator().validate(entity, getValidationGroups());
189
                if (errors.size() != 0) {
190
                    if (logger.isInfoEnabled()){logger.info(errors.size() + " constraint violation(s) detected in entity " + entity.toString());}
191
//                    entityValidationService.saveEntityValidation(entity, errors, CRUDEventType.NONE,
192
//                            getValidationGroups());
193

  
194
                    jdbcPersister.saveEntityValidation(entity, errors, CRUDEventType.NONE, getValidationGroups());
195
                }
196
            } catch (Exception e) {
197
                // TODO Exception handling
198
                e.printStackTrace();
199
            }
200
        }
201

  
202
    }
203

  
204
    private <T extends ICdmBase, S extends T> void validate_old() {
205
        logger.info("Starting batch validation");
206

  
207
        if (validationGroups == null) {
208
            validationGroups = DEFAULT_VALIDATION_GROUPS;
209
        }
210

  
211
        // Get service for saving errors to database
212
        IEntityValidationService validationResultService = repository.getEntityValidationService();
213

  
214
        // Get all services dealing with "real" entities
215
        List<EntityValidationUnit<T, S>> validationUnits = BatchValidationUtil.getAvailableServices(repository);
216

  
217
        for (EntityValidationUnit<T, S> unit : validationUnits) {
218
            Class<S> entityClass = unit.getEntityClass();
219
            IService<T> entityLoader = unit.getEntityLoader();
220
            logger.info("Loading entities of type " + entityClass.getName());
221
            List<S> entities;
222
            try {
223
                entities = entityLoader.list(entityClass, 0, 0, null, null);
224
            } catch (Throwable t) {
225
                logger.error("Failed to load entities", t);
226
                continue;
227
            }
228
            for (S entity : entities) {
229
                if (BatchValidationUtil.isConstrainedEntityClass(getValidator(), entity.getClass())) {
230
                    Set<ConstraintViolation<S>> errors = getValidator().validate(entity, validationGroups);
231
                    if (errors.size() != 0) {
232
                        logger.warn(errors.size() + " error(s) detected in entity " + entity.toString());
233
                        validationResultService.saveEntityValidation(entity, errors, CRUDEventType.NONE,
234
                                validationGroups);
235
                    }
236
                }
237
            }
238
        }
239

  
240
        logger.info("Batch validation complete");
241
    }
242

  
243
    /**
244
     * Get the application context that will provide the services that will, on
245
     * their turn, provide the entities to be validated.
246
     *
247
     * @return The application context
248
     */
249
    public ICdmApplicationConfiguration getAppController() {
250
        return repository;
251
    }
252

  
253
    /**
254
     * Set the application context.
255
     *
256
     * @param context
257
     *            The application context
258
     */
259
    public void setAppController(ICdmApplicationConfiguration context) {
260
        this.repository = context;
261
    }
262

  
263
    /**
264
     * Get the {@code Validator} instance that will carry out the validations.
265
     *
266
     * @return The {@code Validator}
267
     */
268
    public Validator getValidator() {
269
        return validator;
270
    }
271

  
272
    /**
273
     * Set the {@code Validator} instance that will carry out the validations.
274
     *
275
     * @param validator
276
     *            The {@code Validator}
277
     */
278
    public void setValidator(Validator validator) {
279
        this.validator = validator;
280
    }
281

  
282
    /**
283
     * Get the validation groups to be applied by the {@code Validator}.
284
     *
285
     * @return The validation groups
286
     */
287
    public Class<?>[] getValidationGroups() {
288
        return validationGroups;
289
    }
290

  
291
    /**
292
     * Set the validation groups to be applied by the {@code Validator}. By
293
     * default all Level2 and Level3 will be checked. So if that is what you
294
     * want, you do not need to call this method before calling {@link #run()}.
295
     *
296
     * @param validationGroups
297
     *            The validation groups
298
     */
299
    public void setValidationGroups(Class<?>... validationGroups) {
300
        this.validationGroups = validationGroups;
301
    }
302

  
303
}

Also available in: Unified diff