//Copyright (c)2005 Holobloc Inc.
//Contributed to the OOONEIDA FBench project under the Common Public License.
package fbench.dom;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.ArrayList;
import javax.swing.JEditorPane;
import javax.swing.text.BadLocationException;
import javax.swing.text.html.HTMLDocument;
import javax.swing.text.html.HTMLEditorKit;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import fbench.FBench;
//import fbench.XMLCodeGenerator;
import fbench.dom.events.ElementSelectionEvent;
import fbench.translate.ParseContext;
import fbench.translate.ParseError;
import fbench.translate.ParseResult;
import fbench.translate.ParseTarget;
import fbench.translate.Translator;
import fbench.translate.TranslatorSource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.w3c.dom.events.Event;
import org.w3c.dom.events.EventListener;
import org.w3c.dom.events.MutationEvent;
/**
* A model for displaying a selected DOM Element in a JEditorPane using an XSLT
* stylesheet.
*
* @author JHC
* @version 20051111/JHC - Changed ItemListener, TableListener to EventListener;
* extended from ElementModel.
* @version 20050927/JHC
*/
public class DOMTranslationModel extends ElementModel implements EventListener {
protected JEditorPane editorPane;
protected Transformer transformer;
protected Document document;
protected DOMSource src = new DOMSource();
protected String targetLanguage;
StreamResult dst = new StreamResult();
public DOMTranslationModel(Document doc, JEditorPane textArea,
String stylesheetName, String targetLanguage) {
super();
this.document = doc;
this.editorPane = textArea;
this.targetLanguage = targetLanguage;
((org.w3c.dom.events.EventTarget) doc).addEventListener("ElementSelectionEvent", this,
false);
TransformerFactory tf = TransformerFactory.newInstance();
try {
transformer = tf.newTransformer(new StreamSource(getClass()
.getResourceAsStream(stylesheetName)));
} catch (TransformerConfigurationException e) {
messageNoTransformer();
}
}
public void setElement(Element el) {
super.setElement(el);
((org.w3c.dom.events.EventTarget) el).addEventListener("MutationEvent", this, false);
if (transformer == null) {
messageNoTransformer();
return;
}
// Clone the dom so the original xml remains intact
el = (Element)el.cloneNode(true);
translate(el.getChildNodes());
cleanAttributeStrings(el.getChildNodes());
src.setNode(el);
StringWriter writer = new StringWriter();
dst.setWriter(writer);
try {
transformer.transform(src, dst);
if(editorPane != null){
editorPane.setText(writer.toString());
}
} catch (TransformerException e) {
if(editorPane != null)
editorPane.setText("XSLT TransformerException occurred.");
}
if(editorPane != null)
editorPane.requestFocus();
}
public String performTranslation(){
// Clone the dom so the original xml remains intact
Element el = document.getDocumentElement();
el = (Element)el.cloneNode(true);
translate(el.getChildNodes());
cleanAttributeStrings(el.getChildNodes());
src.setNode(el);
StringWriter writer = new StringWriter();
dst.setWriter(writer);
try {
transformer.transform(src, dst);
return writer.toString();
} catch (TransformerException e) {
e.printStackTrace();
}
return null;
}
/**
* Removes extra '"' characters at the beginning and end of attribute strings,
* as these create errors in the source code.
* @param nodes
*/
private void cleanAttributeStrings(NodeList nodes) {
// for(int i = 0; i < nodes.getLength(); i++){
// Element node = (Element)nodes.item(i);
// cleanAttributeStrings(node);
// cleanAttributeStrings(node.getChildNodes());
// }
}
private void cleanAttributeStrings(Element node) {
org.w3c.dom.NamedNodeMap map = node.getAttributes();
for(int i = 0; i < map.getLength(); i++){
org.w3c.dom.Attr attr = (org.w3c.dom.Attr)map.item(i);
String value = attr.getValue();
if(value.startsWith("\"") && value.endsWith("\"")){
value = value.substring(1, value.length() - 1);
attr.setValue(value);
}
}
}
protected void messageNoTransformer() {
if(editorPane != null)
editorPane.setText("No XSLT Transformer available.");
}
public void handleEvent(Event evt) {
if (evt instanceof MutationEvent)
setElement(getElement());
else if (evt instanceof ElementSelectionEvent)
setElement(((ElementSelectionEvent) evt).getSelectedElement());
}
private void translate(NodeList nodes){
for(int i = 0; i < nodes.getLength(); i++){
Element node = (Element)nodes.item(i);
if(node.getNodeName().toLowerCase().equals("algorithm")){
translateAlgorithms(node);
}
else if(node.getNodeName().toLowerCase().equals("ectransition")){
translateGuardConditions(node);
}
translate(node.getChildNodes());
}
}
private void translateGuardConditions(Element elem) {
if(elem.getNodeName().toLowerCase().equals("ectransition")){
String stString = elem.getAttribute("Condition");
String guard = "";
if(stString.length() == 0 || stString.equals("1")){
elem.setAttribute("Condition", "true");
return;
}
int index = stString.indexOf('&');
if(index == -1)
return;
guard = stString.substring(0, index);
stString = stString.substring(index + 1);
/*if(stString.startsWith("(") && stString.endsWith(")")){
stString = stString.substring(1, stString.length() - 1);
}*/
stString = FBench.removeHTML(stString);
ParseResult result = null;
Translator translator = TranslatorSource.getInstance().getTranslator("ST", targetLanguage);
if(translator != null){
ParseContext context = new ParseContext(new StringReader(stString), ParseTarget.guardCondition, document);
result = translator.parse(context);
}
else{
return;
}
if(result != null && !result.hasErrors()){
String newCondition = guard + "&(" + result.getSource() + ")";
elem.setAttribute("Condition", newCondition);
}
else{
String newCondition = guard + "&(" + stString + ")";
System.err.println(result.getErrors().get(0) + " in " + elem.getNodeName() + ": " + newCondition);
}
}
}
private void translateAlgorithms(Element elem){
if(elem.getNodeName().toLowerCase().equals("algorithm")){
Element codeNode = (Element)elem.getChildNodes().item(0);
if(codeNode.getAttribute("Text").length() > 0){
ParseResult result = null;
String sourceLanguage;
String nodeName = codeNode.getNodeName();
if(nodeName.equalsIgnoreCase("Other")){
sourceLanguage = codeNode.getAttribute("Language");
}
else{
sourceLanguage = nodeName;
}
String code = codeNode.getAttribute("Text");
code = FBench.removeHTML(code);
Translator translator = TranslatorSource.getInstance().getTranslator(sourceLanguage, targetLanguage);
if(translator != null){
ParseContext context = new ParseContext(new StringReader(code), ParseTarget.algorithm, document);
result = translator.parse(context);
}
else{
System.out.println("No translator: " +
sourceLanguage + " to " + targetLanguage + " (" + elem.getAttribute("Name") + ")");
return;
}
if(result != null && !result.hasErrors()){
elem.removeChild(codeNode);
if(targetLanguage.equalsIgnoreCase("ST")){
codeNode = document.createElement("ST");
}
else if(targetLanguage.equalsIgnoreCase("LD")){
codeNode = document.createElement("LD");
}
else if(targetLanguage.equalsIgnoreCase("FBD")){
codeNode = document.createElement("FBD");
}
else{
codeNode = document.createElement("Other");
codeNode.setAttribute("Language", targetLanguage);
}
String source = result.getSource();
source = XmlWriter.replaceChars(source);
codeNode.setAttribute("Text", source);
elem.appendChild(codeNode);
}
else if(result != null){
System.out.println("\nAlgorithm: " + elem.getAttribute("Name") +
" (" + codeNode.getNodeName() + ") parse failure.");
ArrayList<ParseError> errors = result.getErrors();
for(int i = 0; i < errors.size(); i++){
System.err.println(errors.get(i).toString());
}
}
else{
System.out.println("\nAlgorithm: " + elem.getAttribute("Name") +
" (" + codeNode.getNodeName() + ") Language could not be translated to Java.");
}
}
}
}
}