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