5

I wrote a simply java program (jdk 1.7) that lists all my service bus topics and prints out the name of each topic to stdout:

try {
    String namespace = "myservicebus"; // from azure portal
    String issuer = "owner";  // from azure portal
    String key = "asdjklasdjklasdjklasdjklasdjk";  // from azure portal
            
    Configuration config = ServiceBusConfiguration.configureWithWrapAuthentication(
        namespace, 
        issuer,
        key, 
        ".servicebus.windows.net", 
        "-sb.accesscontrol.windows.net/WRAPv0.9"); 
             
    ServiceBusContract service = ServiceBusService.create(config);
    ListTopicsResult result = service.listTopics();
    List<TopicInfo> infoList = result.getItems();
    for(TopicInfo info : infoList) {
        System.out.println( info.getPath());
    }
} catch (Exception e) {
    e.printStackTrace();
}

Now, i am trying to run this example in a simple android project (Android 4.2) but it wont work. The runtime always throws following error:

java.lang.RuntimeException: Service or property not registered:  com.microsoft.windowsazure.services.serviceBus.ServiceBusContract

Has anyone successfully established a connection from an android device (or emulator) to azure service bus?

Does the Microsoft Azure-Java-SDK not support android projects?

Thanks in advance

Jon Bates
  • 3,055
  • 2
  • 30
  • 48
stef
  • 271
  • 3
  • 10
  • Ermm ... you might want to obscure you app key in your code sample above! – Rich Turner Mar 11 '13 at 07:02
  • Have u tried the same sample code on a Linux/Mac/Windows machine? Are you sure that is an Android compatibility problem? – Albert Cheng Mar 11 '13 at 17:38
  • The app key is obscured ;-) – stef Mar 11 '13 at 19:56
  • @AlbertCheng I have no idea what the problem could be. The sample code uses the official Java-SDK from [Microsoft](http://dl.msopentech.com/lib/PackageForWindowsAzureLibrariesForJava.html). I've tried the code on a Windows 7 machine. I suppose the Java API for the service bus simply does not work under android – stef Mar 11 '13 at 19:58
  • Could be... I am still curious about why it doesn't work under Android because according to this blog post, here is the difference between normal Java and Android Java http://www.zdnet.com/blog/burnette/java-vs-android-apis/504 . Service Bus doesn't seem to use much banned stuff. – Albert Cheng Mar 11 '13 at 21:15
  • This error seems to be related with SerivceLoader, this is Javas DI framework built into java from 1.6. Check if the android jdk support ServiceLoader. – Dhana Krishnasamy Dec 12 '13 at 13:43
  • Looks like class loader problem , see my response for http://stackoverflow.com/questions/26073178/service-or-property-not-registered-error. – snallami Nov 07 '14 at 07:20

1 Answers1

2

This error is due to the fact that apks generated do not include (remove) the ServiceLoader information (under META-INF/services). You can test yourself deleting it from the jar generated and see that the same error appears. In the documentation it is said that it is now supported, but i found problems to use it.

http://developer.android.com/reference/java/util/ServiceLoader.html

You can include manually the data in the apk using ant

Keep 'META-INF/services'-files in apk

After 10h debugging, removing classes manually, including META-INF/services, etc, I found that the Azure SDK uses some classes not supported by Android (javax.ws.*) and any woraround works for me.

So I would recommend using the REST API in Android environments, find below the source code i used to sebd messages to the topic.

private static String generateSasToken(URI uri) {
    String targetUri;
    try {
        targetUri = URLEncoder
        .encode(uri.toString().toLowerCase(), "UTF-8")
        .toLowerCase();

        long expiresOnDate = System.currentTimeMillis();
        int expiresInMins = 20; // 1 hour
        expiresOnDate += expiresInMins * 60 * 1000;
        long expires = expiresOnDate / 1000;
        String toSign = targetUri + "\n" + expires;

        // Get an hmac_sha1 key from the raw key bytes
        byte[] keyBytes = sasKey.getBytes("UTF-8");
        SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256");

        // Get an hmac_sha1 Mac instance and initialize with the signing key
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);
        // Compute the hmac on input data bytes
        byte[] rawHmac = mac.doFinal(toSign.getBytes("UTF-8"));

        // using Apache commons codec for base64
//      String signature = URLEncoder.encode(
//      Base64.encodeBase64String(rawHmac), "UTF-8");
        String rawHmacStr = new String(Base64.encodeBase64(rawHmac, false),"UTF-8");
        String signature = URLEncoder.encode(rawHmacStr, "UTF-8");

        // construct authorization string
        String token = "SharedAccessSignature sr=" + targetUri + "&sig="
        + signature + "&se=" + expires + "&skn=" + sasKeyName;
        return token;
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

public static void Send(String topic, String subscription, String msgToSend) throws Exception {

        String url = uri+topic+"/messages";

        HttpClient client = new DefaultHttpClient();
        HttpPost post = new HttpPost(url);

        // Add header
        String token = generateSasToken(new URI(uri));
        post.setHeader("Authorization", token);
        post.setHeader("Content-Type", "text/plain");
        post.setHeader(subscription, subscription);
        StringEntity input = new StringEntity(msgToSend);
        post.setEntity(input);

        System.out.println("Llamando al post");
        HttpResponse response = client.execute(post);
        System.out.println("Response Code : " 
                + response.getStatusLine().getStatusCode());
        if (response.getStatusLine().getStatusCode() != 201)
            throw new Exception(response.getStatusLine().getReasonPhrase());

}

Further info at REST API Azure information.

Community
  • 1
  • 1
Carlos Cavero
  • 3,011
  • 5
  • 21
  • 41