001/* 002 * Copyright 2013-2014 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.configuration.xml; 017 018import java.util.HashMap; 019import java.util.List; 020import java.util.Map; 021import java.util.Properties; 022 023import org.springframework.batch.core.jsr.configuration.support.BatchArtifactType; 024import org.springframework.beans.factory.config.BeanDefinition; 025import org.springframework.beans.factory.support.ManagedMap; 026import org.springframework.beans.factory.xml.ParserContext; 027import org.springframework.util.xml.DomUtils; 028import org.w3c.dom.Element; 029 030/** 031 * <p> 032 * Parser for the <properties /> element defined by JSR-352. 033 * </p> 034 * 035 * @author Chris Schaefer 036 * @since 3.0 037 */ 038public class PropertyParser { 039 private static final String PROPERTY_ELEMENT = "property"; 040 private static final String PROPERTIES_ELEMENT = "properties"; 041 private static final String PROPERTY_NAME_ATTRIBUTE = "name"; 042 private static final String PROPERTY_VALUE_ATTRIBUTE = "value"; 043 private static final String JOB_PROPERTIES_BEAN_NAME = "jobProperties"; 044 private static final String BATCH_PROPERTY_CONTEXT_BEAN_NAME = "batchPropertyContext"; 045 private static final String JOB_PROPERTIES_PROPERTY_NAME = "jobProperties"; 046 private static final String STEP_PROPERTIES_PROPERTY_NAME = "stepProperties"; 047 private static final String ARTIFACT_PROPERTIES_PROPERTY_NAME = "artifactProperties"; 048 private static final String STEP_ARTIFACT_PROPERTIES_PROPERTY_NAME = "stepArtifactProperties"; 049 050 private String beanName; 051 private String stepName; 052 private ParserContext parserContext; 053 private BatchArtifactType batchArtifactType; 054 055 public PropertyParser(String beanName, ParserContext parserContext, BatchArtifactType batchArtifactType) { 056 this.beanName = beanName; 057 this.parserContext = parserContext; 058 this.batchArtifactType = batchArtifactType; 059 } 060 061 public PropertyParser(String beanName, ParserContext parserContext, BatchArtifactType batchArtifactType, String stepName) { 062 this(beanName, parserContext, batchArtifactType); 063 this.stepName = stepName; 064 } 065 066 /** 067 * <p> 068 * Parses <property> tag values from the provided {@link Element} if it contains a <properties /> element. 069 * Only one <properties /> element may be present. <property> elements have a name and value attribute 070 * which represent the property entries key and value. 071 * </p> 072 * 073 * @param element the element to parse looking for <properties /> 074 */ 075 public void parseProperties(Element element) { 076 List<Element> propertiesElements = DomUtils.getChildElementsByTagName(element, PROPERTIES_ELEMENT); 077 078 if (propertiesElements.size() == 1) { 079 parsePropertyElement(propertiesElements.get(0)); 080 } else if (propertiesElements.size() > 1) { 081 parserContext.getReaderContext().error("The <properties> element may not appear more than once.", element); 082 } 083 } 084 085 /** 086 * <p> 087 * Parses a <property> tag value from the provided {@link Element}. <property> elements have a name and 088 * value attribute which represent the property entries key and value. 089 * </p> 090 * 091 * @param element the element to parse looking for <property/> 092 */ 093 public void parseProperty(Element element) { 094 parsePropertyElement(element); 095 } 096 097 private void parsePropertyElement(Element propertyElement) { 098 Properties properties = new Properties(); 099 100 for (Element element : DomUtils.getChildElementsByTagName(propertyElement, PROPERTY_ELEMENT)) { 101 properties.put(element.getAttribute(PROPERTY_NAME_ATTRIBUTE), element.getAttribute(PROPERTY_VALUE_ATTRIBUTE)); 102 } 103 104 setProperties(properties); 105 setJobPropertiesBean(properties); 106 } 107 108 private void setProperties(Properties properties) { 109 Object propertyValue; 110 BeanDefinition beanDefinition = parserContext.getRegistry().getBeanDefinition(BATCH_PROPERTY_CONTEXT_BEAN_NAME); 111 112 if(batchArtifactType.equals(BatchArtifactType.JOB)) { 113 propertyValue = getJobProperties(properties); 114 } else if (batchArtifactType.equals(BatchArtifactType.STEP)) { 115 propertyValue = getProperties(stepName, properties); 116 } else if (batchArtifactType.equals(BatchArtifactType.ARTIFACT)) { 117 propertyValue = getProperties(beanName, properties); 118 } else if (batchArtifactType.equals(BatchArtifactType.STEP_ARTIFACT)) { 119 propertyValue = getStepArtifactProperties(beanDefinition, properties); 120 } else { 121 throw new IllegalStateException("Unhandled BatchArtifactType of: " + batchArtifactType); 122 } 123 124 beanDefinition.getPropertyValues().addPropertyValue(getPropertyName(batchArtifactType), propertyValue); 125 } 126 127 private Map<String, Properties> getProperties(String keyName, Properties properties) { 128 ManagedMap<String, Properties> stepProperties = new ManagedMap<String, Properties>(); 129 stepProperties.setMergeEnabled(true); 130 stepProperties.put(keyName, properties); 131 132 return stepProperties; 133 } 134 135 private Properties getJobProperties(Properties properties) { 136 return properties; 137 } 138 139 @SuppressWarnings("unchecked") 140 private Map<String, Map<String, Properties>> getStepArtifactProperties(BeanDefinition beanDefinition, Properties properties) { 141 ManagedMap<String, Map<String, Properties>> stepArtifacts = new ManagedMap<String, Map<String, Properties>>(); 142 stepArtifacts.setMergeEnabled(true); 143 144 Map<String, Map<String, Properties>> existingArtifacts 145 = (Map<String, Map<String, Properties>>) beanDefinition.getPropertyValues().get(getPropertyName(batchArtifactType)); 146 147 ManagedMap<String, Properties> artifactProperties = new ManagedMap<String, Properties>(); 148 artifactProperties.setMergeEnabled(true); 149 150 if(existingArtifacts != null && existingArtifacts.containsKey(stepName)) { 151 Map<String, Properties> existingArtifactsMap = existingArtifacts.get(stepName); 152 153 for(Map.Entry<String, Properties> existingArtifactEntry : existingArtifactsMap.entrySet()) { 154 artifactProperties.put(existingArtifactEntry.getKey(), existingArtifactEntry.getValue()); 155 } 156 } 157 158 artifactProperties.put(beanName, properties); 159 stepArtifacts.put(stepName, artifactProperties); 160 161 return stepArtifacts; 162 } 163 164 private void setJobPropertiesBean(Properties properties) { 165 if (batchArtifactType.equals(BatchArtifactType.JOB)) { 166 Map<String, String> jobProperties = new HashMap<String, String>(); 167 168 if (properties != null && !properties.isEmpty()) { 169 for (String param : properties.stringPropertyNames()) { 170 jobProperties.put(param, properties.getProperty(param)); 171 } 172 } 173 174 BeanDefinition jobPropertiesBeanDefinition = parserContext.getRegistry().getBeanDefinition(JOB_PROPERTIES_BEAN_NAME); 175 jobPropertiesBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(jobProperties); 176 } 177 } 178 179 private String getPropertyName(BatchArtifactType batchArtifactType) { 180 if(batchArtifactType.equals(BatchArtifactType.JOB)) { 181 return JOB_PROPERTIES_PROPERTY_NAME; 182 } else if (batchArtifactType.equals(BatchArtifactType.STEP)) { 183 return STEP_PROPERTIES_PROPERTY_NAME; 184 } else if (batchArtifactType.equals(BatchArtifactType.ARTIFACT)) { 185 return ARTIFACT_PROPERTIES_PROPERTY_NAME; 186 } else if (batchArtifactType.equals(BatchArtifactType.STEP_ARTIFACT)) { 187 return STEP_ARTIFACT_PROPERTIES_PROPERTY_NAME; 188 } else { 189 throw new IllegalStateException("Unhandled BatchArtifactType of: " + batchArtifactType); 190 } 191 } 192}