3

I am trying to execute apache pulsar producer and consumer program through java, I installed apache-pulsar standalone in GCP virtual machine and started the cluster in standalone mode. Next step is I had given a maven build in windows eclipse and same jar file I uploaded in GCP machine When I am executing producer and consumer program in windows eclipse I am getting connection refused error which is obvious because pulsar is not installed in windows machine. But when I am trying same thing in GCP instance even cluster is already started I am getting error which is related to no class def found error.

pom.xml >>>

<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>pulsar-client-project</groupId>
<artifactId>pulsar-client-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>pulsar-client-project</name>
 <url>http://maven.apache.org</url>

<properties>
<java.version>1.8</java.version>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
  <dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>3.8.1</version>
  <scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.pulsar</groupId>
<artifactId>pulsar-client</artifactId>
<version>2.0.1-incubating</version>
</dependency>
</dependencies>
</project>

ProducerTutorial.java >>>

package pulsar_client_project.pulsar_client_project;


import org.apache.pulsar.client.api.CompressionType;
import org.apache.pulsar.client.api.Message;
import org.apache.pulsar.client.api.MessageBuilder;
import org.apache.pulsar.client.api.MessageId;
import org.apache.pulsar.client.api.Producer;
import org.apache.pulsar.client.api.PulsarClient;
import org.apache.pulsar.client.api.PulsarClientException;
//import org.slf4j.Logger;
//import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.stream.IntStream;

public class ProducerTutorial {
  //    private static final Logger log = 
LoggerFactory.getLogger(ProducerTutorial.class);
private static final String SERVICE_URL = "pulsar://localhost:6650";
private static final String TOPIC_NAME = "my-topic";

public static void main(String[] args) throws IOException {
    System.out.println("inside main");
    // Create a Pulsar client instance. A single instance can be shared across many
    // producers and consumer within the same application
    PulsarClient client = PulsarClient.builder()
            .serviceUrl(SERVICE_URL)
            .build();
    System.out.println("client.."+client);
    // Here you get the chance to configure producer specific settings
    Producer<byte[]> producer = client.newProducer()
            // Set the topic
            .topic(TOPIC_NAME)
            // Enable compression
            .compressionType(CompressionType.LZ4)
            .create();  

    System.out.println("producer.."+producer);
    // Once the producer is created, it can be used for the entire application life-cycle
   // log.info("Created producer for the topic {}", TOPIC_NAME);

    // Send 10 test messages
    IntStream.range(1, 11).forEach(i -> {
        String content = String.format("hello-pulsar-%d", i);

        // Build a message object
        Message<byte[]> msg = MessageBuilder.create()
                .setContent(content.getBytes())
                .build();

        // Send each message and log message content and ID when successfully received
        try {
            MessageId msgId = producer.send(msg);

            //log.info("Published message '{}' with the ID {}", content, msgId);
        } catch (PulsarClientException e) {
            //log.error(e.getMessage());
        }
    });

    client.close();
  }
 }

ConsumerTutorial >>>>

package pulsar_client_project.pulsar_client_project;

import java.io.IOException;

import org.apache.pulsar.client.api.Consumer;
import org.apache.pulsar.client.api.Message;
import org.apache.pulsar.client.api.PulsarClient;
import org.apache.pulsar.client.api.SubscriptionType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ConsumerTutorial {
//private static final Logger log = 
LoggerFactory.getLogger(ConsumerTutorial.class);
private static final String SERVICE_URL = "pulsar://localhost:6650";
private static final String TOPIC_NAME = "my-topic";
private static final String SUBSCRIPTION_NAME = "my-subscription";

public static void main(String[] args) throws IOException {
    // Create a Pulsar client instance. A single instance can be shared 
 across many
    // producers and consumer within the same application
    System.out.println("inside main");
    PulsarClient client = PulsarClient.builder()
            .serviceUrl(SERVICE_URL)
            .build();
    System.out.println("client.."+client);
    // Here you get the chance to configure consumer specific settings. eg:
    Consumer<byte[]> consumer = client.newConsumer()
            .topic(TOPIC_NAME)
            // Allow multiple consumers to attach to the same subscription
            // and get messages dispatched as a queue
            .subscriptionType(SubscriptionType.Shared)
            .subscriptionName(SUBSCRIPTION_NAME)
            .subscribe();

    System.out.println("consumer.."+consumer);
    // Once the consumer is created, it can be used for the entire application lifecycle
    //log.info("Created consumer for the topic {}", TOPIC_NAME);

    do {
        // Wait until a message is available
        Message<byte[]> msg = consumer.receive();

        // Extract the message as a printable string and then log
        String content = new String(msg.getData());
      //  log.info("Received message '{}' with ID {}", content, msg.getMessageId());

        // Acknowledge processing of the message so that it can be deleted
        consumer.acknowledge(msg);
    } while (true);
  }
}

Error_from_GCP_instance

Error_from_windows_eclipse

So, What is the appropriate solution for ubuntu/GCP VM machine. What I have done wrong, Please give me direction

Thanks in advance

Naman
  • 27,789
  • 26
  • 218
  • 353
Bhagesh Arora
  • 547
  • 2
  • 12
  • 30

1 Answers1

4

ClassNotFoundException means that the class is not found in your classpath.

When you run locally from Eclipse the pulsar-client classes are visible to the java process that is being summoned by Eclipse when you press the run button. However when you run the jar on the GCP machine you are not including classes from pulsar-client jar in your classpath and that is why they are missing:

java -cp pulsar-client-project-0.0.1-SNAPSHOT.jar pulsar_client_project.pulsar_client_project.ConsumerTutorial

The above command states that the classpath for the java process are standard JDK classes and the classes from the jar pulsar-client-project-0.0.1-SNAPSHOT and the class to be ran (main-class) is pulsar_client_project.pulsar_client_project.ConsumerTutorial.

What you need to do is provide a copy of pulsar-client jar on the GCP machine and include it in your classpath. E.g.

    java -cp pulsar-client-project-0.0.1-SNAPSHOT.jar:pulsar-client.jar pulsar_client_project.pulsar_client_project.ConsumerTutorial

or

    java -cp pulsar-client-project-0.0.1-SNAPSHOT.jar;pulsar-client.jar pulsar_client_project.pulsar_client_project.ConsumerTutorial

depending on the GCP machine operating system (: is usually path separator on unix like operating systems whereas ; is usually path separator on windows systems). Something similar is being done automatically by your Eclipse when running locally.

The potentially easier way to do that would be to include all project dependencies in the resulting jar file. If you modify your pom like this:

<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>pulsar-client-project</groupId>
<artifactId>pulsar-client-project</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>pulsar-client-project</name>
<url>http://maven.apache.org</url>

<properties>
    <java.version>1.8</java.version>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
</properties>

<dependencies>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-simple</artifactId>
        <version>1.7.25</version>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>3.8.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.pulsar</groupId>
        <artifactId>pulsar-client</artifactId>
        <version>2.0.1-incubating</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <descriptorRefs>
                            <descriptorRef>jar-with-dependencies</descriptorRef>
                        </descriptorRefs>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

Here the assembly plugin is defined which will include all the dependencies in the resulting jar file target/pulsar-client-project-0.0.1-SNAPSHOT-jar-with-dependencies. You can see that its size is ~25 MB whereas the original target/pulsar-client-project-0.0.1-SNAPSHOT.jar is ~5KB. You can also open the jars with any zip capable archiver program (winzip, peazip, unzip...) and inspect their contents since the jar file format is built upon zip file format.

Now, when you copy the bigger jar file to GCP machine you should be able to run it like this:

java -cp pulsar-client-project-0.0.1-SNAPSHOT-jar-with-dependencies.jar pulsar_client_project.pulsar_client_project.ConsumerTutorial

or

    java -cp pulsar-client-project-0.0.1-SNAPSHOT-jar-with-dependencies.jar pulsar_client_project.pulsar_client_project.ProducerTutorial
linski
  • 5,046
  • 3
  • 22
  • 35
  • Still I am getting error >> SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder". SLF4J: Defaulting to no-operation (NOP) logger implementation SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details. Even I added org.slf4j slf4j-log4j12 log4j log4j In my pom.xml file. – Bhagesh Arora Feb 11 '19 at 07:33
  • 1
    Hi @BhageshArora, sorry for late answer: I have added the `org.slf4j:slf4j-simple:1.7.25` (slf4j implementation) to pom.xml, just replace the entire contents of your pom.xml with the entire contents of above pom.xml. The app was working even without that but the logging was not configured - meaning you would see no log outputs on your console. The reason for that is that pulsar-client has only `org.slf4j:slf4j-api:jar:1.7.25:compile` which is slf4j interface - and it needs the implementation of that interface in order to work. See [SLF4J](https://www.slf4j.org/index.html) for more info. – linski Feb 14 '19 at 19:20
  • 1
    You can see all the dependencies of your project by running `mvn dependency:tree -Dverbose` from the root folder of your project - the one where pom.xml is. – linski Feb 14 '19 at 19:22
  • 1
    The artifact you tried to exclude `org.slf4j:slf4j-log4j12` is not referenced by any dependency in your project so that had no effect. – linski Feb 14 '19 at 19:24