Added tutorial for portal-sdk apps
[portal.git] / docs / tutorials / portal-sdk / pulling-db-data.rst
1 Pulling DB data
2 ===============
3
4 In the :ref:`connectionjava` section, we set up a connection to the :code:`ecomp_sdk` database. Now, we going to use our AngularJS controller (:code:`controller.js`) and data service (:code:`data-service.js`) to make an HTTP request to our Spring controller (:code:`MyAppController.java`), wait for the results, and map them into a Google Chart.
5
6 AngularJS Promises
7 ----------------------
8
9 "Promises" are a core feature of AngularJS, and whether you fully understand them or not, you will be using them in your applications. Promises use AJAX (Asynchronous JavaScript and XML -- you can also use JSON). When we make a call to a web server for some data, we don't want our application to become unresponsive while we wait for an answer. Therefore, :code:`$http.get` calls (more in a minute), return a Promise object rather than text from the web server. Then, we make sure that the Promise object does the right thing at the right time by assigning callback functions when the web server either returns results or fails to return a result. Something like this:
10
11 .. code-block:: javascript
12
13   var p = $http.get("http://somedomain.com/some_request");
14   
15   p.success(function(result) {
16     console.log("The web server returned: " + result);
17   });
18   
19   p.error(function(response, status) {
20     console.log("The web server returned:\n\tStatus: " + status + "\n\tError: " + response);
21   });
22
23 Here, AJAX (via the AngularJS module :code:`$http`) makes a request to :code:`somedomain.com/some_request`. Our JavaScript engine immediately then moves to assign anonymous functions as callbacks for success and error conditions. Then, when the web server finally returns a result, the callbacks are run. 
24
25 Data service
26 ------------
27
28 Our special function in :code:`data-service.js` uses Promises. We make sure to execute code in the correct order by using the :code:`then` Promise function.
29
30 Something like this:
31
32 .. code-block:: javascript
33
34   $scope.myFunction = function() {
35     dataService.getSomeData().then(function(rv) {
36       // Do something here.
37     });
38   }
39
40 Here, :code:`getSomeData` returns a Promise object. The :code:`then` function tells the JavaScript engine to execute the given anonymous function only after the request has completed.
41
42 Technically, the :code:`then` function takes two functions as arguments. The first defines what to do upon success, and the second defines what to do upon failure. We omitted the failure argument above.
43
44 Here is our :code:`data-service.js` code:
45
46 .. code-block:: javascript
47
48   appDS2.factory('dataService', function ($http, $q, $log) {
49     return {
50       // Service to return chart data
51       getChartData: function(direction) {
52         return $http.get("get_chart_data/" + direction + "/").then(function(response) {
53           if (typeof response.data === 'object' || typeof response.data === 'string') {
54             return response.data;
55           }
56           else {
57             return $q.reject(response.data);
58           }
59         }, function(response) {
60           return $q.reject(response.data);
61         })
62       }
63     };
64   });
65
66 The syntax of this function is not immediately obvious unless you are comfortable with JavaScript Promises and Deferreds. For a more complete explanation with examples, check out `this blog post <http://chariotsolutions.com/blog/post/angularjs-corner-using-promises-q-handle-asynchronous-calls/>`_.
67
68 Essentially, our service definition is a super-concise JavaScript way to allow this from within our controller:
69
70 .. code-block:: javascript
71
72   dataService.getChartData(direction).then(function(rv) {
73     // Do something here
74   });
75
76 Behind the scenes, this makes an :code:`HTTP` request that looks like this:
77
78 :code:`http://localhost:8080/epsdk-app-os/get_chart_data/<direction>/`
79
80 where :code:`direction` is either "upload" or "download" and returns the result back to our controller as JSON text, which we'll convert into a JavaScript object for further processing.
81
82 Modifying our Spring controller
83 -------------------------------
84
85 Let's add a couple of functions to our Spring controller, :code:`MyAppController.java`:
86
87 .. code-block:: java
88   
89   @RequestMapping(value = {"/get_chart_data/{direction}/"}, method = RequestMethod.GET)
90   public void getChartData(@PathVariable("direction") String direction, HttpServletRequest request, HttpServletResponse response){
91     try {
92       Object a = _getChartData(direction);
93       response.getWriter().write(a.toString());
94     } catch (IOException e) {
95       // Probably should do something here ;-)
96     }
97   }
98
99   private Object _getChartData(String direction) {
100     ArrayList<JSONObject> allData = new ArrayList<JSONObject>();
101     JdbcTemplate jdbcTempl = new JdbcTemplate(m_dataSources.get("myappdb"));
102
103     // Check our parameter
104     if (!direction.equals("download") && !direction.equals("upload"))
105       direction = "download";
106     }
107
108     String query = "select data_date, speedmbps, direction from mock_data_avg_speed where direction='" + direction + "' order by data_date asc";
109
110     List<Map<String,Object>> out = jdbcTempl.queryForList(query);
111     for (Map<String,Object> row: out) {
112       JSONObject jo = new JSONObject();
113       jo.put("data_date", row.get("data_date"));
114       jo.put("speedmbps", row.get("speedmbps"));
115       jo.put("direction", row.get("direction"));
116       allData.add(jo);
117     }
118
119     return allData;
120   }
121
122 Testing our changes
123 -------------------
124
125 To test our database connection, first compile and install the war as in the :ref:`installingyourapp` section. Next, `login`_. Now try the `following URL`_:
126
127 ::
128
129   http://localhost:8080/epsdk-app-os/get_chart_data/download/
130
131 .. note:: Using the trailing '/' character can prevent confusion with AngularJS routing. It might not always be necessary, but it is good practice to use it in this context to prevent headaches later on.
132
133 If everything went as planned, you should see:
134
135 ::
136
137   [{"speedmbps":40,"data_date":"2017-08-01","direction":"download"}, {"speedmbps":18,"data_date":"2017-08-02","direction":"download"}, {"speedmbps":25,"data_date":"2017-08-03","direction":"download"}, {"speedmbps":48,"data_date":"2017-08-04","direction":"download"}, {"speedmbps":49,"data_date":"2017-08-05","direction":"download"}, {"speedmbps":46,"data_date":"2017-08-06","direction":"download"}, {"speedmbps":35,"data_date":"2017-08-07","direction":"download"}]
138
139 This is what makes JSON such a powerful tool. We'll take that JSON output and convert it into JavaScript objects in order to build our chart.
140
141 .. _following URL: http://localhost:8080/epsdk-app-os/get_chart_data/download/
142 .. _login: http://localhost:8080/epsdk-app-os/login.htm