1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package kortsoft.kmx.deployer;
17
18 import java.io.File;
19 import java.io.FilenameFilter;
20 import java.util.ArrayList;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Set;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27
28
29 /***
30 * KmxDameon responsability is to check modified or new components to be deployed.
31 * It must be assigned the directories to check (in the future it could check
32 * other sources) with the method <code>setWatchDirectories(List<File>)</code>.
33 * Takes the modified or new components and selects a Deployer taken within:
34 * <ul>
35 * <li>Default Deployers (directory and jar)</li>
36 * <li>Extra Deployers (based on a <code>FilenameFilter</code>)</li>
37 * </ul>
38 * <p>
39 * These <em>Extra</em> deployers must be assigned with the method
40 * <code>addExtraDeployer(Class<? extends Deployer>,FilenameFilter)</code>.
41 * </p>
42 * <a href="KmxDaemon.java.html"> <b><i>View Source </i> </b> </a>
43 *
44 * @author Alvaro
45 * @version $Revision: 1.2 $
46 *
47 * @todo Refactor Deployer selection and invocation to a "DeployerManager"
48 *
49 */
50 public class KmxDaemon implements KmxDaemonInterface, KmxDaemonMBean {
51
52 private Map<File, Class< ? extends Deployer>> deployersCache = new HashMap<File, Class< ? extends Deployer>>();
53
54 private Map<FilenameFilter, Class< ? extends Deployer>> extraDeployers = new HashMap<FilenameFilter, Class< ? extends Deployer>>();
55
56 private List<File> watchDirectories;
57
58 private Map<File,Long> lastLoading;;
59
60 private ClassLoader baseClassLoader;
61
62 /***
63 * Check modifications in a directory. New files and modified
64 * files/directories are returned as a List <File>. It is passed a Map with
65 * the timestamp of the file/directory last load, so it can be compared with
66 * the modification timestamp.
67 *
68 * @param directory
69 * @param lastLoadings
70 * @return
71 *
72 * @todo Implement
73 */
74 protected List<File> checkDirectoryChanges(File directory,
75 Map<File, Long> lastLoadings) {
76 long now=System.currentTimeMillis();
77 List<File> toLoadFiles = new ArrayList<File>();
78 String[] fileNames = directory.list();
79 for (int i = 0; i < fileNames.length; i++) {
80 String fileName = fileNames[i];
81 File checkedFile = new File(directory, fileName);
82 Long lastLoading = lastLoadings.get(checkedFile);
83 long lastModified = checkedFile.lastModified();
84 if (lastLoading == null)
85 toLoadFiles.add(checkedFile);
86 else if (lastLoading <= checkedFile.lastModified())
87
88 toLoadFiles.add(checkedFile);
89 lastLoadings.put(checkedFile, now);
90 }
91 return toLoadFiles;
92 }
93
94 /***
95 * Loads an instance of a Deployer suitable for the specified file. First
96 * seek for the deployer class in a caché if it has been loaded previously
97 * (now it is a reload). If it doesn't find the file in the caché, look for
98 * a deployer for that type of file (both in advanced Deployer and in
99 * default deployes).
100 *
101 * @param jarFile
102 * @return
103 */
104 protected Deployer loadDeployer(File element)
105 throws DeployerCreationException {
106 Class< ? extends Deployer> deployerClass = null;
107 if (!deployersCache.containsKey(element)) {
108 deployerClass = checkDeployerType(element);
109 if (deployerClass == null)
110 deployerClass = checkDefaultDeployerType(element);
111 deployersCache.put(element, deployerClass);
112 } else
113 deployerClass = deployersCache.get(element);
114 try {
115 Deployer deployer = deployerClass.newInstance();
116 deployer.setParent(getBaseClassLoader());
117 return deployer;
118 } catch (InstantiationException e) {
119 throw new DeployerCreationException(e);
120 } catch (IllegalAccessException e) {
121 throw new DeployerCreationException(e);
122 }
123
124 }
125
126 /***
127 * @param element
128 * @return
129 */
130 private Class< ? extends Deployer> checkDefaultDeployerType(File element) {
131 if (element.isDirectory())
132 return ComponentDirDeployer.class;
133 if (element.getName().toLowerCase().endsWith(".jar"))
134 return JarDeployer.class;
135 else
136 return SimpleFileDeployer.class;
137 }
138
139 /***
140 * @param element
141 * @return
142 */
143 private Class< ? extends Deployer> checkDeployerType(File element) {
144 Set<FilenameFilter> filters = extraDeployers.keySet();
145 for (FilenameFilter filter : filters) {
146 if (filter.accept(element.getParentFile(), element.getName()))
147 return extraDeployers.get(filter);
148 }
149 return null;
150 }
151
152
153 /***
154 * @param name
155 * @param filter
156 */
157 public void addExtraDeployer(Class< ? extends Deployer> deployerType,
158 FilenameFilter filter) {
159 this.extraDeployers.put(filter, deployerType);
160 }
161
162 /***
163 * @param watchDirectories
164 */
165 public void setWatchDirectories(List<File> watchDirectories) {
166 synchronized (watchDirectories) {
167 this.watchDirectories = watchDirectories;
168 }
169 }
170
171 /***
172 * Executes one iteration of loading.
173 *
174 */
175 public void runDaemon() {
176 List<File> auxDirectories=new ArrayList<File>();
177 synchronized (watchDirectories){
178 if (watchDirectories==null || (watchDirectories.size()==0))
179 return;
180 for (File f : watchDirectories)
181 auxDirectories.add(f);
182 }
183 if (lastLoading==null)
184 lastLoading=new HashMap<File,Long>();
185 for (File directory : auxDirectories){
186 List<File> toLoads=checkDirectoryChanges(directory,lastLoading);
187 for (File toLoad : toLoads){
188 try {
189 Deployer deployer = loadDeployer(toLoad);
190 deployer.deployElement(toLoad);
191 } catch (DeployerCreationException e) {
192 error("Error creating deployer for File "
193 + toLoad.getName());
194 }
195 }
196 }
197 }
198
199 /***
200 * @param string
201 */
202 private void error(String string) {
203 Logger.getLogger(this.getClass().getName()).log(Level.FINE,string);
204 }
205 /***
206 * @return Returns the watchDirectories.
207 */
208 public List<File> getWatchDirectories() {
209 return watchDirectories;
210 }
211 /***
212 * @return Returns the baseClassLoader.
213 */
214 public ClassLoader getBaseClassLoader() {
215 return baseClassLoader;
216 }
217 /***
218 * @param baseClassLoader The baseClassLoader to set.
219 */
220 public void setBaseClassLoader(ClassLoader baseClassLoader) {
221 this.baseClassLoader = baseClassLoader;
222 }
223 }