/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV 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 should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.debug; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import org.mozilla.javascript.Undefined; import org.mozilla.javascript.Wrapper; import com.servoy.j2db.scripting.JSEvent; /** * @author jcompagner * */ public final class ProfileData { private final String functionName; private final long time; private final String[] args; private final String sourceName; private final List<ProfileData> childs = new ArrayList<ProfileData>(); private ProfileData parent; private final boolean isCalculation; private final String parentSourceCall; private final boolean innerFunction; private final int[] lineNumbers; private final List<DataCallProfileData> dataCallProfileDatas; /** * @param functionName * @param l * @param args * @param sourceName * @param parentSourceCall * @param innerFunction * @param lineNumbers * @param dataCallProfileDatas */ public ProfileData(String functionName, long time, Object[] args, String sourceName, String parentSourceCall, boolean innerFunction, int[] lineNumbers, List<DataCallProfileData> dataCallProfileDatas) { this.parentSourceCall = parentSourceCall; this.innerFunction = innerFunction; this.lineNumbers = lineNumbers; this.dataCallProfileDatas = dataCallProfileDatas; if (this.lineNumbers != null) { Arrays.sort(this.lineNumbers); } // calcs always end with _ and are always in a source file that ends with _calculations) if (functionName != null && functionName.endsWith("_") && sourceName.endsWith("_calculations.js")) { this.functionName = functionName.substring(0, functionName.length() - 1); this.isCalculation = true; } else { this.functionName = functionName == null ? "<eval>" : functionName; this.isCalculation = false; } this.time = time; this.args = new String[args.length]; this.sourceName = sourceName; for (int i = 0; i < args.length; i++) { if (args[i] instanceof Wrapper) { args[i] = ((Wrapper)args[i]).unwrap(); } if (args[i] instanceof JSEvent) { JSEvent event = (JSEvent)args[i]; StringBuilder sb = new StringBuilder(); sb.append("JSEvent["); boolean added = false; if (event.getType() != null) { sb.append("type="); sb.append(event.getType()); added = true; } if (event.getFormName() != null) { if (added) sb.append(","); sb.append("form="); sb.append(event.getFormName()); added = true; } if (event.getElementName() != null) { if (added) sb.append(","); sb.append("element="); sb.append(event.getElementName()); added = true; } if (event.getModifiers() != 0) { if (added) sb.append(","); sb.append("modifiers="); sb.append(event.getModifiers()); added = true; } if (event.getX() != 0) { if (added) sb.append(","); sb.append("x="); sb.append(event.getX()); added = true; } if (event.getY() != 0) { if (added) sb.append(","); sb.append("y="); sb.append(event.getY()); added = true; } sb.append("]"); this.args[i] = sb.toString(); } else if (args[i] instanceof Undefined) { this.args[i] = "undefined"; } else { this.args[i] = args[i] != null ? args[i].toString() : null; } } } /** * @return the dataCallProfileDatas */ public List<DataCallProfileData> getDataCallProfileDatas() { return dataCallProfileDatas; } /** * @param profileData */ public void addChild(ProfileData profileData) { profileData.setParent(this); childs.add(profileData); } public boolean isInnerFunction() { return innerFunction; } public int[] getLineNumbers() { return lineNumbers; } /** * @return the isCalculation */ public boolean isCalculation() { return isCalculation; } /** * @param profileData */ private void setParent(ProfileData parent) { this.parent = parent; } /** * @return */ public ProfileData getParent() { return parent; } /** * @return */ public ProfileData[] getChildren() { return childs.toArray(new ProfileData[0]); } /** * @return */ public String getMethodName() { return functionName; } public String getArgs() { return Arrays.toString(args); } public long getOwnTime() { int childtime = 0; for (ProfileData pd : childs) { childtime += pd.time; } return time - childtime; } public long getTime() { return time; } public String getSourceName() { return sourceName; } /** * @return the parentSourceCall */ public String getParentSourceCall() { return parentSourceCall; } /** * @param sb */ public void toXML(StringBuilder sb) { String childPrefix = "\t"; int endLine = sb.lastIndexOf("\n"); if (endLine != -1) { childPrefix = sb.substring(endLine + 1) + '\t'; } sb.append("<profiledata "); sb.append("methodname=\""); sb.append(functionName); sb.append("\" innerfuction=\""); sb.append(innerFunction); sb.append("\" owntime=\""); sb.append(getOwnTime()); sb.append("\" totaltime=\""); sb.append(time); sb.append("\" args=\""); sb.append(getArgs()); sb.append("\" source=\""); sb.append(sourceName); if (parentSourceCall != null) { sb.append("\" callposition=\""); sb.append(parentSourceCall); } sb.append("\">"); for (ProfileData child : childs) { sb.append('\n'); sb.append(childPrefix); child.toXML(sb); } sb.append("</profiledata>"); } }