Project

General

Profile

« Previous | Next » 

Revision 46151

Branch for migration to Saxon HE

View differences:

TransformationImpl.java
1
package eu.dnetlib.data.collective.transformation.engine.core;
2

  
3
import java.io.Reader;
4
import java.io.StringReader;
5
import java.io.StringWriter;
6
import java.util.*;
7
import javax.xml.transform.*;
8
import javax.xml.transform.stream.StreamResult;
9
import javax.xml.transform.stream.StreamSource;
10

  
11
import eu.dnetlib.data.collective.transformation.TransformationException;
12
import eu.dnetlib.data.collective.transformation.core.schema.SchemaInspector;
13
import eu.dnetlib.data.collective.transformation.rulelanguage.RuleLanguageParser;
14
import eu.dnetlib.data.collective.transformation.rulelanguage.Rules;
15
import eu.dnetlib.data.collective.transformation.utils.NamespaceContextImpl;
16
import net.sf.saxon.expr.instruct.TerminationException;
17
import net.sf.saxon.lib.FeatureKeys;
18
import org.apache.commons.logging.Log;
19
import org.apache.commons.logging.LogFactory;
20
import org.dom4j.*;
21
import org.dom4j.io.SAXReader;
22
import org.springframework.core.io.Resource;
23

  
24
// import net.sf.saxon.event.MessageWarner;
25

  
26
/**
27
 * @author jochen
28
 */
29
public class TransformationImpl implements ITransformation {
30

  
31
	private static final String rootElement = "record";
32
	private final Log log = LogFactory.getLog(TransformationImpl.class);
33
	protected RuleLanguageParser ruleLanguageParser;
34
	private Document xslDoc;
35
	private SAXReader reader = new SAXReader();
36
	private Transformer transformer;
37
	private Transformer transformerFailed;
38
	private StylesheetBuilder stylesheetBuilder;
39
	// cache static transformation results, valid for one transformation job
40
	private Map<String, String> staticResults = new LinkedHashMap<String, String>();
41
	private Map<String, String> jobConstantMap = new HashMap<String, String>();
42
	//	private MessageWarner mw = new MessageWarner();
43

  
44
	//@javax.annotation.Resource(name = "template")
45
	private Resource template;
46

  
47
	private Resource schema;
48

  
49
	private Source xsltSyntaxcheckFailed;
50
	//@Autowired
51
	private TransformerFactory saxonTransformerFactory;
52

  
53
	public TransformationImpl(TransformerFactory saxonTransformerFactory){
54
		this.saxonTransformerFactory = saxonTransformerFactory;
55
	}
56

  
57
	/**
58
	 * initializes the transformation with the underlying XSL-template
59
	 */
60
	public void init() {
61
		try {
62
			xslDoc = reader.read(template.getInputStream());
63
			Resource xslResource = template.createRelative(XSLSyntaxcheckfailed);
64
			String systemId = xslResource.getURL().toExternalForm();
65
			xsltSyntaxcheckFailed = new StreamSource(xslResource.getInputStream(), systemId);
66

  
67
		} catch (Throwable e) {
68
			log.error("cannot initialize this transformation.", e);
69
			throw new IllegalStateException(e);
70
		}
71

  
72
	}
73

  
74
	public void addJobConstant(String aKey, String aValue) {
75
		this.jobConstantMap.put(aKey, aValue);
76
	}
77

  
78
	/**
79
	 * creates a new Transformer object using a stylesheet based on the transformation rules
80
	 */
81
	public void configureTransformation() throws TransformerConfigurationException {
82
		saxonTransformerFactory.setAttribute(FeatureKeys.ALLOW_EXTERNAL_FUNCTIONS, Boolean.TRUE);
83

  
84
		Templates templates = null;
85
		if (this.ruleLanguageParser.isXslStylesheet()) {
86
			templates = saxonTransformerFactory.newTemplates(new StreamSource(new StringReader(ruleLanguageParser.getXslStylesheet())));
87
		} else {
88
			templates = saxonTransformerFactory.newTemplates(new StreamSource(createStylesheet()));
89
		}
90

  
91
		transformer = templates.newTransformer();
92
		//((net.sf.saxon.Controller)transformer).setMessageEmitter(mw);
93
		transformer.setOutputProperty(OutputKeys.INDENT, "yes");
94
		transformer.setOutputProperty(OutputKeys.METHOD, "xml");
95
		transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
96

  
97
		Templates templateFailed = saxonTransformerFactory.newTemplates(xsltSyntaxcheckFailed);
98
		transformerFailed = templateFailed.newTransformer();
99
		//((net.sf.saxon.Controller)transformerFailed).setMessageEmitter(mw);
100
	}
101

  
102
	/* (non-Javadoc)
103
	 * @see eu.dnetlib.data.collective.transformation.engine.core.ITransformation#transformRecord(java.lang.String, int)
104
	 */
105
	public String transformRecord(String record, int index) throws TerminationException, TransformationException {
106
		try {
107
			StreamSource s = new StreamSource(new StringReader(record));
108
			StringWriter writer = new StringWriter();
109
			StreamResult r = new StreamResult(writer);
110
			transformer.setParameter("index", index);
111
			transformer.transform(s, r);
112
			return writer.toString();
113
		} catch (TerminationException e) {
114
			log.debug(e.getLocalizedMessage());
115
			throw e;
116
		} catch (TransformerException e) {
117
			log.error(e);
118
			throw new TransformationException(e);
119
		}
120
	}
121

  
122
	public String transformRecord(String record, Map<String, String> parameters) throws TerminationException, TransformationException {
123
		try {
124
			StreamSource s = new StreamSource(new StringReader(record));
125
			StringWriter writer = new StringWriter();
126
			StreamResult r = new StreamResult(writer);
127
			for (String key : parameters.keySet()) {
128
				transformer.setParameter(key, parameters.get(key));
129
			}
130
			transformer.transform(s, r);
131
			return writer.toString();
132
		} catch (TerminationException e) {
133
			log.debug(e.getLocalizedMessage());
134
			throw e;
135
		} catch (TransformerException e) {
136
			log.error(e);
137
			throw new TransformationException(e);
138
		}
139
	}
140

  
141
	public String transformRecord(String record, String stylesheetName) throws TransformationException {
142
		if (!stylesheetName.equals(XSLSyntaxcheckfailed))
143
			throw new IllegalArgumentException("in TransformationImpl: stylesheetname " + stylesheetName + " is unsupported!");
144
		try {
145
			StreamSource s = new StreamSource(new StringReader(record));
146
			StringWriter w = new StringWriter();
147
			StreamResult r = new StreamResult(w);
148
			transformerFailed.transform(s, r);
149
			return w.toString();
150
		} catch (TransformerException e) {
151
			log.error(e);
152
			throw new TransformationException(e);
153
		}
154
	}
155

  
156
	public String dumpStylesheet() {
157
		return xslDoc.asXML();
158

  
159
		//		StringWriter writer = new StringWriter();
160
		//		try {
161
		//			Transformer tXsl = transformer; //.newTransformer();
162
		//			tXsl.setOutputProperty(OutputKeys.INDENT, "yes");
163
		//			tXsl.setOutputProperty(OutputKeys.METHOD, "xml");
164
		//			tXsl.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
165
		//
166
		//		StreamResult r = new StreamResult(writer);
167
		//		Source s = new StreamSource(new StringReader(xslDoc.asXML()));
168
		//			tXsl.transform(s, r);
169
		//		} catch (TransformerException e) {
170
		//			// TODO Auto-generated catch block
171
		//			e.printStackTrace();
172
		//		}
173
		//		return writer.toString();
174
	}
175

  
176
	/**
177
	 * @return the resource to access the XSL template
178
	 */
179
	public Resource getTemplate() {
180
		return template;
181
	}
182

  
183
	/**
184
	 * sets the XSL template
185
	 *
186
	 * @param template - resource to access the XSL template
187
	 */
188
	public void setTemplate(Resource template) {
189
		this.template = template;
190
	}
191

  
192
	public RuleLanguageParser getRuleLanguageParser() {
193
		return ruleLanguageParser;
194
	}
195

  
196
	public void setRuleLanguageParser(RuleLanguageParser ruleLanguageParser) {
197
		this.ruleLanguageParser = ruleLanguageParser;
198
	}
199

  
200
	/**
201
	 * @return the stylesheetBuilder
202
	 */
203
	public StylesheetBuilder getStylesheetBuilder() {
204
		return stylesheetBuilder;
205
	}
206

  
207
	/**
208
	 * @param stylesheetBuilder the stylesheetBuilder to set
209
	 */
210
	public void setStylesheetBuilder(StylesheetBuilder stylesheetBuilder) {
211
		this.stylesheetBuilder = stylesheetBuilder;
212
	}
213

  
214
	/**
215
	 * @return the transformation rules as String object
216
	 */
217
	protected String getTransformationRules() {
218
		// add job-properties to the rules as variables
219
		for (String key : jobConstantMap.keySet()) {
220
			Rules r = new Rules();
221
			r.setVariable(key);
222
			r.setConstant("'" + jobConstantMap.get(key) + "'");
223
			ruleLanguageParser.getVariableMappingRules().put(JOBCONST_DATASINKID, r);
224
		}
225
		if (this.stylesheetBuilder == null) {
226
			// create DMF compliant stylesheet builder
227
			this.stylesheetBuilder = new StylesheetBuilder(saxonTransformerFactory);
228
			this.stylesheetBuilder.setRuleLanguageParser(this.ruleLanguageParser);
229
			NamespaceContextImpl namespaceContext = new NamespaceContextImpl();
230
			for (String prefix : ruleLanguageParser.getNamespaceDeclarations().keySet()) {
231
				namespaceContext.addNamespace(prefix, ruleLanguageParser.getNamespaceDeclarations().get(prefix));
232
			}
233
			SchemaInspector inspector = new SchemaInspector();
234
			try {
235
				inspector.inspect(this.schema.getURL(), rootElement);
236
			} catch (Exception e) {
237
				throw new IllegalStateException(e);
238
			}
239
			this.stylesheetBuilder.setNamespaceContext(namespaceContext);
240
			this.stylesheetBuilder.setSchemaInspector(inspector);
241
		}
242
		return this.stylesheetBuilder.createTemplate();
243
	}
244

  
245
	/**
246
	 * creates a stylesheet from transformation rules;
247
	 * <p>don't call this method multiple times, unless transformation configuration changes, then re-init and configure transformation</p>
248
	 *
249
	 * @return the stylesheet
250
	 */
251
	private Reader createStylesheet() {
252
		try {
253
			Document rulesDoc = DocumentHelper.parseText(getTransformationRules());
254
			for (String key : this.ruleLanguageParser.getNamespaceDeclarations().keySet()) {
255
				xslDoc.getRootElement().addNamespace(key, this.ruleLanguageParser.getNamespaceDeclarations().get(key));
256
			}
257
			@SuppressWarnings("unchecked")
258
			List<Node> nodes = rulesDoc.getRootElement().selectNodes("//xsl:template");
259

  
260
			@SuppressWarnings("unchecked")
261
			List<Node> varNodes = rulesDoc.getRootElement().selectNodes("/templateroot/xsl:param");
262
			for (Node node : varNodes) {
263
				xslDoc.getRootElement().add(((Element) node).detach());
264
			}
265

  
266
			//			xslDoc.getRootElement().add(rulesDoc.getRootElement().selectSingleNode("//xsl:param[@name='var1']").detach());
267
			for (Node node : nodes) {
268
				xslDoc.getRootElement().add(((Element) node).detach()); //  (rulesDoc.getRootElement().aget);
269
			}
270
		} catch (DocumentException e) {
271
			log.error("error in creating stylesheet: " + e);
272
			throw new IllegalStateException(e);
273
		}
274
		String xsl = xslDoc.asXML();
275
		log.debug(xsl);
276
		return new StringReader(xsl);
277
	}
278

  
279
	/**
280
	 * @return the schema
281
	 */
282
	public Resource getSchema() {
283
		return schema;
284
	}
285

  
286
	/**
287
	 * @param schema the schema to set
288
	 */
289
	public void setSchema(Resource schema) {
290
		this.schema = schema;
291
	}
292

  
293
	@Override
294
	public Map<String, String> getStaticTransformationResults() {
295
		return this.staticResults;
296
	}
297

  
298
	@Override
299
	public Map<String, String> getJobProperties() {
300
		// TODO Auto-generated method stub
301
		return this.jobConstantMap;
302
	}
303

  
304
	@Override
305
	public Properties getLogInformation() {
306
		// TODO Auto-generated method stub
307
		return null;
308
	}
309

  
310
}

Also available in: Unified diff