/* * Copyright 2010 Pablo Arrighi, Alex Concha, Miguel Lezama for version 1. * Copyright 2013 Pablo Arrighi, Miguel Lezama, Kevin Mazet for version 2. * * This file is part of GOOL. * * GOOL is free software: you can redistribute it and/or modify it under the terms of the GNU * General Public License as published by the Free Software Foundation, version 3. * * GOOL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without * even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License version 3 for more details. * * You should have received a copy of the GNU General Public License along with GOOL, * in the file COPYING.txt. If not, see <http://www.gnu.org/licenses/>. */ package gool.generator.xml; import java.io.File; import java.io.FileNotFoundException; import java.io.PrintWriter; import java.io.Writer; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.w3c.dom.*; import com.sun.org.apache.xml.internal.serialize.OutputFormat; import com.sun.org.apache.xml.internal.serialize.XMLSerializer; import javax.xml.parsers.*; import logger.Log; import gool.ast.core.ClassDef; import gool.generator.common.CodePrinter; import gool.generator.java.JavaGenerator; public class XmlCodePrinter extends CodePrinter { /** * list every risked methods for every node with recursion risk. */ private static final java.util.HashMap<String, String[]> methexclude = new java.util.HashMap<String, String[]>(); static { String[] letableau = { "getClassReference" }; methexclude.put("gool.ast.type.TypeClass", letableau); } /** * list ignored getter for attribute. */ private static final java.util.ArrayList<String> attrexclude = new java.util.ArrayList<String>(); static { attrexclude.add("getClass"); attrexclude.add("getAccessModifier"); attrexclude.add("getHeader"); attrexclude.add("getBlock"); } /** * node counter for debugging */ int nbNode = 0; /** * Authorize only one ClassDef */ private boolean classdefok = true; public XmlCodePrinter(File outputDir, Collection<File> myF) { // Chose you're favorite Generator for recognized. super(new JavaGenerator(), outputDir, myF); } private Set<ClassDef> printedClasses = new HashSet<ClassDef>(); @Override public List<File> print(ClassDef pclass) throws FileNotFoundException { Document document = null; DocumentBuilderFactory fabrique = null; List<File> result = new ArrayList<File>(); // Debugging info // nbNode = 0; try { // creat document structure fabrique = DocumentBuilderFactory.newInstance(); DocumentBuilder builder = fabrique.newDocumentBuilder(); document = builder.newDocument(); Element racine = (Element) document.createElement("file"); Element el = NodeToElement(pclass, document); if (el != null) racine.appendChild(el); document.appendChild(racine); // file separator is just a slash in Unix // so the second argument to File() is just the directory // that corresponds to the package name // the first argument is the default output directory of the // platform // so the directory name ends up being something like // GOOLOUPTUTTARGET/pack/age File dir = new File(getOutputDir().getAbsolutePath(), StringUtils.replace(pclass.getPackageName(), ".", File.separator)); // Typically the outputdir was created before, but not the package // subdirs dir.mkdirs(); // Create the file for the class, fill it in, close it File classFile = new File(dir, getFileName(pclass.getName())); Log.i(String.format("Writing to file %s", classFile)); // Create formating output OutputFormat format = new OutputFormat(document); format.setEncoding("UTF-8"); format.setLineWidth(80); format.setIndenting(true); format.setIndent(4); // save to output file Writer out = new PrintWriter(classFile); XMLSerializer serializer = new XMLSerializer(out, format); serializer.serialize(document); // Remember that you did the generation for this one abstract GOOL // class printedClasses.add(pclass); result.add(classFile); classdefok = true; } catch (Exception e) { Log.e(e); System.exit(1); } return result; } /** * Translate GOOL node to XML Element. * * @param node * GOOL node * @param document * XML Document * @return XML Element */ private Element NodeToElement(Object node, Document document) { // element create for return Element newElement = null; // check if the parameter does not cause trouble if (node == null || node.getClass().getName() .equals("gool.generator.xml.XmlPlatform")) return null; if (node.getClass().isAssignableFrom(gool.ast.core.Node.class)) { return null; } if (node.getClass().getName().equals("gool.ast.core.ClassDef")) { if (classdefok) classdefok = false; else return null; } // Create the new Element newElement = document.createElement(node.getClass().getName() .substring(9)); // find every method to find every child node Method[] meths = node.getClass().getMethods(); for (Method meth : meths) { Class<?> laCl = meth.getReturnType(); // check if the method return type is a node. if (gool.ast.core.Node.class.isAssignableFrom(laCl) && (meth.getParameterTypes().length == 0) /* && nbNode<1000 */) { // Debug for recursion // nbNode++; // Log.d(laCl.getName() + "\n" + nbNode); try { gool.ast.core.Node newNode = (gool.ast.core.Node) meth .invoke(node); // detect recursion risk. boolean recursionRisk = (newNode == node) ? true : false; if (methexclude.containsKey(node.getClass().getName())) { for (String exmeth : methexclude.get(node.getClass() .getName())) { if (newNode == null || meth.getName().equals(exmeth)) recursionRisk = true; } } if (recursionRisk) { Element newElement2 = document.createElement(node .getClass().getName().substring(9)); newElement2.setTextContent("recursion risk detected!"); newElement.appendChild(newElement2); } else { Element el = NodeToElement(newNode, document); if (el != null) { el.setAttribute("getterName", meth.getName()); newElement.appendChild(el); } } } catch (Exception e) { Log.e(e); System.exit(1); } } // if the method return node list. else if (java.util.List.class.isAssignableFrom(laCl)) { try { java.util.List<Object> listObj = (java.util.List<Object>) meth .invoke(node); for (Object o : listObj) { Element el = NodeToElement(o, document); if (el != null) { el.setAttribute("getterName", meth.getName()); newElement.appendChild(el); } } } catch (Exception e) { Log.e(e); System.exit(1); } } // generate XML attribute for getter else if (meth.getName().startsWith("get") && !meth.getName().equals("getCode") && (meth.getParameterTypes().length == 0)) { try { if (!attrexclude.contains(meth.getName())) newElement.setAttribute(meth.getName().substring(3), meth.invoke(node) == null ? "null" : meth .invoke(node).toString()); } catch (Exception e) { Log.e(e); System.exit(1); } } // generate XML attribute for iser else if (meth.getName().startsWith("is") && (meth.getParameterTypes().length == 0)) { try { if (!attrexclude.contains(meth.getName())) newElement.setAttribute(meth.getName().substring(2), meth.invoke(node) == null ? "null" : meth .invoke(node).toString()); } catch (Exception e) { Log.e(e); System.exit(1); } } } return newElement; } @Override public Collection<File> print(Collection<ClassDef> generatedClassDefs, boolean isGool) throws FileNotFoundException { return super.print(generatedClassDefs, isGool); } @Override public String getFileName(String className) { return className + ".xml"; } @Override public String getTemplateDir() { return ""; } }