1 /**
2 * Copyright 2005-2006 the original author or authors.
3 *
4 * Licensed under the Gnu General Pubic License, Version 2.0 (the
5 * "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.opensource.org/licenses/gpl-license.php
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the Gnu General Public License for more details.
14 */
15 package org.figure8.join.services.scripting.ant.tasks;
16
17 import org.figure8.join.services.remoting.ParameterService;
18 import org.figure8.join.services.remoting.InvalidSessionException;
19 import org.figure8.join.services.remoting.beans.RemoteParameter;
20 import org.figure8.join.services.security.InvalidLoginException;
21
22 import org.apache.tools.ant.Project;
23 import org.apache.tools.ant.BuildException;
24 import org.apache.tools.ant.DirectoryScanner;
25 import org.apache.tools.ant.types.FileSet;
26
27 import java.io.File;
28 import java.io.BufferedReader;
29 import java.io.FileReader;
30 import java.io.BufferedWriter;
31 import java.io.FileWriter;
32 import java.util.Map;
33 import java.util.List;
34 import java.util.HashMap;
35 import java.util.ArrayList;
36 import java.util.regex.Pattern;
37 import java.util.regex.Matcher;
38 import java.rmi.RemoteException;
39 /**
40 * This is an Ant task to use for substituting deployment parameters, into source files,
41 * by their values according to environment and deployment target.<br/> As an example,
42 * use a <i>substituteParams</i> that way to ensure substitution :<br/>
43 * <code>
44 * >substituteParams environmentKey="env01" targetName="full" regExp="\\$(\\w+)\\$"
45 * toDir="${dest.dir}"<<br/>
46 * >fileset dir="${src.dir}" includes="*.properties"/<<br/>
47 * >fileset dir="${src2.dir}" includes="*.xml"/<<br/>
48 * >substituteParams/<<br/>
49 * </code><br/>
50 * This task connects to Join server in order to dynamically retrieve the parameters
51 * name/value pairs for environment "env01" and target "full". It then uses the regular
52 * expression pattern "\$(\w+)\$" (this is its default value and you may omit it - be
53 * careful to double backslashes for Java string) to find the parameter names into source
54 * files contained into filesets.
55 * <br/>
56 * By default, if an exception occurs or if a found parameter has no value, the task
57 * produces a "SubstituteTask.log" log file into destination directory. You may change
58 * the name of this log file using the <i>log</i> attribute of task. If you may also want
59 * the task to fail on error, set the <i>failonerror</i> attribute to true.
60 * <br/>
61 * @author <a href="mailto:laurent.broudoux@free.fr">Laurent Broudoux</a>
62 * @version $Revision: 1.2 $
63 */
64 public class SubstituteParametersTask extends RemoteServiceTask{
65
66
67
68 /** Constant representing the default regular expression used : \$(\w+)\$ */
69 public static final String DEFAULT_REGEXP = "\\$(\\w+)\\$";
70 /** Constant representing the default name for log file */
71 public static final String DEFAULT_LOGFILE = "SubstituteTask.log";
72
73
74
75
76 /** The key of physical environment to use for retrieving parameter references */
77 private String environmentKey;
78 /** The name of deployment target to use for retrieving parameter references */
79 private String targetName;
80 /** The regular expression pattern for selecting parameters within files */
81 private String regExp = DEFAULT_REGEXP;
82 /** The destination directory for substituted files */
83 private String toDir;
84 /** The name of log file where to write errors or warning */
85 private String logFile = DEFAULT_LOGFILE;
86 /** Flag telling if substitution exceptions thrown a BuildException */
87 private boolean failonerror = false;
88
89 /** A list of Ant filesets to process */
90 private ArrayList fileSets = new ArrayList();
91
92 /** The file representation of toDir attribute */
93 private File destinationDir;
94
95
96
97
98 /** Creates a new instance of SubstituteParametersTask */
99 public SubstituteParametersTask(){
100 }
101
102
103
104
105 /** @return The key of physical environment to use for retrieving parameter references */
106 public String getEnvironmentKey(){
107 return environmentKey;
108 }
109 /** @param environmentKey The key of physical environment to use for retrieving parameter references */
110 public void setEnvironmentKey(String environmentKey){
111 this.environmentKey = environmentKey;
112 }
113
114 /** @return The name of deployment target to use for retrieving parameter references */
115 public String getTargetName(){
116 return targetName;
117 }
118 /** @param targetName The name of deployment target to use for retrieving parameter references */
119 public void setTargetName(String targetName){
120 this.targetName = targetName;
121 }
122
123 /** @return The regular expression pattern for selecting parameters within files */
124 public String getRegExp(){
125 return regExp;
126 }
127 /** @param regExp The regular expression pattern for selecting parameters within files */
128 public void setRegExp(String regExp){
129 this.regExp = regExp;
130 }
131
132 /** @return The destination directory for processed files */
133 public String getToDir(){
134 return toDir;
135 }
136 /** @param toDir The destination directory for processed files */
137 public void setToDir(String toDir){
138 this.toDir = toDir;
139 }
140
141 /** @return The name of log file where to write errors or warning */
142 public String getLogFile(){
143 return logFile;
144 }
145 /** @param logFile The name of log file where to write errors or warning */
146 public void setLogFile(String logFile){
147 this.logFile = logFile;
148 }
149
150 /** @return Flag telling if substitution exceptions thrown a BuildException */
151 public boolean isFailonerror(){
152 return failonerror;
153 }
154 /** @param failonerror Flag telling if substitution exceptions thrown a BuildException */
155 public void setFailonerror(boolean failonerror){
156 this.failonerror = failonerror;
157 }
158
159 /**
160 * Adds a set of files (nested fileset element)
161 * @param set A FileSet containing files to process
162 */
163 public void addFileset(FileSet set){
164 fileSets.add(set);
165 }
166
167
168
169
170 /**
171 * Execute this task : do the substitution according into configured filesets
172 * @throws BuildException if something wrong occurs during task process
173 */
174 public void execute() throws BuildException{
175
176 validateAttributes();
177
178 Map parametersMap = retrieveParametersMap();
179
180 doSubstitution(parametersMap);
181 }
182
183
184
185
186 /**
187 * Validate this task attributes before execution
188 * @throws BuildException if a mandatory attribute is not present
189 */
190 protected void validateAttributes() throws BuildException{
191
192 if (environmentKey == null || environmentKey.length() == 0)
193 throw new BuildException("No environment key specified for substituteParameters", getLocation());
194
195 if (targetName == null || targetName.length() == 0)
196 throw new BuildException("No deployment target specified for substituteParameters", getLocation());
197
198 if (toDir == null || toDir.length() == 0)
199 throw new BuildException("No destination directory specified for substituteParameters", getLocation());
200
201 destinationDir = new File(toDir);
202 if (!destinationDir.isDirectory())
203 throw new BuildException("The destination directory specified is not a valid directory", getLocation());
204
205 if (fileSets.isEmpty())
206 throw new BuildException("No FileSet specified for substituteParameters", getLocation());
207 }
208
209 /**
210 * Connect to remote service for retrieving a map containing parameters.
211 * @throws BuildException
212 */
213 protected Map retrieveParametersMap() throws BuildException{
214
215 ParameterService service = (ParameterService)retrieveRemoteService("ParameterService", ParameterService.class);
216
217 String token = null;
218 HashMap parametersMap = new HashMap();
219 try{
220
221 token = loginToRemoteService(service);
222 RemoteParameter[] parameters = service.getDeploymentParameters(token, environmentKey, targetName);
223
224 for (int i=0; i<parameters.length; i++)
225 parametersMap.put(parameters[i].getName(), parameters[i].getValue());
226 }
227 catch (InvalidLoginException ile){
228
229 log("InvalidLoginException while logging to remote service: " + ile.getMessage(), Project.MSG_ERR);
230 throw new BuildException("Exception while logging to remote service", ile, getLocation());
231 }
232 catch (InvalidSessionException ise){
233
234 log("InvalidSessionException while invoking remote service: " + ise.getMessage(), Project.MSG_ERR);
235 throw new BuildException("Exception while invoking remote service", ise, getLocation());
236 }
237 catch (RemoteException re){
238
239 log("RemoteException while logging to remote service: " + re.getMessage(), Project.MSG_ERR);
240 throw new BuildException("Exception while logging to remote service", re, getLocation());
241 }
242
243 releaseRemoteService(service, token);
244 return parametersMap;
245 }
246
247 /**
248 * Do the substitution using the given parameters map into the configured filesets
249 * @throws BuildException if exception occurs during log file writing or if errors
250 * and failonerror falgf is set to true
251 */
252 protected void doSubstitution(Map parametersMap) throws BuildException{
253
254 ArrayList globalMessages = new ArrayList();
255 Pattern pattern = Pattern.compile(regExp);
256
257
258 for (int i=0; i<fileSets.size(); i++){
259 FileSet set = (FileSet)fileSets.get(i);
260 DirectoryScanner scanner = set.getDirectoryScanner(getProject());
261
262 File sourceDir = set.getDir(getProject());
263 String[] fileNames = scanner.getIncludedFiles();
264
265
266 for (int j=0; i<fileNames.length; i++){
267 File src = new File(sourceDir, fileNames[i]);
268 File dest = new File(destinationDir, fileNames[j]);
269 List messages = doSubstitutionInFile(src, dest, pattern, parametersMap);
270
271 if (messages != null && !messages.isEmpty())
272 globalMessages.addAll(messages);
273 }
274 }
275
276
277 if (!globalMessages.isEmpty()){
278 BufferedWriter writer = null;
279 try{
280
281 writer = new BufferedWriter(new FileWriter(new File(destinationDir, logFile)));
282 for (int i=0; i<globalMessages.size(); i++){
283 String message = (String)globalMessages.get(i);
284 writer.write(message);
285 writer.newLine();
286 }
287 }
288 catch (Exception e){
289
290 log("Exception while writing log for substitution: " + e.getMessage(), Project.MSG_ERR);
291 throw new BuildException("Exception while writing log for substitution: " + e.getMessage());
292 }
293 finally{
294 try {writer.close();}
295 catch (Exception e) {log("Exception while closing writer", Project.MSG_DEBUG);}
296 }
297
298 if (failonerror){
299
300 log("Exception while doing parameters substitution. Check " + logFile + " log file!", Project.MSG_ERR);
301 throw new BuildException("Exception while doing parameters substitution. Check " + logFile + " log file!");
302 }
303 }
304 }
305
306 /**
307 * Do the substitution work from a source file into a destination file
308 * @param src The source file to substitute parameters in
309 * @param dest The destination file to write with parameters values
310 * @param pattern The regular expression pattern for selecting parameters into <b>src</b>
311 * @param parametersMap The map containing parameter name/value pairs
312 * @return A list containing substitution error messages (may be empty)
313 */
314 protected List doSubstitutionInFile(File src, File dest, Pattern pattern, Map parametersMap){
315
316 BufferedReader reader = null;
317 BufferedWriter writer = null;
318 ArrayList result = new ArrayList();
319
320 try{
321
322 reader = new BufferedReader(new FileReader(src));
323 writer = new BufferedWriter(new FileWriter(dest));
324
325 String line = null;
326
327 while ((line = reader.readLine()) != null){
328 Matcher matcher = pattern.matcher(line);
329 while (matcher.lookingAt()){
330 String param = matcher.group(1);
331 String value = (String)parametersMap.get(param);
332
333 if (value != null){
334
335 line = matcher.replaceFirst(value);
336 matcher.reset(line);
337 }
338 else{
339
340 log("Parameter '" + param + "' is unknown", Project.MSG_DEBUG);
341 result.add("Parameter '" + param + "' is unknown");
342 }
343 }
344
345 writer.write(line);
346 writer.newLine();
347 }
348 }
349 catch (Exception e){
350
351 log("Exception while doing substitution into file: " + src.getPath(), Project.MSG_WARN);
352 result.add("Exception while doing substitution into file: " + src.getPath());
353 }
354 finally{
355 try {writer.close();}
356 catch (Exception e) {log("Exception while closing writer", Project.MSG_DEBUG);}
357 try {reader.close();}
358 catch (Exception e) {log("Exception while closing reader", Project.MSG_DEBUG);}
359 }
360
361 return result;
362 }
363 }