001package ca.uhn.fhir.jpa.batch.writer;
002
003/*-
004 * #%L
005 * HAPI FHIR JPA Server
006 * %%
007 * Copyright (C) 2014 - 2022 Smile CDR, Inc.
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import org.slf4j.Logger;
024import org.slf4j.LoggerFactory;
025import org.springframework.batch.core.StepExecution;
026import org.springframework.batch.core.annotation.BeforeStep;
027import org.springframework.batch.item.ItemWriter;
028
029import javax.persistence.EntityManager;
030import javax.persistence.PersistenceContext;
031import javax.persistence.PersistenceContextType;
032import java.util.List;
033
034/**
035 * This Spring Batch writer accepts a list of SQL commands and executes them.
036 * The total number of entities updated or deleted is stored in the execution context
037 * with the key {@link #ENTITY_TOTAL_UPDATED_OR_DELETED}.  The entire list is committed within a
038 * single transaction (provided by Spring Batch).
039 */
040public class SqlExecutorWriter implements ItemWriter<List<String>> {
041        private static final Logger ourLog = LoggerFactory.getLogger(SqlExecutorWriter.class);
042
043        public static final String ENTITY_TOTAL_UPDATED_OR_DELETED = "entity.total.updated-or-deleted";
044
045        @PersistenceContext(type = PersistenceContextType.TRANSACTION)
046        private EntityManager myEntityManager;
047        private Long totalUpdated = 0L;
048        private StepExecution myStepExecution;
049
050        @BeforeStep
051        public void setStepExecution(StepExecution stepExecution) {
052                myStepExecution = stepExecution;
053        }
054
055        @Override
056        public void write(List<? extends List<String>> theSqlLists) throws Exception {
057
058                // Note that since our chunk size is 1, there will always be exactly one list
059                for (List<String> sqlList : theSqlLists) {
060                        ourLog.info("Executing {} sql commands", sqlList.size());
061                        for (String sql : sqlList) {
062                                ourLog.trace("Executing sql " + sql);
063                                totalUpdated += myEntityManager.createNativeQuery(sql).executeUpdate();
064                                myStepExecution.getExecutionContext().putLong(ENTITY_TOTAL_UPDATED_OR_DELETED, totalUpdated);
065                        }
066                }
067                ourLog.debug("{} records updated", totalUpdated);
068        }
069}