RulesTracing.java
/*
** Module : RulesTracing.java
** Abstract : Class implementing rules tracing.
**
** Copyright (c) 2016-2017, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------Description----------------------------------
** 001 HC 20160907 Created initial version.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program 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 Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.pattern;
import com.goldencode.ast.*;
import java.util.*;
/**
* The class implements support for simple tracing of rules processing.
* <p>
* When tracing is active all {@link Rule} instances originating from rules xml files are created
* with additional tracing information - the rules file and line number each rule is defined on.
* Also all {@link AnnotatedAst} nodes created as the result of processing of the individual
* rules are annotated with the positional information.
* <p>
* To turn tracing ON the Java property "rules.tracing" must be defined (for example with the
* -D param on the command line when the Java process is started).
*/
public class RulesTracing
{
/**
* Flag to indicate whether tracing is ON.
*/
public static final boolean isOn = System.getProperty("rules.tracing") != null;
/**
* The stack of rule processing locations.
**/
private static ThreadLocal<Stack<Location>> locationStack =
ThreadLocal.withInitial(() -> new Stack<Location>());
/**
* Flag preventing infinite recursion.
*/
private static ThreadLocal<Boolean> annotating = new ThreadLocal<>();
/**
* Annotation key suffix.
*/
private static final String ANNOTATION_SUFFIX = "ByRule";
/**
* Pushes positional information on the stack.
*
* @param file File name.
* @param line Line number.
*/
public static void pushLocation(String file, int line)
{
locationStack.get().push(new Location(file, line));
}
/**
* Pops positional information from the stack.
*
* @return The popped location.
*/
public static Location popLocation()
{
return locationStack.get().pop();
}
/**
* Peeks the positional information currently on the top of the stack.
*
* @return The location on the top of the stack.
*/
public static Location peekLocation()
{
Stack<Location> stack = locationStack.get();
return stack.isEmpty() ? null : stack.peek();
}
/**
* Annotates the passed in node instance with positional information currently on the top of
* the stack.
*
* @param ast A valid syntax tree node instance to annotate.
*/
public static void putCreateLocation(AnnotatedAst ast)
{
// prevent recursion on the thread
if (Boolean.TRUE.equals(annotating.get()))
{
return;
}
Location loc = peekLocation();
if (loc == null)
{
// no location being recorded, nothing to do
return;
}
try
{
annotating.set(Boolean.TRUE);
ast.putAnnotation(ANNOTATION_SUFFIX, formatLocation(loc));
}
finally
{
annotating.remove();
}
}
/**
* Annotates the passed in node instance with positional information currently on the top of
* the stack. The positional information is subjected to the passed in annotation name.
*
* @param ast A valid syntax tree node instance to annotate.
* @param annotationName A valid annotation name.
*/
public static void putCreateLocation(AnnotatedAst ast, String annotationName)
{
// prevent recursion on the thread
if (Boolean.TRUE.equals(annotating.get()))
{
return;
}
Location loc = peekLocation();
if (loc == null)
{
return;
}
try
{
annotating.set(Boolean.TRUE);
ast.putAnnotation(annotationName + "-" + ANNOTATION_SUFFIX, formatLocation(loc));
}
finally
{
annotating.remove();
}
}
/**
* Remover the tracing annotation from the passed in node instance.
*
* @param ast
* A valid syntax tree node instance to annotate.
* @param annotationName
* A valid annotation name.
*/
public static void removeCreateLocation(AnnotatedAst ast, String annotationName)
{
// prevent recursion on the thread
if (Boolean.TRUE.equals(annotating.get()))
{
return;
}
try
{
annotating.set(Boolean.TRUE);
ast.removeAnnotation(annotationName + "-" + ANNOTATION_SUFFIX);
}
finally
{
annotating.remove();
}
}
/**
* Returns the formatted string of the passed in location.
*
* @param loc A valid location.
* @return See above.
*/
private static String formatLocation(Location loc)
{
return loc.file + ":" + loc.line;
}
/**
* Holds the positional information.
*/
public static class Location
{
/**
* Ctor.
*
* @param file A valid file name.
* @param line A valid line number.
*/
public Location(String file, int line)
{
this.file = file;
this.line = line;
}
/**
* File name.
*/
public String file;
/**
* File number.
*/
public int line;
}
}