Apache Wicket is a Java-based framework for developing web-apps, somewhat comparable to Tapestry. In Wicket, code is written ala Swing, pages and components are written as Java POJO's, etc.
The Wicket framework only has one nasty side-effect for AppDynamics; a http request does not contain a servlet path or anything comparable, but only contains a unique user-session ID. Transaction splitting based on request URI will lead to an unlimited amount of unique BT's.
One of our customers, Netherlands based web-shop for postcards Greetz, has found a work-around. The solution is described below. Although it does require some changes to the application code, it gives a high level of control over the naming of the Business Transactions. Improvements are welcomed.
Please let me know if there are questions. Thanks to Greetz for providing this solution.
/Miel Donkers
miel.donkers@codecentric.nl
-----
For Wicket we are now using a special annotation in the Wicket Java code to indicate that a Page or Form should be treated as a business transaction. In the annotation we set the name of the business transaction.
Annotation definition
package com.greetz.wicket.measurement;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface BusinessTransaction
{
String value() default "";
}
Annotation usage
@BusinessTransaction("gap.login")
private class SignInForm extends Form
{
...
}
Next, and this is where stuff gets funky, we’ve overridden some classes around WebRequestCycleProcessor and made our own processor with a post encoder.
public class ConcurrentWebRequestWithPostEncoderCodingStrategy implements IRequestCodingStrategy, IRequestTargetMountsInfo
{
…
public final CharSequence encode(final RequestCycle requestCycle, final IRequestTarget requestTarget)
{
…
url = postEncoder.doPostEncode(requestCycle,requestTarget,requestCycle.getOriginalResponse().encodeURL(result));
…
}
}
In the post encoder we simply check if there is a BusinessTransaction annotation present on the Page or Component. The value set in the BusinessTransaction annotation is added to the path, so when the user e.g. clicks on a button to execute a request, the name of the BT is part of the request URI.
public class SecureWebRequestPostEncoder implements WebRequestPostEncoder
{
@Override
public CharSequence doPostEncode(final RequestCycle requestCycle, final IRequestTarget requestTarget, final CharSequence result)
{
...
Class<?> targetClass = null;
if (requestTarget instanceof IBookmarkablePageRequestTarget)
{
targetClass = ((IBookmarkablePageRequestTarget) requestTarget).getPageClass();
} else if (requestTarget instanceof ISharedResourceRequestTarget)
{
targetClass = ((ISharedResourceRequestTarget) requestTarget).getClass();
} else if (requestTarget instanceof IListenerInterfaceRequestTarget)
{
targetClass = ((IListenerInterfaceRequestTarget) requestTarget).getTarget().getClass();
} else if (requestTarget instanceof IPageRequestTarget)
{
targetClass = ((IPageRequestTarget) requestTarget).getPage().getClass();
}
if (targetClass != null && targetClass.isAnnotationPresent(BusinessTransaction.class) && allowBusinessTransactions)
{
returnUrlUpdated = true;
path = appendBusinessTransaction(targetClass, path);
}
}
}
Hi Miel,
Thanks for writing in. Thanks for detailed analysis and providing the solution for the scenario.
Thanks,
Arun