001/* 002 * Copyright 2006-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 */ 016 017package org.springframework.batch.core.configuration.support; 018 019import java.util.ArrayList; 020import java.util.Collection; 021 022import org.springframework.batch.core.Job; 023import org.springframework.batch.core.configuration.DuplicateJobException; 024import org.springframework.batch.core.configuration.JobRegistry; 025import org.springframework.beans.factory.InitializingBean; 026import org.springframework.context.ApplicationContext; 027import org.springframework.context.ApplicationContextAware; 028import org.springframework.context.Lifecycle; 029import org.springframework.context.SmartLifecycle; 030import org.springframework.context.event.ApplicationContextEvent; 031import org.springframework.core.Ordered; 032import org.springframework.util.Assert; 033 034/** 035 * Loads and unloads {@link Job Jobs} when the application context is created and destroyed. Each resource provided is 036 * loaded as an application context with the current context as its parent, and then all the jobs from the child context 037 * are registered under their bean names. A {@link JobRegistry} is required. 038 * 039 * @author Lucas Ward 040 * @author Dave Syer 041 * @author Mahmoud Ben Hassine 042 * 043 * @since 2.1 044 */ 045public class AutomaticJobRegistrar implements Ordered, SmartLifecycle, ApplicationContextAware, 046 InitializingBean { 047 048 private Collection<ApplicationContextFactory> applicationContextFactories = new ArrayList<ApplicationContextFactory>(); 049 050 private JobLoader jobLoader; 051 052 private ApplicationContext applicationContext; 053 054 private volatile boolean running = false; 055 056 private int phase = Integer.MIN_VALUE + 1000; 057 058 private boolean autoStartup = true; 059 060 private Object lifecycleMonitor = new Object(); 061 062 private int order = Ordered.LOWEST_PRECEDENCE; 063 064 /** 065 * The enclosing application context, which can be used to check if {@link ApplicationContextEvent events} come 066 * from the expected source. 067 * 068 * @param applicationContext the enclosing application context if there is one 069 * @see ApplicationContextAware#setApplicationContext(ApplicationContext) 070 */ 071 @Override 072 public void setApplicationContext(ApplicationContext applicationContext) { 073 this.applicationContext = applicationContext; 074 } 075 076 /** 077 * Add some factories to the set that will be used to load contexts and jobs. 078 * 079 * @param applicationContextFactory the {@link ApplicationContextFactory} values to use 080 */ 081 public void addApplicationContextFactory(ApplicationContextFactory applicationContextFactory) { 082 if (applicationContextFactory instanceof ApplicationContextAware) { 083 ((ApplicationContextAware) applicationContextFactory).setApplicationContext(applicationContext); 084 } 085 this.applicationContextFactories.add(applicationContextFactory); 086 } 087 088 /** 089 * Add some factories to the set that will be used to load contexts and jobs. 090 * 091 * @param applicationContextFactories the {@link ApplicationContextFactory} values to use 092 */ 093 public void setApplicationContextFactories(ApplicationContextFactory[] applicationContextFactories) { 094 for (ApplicationContextFactory applicationContextFactory : applicationContextFactories) { 095 this.applicationContextFactories.add(applicationContextFactory); 096 } 097 } 098 099 /** 100 * The job loader that will be used to load and manage jobs. 101 * 102 * @param jobLoader the {@link JobLoader} to set 103 */ 104 public void setJobLoader(JobLoader jobLoader) { 105 this.jobLoader = jobLoader; 106 } 107 108 @Override 109 public int getOrder() { 110 return order; 111 } 112 113 /** 114 * The order to start up and shutdown. 115 * @param order the order (default {@link Ordered#LOWEST_PRECEDENCE}). 116 * @see Ordered 117 */ 118 public void setOrder(int order) { 119 this.order = order; 120 } 121 122 /** 123 */ 124 @Override 125 public void afterPropertiesSet() { 126 127 Assert.state(jobLoader != null, "A JobLoader must be provided"); 128 129 } 130 131 /** 132 * Delegates to {@link JobLoader#clear()}. 133 * 134 * @see Lifecycle#stop() 135 */ 136 @Override 137 public void stop() { 138 synchronized (this.lifecycleMonitor) { 139 jobLoader.clear(); 140 running = false; 141 } 142 } 143 144 /** 145 * Take all the contexts from the factories provided and pass them to the {@link JobLoader}. 146 * 147 * @see Lifecycle#start() 148 */ 149 @Override 150 public void start() { 151 synchronized (this.lifecycleMonitor) { 152 if (running) { 153 return; 154 } 155 for (ApplicationContextFactory factory : applicationContextFactories) { 156 try { 157 jobLoader.load(factory); 158 } 159 catch (DuplicateJobException e) { 160 throw new IllegalStateException(e); 161 } 162 } 163 running = true; 164 } 165 } 166 167 /** 168 * Check if this component has been started. 169 * 170 * @return true if started successfully and not stopped 171 * @see Lifecycle#isRunning() 172 */ 173 @Override 174 public boolean isRunning() { 175 synchronized (this.lifecycleMonitor) { 176 return running; 177 } 178 } 179 180 @Override 181 public boolean isAutoStartup() { 182 return autoStartup; 183 } 184 185 /** 186 * @param autoStartup true for auto start. 187 * @see #isAutoStartup() 188 */ 189 public void setAutoStartup(boolean autoStartup) { 190 this.autoStartup = autoStartup; 191 } 192 193 @Override 194 public int getPhase() { 195 return phase; 196 } 197 198 /** 199 * @param phase the phase. 200 * @see #getPhase() 201 */ 202 public void setPhase(int phase) { 203 this.phase = phase; 204 } 205 206 @Override 207 public void stop(Runnable callback) { 208 stop(); 209 callback.run(); 210 } 211 212}