Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Wednesday, 28 August 2019

Setting up jEnv

With OpenJDK, there is a need to have multiple JDK versions installed as there are many releases that are used by different projects. More and more projects are supporting multiple Java versions as well. This problem was not as prevalent in the Java ecosystem but the Ruby ecosystem had it long back. There are multiple tools to manage Ruby versions. The approach of rbenv is probably the simplest. On the same lines, we have jEnv for Java.

To setup jEnv, the steps are simple

  1. Install jEnv (brew install jenv)
  2. Setup shell profile (~/.bash_profile)
  3. export PATH="$HOME/.jenv/bin:$PATH"
    eval "$(jenv init -)"

  4. Install Java
  5. Set local or shell version of Java (jenv local openjdk64-1.8.0.192)

Thursday, 22 August 2019

Jacoco instrumentation error

In a Java project build, I was getting an error complaining about Jacoco failing to instrument a particular class. Looking at the complete stack trace of the error, it was an exception about index going out of bounds.

Caused by: java.lang.ArrayIndexOutOfBoundsException: 6
at org.jacoco.core.internal.BytecodeVersion.get(BytecodeVersion.java:41)
at org.jacoco.core.instr.Instrumenter.instrument(Instrumenter.java:87)
at org.jacoco.core.instr.Instrumenter.instrument(Instrumenter.java:123)
... 25 more
Fortunately, a little bit of search showed that it is related to Java. My initial version of Java was '1.8.0.121'. The fix was backported to '1.8.0.172'. I also had '1.8.0.192' installed. So, I switched versions and tried a clean build. It worked fine.

Tuesday, 25 September 2018

Hello OSGi

I found existing guides for OSGi to be a bit outdated. So, it is probably better to document the basic setup.

The plan is to first create a consumable bundle, i.e. a service bundle followed by a consumer bundle that uses the former.

I am also using maven for creating the projects so that the maven toolchain can be used for proper packaging.

For the consumable bundle, we start with defining an interface that exposes functionality of the bundle.

package main.java.interfaces;

public interface TestService {
    void hello();
}


We then implement it.

package main.java.impls;



import main.java.interfaces.TestService;



public class TestServiceImpl implements TestService {

    @Override

    public void hello() {

        System.out.println("Hello Duniya");
    }
}

We then add the activation logic for the bundle.

package main.java.provider;

import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceRegistration;

import main.java.interfaces.TestService;
import main.java.impls.TestServiceImpl;

public class ServiceActivator implements BundleActivator {
    private ServiceRegistration registration;

    @Override
    public void start(BundleContext bundleContext) throws Exception {
        registration = bundleContext.registerService(
                TestService.class.getName(),
                new TestServiceImpl(),
                null);
        System.out.println("ServiceActivator started");
    }

    @Override
    public void stop(BundleContext bundleContext) throws Exception {
        registration.unregister();
    }
}



We complete this bundle by adding a POM for building it.




<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>felix_test</groupId>
    <artifactId>felix_test</artifactId>
    <version>1.0</version>
    <packaging>bundle</packaging>

    <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>6.0.0</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>felix_test</Bundle-SymbolicName>
                        <Export-Package>main.java.interfaces</Export-Package>
                        <Bundle-Activator>main.java.provider.ServiceActivator</Bundle-Activator>
                        <Bundle-Vendor>Amitav Mohanty</Bundle-Vendor>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>


The package of interfaces that are to be exposed are called out along with the activator so that the maven toolchain can build our bundle properly.

We move on to create the consumer bundle next. We start with the bundle activator.

package main.java.consumer;

import main.java.interfaces.TestService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;

public class FelixTestActivator implements BundleActivator {
    @Override
    public void start(BundleContext bundleContext) throws Exception {
        ServiceReference reference = bundleContext.getServiceReference(TestService.class.getName());
        consumer = new TestConsumer((TestService)bundleContext.getService(reference));
        consumer.startTimer();
    }

    @Override
    public void stop(BundleContext bundleContext) throws Exception {
        consumer.stopTimer();
    }

    private TestConsumer consumer;
}

We then add the consumer.


package main.java.consumer;

import main.java.interfaces.TestService;

import javax.swing.Timer;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class TestConsumer implements ActionListener {
    @Override
    public void actionPerformed(ActionEvent e) {
        service.hello();
    }

    public TestConsumer(TestService service){
        super();
        this.service = service;
        timer = new Timer(1000, this);
    }

    public void startTimer(){
        timer.start();
    }

    public void stopTimer(){
        timer.stop();
    }

    private final TestService service;
    private final Timer timer;

}


The initiation of the consumer happens when the bundle is started.

The POM for building the consumer bundle is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>consumer</groupId>
    <artifactId>consumer</artifactId>
    <version>1.0</version>
    <packaging>bundle</packaging>

    <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
            <version>6.0.0</version>
        </dependency>

        <dependency>
            <groupId>felix_test</groupId>
            <artifactId>felix_test</artifactId>
            <version>1.0</version>
            <scope>system</scope>
            <systemPath>${basedir}/../target/felix_test-1.0.jar</systemPath>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.0.2</version>
                <configuration>
                    <source>1.6</source>
                    <target>1.6</target>
                </configuration>
            </plugin>

            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <configuration>
                    <instructions>
                        <Bundle-SymbolicName>consumer</Bundle-SymbolicName>
                        <Bundle-Activator>main.java.consumer.FelixTestActivator</Bundle-Activator>
                        <Bundle-Vendor>Amitav Mohanty</Bundle-Vendor>
                    </instructions>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

The dependency on the other bundle is called out.

The "packaging" node in the POMs is essential for creating OSGi bundles.

Monday, 30 October 2017

Manually install maven dependency

Error messages from Maven are often useless. The root cause is mostly never captured. Debugging issues might require manually installing a dependency. The way to do it is as follows:

mvn install:install-file -DgroupId=jnuit -DartifactId=junit -Dversion=3.8.1 -Dpackaging=jar -Dfile=/path/to/file

Thursday, 14 March 2013

Memory snapshot in Jetbrains RubyMine on linux

I use RubyMine on linux for Ruby on Rails development. Of late, it had been hanging up frequently. I reported this to Jetbrains. They got back to me asking me to provide more details so that the concerned developer can try and find more details about the issue. On a side note, their customer support was so fast in responding, I was amazed. Also, the guy responding back was pretty technical himself.

Getting back to the topic, they had asked me to provide a memory snapshot. The process of generating a memory snapshot is described here. However, that process requires users to download YourKit Java Profiler, which apart from being a large download, comes with a 15-day license. To me it did not make sense. So, I got back to them about it and it turns out on linux, you don't really need it. The linux version of RubyMine, comes with the profiler libraries bundled.

$RUBYMINE_HOME/bin/libyjpagent-linux.so
$RUBYMINE_HOME/bin/libyjpagent-linux64.so

To enable its usage all you need to do is, edit the following script and set IS_EAP to "true".

$RUBYMINE_HOME/bin/rubymine.sh

Restarting RubyMine after that change, will show the memory and CPU snapshot icons. It is also advised to provide thread dumps, as described here, along with the memory snapshot.

Wednesday, 26 December 2012

Rails is re-inventing the wheel

In recent years, there has been a surge in web applications. To support the growing market, frameworks have developed around scripting languages for developing web applications fast. Of those Ruby on Rails seems to be the most mature. Django, the most advanced Python framework for web applications is yet to come at par with it.

Be it Django or Ruby on Rails, both follow a model-view-controller architecture to web applications. Now, many web applications using these frameworks follow 'skinny controllers, fat models'. As a result the models become home to a lot of business logic. Models are intended to serve only as an abstraction to the database. They are meant to be 'models of data'. Also, when the application grows huge, we run into issues of scalability and we resort to techniques like sharding. Now, there are of course multiple ways of sharding and you need to decide what suits you better. Here, I list a few ways for Rails applications.
Now, sometimes the sharding logic also creeps into the models. Obviously objects of model classes do not have a single purpose any more. Over time, the model classes obviously become too complicated. It becomes difficult to maintain and debug. The Rails community is becoming increasingly aware of these issues. There are multiple ways in which developers are trying to move business logic away from models. Here I list of couple of those ways.
Looking at the overall scenario reminds me of building N-tier applications using Java Enterprise Edition. The sharding logic and details of data fetching can be a tier below models and the business logic can be a tier above it. ' seems to me developers using web frameworks like Django and Rails are just re-inventing the wheel. Also, Java has optimized garbage collection which can be tuned to various needs. In Ruby garbage collection seems to be a big issue, though good work in the area is coming in the next version.

So much in the name of innovation, eh? In case my ideas seem to waver from reality do point me in the right direction.

Update: You can follow the discussion on Hacker News on the topic.

Thursday, 13 September 2012

JVM crash: an eye opener

I had done some programming but I guess I had not hit many walls. In C, my programs had segfaulted; but every time that happened I knew that my program broke; but there was never a notion of the programming environment breaking down. I, of course, know that when one is coding specifically to break the environment, it is not impossible; but I am talking about cases when the break is not intended. I could never imagine the shell, in which I am running a program for connecting to some website and getting some data, breaking down in between the running of the program.

However, recently I was using Rubymine to test some XML parsers I had written and suddenly it crashed. Initially, I thought may be Rubymine crashed, so I went back to shell where I had started it. To my utter surprise, it was the JVM that had crashed. That is when it hit me that programming environments can also crash. I have reported the bug; but there is not much done from Oracle's side about it.

Well, I do not expect much from them either; but the lesson I learnt is valuable: it is not only the program; but also the program's environment that can crash. Its not that I did not know it but it is not something I regularly expected. From now on, I will though. It did change the way I looked at errors. I guess this is what counts as experience.