Null Pointer Exception in YouTube Analytics API Using Java IntelliJ IDEA ?
Could Please Give an any Suggestion ?
Throwable: null
java.lang.NullPointerException
at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkNotNull(Preconditions.java:191)
at com.google.api.client.util.Preconditions.checkNotNull(Preconditions.java:127)
at com.google.api.client.json.jackson2.JacksonFactory.createJsonParser(JacksonFactory.java:96)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:85)
at com.google.api.client.json.JsonObjectParser.parseAndClose(JsonObjectParser.java:81)
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:88)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
at com.google.api.client.auth.oauth2.Credential.executeRefreshToken(Credential.java:570)
at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:859)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)
at com.google.api.services.samples.youtube.cmdline.analytics.YouTubeAnalyticsReports.main(YouTubeAnalyticsReports.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:134)
This is 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>com.google.api.services.samples.youtube.cmdline</groupId>
<artifactId>samples</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>youtube-api-cmdline-samples</name>
<url>http://maven.apache.org</url>
<properties>
<project.youtube.version>v3-rev107-1.18.0-rc</project.youtube.version>
<project.youtube.analytics.version>v1-rev24-1.17.0-rc</project.youtube.analytics.version>
<project.http.version>1.18.0-rc</project.http.version>
<project.oauth.version>1.18.0-rc</project.oauth.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<repositories>
<repository>
<id>google-api-services</id>
<url>http://google-api-client-libraries.appspot.com/mavenrepo</url>
</repository>
</repositories>
<dependencies>
<!-- YouTube Data V3 support -->
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-youtube</artifactId>
<version>${project.youtube.version}</version>
</dependency>
<!-- Required for any code that makes calls to the Google Analytics API -->
<dependency>
<groupId>com.google.apis</groupId>
<artifactId>google-api-services-youtubeAnalytics</artifactId>
<version>${project.youtube.analytics.version}</version>
</dependency>
<!-- This dependency is only used for the Topics API sample, which requires the Jackson JSON parser -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>com.google.http-client</groupId>
<artifactId>google-http-client-jackson2</artifactId>
<version>${project.http.version}</version>
</dependency>
<dependency>
<groupId>com.google.oauth-client</groupId>
<artifactId>google-oauth-client-jetty</artifactId>
<version>${project.oauth.version}</version>
</dependency>
<dependency>
<groupId>com.google.collections</groupId>
<artifactId>google-collections</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- Forces Maven to use Java 1.6 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgument></compilerArgument>
</configuration>
</plugin>
</plugins>
</build>
i need Report Generation for You Tube Videos using YouTube Analytics API in Java IntelliJ IDEA?
How to Fix the Exception could u please any one help u it Will helpful for me.
Report.java
package com.google.api.services.samples.youtube.cmdline.analytics;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.samples.youtube.cmdline.Auth;
import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.Channel;
import com.google.api.services.youtube.model.ChannelListResponse;
import com.google.api.services.youtubeAnalytics.YouTubeAnalytics;
import com.google.api.services.youtubeAnalytics.model.ResultTable;
import com.google.api.services.youtubeAnalytics.model.ResultTable.ColumnHeaders;
import com.google.common.collect.Lists;
import java.io.IOException;
import java.io.PrintStream;
import java.math.BigDecimal;
import java.util.List;
public class YouTubeAnalyticsReports {
/**
* Define a global instance of the HTTP transport.
*/
private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
/**
* Define a global instance of the JSON factory.
*/
private static final JsonFactory JSON_FACTORY = new JacksonFactory();
/**
* Define a global instance of a Youtube object, which will be used
* to make YouTube Data API requests.
*/
private static YouTube youtube;
/**
* Define a global instance of a YoutubeAnalytics object, which will be
* used to make YouTube Analytics API requests.
*/
private static YouTubeAnalytics analytics;
/**
* This code authorizes the user, uses the YouTube Data API to retrieve
* information about the user's YouTube channel, and then fetches and
* prints statistics for the user's channel using the YouTube Analytics API.
*
* #param args command line args (not used).
*/
public static void main(String[] args) {
// These scopes are required to access information about the
// authenticated user's YouTube channel as well as Analytics
// data for that channel.
List<String> scopes = Lists.newArrayList(
"https://www.googleapis.com/auth/yt-analytics.readonly",
"https://www.googleapis.com/auth/youtube.readonly"
);
try {
// Authorize the request.
Credential credential = Auth.authorize(scopes, "analyticsreports");
// This object is used to make YouTube Data API requests.
youtube = new YouTube.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("youtube-analytics-api-report-example")
.build();
// This object is used to make YouTube Analytics API requests.
analytics = new YouTubeAnalytics.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
.setApplicationName("youtube-analytics-api-report-example")
.build();
// Construct a request to retrieve the current user's channel ID.
YouTube.Channels.List channelRequest = youtube.channels().list("id,snippet");
channelRequest.setMine(true);
channelRequest.setFields("items(id,snippet/title)");
ChannelListResponse channels = channelRequest.execute();
// List channels associated with the user.
List<Channel> listOfChannels = channels.getItems();
// The user's default channel is the first item in the list.
Channel defaultChannel = listOfChannels.get(0);
String channelId = defaultChannel.getId();
PrintStream writer = System.out;
if (channelId == null) {
writer.println("No channel found.");
} else {
writer.println("Default Channel: " + defaultChannel.getSnippet().getTitle() +
" ( " + channelId + " )\n");
printData(writer, "Views Over Time.", executeViewsOverTimeQuery(analytics, channelId));
printData(writer, "Top Videos", executeTopVideosQuery(analytics, channelId));
printData(writer, "Demographics", executeDemographicsQuery(analytics, channelId));
}
} catch (IOException e) {
System.err.println("IOException: " + e.getMessage());
e.printStackTrace();
} catch (Throwable t) {
System.err.println("Throwable: " + t.getMessage());
t.printStackTrace();
}
}
/**
* Retrieve the views and unique viewers per day for the channel.
*
* #param analytics The service object used to access the Analytics API.
* #param id The channel ID from which to retrieve data.
* #return The API response.
* #throws IOException if an API error occurred.
*/
private static ResultTable executeViewsOverTimeQuery(YouTubeAnalytics analytics,
String id) throws IOException {
return analytics.reports()
.query("channel==" + id, // channel id
"2012-01-01", // Start date.
"2012-01-14", // End date.
"views,uniques") // Metrics.
.setDimensions("day")
.setSort("day")
.execute();
}
/**
* Retrieve the channel's 10 most viewed videos in descending order.
*
* #param analytics the analytics service object used to access the API.
* #param id the string id from which to retrieve data.
* #return the response from the API.
* #throws IOException if an API error occurred.
*/
private static ResultTable executeTopVideosQuery(YouTubeAnalytics analytics,
String id) throws IOException {
return analytics.reports()
.query("channel==" + id, // channel id
"2012-01-01", // Start date.
"2012-08-14", // End date.
"views,subscribersGained,subscribersLost") // Metrics.
.setDimensions("video")
.setSort("-views")
.setMaxResults(10)
.execute();
}
/**
* Retrieve the demographics report for the channel.
*
* #param analytics the analytics service object used to access the API.
* #param id the string id from which to retrieve data.
* #return the response from the API.
* #throws IOException if an API error occurred.
*/
private static ResultTable executeDemographicsQuery(YouTubeAnalytics analytics,
String id) throws IOException {
return analytics.reports()
.query("channel==" + id, // channel id
"2007-01-01", // Start date.
"2012-08-14", // End date.
"viewerPercentage") // Metrics.
.setDimensions("ageGroup,gender")
.setSort("-viewerPercentage")
.execute();
}
/**
* Prints the API response. The channel name is printed along with
* each column name and all the data in the rows.
*
* #param writer stream to output to
* #param title title of the report
* #param results data returned from the API.
*/
private static void printData(PrintStream writer, String title, ResultTable results) {
writer.println("Report: " + title);
if (results.getRows() == null || results.getRows().isEmpty()) {
writer.println("No results Found.");
} else {
// Print column headers.
for (ColumnHeaders header : results.getColumnHeaders()) {
writer.printf("%30s", header.getName());
}
writer.println();
// Print actual data.
for (List<Object> row : results.getRows()) {
for (int colNum = 0; colNum < results.getColumnHeaders().size(); colNum++) {
ColumnHeaders header = results.getColumnHeaders().get(colNum);
Object column = row.get(colNum);
if ("INTEGER".equals(header.getUnknownKeys().get("dataType"))) {
long l = ((BigDecimal) column).longValue();
writer.printf("%30d", l);
} else if ("FLOAT".equals(header.getUnknownKeys().get("dataType"))) {
writer.printf("%30f", column);
} else if ("STRING".equals(header.getUnknownKeys().get("dataType"))) {
writer.printf("%30s", column);
} else {
// default output.
writer.printf("%30s", column);
}
}
writer.println();
}
writer.println();
}
}
<repositories>
<repository>
<id>google-api-services</id>
<url>http://mavenrepo.google-api-java-client.googlecode.com/hg</url>
</repository>
<repository>
<id>google-api-services</id>
<url>http://google-api-client-libraries.appspot.com/mavenrepo</url>
</repository>
</repositories>
You have defined two repositories with the same ID, delete one of them or change its ID.
Related
i'm trying to integrate the google login function on my website and i'm following the relative google doc for the server side token validation: https://developers.google.com/identity/gsi/web/guides/verify-google-id-token?hl=en .
i've created a simple test app with the GoogleIdTokenVerifier declaration but i'm getting the error:
java.lang.NoClassDefFoundError: com/google/api/client/json/JsonFactory
what am I doing wrong?
Thanks.
this is the test app with the GoogleIdTokenVerifier declaration:
package test;
import java.util.Collections;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
public class Main {
public static void main(String[] args) {
try {
HttpTransport transport = new NetHttpTransport();
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, new GsonFactory())
// Specify the CLIENT_ID of the app that accesses the backend:
.setAudience(Collections.singletonList("xxx.apps.googleusercontent.com"))
// Or, if multiple clients access the backend:
//.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
.build();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
and this is the pom.xml i used for the dependencies:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<dependencies>
<dependency>
<groupId>com.google.api-client</groupId>
<artifactId>google-api-client</artifactId>
<version>2.1.3</version>
</dependency>
</dependencies>
</project>
There is a sample for this on the Verify the Google ID token on your server side documentation page
You apear to be using an old sample i dont think they use GsonFactory anymore with the java library it was removed.
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;
...
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
// Specify the CLIENT_ID of the app that accesses the backend:
.setAudience(Collections.singletonList(CLIENT_ID))
// Or, if multiple clients access the backend:
//.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
.build();
// (Receive idTokenString by HTTPS POST)
GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
Payload payload = idToken.getPayload();
// Print user identifier
String userId = payload.getSubject();
System.out.println("User ID: " + userId);
// Get profile information from payload
String email = payload.getEmail();
boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
String name = (String) payload.get("name");
String pictureUrl = (String) payload.get("picture");
String locale = (String) payload.get("locale");
String familyName = (String) payload.get("family_name");
String givenName = (String) payload.get("given_name");
// Use or store profile information
// ...
} else {
System.out.println("Invalid ID token.");
}
I'm following an example to understand how SOAP works. I have generated code from wsdl using Apache cxf and I can log SOAP web service request e response. Apparently all works fine. I have just a problem to set a relative path. I've followed this solution How to avoid the need to specify the WSDL location in a CXF or JAX-WS generated webservice client?, but there isn't way to solve the log error on console.
The error message on console:
jun 03, 2021 2:17:38 PM io.codejournal.maven.wsdl2java.NumberConversion <clinit>
INFO: Can not initialize the default wsdl from classpath:wsdl/dataaccess-numberconversion.wsdl
this is my pom.xml:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>11</java.version>
<maven.compiler.source>${java.version}</maven.compiler.source>
<maven.compiler.target>${java.version}</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-simple</artifactId>
<version>3.1.18</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>3.4.2</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<goals>
<goal>wsdl2java</goal>
</goals>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/dataaccess-numberconversion.wsdl</wsdl>
<wsdlLocation>classpath:wsdl/dataaccess-numberconversion.wsdl</wsdlLocation>
<packagenames>
<packagename>io.codejournal.maven.wsdl2java</packagename>
</packagenames>
</wsdlOption>
</wsdlOptions>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
My service class:
#WebServiceClient(name = "NumberConversion",
wsdlLocation = "classpath:wsdl/dataaccess-numberconversion.wsdl",
targetNamespace = "http://www.dataaccess.com/webservicesserver/")
public class NumberConversion extends Service {
public final static URL WSDL_LOCATION;
public final static QName SERVICE = new QName("http://www.dataaccess.com/webservicesserver/", "NumberConversion");
public final static QName NumberConversionSoap = new QName("http://www.dataaccess.com/webservicesserver/", "NumberConversionSoap");
public final static QName NumberConversionSoap12 = new QName("http://www.dataaccess.com/webservicesserver/", "NumberConversionSoap12");
static {
URL url = NumberConversion.class.getClassLoader().getResource("wsdl/dataaccess-numberconversion.wsdl");
if (url == null) {
java.util.logging.Logger.getLogger(NumberConversion.class.getName())
.log(java.util.logging.Level.INFO,
"Can not initialize the default wsdl from {0}", "classpath:wsdl/dataaccess-numberconversion.wsdl");
}
WSDL_LOCATION = url;
}
public NumberConversion(URL wsdlLocation) {
super(wsdlLocation, SERVICE);
}
public NumberConversion(URL wsdlLocation, QName serviceName) {
super(wsdlLocation, serviceName);
}
public NumberConversion() {
super(WSDL_LOCATION, SERVICE);
}
public NumberConversion(WebServiceFeature ... features) {
super(WSDL_LOCATION, SERVICE, features);
}
public NumberConversion(URL wsdlLocation, WebServiceFeature ... features) {
super(wsdlLocation, SERVICE, features);
}
public NumberConversion(URL wsdlLocation, QName serviceName, WebServiceFeature ... features) {
super(wsdlLocation, serviceName, features);
}
/**
*
* #return
* returns NumberConversionSoapType
*/
#WebEndpoint(name = "NumberConversionSoap")
public NumberConversionSoapType getNumberConversionSoap() {
return super.getPort(NumberConversionSoap, NumberConversionSoapType.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* #return
* returns NumberConversionSoapType
*/
#WebEndpoint(name = "NumberConversionSoap")
public NumberConversionSoapType getNumberConversionSoap(WebServiceFeature... features) {
return super.getPort(NumberConversionSoap, NumberConversionSoapType.class, features);
}
/**
*
* #return
* returns NumberConversionSoapType
*/
#WebEndpoint(name = "NumberConversionSoap12")
public NumberConversionSoapType getNumberConversionSoap12() {
return super.getPort(NumberConversionSoap12, NumberConversionSoapType.class);
}
/**
*
* #param features
* A list of {#link javax.xml.ws.WebServiceFeature} to configure on the proxy. Supported features not in the <code>features</code> parameter will have their default values.
* #return
* returns NumberConversionSoapType
*/
#WebEndpoint(name = "NumberConversionSoap12")
public NumberConversionSoapType getNumberConversionSoap12(WebServiceFeature... features) {
return super.getPort(NumberConversionSoap12, NumberConversionSoapType.class, features);
}
}
When I run this code URL url = NumberConversion.class.getClassLoader().getResource("wsdl/dataaccess-numberconversion.wsdl"); ,
I'll get a null value back. It is the wrong path that NumberConversion.class.getClassLoader() calls, because this class is in another package.
Any idea how to set in the right way?
There is a mismatch in your <wsdlOption>, between the <wsdl> and <wsdlLocation> values.
<wsdl>${basedir}/src/main/resources/dataaccess-numberconversion.wsdl</wsdl>
<wsdlLocation>classpath:wsdl/dataaccess-numberconversion.wsdl</wsdlLocation>
The first line says the file is in the root of the classpath but in your second line you say it's on a subpath called wsdl. Both cannot be true.
So change your code to either:
<wsdl>${basedir}/src/main/resources/wsdl/dataaccess-numberconversion.wsdl</wsdl>
<wsdlLocation>classpath:wsdl/dataaccess-numberconversion.wsdl</wsdlLocation>
or to:
<wsdl>${basedir}/src/main/resources/dataaccess-numberconversion.wsdl</wsdl>
<wsdlLocation>classpath:dataaccess-numberconversion.wsdl</wsdlLocation>
What's after /src/main/resources/ and classpath: must match.
Whatever variant you choose make sure that:
the WSDL file is in its proper place inside the /src/main/resources/ folder of your project (directly there or in wsdl subfolder).
that all your code also reflects the correct classpath path (on the root of the classpath or inside a subpackage called wsdl);
that after packaging your JAR file, you decompress it and look inside it to see the WSDL file is at the correct location inside the JAR (either directly on the root or in a a wsdl subfolder).
I am working on a java project that runs in Azure Functions. The problem is that I can't make the Java CDI 2.0 work in the application.
Please refer to the application codes below.
Function.java
public class Function {
#Inject
private Util util;
/**
* This function listens at endpoint "/api/HttpTrigger-Java". Two ways to invoke it using "curl" command in bash:
* 1. curl -d "HTTP Body" {your host}/api/HttpTrigger-Java&code={your function key}
* 2. curl "{your host}/api/HttpTrigger-Java?name=HTTP%20Query&code={your function key}"
* Function Key is not needed when running locally, to invoke HttpTrigger deployed to Azure, see here(https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-http-webhook#authorization-keys) on how to get function key for your app.
*/
#FunctionName("HttpTrigger-Java")
public HttpResponseMessage run(
#HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.FUNCTION) HttpRequestMessage<Optional<String>> request,
final ExecutionContext context) {
context.getLogger().info("Java HTTP trigger processed a request.");
// Parse query parameter
String query = request.getQueryParameters().get("name");
String name = request.getBody().orElse(query);
util.display();
if (name == null) {
return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
} else {
return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
}
}
}
Util.java
#RequestScoped
public class Util {
public void display(){
System.out.println("testing..");
}
}
I have this in my pom.xml
<dependency>
<groupId>javax.enterprise</groupId>
<artifactId>cdi-api</artifactId>
<version>2.0</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
when I deploy this and hit the endpoint, I am getting an nullpointerexception when accessing the method from the injected bean..
Can someone enlighten me regarding this matter?
The idea behind what i'm doing is exposing hyperledger fabric blockchain using Spring REST APIs.
When i build my code (withourt REST) and call it using the java command, it works fine and returns the data from Hyperledger fabric.
However, when i try to implement it in the REST controller, i find myself blocked.
Below is my code for the Rest Controller :
#RestController
public class RestWebController {
private static final Logger log = Logger.getLogger(RestWebController.class);
#RequestMapping(value = "/getall", method = RequestMethod.GET)
public void getAll(){
try {
HFCAClient caClient = getHfCaClient("http://localhost:7054", null);
// enroll or load admin
AppUser admin = getAdmin(caClient);
log.info(admin);
// register and enroll new user
AppUser appUser = getUser(caClient, admin, "hfuser");
log.info(appUser);
// get HFC client instance
HFClient client = getHfClient();
// set user context
client.setUserContext(admin);
// get HFC channel using the client
Channel channel = getChannel(client);
log.info("Channel: " + channel.getName());
// call query blockchain example
queryBlockChain(client);
}
catch (Exception e) {
e.printStackTrace();
}
}
/**
* Invoke blockchain query
*
* #param client The HF Client
* #throws ProposalException
* #throws InvalidArgumentException
*/
static void queryBlockChain(HFClient client) throws ProposalException, InvalidArgumentException {
// get channel instance from client
Channel channel = client.getChannel("mychannel");
// create chaincode request
QueryByChaincodeRequest qpr = client.newQueryProposalRequest();
// build cc id providing the chaincode name. Version is omitted here.
ChaincodeID fabcarCCId = ChaincodeID.newBuilder().setName("poc-app").build();
qpr.setChaincodeID(fabcarCCId);
// CC function to be called
qpr.setFcn("queryAllTransactions");
Collection<ProposalResponse> res = channel.queryByChaincode(qpr);
// display response
for (ProposalResponse pres : res) {
String stringResponse = new String(pres.getChaincodeActionResponsePayload());
log.info(stringResponse);
}
}
/**
* Initialize and get HF channel
*
* #param client The HFC client
* #return Initialized channel
* #throws InvalidArgumentException
* #throws TransactionException
*/
static Channel getChannel(HFClient client) throws InvalidArgumentException, TransactionException {
// initialize channel
// peer name and endpoint in fabcar network
Peer peer = client.newPeer("peer0.org1.example.com", "grpc://localhost:7051");
// eventhub name and endpoint in fabcar network
EventHub eventHub = client.newEventHub("eventhub01", "grpc://localhost:7053");
// orderer name and endpoint in fabcar network
Orderer orderer = client.newOrderer("orderer.example.com", "grpc://localhost:7050");
// channel name in fabcar network
Channel channel = client.newChannel("mychannel");
channel.addPeer(peer);
channel.addEventHub(eventHub);
channel.addOrderer(orderer);
channel.initialize();
return channel;
}
/**
* Create new HLF client
*
* #return new HLF client instance. Never null.
* #throws CryptoException
* #throws InvalidArgumentException
*/
static HFClient getHfClient() throws Exception {
// initialize default cryptosuite
CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
// setup the client
HFClient client = HFClient.createNewInstance();
client.setCryptoSuite(cryptoSuite);
return client;
}
/**
* Register and enroll user with userId.
* If AppUser object with the name already exist on fs it will be loaded and
* registration and enrollment will be skipped.
*
* #param caClient The fabric-ca client.
* #param registrar The registrar to be used.
* #param userId The user id.
* #return AppUser instance with userId, affiliation,mspId and enrollment set.
* #throws Exception
*/
static AppUser getUser(HFCAClient caClient, AppUser registrar, String userId) throws Exception {
AppUser appUser = tryDeserialize(userId);
if (appUser == null) {
RegistrationRequest rr = new RegistrationRequest(userId, "org1");
String enrollmentSecret = caClient.register(rr, registrar);
Enrollment enrollment = caClient.enroll(userId, enrollmentSecret);
appUser = new AppUser(userId, "org1", "Org1MSP", enrollment);
serialize(appUser);
}
return appUser;
}
/**
* Enroll admin into fabric-ca using {#code admin/adminpw} credentials.
* If AppUser object already exist serialized on fs it will be loaded and
* new enrollment will not be executed.
*
* #param caClient The fabric-ca client
* #return AppUser instance with userid, affiliation, mspId and enrollment set
* #throws Exception
*/
static AppUser getAdmin(HFCAClient caClient) throws Exception {
AppUser admin = tryDeserialize("admin");
if (admin == null) {
Enrollment adminEnrollment = caClient.enroll("admin", "adminpw");
admin = new AppUser("admin", "org1", "Org1MSP", adminEnrollment);
serialize(admin);
}
return admin;
}
/**
* Get new fabic-ca client
*
* #param caUrl The fabric-ca-server endpoint url
* #param caClientProperties The fabri-ca client properties. Can be null.
* #return new client instance. never null.
* #throws Exception
*/
static HFCAClient getHfCaClient(String caUrl, Properties caClientProperties) throws Exception {
CryptoSuite cryptoSuite = CryptoSuite.Factory.getCryptoSuite();
HFCAClient caClient = HFCAClient.createNewInstance(caUrl, caClientProperties);
caClient.setCryptoSuite(cryptoSuite);
return caClient;
}
// user serialization and deserialization utility functions
// files are stored in the base directory
/**
* Serialize AppUser object to file
*
* #param appUser The object to be serialized
* #throws IOException
*/
static void serialize(AppUser appUser) throws IOException {
try (ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(
Paths.get(appUser.getName() + ".jso")))) {
oos.writeObject(appUser);
}
}
/**
* Deserialize AppUser object from file
*
* #param name The name of the user. Used to build file name ${name}.jso
* #return
* #throws Exception
*/
static AppUser tryDeserialize(String name) throws Exception {
if (Files.exists(Paths.get(name + ".jso"))) {
return deserialize(name);
}
return null;
}
static AppUser deserialize(String name) throws Exception {
try (ObjectInputStream decoder = new ObjectInputStream(
Files.newInputStream(Paths.get(name + ".jso")))) {
return (AppUser) decoder.readObject();
}
}
I run spring boot using mvn spring-boot:run, the server starts normally. this is my pom.xml :
<?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>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hyperledger.fabric-sdk-java</groupId>
<artifactId>fabric-sdk-java</artifactId>
<version>1.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
After calling the server on localhost:8080/getall , i get this error :
2018-07-13 14:56:33.439 WARN 24669 --- [ault-executor-0] io.grpc.internal.ChannelExecutor : Runnable threw exception in ChannelExecutor
java.lang.NoClassDefFoundError: io/netty/handler/codec/http2/internal/hpack/Decoder
at io.grpc.netty.GrpcHttp2HeadersDecoder.<init>(GrpcHttp2HeadersDecoder.java:85) ~[grpc-netty-1.3.0.jar:1.3.0]
at io.grpc.netty.GrpcHttp2HeadersDecoder$GrpcHttp2ClientHeadersDecoder.<init>(GrpcHttp2HeadersDecoder.java:147) ~[grpc-netty-1.3.0.jar:1.3.0]
at io.grpc.netty.NettyClientHandler.newHandler(NettyClientHandler.java:119) ~[grpc-netty-1.3.0.jar:1.3.0]
at io.grpc.netty.NettyClientTransport.start(NettyClientTransport.java:190) ~[grpc-netty-1.3.0.jar:1.3.0]
at io.grpc.internal.ForwardingConnectionClientTransport.start(ForwardingConnectionClientTransport.java:44) ~[grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.InternalSubchannel.startNewTransport(InternalSubchannel.java:216) ~[grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.InternalSubchannel.obtainActiveTransport(InternalSubchannel.java:186) ~[grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.ManagedChannelImpl$SubchannelImplImpl.obtainActiveTransport(ManagedChannelImpl.java:812) ~[grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.GrpcUtil.getTransportFromPickResult(GrpcUtil.java:592) ~[grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.DelayedClientTransport.reprocess(DelayedClientTransport.java:295) ~[grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.ManagedChannelImpl$LbHelperImpl$5.run(ManagedChannelImpl.java:718) ~[grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.ChannelExecutor.drain(ChannelExecutor.java:87) ~[grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.ManagedChannelImpl$LbHelperImpl.runSerialized(ManagedChannelImpl.java:709) [grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.ManagedChannelImpl$NameResolverListenerImpl.onAddresses(ManagedChannelImpl.java:758) [grpc-core-1.3.0.jar:1.3.0]
at io.grpc.internal.DnsNameResolver$1.run(DnsNameResolver.java:175) [grpc-core-1.3.0.jar:1.3.0]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]
Caused by: java.lang.ClassNotFoundException: io.netty.handler.codec.http2.internal.hpack.Decoder
at java.net.URLClassLoader.findClass(URLClassLoader.java:381) ~[na:1.8.0_171]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[na:1.8.0_171]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[na:1.8.0_171]
... 18 common frames omitted
2018-07-13 14:56:35.321 ERROR 24669 --- [nio-8080-exec-2] o.hyperledger.fabric.sdk.OrdererClient : sendDeliver time exceeded for orderer
org.hyperledger.fabric.sdk.exception.TransactionException: sendDeliver time exceeded for orderer
at org.hyperledger.fabric.sdk.OrdererClient.sendDeliver(OrdererClient.java:274) ~[fabric-sdk-java-1.0.0.jar:na]
at org.hyperledger.fabric.sdk.Orderer.sendDeliver(Orderer.java:165) [fabric-sdk-java-1.0.0.jar:na]
at org.hyperledger.fabric.sdk.Channel.getLatestBlock(Channel.java:1074) [fabric-sdk-java-1.0.0.jar:na]
at org.hyperledger.fabric.sdk.Channel.getConfigurationBlock(Channel.java:898) [fabric-sdk-java-1.0.0.jar:na]
at org.hyperledger.fabric.sdk.Channel.parseConfigBlock(Channel.java:826) [fabric-sdk-java-1.0.0.jar:na]
at org.hyperledger.fabric.sdk.Channel.initialize(Channel.java:526) [fabric-sdk-java-1.0.0.jar:na]
at com.example.demo.controller.RestWebController.getChannel(RestWebController.java:144) [classes/:na]
at com.example.demo.controller.RestWebController.getAll(RestWebController.java:84) [classes/:na]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_171]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_171]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_171]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_171]
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:209) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136) [spring-web-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:877) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:783) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:974) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:866) [spring-webmvc-5.0.7.RELEASE.jar:5.0.7.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:635) [tomcat-embed-core-8.5.31.jar:8.5.31]
NOTE: The network is working fine, by calling the .jar independently, and even running the hyperledger fabric nodeJS sdk.
NoClassDefFoundError means the is a version conflict. gRPC was compiled to use a method that isn't existing at runtime.
Using mvn dependency:tree I see that Netty version 4.1.25.Final is being used. But looking at fabric-sdk-java 1.0.0, it is using grpc-netty 1.3.0 and Netty 4.1.8.Final. spring-boot-starter-parent is pulling in spring-boot-dependencies which is selecting Netty 4.1.25.Final.
I suggest upgrading to fabric-sdk-java 1.1.0 which uses grpc-netty 1.11.0 and Netty 4.1.23.Final. Then override spring-boot-dependencies to use Netty 4.1.23.Final by setting the netty.version property:
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<netty.version>4.1.23.Final</netty.version> <!-- add this line -->
</properties>
I also encountered this problem, thanks to the answer Eric Anderson, I solved the problem.
It's completely correct that NoClassDefFoundError means a version conflict.
My version: fabric-sdk-java 1.0.0 , Spring Boot 2.2.6.RELEASE.
The netty version of fabric-sdk-java 1.0.0 is 4.1.8.Final,but netty version of Spring Boot 2.2.6.RELEASE parent is 4.1.48.Final,if you do nothing,fabric-sdk-java can use 4.1.48.Final,so it produces an error.
This is my solution:
<properties>
<java.version>1.8</java.version>
<netty.version>4.1.8.Final</netty.version>
</properties>
I am trying to run a PDI transformation involving database (any database, but noSQL one are more preferred) from Java.
I've tried using mongodb and cassandradb and got missing plugins, I've already asked here: Running PDI Kettle on Java - Mongodb Step Missing Plugins, but no one replied yet.
I've tried switching to SQL DB using PostgreSQL too, but it still doesn't work. From the research I did, I think it was because I didn't connect the database from the Java thoroughly, yet I haven't found any tutorial or direction that works for me. I've tried following directions from this blog : http://ameethpaatil.blogspot.co.id/2010/11/pentaho-data-integration-java-maven.html : but still got some problems about repository (because I don't have any and there seems to be required).
The transformations are fine when I run it from Spoon. It only failed when I run it from Java.
Can anyone help me how to run PDI transformation involving database? Where did I go wrong?
Is anyone ever succeeded in running PDI transformation from involving either noSQL and SQL database? what DB did you use?
I'm sorry if I asked too many questions, I am so desperate. any kind of information will be very appreciated. Thank you.
Executing PDI Jobs from Java is pretty straight forward. You just need to import all the necessary jar files (for the databases) and then call in the kettle class. The best way is obviously to use "Maven" to control the dependency. In the maven pom.xml file, just call the database drivers.
A Sample Maven file would be something like below, assuming you are using pentaho v5.0.0GA and Database as PostgreSQL:
<dependencies>
<!-- Pentaho Kettle Core dependencies development -->
<dependency>
<groupId>pentaho-kettle</groupId>
<artifactId>kettle-core</artifactId>
<version>5.0.0.1</version>
</dependency>
<dependency>
<groupId>pentaho-kettle</groupId>
<artifactId>kettle-dbdialog</artifactId>
<version>5.0.0.1</version>
</dependency>
<dependency>
<groupId>pentaho-kettle</groupId>
<artifactId>kettle-engine</artifactId>
<version>5.0.0.1</version>
</dependency>
<dependency>
<groupId>pentaho-kettle</groupId>
<artifactId>kettle-ui-swt</artifactId>
<version>5.0.0.1</version>
</dependency>
<dependency>
<groupId>pentaho-kettle</groupId>
<artifactId>kettle5-log4j-plugin</artifactId>
<version>5.0.0.1</version>
</dependency>
<!-- The database dependency files. Use it if your kettle file involves database connectivity. -->
<dependency>
<groupId>postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.1-902.jdbc4</version>
</dependency>
You can check my blog for more. It works for database connections.
Hope this helps :)
I had the same problem in a application using the pentaho libraries. I resolved the problem with this code:
The singleton to init Kettle:
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.exception.KettleException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Inicia as configurações das variáveis de ambiente do kettle
*
* #author Marcos Souza
* #version 1.0
*
*/
public class AtomInitKettle {
private static final Logger LOGGER = LoggerFactory.getLogger(AtomInitKettle.class);
private AtomInitKettle() throws KettleException {
try {
LOGGER.info("Iniciando kettle");
KettleJNDI.protectSystemProperty();
KettleEnvironment.init();
LOGGER.info("Kettle iniciado com sucesso");
} catch (Exception e) {
LOGGER.error("Message: {} Cause {} ", e.getMessage(), e.getCause());
}
}
}
And the code that saved me:
import java.io.File;
import java.util.Properties;
import org.pentaho.di.core.Const;
import org.pentaho.di.core.exception.KettleException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class KettleJNDI {
private static final Logger LOGGER = LoggerFactory.getLogger(KettleJNDI.class);
public static final String SYS_PROP_IC = "java.naming.factory.initial";
private static boolean init = false;
private KettleJNDI() {
}
public static void initJNDI() throws KettleException {
String path = Const.JNDI_DIRECTORY;
LOGGER.info("Kettle Const.JNDI_DIRECTORY= {}", path);
if (path == null || path.equals("")) {
try {
File file = new File("simple-jndi");
path = file.getCanonicalPath();
} catch (Exception e) {
throw new KettleException("Error initializing JNDI", e);
}
Const.JNDI_DIRECTORY = path;
LOGGER.info("Kettle null > Const.JNDI_DIRECTORY= {}", path);
}
System.setProperty("java.naming.factory.initial", "org.osjava.sj.SimpleContextFactory");
System.setProperty("org.osjava.sj.root", path);
System.setProperty("org.osjava.sj.delimiter", "/");
}
public static void protectSystemProperty() {
if (init) {
return;
}
System.setProperties(new ProtectionProperties(SYS_PROP_IC, System.getProperties()));
if (LOGGER.isInfoEnabled()) {
LOGGER.info("Kettle System Property Protector: System.properties replaced by custom properies handler");
}
init = true;
}
public static class ProtectionProperties extends Properties {
private static final long serialVersionUID = 1L;
private final String protectedKey;
public ProtectionProperties(String protectedKey, Properties prprts) {
super(prprts);
if (protectedKey == null) {
throw new IllegalArgumentException("Properties protection was provided a null key");
}
this.protectedKey = protectedKey;
}
#Override
public synchronized Object setProperty(String key, String value) {
// We forbid changes in general, but do it silent ...
if (protectedKey.equals(key)) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Kettle System Property Protector: Protected change to '" + key + "' with value '" + value + "'");
}
return super.getProperty(protectedKey);
}
return super.setProperty(key, value);
}
}
}
I think your problem is with connection of data base. You can configure in transformation and do not need use JNDI.
public class DatabaseMetaStep {
private static final Logger LOGGER = LoggerFactory.getLogger(DatabaseMetaStep.class);
/**
* Adds the configurations of access to the database
*
* #return
*/
public static DatabaseMeta createDatabaseMeta() {
DatabaseMeta databaseMeta = new DatabaseMeta();
LOGGER.info("Carregando informacoes de acesso");
databaseMeta.setHostname("localhost");
databaseMeta.setName("stepName");
databaseMeta.setUsername("user");
databaseMeta.setPassword("password");
databaseMeta.setDBPort("port");
databaseMeta.setDBName("database");
databaseMeta.setDatabaseType("MonetDB"); // sql, MySql ...
databaseMeta.setAccessType(DatabaseMeta.TYPE_ACCESS_NATIVE);
return databaseMeta;
}
}
Then you need set the databaseMeta to Transmeta
DatabaseMeta databaseMeta = DatabaseMetaStep.createDatabaseMeta();
TransMeta transMeta = new TransMeta();
transMeta.setUsingUniqueConnections(true);
transMeta.setName("ransmetaNeame");
List<DatabaseMeta> databases = new ArrayList<>();
databases.add(databaseMeta);
transMeta.setDatabases(databases);
I tried your code with a "tranformation without jndi" and works!
But I needed add this repository in my pom.xml:
<repositories>
<repository>
<id>pentaho-releases</id>
<url>http://repository.pentaho.org/artifactory/repo/</url>
</repository>
</repositories>
Also when I try with a datasource I have this error : Cannot instantiate class: org.osjava.sj.SimpleContextFactory [Root exception is java.lang.ClassNotFoundException: org.osjava.sj.SimpleContextFactory]
Complete log here:
https://gist.github.com/eb15f8545e3382351e20.git
[FIX] : Add this dependency :
<dependency>
<groupId>pentaho</groupId>
<artifactId>simple-jndi</artifactId>
<version>1.0.1</version>
</dependency>
After that a new error occurs:
transformation_with_jndi - Dispatching started for transformation [transformation_with_jndi]
Table input.0 - ERROR (version 5.0.0.1.19046, build 1 from 2013-09-11_13-51-13 by buildguy) : An error occurred, processing will be stopped:
Table input.0 - Error occured while trying to connect to the database
Table input.0 - java.io.File parameter must be a directory. [D:\opt\workspace-eclipse\invoke-ktr-jndi\simple-jndi]
Complete log : https://gist.github.com/jrichardsz/9d74c7263f3567ac4b45
[EXPLANATION] This is due to in
KettleEnvironment.init();
https://github.com/jrichardsz/pentaho-pdi-spoon-usefull-templates/blob/master/running-etl-transformation-using-java/researching-pentaho-classes/KettleEnvironment.java
There is a inicialization :
if (simpleJndi) {
JndiUtil.initJNDI();
}
And in JndiUtil:
String path = Const.JNDI_DIRECTORY;
if ((path == null) || (path.equals("")))
https://github.com/jrichardsz/pentaho-pdi-spoon-usefull-templates/blob/master/running-etl-transformation-using-java/researching-pentaho-classes/JndiUtil.java
And in Const class :
public static String JNDI_DIRECTORY = NVL(System.getProperty("KETTLE_JNDI_ROOT"), System.getProperty("org.osjava.sj.root"));
https://github.com/jrichardsz/pentaho-pdi-spoon-usefull-templates/blob/master/running-etl-transformation-using-java/researching-pentaho-classes/Const.java
So wee need set this variable KETTLE_JNDI_ROOT
[FIX] A small change in your example : Just add this
System.setProperty("KETTLE_JNDI_ROOT", jdbcPropertiesPath);
before
KettleEnvironment.init();
A complete example based in your code :
import java.io.File;
import org.pentaho.di.core.KettleEnvironment;
import org.pentaho.di.core.exception.KettleException;
import org.pentaho.di.trans.Trans;
import org.pentaho.di.trans.TransMeta;
public class ExecuteSimpleTransformationWithJndiDatasource {
public static void main(String[] args) {
String resourcesPath = (new File(".").getAbsolutePath())+"\\src\\main\\resources";
String ktr_path = resourcesPath+"\\transformation_with_jndi.ktr";
//KETTLE_JNDI_ROOT could be the simple-jndi folder in your pdi or spoon home.
//in this example, is the resources folder
String jdbcPropertiesPath = resourcesPath;
try {
/**
* Initialize the Kettle Enviornment
*/
System.setProperty("KETTLE_JNDI_ROOT", jdbcPropertiesPath);
KettleEnvironment.init();
/**
* Create a trans object to properly assign the ktr metadata.
*
* #filedb: The ktr file path to be executed.
*
*/
TransMeta metadata = new TransMeta(ktr_path);
Trans trans = new Trans(metadata);
// Execute the transformation
trans.execute(null);
trans.waitUntilFinished();
// checking for errors
if (trans.getErrors() > 0) {
System.out.println("Erroruting Transformation");
}
} catch (KettleException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
For a complete example check my github channel:
https://github.com/jrichardsz/pentaho-pdi-spoon-usefull-templates/tree/master/running-etl-transformation-using-java/invoke-transformation-from-java-jndi/src/main/resources