DX Application Performance Management

 View Only
  • 1.  Tech Tip - CA Mobile App Analytics: MAA Reporting API Example

    Posted Jul 08, 2015 02:58 PM

    CA Mobile Application Analytics (MAA) Tuesday Tip by Bryan Whitmarsh, Sr Principal Technical Consultant for Tuesday, July 7, 2015

     

    In this Tuesday tip I’ll walk you through how to access MAA’s Secure Reporting APIs. The MAA platform has been designed to be flexible. Ok, so maybe the MAA Server can’t reach down and touch its keyboard, but flexible in the sense that it can be adapted and easily integrated into a customer’s environment; meeting their specific mobile analytics needs. Maybe a customer wants to have their own custom analytics dashboard or integrate certain analytics data collected by MAA into other systems (maybe even a non-CA system…;). This is all possible leveraging MAA’s Secure Reporting APIs.   

     

    First off, let’s get a feel for these API’s by viewing them being called in the MAA Console from your favorite browser. My favorite browser these days is Chrome (had to stop using Netscape…;) To view the MAA Reporting API calls, open up the browser’s console. For Chrome, you click on the three horizontal line icon next to the address bar and then select “More tools -> JavaScript Console”. 

    Image_01.png

    Then in the console on the bottom, click on the “Network” tab. This will show you all the network calls the browser is making. If you login to your MAA Console and click on the “Crashes” menu you can view the sample crash_summary REST API call we are going to use in this tip (mouse over the call to see the full http syntax). Note: If you try and copy/paste this url into your browser address you won’t get a response because you first need proper authentication to make the calls (shown in MAA_Reporting_API_Sample.sh content below).

    Image_02.jpg

    Another great resource for learning about the MAA Secure Reporting APIs is the “HELP” screen within the MAA Console.

    Image_03.jpg

    Once the “HELP” screen is open, click on the “REPORTING API” menu. Click on the “crashes:Crashes” operation and then on the “GET” button next to the “/crashes/crash_summary” operation. You can enter in parameters (required parameters are in BOLD) and then click on “Try it out!” to see the syntax of the REST API call.

    Image_04.jpg

    Note: Because localhost is the server name used for the “Try it out!” feature, unless you are running this from your MAA Server, you will not get a response. But this feature is useful for understanding which reporting APIs are available and their correct syntax.

     

    Ok, I think we are ready to create our Secure Rest Call and send it off for a response. Attached is a sample shell script file (MAA_Reporting_API_Sample.sh). This script needs to be run from a machine that can run the Unix shell like the MacOS Terminal, or from the command line of a Unix/Linux machine. Before we can run it, we need to customize it for the specific MAA server you are using. Open up the attached MAA_Reporting_API_Sample.sh file and add your MAA Server/App values for the following variables; USER, COHORT, PASS, SERVER, AGGREGATION, START_DATE, END_DATE, and APP_ID. After you have done this you can save and run the script.

     

    ---- Content Start: MAA_Reporting_API_Sample.sh---

    #This script is used to call the Secure MAA crash_summary Reporting API

     

    #Replace the values for the ones below with your values

     

    #Server Variables

    USER=YOUR_USER_NAME

    COHORT=YOUR_TENANT_NAME

    PASS=YOUR_USER_PASSWORD

    SERVER=https://your_server_address.com

     

    #Required Parameters for crash_summary reporting API

    AGGREGATION=day         #this value can be hour, day, or month

    START_DATE=2015-07-01   #year-month-day

    END_DATE=2015-07-07     #year-month-day

     

    #Optional Parameter for carsh_summary reporting API

    APP_ID=YOUR_APP_ID

     

    #Converting your Tenant name to base64 (text) for making the below JSON REST calls

    cohort=`echo $COHORT | openssl enc -base64`

    echo

    #Sending the Servername, User, and base64 tenant name to the screen so you can see it...

    echo Using Server : $SERVER with User : $USER and cohort : $COHORT

    echo

     

    #Before we can access the MAA Secure Reporting APIs we need to get an authentication token

    TOKEN=`curl -s  -X POST -H "Authorization: Basic $cohort" -H "Accept-Language: en_US" -d "grant_type=PASSWORD&username=$USER&password=$PASS" $SERVER/ess/security/v1/token  | json tkn`

    curl   -v -X POST -H "Authorization: Basic $cohort" -d "grant_type=PASSWORD&username=$USER&password=$PASS" $SERVER/ess/security/v1/token

     

    #Sending the token to the screen so you can see one was received

    echo "TOKEN:" $TOKEN

     

    #Exiting the script if we don't get a token because you can't continue with this script if you don't have a token

    if [ -z "$TOKEN" ]; then

    echo no token

    exit 1

    fi

     

    #For the below REST calls we are going to get the data for a specific tenant so we are going to create a base64 token including the necessary tenant info

    ENC_AUTHZ=`echo \{\"tkn\":\"$TOKEN\",\"t\":\"$COHORT\"\}    | openssl enc -base64 -A`

    #Sending the token to the screen so you can see one was created

    echo 'ENC_AUTHZ' $ENC_AUTHZ

    echo

     

    #Calling the Secure MAA Reporting API using a curl command to receive crash_summary information

    #The curl command is a tool to transfer data to/from a server

    #The -s = silent mode, -S will show any errors, -H allows us to pass the required authentication token as a header with the call

    #The "| json" will format the return data so it's more readable, if you don't have json installed you will get an error so you can remove this (or install json)

    curl -s -H "Authorization: Bearer $ENC_AUTHZ" "$SERVER/mdo/v1/crashes/crash_summary?aggregation=$AGGREGATION&start_date=$START_DATE&end_date=$END_DATE&app_id=$APP_ID" | json

     

    echo

    ---- Content End: MAA_Reporting_API_Sample.sh---

     

    Additional details regarding the CA MAA Reporting APIs can be found on the public CA Mobile App Analytics Product Wiki https://wiki.ca.com/dashboard.action under the “Reference-Use the REST APIs” section.

     

    Please add your own sample code in various languages to this post.



  • 2.  Re: Tech Tip - CA Mobile App Analytics: MAA Reporting API Example

    Broadcom Employee
    Posted Sep 02, 2015 12:10 PM

    Thanks, Bryan. The attached Android java and xml is for an app that looks like this

     

    maa_app.png



  • 3.  Re: Tech Tip - CA Mobile App Analytics: MAA Reporting API Example

    Broadcom Employee
    Posted Sep 02, 2015 12:11 PM

    MainActivity.java

     

    //##########################################

     

    package com.ca.kopja02.maadata;

    import android.app.Activity;
    import android.content.SharedPreferences;
    import android.graphics.Typeface;
    import android.os.AsyncTask;
    import android.os.Bundle;
    import android.os.StrictMode;
    import android.text.method.ScrollingMovementMethod;
    import android.util.Base64;
    import android.view.View;
    import android.view.inputmethod.InputMethodManager;
    import android.widget.Button;
    import android.widget.CheckBox;
    import android.widget.EditText;
    import android.widget.LinearLayout;
    import android.widget.Spinner;
    import android.widget.TextView;

    import org.apache.http.HttpEntity;
    import org.apache.http.HttpResponse;
    import org.apache.http.client.ClientProtocolException;
    import org.apache.http.client.HttpClient;
    import org.apache.http.client.methods.HttpGet;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.ByteArrayEntity;
    import org.apache.http.impl.client.DefaultHttpClient;
    import org.json.JSONException;
    import org.json.JSONObject;

    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.StringReader;
    import java.net.URL;
    import java.net.URLConnection;
    import java.text.DateFormat;
    import java.text.SimpleDateFormat;
    import java.util.Arrays;
    import java.util.Calendar;
    import java.util.HashSet;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;

    // Android app code to consume CA MAA Web Services reports. kopja02@ca.com @CA Technologies, 2015

    public class MainActivity extends Activity implements View.OnClickListener {

        // Initiate public String for capturing API call result
        public String GETresult = null;
        public String GETmsg = null;
        private Button btn;
        private CheckBox saveLoginCheckBox;
        private static final String USERNAME = "username";
        private static final String TENANT = "tenant";
        private static final String SERVER = "server";
        public static final String PREFS_NAME = "MyPrefsFile";

        LinearLayout linearChart;

        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            //  value=(EditText)findViewById(R.id.editText1);
            btn = (Button) findViewById(R.id.button1);
            btn.setOnClickListener(this);


            // Change static field font to CA Sans, and CA logo to imageButton

            TextView caTextView = (TextView) findViewById(R.id.txtLogin);
            TextView result = (TextView) findViewById(R.id.txtResult);
            // set a soft shadow to text to mark it as result output
            //  result.setShadowLayer(10, 0, 0, Color.WHITE);

            // Set CA typeface
            Typeface myCA = Typeface.createFromAsset(getAssets(), "fonts/CA Sans-Bold.ttf");
            caTextView.setTypeface(myCA);
            btn.setTypeface(myCA);

            result.setMovementMethod(new ScrollingMovementMethod());

            // RETRIEVE SAVED USERNAME, tenant and server URL

            SharedPreferences pref = getSharedPreferences(PREFS_NAME, MODE_PRIVATE);
            String username = pref.getString(USERNAME, null);
            String cohort = pref.getString(TENANT, null);
            String serverURL = pref.getString(SERVER, null);
            EditText uname = (EditText) findViewById(R.id.fld_username);
            uname.setText(username);
            EditText server = (EditText) findViewById(R.id.fld_server);
            server.setText(serverURL);
            EditText tenant = (EditText) findViewById(R.id.fld_enter_org);
            tenant.setText(cohort);

        }


        public void onClick(View v) {

    // check for entered username, pwd etc and set output initial 'processing' messages

            TextView resText = (TextView) findViewById(R.id.txtResult);
            TextView resText2 = (TextView) findViewById(R.id.txtResult2);
            TextView resTextRaw = (TextView) findViewById(R.id.txtResultRaw);
            resText.setText("Check login information");
            resText2.setText("");
            resTextRaw.setText("");

            EditText uname = (EditText) findViewById(R.id.fld_username);
            EditText password = (EditText) findViewById(R.id.fld_password);
            EditText server = (EditText) findViewById(R.id.fld_server);
            EditText tenant = (EditText) findViewById(R.id.fld_enter_org);
            String strUserName = uname.getText().toString();
            String strPwd = password.getText().toString();
            String svr = server.getText().toString();
            String ten = tenant.getText().toString();


            // hide soft keyboard after button click
            InputMethodManager inputManager = (InputMethodManager)
                    getSystemService(this.INPUT_METHOD_SERVICE);

            inputManager.hideSoftInputFromWindow((null == getCurrentFocus()) ? null : getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);


    // save username into local preferences file "MyPrefsFile" if saveLogin is checked

            CheckBox saveLogin = (CheckBox) findViewById(R.id.saveLoginCheckBox);

            if (saveLogin.isChecked()) {

                getSharedPreferences(PREFS_NAME, MODE_PRIVATE)
                        .edit()
                        .putString(USERNAME, strUserName)
                        .putString(TENANT, ten)
                        .putString(SERVER, svr)
                        .commit();
            }


    // check all input fields to make sure they have a value before executing

            if (!isValidPassword(strUserName)) {


                uname.setError("Username required");
                //finish();

            } else if (!isValidPassword(strPwd)) {

                password.setError("Password required");
                //finish();

            } else if (!isValidPassword(ten)) {

                tenant.setError("MAA Tenant ID required");
                // finish();

            } else if (!isValidPassword(svr)) {

                server.setError("Server base URL required");
                // finish();

                // Test if entered URL has connectivity
            } else if (!conn_test(svr)) {

                server.setError("URL has no connectivity");
            } else {

                // Process login request
                resText.setText("Processing...");
                resText2.setText("");
                resTextRaw.setText("");

                // All required fields have a correct value. Execute async background process to POST and GET data.
                new MyAsyncTask().execute("test");
            }


        }

        private class MyAsyncTask extends AsyncTask<String, String, String> {


            @Override
            protected String doInBackground(String... params) {
                // TODO Auto-generated method stub
                postData(GETresult);
                return null;
            }

            protected void onPostExecute(String result) {


                // Toast toast = Toast.makeText(getApplicationContext(), "Data received", Toast.LENGTH_SHORT);
                // toast.setGravity(Gravity.TOP | Gravity.RIGHT, 0, 0);
                // toast.show();

                // Appending the API call result from global string GETresult to TextViews. Parse first


                // set initial responses - input2 for parsing output if present, input3 for login errors and raw output
                String input2 = GETresult;
                String input3 = GETresult;


                // Parsing according to report type and spinner1 selection.....they all output different data
                try {

                    Spinner urls = (Spinner) findViewById(R.id.spinner1);

                    //############ USERS ##################

                    if (urls.getSelectedItem().toString().equals("Users")) {
                        input2 = input2.replaceAll("00:00:00", "").replaceAll("\"", "").replaceAll("\\],", " \n").replaceAll("\\[|\\]", "").replaceAll("\\{|\\}", "");

                        // Go through parsed input2 line by line to only get certain data from it

                        Scanner scan = new Scanner(new StringReader(input2));
                        StringBuilder sb1 = new StringBuilder();
                        StringBuilder sb2 = new StringBuilder();

                        while (scan.hasNextLine()) {

                            String line = scan.nextLine();
                           // System.out.println(line);

                            // only split on the first : delimiter (split(":",2) to preserve further constructs like 'LENOVO: avg_cpu: 35' on the same line with device performace report
                            String[] parts = line.split(",");

                            // loop throug resulting string array. check items length to avoid arrayOutOfBounds -exceptions and look for certain values only
                            // Construct semicolon separated input2 -string for display using date format found

                            SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
                            Pattern p = Pattern.compile("\\d\\d\\d\\d-\\d\\d-\\d\\d");

                            for (int i = 0; i < parts.length - 1; i++) {

                                Matcher m = p.matcher(parts[i].trim());
                                if (m.find()) {
                                    sb1.append("Date:" + parts[i] + "\n");
                                    sb1.append("Total users:" + parts[i + 1] + "\n");
                                    sb1.append("New users:" + parts[i + 2] + "\n");
                                    sb1.append("Repeat users:" + parts[i + 3] + "\n");

                                }
                            }

                            input2 = sb1.toString();
                        }


                        //############ ACTIVE USERS ##################


                    } else if (urls.getSelectedItem().toString().equals("Active Users")) {

                        input2 = input2.replaceAll("00:00:00", "").replaceAll("\"", "").replaceAll("\\],", " \n").replaceAll("\\[|\\]", "").replaceAll("\\{|\\}", "");


                        // Go through input2 to only get certain data from it

                        Scanner scan = new Scanner(new StringReader(input2));
                        StringBuilder sb1 = new StringBuilder();
                        StringBuilder sb2 = new StringBuilder();

                        while (scan.hasNextLine()) {

                            String line = scan.nextLine();
                           // System.out.println(line);

                            // only split on the first : delimiter (split(":",2) to preserve further constructs like 'LENOVO: avg_cpu: 35' on the same line with device performace report
                            String[] parts = line.split(",");

                            // loop throug resulting string array. check items length to avoid arrayOutOfBounds -exceptions and look for certain values only
                            // Construct semicolon separated input2 -string for display

                            SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
                            Pattern p = Pattern.compile("\\d\\d\\d\\d-\\d\\d-\\d\\d");

                            for (int i = 0; i < parts.length - 1; i++) {

                                Matcher m = p.matcher(parts[i].trim());
                                if (m.find()) {

                                    //  if (parts[i].matches("^*[0-9]{4}-*"))  {
                                    sb1.append(parts[i] + ":" + parts[i + 1] + "\n");


                                }
                            }

                            input2 = sb1.toString();
                        }


                        //############ SESSIONS ##################


                    } else if (urls.getSelectedItem().toString().equals("Sessions")) {
                        input2 = input2.replaceAll("00:00:00", "").replaceAll("\"", "").replaceAll("\\],", " \n").replaceAll("\\[|\\]", "").replaceAll("\\{|\\}", "").trim();


                        // Go through input2 to only get certain data from it

                        Scanner scan = new Scanner(new StringReader(input2));
                        StringBuilder sb1 = new StringBuilder();
                        StringBuilder sb2 = new StringBuilder();

                        while (scan.hasNextLine()) {

                            String line = scan.nextLine();
                            //System.out.println(line);

                            // only split on the first : delimiter (split(":",2) to preserve further constructs like 'LENOVO: avg_cpu: 35' on the same line with device performace report
                            String[] parts = line.split(",");

                            // loop throug resulting string array. check items length to avoid arrayOutOfBounds -exceptions and look for certain values only
                            // Construct semicolon separated input2 -string for display

                            SimpleDateFormat format = new SimpleDateFormat("yyyy-mm-dd");
                            Pattern p = Pattern.compile("\\d\\d\\d\\d-\\d\\d-\\d\\d");

                            for (int i = 0; i < parts.length - 1; i++) {

                                Matcher m = p.matcher(parts[i].trim());
                                if (m.find()) {

                                    //  if (parts[i].matches("^*[0-9]{4}-*"))  {
                                    sb1.append(parts[i] + ":" + parts[i + 2] + "\n");


                                }
                            }

                            input2 = sb1.toString();
                        }


                        //############ REGISTERED APPS ##################


                    } else if (urls.getSelectedItem().toString().equals("Registered Apps")) {
                        // not a valid JSON object, so just parse the whole result
                        input2 = input2.replaceAll("appId", "Application name").replaceAll("\",", " \n").replaceAll("\"", "").replaceAll(",", " \n").replaceAll("\\[|\\]", "").replaceAll("\\{|\\}", "").replaceAll("_", " ");

                        // Go through input2 to only get appId data from it

                        Scanner scan = new Scanner(new StringReader(input2));
                        StringBuilder sb1 = new StringBuilder();
                        StringBuilder sb2 = new StringBuilder();

                        while (scan.hasNextLine()) {

                            String line = scan.nextLine();
                            // System.out.println(line);

                            // only split on the first : delimiter (split(":",2) to preserve further constructs like 'LENOVO: avg_cpu: 35' on the same line with device performace report
                            String[] parts = line.split(":", 2);

                            // loop throug resulting string array. check items length to avoid arrayOutOfBounds -exceptions and look for certain values only

                            final Set<String> values = new HashSet<String>(Arrays.asList("Application name", "status", "secure", "state"));
                            for (int i = 0; i < parts.length - 1; i++) {

                                if (values.contains(parts[i])) {
                                    sb1.append(parts[i] + ":" + (parts[i + 1] + "\n"));

                                }
                            }

                            input2 = sb1.toString();
                        }

                        //############ APP PERFORMANCE ##################

                    } else if (urls.getSelectedItem().toString().equals("App Performance")) {
                        JSONObject jObject = new JSONObject(GETresult);
                        input2 = jObject.getString("averages");
                        input2 = input2.replaceAll("],", "\n").replaceAll("\\[|\\]", "").replaceAll("00:00", "00").replaceAll("\\{|\\}", "").replace("\"", "").replaceAll(",", "\n").replaceAll("_", " ");

                        //############ DEVICE PERFORMANCE ##################

                    } else if (urls.getSelectedItem().toString().equals("Device Performance")) {
                        JSONObject jObject = new JSONObject(GETresult);
                        input2 = jObject.getString("result");
                        input2 = input2.replaceAll("],", "\n").replaceAll("\\[|\\]", "").replaceAll("\\{|\\}", "").replace("\"", "").replaceAll(",", "\n").replaceAll("_", " ");

                        //############ ACTIVITY BY GEO ##################

                    } else if (urls.getSelectedItem().toString().equals("Activity by Geo")) {
                        JSONObject jObject = new JSONObject(GETresult);
                        input2 = jObject.getString("countries");
                        input2 = input2.replaceAll("],", "\n").replaceAll("\\[|\\]", "").replaceAll("\\{|\\}", "").replace("\"", "").replaceAll(",", ":");

                        //############ CRASH SUMMARY ##################
                    } else if (urls.getSelectedItem().toString().equals("Crash Summary")) {
                        JSONObject jObject = new JSONObject(GETresult);
                        input2 = jObject.getString("total_summary");
                        // Among other things, replace 00:00 time constructs with 00 to make splitting easier
                        input2 = input2.replaceAll("],", "\n").replaceAll("00:00", "00").replaceAll("\\[|\\]", "").replaceAll("\\{|\\}", "").replace("\"", "").replaceAll(",", "\n").replaceAll("_", " ");

                        //############ CRASH SUMMARY BY APPS ##################
                    } else if (urls.getSelectedItem().toString().equals("Crash Summary by Apps")) {
                        JSONObject jObject = new JSONObject(GETresult);
                        input2 = jObject.getString("result");
                        input2 = input2.replaceAll("\\],", "\n").replaceAll("\\[|\\]", "").replace("\"", "").replace(",", ":").replaceAll("_", " ");

                        //############ OTHER ##################
                    } else {
                        // just show input without parsing
                        input2 = input2.replaceAll("\\],", "\n").replaceAll("\\[|\\]", "").replace("\"", "").replace(",", ": ").replaceAll("_", " ");
                    }

                } catch (JSONException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }

                // comment out debug messages
                // System.out.print("OUTPUT: "+input2);

                // parse error message if there
                input3 = input3.replaceAll("\\{|\\}", "").replace("\"", "").replace(",", ": ").replaceAll("_", " ");
                // if actual responseis empty, use error message
                if (input2.length() < 1) input2 = input3;

    // scan the input string line by line and separate tokens into two text views for clarity


                Scanner scan = new Scanner(new StringReader(input2));
                StringBuilder sb1 = new StringBuilder();
                StringBuilder sb2 = new StringBuilder();

                while (scan.hasNextLine()) {

                    String line = scan.nextLine();
                    // only split on the first : delimiter (split(":",2) to preserve further constructs like 'LENOVO: avg_cpu: 35' on the same line with device performace report
                    String[] parts = line.split(":", 2);

                    // loop throug resulting string array. check items length to avoid arrayOutOfBounds -exceptions for empty ones
                    for (int i = 0; i < parts.length - 1; i++) {

                        sb1.append(parts[i].trim() + "\n");
                        sb2.append(parts[i + 1].trim() + "\n");

                    }

                }


                TextView resText1 = (TextView) findViewById(R.id.txtResult);
                TextView resText2 = (TextView) findViewById(R.id.txtResult2);
                TextView resTextRaw = (TextView) findViewById(R.id.txtResultRaw);


                //Display raw or parsed output depending on user selection

                CheckBox rawOutput = (CheckBox) findViewById(R.id.rawOutputCheckBox);


                Typeface myCA = Typeface.createFromAsset(getAssets(), "fonts/CA Sans-Bold.ttf");
                rawOutput.setTypeface(myCA);

                if (rawOutput.isChecked()) {
                    resTextRaw.setText(GETresult);
                    resText1.setText("");
                } else {

                    resText1.setText(sb1);
                    resText2.setText(sb2);
                     resTextRaw.setText("");
                }

            }

            public String postData(String valueIWantToSend) {

                // execute the httpClient requests in sequence: first POST to get token, and GET to get data

                EditText uname = (EditText) findViewById(R.id.fld_username);
                EditText password = (EditText) findViewById(R.id.fld_password);
                EditText server = (EditText) findViewById(R.id.fld_server);
                EditText tenant = (EditText) findViewById(R.id.fld_enter_org);

                String username = uname.getText().toString();
                String pwd = password.getText().toString();
                String targeturl = server.getText().toString();
                String org = tenant.getText().toString();

    // POST first to get Basic token - base64 encode
                String POSTtarget = targeturl + "/ess/security/v1/token";
                String headerOrg = new String("Basic " + Base64.encodeToString(org.getBytes(), Base64.NO_WRAP));
                //System.out.println(headerOrg);

                try {
                    // Create a new HttpClient
                    HttpClient httpclient = new DefaultHttpClient();
                    HttpPost httppost = new HttpPost(POSTtarget);

                    // Add your headers with tenant base64 authorization

                    httppost.setHeader("Content-type", "application/x-www-form-urlencoded");
                    httppost.setHeader("Authorization", headerOrg);
                    httppost.setHeader("Cache-Control", "no-cache");

                    // pass the body of the request as a String entity
                    String myPayload = ("username=" + username + "&password=" + pwd + "&grant_type=PASSWORD");
                    HttpEntity entity = new ByteArrayEntity(myPayload.getBytes("UTF-8"));

                    httppost.setEntity(entity);

                    // Execute HTTP Post Request
                    HttpResponse response = httpclient.execute(httppost);
                   // System.out.println(response);

                    // read response line by line to string builder to build a json object for parsing

                    BufferedReader br = new BufferedReader(new InputStreamReader(
                            (response.getEntity().getContent())));
                    StringBuilder sb = new StringBuilder();
                    String output;
                  //  System.out.println("Output from Server .... \n");
                    while ((output = br.readLine()) != null) {
                        //System.out.println(output);
                        sb.append(output + "\n");

                    }
                    String result = sb.toString();

                    // set initial response in case failures - this will output if login fails or something else goes wrong with the authorization
                    GETresult = result;

                    String bearerTkn = null;
                    String errTkn = null;

                    try {

                        JSONObject jObject = new JSONObject(result);
                        // get access token by parsing the JSON object tkn -value

                        bearerTkn = jObject.getString("tkn");

                        //System.out.println("tkn " + bearerTkn);


                    } catch (JSONException je) {
                        je.printStackTrace();
                    }


                    // Build Bearer token and encode it

                    String bearerToken = "{\"tkn\":\"" + bearerTkn + "\",\"all\":\"true\"}";
                    String headerAz = new String("Bearer " + Base64.encodeToString(bearerToken.getBytes(), Base64.NO_WRAP));
                    //System.out.println("Bearer " + headerAz);


                    // get a reference to selected period from spinner2
                    Spinner periods = (Spinner) findViewById(R.id.spinner1_new);
                    String period_ext = periods.getSelectedItem().toString();

                    // Get a reference to the selected report spinner1

                    Spinner urls = (Spinner) findViewById(R.id.spinner1);
                    String url_ext = null;

                    // Build correct URL extension for each report

                    if (urls.getSelectedItem().toString().equals("Registered Apps"))
                        url_ext = "/mdo/v1/apps";
                    else if (urls.getSelectedItem().toString().equals("App Performance"))
                        url_ext = "/mdo/v1/performance/apps";
                        // else if (urls.getSelectedItem().toString().equals("URL Performance"))
                        //     url_ext = "/mdo/v1/performance/urls";
                        //   else if (urls.getSelectedItem().toString().equals("Carrier Performance"))
                        //       url_ext = "/mdo/v1/performance/carrier";
                    else if (urls.getSelectedItem().toString().equals("Device Performance"))
                        url_ext = "/mdo/v1/performance/devices";
                    else if (urls.getSelectedItem().toString().equals("Error Codes"))
                        url_ext = "/mdo/v1/performance/errorcodes";
                        // else if (urls.getSelectedItem().toString().equals("App Summary"))
                        //     url_ext = "/mdo/v1/performance/apps_summary";
                    else if (urls.getSelectedItem().toString().equals("Users"))
                        url_ext = "/mdo/v1/usage/users";
                    else if (urls.getSelectedItem().toString().equals("Active Users"))
                        url_ext = "/mdo/v1/usage/active_users";
                    else if (urls.getSelectedItem().toString().equals("Sessions"))
                        url_ext = "/mdo/v1/usage/sessions";
                    else if (urls.getSelectedItem().toString().equals("Activity by Geo"))
                        url_ext = "/mdo/v1/usage/geo";
                    else if (urls.getSelectedItem().toString().equals("Crash Summary"))
                        url_ext = "/mdo/v1/crashes/crash_summary";
                    else if (urls.getSelectedItem().toString().equals("Crash Summary by Apps"))
                        url_ext = "/mdo/v1/crashes/crash_summary_by_apps";

                    else url_ext = urls.getSelectedItem().toString();

                    // Get start date of -30, -7 and -1 days ago. Construct filter URL extension for aggregation and start / end accordingly

                    Calendar cal = Calendar.getInstance();
                    DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                    cal.add(Calendar.DATE, +1);
                    String today = String.valueOf(dateFormat.format(cal.getTime()));
                    cal.add(Calendar.DATE, -1);
                    String yesterday = String.valueOf(dateFormat.format(cal.getTime()));
                    cal.add(Calendar.DATE, -7);
                    String week = String.valueOf(dateFormat.format(cal.getTime()));
                    cal.add(Calendar.DATE, -30);
                    String month = String.valueOf(dateFormat.format(cal.getTime()));


                    String p = null;

                    // build the correct period URL extensions for monthly, weekly and daily reports
                    if (period_ext.equals("Month")) {
                        p = "?aggregation=month&end_date=" + today + "&start_date=" + month;
                       // System.out.println("Fetching data for month: end_date=" + today + ", start_date=" + month);
                    } else if (period_ext.equals("Week")) {
                        p = "?aggregation=week&end_date=" + today + "&start_date=" + week;
                       // System.out.println("Fetching data for last 7 days");
                    } else if (period_ext.equals("Day")) {
                        p = "?aggregation=day&end_date=" + today + "&start_date=" + yesterday;
                       // System.out.println("Fetching data for last 24 hours");
                    } else p = "?aggregation=month&end_date=" + today + "&start_date=" + month;

                    //System.out.println(p);

                    // Build complete GET URLkopja02

                    String GETtarget = targeturl + url_ext + p;
                   // System.out.println(GETtarget);


                    // Create a new HttpClient and Post Header
                    HttpClient httpclient2 = new DefaultHttpClient();
                    HttpGet httpget = new HttpGet(GETtarget);

                    //httppost2.setHeader("Content-type", "application/x-www-form-urlencoded");
                    httpget.setHeader("Authorization", headerAz);
                    httpget.setHeader("Cache-Control", "no-cache");
                    httpget.setHeader("Accept", "Application/json");
                    // Execute HTTP Post Request
                    HttpResponse response2 = httpclient.execute((httpget));
                   // System.out.println(response2);

                    // read response line by line to string builder to build a json object for parsing

                    BufferedReader br2 = new BufferedReader(new InputStreamReader(
                            (response2.getEntity().getContent())));

                    StringBuilder sb2 = new StringBuilder();
                    String output2;
                  //  System.out.println("GET Output from Server .... \n");
                    while ((output2 = br2.readLine()) != null) {
                        //System.out.println(output2);
                        sb2.append(output2 + "\n");

                    }

                    String result2 = sb2.toString();
                    //System.out.print(result2);


                    GETresult = result2;


                } catch (ClientProtocolException e) {
                    e.printStackTrace();
                } catch (IOException e) {

                    // } catch (JSONException e) {
                    e.printStackTrace();
                }

                return GETresult;

            }


        }

        // ######### validate username etc fields to make sure they contain characters #########

        private boolean isValidPassword(String pass) {
            if (pass != null && pass.length() > 0 && !pass.equals("")) {
                return true;
            }
            return false;
        }


        //################# check URL connectio #############


        public boolean conn_test(String URL) {

            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();

            StrictMode.setThreadPolicy(policy);

            EditText server = (EditText) findViewById(R.id.fld_server);
            String targeturl = server.getText().toString();

            boolean res = false;

            String POSTtarget = targeturl + "/admin/maa";
          //  System.out.println(POSTtarget);
            try {
                URL url = new URL(POSTtarget);
                URLConnection conn = url.openConnection();
                conn.setConnectTimeout(5000);
                conn.connect();
                res = true;
            } catch (Exception e) {
                res = false;
                //System.out.println("can't connect / " + e.toString());
            }
            return res;
        }

        //###############


    }

     

     

    //### END END END  #################################



  • 4.  Re: Tech Tip - CA Mobile App Analytics: MAA Reporting API Example

    Broadcom Employee
    Posted Sep 02, 2015 12:12 PM

    Activity_main.xml

     

    // ##########

     

     

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        xmlns:ndroid="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView android:id="@+id/fillBkg"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:background="#0066CC"
            />

        <TextView android:id="@+id/txtBkg"
            android:layout_width="400dp"
            android:layout_height="130dp"
            android:layout_marginTop="10dp"
            android:layout_marginLeft="2dp"
            android:layout_marginStart="2dp"
            android:background="#00246B"
            />


        <TextView android:id="@+id/txtLogin"

            android:text="@string/lbl_username"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="20dp"
            android:layout_marginLeft="12dp"
            android:layout_marginStart="12dp"
            android:textColor="#FFFFFF"
            android:textSize="20sp"
           />

        <LinearLayout android:id="@+id/uname_block"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/txtLogin"
            android:layout_margin="5dp"
           android:orientation="horizontal">


            <EditText
                android:id="@+id/fld_username"
                android:layout_width="120dp"
                android:layout_height="30dp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:hint="@string/lbl_enter_username"
                android:textColor="#000052"
                android:background="@drawable/borders"
                android:textSize="12sp"
                />

            <EditText
                android:id="@+id/fld_password"
                android:layout_width="120dp"
                android:layout_height="30dp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:hint="@string/lbl_enter_password"
                android:inputType="textPassword"
                android:textColor="#000052"
                android:background="@drawable/borders"
                android:textSize="12sp"
                />

            <EditText
                android:id="@+id/fld_enter_org"
                android:layout_width="120dp"
                android:layout_height="30dp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:hint="@string/lbl_enter_org"
                android:textColor="#000052"
                android:background="@drawable/borders"
                android:textSize="12sp"
                />


        </LinearLayout>

        <LinearLayout android:id="@+id/ip_block"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@id/uname_block"
            android:layout_margin="5dp"
            android:orientation="horizontal">

     

            <EditText
                android:id="@+id/fld_server"
                android:layout_width="170dp"
                android:layout_height="30dp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:hint="@string/lbl_enter_server"
                android:textColor="#000052"
                android:background="@drawable/borders"
                android:textSize="12sp"
                     />

            <CheckBox
                android:id="@+id/saveLoginCheckBox"
                android:layout_width="fill_parent"
                android:layout_height="fill_parent"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:layout_marginLeft="30dp"
                android:layout_marginStart="30dp"
                android:layout_below="@+id/editTextPassword"
                android:text="@string/lbl_saveLogin"
                android:checked="true"
                android:visibility="visible"
                android:textSize="13sp"
                android:textColor="#FFF" />

        </LinearLayout>


        <LinearLayout android:id="@+id/spinner_block_new"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:layout_marginTop="20dp"
            android:layout_below="@id/ip_block"
            android:orientation="horizontal">


            <TextView android:id="@+id/fls_spinner_new"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:textColor="#FFFFFF"
                android:textSize="12sp"
                />

     

            <Spinner
                android:id="@+id/spinner1_new"
                android:layout_width="100dp"
                android:layout_height="wrap_content"
                android:textAlignment="center"
                android:layout_margin="10dp"
                android:fastScrollEnabled="true"
                android:entries="@array/report_period"
                 />

            <Spinner
                android:id="@+id/spinner1"
                android:layout_width="240dp"
                android:layout_height="wrap_content"
                android:textAlignment="center"
                android:layout_margin="10dp"
                android:fastScrollEnabled="true"
                android:entries="@array/url_arrays"
                 />
        </LinearLayout>

        <CheckBox
            android:id="@+id/rawOutputCheckBox"
            android:layout_below="@id/spinner_block_new"
            android:layout_width="150dp"
            android:layout_height="20dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:layout_marginLeft="10dp"
            android:layout_marginStart="10dp"
            android:layout_alignParentLeft="true"
            android:text="@string/lbl_rawOutput"
            android:visibility="visible"
            android:textSize="13sp"
            android:textColor="#FFF" />


        <LinearLayout android:id="@+id/button_block"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_below="@+id/spinner_block_new"
            android:layout_centerVertical="true"
            android:layout_margin="5dp"
            android:orientation="horizontal">


        <Button
            android:id="@+id/button1"
            android:layout_width="380dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="24dp"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:text="@string/lbl_btnSubmit"
            android:textColor="#FFFFFF"
            android:background="#19A347"
                 />

        </LinearLayout>

        <ScrollView android:id="@+id/scrollView1"
        android:layout_width="fill_parent"
            android:layout_below="@+id/button_block"
        android:layout_height="wrap_content" >


        <LinearLayout
            android:orientation="horizontal"
            android:layout_below="@+id/button_block"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal">


        <TextView android:id="@+id/txtResult"
            android:layout_width="180dp"
            android:layout_height="fill_parent"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:layout_marginLeft="10dp"
            android:layout_marginStart="10dp"
            android:scrollHorizontally="true"
            android:background="#0066CC"
            android:textColor="#FFFFFF"
            android:layout_marginTop="20dp"
            android:textSize="14sp"
            android:ellipsize="end"
            android:textIsSelectable="true"
        />


            <TextView android:id="@+id/txtResult2"
                android:layout_width="180dp"
                android:layout_height="match_parent"
                android:maxWidth="190dp"
                android:paddingLeft="5dp"
                android:paddingRight="5dp"
                android:layout_marginLeft="10dp"
                android:layout_marginStart="10dp"
                android:scrollHorizontally="true"
                 android:background="#0066CC"
                android:textColor="#FFFFFF"
                android:layout_marginTop="20dp"
                android:textSize="14sp"
                android:ellipsize="end"
                android:textIsSelectable="true"
                />

     

        </LinearLayout>

        </ScrollView>

        <ScrollView android:id="@+id/scrollView2"
            android:layout_width="wrap_content"
            android:layout_below="@+id/button_block"
            android:layout_height="wrap_content" >

        <TextView android:id="@+id/txtResultRaw"
            android:layout_width="wrap_content"
            android:layout_below="@+id/scrollView1"
            android:layout_height="wrap_content"
            android:paddingLeft="5dp"
            android:paddingRight="5dp"
            android:layout_marginLeft="10dp"
            android:layout_marginStart="10dp"
            android:layout_marginRight="10dp"
            android:scrollHorizontally="true"
            android:background="#0066CC"
            android:textColor="#FFFFFF"
              android:textSize="14sp"
            android:ellipsize="end"
            android:textIsSelectable="true"
            />

        </ScrollView>

    </RelativeLayout>

     

    //######### END END END ###########



  • 5.  Re: Tech Tip - CA Mobile App Analytics: MAA Reporting API Example

    Broadcom Employee
    Posted Sep 02, 2015 12:14 PM
      |   view attached

    Attached the apk files, mail me at kopja02@ca.com with any feedback Also, I've got a java command line executable for consuming the CA MAA web services, if someone is interested

    Attachment(s)

    zip
    apk.zip   3.07 MB 1 version


  • 6.  Re: Tech Tip - CA Mobile App Analytics: MAA Reporting API Example

    Broadcom Employee
    Posted Sep 14, 2015 05:08 AM

    Hi

     

    Here also an example from Xcode (swift). I'm only posting the view controller.swift - if someone wants the complete project, let me know

     

    //"""""""""""""""""""""""

     

    //

    //  ViewController.swift

    //  MAAData

    //

    //  Created by J Koponen on 04/09/2015.

    //  Copyright (c) 2015 J Koponen. All rights reserved.

    //

     

    import UIKit

    class ViewController: UIViewController {

       

        @IBOutlet weak var pvPeriod: UIPickerView!

        @IBOutlet weak var pvReports: UIPickerView!

        @IBOutlet weak var btnSubmit: UIButton!

        @IBOutlet weak var txtResult: UITextView!

        @IBOutlet weak var lblLogin: UILabel!

        @IBOutlet weak var txtUser: UITextField!

        @IBOutlet weak var txtPassword: UITextField!

        @IBOutlet weak var txtTenant: UITextField!

        @IBOutlet weak var txtURL: UITextField!

       

        // initialise pickers using custom UIpicker swift classes

       

      private var delReportTypes = reportTypes()

        private var delReportPeriods = reportPeriods()

     

     

        override func viewDidLoad() {

            super.viewDidLoad()

            // Do any additionl setup such as button background color

           

            btnSubmit.backgroundColor = UIColor(red: 0.4, green: 1.0, blue: 0.2, alpha: 0.5)

           

        // add content to pickers

           

          pvReports.dataSource = delReportTypes

          pvReports.delegate = delReportTypes

            pvPeriod.dataSource = delReportPeriods

          pvPeriod.delegate = delReportPeriods

        }

     

        override func didReceiveMemoryWarning() {

            super.didReceiveMemoryWarning()

            // Dispose of any resources that can be recreated.

           

         }

       

        // '''''''''' REST CALL START

       

        // Async REST call function

        @IBAction func fetchResult() {

     

            // Disable the button until we're done

            self.btnSubmit.enabled = false

       

            // set up the base64-encoded credentials using tenant ID

            let username =  self.txtUser.text

            let password = self.txtPassword.text

            let tenant = self.txtTenant.text

            let URLbase = self.txtURL.text

           

            // Check that username etc has been entered before proceeding

           

            if self.txtUser.text == ""  {

               

                txtResult.text = "Please enter username"

                self.btnSubmit.enabled = true

               

            } else if self.txtPassword.text == ""  {

               

                txtResult.text = "Please enter password"

                self.btnSubmit.enabled = true

               

            }

               

            else if self.txtTenant.text == ""  {

               

                txtResult.text = "Please enter tenant ID"

                self.btnSubmit.enabled = true

               

            }

               

            else if self.txtURL.text == ""  {

               

                txtResult.text = "Please enter CA MAA URL"

                self.btnSubmit.enabled = true

               

            }

           

           

            else { //  proceed with REST calls

               

                // construct security token URL

                let url : NSURL! = NSURL(string: "\(URLbase)/ess/security/v1/token")

               

                let request = NSMutableURLRequest(URL: url)

               

                // Encode the tenant ID as authorization

           

            let loginString = NSString(format: "%@", tenant)

            let loginData: NSData! = loginString.dataUsingEncoding(NSUTF8StringEncoding)

            let base64LoginString = loginData.base64EncodedStringWithOptions(nil)

           

            // ADD HEADERS AND PAYLOAD

       

     

            request.HTTPMethod = "POST"

            request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")

             request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")

           

            var bodyData = "username=\(username)&password=\(password)&grant_type=PASSWORD"

            request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);

          

            txtResult.text = "Basic \(base64LoginString)"

           

            var output = "Processing request";

     

            // we want to dispatch our code back to the Main queue so that we

            // can update the UI

            let q = NSOperationQueue.mainQueue()

           

          

            // Change the colour of the Content text to a red colour

            txtResult.textColor = UIColor(red: 1.0, green: 0, blue: 0.2, alpha: 1.0)

           

            // Issue the HTTP REST API call on a background thread.

          

            NSURLConnection.sendAsynchronousRequest(request, queue: q, completionHandler: {(response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in

               

                // Get initial output as string and check if it contains a security token or an error

               

                output = (NSString(data: data, encoding: NSUTF8StringEncoding))! as String

                println(output)

               

                var token: String

               

                if output.rangeOfString("tkn") != nil {

       

                // token exists in output - Get response as JSON and find the value

               

    var responseDict: NSDictionary = NSJSONSerialization.JSONObjectWithData(data,options: NSJSONReadingOptions.MutableContainers, error:nil) as! NSDictionary

               

               

                token = responseDict["tkn"] as! String

               

                } else {

               

                    // token not retrieved - use phony one that induces a login error - display the error

                   

                token = "Security token not found"

                }

        

                // print auth token or message for debug purposes

               

                println(token)

               

                // GOT AUTH TOKEN, CONSTRUCT BEARER TOKEN and URL, AND RUN REPORT

               

                // First get the selected report type and period from pickers

               

                var report: String = self.delReportTypes.reportName

                var period: String = self.delReportPeriods.reportPeriod

               

                // initialize url extension variables with default values

               

                var URLext : String  = "/mdo/v1/apps?aggregation="

                var URLperiod : String  = "month&end_date=2015-09-10&start_date=2015-08-01"

               

                // get report URL from class reportTypes, function getExt

             

               URLext = self.delReportTypes.getExt(report)

               

                // get period filtering URL extension from function getPeriod

               

                URLperiod = self.delReportPeriods.getPeriod(period)

               

                //construct the full request URL

               

                var url2 : NSURL! = NSURL(string: "\(URLbase)\(URLext)\(URLperiod)")

               

                   

                // initialize URL and construct Bearer token using base64

               

                let request2 = NSMutableURLRequest(URL: url2)

                let bearerToken = "{\"tkn\":\"\(token)\",\"all\":\"true\"}"

               

                // initialize output string var

                var output2 = "Processing request";

               

               

                let loginData2: NSData! = bearerToken.dataUsingEncoding(NSUTF8StringEncoding)

                let base64LoginString2 = loginData2.base64EncodedStringWithOptions(nil)

               

                // print constructed base 64 bearer token for debug purposes

                println("Bearer \(base64LoginString2)")

               

               

                // ADD HEADERS AND PAYLOAD

               

                request2.HTTPMethod = "GET"

                request2.setValue("Bearer \(base64LoginString2)", forHTTPHeaderField: "Authorization")

            

                request2.setValue("Application/json", forHTTPHeaderField: "Accept")

                request2.setValue("Cache-Control", forHTTPHeaderField: "no-cache")

               

                // Perform async request

      

                NSURLConnection.sendAsynchronousRequest(request2, queue: q, completionHandler: {(response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in

                   

     

                   

                    // Capture String output and parse it - needs work !!

                   

                   output2 = (NSString(data: data, encoding: NSUTF8StringEncoding))! as String

                    output2 = output2.stringByReplacingOccurrencesOfString("\"", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)

                    output2 = output2.stringByReplacingOccurrencesOfString("],", withString: "\n", options: NSStringCompareOptions.LiteralSearch, range: nil)

                    output2 = output2.stringByReplacingOccurrencesOfString("[", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)

                    output2 = output2.stringByReplacingOccurrencesOfString("]", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil)

                   

                    // display output in main display

                   

                self.txtResult.text = output2

               

               

                //  end end enable button again

               

                self.btnSubmit.enabled = true

               

               

                })

                })

                }}}