Wiki source code of Click to Debug

Last modified by Kieran Kelleher on 2009/08/12 14:33

Hide last authors
David Holt 6.1 1 == What It Is ==
2
Kieran Kelleher 21.1 3 Click to Debug is a [[doc:documentation.Home.WOLips Tutorials.Click to Open.WebHome]] extension that allows you to toggle binding debugging from the UI while your application is running.
David Holt 6.1 4
5 == What You Need ==
6
Kieran Kelleher 21.1 7 See the [[What You Need>>doc:documentation.Home.WOLips Tutorials.Click to Open.WebHome||anchor="What You Need"]] section of the Click to Open documentation if you are not already using Click to to Open.
David Holt 6.1 8
9 == Getting Set Up ==
10
Kieran Kelleher 21.1 11 See the [[Getting Set Up>>doc:documentation.Home.WOLips Tutorials.Click to Open.WebHome||anchor="Getting Set Up"]] section of the Click to Open documentation if you are not already using Click to to Open.
David Holt 6.1 12
David Holt 18.1 13 Add this line to the {{code language="none"}}Properties{{/code}} file in your application:
David Holt 6.1 14
15 {{code}}
16
17 ognl.debugSupport=true
18
19 {{/code}}
20
21 === Add Support to Application ===
22
David Holt 18.1 23 If your Application.java class extends (directly or indirectly) Wonder's ERXApplication, you can skip this step. Otherwise, add this to your Application() constructor, or a method that runs before requests are processed::
David Holt 6.1 24
David Holt 18.1 25 {{code 0="java"}}
David Holt 6.1 26
27 NSNotificationCenter.defaultCenter().addObserver(this,
28 ERXSelectorUtilities.notificationSelector("applicationDidHandleRequest"),
29 WOApplication.ApplicationDidDispatchRequestNotification, null);
30
31 {{/code}}
32
33 Then add this method to handle this notification:
34
David Holt 18.1 35 {{code 0="java"}}
David Holt 6.1 36
37 /**
38 * When request is finished, we remove the context from thread local storage.
39 *
40 * @see #createContextForRequest(WORequest)
41 * @param n notification
42 */
43 public void applicationDidHandleRequest(NSNotification n) {
44 ERXWOContext.setCurrentContext(null);
45 ERXThreadStorage.removeValueForKey(ERXWOContext.CONTEXT_DICTIONARY_KEY);
46 }
47
48 {{/code}}
49
50 The next part is a method that sets ERXWOContext.currentContext() when a request is dispatched:
51
David Holt 18.1 52 {{code 0="java"}}
David Holt 6.1 53
54 /**
55 * When a context is created we push it into thread local storage.
56 *
57 * @see #applicationDidHandleRequest(NSNotification)
58 * @param request the request
59 * @return the newly created context
60 */
61 public WOContext createContextForRequest(WORequest request) {
62 WOContext context = super.createContextForRequest(request);
63 // We only want to push in the context the first time it is
64 // created, ie we don't want to lose the current context
65 // when we create a context for an error page.
66 if (ERXWOContext.currentContext() == null) {
67 ERXWOContext.setCurrentContext(context);
68 }
69 return context;
70 }
71
72 {{/code}}
73
74 And finally, add this code to support Click to Debug:
75
David Holt 18.1 76 {{code 0="java"}}
David Holt 6.1 77
Chuck Hill 12.1 78 protected void _debugValueForDeclarationNamed(WOComponent component, String verb, String aDeclarationName,
79 String aDeclarationType, String aBindingName,
80 String anAssociationDescription, Object aValue) {
David Holt 6.1 81 if (aValue instanceof String) {
82 StringBuffer stringbuffer = new StringBuffer(((String) aValue).length() + 2);
83 stringbuffer.append('"');
84 stringbuffer.append(aValue);
85 stringbuffer.append('"');
86 aValue = stringbuffer;
87 }
88 if (aDeclarationName.startsWith("_")) {
89 aDeclarationName = "[inline]";
90 }
91
92 StringBuffer sb = new StringBuffer();
93
94 //NSArray<WOComponent> componentPath = ERXWOContext._componentPath(ERXWOContext.currentContext());
95 //componentPath.lastObject()
96 //WOComponent lastComponent = ERXWOContext.currentContext().component();
97 String lastComponentName = component.name().replaceFirst(".*\\.", "");
98 sb.append(lastComponentName);
99
100 sb.append(verb);
101
102 if (!aDeclarationName.startsWith("_")) {
103 sb.append(aDeclarationName);
104 sb.append(":");
105 }
106 sb.append(aDeclarationType);
107
108 sb.append(" { ");
109 sb.append(aBindingName);
110 sb.append("=");
111
112 String valueStr = aValue != null ? aValue.toString() : "null";
113 if (anAssociationDescription.startsWith("class ")) {
114 sb.append(valueStr);
115 sb.append("; }");
116 }
117 else {
118 sb.append(anAssociationDescription);
119 sb.append("; } value ");
120 sb.append(valueStr);
121 }
122
123 NSLog.debug.appendln(sb.toString());
124 }
125
126 /**
127 * The set of component names that have binding debug enabled
128 */
129 private NSMutableSet<String> _debugComponents = new NSMutableSet<String>();
130
131 /**
132 * Little bit better binding debug output than the original.
133 */
134 @Override
Chuck Hill 12.1 135 public void logTakeValueForDeclarationNamed(String aDeclarationName, String aDeclarationType,
136 String aBindingName, String anAssociationDescription, Object aValue) {
David Holt 6.1 137 WOComponent component = ERXWOContext.currentContext().component();
138 if (component.parent() != null) {
139 component = component.parent();
140 }
Chuck Hill 12.1 141 _debugValueForDeclarationNamed(component, " ==> ", aDeclarationName,
142 aDeclarationType, aBindingName, anAssociationDescription, aValue);
David Holt 6.1 143 }
144
145 /**
146 * Little bit better binding debug output than the original.
147 */
148 @Override
Chuck Hill 12.1 149 public void logSetValueForDeclarationNamed(String aDeclarationName, String aDeclarationType,
150 String aBindingName, String anAssociationDescription, Object aValue) {
David Holt 6.1 151 WOComponent component = ERXWOContext.currentContext().component();
152 if (component.parent() != null) {
153 component = component.parent();
154 }
Chuck Hill 12.1 155 _debugValueForDeclarationNamed(component, " <== ", aDeclarationName, aDeclarationType,
156 aBindingName, anAssociationDescription, aValue);
David Holt 6.1 157 }
158
159 /**
160 * Turns on/off binding debugging for the given component. Binding debugging requires using the WOOgnl
161 * template parser and setting ognl.debugSupport=true.
162 *
163 * @param debugEnabled whether or not to enable debugging
164 * @param componentName the component name to enable debugging for
165 */
166 public void setDebugEnabledForComponent(boolean debugEnabled, String componentName) {
167 if (debugEnabled) {
168 _debugComponents.addObject(componentName);
169 }
170 else {
171 _debugComponents.removeObject(componentName);
172 }
173 }
174
175 /**
176 * Returns whether or not binding debugging is enabled for the given component
177 *
178 * @param componentName the component name
179 * @return whether or not binding debugging is enabled for the given componen
180 */
181 public boolean debugEnabledForComponent(String componentName) {
182 return _debugComponents.containsObject(componentName);
183 }
184
185 /**
186 * Turns off binding debugging for all components.
187 */
188 public void clearDebugEnabledForAllComponents() {
189 _debugComponents.removeAllObjects();
190 }
191
192 {{/code}}
193
194 == Using Click to Debug ==
195
David Holt 18.1 196 Run your application and look in the lower, left hand corner. You should see a link like this:
David Holt 6.1 197
Kieran Kelleher 21.1 198 [[image:attach:documentation.Home.WOLips Tutorials.Click to Open.WebHome@ClickToOpenLink.png]]
Chuck Hill 12.1 199
David Holt 18.1 200 If you don't, check that the page has the WOLToolBar on it and that the {{code language="none"}}er.component.clickToOpen{{/code}} property is set to true and the {{code language="none"}}er.extensions.ERXApplication.developmentMode{{/code}} property is set to true.
Chuck Hill 12.1 201
202 \\
203
204 Click on this component to open the Click to Open UI:
205
Kieran Kelleher 21.1 206 [[image:attach:documentation.Home.WOLips Tutorials.Click to Open.WebHome@WOLipsToolbar.png]]
Chuck Hill 12.1 207
David Holt 18.1 208 **EditDisplayAd** is the page in the browser. Click on this link to open this page in Eclipse.
Chuck Hill 12.1 209
210 \\
211
David Holt 18.1 212 If you are looking for a sub-component of this page, click on the **Click to Debug** link. As you move your mouse over the page, the bread crumb of components will change to show you where you are. Just click to turn binding debug on (or off if it is on) for the component under the mouse in Eclipse. It is that easy!
Chuck Hill 12.1 213
David Holt 18.1 214 [[image:attach:ClickToDebugInAction.png]]
Chuck Hill 12.1 215
216 \\
217
Chuck Hill 14.1 218 With binding debug on, you'll get output like:
219
220 {{code}}
221
222 DEBUG NSLog - HatchViewTaskPage ==> [inline]:HatchEditTask { task=task; } value <com.mdimension.mdtask.model.Task pk:"1027787">
223 DEBUG NSLog - HatchViewTaskPage <== [inline]:HatchEditTask { task=task; } value <com.mdimension.mdtask.model.Task pk:"1027787">
224 DEBUG NSLog - HatchViewTaskPage ==> [inline]:HatchEditTask { task=task; } value <com.mdimension.mdtask.model.Task pk:"1027787">
225 DEBUG NSLog - HatchViewTaskPage <== [inline]:HatchEditTask { task=task; } value <com.mdimension.mdtask.model.Task pk:"1027787">
226 DEBUG NSLog - HatchViewTaskPage ==> [inline]:HatchEditTask { task=task; } value <com.mdimension.mdtask.model.Task pk:"1027787">
227 DEBUG NSLog - HatchViewTaskPage <== [inline]:HatchEditTask { task=task; } value null
228 DEBUG NSLog - HatchViewTaskPage ==> [inline]:HatchEditTask { task=task; } value null
229 DEBUG NSLog - HatchViewTaskPage <== [inline]:HatchEditTask { task=task; } value null
230
231 {{/code}}
232
David Holt 18.1 233 **Note**: A prefix like {{code language="none"}}Dec 13 11:00:29 MDTask[WOL:62934] (ERXNSLogLog4jBridge.java:46){{/code}} was removed from each line above to make this easier to read.
Chuck Hill 14.1 234
David Holt 18.1 235 So what that's showing is HatchViewTaskPage component is pushing the task binding into the HatchEditTask component with the value Task
236 1027787, then HatchEditTask component is pushing the binding back up. So you can see here that 6th line, HatchEditTask component is pushing a null binding back out (which, in this case, was causing a problem I was trying to find).