[AAI-2175] Change aai champ container processes to run as non-root on the host
[aai/champ.git] / README.md
1 Champ
2 =====
3
4 What is Champ?
5 --------------
6
7 Champ is an abstraction from underlying graph storage systems that A&AI would otherwise interface with.
8
9 Building Champ
10 --------------
11
12 To build Champ run the following maven command from the project's root level pom directory:
13
14     mvn clean install
15
16 Deploying The Microservice
17 --------------------------
18
19 Push the Docker image that you have built to your Docker repository and pull it down to the location from which you will be running the service.
20
21 **Create the following directories on the host machine:**
22
23     ../logs
24     ../appconfig
25         ../appconfig/auth
26     ../dynamic/conf
27     
28 You will be mounting these as data volumes when you start the Docker container.
29
30 #### Configuring the Microservice
31
32 Create beans file **../dynamic/conf/champ-beans.xml**
33
34 Example:
35
36     <beans xmlns="http://www.springframework.org/schema/beans"
37         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
38         xmlns:util="http://www.springframework.org/schema/util"
39         xsi:schemaLocation="
40             http://www.springframework.org/schema/beans
41             http://www.springframework.org/schema/beans/spring-beans.xsd
42             http://www.springframework.org/schema/util
43             http://www.springframework.org/schema/util/spring-util.xsd
44             ">
45
46         <util:constant id="DEFAULT_BATCH_SIZE" static-field="com.att.ecomp.event.client.DMaaPEventPublisher.DEFAULT_BATCH_SIZE" />
47         <util:constant id="DEFAULT_BATCH_AGE" static-field="com.att.ecomp.event.client.DMaaPEventPublisher.DEFAULT_BATCH_AGE" />
48         <util:constant id="DEFAULT_BATCH_DELAY" static-field="com.att.ecomp.event.client.DMaaPEventPublisher.DEFAULT_BATCH_DELAY" />
49
50         
51         <bean id="champEventPublisher" class="com.att.ecomp.event.client.DMaaPEventPublisher" >
52             <constructor-arg name="host" value="<%= @CHAMP_EVBUS_HOSTS %>" />
53             <constructor-arg name="topic" value="<%= @CHAMP_EVENT_TOPIC %>" />
54             <constructor-arg name="username" value="<%= @CHAMP_DMAAP_API_KEY %>" />
55             <constructor-arg name="password" value="<%= @CHAMP_DMAAP_API_SECRET %>" />
56             <constructor-arg name="maxBatchSize" ref="DEFAULT_BATCH_SIZE" />
57             <constructor-arg name="maxAgeMs" ref="DEFAULT_BATCH_AGE" />
58             <constructor-arg name="delayBetweenBatchesMs" ref="DEFAULT_BATCH_DELAY" />
59             <constructor-arg name="transportType" value="HTTPAUTH" />           
60         </bean>
61     
62         <!-- Graph Implementation Configuration-->
63         <util:map id="props" map-class="java.util.HashMap" key-type="java.lang.String" value-type="java.lang.Object">
64             <entry key="champcore.event.stream.buffer.capacity" value="50" value-type="java.lang.Integer"/>
65             <entry key="champcore.event.stream.publisher-pool-size" value="10" value-type="java.lang.Integer"/>
66             <entry key="champcore.event.stream.publisher" value-ref="champEventPublisher"/>
67     
68             <entry key="graph.name" value="<%= @CHAMP_GRAPH_NAME %>"/>
69             <entry key="storage.backend" value="<%= @CHAMP_STORAGE_BACKEND_DB %>"/>
70             <entry key="storage.hostname" value="<%= @CHAMP_GRAPH_HOST %>"/>
71         
72             <!-- Hbase Config -->
73             <entry key="storage.hbase.ext.hbase.zookeeper.property.clientPort" value="<%= @CHAMP_GRAPH_PORT %>"/>
74             <entry key="storage.hbase.ext.zookeeper.znode.parent" value="/hbase-unsecure"/>
75         
76             <!-- Cassandra Config -->
77             <entry key="storage.port" value="<%= @CHAMP_GRAPH_PORT %>"/>
78         </util:map>
79     
80         <!-- Janus Implementation -->
81         <bean id="graphBuilder" class="org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl$Builder">
82             <constructor-arg value="<%= @CHAMP_GRAPH_NAME %>"/>
83             <constructor-arg ref="props" />
84         </bean>
85         <bean id="graphImpl" class="org.onap.aai.champjanus.graph.impl.JanusChampGraphImpl">
86             <constructor-arg ref="graphBuilder" />
87         </bean>
88         <bean id="champRestService" class="org.onap.champ.ChampRESTAPI" >
89             <constructor-arg ref="graphImpl" />
90                     <constructor-arg name="txTimeOutInSec" value="300" />
91         </bean>
92     </beans>
93
94 Create configuration file **../appconfig/auth/champ-policy.json**
95
96 This policy file defines which client certificates are authorized to use the service's APIs.  An example policy file follows:
97
98     {
99         "roles": [
100             {
101                 "name": "admin",
102                 "functions": [
103                     {
104                         "name": "search", "methods": [ { "name": "GET" },{ "name": "DELETE" }, { "name": "PUT" }, { "name": "POST" } ]
105                     }
106                 ],
107                 "users": [
108                     {
109                         "username": "CN=admin, OU=My Organization Unit, O=, L=Sometown, ST=SomeProvince, C=CA"
110                     }    
111                 ]
112             }
113         ]
114     }
115
116 Create keystore file **../appconfig/auth/tomcat\_keystore**
117 _tomcat\_keystore_
118
119 Create a keystore with this name containing whatever CA certificates that you want your instance of the CHAMP service to accept for HTTPS traffic.
120
121 #### Start the service
122
123 You can now start the Docker container in the following manner:
124
125         docker run -d \
126             -p 9520:9520 \
127                 -e CONFIG_HOME=/opt/app/champ-service/config/ \
128                 -e KEY_STORE_PASSWORD={{obfuscated password}} \
129                 -e KEY_MANAGER_PASSWORD=OBF:{{obfuscated password}} \
130             -v /<path>/logs:/opt/aai/logroot/AAI-CHAMP \
131             -v /<path>/appconfig:/opt/app/champ-service/config \
132             --name champ-service \
133             {{your docker repo}}/champ-service
134
135 Where,
136
137     {{your docker repo}} = The Docker repository you have published your CHAMP Service image to.
138     {{obfuscated password}} = The password for your key store/key manager after running it through the Jetty obfuscation tool.
139
140 API Specification
141 -----------------
142
143 Champ has methods for:
144
145 1) Objects
146 2) Relationships
147 3) Transactions
148
149 In the future we plan on adding in partitions, indicies, schemas, and traversals, but at the moment that is outside the scope of Champ.  If you have suggestions on how this should be implemented, we look forward to your pull request.
150
151 API Implementations
152 -------------------
153
154 Champ ships with both Titan and Janus implementations. These are switchable after deployment, but the champ-beans.xml file needs to be changed and the champ-service must be restarted.
155
156 Event Generation
157 ----------------
158
159 Champ can be configured to generate a notification whenever it is used to modify data in the graph.  The notification comes in the form of an event which is posted to the **champRawEvents** Event Bus topic.  This event stream allows downstream clients to be notified about objects and relationships which are added/modified/deleted in the graph.
160
161 The following configuration parameters define the behaviour of the event generation feature:
162
163 - **champ.event.stream.publisher**: _EventClientPublisher_ instance to use for forwarding events to the event stream (see below).
164 - **champ.event.stream.publisher-pool-size**: Optional: number of worker threads to use for event publishing.
165 - **champ.event.stream.buffer.capacity**: Optional: maximum number of events which may be enqueued waiting to be published at any given time.
166  
167
168 The following examples illustrate snippets of typical spring-beans configuration file which instantiate a producer (if your client is not spring enabled then you may just directly instantiate an _EventBusPublisher_ - refer to the _ECOMP Event Bus Client_ library for details):
169
170 _Instantiating an event producer backed by a native Kafka implementation:_
171
172     <!-- Event publisher to pass to the Champ library for logging raw graph events. -->
173     <bean id="champEventPublisher" class="com.att.ecomp.event.client.KafkaEventPublisher" >
174         <constructor-arg name="hosts" value="1.2.3.4:9092, 5.6.7.8:9092, 9.10.11.12:9092" />
175         <constructor-arg name="topic" value="champRawEvents" />
176     </bean>
177
178 _Instantiating an event producer backed by a DMaaP Client implementation:_
179
180     <bean id="champEventPublisher" class="com.att.ecomp.event.client.DMaaPEventPublisher" >
181         <constructor-arg name="urlList" value="1.2.3.4, 5.6.7.8, 9.10.11.12" />
182         <constructor-arg name="topic" value="champRawEvents" />
183         <constructor-arg name="apiKey" value="OBF:1r2v1qc51i0r1l6n1m4q1jew1bpt1lkp1ll11bot1jee1m7o1l6n1i0z1qax1r53" />
184         <constructor-arg name="apiSecret" value="OBF:1ro81caa1myq1mzs1nx31kfl1d2q1zsp1yt81nz31f8h1hmd1hmx1fa51nxb1yte1zt11d3g1kct1nzb1mxi1myk1cb01rqe" />
185     </bean>
186
187         
188
189 Usage
190 -----
191
192 ### Echo
193
194     URL: https://<host>:9522/services/echo-service/echo/<input>
195     Method: GET
196     Success Response: 200 OK
197
198
199 ### Objects
200
201 #### Create a new object
202 Inserts a new object into the graph with the type and properties from the body of the request. Returns the object that was created, along with its assigned key and timestamps.
203
204     URL: https://<host>:9522/services/champ-service/v1/objects
205     Method: POST
206     Body: 
207          {
208            "type" : "test",
209            "properties" : {
210              "key1" : "val1",
211              "key2" : "val2"
212            }
213          }
214          
215     Success Response:
216         Code: 201
217         Content:
218             {
219                 "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
220                 "type": "test",
221                 "properties": {
222                     "key1": "val1",
223                     "key2": "val2",
224                     "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
225                     "aai-created-ts": 1516731449014,
226                     "aai-last-mod-ts": 1516731449014
227                 }
228             }
229
230 #### Retrieve an object
231 A GET request that returns the object with the given key
232
233     URL: https://<host>:9522/services/champ-service/v1/objects/<key>
234     Method: GET
235     Success Response:
236         Code: 200 OK
237         Content:
238             {
239                 "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
240                 "type": "test",
241                 "properties": {
242                     "key1": "val1",
243                     "key2": "val2",
244                     "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
245                     "aai-created-ts": 1516731449014,
246                     "aai-last-mod-ts": 1516731449014
247                 }
248             }
249
250 #### Updating an object
251 Replace any of the properties with a PUT request, get the updated object back. Inclusion of timestamps is optional, but the request will be rejected if they do not match the DB.
252
253     URL: https://<host>:9522/services/champ-service/v1/objects/<key>
254     Method: PUT
255     Content:
256         {
257             "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
258             "type": "test",
259             "properties": {
260                 "key1": "val3",
261                 "key2": "val2",
262                 "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
263                 "key4": "val4",
264                 "aai-created-ts": 1516731449014
265             }
266         }
267         
268     Response:
269         Code: 200 OK
270         Content:
271             {
272                 "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
273                 "type": "test",
274                 "properties": {
275                     "key1": "val3",
276                     "key2": "val2",
277                     "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
278                     "key4": "val4",
279                     "aai-created-ts": 1516731449014,
280                     "aai-last-mod-ts": 1516730919213
281                 }
282             }
283
284 #### Delete objects
285 Deletes the object from the graph if there are no connected relationships
286
287     URL: https://<host>:9522/services/champ-service/v1/objects/<key>
288     Method: DELETE
289     Success Response:
290         Code: 200 OK
291         
292
293   
294 #### Filtered object search
295 Get a list of objects filtered by key/value pairs
296
297     URL: https://<host>:9522/services/champ-service/v1/objects/filter?<key>=<val>
298     Method: GET
299     Success Response:
300         [
301             {
302                 "key": "e0d3a253-4a1b-4ca4-a862-8a52b1e3fdfb",
303                 "type": "test2",
304                 "properties": {}
305             }
306         ]
307
308 Get a list of objects filtered by key/value pairs with specific properties
309
310     URL: https://<host>:9522/services/champ-service/v1/objects/filter?<key>=<val>&properties=<prop1>&properties=<prop2>
311     Method: GET
312     Success Response:
313         [
314             {
315                 "key": "e0d3a253-4a1b-4ca4-a862-8a52b1e3fdfb",
316                 "type": "test2",
317                 "properties": {
318                     "key1": "val1",
319                     "filter-sample": "yes"
320                 }
321             }
322         ] 
323
324 Get a list of objects filtered by key/value pairs with all properties
325
326     URL: https://<host>:9522/services/champ-service/v1/objects/filter?<key>=<val>&properties=all
327     Method: GET
328     Success Response:
329         [
330             {
331                 "key": "e0d3a253-4a1b-4ca4-a862-8a52b1e3fdfb",
332                 "type": "test2",
333                 "properties": {
334                     "key1": "val1",
335                     "aai-uuid": "e0d3a253-4a1b-4ca4-a862-8a52b1e3fdfb",
336                     "filter-sample": "yes"
337                 }
338             }
339         ]
340
341 ### Relationships
342 Relationships are used to create a connection between two pre-existing objects.
343
344 #### Create a new relationship
345 Creates a new relationship with the specified properties. "source" and "target" must be objects that have already been created, specified by their keys. Returns the created relationship with its key and timestamps.
346
347     URL: https://<host>:9522/services/champ-service/v1/relationships
348     Method: POST
349     Content:
350         {
351             "type": "testOnTest2",
352             "properties": {
353                 "beep": "boop",
354                 "a": "b"
355             },
356             "source": {
357                 "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
358                 "type": "test",
359                 "properties": {
360                     "key1": "val3",
361                     "key2": "val2",
362                     "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
363                     "key4": "val4"
364                 }
365             },
366             "target": {
367                 "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
368                 "type": "test2",
369                 "properties": {
370                     "key1": "val1",
371                     "key2": "val2",
372                     "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
373                     "key4": "val4"
374                 }
375             }
376         }
377         
378     Response:
379         Code: 201 Created
380         Content:
381         {
382             "key": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1",
383             "type": "testOnTest2",
384             "properties": {
385                 "beep": "boop",
386                 "a": "b",
387                 "aai-uuid": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1"
388                 "aai-last-mod-ts": 1516730919213,
389                 "aai-created-ts": 1516730919213
390             },
391             "source": {
392                 "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
393                 "type": "test",
394                 "properties": {
395                     "key1": "val3",
396                     "key2": "val2",
397                     "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
398                     "key4": "val4"
399                 }
400             },
401             "target": {
402                 "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
403                 "type": "test2",
404                 "properties": {
405                     "key1": "val1",
406                     "key2": "val2",
407                     "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
408                     "key4": "val4"
409                 }
410             }
411         }
412         
413 #### Retrieving relationships
414 Returns the relationship, looked up by key.
415
416     URL: https://<host>:9522/services/champ-service/v1/relationships/<key>
417     Method: GET
418     Response:
419         Code: 200 OK
420         Content:
421             {
422                 "key": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1",
423                 "type": "testOnTest2",
424                 "properties": {
425                     "beep": "boop",
426                     "a": "b",
427                     "aai-uuid": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1"
428                     "aai-last-mod-ts": 1516730919213,
429                     "aai-created-ts": 1516730919213
430                 },
431                 "source": {
432                     "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
433                     "type": "test",
434                     "properties": {
435                         "key1": "val3",
436                         "key2": "val2",
437                         "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
438                         "key4": "val4"
439                     }
440                 },
441                 "target": {
442                     "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
443                     "type": "test2",
444                     "properties": {
445                         "key1": "val1",
446                         "key2": "val2",
447                         "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
448                         "key4": "val4"
449                     }
450                 }
451             }
452             
453             #### Get relationships for an object
454             Given an object, returns all connected relationships.
455             
456                 URL: https://<host>:9522/services/champ-service/v1/objects/relationships/<object-id>
457                 Method: GET
458                 Success Response:
459                     Code: 200 OK
460                     Content: 
461                         [
462                             {
463                                 "key": "4ba8dcc2-806d-4312-aecb-503435f355e5",
464                                 "type": "testOnTest2",
465                                 "properties": {
466                                     "beep": "fdsa",
467                                     "a": "c",
468                                     "aai-uuid": "4ba8dcc2-806d-4312-aecb-503435f355e5"
469                                 },
470                                 "source": {
471                                     "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
472                                     "type": "test",
473                                     "properties": {
474                                         "key1": "val3",
475                                         "key2": "val2",
476                                         "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
477                                         "key4": "val4"
478                                     }
479                                 },
480                                 "target": {
481                                     "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
482                                     "type": "test2",
483                                     "properties": {
484                                         "key1": "val1",
485                                         "key2": "val2",
486                                         "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
487                                         "key4": "val4"
488                                     }
489                                 }
490                             },
491                             {
492                                 "key": "a3096bb8-dc66-4a9c-ab33-a1183f784fbb",
493                                 "type": "testOnTest2",
494                                 "properties": {
495                                     "beep": "fdsa",
496                                     "a": "c",
497                                     "aai-uuid": "a3096bb8-dc66-4a9c-ab33-a1183f784fbb"
498                                 },
499                                 "source": {
500                                     "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
501                                     "type": "test",
502                                     "properties": {
503                                         "key1": "val3",
504                                         "key2": "val2",
505                                         "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
506                                         "key4": "val4"
507                                     }
508                                 },
509                                 "target": {
510                                     "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
511                                     "type": "test2",
512                                     "properties": {
513                                         "key1": "val1",
514                                         "key2": "val2",
515                                         "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
516                                         "key4": "val4"
517                                     }
518                                 }
519                             }
520                         ]
521
522 #### Updating relationships
523 Update the relationship properties. Passing timestamps is optional, but the request will be rejected if they are incorrect.
524
525     URL: https://<host>:9522/services/champ-service/v1/relationships/<key>
526     Method: PUT
527     Content: 
528         {
529             "key": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1",
530             "type": "testOnTest2",
531             "properties": {
532                 "beep": "borp",
533                 "a": "c",
534                 "aai-uuid": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1"
535             },
536             "source": {
537                 "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
538                 "type": "test",
539                 "properties": {
540                     "key1": "val3",
541                     "key2": "val2",
542                     "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
543                     "key4": "val4"
544                 }
545             },
546             "target": {
547                 "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
548                 "type": "test2",
549                 "properties": {
550                     "key1": "val1",
551                     "key2": "val2",
552                     "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
553                     "key4": "val4"
554                 }
555             }
556         }
557         
558     Response:
559         Code: 200 OK
560         Content:
561             {
562                 "key": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1",
563                 "type": "testOnTest2",
564                 "properties": {
565                     "beep": "borp",
566                     "a": "c",
567                     "aai-uuid": "7a3282d0-6904-40f2-ae1e-8246bb1f49c1",
568                     "aai-last-mod-ts": 1516734987294,
569                     "aai-created-ts": 1516730919213
570                 },
571                 "source": {
572                     "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
573                     "type": "test",
574                     "properties": {
575                         "key1": "val3",
576                         "key2": "val2",
577                         "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
578                         "key4": "val4"
579                     }
580                 },
581                 "target": {
582                     "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
583                     "type": "test2",
584                     "properties": {
585                         "key1": "val1",
586                         "key2": "val2",
587                         "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
588                         "key4": "val4"
589                     }
590                 }
591             }
592             
593 #### Deleting relationships
594 Deletes the relationship specified by key.
595
596     URL: https://<host>:9522/services/champ-service/v1/relationships/<key>
597     Method: Delete
598     Response: 200 OK
599     
600 #### Filtered Relationship
601 Returns a list of relationships that have key/value properties matching the filter
602
603     URL: https://<host>:9522/services/champ-service/v1/objects/filter?<key>=<val>
604     Method: GET
605     Success Response:
606         [
607             {
608                 "key": "a4d51cd9-f271-4201-975d-168ec6bde501",
609                 "type": "testOnTest2",
610                 "properties": {
611                     "beep": "yes",
612                     "a": "c",
613                     "aai-uuid": "a4d51cd9-f271-4201-975d-168ec6bde501"
614                 },
615                 "source": {
616                     "key": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
617                     "type": "test",
618                     "properties": {
619                         "key1": "val3",
620                         "key2": "val2",
621                         "aai-uuid": "890c8b3f-892f-48e3-85cd-748ebf0426a5",
622                         "key4": "val4"
623                     }
624                 },
625                 "target": {
626                     "key": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
627                     "type": "test2",
628                     "properties": {
629                         "key1": "val1",
630                         "key2": "val2",
631                         "aai-uuid": "559855df-62e2-4b06-a1ae-18e0d5ac9826",
632                         "key4": "val4"
633                     }
634                 }
635             }
636         ]
637
638 ### Transactions
639 Transactions allow multiple graph operations to be grouped into a logical, sandboxed context, so that the option exists to either persist ALL of the grouped changes together, or NONE of them.
640
641 Explicit use of transactions is entirely optional for the client.  Calling the API methods described below without supplying a transaction
642 object results in a transaction being implicitly opened for the single operation, and then automatically committed.
643
644 However, all of the API calls described above related to persisting, retrieving, and deleting vertices, edges and graph partitions also 
645 expose a version of the call which optionally accepts a transaction id (acquired by explicitly calling the /transaction API endpoint).
646 In this case, the supplied transaction is used for the operation, and no automatic commit occurs.  It is the responsibility of
647 the client to explicitly commit or rollback the transaction at his or her discretion.
648
649 #### Open a new transaction
650 To use explicit transaction the client must request a transaction id from the Champ service by making a request to open a new transaction.
651
652         URL: https://<host>:9522/services/champ-service/v1/transaction/
653         Method: POST
654         Response:
655             Code: 200 OK
656             Content: 5d90f5ae-1f1e-4c3e-b20b-2f7c45f822eb
657             
658 #### Working within a transaction
659 Operations can be done within a transaction by putting the transactionId in the query string.
660
661     Query string: transactionId=<id>
662     
663 Example object creation:
664
665     URL: https://<host>:9522/services/champ-service/v1/objects?transactionId=5d90f5ae-1f1e-4c3e-b20b-2f7c45f822eb
666     
667 Example relationship update:
668
669     URL: https://<host>:9522/services/champ-service/v1/relationships/<key>?transactionId=5d90f5ae-1f1e-4c3e-b20b-2f7c45f822eb
670
671 #### Checking a transaction
672 If you wish to check the status of a transaction, you can do a get on it
673
674     URL: https://<host>:9522/services/champ-service/v1/transaction/<transaction-id>
675     Method: GET
676 If the transaction is currently open:
677
678     Response:
679         Code: 200 OK
680         Content: "fa0890d9-6ac4-40aa-9838-745a25a61fa6 is OPEN"
681 If the transaction is not open:
682
683     Response:
684         Code: 404 Not Found
685         Content: {}
686     
687
688 #### Committing a transaction
689 Operations performed within the context of a transaction are not visible outside of that context 
690 until the client explicitly commits the transaction.  Up until that point, there is always the
691 option to just roll back the changes.
692
693     URL: https://<host>:9522/services/champ-service/v1/transaction/<transaction-id>
694     Method: PUT
695     Content: {"method":"commit"}
696     
697     Response:
698         Code: 200 OK
699         Content: COMMITED
700     
701 ### Rolling back a transaction.
702 In the event that a sequence of graph operations which were performed within the same transactional context need to be aborted (for example one of the operations in the sequence encountered a failure of some kind) the entire transaction can be aborted by rolling back the transaction.  This effectively undoes all of the operations which were performed within the open transaction.
703
704 Note, once a transaction has been committed, it is no longer possible to rollback the contents of the transaction.
705  
706     URL: https://<host>:9522/services/champ-service/v1/transaction/<transaction-id>
707         Method: PUT
708         Content: {"method":"rollback"}
709         
710         Response:
711             Code: 200 OK
712             Content: ROLLED BACK