/* * (c) Copyright 2010-2011 AgileBirds * * This file is part of OpenFlexo. * * OpenFlexo 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, either version 3 of the License, or * (at your option) any later version. * * OpenFlexo 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 for more details. * * You should have received a copy of the GNU General Public License * along with OpenFlexo. If not, see <http://www.gnu.org/licenses/>. * */ package org.openflexo.antar.java; import java.util.StringTokenizer; import java.util.Vector; import java.util.logging.Level; import java.util.logging.Logger; import org.openflexo.antar.Assignment; import org.openflexo.antar.Class; import org.openflexo.antar.Conditional; import org.openflexo.antar.ControlGraph; import org.openflexo.antar.Declaration; import org.openflexo.antar.Flow; import org.openflexo.antar.Instruction; import org.openflexo.antar.Loop; import org.openflexo.antar.Nop; import org.openflexo.antar.Procedure; import org.openflexo.antar.Procedure.ProcedureParameter; import org.openflexo.antar.ProcedureCall; import org.openflexo.antar.Sequence; import org.openflexo.antar.expr.Expression; import org.openflexo.antar.pp.PrettyPrinter; import org.openflexo.logging.FlexoLogger; import org.openflexo.toolbox.StringUtils; import org.openflexo.toolbox.ToolBox; import de.hunsicker.jalopy.Jalopy; public class JavaPrettyPrinter extends PrettyPrinter { private static final Logger logger = FlexoLogger.getLogger(JavaPrettyPrinter.class.getPackage().getName()); private static final String MULTIPLE_NEW_LINE_ALONE_REG_EXP = "([\\s&&[^\n\r]]*[\n\r]{2,})"; public JavaPrettyPrinter() { super(new JavaExpressionPrettyPrinter()); } protected String makeJavadocComment(String javadocComment) { return "/** " + StringUtils.LINE_SEPARATOR + " * " + ToolBox.getJavaDocString(javadocComment, " ") + " */" + StringUtils.LINE_SEPARATOR; } protected String makeInlineComment(String inlineComment) { return "/* " + inlineComment + " */"; } protected String makeHeaderComment(String headerComment) { StringBuffer returned = new StringBuffer(); StringTokenizer st = new StringTokenizer(headerComment, StringUtils.LINE_SEPARATOR); while (st.hasMoreTokens()) { String next = st.nextToken(); if (!next.trim().equals("")) { returned.append("// " + next + StringUtils.LINE_SEPARATOR); } } return returned.toString(); } @Override public String makeStringRepresentation(Conditional conditional) { String headerComment = conditional.getHeaderComment() != null ? makeHeaderComment(conditional.getHeaderComment()) : ""; String inlineComment = conditional.getInlineComment() != null ? makeInlineComment(conditional.getInlineComment()) : ""; StringBuffer sb = new StringBuffer(); sb.append(headerComment); sb.append("if "); sb.append(getStringRepresentation(conditional.getCondition())); sb.append(inlineComment); sb.append(" {" + StringUtils.LINE_SEPARATOR); sb.append(getStringRepresentation(conditional.getThenStatement())); sb.append(StringUtils.LINE_SEPARATOR + "}"); if (conditional.getElseStatement() != null) { if (conditional.getElseStatement() instanceof Conditional) { // This special case handles "else if" patterns ControlGraph elseStatement = conditional.getElseStatement(); while (elseStatement instanceof Conditional) { Conditional currentConditional = (Conditional) elseStatement; String headerComment2 = currentConditional.getHeaderComment() != null ? StringUtils.LINE_SEPARATOR + makeHeaderComment(currentConditional.getHeaderComment()) : ""; String inlineComment2 = currentConditional.getInlineComment() != null ? makeInlineComment(currentConditional .getInlineComment()) : ""; sb.append(headerComment2); sb.append("else if "); sb.append(getStringRepresentation(currentConditional.getCondition())); sb.append(inlineComment2); sb.append(" {" + StringUtils.LINE_SEPARATOR); sb.append(getStringRepresentation(currentConditional.getThenStatement())); sb.append(StringUtils.LINE_SEPARATOR + "}"); elseStatement = currentConditional.getElseStatement(); } if (elseStatement != null) { sb.append(" else {" + StringUtils.LINE_SEPARATOR); sb.append(getStringRepresentation(elseStatement)); sb.append(StringUtils.LINE_SEPARATOR + "}"); } } else { sb.append(" else {" + StringUtils.LINE_SEPARATOR); sb.append(getStringRepresentation(conditional.getElseStatement())); sb.append(StringUtils.LINE_SEPARATOR + "}"); } } return sb.toString(); } @Override public String makeStringRepresentation(Instruction instruction) { String headerComment = instruction.getHeaderComment() != null ? makeHeaderComment(instruction.getHeaderComment()) : ""; String inlineComment = instruction.getInlineComment() != null ? makeInlineComment(instruction.getInlineComment()) : ""; if (instruction instanceof Nop) { return headerComment + (instruction.getInlineComment() == null ? "/* Nothing to do */" : inlineComment) + ";"; } if (instruction instanceof Assignment) { return headerComment + makeStringRepresentation((Assignment) instruction) + inlineComment; } if (instruction instanceof ProcedureCall) { return headerComment + makeStringRepresentation((ProcedureCall) instruction) + inlineComment; } if (instruction instanceof Declaration) { return headerComment + makeStringRepresentation((Declaration) instruction) + inlineComment; } if (instruction instanceof JavaPrettyPrintable) { return headerComment + ((JavaPrettyPrintable) instruction).getJavaStringRepresentation() + inlineComment; } return "???"; } public String makeStringRepresentation(Assignment assignment) { return assignment.getReceiver().getName() + " = " + getStringRepresentation(assignment.getAssignmentValue()) + ";"; } public String makeStringRepresentation(ProcedureCall procedureCall) { StringBuffer sb = new StringBuffer(); StringBuffer args = new StringBuffer(); if (procedureCall.getArguments().size() > 0) { boolean isFirst = true; for (Expression e : procedureCall.getArguments()) { args.append((isFirst ? "" : ",") + getStringRepresentation(e)); isFirst = false; } } sb.append(procedureCall.getProcedure().getProcedureName()); sb.append("(" + args.toString() + ");"); return sb.toString(); } public String makeStringRepresentation(Declaration declaration) { StringBuffer sb = new StringBuffer(); sb.append(declaration.getType().getTypeName() + " "); sb.append(declaration.getVariable().getName()); if (declaration.getInitializationValue() != null) { sb.append(" = " + getStringRepresentation(declaration.getInitializationValue())); } sb.append(";"); return sb.toString(); } @Override public String makeStringRepresentation(Procedure procedure) { StringBuffer sb = new StringBuffer(); if (procedure.getComment() != null && !procedure.getComment().trim().equals("")) { sb.append(makeJavadocComment(procedure.getComment())); } StringBuffer params = new StringBuffer(); if (procedure.getParameters().size() > 0) { boolean isFirst = true; for (ProcedureParameter p : procedure.getParameters()) { params.append((isFirst ? "" : ",") + p.getType().getTypeName() + " " + p.getVariable().getName()); isFirst = false; } } sb.append("public "); sb.append(procedure.getReturnType() == null ? "void" : procedure.getReturnType()); sb.append(" " + procedure.getProcedureName()); sb.append("(" + params.toString() + ")" + StringUtils.LINE_SEPARATOR + "{" + StringUtils.LINE_SEPARATOR); sb.append(getStringRepresentation(procedure.getControlGraph()) + StringUtils.LINE_SEPARATOR); sb.append("}"); return sb.toString(); } @Override public String makeStringRepresentation(Class aClass) { StringBuffer sb = new StringBuffer(); if (aClass.getGroupName() != null) { sb.append("package ").append(aClass.getGroupName()).append(";").append(StringUtils.LINE_SEPARATOR) .append(StringUtils.LINE_SEPARATOR); } sb.append("import be.denali.flexo.engine.*;").append(StringUtils.LINE_SEPARATOR).append(StringUtils.LINE_SEPARATOR); if (aClass.getComment() != null && !aClass.getComment().trim().equals("")) { sb.append(makeJavadocComment(aClass.getComment())); } sb.append("public class"); sb.append(" " + aClass.getClassName()); sb.append(" extends ProcessProcessor {" + StringUtils.LINE_SEPARATOR + StringUtils.LINE_SEPARATOR); sb.append("public "); sb.append(" " + aClass.getClassName()); sb.append("(IProcessInstance processInstance){").append(StringUtils.LINE_SEPARATOR); sb.append("super(processInstance);").append(StringUtils.LINE_SEPARATOR); sb.append("}").append(StringUtils.LINE_SEPARATOR).append(StringUtils.LINE_SEPARATOR); String processInstanceClassName = aClass.getClassName().substring(0, aClass.getClassName().length() - "Processor".length()); sb.append("@Override" + StringUtils.LINE_SEPARATOR); sb.append("public " + processInstanceClassName); sb.append(" getProcessInstance(){"); sb.append("return (" + processInstanceClassName + ")processInstance;").append(StringUtils.LINE_SEPARATOR); sb.append("}").append(StringUtils.LINE_SEPARATOR).append(StringUtils.LINE_SEPARATOR); if (aClass.getProcedures().size() > 0) { for (Procedure p : aClass.getProcedures()) { sb.append(getStringRepresentation(p)); sb.append(StringUtils.LINE_SEPARATOR); } } sb.append("}"); sb.append(StringUtils.LINE_SEPARATOR); return sb.toString(); } @Override public String makeStringRepresentation(Loop loop) { // TODO Auto-generated method stub return null; } @Override public String makeStringRepresentation(Sequence sequence) { StringBuffer sb = new StringBuffer(); String headerComment = sequence.getHeaderComment() != null ? makeHeaderComment(sequence.getHeaderComment()) : ""; sb.append(headerComment); for (ControlGraph statement : sequence.getStatements()) { sb.append(getStringRepresentation(statement) + (statement != sequence.getStatements().lastElement() ? StringUtils.LINE_SEPARATOR : "")); } return sb.toString(); } @Override public String makeStringRepresentation(Flow sequence) { StringBuffer sb = new StringBuffer(); String headerComment = sequence.getHeaderComment() != null ? makeHeaderComment(sequence.getHeaderComment()) : ""; sb.append(headerComment); for (ControlGraph statement : sequence.getStatements()) { sb.append("getExecutorService().submit(new Runnable(){" + StringUtils.LINE_SEPARATOR); sb.append("public void run(){" + StringUtils.LINE_SEPARATOR); sb.append(getStringRepresentation(statement)); sb.append("}" + StringUtils.LINE_SEPARATOR); sb.append("});" + StringUtils.LINE_SEPARATOR); sb.append(statement != sequence.getStatements().lastElement() ? StringUtils.LINE_SEPARATOR : ""); } return sb.toString(); } private static class JalopyFactory { private static Jalopy jalopy; public static Jalopy getJalopy() { if (jalopy == null) { jalopy = new Jalopy(); } jalopy.reset(); return jalopy; } } public static String formatJavaCodeAsClassCode(String someCode) throws JavaFormattingException { if (someCode == null) { return null; } if (someCode.trim().equals("")) { return ""; } String javaCode = someCode; javaCode = javaCode.replace("\r", ""); javaCode = javaCode.replaceAll(MULTIPLE_NEW_LINE_ALONE_REG_EXP, StringUtils.LINE_SEPARATOR + StringUtils.LINE_SEPARATOR); Jalopy jalopy = JalopyFactory.getJalopy(); try { StringBuffer sb = new StringBuffer(); jalopy.setInspect(false); jalopy.setForce(true); jalopy.setInput(javaCode, "Format.java"); jalopy.setOutput(sb); if (jalopy.format()) { String formatted = sb.toString(); return removeExtraIndentation(formatted); } } catch (Exception e) { e.printStackTrace(); if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception occured while parsing the java code"); } } if (jalopy.getState() == Jalopy.State.ERROR) { logger.warning("Java code could not be formatted"); throw new JavaFormattingException(); } if (logger.isLoggable(Level.WARNING)) { logger.warning("Java code could not be formatted: " + jalopy.getState()); } return someCode; } public static String formatJavaCodeAsMethodCode(String someCode) throws JavaFormattingException { if (someCode == null) { return null; } if (someCode.trim().equals("")) { return ""; } String javaCode = "public class Format {" + StringUtils.LINE_SEPARATOR + someCode + StringUtils.LINE_SEPARATOR + "}"; javaCode = javaCode.replace("\r", ""); javaCode = javaCode.replaceAll(MULTIPLE_NEW_LINE_ALONE_REG_EXP, StringUtils.LINE_SEPARATOR + StringUtils.LINE_SEPARATOR); Jalopy jalopy = JalopyFactory.getJalopy(); try { StringBuffer sb = new StringBuffer(); jalopy.setInspect(false); jalopy.setForce(true); jalopy.setInput(javaCode, "Format.java"); jalopy.setOutput(sb); if (jalopy.format()) { String formatted = sb.toString(); // System.out.println("Unformatted:["+someCode+"]"); return removeExtraIndentation(formatted.substring(21 + StringUtils.LINE_SEPARATOR.length(), formatted.length() - 1 - StringUtils.LINE_SEPARATOR.length())); // return formatted.substring(53,formatted.length()-4); } } catch (Exception e) { e.printStackTrace(); if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception occured while parsing the java code"); } } if (jalopy.getState() == Jalopy.State.ERROR) { logger.warning("Java code could not be formatted"); throw new JavaFormattingException(); } if (logger.isLoggable(Level.WARNING)) { logger.warning("Java code could not be formatted: " + jalopy.getState()); } return someCode; } public static String formatJavaCodeAsInlineCode(String someCode) throws JavaFormattingException { if (someCode == null) { return null; } if (someCode.trim().equals("")) { return ""; } String javaCode = "public class Format {" + StringUtils.LINE_SEPARATOR + "public void formatThis() {" + StringUtils.LINE_SEPARATOR + "" + someCode + "" + StringUtils.LINE_SEPARATOR + "}" + StringUtils.LINE_SEPARATOR + "}"; javaCode = javaCode.replace("\r", ""); javaCode = javaCode.replaceAll(MULTIPLE_NEW_LINE_ALONE_REG_EXP, StringUtils.LINE_SEPARATOR + StringUtils.LINE_SEPARATOR); Jalopy jalopy = JalopyFactory.getJalopy(); try { StringBuffer sb = new StringBuffer(); jalopy.setInspect(false); jalopy.setForce(true); jalopy.setInput(javaCode, "Format.java"); jalopy.setOutput(sb); if (jalopy.format()) { String formatted = sb.toString(); // System.out.println("Unformatted:["+someCode+"]"); return removeExtraIndentation(formatted.substring(51 + 2 * StringUtils.LINE_SEPARATOR.length(), formatted.length() - 2 - 2 * StringUtils.LINE_SEPARATOR.length())); // return formatted.substring(53,formatted.length()-4); } } catch (Exception e) { e.printStackTrace(); if (logger.isLoggable(Level.WARNING)) { logger.warning("Exception occured while parsing the java code"); } } if (jalopy.getState() == Jalopy.State.ERROR) { logger.warning("Java code could not be formatted"); throw new JavaFormattingException(); } if (logger.isLoggable(Level.WARNING)) { logger.warning("Java code could not be formatted: " + jalopy.getState()); } return someCode; } public static String removeExtraIndentation(String someCode) { StringTokenizer st = new StringTokenizer(someCode, StringUtils.LINE_SEPARATOR); Vector<String> lines = new Vector<String>(); while (st.hasMoreTokens()) { String next = st.nextToken(); if (!next.trim().equals("")) { lines.add(next); } } boolean charIsUnsignificantAndMatchesEverywhere = true; int firstSignificantCharIndex = 0; while (charIsUnsignificantAndMatchesEverywhere) { char c = lines.firstElement().charAt(firstSignificantCharIndex); if (c < 32 || c == ' ' || c == '\t') { for (int i = 1; i < lines.size(); i++) { if (lines.elementAt(i).length() <= firstSignificantCharIndex || lines.elementAt(i).charAt(firstSignificantCharIndex) != c) { charIsUnsignificantAndMatchesEverywhere = false; } } if (charIsUnsignificantAndMatchesEverywhere) { // System.out.println("Found char "+c+" of "+((int)c)); firstSignificantCharIndex++; } } else { charIsUnsignificantAndMatchesEverywhere = false; } } StringBuffer returned = new StringBuffer(); st = new StringTokenizer(someCode, StringUtils.LINE_SEPARATOR, true); while (st.hasMoreTokens()) { String next = st.nextToken(); if (firstSignificantCharIndex < next.length()) { returned.append(next.substring(firstSignificantCharIndex)); } else { returned.append(next); } } return returned.toString(); } }