KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > emf > examples > jet > article2 > codegen > JETGateway


1 package org.eclipse.emf.examples.jet.article2.codegen;
2
3
4 import java.io.ByteArrayInputStream JavaDoc;
5 import java.io.InputStream JavaDoc;
6
7 import org.eclipse.core.resources.IContainer;
8 import org.eclipse.core.resources.IFile;
9 import org.eclipse.core.runtime.CoreException;
10 import org.eclipse.core.runtime.IPath;
11 import org.eclipse.core.runtime.IProgressMonitor;
12 import org.eclipse.core.runtime.NullProgressMonitor;
13 import org.eclipse.core.runtime.Path;
14 import org.eclipse.core.runtime.SubProgressMonitor;
15
16 import org.eclipse.emf.codegen.CodeGen;
17 import org.eclipse.emf.codegen.jet.JETEmitter;
18 import org.eclipse.emf.codegen.jet.JETException;
19 import org.eclipse.emf.codegen.jmerge.JControlModel;
20 import org.eclipse.emf.codegen.jmerge.JMerger;
21
22
23 /**
24  * This class encapsulates access to the JET and JMerge packages.
25  *
26  * @author Remko Popma
27  * @version $Revision: 1.2 $ ($Date: 2004/06/21 22:08:07 $)
28  */

29 public class JETGateway
30 {
31
32   private Config mConfig = null;
33
34   public JETGateway(Config config)
35   {
36     mConfig = config;
37   }
38
39   /**
40    * Invokes the JET template specified in the <code>Config</code> with the
41    * model specified in the <code>Config</code> and returns the generated text
42    * as a String.
43    * <p>
44    * This implementation uses a <code>JETEmitter</code> to translate the
45    * template to a Java implementation class. The translated class is created in
46    * a hidden project called <code>.JETEmitters</code>.
47    * <p>
48    * In order to be able to compile the translated template implementation
49    * class, the classes used by the model specified in the <code>Config</code>
50    * must be available in the classpath. For this reason, this method sets the
51    * first runtime library of the plugin specified in the <code>Config</code>
52    * as a classpath variable to the <code>.JETEmitters</code> project.
53    *
54    * @param monitor
55    * the progress monitor to use. May be <code>null</code>.
56    * @return the source code text generated by the JET template
57    * @throws CoreException
58    */

59   public String JavaDoc generate(IProgressMonitor monitor) throws CoreException
60   {
61     monitor = createIfNull(monitor);
62
63     Config config = getConfig();
64     JETEmitter emitter = new JETEmitter(config.getTemplateFullUri(), getClass().getClassLoader());
65     emitter.addVariable(config.getClasspathVariable(), config.getPluginId());
66
67     IProgressMonitor sub = new SubProgressMonitor(monitor, 1);
68     String JavaDoc result = emitter.generate(sub, new Object JavaDoc []{ config.getModel() });
69     monitor.worked(1);
70     return result;
71   }
72
73   /**
74    * Merges the specified emitterResult with the contents of an existing file
75    * and returns the result. The existing file is not modified.
76    * <p>
77    * The location of the file to merge with is found by finding or creating the
78    * container (folder) for the <code>Config</code>'s package in the
79    * <code>Config</code>'s target folder. The name of the file to merge with
80    * is the <code>Config</code>'s target file.
81    *
82    * @param monitor
83    * the progress monitor to use. May be <code>null</code>.
84    * @param emitterResult
85    * generated content to merge with the existing content
86    * @return the result of merging the specified generated contents with the
87    * existing file
88    * @throws CoreException
89    * if an error occurs accessing the contents of the file
90    */

91   public String JavaDoc merge(IProgressMonitor monitor, String JavaDoc emitterResult) throws CoreException
92   {
93     monitor = createIfNull(monitor);
94
95     Config config = getConfig();
96     IContainer container = findOrCreateContainer(monitor, config.getTargetFolder(), config.getPackageName());
97     if (container == null)
98     {
99       throw new JETException("Cound not find or create container for package " + config.getPackageName() + " in "
100         + config.getTargetFolder());
101     }
102
103     IFile targetFile = container.getFile(new Path(config.getTargetFile()));
104     if (!targetFile.exists())
105     {
106       monitor.worked(1);
107       return emitterResult;
108     }
109
110     JMerger jMerger = new JMerger();
111     jMerger.setControlModel(new JControlModel(config.getMergeXmlFullUri()));
112     jMerger.setSourceCompilationUnit(jMerger.createCompilationUnitForContents(emitterResult));
113
114     jMerger.setTargetCompilationUnit(jMerger.createCompilationUnitForInputStream(targetFile.getContents(true)));
115     String JavaDoc oldContents = jMerger.getTargetCompilationUnit().getContents();
116
117     jMerger.merge();
118     monitor.worked(1);
119
120     String JavaDoc result = jMerger.getTargetCompilationUnit().getContents();
121     if (oldContents.equals(result))
122     {
123       return result;
124     }
125
126     if (!targetFile.isReadOnly())
127     {
128       return result;
129     }
130
131     // The file may be read-only because it is checked out
132
// by a VCM component. Here we ask permission to change the file.
133
if (targetFile.getWorkspace().validateEdit(new IFile []{ targetFile }, new SubProgressMonitor(monitor, 1)).isOK())
134     {
135
136       jMerger.setTargetCompilationUnit(jMerger.createCompilationUnitForInputStream(targetFile.getContents(true)));
137       jMerger.remerge();
138       return jMerger.getTargetCompilationUnit().getContents();
139     }
140     return result;
141   }
142
143   /**
144    * Saves the specified contents to a location specified by the
145    * <code>Config</code> settings. The location of the file to save is found
146    * by finding or creating the container (folder) for the <code>Config</code>
147    * 's package in the <code>Config</code>'s target folder. The name of the
148    * file to save is the <code>Config</code>'s target file.
149    *
150    * @param monitor
151    * the progress monitor to use. May be <code>null</code>.
152    * @param contents
153    * the byte contents of the file to save
154    * @throws CoreException
155    */

156   public IFile save(IProgressMonitor monitor, byte[] contents) throws CoreException
157   {
158     monitor = createIfNull(monitor);
159
160     Config config = getConfig();
161     IContainer container = findOrCreateContainer(monitor, config.getTargetFolder(), config.getPackageName());
162     if (container == null)
163     {
164       throw new JETException("Cound not find or create container for package " + config.getPackageName() + " in "
165         + config.getTargetFolder());
166     }
167     IFile targetFile = container.getFile(new Path(config.getTargetFile()));
168     IFile result = getWritableTargetFile(targetFile, container, config.getTargetFile());
169
170     InputStream JavaDoc newContents = new ByteArrayInputStream JavaDoc(contents);
171     if (result.exists())
172     {
173       result.setContents(newContents, true, true, new SubProgressMonitor(monitor, 1));
174     }
175     else
176     {
177       result.create(newContents, true, new SubProgressMonitor(monitor, 1));
178     }
179     return result;
180   }
181
182   /**
183    * Returns a non-null progress monitor.
184    *
185    * @param monitor
186    * an existing progress monitor
187    * @return a new <code>NullProgressMonitor</code> if the specified monitor
188    * is <code>null</code>, or the existing monitor otherwise
189    */

190   private IProgressMonitor createIfNull(IProgressMonitor monitor)
191   {
192     if (monitor == null)
193     {
194       return new NullProgressMonitor();
195     }
196     return monitor;
197   }
198
199   private IContainer findOrCreateContainer(IProgressMonitor progressMonitor, String JavaDoc targetDirectory, String JavaDoc packageName) throws CoreException
200   {
201
202     IPath outputPath = new Path(targetDirectory + "/" + packageName.replace('.', '/'));
203     progressMonitor.beginTask("", 4);
204
205     IProgressMonitor sub = new SubProgressMonitor(progressMonitor, 1);
206     IPath localLocation = null; // use default
207
IContainer container = CodeGen.findOrCreateContainer(outputPath, true, localLocation, sub);
208     return container;
209   }
210
211   /**
212    * Returns a <code>IFile</code> that can be written to. If the specified
213    * file is read-write, it is returned unchanged. If the specified file is
214    * read-only and {@link Config#isForceOverwrite()}returns <code>true</code>,
215    * the file is made writable, otherwise a new file is returned in the
216    * specified container with filename <code>"." + fileName + ".new"</code>.
217    *
218    * @param container
219    * container to create the new file in if the specified file cannot
220    * be made writable
221    * @param targetFile
222    * the file to make writable
223    * @param fileName
224    * used to create a new file name if the specified file cannot be
225    * made writable
226    * @return a <code>IFile</code> that can be written to
227    */

228   private IFile getWritableTargetFile(IFile targetFile, IContainer container, String JavaDoc fileName)
229   {
230     if (targetFile.isReadOnly())
231     {
232       if (getConfig().isForceOverwrite())
233       {
234         targetFile.setReadOnly(false);
235       }
236       else
237       {
238         targetFile = container.getFile(new Path("." + fileName + ".new"));
239       }
240     }
241     return targetFile;
242   }
243
244   /**
245    * Returns the <code>Config</code> object
246    *
247    * @return the <code>Config</code> object
248    */

249   protected Config getConfig()
250   {
251     return mConfig;
252   }
253 }
Popular Tags