KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > go > teaservlet > util > RemoteCompiler


1 /* ====================================================================
2  * Tea - Copyright (c) 1997-2000 Walt Disney Internet Group
3  * ====================================================================
4  * The Tea Software License, Version 1.1
5  *
6  * Copyright (c) 2000 Walt Disney Internet Group. All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  *
20  * 3. The end-user documentation included with the redistribution,
21  * if any, must include the following acknowledgment:
22  * "This product includes software developed by the
23  * Walt Disney Internet Group (http://opensource.go.com/)."
24  * Alternately, this acknowledgment may appear in the software itself,
25  * if and wherever such third-party acknowledgments normally appear.
26  *
27  * 4. The names "Tea", "TeaServlet", "Kettle", "Trove" and "BeanDoc" must
28  * not be used to endorse or promote products derived from this
29  * software without prior written permission. For written
30  * permission, please contact opensource@dig.com.
31  *
32  * 5. Products derived from this software may not be called "Tea",
33  * "TeaServlet", "Kettle" or "Trove", nor may "Tea", "TeaServlet",
34  * "Kettle", "Trove" or "BeanDoc" appear in their name, without prior
35  * written permission of the Walt Disney Internet Group.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE WALT DISNEY INTERNET GROUP OR ITS
41  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
42  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
43  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
44  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
45  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
47  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  * ====================================================================
49  *
50  * For more information about Tea, please see http://opensource.go.com/.
51  */

52
53 package com.go.teaservlet.util;
54
55 import java.io.IOException JavaDoc;
56 import java.io.InputStream JavaDoc;
57 import java.io.File JavaDoc;
58 import java.io.BufferedInputStream JavaDoc;
59 import java.io.Reader JavaDoc;
60 import java.io.InputStreamReader JavaDoc;
61 import java.io.OutputStream JavaDoc;
62 import java.io.BufferedOutputStream JavaDoc;
63 import java.io.FileOutputStream JavaDoc;
64 import java.io.StreamTokenizer JavaDoc;
65 import java.net.Socket JavaDoc;
66 import java.util.Collection JavaDoc;
67 import java.util.Map JavaDoc;
68 import java.util.TreeMap JavaDoc;
69 import java.util.Arrays JavaDoc;
70 import java.util.Vector JavaDoc;
71 import com.go.trove.util.ClassInjector;
72 import com.go.trove.io.DualOutput;
73 import com.go.tea.compiler.Compiler;
74 import com.go.tea.compiler.CompilationUnit;
75 import com.go.tea.compiler.ErrorListener;
76 import com.go.tea.util.AbstractFileCompiler;
77
78 /******************************************************************************
79  * RemoteCompiler compiles tea source files by reading them from a remote
80  * location specified by a URL. The compiled code can be written as class files
81  * to a given destination directory, they can be passed to a ClassInjector, or
82  * they can be sent to both.
83  *
84  * <p>When given a URL, RemoteCompiler compiles all files with the
85  * extension ".tea". If a destination directory is used, tea files that have a
86  * matching class file that is more up-to-date will not be compiled, unless
87  * they are forced to be re-compiled.
88  *
89  * @author Jonathan Colwell
90  * @version
91  * <!--$$Revision:--> 6 <!-- $--> 21 <!-- $$JustDate:--> 00/12/13 <!-- $-->
92  * @see ClassInjector
93  */

94 public class RemoteCompiler extends AbstractFileCompiler {
95     
96     private static final String JavaDoc TEMPLATE_LOAD_PROTOCOL = "http://";
97     private String JavaDoc[] mRemoteSourceDirs;
98     private String JavaDoc mRootPackage;
99     private File JavaDoc mRootDestDir;
100     private ClassInjector mInjector;
101     private String JavaDoc mEncoding;
102     private boolean mForce = false;
103     private Map JavaDoc mTemplateMap;
104     
105     
106     public RemoteCompiler(String JavaDoc[] rootSourceDirs,
107                           String JavaDoc rootPackage,
108                           File JavaDoc rootDestDir,
109                           ClassInjector injector,
110                           String JavaDoc encoding) {
111         super();
112         mRemoteSourceDirs = rootSourceDirs;
113         mRootPackage = rootPackage;
114         mRootDestDir = rootDestDir;
115         mInjector = injector;
116         mEncoding = encoding;
117
118         if (mRootDestDir != null &&
119             !mRootDestDir.isDirectory()) {
120             throw new IllegalArgumentException JavaDoc
121                 ("Destination is not a directory: " + rootDestDir);
122         }
123
124         mTemplateMap = retrieveTemplateMap();
125     }
126
127     /**
128      * @param force When true, compile all source, even if up-to-date
129      */

130     public void setForceCompile(boolean force) {
131         mForce = force;
132     }
133     
134     /**
135      * Checks that the source code for a specified template exists.
136      */

137     public boolean sourceExists(String JavaDoc name) {
138         return mTemplateMap.containsKey(name);
139     }
140     
141     public String JavaDoc[] getAllTemplateNames() {
142         return (String JavaDoc[])mTemplateMap.keySet().toArray(new String JavaDoc[0]);
143     }
144
145     /**
146      * Overrides the method from Compiler to allow timestamp synchronization
147      * after the actual compilation has taken place.
148      */

149     public String JavaDoc[] compile(String JavaDoc[] names) throws IOException JavaDoc {
150         String JavaDoc[] compiled = super.compile(names);
151         for (int j=0;j<names.length;j++) {
152             syncSources(names[j]);
153         }
154         return compiled;
155     }
156     
157     protected CompilationUnit createCompilationUnit(String JavaDoc name) {
158         return new Unit(name,this);
159     }
160
161     /**
162      * sets the template classes to have the same timestamp as the sources
163      * to account for differences between the machine clocks.
164      */

165     private void syncSources(String JavaDoc name) {
166         TemplateSourceInfo info = (TemplateSourceInfo)mTemplateMap.get(name);
167         Unit compUnit = (Unit)this.getCompilationUnit(name,null);
168         compUnit.getDestinationFile().setLastModified(info.timestamp);
169     }
170       
171     /**
172      * returns a socket connected to a host running the TemplateServerServlet
173      */

174     private Socket JavaDoc getTemplateServerSocket(String JavaDoc remoteSource) throws IOException JavaDoc {
175         int port = 80;
176         String JavaDoc host = remoteSource.substring(TEMPLATE_LOAD_PROTOCOL.length());
177         int portIndex = host.indexOf("/");
178         
179         if (portIndex >= 0) {
180             host = host.substring(0,portIndex);
181         }
182         
183         portIndex = host.indexOf(":");
184         if (portIndex >= 0) {
185             try {
186                 port = Integer.parseInt(host.substring(portIndex+1));
187             }
188             catch (NumberFormatException JavaDoc nfe) {
189                 System.out.println("Invalid port number specified");
190             }
191             host = host.substring(0,portIndex);
192         }
193         return new Socket JavaDoc(host,port);
194     }
195     
196     /**
197      * turns a template name and a servlet path into a
198      */

199     private byte[] createTemplateServerRequest(String JavaDoc servletPath,String JavaDoc templateName) {
200         String JavaDoc pathInfo = servletPath.substring(servletPath.indexOf("/",TEMPLATE_LOAD_PROTOCOL.length()));
201         if (templateName != null) {
202             pathInfo = pathInfo + templateName;
203         }
204         return ("GET " + pathInfo + " HTTP/1.0\r\n\r\n").getBytes();
205     }
206     
207     /**
208      * creates a map relating the templates found on the template server
209      * to the timestamp on the sourcecode
210      */

211     private Map JavaDoc retrieveTemplateMap() {
212         Map JavaDoc templateMap = new TreeMap JavaDoc();
213         for (int j=0;j<mRemoteSourceDirs.length;j++) {
214             String JavaDoc remoteSource = mRemoteSourceDirs[j];
215             if (!remoteSource.endsWith("/")) {
216                 remoteSource = remoteSource + "/";
217             }
218             
219             try {
220                 Socket JavaDoc tsSock = getTemplateServerSocket(remoteSource);
221                 OutputStream JavaDoc out = new BufferedOutputStream JavaDoc(
222                                     tsSock.getOutputStream());
223                 Reader JavaDoc rin = new InputStreamReader JavaDoc(new BufferedInputStream JavaDoc(
224                                     tsSock.getInputStream()));
225
226                 out.write(createTemplateServerRequest(remoteSource,null));
227                 out.flush();
228                 StreamTokenizer JavaDoc st = new StreamTokenizer JavaDoc(rin);
229                 st.resetSyntax();
230                 st.wordChars('!','{');
231                 st.wordChars('}','}');
232                 st.whitespaceChars(0,' ');
233                 st.parseNumbers();
234                 st.quoteChar('|');
235                 st.eolIsSignificant(true);
236                 String JavaDoc templateName = null;
237                 int tokenID = 0;
238                 // ditching the headers by looking for "\r\n\r\n"
239
while (!((tokenID = st.nextToken()) == StreamTokenizer.TT_EOL
240                             && st.nextToken() == StreamTokenizer.TT_EOL)
241                             && tokenID != StreamTokenizer.TT_EOF) {
242                 }
243                 while ((tokenID = st.nextToken()) != StreamTokenizer.TT_EOF) {
244                     if (tokenID == '|' || tokenID == StreamTokenizer.TT_WORD) {
245                         
246                         templateName = st.sval;
247                     }
248                     else if (tokenID == StreamTokenizer.TT_NUMBER
249                             && templateName != null) {
250                         templateName = templateName.substring(1);
251                         //System.out.println(templateName);
252
templateMap.put(templateName.replace('/','.'),
253                                     new TemplateSourceInfo(
254                                     templateName,
255                                     remoteSource,
256                                     (long)st.nval));
257                         templateName = null;
258                     }
259                 }
260                 out.close();
261                 rin.close();
262             }
263             catch (IOException JavaDoc ioe) {
264                 ioe.printStackTrace();
265             }
266         }
267         //System.out.println("retrieving templateMap");
268
return templateMap;
269     }
270     
271     /**
272      * inner class to store a templates' name, server location and timestamp
273      */

274     private class TemplateSourceInfo {
275         public String JavaDoc name;
276         public String JavaDoc server;
277         public long timestamp;
278         
279         TemplateSourceInfo(String JavaDoc name,String JavaDoc server,long timestamp) {
280             this.name = name;
281             this.server = server;
282             this.timestamp = timestamp;
283         }
284     }
285     
286     public class Unit extends CompilationUnit {
287         
288         private String JavaDoc mSourceFilePath;
289         private File JavaDoc mDestDir;
290         private File JavaDoc mDestFile;
291         
292         Unit(String JavaDoc name, Compiler JavaDoc compiler) {
293             super(name,compiler);
294             mSourceFilePath = name;
295             String JavaDoc slashPath = mSourceFilePath.replace('.',File.separatorChar);
296             if (slashPath.lastIndexOf(File.separatorChar) >= 0) {
297                 mDestDir = new File JavaDoc
298                     (mRootDestDir,
299                      slashPath.substring(0,slashPath.lastIndexOf(File.separatorChar)));
300             }
301             else {
302                 mDestDir = mRootDestDir;
303             }
304             mDestDir.mkdirs();
305             mDestFile = new File JavaDoc
306                 (mDestDir,
307                  slashPath.substring(slashPath.lastIndexOf(File.separatorChar) + 1) + ".class");
308             /*
309             try {
310                 if (mDestFile.createNewFile()) {
311                     System.out.println(mDestFile.getPath() + " created");
312                 }
313                 else {
314                     System.out.println(mDestFile.getPath() + " NOT created");
315                 }
316             }
317             catch (IOException ioe) {ioe.printStackTrace();}
318             */

319         }
320
321         public String JavaDoc getTargetPackage() {
322             return mRootPackage;
323         }
324
325         public String JavaDoc getSourceFileName() {
326             return mSourceFilePath.substring
327                 (mSourceFilePath.lastIndexOf('.') + 1) + ".tea";
328         }
329
330
331         public Reader JavaDoc getReader() throws IOException JavaDoc {
332             Reader JavaDoc reader = null;
333             InputStream JavaDoc in = getTemplateSource(mSourceFilePath);
334             if (mEncoding == null) {
335                 reader = new InputStreamReader JavaDoc(in);
336             }
337             else {
338                 reader = new InputStreamReader JavaDoc(in, mEncoding);
339             }
340             
341             while(!(reader.read() == '\n' && reader.read() == '\r')) {}
342             reader.read();
343             return reader;
344         }
345
346         public boolean shouldCompile() {
347             if (!mForce &&
348                 mDestFile != null &&
349                 mDestFile.exists() &&
350                 mDestFile.lastModified() >=
351                     ((TemplateSourceInfo)mTemplateMap
352                     .get(mSourceFilePath)).timestamp) {
353
354                 return false;
355             }
356             return true;
357         }
358         
359
360         /**
361          * @return the file that gets written by the compiler.
362          */

363         public File JavaDoc getDestinationFile() {
364             return mDestFile;
365         }
366
367         public OutputStream JavaDoc getOutputStream() throws IOException JavaDoc {
368             OutputStream JavaDoc out1 = null;
369             OutputStream JavaDoc out2 = null;
370
371             if (mDestDir != null) {
372                 if (!mDestDir.exists()) {
373                     mDestDir.mkdirs();
374                 }
375
376                 out1 = new FileOutputStream JavaDoc(mDestFile);
377             }
378
379             if (mInjector != null) {
380                 String JavaDoc className = getName();
381                 String JavaDoc pack = getTargetPackage();
382                 if (pack != null && pack.length() > 0) {
383                     className = pack + '.' + className;
384                 }
385                 out2 = mInjector.getStream(className);
386             }
387
388             OutputStream JavaDoc out;
389
390             if (out1 != null) {
391                 if (out2 != null) {
392                     out = new DualOutput(out1, out2);
393                 }
394                 else {
395                     out = out1;
396                 }
397             }
398             else if (out2 != null) {
399                 out = out2;
400             }
401             else {
402                 out = new OutputStream JavaDoc() {
403                     public void write(int b) {}
404                     public void write(byte[] b, int off, int len) {}
405                 };
406             }
407
408             return new BufferedOutputStream JavaDoc(out);
409         }
410         
411         /**
412          * get a input stream containing the template source data.
413          */

414         private InputStream JavaDoc getTemplateSource(String JavaDoc templateSourceName)
415                                                         throws IOException JavaDoc {
416             TemplateSourceInfo tsInfo = (TemplateSourceInfo)mTemplateMap
417                                                 .get(templateSourceName);
418             Socket JavaDoc sock = getTemplateServerSocket(tsInfo.server);
419             OutputStream JavaDoc out = new BufferedOutputStream JavaDoc(
420                                 sock.getOutputStream());
421             InputStream JavaDoc in = new BufferedInputStream JavaDoc(sock.getInputStream());
422
423             out.write(createTemplateServerRequest(tsInfo.server,tsInfo.name + ".tea"));
424             out.flush();
425             //out.close();
426
return in;
427         }
428     }
429 }
430
Popular Tags