Archive

Posts Tagged ‘hybris’
  • Using Kotlin on the SAP Hybris platform

    SAP Hybris logo

    Since I discovered Kotlin, I use it in all my personal projects. I’ve become quite fond of the language, and with good reason. However, there’s yet no integration with the Hybris platform - though there’s with Groovy and Scala. This post aims at achieving just that, to be able to use Kotlin on Hybris projects.

    Generate a new extension

    The first step on the journey is to create a new extension:

    ant extgen
    1. Choose the yempty package
    2. Choose an adequate name, e.g. "kotlinfun"
    3. Choose a root package, e.g. ch.frankel.blog.kotlin
    Don’t forget to add this new extension to the localextensions.xml file.

    Add libraries

    Kotlin requires libraries, both to compile and to run. They include:

    • kotlin-ant.jar
    • kotlin-compiler.jar
    • kotlin-preloader.jar
    • kotlin-reflect.jar
    • kotlin-script-runtime.jar

    Though it would be nice to use external-dependencies.xml, some JAR are not available as Maven dependencies (e.g. kotlin-ant.jar). Thus, it’s required to manually get the relevant Kotlin compiler and unpack it.

    Create folders

    To help with the build, let’s create dedicated folders for sources and tests, respectively kotlinsrc and kotlintestsrc. Configure the module or the project accordingly - depending whether your IDE of choice is IntelliJ IDEA or Eclipse.

    On the Hybris platform, both sources and tests will compile in the same folder.

    Create simple Kotlin files in kotlinsrc and kotlintestsrc.

    Configure Kotlin in IDE

    While at it, configure Kotlin for the IDE. IntelliJ IDEA will pop-up an alert box to do so if a Kotlin file is created anyway. I have no clue about Eclipse…​

    The fun part

    Now that compiling works inside of the IDE, it should also be part of the standard command-line build. Fortunately, there are build hooks into the Hybris build pipeline. Those are configured inside the build_callbacks.xml file.

    A naive first draft would look like:

    <project name="kotlinfun_buildcallbacks">
    
        <property name="kotlin.lib.dir" location="${ext.kotlinfun.path}/lib"/>
    
        <taskdef resource="org/jetbrains/kotlin/ant/antlib.xml">
            <classpath>
                <pathelement location="${kotlin.lib.dir}/kotlin-ant.jar"/>
                <pathelement location="${kotlin.lib.dir}/kotlin-compiler.jar"/>
                <pathelement location="${kotlin.lib.dir}/kotlin-preloader.jar"/>
                <pathelement location="${kotlin.lib.dir}/kotlin-reflect.jar"/>
                <pathelement location="${kotlin.lib.dir}/kotlin-script-runtime.jar"/>
            </classpath>
        </taskdef>
    
        <macrodef name="kotlin_compile">
            <attribute name="srcdir"/>
            <attribute name="destdir"/>
            <attribute name="extname"/>
    
            <sequential>
                <echo message="compile kotlin sources for @{extname} using srcdir: @{srcdir}"/>
                <mkdir dir="@{destdir}"/>
                <kotlinc src="@{srcdir}" output="@{destdir}">
                    <classpath>
                        <pathelement location="${kotlin.lib.dir}/kotlin-stdlib.jar"/>
                        <fileset dir="${[email protected]{extname}.path}" erroronmissingdir="false">
                            <include name="${[email protected]{extname}.additional.src.dir}/**"/>
                            <include name="${[email protected]{extname}.additional.testsrc.dir}/**"/>
                        </fileset>
                        <pathelement path="${build.classpath}"/>
                        <pathelement path="${platformhome}/bootstrap/bin/models.jar" />
                        <fileset dir="${bundled.tomcat.home}">
                            <include name="lib/jsp-api.jar"/>
                            <include name="lib/servlet-api.jar"/>
                            <include name="lib/el-api.jar"/>
                            <include name="lib/wrapper*.jar"/>
                        </fileset>
                        <pathelement path="${[email protected]{extname}.classpath}" />
                    </classpath>
                </kotlinc>
            </sequential>
        </macrodef>
    
        <macrodef name="kotlinfun_compile_core">
            <attribute name="extname"/>
            <sequential>
                <if>
                    <isset property="[email protected]{extname}.coremodule.available"/>
                    <then>
                        <if>
                            <istrue value="${[email protected]{extname}.extension.coremodule.sourceavailable}"/>
                            <then>
                                <kotlin_compile srcdir="${[email protected]{extname}.path}/kotlinsrc"
                                               destdir="${[email protected]{extname}.path}/classes"
                                               extname="@{extname}"/>
                                <kotlin_compile srcdir="${[email protected]{extname}.path}/kotlintestsrc"
                                               destdir="${[email protected]{extname}.path}/classes"
                                               extname="@{extname}"/>
                            </then>
                        </if>
                    </then>
                </if>
            </sequential>
        </macrodef>
    
        <macrodef name="kotlinfun_after_compile_core">
            <sequential>
                <kotlinfun_compile_core extname="kotlinfun"/>
            </sequential>
        </macrodef>
    </project>

    The above is configured for a simple core module, not a web one. It can be added afterwards though.

    Unfortunately, this doesn’t work. Launching the build with ant build will produce the following output:

    /hybris/bin/platform/resources/ant/compiling.xml:530: java.lang.NoSuchMethodError:
     com.google.common.collect.Iterables.filter(Ljava/lang/Iterable;Lcom/google/common/base/Predicate;)Ljava/lang/Iterable;

    Looking more closely at the kotlin-compiler.jar, one must notice it embeds Guava, which also happens to be on the hybris classpath. Hence, there’s a version conflict. Fortunately, there’s a smarter version of the compiler - kotlin-compiler-embeddedable.jar available on repo1 that shades Guava i.e. embeds it using a different package name, thus resolving the conflict. Just update the callback file with the new JAR name, and be done.

    Now, the build produces a different output:

    /hybris/bin/custom/kotlinfun/buildcallbacks.xml:34: java.lang.IllegalStateException:
     File is not found in the directory of Kotlin Ant task: kotlin-compiler.jar

    For reasons unknown, the Ant task checks the existence of dependent libraries using their file names! Check the source code for proof. There’s an evil workaround: rename the JAR as it’s expected. And update the build file back to the initial version…​

    At this point, it’s possible to build the platform with Kotlin files compiled.

    Improvements

    Though it works, there are a couple of possible improvements:

    • Change the lib folder to a dedicated folder e.g. compile , so as not to ship it in the distributed archive
    • Add the configuration to also compile a web module
    • Refactor the macros into a common extension, so that different Kotlin extensions can use it.

    In the end, nothing prevents you from using Kotlin on SAP hybris right now!

    Categories: Development Tags: Kotlinhybris
  • The middle path approach

    hybris software, the future of commerce

    I’ve been doing software development for most of my career, so that I think myself as a software developer (or software architect), even though I’ve dabbled in solutions engineering more than once. This surely has an effect on how I see the architecture landscape, but I’ll try to be as objective as possible.

    Historically, there have been two approaches in providing software solutions to business requirements:

    • Either create custom software to address the requirements
    • Or purchase an out-of-the-box solution to do the same

    My software developer side was formerly more in favor of the first option. I thought that this way provided more flexibility than an editor package. During my professional life, I’ve come to realize that management sits on the opposite side, viewing out-of-the-box packages as less risky and less expensive. Even if I agree to the risk point, there are numerous cons to purchase such a solution:

    1. All projects I encoutered only planned for license costs. However, users generally ask for numerous adaptations that require a long configuration
    2. Some, if not most, of those adaptations require more than configuration, but hacking the product itself, which costs even more
    3. Changing the product has a great influence on the maintenance costs, especially toward upgrading: you’ll have to patch the code in the newer version, provided it is compatible
    4. Cutting on the adaptation side will also have an effect on the business side and will require a stronger change management planning
    5. Most products used are provided by (really) big companies: you’ll need to also purchase the associated infrastructure in order to benefit from full editor support (believe, I’ve tried going the other way to my chagrin)

    Preaching that out-of-the-box solutions are thus cost-effective is the biggest lie of all!

    So basically, it’s either take the risky development road or the costly/coupled product one. Shouldn’t there be an alternative path, that could address these issues?

    Since the beginning of the year, I’m working for a company that I think provide such an alternative. It comes in the form of a product whose features include:

    • a basic platform developed with Java & Spring and providing a plugin architecture
    • an extensible business model
    • a service layer, designed around an interface and an out-of-the-box implementation. Implementations can be replaced through a developed plugin
    • a templated web layer, based on Spring MVC that can be modified as needed

    IMHO, this is the best alternative I’ve ever seen. This way, you can get the whole shebang in production very quickly, adapt the system to your specific needs (either before production or by incremental steps) and still be able to upgrade easily with each version. Software companies should probably invest in migrating their products to this kind of architecture.

    The company is hybris, and I’m very happy to have joined their ranks since the start of this year.

    Categories: Technical Tags: commercehybrissolution