1 package com.atlassian.plugin.loaders;
2
3 import com.atlassian.plugin.PluginException;
4 import com.atlassian.plugin.loaders.classloading.DeploymentUnit;
5 import org.apache.commons.lang.Validate;
6 import org.slf4j.Logger;
7 import org.slf4j.LoggerFactory;
8
9 import java.io.File;
10 import java.io.FilenameFilter;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.TreeMap;
18
19
20
21
22
23
24
25 public class DirectoryScanner implements com.atlassian.plugin.loaders.classloading.Scanner
26 {
27 private static Logger log = LoggerFactory.getLogger(DirectoryScanner.class);
28
29
30
31
32 private final File pluginsDirectory;
33
34
35
36
37 private final Map<String,DeploymentUnit> scannedDeploymentUnits = new TreeMap<String,DeploymentUnit>();
38
39
40
41
42
43
44
45 public DirectoryScanner(File pluginsDirectory)
46 {
47 Validate.notNull(pluginsDirectory, "Plugin scanner directory must not be null");
48 this.pluginsDirectory = pluginsDirectory;
49 }
50
51 private DeploymentUnit createAndStoreDeploymentUnit(File file)
52 {
53 if (isScanned(file))
54 return null;
55
56 DeploymentUnit unit = new DeploymentUnit(file);
57 scannedDeploymentUnits.put(file.getAbsolutePath(), unit);
58
59 return unit;
60 }
61
62
63
64
65
66
67 public DeploymentUnit locateDeploymentUnit(File file)
68 {
69 return scannedDeploymentUnits.get(file.getAbsolutePath());
70 }
71
72
73
74
75 private boolean isScanned(File file)
76 {
77 return locateDeploymentUnit(file) != null;
78 }
79
80
81
82
83
84
85
86 public void clear(File file)
87 {
88 scannedDeploymentUnits.remove(file.getAbsolutePath());
89 }
90
91
92
93
94
95
96
97
98 public Collection<DeploymentUnit> scan()
99 {
100
101 List<File> removedFiles = new ArrayList<File>();
102 for (DeploymentUnit unit : scannedDeploymentUnits.values())
103 {
104 if (!unit.getPath().exists() || !unit.getPath().canRead())
105 {
106 removedFiles.add(unit.getPath());
107 }
108 }
109 clear(removedFiles);
110
111
112 Collection<DeploymentUnit> result = new ArrayList<DeploymentUnit>();
113 File files[] = pluginsDirectory.listFiles(new FilenameFilter()
114 {
115
116 public boolean accept(File dir, String name)
117 {
118 return !name.startsWith(".");
119 }
120 });
121
122 if (files == null)
123 {
124 log.error("listFiles returned null for directory " + pluginsDirectory.getAbsolutePath());
125 return result;
126 }
127
128 Arrays.sort(files);
129 for (File file : files)
130 {
131 if (isScanned(file) && isModified(file))
132 {
133 clear(file);
134 DeploymentUnit unit = createAndStoreDeploymentUnit(file);
135 if (unit != null)
136 result.add(unit);
137 }
138 else if (!isScanned(file))
139 {
140 DeploymentUnit unit = createAndStoreDeploymentUnit(file);
141 if (unit != null)
142 result.add(unit);
143 }
144 }
145 return result;
146 }
147
148 private boolean isModified(File file)
149 {
150 DeploymentUnit unit = locateDeploymentUnit(file);
151 return file.lastModified() > unit.lastModified();
152 }
153
154 private void clear(List<File> toUndeploy)
155 {
156 for (File aToUndeploy : toUndeploy)
157 {
158 clear( aToUndeploy);
159 }
160 }
161
162
163
164
165
166
167 public Collection<DeploymentUnit> getDeploymentUnits()
168 {
169 return Collections.unmodifiableCollection(scannedDeploymentUnits.values());
170 }
171
172
173
174
175 public void reset()
176 {
177 scannedDeploymentUnits.clear();
178 }
179
180 public void remove(DeploymentUnit unit) throws PluginException
181 {
182 if (unit.getPath().exists())
183 {
184 if (!unit.getPath().delete())
185 {
186 throw new PluginException("Unable to delete file: " + unit.getPath());
187 }
188 }
189 else
190 {
191 log.debug("Plugin file <" + unit.getPath().getPath() + "> doesn't exist to delete. Ignoring.");
192 }
193
194 clear(unit.getPath());
195 }
196 }