Hot questions for Using Azure in powerbi

Question:

FINAL EDIT: The answer has been found. It was a dependency issue. Read answer below.

I'm working on a program that eventually should push data from an SQL server db real-time to our power BI report. I'm currently at a stage where I try to connect to my power BI from my client app.

For the authentication process I've followed this example for the code: https://gist.github.com/dquig/a4f2f02fe3e306cebe2e The authentication seems to be working fine. I'm getting an accesstoken (which is the same everytime, I haven't found yet if this is as supposed to be). EDIT: I also checked all of the msdn pages for OAuth2, powerBI API (including the Azure Active Directory steps).

EDIT: I've just noticed I even get an accesstoken if I fill in complete nonsense (why didn't I try this before... ). What I get is the same token everytime. The Response for the webrequest has a 200 status but a null entity.

Here is my code for authentication (I've left out the request here):

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.microsoft.aad.adal4j.AuthenticationContext;

public class PowerBIController {

private static final String POWER_BI_BASE_URL = "https://api.powerbi.com";
private static final String AUTH_URI = "https://login.windows.net/common/oauth2/authorize";
private static final String RESOURCE_URI = "https://analysis.windows.net/powerbi/api";
private static final boolean VALIDATE_AUTHORITY = false;

private static final String NATIVE_CLIENT_ID = "4b2f0d69-c17d-4d61-b2c0-4aeee5dfffe8";
private static final String USER_AT_TENANT = "powerBIUser@pveermanvicrea.onmicrosoft.com";
private static final String PASSWORD = "****";

private AuthenticationContext context = null;
private Client client;
private ExecutorService service = null;
private Response response;

public PowerBIController() throws Exception {
    client = ClientBuilder.newClient();
    service = Executors.newSingleThreadExecutor();
    context = new AuthenticationContext(AUTH_URI, VALIDATE_AUTHORITY, service);
    String powerBIAccessToken = getToken(RESOURCE_URI, NATIVE_CLIENT_ID, USER_AT_TENANT, PASSWORD);
}

private String getToken(String resourceUri, String nativeClientId,
        String tenant, String password) throws ExecutionException, InterruptedException{
    return context.acquireToken(
            resourceUri,
            nativeClientId,
            tenant,
            password,
            null
    ).get().getAccessToken();
}

Then comes the http request: I tried copy-pasting the whole example (from the link above) but readEntity is not a method of Response. I found the following post on this Read response body in JAX-RS client from a post request. But I am using version 2.0 of javax.ws.rs. So, here is a little confusion for me.

public PowerBIController() throws Exception {
    client = ClientBuilder.newClient();
    service = Executors.newSingleThreadExecutor();
    context = new AuthenticationContext(AUTH_URI, VALIDATE_AUTHORITY, service);
    String powerBIAccessToken = getToken(RESOURCE_URI, NATIVE_CLIENT_ID, USER_AT_TENANT, PASSWORD);    
    post(biTarget, powerBIAccessToken);
}
private void post(WebTarget biTarget, String powerBIAccessToken) throws URISyntaxException, IOException, ExecutionException, InterruptedException {
    Response response = target
    Invocation.Builder builder = biTarget.request(MediaType.APPLICATION_JSON);
    Invocation.Builder header = builder.header("Authorization",
                                               "Bearer " +    powerBIAccessToken);
    response = header.get();
    System.out.println("header: " + header.toString());
    System.out.println("status: " + response.getStatus());
    System.out.println("body:" + response.readEntity(String.class));
}

I've checked at http://docs.powerbi.apiary.io/. Here I have to log in to my Office 365 account and then I can use the same code to get the list of datasets. Here I don't have to authenticate, which could make the difference but when I run as debug I can clearly see I have an accesstoken. Here is the code they say can call the get request properly. Obviously this doesn't work I'm also quite sure the target has typos:

import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.MediaType;

Client client = ClientBuilder.newClient();
Response response = client.target("https://api.powerbi.com/beta/myorghttps://api.powerbi.com/beta/myorg/datasets{?defaultRetentionPolicy}")
  .request(MediaType.TEXT_PLAIN_TYPE)
  .header("undefined", "")
  .get();

System.out.println("status: " + response.getStatus());
System.out.println("headers: " + response.getHeaders());
System.out.println("body:" + response.readEntity(String.class));

I've tried using Fiddler to see what is actually happening when I run. However, Fiddler is showing no activity at all (even though I checked the https option).

Finally here are my dependencies for this code:

<dependency>
  <groupId>javax.ws.rs</groupId>
   <artifactId>javax.ws.rs-api</artifactId>
  <version>2.0</version>
</dependency>
<dependency>
  <groupId>org.jboss.resteasy</groupId>
   <artifactId>resteasy-client</artifactId>
  <version>3.0.2.Final</version>
</dependency>
<dependency>
  <groupId>com.microsoft.azure</groupId>
   <artifactId>adal4j</artifactId>
  <version>1.0.0</version>
</dependency>

I'm really looking forward to any help. If anything is wrong with my question please say so. I tried my best to be clear and follow the rules of this forum but I might've missed something.

Much thanks in advance

ANSWER: I was also using azure-media 0.6.0 for parts of my program. This includes a jersey-core 1.3.1. Conclusion: Even though I thought I was importing from javax.ws.rs 2.0 (which it even said if you looked at the type) It was actually getting its object definitions from jersey 1.3.1. This held for more than just the azure-media dependency.

So I will post the dependencies that needed exclusions and the eventual dependencies which were necessary.

<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-management</artifactId>
<version>0.7.0</version>
<exclusions>
  <exclusion>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
    </exclusion>
  <exclusion>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-json</artifactId>
    </exclusion>
</exclusions>
</dependency>
<dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-servicebus</artifactId>
<version>0.7.0</version>
<exclusions>
  <exclusion>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
    </exclusion>
  <exclusion>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-json</artifactId>
    </exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-serviceruntime</artifactId>
<version>0.6.0</version>
<exclusions>
  <exclusion>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
    </exclusion>
  <exclusion>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-json</artifactId>
    </exclusion>
</exclusions>
</dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-media</artifactId>
<version>0.6.0</version>
<exclusions>
  <exclusion>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-client</artifactId>
    </exclusion>
  <exclusion>
      <groupId>com.sun.jersey</groupId>
      <artifactId>jersey-json</artifactId>
    </exclusion>
</exclusions>
</dependency>

The necessary dependencies:

<dependency>
<groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-client</artifactId>
<version>3.0.2.Final</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>adal4j</artifactId>
<version>1.0.0</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.core</groupId>
    <artifactId>jersey-client</artifactId>
    <version>2.19</version>
</dependency>
</dependencies>

Answer:

So, the problem was that I used several Maven dependencies which had partially overlapping dependencies in their hierarchy.

For example, I included the Jersey client v2.1.9 as well as the microsoft windows azure API, which uses a Jersey client v1.13.

The key point of this answer is as follows: When you're working with Azure SDK and Power BI REST API, there is a really high chance of you getting messed up dependencies. Check your dependency hierarchy to see which dependencies are used more than once.

Question:

I am knew to java, azure ad and power bi and I want to test pushing data into power bi using the azure ad java library (ADAL) here : http://innerdot.com/azure/authenticating-to-azure-resource-manager-using-java

I've created a netbeans project and used this code : http://innerdot.com/azure/authenticating-to-azure-resource-manager-using-java and tested it so that I know I have all rights to access my azure ad application.

In the Power BI documentation, we tell you to register your app and get the authentication token which will help you use the API to send GET/POST.. requests

I used a sample code I found on Github. However, following the examples in the power bi apiary docs I get a "403" or "404" http reponse status.

 public class ApplicationAuthExample {

    private final static String AUTHORIZATION_ENDPOINT = "https://login.microsoftonline.com/";
    private final static String ARM_ENDPOINT = "https://management.azure.com/";
    private static final boolean DEV_MODE = true;

    public static void main(String[] args) throws Exception {
        String username = null;
        String credential = null;
        String tenantId = null;
        String clientId = null;
        String subscriptionId = null;

        if (DEV_MODE) {
            username = "name.name@entity.com";
            credential = "******";
            clientId = "50xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
            tenantId = "bbexxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
            subscriptionId = "16bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
        } else {
            if ((!args[0].equals("service-principal") && !args[0].equals("user"))
                    || (args[0].equals("user") && args.length != 6)
                    || (args[0].equals("service-principal") && args.length != 5)) {
                System.out.println("Usage:");
                System.out.println(" user <username> <password> <client id> <tenant id> <subscription id>");
                System.out.println(" service-principal <password> <client id> <tenant id> <subscription id>");
                System.exit(1);
            }
            int idx = 1;
            if (args[0].equals("user")) {
                username = args[idx++];
            }
            credential = args[idx++];
            clientId = args[idx++];
            tenantId = args[idx++];
            subscriptionId = args[idx++];
        }

        // use adal to Authenticate
        AuthenticationContext context = null;
        AuthenticationResult result = null;
        ExecutorService service = null;

        try {
            service = Executors.newFixedThreadPool(1);
            String url = AUTHORIZATION_ENDPOINT + tenantId + "/oauth2/authorize";
            context = new AuthenticationContext(url,
                    false,
                    service);
            Future<AuthenticationResult> future = null;
            if (username == null) {
                System.out.println("username = null");
                ClientCredential cred = new ClientCredential(clientId, credential);
                future = context.acquireToken(ARM_ENDPOINT, cred, null);
            } else {
                future = context.acquireToken(ARM_ENDPOINT, clientId,
                        username, credential, null);
            }
            result = future.get();
        } catch (Exception ex) {
            System.out.println("Exception occurred:");
            ex.printStackTrace();
            System.exit(1);
        } finally {
            service.shutdown();
        }

        // make a request to list available providers
        String url = ARM_ENDPOINT
                + "subscriptions/" + subscriptionId
                + "/providers"
                + "?api-version=2014-04-01-preview";
//        String url = "https://api.powerbi.com/v1.0/myorg/datasets";
        String body = null;
        try {
            //final HttpClient httpClient = new DefaultHttpClient();
            final HttpClient httpClient = HttpClientBuilder.create().build();
            //HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), 10000);
             RequestConfig requestConfig = RequestConfig.custom()
                .setSocketTimeout(5000)
                .setConnectTimeout(5000)
                .setConnectionRequestTimeout(5000)
                .build();
            HttpGet httpGet = new HttpGet(url);
            httpGet.setConfig(requestConfig);
            System.out.println("url : "+url);
            httpGet.addHeader("Authorization", "Bearer " + result.getAccessToken());
           // httpGet.setHeader("Authorization", "Bearer " + result.getAccessToken());
//            System.out.println("token : "+result.getAccessToken());
            HttpResponse response = httpClient.execute(httpGet);
            int statusCode = response.getStatusLine().getStatusCode();
            System.out.println("status : "+statusCode);
            if(statusCode == 403){
                System.out.println(statusCode+": acces denied");
            }
            HttpEntity entity = response.getEntity();
            InputStream instream = entity.getContent();

            StringBuilder sb = new StringBuilder();
            BufferedReader r = new BufferedReader(new InputStreamReader(instream), 1000);
            for (String line = r.readLine(); line != null; line = r.readLine()) {
                sb.append(line);
            }
            instream.close();
            body = sb.toString();
        } catch (Exception ex) {
            System.out.println(ex.toString());
            System.exit(1);
        }

        System.out.println("body : "+body);
    }
}

Thank you for your help.


Answer:

As I known, the endpoints in your code are only for service on Azure, not for PowerBI. Please follow the PowerBI offical document to set the endpoints for authenticating, and see the document Push data into a Power BI Dashboard to know how to get started.

For authenticating to PowerBI service, please according to your needs to register a client app or a web app that needs different authentication.

There is a sample which I searched in GitHub, that includes the code for getting access token for PowerBI authentication using Java, please see https://github.com/satalyst/powerbi-rest-java/blob/master/src/main/java/com/satalyst/powerbi/impl/Office365Authenticator.java.

Hope it helps.

Any concern, please feel free to let me know.