org.glassfish.pfl.tf.tools.enhancer.EnhanceTool Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package org.glassfish.pfl.tf.tools.enhancer ;
import org.glassfish.pfl.basic.tools.argparser.DefaultValue ;
import org.glassfish.pfl.basic.tools.argparser.Help ;
import org.glassfish.pfl.basic.tools.argparser.ArgParser ;
import org.glassfish.pfl.basic.tools.file.ActionFactory;
import org.glassfish.pfl.basic.tools.file.Scanner ;
import org.glassfish.pfl.basic.tools.file.Recognizer ;
import org.glassfish.pfl.basic.tools.file.FileWrapper ;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.Set;
import org.glassfish.pfl.tf.timer.spi.TimerPointSourceGenerator;
import org.glassfish.pfl.tf.timer.spi.TimingInfoProcessor;
import org.glassfish.pfl.tf.timer.spi.TimerFactory;
import org.glassfish.pfl.basic.contain.Pair;
import org.glassfish.pfl.basic.func.UnaryFunction;
import org.glassfish.pfl.tf.spi.Util;
/** Tool for enhancing classes annotated with tracing facility annotations.
* The processing is divided into two phases:
*
* - The first phase adds code to the static initialized of the class to
* register the class with the TF framework. This phase also modifies all
* calls to @InfoMethod annotated methods to pass extra arguments needed for
* tracing. Note that this phase must be done at build time, because it
* modifies the schema of the class.
*
- The second phase adds the actual trace code to methods annotated with
* tracing annotations. This does not change the schema, so this phase
* could be done either at build time, or at runtime. Tracing the code only
* at runtime may reduce the overhead, since untraced code need not be modified.
*
* This tool can do either phase 1, or phase 1 and 2, against ALL classes
* reachable from a starting directory.
* @author ken
*/
public class EnhanceTool {
private static int errorCount = 0 ;
private Util util ;
public enum ProcessingMode {
/** Only generate the timing points file: no changes to monitored class
* bytecode.
*/
TimingPoints,
/** Update the class schemas for monitored classes, but don't insert
* the tracing code. Generate the TimingPoints file if the
* timingPointDir and timingPointClass options are set.
*/
UpdateSchemas,
/** Update the class schema and insert tracing code. Generate the
* TimingPoints file if the timingPointDir and timingPointClass
* options are set.
*/
TraceEnhance
}
public interface Arguments {
@DefaultValue( "tfannotations.properties" )
@Help( "Name of resource file containing information "
+ "about tf annotations")
File rf() ;
@DefaultValue( "false" )
@Help( "Debug flag" )
boolean debug() ;
@DefaultValue( "0" )
@Help( "Verbose flag" )
int verbose() ;
@DefaultValue( "false" )
@Help( "Indicates a run that only prints out actions, "
+ "but does not perform them")
boolean dryrun() ;
@DefaultValue( "." )
@Help( "Directory to scan for class file" )
File dir() ;
@DefaultValue( "false")
@Help( "If true, write output to a .class.new file")
boolean newout() ;
@DefaultValue( "TimingPoints" )
@Help( "Control the mode of operation: TimingPoints, UpdateSchema, or TraceEnhance")
ProcessingMode mode() ;
@DefaultValue( "" )
@Help( "The timing point class name")
String timingPointClass() ;
@DefaultValue( "" )
@Help( "The directory in which to write the TimingPoint file")
String timingPointDir() ;
}
private Arguments args ;
private TimingInfoProcessor tip ;
private class EnhancerFileAction implements Scanner.Action {
private UnaryFunction ea ;
public EnhancerFileAction( UnaryFunction ea ) {
this.ea = ea ;
}
@Override
public boolean evaluate( FileWrapper fw ) {
try {
util.info( 2, "Processing class " + fw.getName() ) ;
byte[] inputData = fw.readAll() ;
byte[] outputData = ea.evaluate( inputData ) ;
if (outputData != null) {
if (args.newout()) {
String fname = fw.getName() + ".new" ;
util.info( 1, "Writing to class file " + fname ) ;
FileWrapper fwo = new FileWrapper( fname ) ;
fwo.writeAll( outputData ) ;
} else {
util.info( 1, "Writing to class file " + fw.getName() ) ;
fw.writeAll( outputData ) ;
}
}
} catch (Exception exc) {
util.info( 1, "Exception " + exc + " while processing class "
+ fw.getName() ) ;
errorCount++ ;
}
// Always succeed, so we keep processing files after the first
// error.
return true ;
}
}
private void generatePropertiesFile( Arguments args,
Set anames ) throws IOException {
// Resource file that lists all MM annotations:
// org.glassfish.tf.annotations.size=n
// org.glassfish.tf.annotation.1=...
// ...
// org.glassfish.tf.annotation.n=...
final FileWrapper fw = new FileWrapper( args.rf() ) ;
fw.open( FileWrapper.OpenMode.WRITE_EMPTY ) ;
try {
fw.writeLine( "# Trace Facility Annotations" ) ;
fw.writeLine( "# generated by EnhanceTool on " + new Date() ) ;
fw.writeLine( "org.glassfish.tf.annotations.size="
+ anames.size() ) ;
int ctr=1 ;
for (String str : anames) {
String cname = str.replace( '/', '.' ) ;
fw.writeLine( "org.glassfish.tf.annotation."
+ ctr + "=" + cname ) ;
ctr++ ;
}
} finally {
fw.close() ;
}
}
private Scanner.Action makeIgnoreAction(
final boolean trace ) {
return new Scanner.Action() {
@Override
public String toString() {
return "ignore action (ignore files that don't match)" ;
}
@Override
public boolean evaluate(FileWrapper arg) {
if (trace) {
util.info( 1, "Skipping " + arg ) ;
}
return true ;
}
} ;
}
private void doScan( Arguments args, ActionFactory af,
Scanner scanner, Scanner.Action classAct ) throws IOException {
final Recognizer classRecognizer = af.getRecognizerAction() ;
final Scanner.Action ignoreAction = makeIgnoreAction(
args.debug() || args.verbose() > 2 ) ;
classRecognizer.setDefaultAction( ignoreAction ) ;
classRecognizer.addKnownSuffix( "class", classAct ) ;
scanner.scan( classRecognizer ) ;
}
public void run( String[] strs ) {
try {
final ArgParser ap = new ArgParser( Arguments.class ) ;
args = ap.parse( strs, Arguments.class ) ;
util = new Util( args.debug(), args.verbose() ) ;
final String tpname = args.timingPointClass() ;
String pkg = "" ;
String cname = tpname ;
if (tpname.length() > 0) {
int index = tpname.lastIndexOf('.') ;
if (index > 0) {
cname = tpname.substring( index + 1 ) ;
pkg = tpname.substring( 0, index ) ;
}
} else {
cname = "NotUsed" ;
pkg = "no.package" ;
}
tip = new TimingInfoProcessor( cname, pkg ) ;
final ActionFactory af = new ActionFactory( 0, args.dryrun() ) ;
final Scanner scanner = new Scanner( 0, args.dir() ) ;
AnnotationScannerAction annoAct = new AnnotationScannerAction( util,
tip ) ;
doScan( args, af, scanner, annoAct ) ;
Set anames = annoAct.getAnnotationNames() ;
if (args.debug()) {
util.info( 1, "MM Annotations: " + anames ) ;
}
generatePropertiesFile( args, anames ) ;
Transformer ea = new Transformer( util,
args.mode(), tip, anames ) ;
final Scanner.Action act = new EnhancerFileAction( ea ) ;
doScan( args, af, scanner, act ) ;
Pair res = tip.getResult() ;
if (!args.timingPointDir().equals( "" ) ) {
TimerPointSourceGenerator.generateFile(
args.timingPointDir(), res );
}
} catch (Exception exc) {
if (util == null) {
util = new Util( true, 1 ) ;
}
util.info( 1, "Exception: " + exc ) ;
if (args.debug()) {
exc.printStackTrace() ;
}
}
}
public static void main( String[] strs ) {
(new EnhanceTool()).run( strs ) ;
if (errorCount > 0) {
System.exit(errorCount);
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy