1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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
55
56
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
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
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
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
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
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 }