Subversion Repositories XServices

Rev

Rev 198 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
102 brianR 1
/*
2
 *   Copyright 2013 Brian Rosenberger (Brutex Network)
3
 *
4
 *   Licensed under the Apache License, Version 2.0 (the "License");
5
 *   you may not use this file except in compliance with the License.
6
 *   You may obtain a copy of the License at
7
 *
8
 *       http://www.apache.org/licenses/LICENSE-2.0
9
 *
10
 *   Unless required by applicable law or agreed to in writing, software
11
 *   distributed under the License is distributed on an "AS IS" BASIS,
12
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
 *   See the License for the specific language governing permissions and
14
 *   limitations under the License.
15
 */
16
 
17
package net.brutex.xservices.util.cache;
18
 
19
import java.io.File;
20
import java.io.IOException;
21
import java.util.ArrayList;
22
import java.util.Enumeration;
23
import java.util.Iterator;
24
import java.util.List;
25
import java.util.concurrent.ExecutorService;
184 brianR 26
import java.util.concurrent.TimeUnit;
102 brianR 27
import java.util.regex.Matcher;
28
import java.util.regex.Pattern;
29
import javax.servlet.ServletContext;
30
import javax.servlet.ServletException;
31
import javax.servlet.http.HttpServlet;
32
import javax.ws.rs.core.Response;
199 brianR 33
 
34
import lombok.extern.slf4j.Slf4j;
102 brianR 35
import net.brutex.xservices.types.scm.ItemListType;
36
import net.brutex.xservices.types.scm.ItemType;
37
import net.brutex.xservices.types.scmfindings.FindingDetailsType;
38
import net.brutex.xservices.types.scmfindings.FindingType;
39
import net.brutex.xservices.types.scmfindings.FindingsListType;
40
import net.brutex.xservices.types.scmfindings.GroupMatchListType;
41
import net.brutex.xservices.types.scmfindings.ObjectFactory;
42
import net.brutex.xservices.ws.rs.CVSInfoImpl;
43
 
185 brianR 44
import org.apache.commons.configuration2.PropertiesConfiguration;
45
import org.apache.commons.configuration2.builder.fluent.Configurations;
46
import org.apache.commons.configuration2.ex.ConfigurationException;
47
import org.apache.commons.jcs.access.exception.CacheException;
48
 
199 brianR 49
 
102 brianR 50
/**
51
 * @author Brian Rosenberger, bru(at)brutex.de
52
 *
53
 */
199 brianR 54
@Slf4j
102 brianR 55
public class FindingsCacheServlet extends HttpServlet {
56
 
57
	private static final long serialVersionUID = 4041338473949999960L;
58
	private final List<File> configfiles = new ArrayList<File>();
59
	private final ObjectFactory FACTORY = new ObjectFactory();
184 brianR 60
	private ExecutorService executor;
102 brianR 61
 
62
	@Override
63
	public void init() throws ServletException {
64
		super.init();
184 brianR 65
		executor = (ExecutorService) getServletContext()
102 brianR 66
				.getAttribute("CACHE_EXECUTOR");
67
 
68
		if(! this.initConfigList()) return;
69
		if(! this.initConfigFindings()) return;
70
 
71
		int i = 1;
72
		for(File f: configfiles) {
73
			//Initialise configuration bean using default values
199 brianR 74
			FindingsConfigBean cbean = new FindingsConfigBean(i);
102 brianR 75
			i++;
76
 
77
 
78
 
79
			//Read cvs-cache-interval parameter
80
			try {
81
				int cacheinterval = Integer.parseInt(getServletContext()
82
						.getInitParameter("cvs-cache-interval"));
83
				cbean.setCacheinterval(cacheinterval);
199 brianR 84
				log.info("FindingsCacheServlet set to "+ cacheinterval + " minutes interval.");
102 brianR 85
			} catch (NumberFormatException e) {
199 brianR 86
				 log.warn("Could not read parameter 'cvs-cache-interval' from web.xml. Using default value '"
102 brianR 87
						+ cbean.getCacheinterval()+ "' minutes");
88
			}
89
 
185 brianR 90
			Configurations configs = new Configurations();
102 brianR 91
			PropertiesConfiguration config = null;
92
			try {
185 brianR 93
				config = configs.properties(f);
102 brianR 94
			} catch (ConfigurationException e) {
199 brianR 95
				log.error("Could not read parameter file at '"+f.getAbsolutePath()+"'");
102 brianR 96
				return;
97
			}
98
 
99
 
100
			File cvsconfig = new File(config.getString("CVSROOTCONFIGFILE"));
101
			cbean.setCvsconfig(cvsconfig);
199 brianR 102
			FindingsCacheServlet.log.debug("Fetching list of files using '"
102 brianR 103
					+ cvsconfig.getAbsolutePath() + "' config file");
104
 
105
 
106
			List<Object> filepatterns = config.getList("FILESEARCH");
107
			cbean.setFilepatterns(filepatterns);
199 brianR 108
			FindingsCacheServlet.log.debug("Checking '"
102 brianR 109
					+ filepatterns.size()
110
					+ "' patterns for file name and path matching.");
111
 
112
 
113
			List<Object> contentpatterns = config.getList("CONTENTSEARCH");
114
			cbean.setContentpatterns(contentpatterns);
199 brianR 115
			FindingsCacheServlet.log.debug("Checking '"
102 brianR 116
					+ contentpatterns.size()
117
					+ "' patterns for content matching");
118
 
119
 
120
 
121
 
122
			executor.submit(new ThisRunnable(cbean));
184 brianR 123
 
102 brianR 124
		}
199 brianR 125
		log.info("FindingsCacheServlet has been initialized.");
102 brianR 126
 
127
	}
128
 
129
	/*
130
	 * Initialise CVS findings configuration
131
	 */
132
	private boolean initConfigFindings() {
133
		String filename = getServletContext().getInitParameter(
134
				"cvs-findings-configuration");
135
		if (filename == null) {
199 brianR 136
			log.warn("'cvs-findings-configuration' init parameter is not specified.");
102 brianR 137
			return false;
138
		}
139
		final File findingsconfig = new File(filename);
199 brianR 140
		log.info("CVS findings configuration file found at '"
102 brianR 141
				+ findingsconfig.getAbsolutePath() + "'");
142
		if ((!findingsconfig.canRead()) || (findingsconfig.isDirectory())) {
199 brianR 143
			log.info("CVS findings configuration file '"
102 brianR 144
					+ findingsconfig.getAbsolutePath() + "' does not exist.");
145
			return false;
146
		}
147
		return true;
148
	}
149
 
150
	/*
151
	 * Add all specified CVS configuration files to the list. Parameter pattern
152
	 * is "cvs-config-XX".
153
	 */
154
	private boolean initConfigList() {
155
		Enumeration<String> attributes = getServletContext()
156
				.getInitParameterNames();
157
		while (attributes.hasMoreElements()) {
158
			String name = (String) attributes.nextElement();
159
			if (name.startsWith("cvs-config-")) {
160
				String configfile = getServletContext().getInitParameter(name);
199 brianR 161
				log.info("Adding CVS configuration file: " + configfile);
102 brianR 162
				this.configfiles.add(new File(configfile));
163
			}
164
		}
165
		/*
166
		 * Verify, that all configuration files do exists and are readable.
167
		 */
168
		List<File> removelist = new ArrayList<File>();
169
		for (File f : configfiles) {
170
			if (!f.exists()) {
199 brianR 171
				log.warn("CVS configuration file '"
102 brianR 172
						+ f.getAbsolutePath()
173
						+ "' is specified, but does not exist. Removing from list.");
174
				removelist.add(f);
175
			} else if (!f.canRead()) {
199 brianR 176
				log.warn("CVS configuration file '"
102 brianR 177
						+ f.getAbsolutePath()
178
						+ "' does exist, but is not readable. Removing from list.");
179
				removelist.add(f);
180
			}
181
		}
182
		configfiles.removeAll(removelist);
183
		return true;
184
	}
185
 
186
 
187
 
188
 
189
	class ThisRunnable implements Runnable {
190
		boolean isInterrupted = false;
191
		FindingsConfigBean configuration;
192
 
193
		public ThisRunnable(FindingsConfigBean configuration) {
194
			this.configuration = configuration;
195
		}
196
 
197
		public void run() {
198
			CVSInfoImpl instance = new CVSInfoImpl();
199
 
200
			ItemListType fileslist = (ItemListType) instance
201
					.getRepositoryFiles(null, configuration.getCvsconfig(), "", true, true, true)
202
					.getEntity();
203
			ObjectFactory FACTORY = new ObjectFactory();
204
			FindingsListType findingsList = FACTORY.createFindingsListType();
205
 
199 brianR 206
			FindingsCacheServlet.log.info("Processing '"
102 brianR 207
					+ fileslist.getItems().size() + "' files and directories.");
208
 
209
			while (!this.isInterrupted) {
210
				Pattern p;
211
				for (ItemType i : fileslist.getItems()) {
212
					if (this.isInterrupted)
213
						break;
214
					Iterator<Object> iterF = configuration.getFilepatterns().iterator();
215
					while(iterF.hasNext()) {
216
						Object o = iterF.next();
217
						if (this.isInterrupted)
218
							break;
199 brianR 219
						FindingsCacheServlet.log.debug("Scanning filename '"
102 brianR 220
								+ i.getFullname() + "' for pattern '"
221
								+ (String) o + "'");
222
						p = Pattern.compile((String) o);
223
						Matcher m = p.matcher(i.getFullname());
224
						if (m.find()) {
225
							FindingType finding = FACTORY.createFindingType();
226
							finding.setFilesearch(p.toString());
227
							ItemType it = (ItemType) instance.getFileContent(
228
									null, configuration.getCvsconfig(), i.getFullname(), true)
229
									.getEntity();
230
							finding.setContent(it.getContent());
231
							finding.setData(it.getData());
232
							finding = copyDetails(finding, i);
233
							findingsList.getFindings().add(finding);
199 brianR 234
							FindingsCacheServlet.log
102 brianR 235
									.debug("Match found for '"
236
											+ i.getFullname() + "'");
237
							break;
238
						}
199 brianR 239
						FindingsCacheServlet.log
102 brianR 240
								.debug("No match found for '" + i.getFullname()
241
										+ "'");
242
					}
243
				}
199 brianR 244
				FindingsCacheServlet.log
102 brianR 245
						.debug("Processing file content for '"
246
								+ findingsList.getFindings().size()
247
								+ "' entries in the list.");
248
 
249
				for (FindingType t : findingsList.getFindings()) {
250
					if (this.isInterrupted)
251
						break;
252
					boolean isFound = false;
253
					Matcher m;
254
					Iterator<Object> iter = configuration.getContentpatterns().iterator();
255
					while (iter.hasNext()) {
256
 
257
						Object o = iter.next();
258
						if (this.isInterrupted)
259
							break;
199 brianR 260
						FindingsCacheServlet.log
102 brianR 261
								.debug("Scanning file content for file '"
262
										+ t.getFullname() + "' for pattern '"
263
										+ (String) o + "'");
264
 
265
						Pattern p1 = Pattern.compile((String) o);
266
						m = p1.matcher(t.getContent());
267
						t.setContentsearch(p1.toString());
268
 
269
						isFound = true;
270
						int s = m.start();
271
						int e = m.end();
272
						String c = m.group();
273
 
274
						FindingDetailsType fd = FACTORY
275
								.createFindingDetailsType();
276
						GroupMatchListType gm = FACTORY
277
								.createGroupMatchListType();
278
						gm.setMatchAtIndex(s);
279
						gm.setMatchToIndex(e);
280
						gm.setMatchString(c);
281
						gm.setMatchGroup(0);
282
						fd.setFullmatch(gm);
283
						for (int i = 1; i <= m.groupCount(); i++) {
284
							GroupMatchListType gmg = FACTORY
285
									.createGroupMatchListType();
286
							s = m.start(i);
287
							e = m.end(i);
288
							c = m.group(i);
289
							gmg.setMatchAtIndex(s);
290
							gmg.setMatchToIndex(e);
291
							gmg.setMatchString(c);
292
							gmg.setMatchGroup(i);
293
							fd.getMatchLists().add(gmg);
294
						}
295
						t.getFindingLists().add(fd);
199 brianR 296
						FindingsCacheServlet.log
102 brianR 297
								.debug("Found matching content at index '" + s
298
										+ "' in file '" + t.getFullname()
299
										+ "' with pattern '" + p1.toString()
300
										+ "'");
301
					}
302
 
303
					if (!isFound) {
304
						findingsList.getFindings().remove(t);
199 brianR 305
						FindingsCacheServlet.log
102 brianR 306
								.debug("Found matching filename for '"
307
										+ t.getFullname()
308
										+ "' but content didn't match. Removing.");
309
					}
310
 
311
					try {
312
						instance.getCacheInstance().put(
313
								"FINDINGS-" + t.getROOT(), findingsList);
199 brianR 314
						FindingsCacheServlet.log
102 brianR 315
								.info("FINDINGS for CVSROOT '" + t.getROOT()
316
										+ "' have been updated in cache.");
317
					} catch (CacheException e) {
199 brianR 318
						FindingsCacheServlet.log.error(e.getMessage(), e);
102 brianR 319
					}
320
				}
321
				try {
322
					int cacheinterval = configuration.getCacheinterval();
199 brianR 323
					FindingsCacheServlet.log.debug("Now sleeping for '"
102 brianR 324
							+ cacheinterval + "' minutes");
325
					Thread.currentThread();
326
					Thread.sleep(cacheinterval * 60000);
199 brianR 327
					FindingsCacheServlet.log.debug("Waking up after '"
102 brianR 328
							+ cacheinterval + "' minutes of sleep");
329
				} catch (InterruptedException e) {
330
					this.isInterrupted = true;
199 brianR 331
					FindingsCacheServlet.log
102 brianR 332
							.warn("FindingsCacheServlet cache was interrupted. Shutting down.");
333
				}
334
			}
335
 
336
		}
337
 
338
		private FindingType copyDetails(FindingType finding, ItemType item) {
339
			finding.setDescription(item.getDescription());
340
			finding.setFullname(item.getFullname());
341
			finding.setName(item.getName());
342
			finding.setPath(item.getPath());
343
			finding.setRemotefullname(item.getRemotefullname());
344
			finding.setRemotename(item.getRemotename());
345
			finding.setRemotepath(item.getRemotepath());
346
			finding.setROOT(item.getROOT());
347
			return finding;
348
		}
349
 
350
	}
184 brianR 351
 
352
 
353
 
354
 
355
	/* (non-Javadoc)
356
	 * @see javax.servlet.GenericServlet#destroy()
357
	 */
358
	@Override
359
	public void destroy() {
360
		// TODO Auto-generated method stub
361
		executor.shutdown();
362
		try {
363
			executor.awaitTermination(3, TimeUnit.SECONDS);
199 brianR 364
			log.info("Cache Worker Threads have shut down.");
184 brianR 365
		} catch (InterruptedException e) {
199 brianR 366
			log.error("Cache Worker Threads did not terminate within timeout.", e);
184 brianR 367
		}
368
		super.destroy();
369
	}
370
 
102 brianR 371
}