001/*
002 * Copyright 2013-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.springframework.batch.core.jsr;
017
018import java.util.Map;
019import java.util.Properties;
020
021import javax.sql.DataSource;
022
023import org.springframework.batch.core.JobParameter;
024import org.springframework.batch.core.JobParameters;
025import org.springframework.batch.core.JobParametersBuilder;
026import org.springframework.batch.core.converter.JobParametersConverter;
027import org.springframework.batch.core.repository.JobRepository;
028import org.springframework.batch.core.repository.dao.AbstractJdbcBatchMetadataDao;
029import org.springframework.batch.item.database.support.DataFieldMaxValueIncrementerFactory;
030import org.springframework.batch.item.database.support.DefaultDataFieldMaxValueIncrementerFactory;
031import org.springframework.batch.support.DatabaseType;
032import org.springframework.beans.factory.InitializingBean;
033import org.springframework.jdbc.support.incrementer.DataFieldMaxValueIncrementer;
034import org.springframework.lang.Nullable;
035import org.springframework.util.Assert;
036
037/**
038 * Provides default conversion methodology for JSR-352's implementation.
039 *
040 * Since Spring Batch uses job parameters as a way of identifying a job
041 * instance, this converter will add an additional identifying parameter if
042 * it does not exist already in the list.  The id for the identifying parameter
043 * will come from the JOB_SEQ sequence as used to generate the unique ids
044 * for BATCH_JOB_INSTANCE records.
045 *
046 * @author Michael Minella
047 * @author Mahmoud Ben Hassine
048 * @since 3.0
049 */
050public class JsrJobParametersConverter implements JobParametersConverter, InitializingBean {
051
052        public static final String JOB_RUN_ID = "jsr_batch_run_id";
053        public DataFieldMaxValueIncrementer incrementer;
054        public String tablePrefix = AbstractJdbcBatchMetadataDao.DEFAULT_TABLE_PREFIX;
055        public DataSource dataSource;
056
057        /**
058         * Main constructor.
059         *
060         * @param dataSource used to gain access to the database to get unique ids.
061         */
062        public JsrJobParametersConverter(DataSource dataSource) {
063                Assert.notNull(dataSource, "A DataSource is required");
064                this.dataSource = dataSource;
065        }
066
067        /**
068         * The table prefix used in the current {@link JobRepository}
069         *
070         * @param tablePrefix the table prefix used for the job repository tables
071         */
072        public void setTablePrefix(String tablePrefix) {
073                this.tablePrefix = tablePrefix;
074        }
075
076        @Override
077        public void afterPropertiesSet() throws Exception {
078                DataFieldMaxValueIncrementerFactory factory = new DefaultDataFieldMaxValueIncrementerFactory(dataSource);
079
080                this.incrementer = factory.getIncrementer(DatabaseType.fromMetaData(dataSource).name(), tablePrefix + "JOB_SEQ");
081        }
082
083        /* (non-Javadoc)
084         * @see org.springframework.batch.core.converter.JobParametersConverter#getJobParameters(java.util.Properties)
085         */
086        @Override
087        public JobParameters getJobParameters(@Nullable Properties properties) {
088                JobParametersBuilder builder = new JobParametersBuilder();
089                boolean runIdFound = false;
090
091                if(properties != null) {
092                        for (Map.Entry<Object, Object> curParameter : properties.entrySet()) {
093                                if(curParameter.getValue() != null) {
094                                        if(curParameter.getKey().equals(JOB_RUN_ID)) {
095                                                runIdFound = true;
096                                                builder.addLong(curParameter.getKey().toString(), Long.valueOf((String) curParameter.getValue()), true);
097                                        } else {
098                                                builder.addString(curParameter.getKey().toString(), curParameter.getValue().toString(), false);
099                                        }
100                                }
101                        }
102                }
103
104                if(!runIdFound) {
105                        builder.addLong(JOB_RUN_ID, incrementer.nextLongValue());
106                }
107
108                return builder.toJobParameters();
109        }
110
111        /* (non-Javadoc)
112         * @see org.springframework.batch.core.converter.JobParametersConverter#getProperties(org.springframework.batch.core.JobParameters)
113         */
114        @Override
115        public Properties getProperties(@Nullable JobParameters params) {
116                Properties properties = new Properties();
117                boolean runIdFound = false;
118
119                if(params != null) {
120                        for(Map.Entry<String, JobParameter> curParameter: params.getParameters().entrySet()) {
121                                if(curParameter.getKey().equals(JOB_RUN_ID)) {
122                                        runIdFound = true;
123                                }
124
125                                properties.setProperty(curParameter.getKey(), curParameter.getValue().getValue().toString());
126                        }
127                }
128
129                if(!runIdFound) {
130                        properties.setProperty(JOB_RUN_ID, String.valueOf(incrementer.nextLongValue()));
131                }
132
133                return properties;
134        }
135}