| /******************************************************************************* |
| * Copyright (c) 2014 E.D.Willink and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * R.Dvorak and others - QVTo debugger framework |
| * E.D.Willink - revised API for OCL debugger framework |
| *******************************************************************************/ |
| package org.eclipse.ocl.examples.debug.evaluator; |
| |
| import java.util.ArrayList; |
| import java.util.Collection; |
| import java.util.List; |
| import java.util.regex.Pattern; |
| |
| import org.apache.log4j.FileAppender; |
| import org.apache.log4j.Level; |
| import org.apache.log4j.Logger; |
| import org.apache.log4j.PatternLayout; |
| import org.eclipse.emf.ecore.EClass; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.EStructuralFeature; |
| import org.eclipse.jdt.annotation.NonNull; |
| import org.eclipse.jdt.annotation.Nullable; |
| import org.eclipse.ocl.examples.pivot.Element; |
| import org.eclipse.ocl.examples.pivot.prettyprint.PrettyPrinter; |
| |
| |
| /** |
| * The Class OCLAbstractTracingEvaluationVisitor is a decorator visitor that prints |
| * AST, variable values and other information useful for debugging. |
| * |
| * @author Horacio Hoyos |
| */ |
| public abstract class OCLAbstractTracingEvaluationVisitor extends OCLVMEvaluationVisitorDecorator |
| { |
| |
| protected static Logger logger = Logger.getLogger(OCLAbstractTracingEvaluationVisitor.class); |
| |
| /** The Constant DEFAULT_INDENT. */ |
| protected static final String DEFAULT_INDENT = " "; |
| |
| /** The verbose level low. */ |
| static int VERBOSE_LEVEL_LOW = 0; |
| |
| /** The verbose level med. */ |
| static int VERBOSE_LEVEL_MED = 1; |
| |
| /** The verbose level high. */ |
| static int VERBOSE_LEVEL_HIGH = 2; |
| |
| /** The verbose level. */ |
| protected static int verboseLevel = VERBOSE_LEVEL_LOW; |
| |
| /** The indent level. */ |
| private int indentLevel = 0; |
| |
| |
| /** |
| * Instantiates a new OCL tracing evaluation visitor. |
| * |
| * @param decorated the decorated |
| */ |
| public OCLAbstractTracingEvaluationVisitor(@NonNull IOCLVMEvaluationVisitor decorated) { |
| |
| this(decorated, 0); |
| if (logger.getAppender("OCLTrace") == null) { |
| FileAppender appender = new FileAppender(); |
| // configure the appender here, with file location, etc |
| appender.setFile("OCLTrace.log"); |
| appender.setName("OCLTrace"); |
| appender.setLayout(new PatternLayout(PatternLayout.DEFAULT_CONVERSION_PATTERN)); |
| appender.setAppend(false); |
| appender.activateOptions(); |
| logger.addAppender(appender); |
| } |
| logger.setAdditivity(false); |
| logger.setLevel(Level.DEBUG); |
| } |
| |
| /** |
| * Instantiates a new OCL tracing evaluation visitor. |
| * |
| * @param decorated the decorated |
| * @param indentLevel the indent level |
| */ |
| protected OCLAbstractTracingEvaluationVisitor(@NonNull IOCLVMEvaluationVisitor decorated, int indentLevel) { |
| |
| super(decorated); |
| this.indentLevel = indentLevel; |
| } |
| |
| |
| /** |
| * Gets the verbose level. |
| * |
| * @return the verbose level |
| */ |
| public int getVerboseLevel() { |
| return verboseLevel; |
| } |
| |
| |
| /** |
| * Sets the verbose level. |
| * |
| * @param verboseLevel the new verbose level |
| */ |
| public void setVerboseLevel(int verboseLevel) { |
| OCLAbstractTracingEvaluationVisitor.verboseLevel = verboseLevel; |
| } |
| |
| /** |
| * Gets the indent. |
| * |
| * @return the indent |
| */ |
| protected @NonNull String getIndent() { |
| |
| StringBuilder outputBuffer = new StringBuilder(indentLevel); |
| for (int i = 0; i < indentLevel; i++){ |
| outputBuffer.append(DEFAULT_INDENT); |
| } |
| @SuppressWarnings("null")@NonNull String string = outputBuffer.toString(); |
| return string; |
| } |
| |
| public @NonNull Pattern getRegexPattern(@NonNull String regex) { |
| return delegate.getRegexPattern(regex); |
| } |
| |
| /** |
| * Safe print. |
| * |
| * @param element the element |
| * @return the string |
| */ |
| protected @NonNull String safePrint(@Nullable Element element) { |
| return element != null ? PrettyPrinter.print(element) : "null"; |
| } |
| |
| |
| /** |
| * Pretty print Objects. EObjects are printed at 1 level depth (i.e. no |
| * navigation through associations). Other objects are printed as Strings |
| * |
| * @param object the object |
| * @return the string |
| */ |
| protected String prettyPrint(Object object) { |
| |
| List<String> lines = new ArrayList<String>(); |
| if (object instanceof EObject) { |
| EObject eo = (EObject) object; |
| EClass eClass = eo.eClass(); |
| lines.add(eClass.getName() + " [" + Integer.toHexString(eo.hashCode()) + "] {"); // |
| indentLevel++; |
| for (EStructuralFeature feature : eClass.getEAllStructuralFeatures()) { |
| Object value = eo.eGet(feature); |
| String line = getIndent() + feature.getName() + " = "; |
| if (value instanceof Collection<?>) { |
| int size = ((Collection<?>)value).size(); |
| if (size > 0) { |
| line += "[" + ((EObject)((Iterable<?>) value).iterator().next()).eClass().getName() + "] x " + size; |
| } else { |
| line += "[ ]"; |
| } |
| } else if (value instanceof EObject) { |
| eClass = ((EObject) value).eClass(); |
| line += eClass.getName() + " [" + Integer.toHexString(value.hashCode()) + "]"; |
| } else { |
| if (value == null) { |
| line += "[ null ]"; |
| } else { |
| line += String.valueOf(value); |
| } |
| } |
| lines.add(line); |
| } |
| lines.add(getIndent() + "}"); |
| indentLevel--; |
| StringBuilder sb = new StringBuilder(); |
| for (String line : lines) { |
| sb.append(line).append('\n'); |
| } |
| sb.delete(sb.length()-1, sb.length()); |
| return sb.toString(); |
| } else { |
| return String.valueOf(object); |
| } |
| } |
| |
| protected String prettyPrintUnident(Object object) { |
| List<String> lines = new ArrayList<String>(); |
| if (object instanceof EObject) { |
| EObject eo = (EObject) object; |
| EClass eClass = eo.eClass(); |
| lines.add(eClass.getName() + " [" + Integer.toHexString(eo.hashCode()) + "] {"); // |
| indentLevel++; |
| for (EStructuralFeature feature : eClass.getEAllStructuralFeatures()) { |
| Object value = eo.eGet(feature); |
| String line = DEFAULT_INDENT + feature.getName() + " = "; |
| if (value instanceof Collection<?>) { |
| int size = ((Collection<?>)value).size(); |
| if (size > 0) { |
| line += "[" + ((EObject)((Iterable<?>) value).iterator().next()).eClass().getName() + "] x " + size; |
| } else { |
| line += "[ ]"; |
| } |
| } else if (value instanceof EObject) { |
| eClass = ((EObject) value).eClass(); |
| line += eClass.getName() + " [" + Integer.toHexString(value.hashCode()) + "]"; |
| } else { |
| if (value == null) { |
| line += "[ null ]"; |
| } else { |
| line += String.valueOf(value); |
| } |
| } |
| lines.add(line); |
| } |
| lines.add(DEFAULT_INDENT + "}"); |
| indentLevel--; |
| StringBuilder sb = new StringBuilder(); |
| for (String line : lines) { |
| sb.append(line).append('\n'); |
| } |
| sb.delete(sb.length()-1, sb.length()); |
| return sb.toString(); |
| } else { |
| return String.valueOf(object); |
| } |
| |
| |
| } |
| } |