eCommerce with Hybris: Debugging Hybris with Beanshell from Eclipse IDE

Overview

BeanShell is a Java-like dynamically typed language that allows to execute scripts in a running Java environment. You can use it to enhance the functionality of your application or to test and debug snippets of code without the lengthy compile and re-deploy cycles.

In this article, after a brief illustration of the Beanshell’s role in Hybris, I will guide you step-by-step how to execute Beanshell scripts against live Hybris instance from Eclipse IDE. Out-of-the-box Hybris confines your interaction with BeanShell to the web-based Hybris Administration Console.

Disclaimer. The article contains links to Hybris Wiki that open only for registered Hybris users.

Beanshell in Hybris

Hybris platform incorporates BeanShell since its release 4. The Import/Export functionality is one example of BeanShell extension: you can place Java code inside an IMPEX file to be interpreted and executed during processing of IMPEX code lines (see link for more information). Another example is  Dynamic Constraints, part of Hybris validation framework. Dynamic Constraints support validation rules that do not need to be compiled: you write the body for the Dynamic Constraints in BeanShell.

You can experiment with BeanShell using Hybris Administration Console, BeanShell tab. For example: create some Hybris object, persist it and feed it to the service method. The screenshot  below presents the console with the sample code that outputs catalog versions. If you start the server in the debug mode you can have a full-blown remote debugging session of this code:

BeanShell Web Console

BeanShell Web Console

You may ask how the BeanShell console might be better than Integration Test or a Standalone class with  main method?

The main difference is that BeanShell is executed in the live environment. An arbitrary code snippet containing any of the API of the deployed extensions can be immediately executed as if it’s a simple Hello World program. With Integration Test or Standalone main function routes you need to wait for the reloading of the Spring Application Context of the hybris platform and all extensions. This gets very time consuming: you wait about a minute for each try!

Now you can see the real benefit of using BeanShell, but on the other hand it’s not easy to write code snippets using just the Web interface in Hybris administration console as there is no auto-completion and auto-type detection. For developers who are spoiled by the top-notch IDEs like Eclipse it might be a serious obstacle for using BeanShell.

In the next section I’ll show you a simple solution how to run BeanShell scripts from Eclipse environment.

Running BeanShell scripts from Eclipse

The below solution must be used only in local development environments.The following steps must be completed before you can run Hybris BeanShell scripts from Eclipse IDE:

  1. Create a new project in Eclipse workspace with the Hybris platform.

  2. Add to the project dependency the Hybris platform files and extensions you are working with (Project Properties -> Java Build Path -> Projects -> Add).

  3. Download the attached BeanshellMain.java class: BeanshellMain.java.
    This file contains the code that performs HTTP Post request to the remote endpoint associated with the BeanShell interpreter. The body of the request is composed from import declarations used in BeanshellMain.java and a piece of code between BEANSHELL_SCRIPT_START and BEANSHELL_SCRIPT_END placeholders.

    It’s important to understand that Beanshell syntax is not exactly the same as Java. For example don’t be surprised by the fact that it misses generics. After all it’s not statically typed. That’s why in BeanshellMain.java you can find a piece of code responsible for removing generic types and final modifiers.

  4. Copy the BeanshellMain file to the root of the source folder: src/BeanshellMain.java(don’t create any packages).

  5. In Hybris development environment disable security for beanshell url
    by adding next line:

     <http pattern="/console/**" security="none" />

    to the ${HYBRIS_PLATFORM}/ext/hac/web/webroot/WEB-INF/config/spring-security-config.xml
    It’s necessary step to bypass authentication and authorization.

    IMPORTANT: Do this step only on local development environment.

  6. Launch hybris server. Make sure that Hybris BeanShell is available on http://localhost:9001/console/beanshell without authentication.

  7. Execute code from BeanshellMain#main() in the runtime environment by running BeanshellMain in eclipse(Ctrl-F11 by default). All system.out.println statements from BeanshellMain#main() will be shown in the Eclipse console immediately, because code passed to dynamic BeanShell environment, and there is no need to reload Spring Application Context. In this example we just output all catalog versions available in the system.

Now you know how to run a specific piece of code code defined in BeanshellMain#main() on  running hybris platform. On each run the src/BeanshellMain.bsh file is created – it  contains the actual code that was posted to the server. You can copy it for later use.

For example you can post bsh script directly to a remote url with curl:

curl -X POST --data-urlencode script@BeanshellMain.bsh http://localhost:9001/console/beanshell/execute

Optional: See the utility bash script that posts bsh files to remote endpoint and returns formatted output hybris_bsh

The Usage Sample

Let’s consider an example where you might find it helpful to use BeanShell. Imagine the situation when you were assigned a bug related to the order price calculation. You know that logic related to price calculation is hidden in DefaultCalculationService#recalculate(AbstractOrderModel). All you really have to do to find out the cause of the problem is to carefully go through all steps of the price and tax calculation in the debug mode. With BeanShell you can do it this way:

a) Open DefaultCalculationService.java in eclipse and place a debug breakpoint in DefaultCalculationService#recalculate method. Make sure that the remote debug is appropriately launched.

b) find out PK of the order you are interested in and add next code to the BeanshellMain#main() function:

long orderPk =  //TODO: add order PK here
ModelService modelService = (ModelService) Registry.getApplicationContext().getBean("modelService");
OrderModel order = modelService.get(PK.fromLong(orderPk));
CalculationService calculationService = (CalculationService) Registry.getApplicationContext().getBean("calculationService");
if (order == null) {
    System.out.println("Order is not found");
} else {
    order.setCalculated(Boolean.FALSE); // enable recalculation
    calculationService.calculate(order);
    System.out.println("Total price: " + order.getTotalPrice());
}

c) Launch the BeanshellMain as Java application. Eclipse will stop in  the DefaultCalculationService#recalculate function. Now you can investigate the executed code for specified order by going through each line in debug mode.

Conclusion

Executing BeanShell scripts from Eclipse environment on the running Hybris instance is one of the tricks I use in my daily work with Hybris. I hope scripting languages like BeanShell will make you more productive by minimizing the number of rebuild/redeploy cycles during your work day. If you would like to use something more powerful for scripting, consider groovy web console that comes with Hybris and pursues the same goal as BeanShell.

References

http://en.wikipedia.org/wiki/BeanShell
http://www.beanshell.org/intro.html
https://wiki.hybris.com/display/release5/ImpEx+API#ImpExAPI-BeanShell
https://wiki.hybris.com/display/release5/Data+Validation+Framework#DataValidationFramework-CreatingDynamicConstraints
https://wiki.hybris.com/display/partnerblog/2012/03/05/The+Groovy+Web+Console