GitHub user i7pacheco edited a discussion: PLC4X Kafka Connect 0.12.0 – NoClassDefFoundError for PlcDriverManager in Docker
Hello everyone, I’m integrating PLC4X with Kafka Connect (version 0.12.0, I've tried 0.8.0 and 0.10.0 too) inside a Docker container to collect data from an S7 PLC. I’m running into persistent issues with plugin dependencies and classpath resolution, and would appreciate guidance from the community. ### **Environment** - **Kafka Connect:** 3.6.x (Confluent Platform, Dockerized) - **PLC4X Kafka Connector:** 0.12.0 - **Docker**: Custom image, plugins in `/usr/share/java/plc4x/` - **OS:** Linux (containerized) - **Goal:** Connect to S7 PLC and publish data to a Kafka topic ### **What I’ve Done** - Placed all PLC4X JARs (including `plc4j-apache-kafka-0.12.0.jar`, `plc4j-api-0.12.0.jar`, `plc4j-spi-0.12.0.jar`, `plc4j-driver-s7-0.12.0.jar`, and other dependencies) in `/usr/share/java/plc4x/`. - Set `plugin.path` to include `/usr/share/java/`. - Verified that `org.apache.plc4x.kafka.Plc4xSourceConnector` appears in the `/connector-plugins/` REST API output. - Used the advanced connector configuration format. ### **Problem** When I POST the connector config, I get a 500 error and the logs show: ``` Caused by: java.lang.NoClassDefFoundError: org/apache/plc4x/java/PlcDriverManager at org.apache.plc4x.kafka.config.Source.validate(Source.java:76) ... Caused by: java.lang.ClassNotFoundException: org.apache.plc4x.java.PlcDriverManager at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:476) ... ``` I also tried running `jdeps -summary plc4j-apache-kafka-0.12.0.jar` in the container and saw: ``` plc4j-apache-kafka-0.12.0.jar -> java.base plc4j-apache-kafka-0.12.0.jar -> not found ``` ### **What I’ve Checked** - All JARs are present in `/usr/share/java/plc4x/` (listing below). - No duplicate or mismatched versions. - Restarted Kafka Connect after every change. - The connector config uses the advanced format and references the correct classes. ### **Questions** 1. **What could cause NoClassDefFoundError for `PlcDriverManager` even when `plc4j-api-0.12.0.jar` is present?** 2. **Are there any known issues with PLC4X classloading in Dockerized Kafka Connect?** 3. **Is there a definitive list of all dependencies (including transitive ones) for the PLC4X Kafka connector 0.12.0?** 4. **Are there best practices for structuring the plugin path or for troubleshooting classpath issues in this scenario?** 5. **Any tips for debugging further or confirming exactly which JAR is missing or not being loaded?** ### **Directory Listing** Here’s what’s in `/usr/share/java/plc4x/`: ``` plc4j-apache-kafka-0.12.0.jar plc4j-api-0.12.0.jar plc4j-spi-0.12.0.jar plc4j-driver-s7-0.12.0.jar commons-codec-*.jar commons-lang3-*.jar jackson-*.jar bcprov-*.jar bcpkix-*.jar bcutil-*.jar ... ``` ### **Connector Config (Snippet)** ```json { "name": "plc4x-source", "config": { "connector.class": "org.apache.plc4x.kafka.Plc4xSourceConnector", "tasks.max": "1", "default-topic": "sensor_data", "sources": "plc1", "sources.plc1.connectionString": "s7://192.168.1.100/0/1", "sources.plc1.jobReferences": "jobA", "sources.plc1.jobReferences.jobA": "sensor_data", "jobs": "jobA", "jobs.jobA.interval": "1000", "jobs.jobA.fields": "tag1,tag2", "jobs.jobA.fields.tag1": "%DB501.DBD1:REAL", "jobs.jobA.fields.tag2": "%DB501.DBD5:REAL" } } ``` The **docker compose file** is: ```yml services: zookeeper: image: confluentinc/cp-zookeeper:7.6.0 container_name: zookeeper environment: ZOOKEEPER_CLIENT_PORT: 2181 ZOOKEEPER_TICK_TIME: 2000 ports: - "2181:2181" kafka: image: confluentinc/cp-kafka:7.6.0 container_name: kafka depends_on: - zookeeper ports: - "9092:9092" - "9093:9093" environment: KAFKA_BROKER_ID: 1 KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181 KAFKA_LISTENERS: PLAINTEXT://0.0.0.0:9092,PLAINTEXT_HOST://0.0.0.0:9093 KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:9093 KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT KAFKA_AUTO_CREATE_TOPICS_ENABLE: "true" KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 volumes: - ./kafka_data:/var/lib/kafka/data kafka-connect: image: confluentinc/cp-kafka-connect:7.6.0 container_name: kafka-connect depends_on: - kafka environment: CONNECT_BOOTSTRAP_SERVERS: kafka:9092 CONNECT_GROUP_ID: connect-cluster CONNECT_CONFIG_STORAGE_TOPIC: connect-configs CONNECT_OFFSET_STORAGE_TOPIC: connect-offsets CONNECT_STATUS_STORAGE_TOPIC: connect-status CONNECT_KEY_CONVERTER: org.apache.kafka.connect.json.JsonConverter CONNECT_VALUE_CONVERTER: org.apache.kafka.connect.json.JsonConverter CONNECT_PLUGIN_PATH: "/usr/share/java,/usr/share/confluent-hub-components,/usr/share/java/plc4x" CONNECT_REST_ADVERTISED_HOST_NAME: kafka-connect # Only working with a single node CONNECT_OFFSET_STORAGE_REPLICATION_FACTOR: 1 CONNECT_CONFIG_STORAGE_REPLICATION_FACTOR: 1 CONNECT_STATUS_STORAGE_REPLICATION_FACTOR: 1 ports: - "8083:8083" volumes: - ./plugins:/plugins - ./timescale-sink.json:/data/timescale-sink.json ``` I prepared some series of bat files that help me set up the connectors: **Installing the PLC4X plugin:** ```bash @echo off REM === CONFIGURATION === set "PLC4X_VERSION=0.12.0" set "CONNECT_CONTAINER=kafka-connect" REM === Step 1: Download the PLC4X Kafka Connect standalone ZIP === echo Downloading PLC4X Kafka Connect standalone ZIP... curl -L -o plc4x-kafka.zip https://repo1.maven.org/maven2/org/apache/plc4x/plc4j-apache-kafka/%PLC4X_VERSION%/plc4j-apache-kafka-%PLC4X_VERSION%-standalone.zip REM === Step 2: Extract the ZIP using PowerShell === echo Extracting PLC4X connector files... powershell -Command "Expand-Archive -Path 'plc4x-kafka.zip' -DestinationPath 'plc4x-kafka' -Force" REM === Step 3: Copy the connector JAR(s) into the Kafka Connect container === echo Copying connector JARs into the container... docker exec %CONNECT_CONTAINER% mkdir -p /usr/share/java/plc4x @REM for %%f in (plc4x-kafka\*.jar) do docker cp %%f %CONNECT_CONTAINER%:/usr/share/java/plc4x/ @REM for /r plc4x-kafka %%f in (*.jar) do docker cp "%%f" %CONNECT_CONTAINER%:/usr/share/java/ for /r plc4x-kafka %%f in (*.jar) do ( echo Copying "%%f" to %CONNECT_CONTAINER%:/usr/share/java/plc4x/ docker cp "%%f" %CONNECT_CONTAINER%:/usr/share/java/plc4x/ if errorlevel 1 echo ERROR copying "%%f" ) REM === Step 4: Restart the Kafka Connect container === echo Restarting Kafka Connect container... docker restart %CONNECT_CONTAINER% REM === Step 5: Wait for Kafka Connect to restart (adjust time if needed) === echo Waiting for Kafka Connect to restart... timeout /t 30 REM === Step 6: Verify the connector is available === echo Checking available connector plugins: docker exec %CONNECT_CONTAINER% curl http://localhost:8083/connector-plugins REM === Step 7: Clean up temporary files === echo Cleaning up... rmdir /s /q plc4x-kafka del plc4x-kafka.zip echo. echo Done! If you see 'org.apache.plc4x.kafka.Plc4xSourceConnector' above, installation succeeded. pause ``` **Registering the plugin:** ```bash @echo off REM === CONFIGURATION === set "PLC4X_VERSION=0.12.0" set "CONNECT_CONTAINER=kafka-connect" echo Registering PLC4X connector... @REM docker cp plc4x-s7-source.json kafka-connect:/data/ @REM docker exec kafka-connect curl -X POST -H "Content-Type: application/json" --data @/data/plc4x-s7-source.json http://localhost:8083/connectors docker cp plc4x-s7-source.json %CONNECT_CONTAINER%:/tmp/plc4x-s7-source.json docker exec %CONNECT_CONTAINER% curl -X POST -H "Content-Type: application/json" --data @/tmp/plc4x-s7-source.json http://localhost:8083/connectors echo Registered connectors: docker exec %CONNECT_CONTAINER% curl -s http://localhost:8083/connectors ``` **Updating the plugin:** ```bash @echo off REM === CONFIGURATION === set "CONNECT_CONTAINER=kafka-connect" set "CONNECTOR_NAME=plc4x-source" set "CONFIGURATION_FILENAME=plc4x-s7-source" set "FULL_JSON=%CONFIGURATION_FILENAME%.json" set "CONFIG_ONLY_JSON=%CONFIGURATION_FILENAME%-config-only.json" REM === Extract only the config object using PowerShell === echo Extracting config section from %FULL_JSON%... powershell -Command "Get-Content %FULL_JSON% | ConvertFrom-Json | Select-Object -ExpandProperty config | ConvertTo-Json | Set-Content %CONFIG_ONLY_JSON%" REM === Copy the config-only JSON to the container === echo Copying config-only JSON to container... docker cp %CONFIG_ONLY_JSON% %CONNECT_CONTAINER%:/tmp/%CONFIG_ONLY_JSON% REM === Update the connector using PUT === echo Updating PLC4X connector... docker exec %CONNECT_CONTAINER% curl -X PUT -H "Content-Type: application/json" --data @/tmp/%CONFIG_ONLY_JSON% http://localhost:8083/connectors/%CONNECTOR_NAME%/config REM === Show registered connectors === echo Registered connectors: docker exec %CONNECT_CONTAINER% curl -s http://localhost:8083/connectors REM === Show connector configuration === echo Current configuration of %CONNECTOR_NAME%: docker exec %CONNECT_CONTAINER% curl -s http://localhost:8083/connectors/%CONNECTOR_NAME%/config REM === Optional: Clean up temp file === del %CONFIG_ONLY_JSON% ``` ### **Any help or troubleshooting suggestions would be greatly appreciated!** Thanks in advance. GitHub link: https://github.com/apache/plc4x/discussions/2164 ---- This is an automatically sent email for dev@plc4x.apache.org. To unsubscribe, please send an email to: dev-unsubscr...@plc4x.apache.org