View Javadoc

1   /*
2   Copyright (c) 2006, University of Tromsø
3   All rights reserved.
4   
5   Redistribution and use in source and binary forms, with or without 
6   modification, are permitted provided that the following conditions are met:
7   
8    * Redistributions of source code must retain the above copyright notice, this list 
9      of conditions and the following disclaimer.
10  
11   * Redistributions in binary form must reproduce the above copyright notice, this 
12     list of conditions and the following disclaimer in the documentation and/or other 
13     materials provided with the distribution.
14  
15   * Neither the name of the University of Tromsø nor the names of its contributors may 
16     be used to endorse or promote products derived from this software without specific 
17     prior written permission.
18  
19  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 
20  EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
21  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
22  SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 
23  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 
24  TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
25  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
26  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
27  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 
28  DAMAGE.
29  */
30  
31  package argos.deploy;
32  
33  import java.io.File;
34  import java.util.ArrayList;
35  import java.util.HashMap;
36  import java.util.List;
37  import java.util.Map;
38  import java.util.logging.Logger;
39  
40  import javax.management.MBeanNotificationInfo;
41  import javax.management.Notification;
42  
43  import argos.annotation.Description;
44  import argos.annotation.Instrument;
45  import argos.annotation.NotificationInfo;
46  import argos.annotation.NotificationSender;
47  import argos.annotation.RemoveInstrumentation;
48  import argos.config.Config;
49  import argos.metadata.ServiceMetaInfo;
50  import argos.naming.NamingService;
51  import argos.proxy.NotificationProxy;
52  
53  /**
54   * Created on 05.jul.2006
55   * 
56   * @author Dan Peder Eriksen
57   */
58  @RemoveInstrumentation
59  @Description("Loads new jar files (services)")
60  public class HotDeployer extends Thread {
61  	private static final Logger logger = Logger.getLogger(HotDeployer.class.getName());
62  	private static HotDeployer singelton = new HotDeployer();
63  	
64  	public static final String NEW_FILE_FOUND = "NEW_FILE_FOUND";
65  	public static final String DEPLOY_FILE_MISSING = "DEPLOY_FILE_MISSING";
66  	public static final String NOT_LOADING_FILE = "NOT_LOADING";
67  	public static final String FILE_UPDATED = "FILE_UPDATED";
68  	public static final String UNDEPLOY_FILE = "UNDEPLOY_FILE";
69  	
70  	public static final String DEPLOY_FILE = "deploy.xml";
71  	public static final int DEFAULT_SLEEP_TIME = 1000;
72  	
73  	private String directory;
74  	private int sleepTime;
75  	private List<File> ignored;
76  	private Map<String, Long> timestamps;
77  	private boolean running;
78  
79  	@NotificationSender
80  	public NotificationProxy proxy;
81  	private long seq;
82  	
83  	private HotDeployer() {
84  		super("HotDeployer");
85  		seq = 0;
86  		directory = Config.get(Config.DEFAULT_DEPLOY_FOLDER);
87  		sleepTime = DEFAULT_SLEEP_TIME;
88  		ignored = new ArrayList<File>();
89  		timestamps = new HashMap<String, Long>();
90  		running = true;
91  	}
92  	
93  	public synchronized void stopDeployer() {
94  		running = false;
95  	}
96  	
97  	@Override
98  	public void run() {
99  		try {
100 			sleep(1);
101 		}
102 		catch(InterruptedException ignore) {}
103 		
104 		ComponentManager cm = ComponentManager.getInstance();
105 		NamingService naming = NamingService.getInstance();
106 		
107 		List<File> deploy = new ArrayList<File>();
108 		List<File> redeploy = new ArrayList<File>();
109 		List<ServiceMetaInfo> stop = new ArrayList<ServiceMetaInfo>();
110 		while(true) {
111 			if(!running) {
112 				return;
113 			}
114 			long start = System.currentTimeMillis();
115 			File dir = new File(directory);
116 			if(dir.isDirectory()) {
117 				for(File file : dir.listFiles()) {
118 					if(file.getName().toLowerCase().endsWith(".jar")) {
119 						if(isIgnored(file)) {
120 							continue;
121 						}
122 						else {
123 							//Make sure the file isnt still being written to
124 							long filesize = file.length();
125 							while(true) {
126 								try {
127 									sleep(10);
128 								}
129 								catch (InterruptedException ignore) {}
130 								if(!running) {
131 									return;
132 								}
133 								long temp = file.length();
134 								if(filesize == temp) {
135 									break;
136 								}
137 								else {
138 									filesize = temp;
139 								}
140 							}
141 							
142 							//Deploy/redeploy
143 							if(!naming.isFileLoaded(file)) {
144 								deploy.add(file);
145 							}
146 							else if(naming.isNewer(file)) {
147 								redeploy.add(file);
148 							}
149 						}
150 					}
151 				}
152 				//Check for missing files
153 				stop.clear();
154 				for(File deployed : naming.getLoadedFiles()) {
155 					boolean found = false;
156 					for(File file : dir.listFiles()) {
157 						if(deployed.equals(file)) {
158 							found = true;
159 							break;
160 						}
161 					}
162 					if(!found) {
163 						stop.add(naming.getServiceByFile(deployed));
164 					}
165 				}
166 				if(!stop.isEmpty()) {
167 					cm.stop(stop);
168 				}
169 				
170 				//Deploy
171 				boolean deployed = false;
172 				if(!redeploy.isEmpty()) {
173 					logger.info("Found updated file(s), starting redeployment.");
174 					cm.redeploy(redeploy);
175 					redeploy.clear();
176 					deployed = true;
177 				}
178 				if(!deploy.isEmpty()) {
179 					logger.info("Found new file(s), starting deployment.");
180 					cm.deploy(deploy);
181 					deploy.clear();
182 					deployed = true;
183 				}
184 				if(deployed) {
185 					double used = (System.currentTimeMillis() - start) / 1000.0;
186 					logger.info("Deployment done in " + used + "s.\r\n");
187 				}
188 			}
189 			else {
190 				logger.severe(dir.getName() + " is not a directory, unable to load components.");
191 			}
192 			
193 			
194 			try {
195 				sleep(sleepTime);
196 			}
197 			catch(InterruptedException ignore) {
198 				continue;
199 			}
200 		}
201 	}
202 	
203 	public void addIgnore(File file) {
204 		ignored.add(file);
205 		timestamps.put(file.getName(), file.lastModified());
206 		proxy.send(new Notification(NOT_LOADING_FILE, Notification.class.getClass().getName(), seq++, file.getAbsolutePath()));
207 	}
208 	
209 	public boolean removeIgnore(File file) {
210 		for(File temp : ignored) {
211 			if(temp.getName().equals(file.getName())) {
212 				timestamps.remove(file.getName());
213 				return ignored.remove(temp);
214 			}
215 		}
216 		return false;
217 	}
218 	
219 	//Returns true when a file is found in ignored and has not been updated.
220 	private boolean isIgnored(File file) {
221 		for(File temp : ignored) {
222 			if(temp.getName().equals(file.getName())) {
223 				long now = file.lastModified();
224 				long then = timestamps.get(temp.getName());
225 				if(now == then) {
226 					return true;
227 				}
228 				else {
229 					ignored.remove(temp);
230 					logger.info(file.getName() + " has been updated, loading.");
231 					return false;
232 				}
233 			}
234 		}
235 		return false;
236 	}
237 	
238 	@Instrument
239 	@Description("The current directory being monitored for new components")
240 	public String getDirectory() {
241 		return directory;
242 	}
243 	
244 	@Instrument
245 	public void setDirectory(String directory) {
246 		this.directory = directory;
247 	}
248 	
249 	@Instrument
250 	@Description("How many mili seconds between each scan for new components")
251 	public int getSleepTime() {
252 		return sleepTime;
253 	}
254 	
255 	@Instrument
256 	public void setSleepTime(int sleepTime) {
257 		this.sleepTime = sleepTime;
258 	}
259 	
260 	public static HotDeployer getInstance() {
261 		return singelton;
262 	}
263 	
264 	@NotificationInfo
265 	public MBeanNotificationInfo[] getNotificationInfo() {
266 		MBeanNotificationInfo[] not = new MBeanNotificationInfo[5];
267 		not[0] = new MBeanNotificationInfo(new String[]{NEW_FILE_FOUND}, Notification.class.getClass().getName(), "Emitted when a new file is found.");
268 		not[1] = new MBeanNotificationInfo(new String[]{DEPLOY_FILE_MISSING}, Notification.class.getClass().getName(), "Emitted when the deploy file is missing from the jar.");
269 		not[2] = new MBeanNotificationInfo(new String[]{NOT_LOADING_FILE}, Notification.class.getClass().getName(), "Emitted when a file is not being loaded.");
270 		not[3] = new MBeanNotificationInfo(new String[]{FILE_UPDATED}, Notification.class.getClass().getName(), "Emitted when a file has been updated.");
271 		not[4] = new MBeanNotificationInfo(new String[]{UNDEPLOY_FILE}, Notification.class.getClass().getName(), "Emitted when a is being undeployed.");
272 		return not;
273 	}
274 }