| /* |
| * 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; |
| } |
| } |