KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > enhydra > barracuda > taskdefs > CopyAndReplace


1 /*
2  * Copyright (C) 2003 Christian Cryder [christianc@granitepeaks.com]
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17  *
18  * $Id: CopyAndReplace.java,v 1.13 2004/02/01 05:16:31 christianc Exp $
19  */

20 package org.enhydra.barracuda.taskdefs;
21
22 import java.util.*;
23 import java.io.*;
24 import org.apache.tools.ant.*;
25 import org.apache.tools.ant.taskdefs.*;
26 import org.apache.tools.ant.types.*;
27
28 /**
29  * <p>A consolidated copy and replace task that extends the basic Ant Copy
30  * taskdef.
31  *
32  * <p>In addition, once files have been copied, a replace function is also
33  * run on them. This replace will only affect the files that actually
34  * get copied; it will not affect any other files in the directory.
35  *
36  * <p>The replace occurs using a simply properties file, rather than
37  * specifying replace parameters via the xml. The format of this file
38  * looks something like this:
39  *
40  * <ul>
41  * <li>token="some target text" value="some replacement text"</li>
42  * <li>token='some target text called "blah"' value='some replacement text named "blech"'</li>
43  * <li>token=~some target text with " and '~ value=^some replacement text with ' and "^</li>
44  * </ul>
45  *
46  * <p>As you can see, the format is flexible. Tokens are identified with "token=" and
47  * values are identified by "value=". The actual token/value delimiters are
48  * taken to be the first character following the = sign. This could be a double
49  * quote, single quote, or any other character (ie. if the text you wish to
50  * replace contains both double and single quotes, you might want to use a ~
51  * delimiter or something like that).
52  *
53  * <p>Note also that this taskdef support SSI replacement, which can be quite useful.
54  * By default, the copied files are NOT processed for SSIs; if you want to use this,
55  * turn is on using the 'ssi=true' attribute. SSI replacement occurs BEFORE the token
56  * replacement (ensuring that the text contained in the SSI gets processed for tokens
57  * as well).
58  *
59  * @author Christian Cryder [christianc@granitepeaks.com]
60  */

61 public class CopyAndReplace extends Copy {
62
63     protected File mappingsFile = null; //the mappings file
64
protected boolean ssi = false; //process for ssi's //csc_111601.1 - added
65

66     /**
67      * Sets the mappings file.
68      */

69     public void setMappings(File mappingsFile) {
70         this.mappingsFile = mappingsFile;
71     }
72
73     //csc_111601.1 - added
74
/**
75      * Process files copied for ssi
76      *
77      * @param issi set "true" to process copied files for ssi
78      */

79     public void setSsi(BooleanAttribute issi) {
80         ssi = (issi.getValue().equals("yes") || issi.getValue().equals("true"));
81     }
82
83     /**
84       * processSSI is the result of a code refactoring due to changes in Ant 1.5 to Ant 1.6
85       * Ant 1.6 supports multiple target file, therefore processSSI might be called n-times
86       * @param fromFile
87       * @param toFile
88       */

89      protected void processSSI(String fromFile, String toFile) {
90          File targetFile = new File(toFile);
91          File fromDir = new File(fromFile).getParentFile();
92
93          //get the file (this will automatically resolve ssi's)
94
byte[] dstbytes = getFile(targetFile, fromDir);
95          if (dstbytes == null)
96              return;
97
98          //now write the file back out
99
try {
100              FileOutputStream fos = new FileOutputStream(targetFile);
101              fos.write(dstbytes);
102              fos.close();
103          } catch (IOException e) {
104              System.out.println("Error writing file " + targetFile + ":" + e);
105          }
106      }
107
108      /**
109       * perform the token-value based replacement. This method was introduced due to changes
110       * from Ant 1.5 to Ant 1.6. It might be called multiple times
111       * @param fromFile
112       * @param toFile
113       * @param tokenList
114       * @param valueList
115       */

116      protected void processReplace(String fromFile, String toFile, List tokenList, List valueList) {
117         File targetFile = new File(toFile);
118
119         //do the replace on each file (this is important: we only
120
//want to do the replace on files we actually copied in)
121
Replace replace = new Replace();
122         replace.setProject(this.getProject());
123         replace.setFile(targetFile);
124         for (int i=0, max=tokenList.size(); i<max; i++) {
125             Replace.Replacefilter rf = replace.createReplacefilter();
126             rf.setToken((String) tokenList.get(i));
127             rf.setValue((String) valueList.get(i));
128         }
129         replace.execute();
130      }
131
132      /**
133      * <p>Actually does the file (and possibly empty directory) copies.
134      * This is a good method for subclasses to override.
135      *
136      * <p>Note that all the copy functionality occurs by simply deferring
137      * to the superclass implementation. The replace functionality follows:
138      *
139      * <ul>
140      * <li><p>first we make sure there is a mappings file</li>
141      * <li><p>next we parse it to determine all token/value mapings</li>
142      * <li><p>finally we iterate through the list of files that actually
143      * got copied and we create Replace task for each of them. This
144      * task contains all the various token/value mappings, and
145      * gets executed for each file, effectively making all the
146      * necessary text substitutions</li>
147      * <ul>
148      */

149     protected void doFileOperations() {
150         //start by allowing the basic copy to occur
151
super.doFileOperations();
152
153         //csc_082802.1_start - move the following block of code up from down below.
154
//This was done in response to a patch submitted by Stefan Armbruster [sarmbruster@web.de]
155
//which allows CopyAndReplace to work if you only want to do SSI processing,
156
//and don't need to do any mapping. This change means that you no longer have
157
//to supply an empty mappings file.
158

159         //support ssi
160
if (ssi) {
161             if (fileCopyMap.size()>0) log("Processing copied files for server side includes");
162
163             Enumeration enum = fileCopyMap.keys();
164             while (enum.hasMoreElements()) {
165                 //figure out the target file
166
String fromFile = (String) enum.nextElement();
167
168                 // sam,2003-08-13: Ant 1.5 returns a String, Ant 1.6 returns a String[] (multiple targets)
169
Object target = fileCopyMap.get(fromFile);
170                 boolean isAnt15 = target instanceof String;
171                 if (isAnt15) {
172                     processSSI(fromFile, (String)target );
173                 } else {
174                     String[] targetArray = (String[]) target;
175                     for (int j = 0; j < targetArray.length; j++) {
176                         processSSI(fromFile, targetArray[j] );
177                     }
178                 }
179                 // sam_2003-08-13: end
180

181             }
182         }
183         //csc_082802.1_end
184

185         //if the mappings file is null or doesn't exist just return
186
if (mappingsFile==null) return;
187         List mappings = new ArrayList();
188         if (!mappingsFile.exists()) {
189             log("Unable to find mappings file: "+mappingsFile+" ... files copied but no text replace occurred", Project.MSG_ERR);
190             return;
191         }
192
193         //start by reading the mappings file
194
List tokenList = new ArrayList();
195         List valueList = new ArrayList();
196         try {
197             BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(mappingsFile)));
198             while (true) {
199                 String s = br.readLine();
200                 if (s==null) break;
201                 String token = null;
202                 String value = null;
203
204                 //get the token
205
int spos = s.indexOf("token=");
206                 if (spos<0 || spos+6>=s.length()) continue;
207                 spos+=6;
208                 String delim = s.substring(spos,spos+1);
209                 spos+=1;
210                 int epos = s.indexOf(delim, spos+1);
211                 if (epos<0 || epos+1>=s.length()) continue;
212                 token = s.substring(spos, epos);
213                 if (token==null) continue;
214
215                 //get the value
216
spos = s.indexOf("value=", epos+1);
217                 if (spos<0 || spos+6>=s.length()) continue;
218                 spos+=6;
219                 delim = s.substring(spos,spos+1);
220                 spos+=1;
221                 epos = s.indexOf(delim, spos+1);
222                 if (epos<0) continue;
223                 value = s.substring(spos, epos);
224                 if (value==null) continue;
225
226                 tokenList.add(token);
227                 valueList.add(value);
228             }
229         } catch (IOException e) {
230             System.out.println ("Error reading file "+mappingsFile+":"+e);
231             return;
232         }
233
234         //now iterate through the file copy list
235
if (fileCopyMap.size()>0) {
236             log("Replacing text in copied files");
237
238             Enumeration enum = fileCopyMap.keys();
239             while (enum.hasMoreElements()) {
240                 //figure out the target file
241
String fromFile = (String) enum.nextElement();
242
243                 // sam,2003-08-13: Ant 1.5 returns a String, Ant 1.6 returns a String[] (multiple targets)
244
Object target = fileCopyMap.get(fromFile);
245                 boolean isAnt15 = target instanceof String;
246                 if (isAnt15) {
247                     processReplace(fromFile, (String)target, tokenList, valueList );
248                 } else {
249                     String[] targetArray = (String[]) target;
250                     for (int j = 0; j < targetArray.length; j++) {
251                         processReplace(fromFile, targetArray[j], tokenList, valueList );
252                     }
253                 }
254                 // sam_2003-08-13: end
255
}
256         }
257     }
258
259     public static class BooleanAttribute extends EnumeratedAttribute {
260         public String[] getValues() {
261             return new String[] {"yes", "no", "true", "false"};
262         }
263     }
264
265
266     //csc_111601.1_start
267
private static String START_SSI = "<!--#include file=\"";
268     private static String END_SSI = "\"-->";
269
270     public byte[] getFile(File targetFile, File fromDir) {
271         //adjust the target file
272
if (!targetFile.exists() && fromDir!=null) {
273             String targetFileName = targetFile.getName();
274             targetFile = new File(fromDir, targetFileName);
275         }
276
277         //get the resource
278
byte[] dstbytes = new byte[10240];
279         try {
280             //read in the file and store it in a byte array
281
FileInputStream fis = new FileInputStream(targetFile);
282             BufferedInputStream in = new BufferedInputStream(fis);
283             int offset = 0;
284             int len = 1024;
285             byte[] inbytes = new byte[len];
286             while (true) {
287                 int cnt = in.read(inbytes, 0, len);
288                 if (cnt==-1) break;
289                 if (offset+cnt>=dstbytes.length) {
290                     byte[] newbytes = new byte[(int) (dstbytes.length+(len*5))];
291                     System.arraycopy(dstbytes, 0, newbytes, 0, dstbytes.length);
292                     dstbytes = newbytes;
293                 }
294                 System.arraycopy(inbytes, 0, dstbytes, offset, cnt);
295                 offset+=cnt;
296             }
297             in.close();
298
299             //when we're done trim off the excess
300
byte[] newbytes = new byte[offset];
301             System.arraycopy(dstbytes, 0, newbytes, 0, offset);
302             dstbytes = newbytes;
303
304             //now create a new string from the result, and process it for ssi's
305
//(this is not exactly the most efficient way of doing things, but it'll
306
//work for now...if you don't like it, optimize it and submit it back
307
//to the group ;-)
308
String result = new String(dstbytes);
309             int spos = 0;
310             int epos = 0;
311             while (true) {
312                 spos = result.indexOf(START_SSI, epos);
313                 if (spos<0) break;
314                 epos = result.indexOf(END_SSI, spos);
315                 if (epos<spos) break;
316                 String ssiName = result.substring(spos+START_SSI.length(), epos);
317                 File ssiFile = null;
318                 if (ssiFile==null || !ssiFile.exists()) ssiFile = new File(targetFile.getParent(), ssiName);
319                 if (ssiFile==null || !ssiFile.exists()) ssiFile = new File(fromDir, ssiName);
320                 if (ssiFile==null || !ssiFile.exists()) ssiFile = new File(ssiName);
321                 if (ssiFile==null || !ssiFile.exists()) {
322                     System.out.println ("Error locating SSI:"+ssiName);
323                     continue;
324                 }
325                 byte[] ssiBytes = getFile(ssiFile, null);
326                 if (ssiBytes!=null) result = result.substring(0,spos)+new String(ssiBytes)+result.substring(epos+END_SSI.length());
327             }
328             dstbytes = result.getBytes();
329
330         } catch (IOException e) {
331             System.out.println ("Error reading file "+targetFile+":"+e);
332             return null;
333         }
334         return dstbytes;
335     }
336     //csc_111601.1_end
337
}
338
Popular Tags