001: package com.xoetrope.template;
002:
003: import java.io.File;
004: import java.io.FilenameFilter;
005: import java.util.HashMap;
006: import java.util.Hashtable;
007: import net.xoetrope.xui.XProject;
008: import net.xoetrope.xui.evaluator.XDefaultAttributeEvaluator;
009:
010: /**
011: * An engine for processing templates containing paramaterized resources.
012: *
013: * <p> Copyright (c) Xoetrope Ltd., 2001-2007, This software is licensed under
014: * the GNU Public License (GPL), please see license.txt for more details. If
015: * you make commercial use of this software you must purchase a commercial
016: * license from Xoetrope.</p>
017: * <p> $Revision: 1.5 $</p>
018: */
019: public class XTemplateEngine {
020: protected String sourcePath;
021: protected String targetPath;
022: protected File sourceDir, targetDir;
023:
024: protected Hashtable<String, XTemplateProcessor> processors;
025:
026: protected XProject currentProject;
027: protected XDefaultAttributeEvaluator evaluator;
028: protected HashMap includes, contents;
029:
030: /**
031: * Creates a new instance of TemplateEngine
032: * @param proj the owner project
033: * @param source the source folder for the templates
034: * @param target the target folder for the template output
035: */
036: public XTemplateEngine(XProject proj, String source, String target) {
037: currentProject = proj;
038:
039: sourcePath = source;
040: targetPath = target;
041: sourceDir = new File(sourcePath);
042: targetDir = new File(targetPath);
043:
044: processors = new Hashtable<String, XTemplateProcessor>();
045:
046: includes = new HashMap();
047: contents = new HashMap();
048: }
049:
050: /**
051: * Process the template resources.
052: * @param sourceResources the resources to process, the file names may contain
053: * wildcard characters
054: * @param targetResources the resources name following processing, the file
055: * names may contain wildcard characters, but they should match the pattern of
056: * the sourceResource argument. The number of array elements should also
057: * match that of the sourceResource. A null value may be passed for an
058: * element or for the argument, in which case the getTargetResourceName
059: * should fixup the resource name.
060: *
061: * @return zero if processing is sucessful or a positive integer if processing
062: * is completed, but with warnings, and a negative value if an error occurs
063: * that prevents complete processing
064: */
065: public int process(String[] sourceResources) {
066: return process(sourceResources, null, null);
067: }
068:
069: /**
070: * Process the template resources.
071: * @param sourceResources the resources to process, the file names may contain
072: * wildcard characters
073: * @param targetResources the resources name following processing, the file
074: * names may contain wildcard characters, but they should match the pattern of
075: * the sourceResource argument. The number of array elements should also
076: * match that of the sourceResource. A null value may be passed for an
077: * element or for the argument, in which case the getTargetResourceName
078: * should fixup the resource name.
079: * @param processingType the type of processing
080: * @return zero if processing is sucessful or a positive integer if processing
081: * is completed, but with warnings, and a negative value if an error occurs
082: * that prevents complete processing
083: */
084: public int process(String[] sourceResources,
085: String[] targetResources, int[] processingTypes) {
086: File sourceDir = new File(sourcePath);
087:
088: int numItems = sourceResources.length;
089: for (int i = 0; i < numItems; i++) {
090: String resource = sourceResources[i];
091: int pt = processingTypes != null ? processingTypes[i]
092: : XTemplateProcessor.COPY_FILE;
093: final String wildcardStr = replaceWildcards(resource);
094: File[] files = sourceDir.listFiles(new FilenameFilter() {
095: public boolean accept(File dir, String name) {
096: return (name.toLowerCase().matches(wildcardStr));
097: }
098: });
099:
100: if (files == null) {
101: files = new File[1];
102: files[0] = new File(sourceDir, resource);
103: }
104:
105: int numFiles = files.length;
106: for (int j = 0; j < numFiles; j++) {
107: String sourceName = files[j].getPath();
108: String targetResource = null;
109: if (targetResources != null)
110: targetResource = targetResources[i];
111: String targetName = getTargetResourceName(resource,
112: sourceName, targetResource, pt);
113:
114: XTemplateProcessor processor = getProcessor(sourceName,
115: pt);
116: processor.process(sourceName, targetName, pt);
117: }
118: }
119: return 0;
120: }
121:
122: /**
123: * Get the processor for a particular type
124: * @param sourceName the resource name
125: * @param processingType the processing instruction
126: * @return the appropriate Processor
127: */
128: public XTemplateProcessor getProcessor(String sourceName,
129: int processingType) {
130: String extension = sourceName.substring(sourceName
131: .lastIndexOf('.'));
132: XTemplateProcessor processor = null;
133: switch (processingType) {
134: case XTemplateProcessor.COPY_FILE:
135: if (extension.equalsIgnoreCase(".xml")) {
136: processor = processors.get(extension);
137: if (processor == null)
138: processors.put(extension,
139: processor = new XXmlTemplateProcessor(
140: currentProject, this ));
141: return processor;
142: } else if (extension.equalsIgnoreCase(".java")
143: || extension.equalsIgnoreCase(".java_template")) {
144: processor = processors.get(extension);
145: if (processor == null)
146: processors.put(extension,
147: processor = new XJavaTemplateProcessor(
148: currentProject, this ));
149: return processor;
150: } else if (extension.equalsIgnoreCase(".properties")) {
151: processor = processors.get(extension);
152: if (processor == null)
153: processors
154: .put(
155: extension,
156: processor = new XPropertiesTemplateProcessor(
157: currentProject, this ));
158: return processor;
159: } else {
160: processor = processors.get(extension);
161: if (processor == null)
162: processors.put(extension,
163: processor = new XResourceTemplateProcessor(
164: currentProject, this ));
165: return processor;
166: }
167: case XTemplateProcessor.RENAME_FILE:
168: break;
169: case XTemplateProcessor.RENAME_ELEMENT:
170: break;
171: case XTemplateProcessor.APPLY_RESOURCE:
172: break;
173: case XTemplateProcessor.PROCESSING_INSTRUCTION:
174: break;
175: }
176:
177: return null;
178: }
179:
180: /**
181: * Get the name of the resource when processed
182: * @param sourcePattern the pattern used to find the source file, the file name may contain
183: * wildcard characters
184: * @param sourceName the actual resource to process
185: * @param targetPattern the resource name/pattern following processing, the file
186: * name may contain wildcard characters, but they should match the pattern of
187: * the sourceResource argument.
188: * @param processingType the type of processing
189: * @return the new resource name
190: */
191: public String getTargetResourceName(String sourcePattern,
192: String sourceName, String targetPattern, int processingType) {
193: if (targetPattern != null) {
194: /** @todo process the wildcard characters fully. This only replaces file extensions*/
195: String srcFile = sourceName
196: .substring(sourcePath.length() + 1);
197: // Matcher sourceMatcher = Pattern.compile( replaceWildcards( sourcePattern )).matcher( srcFile );
198: // sourceMatcher.find();
199: //
200: // targetPattern = replaceWildcards( replaceWildcards( targetPattern ));
201: // int start = sourceMatcher.regionStart();
202: // int end = sourceMatcher.regionEnd();
203: // String[] ss = srcFile.split( sourcePattern );
204: // String s2 = srcFile.replace( replaceWildcards( sourcePattern ), replaceWildcards( targetPattern ));
205: // String targetFile = srcFile.substring( 0, start );
206: // targetFile += srcFile.substring( start, end );
207: // targetFile += srcFile.substring( end );
208:
209: // Hack - assumes pattern is *.ext
210: if (targetPattern.indexOf("*") >= 0) {
211: String targetFile = srcFile.substring(0, srcFile
212: .indexOf("."));
213: targetFile += targetPattern.substring(targetPattern
214: .indexOf("."));
215:
216: return new File(targetDir, targetFile).getPath();
217: }
218:
219: return new File(targetDir, targetPattern).getPath();
220: }
221:
222: return new File(targetDir, sourcePattern).getPath();
223: }
224:
225: /**
226: * Include a given element
227: * @param elementName the name of the element
228: * @return true if the element is included, false if it is to be excluded.
229: */
230: public boolean includes(String elementName) {
231: return true;
232: }
233:
234: /**
235: * Evaluates an attribute value. An attribute may be a value or a method call.
236: * If brackets are part of the value it is assumed that a method call is
237: * intended. The method call is indicated by the '$' symbol e.g. ${myMethod()}
238: * @param attribValue the raw attribute value
239: * @return the evaluated attribute
240: */
241: public Object evaluateAttribute(String attribValue) {
242: if (evaluator == null) {
243: evaluator = (XDefaultAttributeEvaluator) currentProject
244: .getObject("DefaultAttributeEvaluator");
245: if (evaluator == null) {
246: evaluator = new XDefaultAttributeEvaluator(
247: currentProject);
248: evaluator.setCurrentProject(currentProject);
249: currentProject.setObject("DefaultAttributeEvaluator",
250: evaluator);
251: }
252: }
253: return evaluator.evaluateAttribute(this , attribValue);
254: }
255:
256: public String getContent(String key) {
257: Object c = contents.get(key);
258: if (c == null)
259: return "";
260:
261: return c.toString();
262: }
263:
264: public void putContent(String key, String value) {
265: contents.put(key, value);
266: }
267:
268: public HashMap getContents(XTemplateProcessor tp) {
269: if (tp != null)
270: return contents;
271:
272: return null;
273: }
274:
275: public HashMap getIncludes(XTemplateProcessor tp) {
276: if (tp != null)
277: return includes;
278:
279: return null;
280: }
281:
282: /**
283: * Checks for * and ? in the wildcard variable and replaces them correct
284: * pattern characters.
285: *
286: * @param wild - Wildcard name containing * and ?
287: * @return - String containing modified wildcard name
288: */
289: private String replaceWildcards(String wild) {
290: StringBuffer buffer = new StringBuffer();
291:
292: char[] chars = wild.toCharArray();
293:
294: for (int i = 0; i < chars.length; ++i) {
295: if (chars[i] == '*')
296: buffer.append(".*");
297: else if (chars[i] == '?')
298: buffer.append(".");
299: else if ("+()^$.{}[]|\\".indexOf(chars[i]) != -1)
300: buffer.append('\\').append(chars[i]);
301: else
302: buffer.append(chars[i]);
303: }
304:
305: return buffer.toString();
306: }
307: }
|