1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.geekologue.md4j.generators;
18
19 import java.io.BufferedInputStream;
20 import java.io.BufferedOutputStream;
21 import java.io.File;
22 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.InputStream;
26 import java.io.OutputStream;
27 import java.util.HashMap;
28 import java.util.Iterator;
29 import java.util.Map;
30 import javax.xml.parsers.ParserConfigurationException;
31 import javax.xml.parsers.SAXParserFactory;
32 import javax.xml.transform.Source;
33 import javax.xml.transform.Transformer;
34 import javax.xml.transform.TransformerException;
35 import javax.xml.transform.TransformerFactory;
36 import javax.xml.transform.sax.SAXSource;
37 import javax.xml.transform.stream.StreamResult;
38 import org.apache.tools.ant.BuildException;
39 import org.apache.tools.ant.Project;
40 import org.apache.tools.ant.util.FileNameMapper;
41 import org.apache.tools.ant.util.JAXPUtils;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44 import org.xml.sax.XMLReader;
45 import com.geekologue.md4j.tools.ant.HibernateMappingProcessorLiason;
46 import com.geekologue.md4j.tools.ant.HibernateMappingProcessorTask;
47
48 public abstract class AbstractXsltBasedGenerator implements
49 HibernateMappingProcessorLiason {
50 HibernateMappingProcessorTask task;
51
52 private Transformer transformer;
53
54 private ResourceResolver internalResolver;
55
56 protected File destDir = null;
57
58 private FileNameMapper runtimeMapper;
59
60 protected Map styleParameters = new HashMap();
61
62 private String xsl;
63
64 private AbstractXsltBasedGenerator() {
65 super();
66 }
67
68 /***
69 * @param stylesheet
70 * the XSLT file path
71 */
72 protected AbstractXsltBasedGenerator(String stylesheet) {
73 this();
74 this.xsl = stylesheet;
75 }
76
77 /***
78 * Implementations must return a simple structure mapper
79 *
80 * @return the simple mapper
81 */
82 public abstract FileNameMapper getSimpleMapper();
83
84 /***
85 * Implementations must return a nested structure mapper
86 *
87 * @return the nested mapper
88 */
89 public abstract FileNameMapper getNestedMapper();
90
91 /***
92 * @see com.geekologue.md4j.tools.ant.generators.HibernateMappingProcessorLiason#init(com.geekologue.md4j.tools.ant.HibernateMappingProcessorTask)
93 */
94 public void init(Map context) {
95 this.task = (HibernateMappingProcessorTask) context.get("task");
96
97
98 if (this.destDir == null) {
99 this.destDir = task.getDestDir();
100 }
101 try {
102 if (this.task.getMapper().equalsIgnoreCase("simple")) {
103 this.runtimeMapper = this.getSimpleMapper();
104 } else {
105 this.runtimeMapper = this.getNestedMapper();
106 }
107
108 this.internalResolver = new ResourceResolver(this.task);
109
110 TransformerFactory xformFactory = TransformerFactory.newInstance();
111 xformFactory.setURIResolver(this.internalResolver);
112 Source xslSource = this.internalResolver.resolve(this.xsl,
113 HibernateMappingProcessorTask.MD4J_BASE_URI);
114 this.transformer = xformFactory.newTransformer(xslSource);
115
116 this.transformer.setURIResolver(this.internalResolver);
117
118 for (Iterator iter = this.styleParameters.keySet().iterator(); iter
119 .hasNext();) {
120 String paramName = (String) iter.next();
121 this.transformer.setParameter(paramName, this.styleParameters
122 .get(paramName));
123 }
124
125 this.styleParameters.put("package", context.get("package"));
126 } catch (TransformerException e1) {
127 this.task.logOrThrowError("Looks like tranformer trouble: ", e1);
128 }
129 }
130
131 /***
132 * @see com.geekologue.md4j.tools.ant.generators.HibernateMappingProcessorLiason#process(java.io.File,
133 * java.lang.String, java.io.File)
134 */
135 public void process(File contextDir, String xmlFile) throws BuildException {
136 File outFile = null;
137 File inFile = null;
138 try {
139 inFile = new File(contextDir, xmlFile);
140
141 if (inFile.isDirectory()) {
142 this.task.log("Skipping " + inFile + " it is a directory.",
143 Project.MSG_VERBOSE);
144 return;
145 }
146 String[] outFileName = this.runtimeMapper.mapFileName(xmlFile);
147
148 if (outFileName == null || outFileName.length == 0) {
149 this.task.log("Skipping " + inFile
150 + " it cannot get mapped to output.",
151 Project.MSG_VERBOSE);
152 return;
153 } else if (outFileName == null || outFileName.length > 1) {
154 this.task.log("Skipping " + inFile
155 + " its mapping is ambiguous.", Project.MSG_VERBOSE);
156 return;
157 }
158 outFile = new File(this.destDir, outFileName[0]);
159 if (this.task.isForce()
160 || inFile.lastModified() >= outFile.lastModified()) {
161 ensureDirectoryFor(outFile);
162 this.task.log("Processing " + inFile + " to " + outFile,
163 Project.MSG_VERBOSE);
164 process(inFile, outFile);
165 } else {
166 this.task.log("Skipping input file " + inFile
167 + " because it is older than output file " + outFile,
168 Project.MSG_VERBOSE);
169 }
170 } catch (Exception ex) {
171 ex.printStackTrace();
172 this.task.log("Failed to process " + inFile, Project.MSG_ERR);
173 if (outFile != null) {
174 outFile.delete();
175 }
176 throw new BuildException(ex);
177 }
178 }
179
180 /***
181 *
182 * @param infile
183 * @param outfile
184 * @throws Exception
185 */
186 private void process(File infile, File outfile) throws Exception {
187 InputStream fis = null;
188 OutputStream fos = null;
189 try {
190 fis = new BufferedInputStream(new FileInputStream(infile));
191 fos = new BufferedOutputStream(new FileOutputStream(outfile));
192 StreamResult res = new StreamResult(fos);
193 res.setSystemId(JAXPUtils.getSystemId(outfile));
194 Source src = getSource(fis, JAXPUtils.getSystemId(infile));
195 this.transformer.transform(src, res);
196 } finally {
197
198 try {
199 if (fis != null) {
200 fis.close();
201 }
202 } catch (IOException ignored) {
203
204 }
205 try {
206 if (fos != null) {
207 fos.close();
208 }
209 } catch (IOException ignored) {
210
211 }
212 }
213 }
214
215 /***
216 * Get the source instance from the stream and id of the file.
217 *
218 * @param is
219 * the input file stream
220 * @param systemId
221 * the systemid
222 * @return a properly configured source
223 */
224 private Source getSource(InputStream is, String systemId)
225 throws ParserConfigurationException, SAXException {
226 SAXParserFactory spFactory = SAXParserFactory.newInstance();
227 spFactory.setNamespaceAware(true);
228 XMLReader reader = spFactory.newSAXParser().getXMLReader();
229 reader.setEntityResolver(this.task.getXmlCatalog());
230 Source src = new SAXSource(reader, new InputSource(is));
231 src.setSystemId(systemId);
232 return src;
233 }
234
235 /***
236 * Ensure the directory exists for the given file
237 *
238 * @param targetFile
239 * the file for which the directories are required.
240 * @exception BuildException
241 * if the directories cannot be created.
242 */
243 private void ensureDirectoryFor(File targetFile) throws BuildException {
244 File directory = targetFile.getParentFile();
245 if (!directory.exists()) {
246 if (!directory.mkdirs()) {
247 this.task.logOrThrowError("Unable to create directory: "
248 + directory.getAbsolutePath());
249 }
250 }
251 }
252 }