1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package fr.paris.lutece.plugins.identityimport.service;
35
36 import fr.paris.lutece.api.user.User;
37 import fr.paris.lutece.plugins.identityimport.business.Batch;
38 import fr.paris.lutece.plugins.identityimport.business.BatchHome;
39 import fr.paris.lutece.plugins.identityimport.business.CandidateIdentity;
40 import fr.paris.lutece.plugins.identityimport.business.CandidateIdentityAttribute;
41 import fr.paris.lutece.plugins.identityimport.business.CandidateIdentityAttributeHome;
42 import fr.paris.lutece.plugins.identityimport.business.CandidateIdentityHistory;
43 import fr.paris.lutece.plugins.identityimport.business.CandidateIdentityHistoryHome;
44 import fr.paris.lutece.plugins.identityimport.business.CandidateIdentityHome;
45 import fr.paris.lutece.plugins.identityimport.business.ResourceState;
46 import fr.paris.lutece.plugins.identityimport.wf.WorkflowBean;
47 import fr.paris.lutece.plugins.identityimport.wf.WorkflowBeanService;
48 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.common.AttributeDto;
49 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.common.BatchDto;
50 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.common.IdentityDto;
51 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.importing.BatchImportRequest;
52 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.importing.BatchResourceStateDto;
53 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.importing.BatchStatisticsDto;
54 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.importing.BatchStatusDto;
55 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.importing.BatchStatusMode;
56 import fr.paris.lutece.plugins.identitystore.v3.web.rs.dto.importing.ImportingHistoryDto;
57 import fr.paris.lutece.plugins.identitystore.v3.web.rs.util.Constants;
58 import fr.paris.lutece.plugins.identitystore.web.exception.IdentityStoreException;
59 import fr.paris.lutece.plugins.identitystore.web.exception.ResourceNotFoundException;
60 import fr.paris.lutece.plugins.workflowcore.business.resource.ResourceHistory;
61 import fr.paris.lutece.portal.service.progressmanager.ProgressManagerService;
62 import fr.paris.lutece.portal.service.spring.SpringContextService;
63 import fr.paris.lutece.portal.service.util.AppLogService;
64 import fr.paris.lutece.portal.service.util.AppPropertiesService;
65 import fr.paris.lutece.util.sql.TransactionManager;
66 import org.apache.commons.lang3.StringUtils;
67
68 import java.sql.Date;
69 import java.sql.Timestamp;
70 import java.time.Instant;
71 import java.util.List;
72 import java.util.Locale;
73 import java.util.Optional;
74 import java.util.UUID;
75
76 public class BatchService
77 {
78 private static final String BATCH_WFBEANSERVICE = "identityimport.batch.wfbeanservice";
79 private static final String CANDIDATEIDENTITY_WFBEANSERVICE = "identityimport.candidateidentity.wfbeanservice";
80
81 private static final int ARCHIVE_ACTION_ID = AppPropertiesService.getPropertyInt( "identityimport.archive.action.id", 0 );
82 private static final int VALIDATE_BATCH_ACTION_ID = AppPropertiesService.getPropertyInt( "identityimport.validate.action.id", 0 );
83
84 private static final String MESSAGE_KEY_BATCH_EXISTS_WITH_SAME_REFERENCE = "identityimport.error.batch.exists.with.same.reference";
85 private static final String MESSAGE_KEY_BATCH_ERROR_DURING_CREATION = "identityimport.error.batch.during.creation";
86
87 private final WorkflowBeanService<CandidateIdentity> _wfIdentityBeanService = SpringContextService.getBean( CANDIDATEIDENTITY_WFBEANSERVICE );
88 private final WorkflowBeanService<Batch> _wfBatchBeanService = SpringContextService.getBean( BATCH_WFBEANSERVICE );
89 private final ProgressManagerService progressManagerService = ProgressManagerService.getInstance( );
90 private final BatchValidationService validationService = BatchValidationService.instance( );
91
92 private static BatchService instance;
93
94 public static BatchService instance( )
95 {
96 if ( instance == null )
97 {
98 instance = new BatchService( );
99 }
100 return instance;
101 }
102
103 public String importBatchFromApi(final BatchImportRequest request, final String clientCode) throws IdentityStoreException {
104 final BatchDto batch = request.getBatch();
105 batch.setClientCode(clientCode);
106 do {
107 batch.setReference(UUID.randomUUID().toString());
108 } while (BatchHome.getBatch(batch.getReference()) != null);
109
110 TransactionManager.beginTransaction( null );
111 try
112 {
113 final Batch bean = this.getBean( batch );
114 bean.setCreationDate( Timestamp.from( Instant.now( ) ) );
115 BatchHome.create( bean );
116
117
118 final int batchId = bean.getId( );
119 final WorkflowBean<Batch> batchWorkflowBean = _wfBatchBeanService.createWorkflowBean( bean, batchId, null );
120
121
122 for ( final IdentityDto identity : batch.getIdentities( ) )
123 {
124 final CandidateIdentityess/CandidateIdentity.html#CandidateIdentity">CandidateIdentity candidateIdentity = new CandidateIdentity( );
125 candidateIdentity.setIdBatch( batchId );
126 candidateIdentity.setExternalCustomerId( identity.getExternalCustomerId( ) );
127 candidateIdentity.setConnectionId( identity.getConnectionId( ) );
128 candidateIdentity.setClientCode( bean.getClientCode( ) );
129 CandidateIdentityHome.create( candidateIdentity );
130 _wfIdentityBeanService.createWorkflowBean( candidateIdentity, candidateIdentity.getId( ), candidateIdentity.getIdBatch( ), null );
131
132 for ( final AttributeDto importedAttribute : identity.getAttributes( ) )
133 {
134 final CandidateIdentityAttributeateIdentityAttribute.html#CandidateIdentityAttribute">CandidateIdentityAttribute candidateAttribute = new CandidateIdentityAttribute( );
135 candidateAttribute.setIdIdentity( candidateIdentity.getId( ) );
136 candidateAttribute.setCode( importedAttribute.getKey( ) );
137 candidateAttribute.setValue( importedAttribute.getValue( ) );
138 candidateAttribute.setCertDate( Timestamp.from( importedAttribute.getCertificationDate( ).toInstant( ) ) );
139 candidateAttribute.setCertProcess( importedAttribute.getCertifier( ) );
140 CandidateIdentityAttributeHome.create( candidateAttribute );
141 }
142 }
143 TransactionManager.commitTransaction( null );
144 _wfBatchBeanService.processActionNoUser( batchWorkflowBean, VALIDATE_BATCH_ACTION_ID, null, Locale.getDefault( ) );
145 return batch.getReference();
146 }
147 catch( final Exception e )
148 {
149 TransactionManager.rollBack( null );
150 throw new IdentityStoreException( e.getMessage( ), e, MESSAGE_KEY_BATCH_ERROR_DURING_CREATION );
151 }
152 }
153
154 public int importBatchFromIhm(final BatchDto batch, final User user, final String feedToken) throws IdentityStoreException
155 {
156
157 validationService.validateImportBatchLimit( batch );
158
159 TransactionManager.beginTransaction( null );
160
161 try
162 {
163
164 if ( StringUtils.isNotEmpty( feedToken ) )
165 {
166 progressManagerService.initFeed( feedToken, batch.getIdentities( ).size( ) );
167 progressManagerService.addReport( feedToken, "Validating batch ..." );
168 }
169 validationService.validateBatchFromIhm(batch);
170
171
172 if ( StringUtils.isNotEmpty( feedToken ) )
173 {
174 progressManagerService.addReport( feedToken, "Creating batch..." );
175 }
176
177 if ( BatchHome.getBatch( batch.getReference( ) ) != null )
178 {
179 throw new IdentityStoreException( "A batch already exists with this reference.", MESSAGE_KEY_BATCH_EXISTS_WITH_SAME_REFERENCE );
180 }
181 final Batch bean = this.getBean( batch );
182 bean.setCreationDate( Timestamp.from( Instant.now( ) ) );
183 BatchHome.create( bean );
184
185
186 final int batchId = bean.getId( );
187 final WorkflowBean<Batch> batchWorkflowBean = _wfBatchBeanService.createWorkflowBean( bean, batchId, user );
188
189 if ( StringUtils.isNotEmpty( feedToken ) )
190 {
191 progressManagerService.addReport( feedToken, "Batch created with id " + batchId );
192 }
193
194
195 if ( StringUtils.isNotEmpty( feedToken ) )
196 {
197 progressManagerService.addReport( feedToken, "Creating candidate identities..." );
198 }
199 for ( final IdentityDto identity : batch.getIdentities( ) )
200 {
201 final CandidateIdentityess/CandidateIdentity.html#CandidateIdentity">CandidateIdentity candidateIdentity = new CandidateIdentity( );
202 candidateIdentity.setIdBatch( batchId );
203 candidateIdentity.setExternalCustomerId( identity.getExternalCustomerId( ) );
204 candidateIdentity.setConnectionId( identity.getConnectionId( ) );
205 candidateIdentity.setClientCode( bean.getClientCode( ) );
206 CandidateIdentityHome.create( candidateIdentity );
207 _wfIdentityBeanService.createWorkflowBean( candidateIdentity, candidateIdentity.getId( ), candidateIdentity.getIdBatch( ), user );
208
209 for ( final AttributeDto importedAttribute : identity.getAttributes( ) )
210 {
211 final CandidateIdentityAttributeateIdentityAttribute.html#CandidateIdentityAttribute">CandidateIdentityAttribute candidateAttribute = new CandidateIdentityAttribute( );
212 candidateAttribute.setIdIdentity( candidateIdentity.getId( ) );
213 candidateAttribute.setCode( importedAttribute.getKey( ) );
214 candidateAttribute.setValue( importedAttribute.getValue( ) );
215 candidateAttribute.setCertDate( Timestamp.from( importedAttribute.getCertificationDate( ).toInstant( ) ) );
216 candidateAttribute.setCertProcess( importedAttribute.getCertifier( ) );
217 CandidateIdentityAttributeHome.create( candidateAttribute );
218 }
219 if ( StringUtils.isNotEmpty( feedToken ) )
220 {
221 progressManagerService.incrementSuccess( feedToken, 1 );
222 }
223 }
224 if ( StringUtils.isNotEmpty( feedToken ) )
225 {
226 progressManagerService.addReport( feedToken, "Created" + batch.getIdentities( ).size( ) + " candidate identities" );
227 }
228 TransactionManager.commitTransaction( null );
229 _wfBatchBeanService.processActionNoUser( batchWorkflowBean, VALIDATE_BATCH_ACTION_ID, null, Locale.getDefault( ) );
230 return bean.getId( );
231 }
232 catch( final Exception e )
233 {
234 TransactionManager.rollBack( null );
235 if ( StringUtils.isNotEmpty( feedToken ) )
236 {
237 progressManagerService.addReport( feedToken, "An error occurred during creation..." );
238 }
239 if ( e instanceof IdentityStoreException )
240 {
241 throw e;
242 }
243 throw new IdentityStoreException( e.getMessage( ), e, MESSAGE_KEY_BATCH_ERROR_DURING_CREATION );
244 }
245 }
246
247
248
249
250
251
252
253
254 public StringBuilder purgeBatches( final int batchLimit ) throws IdentityStoreException
255 {
256 final StringBuilder msg = new StringBuilder( );
257 final List<Batch> expiredBatches = BatchHome.findExpiredBatches( batchLimit );
258 msg.append( expiredBatches.size( ) ).append( " expired batches found" ).append( System.lineSeparator( ) );
259
260 if ( ARCHIVE_ACTION_ID > 0 )
261 {
262 for ( final Batch expiredBatch : expiredBatches )
263 {
264 msg.append( "Removing expired batch : " ).append( expiredBatch.toLog( ) ).append( System.lineSeparator( ) );
265 final WorkflowBean<Batch> workflowBean = _wfBatchBeanService.createWorkflowBean( expiredBatch, expiredBatch.getId( ), null );
266 _wfBatchBeanService.processAutomaticAction( workflowBean, ARCHIVE_ACTION_ID, null, Locale.getDefault( ) );
267 }
268 }
269 else
270 {
271 AppLogService.error( "Property identityimport.archive.action.id must be defined in order to perform archiving task." );
272 }
273
274
275 return msg;
276 }
277
278
279
280
281
282
283
284
285 public void purgeBatch( final int batchId ) throws IdentityStoreException
286 {
287 final Optional<Batch> expiredBatch = BatchHome.findByPrimaryKey( batchId );
288 if ( expiredBatch.isPresent( ) )
289 {
290 final Batch batch = expiredBatch.get( );
291 TransactionManager.beginTransaction( null );
292
293 try
294 {
295 final List<Integer> idCandidateIdentitiesList = CandidateIdentityHome.getIdCandidateIdentitiesList( batch.getId( ), null );
296 CandidateIdentityHome.delete( idCandidateIdentitiesList );
297 CandidateIdentityAttributeHome.delete( idCandidateIdentitiesList );
298 CandidateIdentityHistoryHome.delete( idCandidateIdentitiesList );
299 TransactionManager.commitTransaction( null );
300 }
301 catch( final Exception e )
302 {
303 TransactionManager.rollBack( null );
304 throw new IdentityStoreException( "An error occurred during batch purge.", e );
305 }
306 }
307 else
308 {
309 throw new IdentityStoreException( "Could not find batch with ID " + batchId );
310 }
311 }
312
313
314
315
316
317
318
319
320 public StringBuilder launchBatches( final int batchLimit )
321 {
322 final StringBuilder msg = new StringBuilder( );
323 try
324 {
325 final List<Batch> initialStateBatches = BatchHome.findInitialStateBatches( batchLimit );
326 if ( !initialStateBatches.isEmpty( ) )
327 {
328 msg.append( initialStateBatches.size( ) ).append( " initial state batches found" ).append( System.lineSeparator( ) );
329 final int actionId = BatchHome.getBatchInitialActionId( );
330 for ( final Batch batch : initialStateBatches )
331 {
332 msg.append( "Launching batch : " ).append( batch.toLog( ) ).append( System.lineSeparator( ) );
333 final WorkflowBean<Batch> workflowBean = _wfBatchBeanService.createWorkflowBean( batch, batch.getId( ), null );
334 _wfBatchBeanService.processAutomaticAction( workflowBean, actionId, null, Locale.getDefault( ) );
335 }
336 }
337 else
338 {
339 msg.append( "No initial state batches found." ).append( System.lineSeparator( ) );
340 }
341 }
342 catch( final Exception e )
343 {
344 msg.append( "Error occurred while launching batches automatically :: " ).append( System.lineSeparator( ) ).append( e.getMessage( ) )
345 .append( System.lineSeparator( ) );
346 }
347 return msg;
348 }
349
350
351
352
353
354
355
356
357 public StringBuilder closeBatches( int batchLimit )
358 {
359 final StringBuilder msg = new StringBuilder( );
360 try
361 {
362 final List<Batch> closableBatches = BatchHome.findClosableBatches( batchLimit );
363 if ( !closableBatches.isEmpty( ) )
364 {
365 msg.append( closableBatches.size( ) ).append( " in treatment state batches found" ).append( System.lineSeparator( ) );
366 final int actionId = BatchHome.getBatchInTreatmentActionId( );
367 for ( final Batch batch : closableBatches )
368 {
369 msg.append( "Closing batch : " ).append( batch.toLog( ) ).append( System.lineSeparator( ) );
370 final WorkflowBean<Batch> workflowBean = _wfBatchBeanService.createWorkflowBean( batch, batch.getId( ), null );
371 _wfBatchBeanService.processAutomaticAction( workflowBean, actionId, null, Locale.getDefault( ) );
372 }
373 }
374 else
375 {
376 msg.append( "No in treatment state batches found." ).append( System.lineSeparator( ) );
377 }
378 }
379 catch( final Exception e )
380 {
381 msg.append( "Error occurred while closing batches automatically :: " ).append( System.lineSeparator( ) ).append( e.getMessage( ) )
382 .append( System.lineSeparator( ) );
383 }
384 return msg;
385 }
386
387 public Batch getBean( BatchDto batch )
388 {
389 final Batchgins/identityimport/business/Batch.html#Batch">Batch bean = new Batch( );
390 bean.setReference( batch.getReference( ) );
391 bean.setComment( batch.getComment( ) );
392 bean.setCreationDate( batch.getCreationDate( ) );
393 bean.setUser( batch.getUser( ) );
394 bean.setAppCode( batch.getAppCode( ) );
395 bean.setClientCode( batch.getClientCode( ) );
396 return bean;
397 }
398
399 public BatchDto getDto( Batch batch )
400 {
401 final BatchDto dto = new BatchDto( );
402 dto.setReference( batch.getReference( ) );
403 dto.setComment( batch.getComment( ) );
404 dto.setCreationDate( batch.getCreationDate( ) );
405 dto.setUser( batch.getUser( ) );
406 dto.setAppCode( batch.getAppCode( ) );
407 dto.setClientCode( batch.getClientCode( ) );
408 return dto;
409 }
410
411 public BatchStatusDto getBatchStatus( final String strBatchReference, final BatchStatusMode mode ) throws IdentityStoreException
412 {
413 final Batch batch = BatchHome.getBatch( strBatchReference );
414 if ( batch == null )
415 {
416 throw new ResourceNotFoundException("Batch not found", Constants.PROPERTY_REST_ERROR_BATCH_NOT_FOUND);
417 }
418 final ResourceState batchState = BatchHome.getBatchState( batch.getId( ) );
419 if ( batchState == null )
420 {
421 throw new ResourceNotFoundException("State of batch not found.", Constants.PROPERTY_REST_ERROR_BATCH_STATE_NOT_FOUND);
422 }
423
424 final BatchStatusDto batchStatus = new BatchStatusDto( );
425
426 batchStatus.setReference( batch.getReference( ) );
427 batchStatus.setClientCode( batch.getClientCode( ) );
428 batchStatus.setUser( batch.getUser( ) );
429 batchStatus.setComment( batch.getComment( ) );
430 batchStatus.setCreationDate( batch.getCreationDate( ) );
431 batchStatus.setStatus( batchState.getName( ) );
432 batchStatus.setStatusDescription( batchState.getDescription( ) );
433
434 final BatchStatisticsDto statisticsDto = new BatchStatisticsDto( );
435 batchStatus.setStatistics( statisticsDto );
436 final List<ResourceState> candidateIdentityStates = CandidateIdentityHome.getCandidateIdentityStates( batch.getId( ) );
437 candidateIdentityStates.stream( ).filter( r -> r.getResourceCount( ) > 0 ).forEach( resourceState -> {
438 final BatchResourceStateDto resourceStateDto = new BatchResourceStateDto( );
439 statisticsDto.getResourceStates( ).add( resourceStateDto );
440 resourceStateDto.setName( resourceState.getName( ) );
441 resourceStateDto.setDescription( resourceState.getDescription( ) );
442 resourceStateDto.setInitialState( resourceStateDto.isInitialState( ) );
443 resourceStateDto.setResourceCount( resourceState.getResourceCount( ) );
444 } );
445
446 statisticsDto.setTotalResourceCount( candidateIdentityStates.stream( ).mapToInt( ResourceState::getResourceCount ).sum( ) );
447
448 if ( mode != BatchStatusMode.IDENTITIES_ONLY )
449 {
450 final List<ResourceHistory> batchHistory = BatchHome.getBatchHistory( batch.getId( ) );
451 for ( final ResourceHistory history : batchHistory )
452 {
453 final ImportingHistoryDto historyDto = new ImportingHistoryDto( );
454 historyDto.setActionName( history.getAction( ).getName( ) );
455 historyDto.setActionDescription( history.getAction( ).getDescription( ) );
456 historyDto.setDate( history.getCreationDate( ) );
457 historyDto.setUserAccessCode( history.getUserAccessCode( ) );
458 batchStatus.getBatchHistory( ).add( historyDto );
459 }
460 }
461 if ( mode != BatchStatusMode.BATCH_ONLY )
462 {
463 final List<CandidateIdentity> identities = CandidateIdentityHome
464 .getCandidateIdentitiesListByIds( CandidateIdentityHome.getIdCandidateIdentitiesList( batch.getId( ), null ) );
465 identities.forEach( candidate -> {
466 final List<CandidateIdentityHistory> identityHistoryList = CandidateIdentityHistoryHome.selectAll( candidate.getId( ) );
467 final List<ResourceHistory> history = CandidateIdentityHome.getHistory( candidate.getId( ) );
468 batchStatus.getIdentities( ).add( CandidateIdentityService.instance( ).getDto( candidate, identityHistoryList, history ) );
469 } );
470 }
471
472 return batchStatus;
473 }
474 }