blob: 9326f05f9970c50324cbc97cc548672fe2fbe69b [file] [log] [blame]
/*
* Copyright 2003-2004 The Apache Software Foundation.
// (c) Copyright IBM Corp. 2004, 2005 All Rights Reserved
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.axis.tools.trace;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Set;
import java.util.StringTokenizer;
import org.apache.axis.tools.common.*;
/**
* A Buffered write that also contains the methods to add in in trace
* TODO: Add in &this and threadid into each trace record
*/
class Tracer extends BufferedWriter {
private Signature signature = null;
private final static String SIGNATURE = " /* AUTOINSERTED TRACE */";
private Headers headers;
private String namespace = null;
private String hashifdef = null;
private String hashelse = null;
private String hashendif = null;
private String module = null;
private static Hashtable typetable = new Hashtable();
static {
typetable.put("char", "CHAR");
typetable.put("unsigned char", "CHAR");
typetable.put("unsigned short", "USHORT");
typetable.put("short", "SHORT");
typetable.put("signed short", "SHORT");
typetable.put("unsigned", "UINT");
typetable.put("unsigned int", "UINT");
typetable.put("int", "INT");
typetable.put("signed int", "INT");
typetable.put("signed", "INT");
typetable.put("unsigned long", "ULONG");
typetable.put("long", "LONG");
typetable.put("signed long", "LONG");
typetable.put("double", "DOUBLE");
typetable.put("float", "FLOAT");
typetable.put("bool", "BOOL");
typetable.put("string", "STLSTRING");
typetable.put("AxisString", "STLSTRING");
typetable.put("AxisXMLString", "STLSTRING");
typetable.put("xsd__string", "STRING");
}
private final static Set charSet =
new HashSet(
Arrays.asList(
new Object[] { "char", "AxisChar", "AxisXMLChar", "XML_Ch" }));
/**
* @param writer a writer to the output file.
*/
Tracer(Writer writer, int depth, Headers headers) throws IOException {
super(writer);
this.headers = headers;
namespace = Configuration.getConfigured("namespace");
if (null != namespace)
namespace += "::";
else
namespace = "";
hashifdef = Configuration.getConfigured("ifdef");
if (null != hashifdef) {
hashifdef = "#ifdef " + hashifdef + "\n";
hashelse = "#else\n";
hashendif = "#endif\n";
} else {
hashifdef = "";
hashelse = "";
hashendif = "";
}
module = Configuration.getConfigured("module");
if (null != module)
module += "::";
else
module = ""; // C-style function
String include = Configuration.getConfigured("include");
String includefile = "";
if (null == include) {
String prefix = "";
if (depth > 1)
for (int i = 1; i < depth; i++)
prefix += "../";
includefile = "\"" + prefix + "common/AxisTrace.h\"";
} else {
includefile = include;
}
String prefix = "";
if (depth > 1)
for (int i = 1; i < depth; i++)
prefix += "../";
String line =
hashifdef
+ "/* TRACE ADDED BY THE TRACE INSTRUMENTOR TOOL */\n"
+ "#include "
+ includefile
+ "\n"
+ hashendif;
writeTrace(line);
flush();
}
/**
* @param signature the signature of this method
* TODO: Can't tell the difference between static and non-static
* methods so can't tell whether to pass this or not. If we pass
* this in a static method it won't compile.
*/
void traceEntry(Signature signature) throws IOException {
this.signature = signature;
if (!signature.traceable())
return;
Parameter[] parms = signature.getParameters();
int len = 0;
if (null != parms) {
if (parms[parms.length - 1].isDotDotDot())
len = parms.length - 1;
else
len = parms.length;
}
String that = "NULL";
if (headers.isInstanceMethod(signature))
that = "this";
String line =
"\n"
+ "\t"
+ hashifdef
+ "\t\tif ("
+ namespace
+ module
+ "isTraceOn())\n"
+ "\t\t\t"
+ namespace
+ module
+ "traceEntry("
+ getClassName()
+ ", \""
+ signature.getMethodName()
+ "\", "
+ that
+ ", "
+ len;
for (int i = 0; null != parms && i < parms.length; i++)
line += getTypeParms(parms[i]);
line += ");\t" + SIGNATURE + "\n";
line += "\t" + hashendif;
writeTrace(line);
flush();
}
void traceExit(int returnIndex) throws Exception {
if (!signature.traceable())
return;
// Check this method really should return void
if (null != signature.getReturnType().getType())
Utils.rude(
"Expecting to return void from a method that returns a value: "
+ signature.toString());
String that = "NULL";
if (headers.isInstanceMethod(signature))
that = "this";
// Enclose the printf/return in {} in case if/then doesn't have {}
String line = "\t{\n";
line += "\t\t" + hashifdef;
line += "\t\t\tif (" + namespace + module + "isTraceOn())\n";
line += "\t\t\t\t"
+ namespace
+ module
+ "traceExit("
+ getClassName()
+ ", \""
+ signature.getMethodName()
+ "\", "
+ that
+ ", "
+ returnIndex
+ ");\t"
+ SIGNATURE
+ "\n";
line += "\t\t" + hashendif;
// now print out the return line itself
line += "\t\treturn;\n";
line += "\t}\n";
writeTrace(line);
flush();
}
/**
* Takes in the return statement and traces out the exit trace statement for it
* This method prints out the complete return line as well so the user
* does not need to print this out themselves.
*/
void traceExit(String value, int returnIndex) throws Exception {
if (!signature.traceable())
return;
// Check this method doesn't return void
if (null == signature.getReturnType().getType())
Utils.rude(
"Expecting to return a value from a method that returns void: "
+ signature.toString());
String that = "NULL";
if (headers.isInstanceMethod(signature))
that = "this";
// Enclose the printf/return in {} in case if/then doesn't have {}
// Copy the return value into a local called traceRet in case the
// return value has side-effects such as "return i++;" or "return func();"
// This makes sure that we don't execute the return value twice.
// Unfortunately if the return value is a class we will invoke
// a copy constructor. When initialising traceRet with value, put value
// in brackets in case it contains an operator that might be invoked
// after the assignment, like another assignment.
String line = "\t{\n";
line += "\t\t" + hashifdef;
line += "\t\t\t"
+ signature.getReturnType().getType()
+ " traceRet = ("
+ value
+ ");\n";
line += "\t\t\tif (" + namespace + module + "isTraceOn())\n";
line += "\t\t\t\t"
+ namespace
+ module
+ "traceExit("
+ getClassName()
+ ", \""
+ signature.getMethodName()
+ "\", "
+ that
+ ", "
+ returnIndex
+ getTypeParms(signature.getReturnType(), true)
+ ");\t"
+ SIGNATURE
+ "\n";
line += "\t\t\treturn traceRet;\n";
line += "\t\t" + hashelse;
if (hashelse.length() > 0)
line += "\t\t\treturn " + value + ";\n";
line += "\t\t" + hashendif;
line += "\t}\n";
writeTrace(line);
flush();
}
void traceCatch(Parameter value, int catchIndex) throws Exception {
if (!signature.traceable())
return;
String that = "NULL";
if (headers.isInstanceMethod(signature))
that = "this";
String line =
"\n"
+ "\t"
+ hashifdef
+ "\t\tif ("
+ namespace
+ module
+ "isTraceOn())\n"
+ "\t\t\t"
+ namespace
+ module
+ "traceCatch("
+ getClassName()
+ ", \""
+ signature.getMethodName()
+ "\", "
+ that
+ ", "
+ catchIndex
+ getTypeParms(value);
line += ");\t" + SIGNATURE + "\n";
line += "\t" + hashendif;
writeTrace(line);
flush();
}
/*
* This method is careful to get the line separators because other
* other methods have been careless assuming that the line separator
* is always only \n, whereas it maybe \r\n.
*/
public void writeTrace(String s) throws IOException {
if (s.startsWith("\n") || s.startsWith("\r"))
super.newLine();
StringTokenizer st = new StringTokenizer(s, "\n\r");
while (st.hasMoreTokens()) {
super.write(st.nextToken());
if (st.hasMoreTokens())
super.newLine();
}
if (s.endsWith("\n") || s.endsWith("\r"))
super.newLine();
if (Options.verbose())
System.out.print(s);
}
// TODO cope with STL strings
// TODO cope with pointers to primitives
// TODO cope with references
private String getTypeParms(Parameter p) { return getTypeParms(p,false); }
private String getTypeParms(Parameter p, boolean isRetType) {
// copes with catch (...)
if ("...".equals(p.getType()))
return " ";
String parms = ",\n\t\t\t\t\tTRACETYPE_";
String name = p.getName();
if (isRetType)
name = "traceRet";
else if (null == name) {
// A parameter without a name can't be traced
parms += "ANONYMOUS, 0, NULL";
return parms;
}
name = "((void*)&" + name + ")";
String type = p.getTypeWithoutConst();
if (null == type || 0 == type.length()) {
parms += "UNKNOWN, 0, NULL";
} else if (typetable.keySet().contains(type)) {
parms += (String) typetable.get(type) + ", 0, " + name;
} else if (type.endsWith("*")) {
String contents = type.substring(0, type.length() - 1);
if (charSet.contains(contents)) {
parms += "STRING, 0, " + name;
} else if ("void".equals(contents)) {
// We just don't know what this void* is pointing at
// so that best we can do is to print out the first byte.
parms += "POINTER, 1, " + name;
} else {
parms += "POINTER, sizeof(" + contents + "), " + name;
}
} else if (type.endsWith("&")) {
String contents = type.substring(0, type.length() - 1);
if (typetable.keySet().contains(contents)) {
parms += (String) typetable.get(contents) + ", 0, " + name;
} else if (contents.startsWith("Axis") && contents.endsWith("Exception")) {
parms += "AXISEXCEPTION, sizeof(" + type + "), " + name;
} else if (contents.equals("exception")) {
parms += "EXCEPTION, sizeof(" + type + "), " + name;
} else {
parms += "DATA, sizeof(" + type + "), " + name;
}
} else if (type.startsWith("Axis") && type.endsWith("Exception")) {
parms += "AXISEXCEPTION, sizeof(" + type + "), " + name;
} else if (type.equals("exception")) {
parms += "EXCEPTION, sizeof(" + type + "), " + name;
} else {
parms += "DATA, sizeof(" + type + "), " + name;
}
return parms;
}
private String getClassName() {
String name;
if (null != signature.getClassName()) {
name = signature.getClassName();
name = name.substring(0, name.indexOf("::"));
name = "\"" + name + "\"";
} else
name = "NULL";
return name;
}
}