1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.libraries.pcc.chronicle.api
18 
19 import com.android.libraries.pcc.chronicle.api.error.ChronicleError
20 import com.android.libraries.pcc.chronicle.api.policy.Policy
21 import kotlin.reflect.KClass
22 
23 /** Chronicle is the primary entry point for features when accessing or manipulating data. */
24 interface Chronicle {
25   /**
26    * Returns the [ConnectionTypes] associated with the provided [dataTypeClass] which are available
27    * via [getConnection].
28    */
getAvailableConnectionTypesnull29   fun getAvailableConnectionTypes(dataTypeClass: KClass<*>): ConnectionTypes
30 
31   /**
32    * Returns the [ConnectionTypes] associated with the provided [dataTypeClass] which are available
33    * via [getConnection].
34    */
35   fun getAvailableConnectionTypes(dataTypeClass: Class<*>): ConnectionTypes =
36     getAvailableConnectionTypes(dataTypeClass.kotlin)
37 
38   /**
39    * Returns a [Connection] of type [T] after checking policy adherence of the
40    * [ConnectionRequest.requester] and the data being requested.
41    */
42   fun <T : Connection> getConnection(request: ConnectionRequest<T>): ConnectionResult<T>
43 
44   /**
45    * A convenience method which calls [getConnection], returning `null` for
46    * [ConnectionResult.Failure] results. An optional [onError] parameter will be called with the
47    * failure result.
48    */
49   fun <T : Connection> getConnectionOrNull(
50     request: ConnectionRequest<T>,
51     onError: (ChronicleError) -> Unit = {}
52   ): T? {
resultnull53     return when (val result = getConnection(request)) {
54       is ConnectionResult.Success<T> -> result.connection
55       is ConnectionResult.Failure<T> -> {
56         onError(result.error)
57         null
58       }
59     }
60   }
61 
62   /**
63    * A convenience method which calls [getConnection], returning `null` for
64    * [ConnectionResult.Failure] results. If a failure occurs, there will be no information provided
65    * about the failure.
66    */
getConnectionOrNullnull67   fun <T : Connection> getConnectionOrNull(
68     request: ConnectionRequest<T>,
69   ): T? = getConnectionOrNull(request) {}
70 
71   /**
72    * A convenience method which calls [getConnection], and throws [ChronicleError] for
73    * [ConnectionResult.Failure] results.
74    */
getConnectionOrThrownull75   fun <T : Connection> getConnectionOrThrow(request: ConnectionRequest<T>): T {
76     return when (val result = getConnection(request)) {
77       is ConnectionResult.Success<T> -> result.connection
78       is ConnectionResult.Failure<T> -> throw (result.error)
79     }
80   }
81 
82   data class ConnectionTypes(
83     val readConnections: Set<Class<out ReadConnection>>,
84     val writeConnections: Set<Class<out WriteConnection>>
85   ) {
86     companion object {
87       val EMPTY = ConnectionTypes(emptySet(), emptySet())
88     }
89   }
90 }
91 
92 /** Result container for [Connection] attempts. */
93 sealed class ConnectionResult<T : Connection> {
94   class Success<T : Connection>(val connection: T) : ConnectionResult<T>()
95   class Failure<T : Connection>(val error: ChronicleError) : ConnectionResult<T>()
96 }
97 
98 /**
99  * A convenience method that will create a [ConnectionRequest] using the class provided as a type
100  * parameter to the call, the provided processor, and provided policy.
101  */
getConnectionnull102 inline fun <reified T : Connection> Chronicle.getConnection(
103   requester: ProcessorNode,
104   policy: Policy? = null
105 ) = getConnection(ConnectionRequest(T::class.java, requester, policy))
106 
107 /**
108  * A convenience method that will create a [ConnectionRequest] using the class provided as a type
109  * parameter to the call, the provided processor, and provided policy.
110  *
111  * An optional [onError] callback will be called with the [ChronicleError] containing the failure
112  * reason if the connection fails.
113  */
114 inline fun <reified T : Connection> Chronicle.getConnectionOrNull(
115   requester: ProcessorNode,
116   policy: Policy? = null,
117   noinline onError: (ChronicleError) -> Unit = {}
118 ) = getConnectionOrNull(ConnectionRequest(T::class.java, requester, policy), onError)
119 
120 /**
121  * A convenience method that will create a [ConnectionRequest] using the class provided as a type
122  * parameter to the call, the provided processor, and provided policy.
123  */
getConnectionOrThrownull124 inline fun <reified T : Connection> Chronicle.getConnectionOrThrow(
125   requester: ProcessorNode,
126   policy: Policy? = null
127 ) = getConnectionOrThrow(ConnectionRequest(T::class.java, requester, policy))
128