1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  *   http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  */
19 
20 #include <stdio.h>
21 #include <glib-object.h>
22 
23 #include <thrift/c_glib/protocol/thrift_binary_protocol.h>
24 #include <thrift/c_glib/transport/thrift_buffered_transport.h>
25 #include <thrift/c_glib/transport/thrift_socket.h>
26 
27 #include "gen-c_glib/calculator.h"
28 
main(void)29 int main (void)
30 {
31   ThriftSocket *socket;
32   ThriftTransport *transport;
33   ThriftProtocol *protocol;
34   CalculatorIf *client;
35 
36   GError *error = NULL;
37   InvalidOperation *invalid_operation = NULL;
38 
39   Work *work;
40 
41   gint32 sum;
42   gint32 diff;
43 
44   int exit_status = 0;
45 
46 #if (!GLIB_CHECK_VERSION (2, 36, 0))
47   g_type_init ();
48 #endif
49 
50   socket    = g_object_new (THRIFT_TYPE_SOCKET,
51                             "hostname",  "localhost",
52                             "port",      9090,
53                             NULL);
54   transport = g_object_new (THRIFT_TYPE_BUFFERED_TRANSPORT,
55                             "transport", socket,
56                             NULL);
57   protocol  = g_object_new (THRIFT_TYPE_BINARY_PROTOCOL,
58                             "transport", transport,
59                             NULL);
60 
61   thrift_transport_open (transport, &error);
62 
63 
64   /* In the C (GLib) implementation of Thrift, service methods on the
65      server are accessed via a generated client class that implements
66      the service interface. In this tutorial, we access a Calculator
67      service through an instance of CalculatorClient, which implements
68      CalculatorIf. */
69   client = g_object_new (TYPE_CALCULATOR_CLIENT,
70                          "input_protocol",  protocol,
71                          "output_protocol", protocol,
72                          NULL);
73 
74   /* Each of the client methods requires at least two parameters: A
75      pointer to the client-interface implementation (the client
76      object), and a handle to a GError structure to receive
77      information about any error that occurs.
78 
79      On success, client methods return TRUE. A return value of FALSE
80      indicates an error occurred and the error parameter has been
81      set. */
82   if (!error && calculator_if_ping (client, &error)) {
83     puts ("ping()");
84   }
85 
86   /* Service methods that return a value do so by passing the result
87      back via an output parameter (here, "sum"). */
88   if (!error && calculator_if_add (client, &sum, 1, 1, &error)) {
89     printf ("1+1=%d\n", sum);
90   }
91 
92   /* Thrift structs are implemented as GObjects, with each of the
93      struct's members exposed as an object property. */
94   work = g_object_new (TYPE_WORK, NULL);
95 
96   if (!error) {
97     g_object_set (work,
98                   "num1", 1,
99                   "num2", 0,
100                   "op",   OPERATION_DIVIDE,
101                   NULL);
102 
103     /* Exceptions are passed back from service methods in a manner
104        similar to return values. */
105     if (calculator_if_calculate (client,
106                                  NULL,
107                                  1,
108                                  work,
109                                  &invalid_operation,
110                                  &error)) {
111       puts ("Whoa? We can divide by zero!");
112     }
113     else {
114       if (invalid_operation) {
115         gchar *why;
116 
117         /* Like structs, exceptions are implemented as objects with
118            properties. */
119         g_object_get (invalid_operation, "why", &why, NULL);
120 
121         printf ("InvalidOperation: %s\n", why);
122 
123         if (why != NULL)
124           g_free (why);
125         g_object_unref (invalid_operation);
126         invalid_operation = NULL;
127       }
128 
129       g_clear_error (&error);
130     }
131   }
132 
133   if (!error) {
134     /* Struct objects can be reused across method invocations. */
135     g_object_set (work,
136                   "num1", 15,
137                   "num2", 10,
138                   "op",   OPERATION_SUBTRACT,
139                   NULL);
140 
141     if (calculator_if_calculate (client,
142                                  &diff,
143                                  1,
144                                  work,
145                                  &invalid_operation,
146                                  &error)) {
147       printf ("15-10=%d\n", diff);
148     }
149   }
150 
151   g_object_unref (work);
152 
153   if (!error) {
154     SharedStruct *shared_struct;
155     gchar *value;
156 
157     shared_struct = g_object_new (TYPE_SHARED_STRUCT, NULL);
158 
159     /* As defined in the Thrift file, the Calculator service extends
160        the SharedService service. Correspondingly, in the generated
161        code CalculatorIf inherits from SharedServiceIf, and the parent
162        service's methods are accessible through a simple cast. */
163     if (shared_service_client_get_struct (SHARED_SERVICE_IF (client),
164                                           &shared_struct,
165                                           1,
166                                           &error)) {
167       g_object_get (shared_struct, "value", &value, NULL);
168       printf ("Check log: %s\n", value);
169       g_free (value);
170     }
171 
172     g_object_unref (shared_struct);
173   }
174 
175   if (error) {
176     printf ("ERROR: %s\n", error->message);
177     g_clear_error (&error);
178 
179     exit_status = 1;
180   }
181 
182   thrift_transport_close (transport, NULL);
183 
184   g_object_unref (client);
185   g_object_unref (protocol);
186   g_object_unref (transport);
187   g_object_unref (socket);
188 
189   return exit_status;
190 }
191