• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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.onboarding.bedsteadonboarding.queryable
18 
19 import android.os.Parcel
20 import android.os.Parcelable
21 import com.android.onboarding.bedsteadonboarding.contractutils.ContractUtils
22 import com.android.onboarding.nodes.OnboardingEvent
23 import com.android.onboarding.nodes.OnboardingGraphNode
24 import com.android.onboarding.nodes.OnboardingGraphLog
25 import com.android.queryable.Queryable
26 import com.android.queryable.queries.BooleanQueryHelper
27 import com.android.queryable.queries.LongQueryHelper
28 import com.android.queryable.queries.StringQueryHelper
29 import java.time.Instant
30 import kotlin.collections.Collection
31 
32 /**
33  * Implementation of [NodeQuery].
34  */
35 class NodeQueryHelper<E : Queryable> : NodeQuery<E> {
36   @Transient private lateinit var query: E
37 
38   private val idQueryHelper: LongQueryHelper<E>
39   private val componentQueryHelper: ComponentQueryHelper<E>
40   private val nameQueryHelper: StringQueryHelper<E>
41   private val startedQueryHelper: BooleanQueryHelper<E>
42   private val finishedQueryHelper: BooleanQueryHelper<E>
43   private val failedQueryHelper: BooleanQueryHelper<E>
44   private val happenedBeforeQueryHelpers: HashMap<OnboardingGraphNode, NodeSequenceQueryHelper<E>>
45   private val happenedAfterQueryHelpers: HashMap<OnboardingGraphNode, NodeSequenceQueryHelper<E>>
46 
47   constructor(query: E) {
48     this.query = query
49     idQueryHelper = LongQueryHelper(query)
50     componentQueryHelper = ComponentQueryHelper(query)
51     nameQueryHelper = StringQueryHelper(query)
52     startedQueryHelper = BooleanQueryHelper(query)
53     finishedQueryHelper = BooleanQueryHelper(query)
54     failedQueryHelper = BooleanQueryHelper(query)
55     happenedBeforeQueryHelpers = HashMap()
56     happenedAfterQueryHelpers = HashMap()
57   }
58 
59   constructor(parcel: Parcel) {
60     idQueryHelper = parcel.readParcelable(NodeQueryHelper::class.java.classLoader)
61       as LongQueryHelper<E>? ?: throw IllegalStateException()
62     componentQueryHelper = parcel.readParcelable(NodeQueryHelper::class.java.classLoader)
63       as ComponentQueryHelper<E>? ?: throw IllegalStateException()
64     nameQueryHelper = parcel.readParcelable(NodeQueryHelper::class.java.classLoader)
65       as StringQueryHelper<E>? ?: throw IllegalStateException()
66     startedQueryHelper = parcel.readParcelable(NodeQueryHelper::class.java.classLoader)
67       as BooleanQueryHelper<E>? ?: throw IllegalStateException()
68     finishedQueryHelper = parcel.readParcelable(NodeQueryHelper::class.java.classLoader)
69       as BooleanQueryHelper<E>? ?: throw IllegalStateException()
70     failedQueryHelper = parcel.readParcelable(NodeQueryHelper::class.java.classLoader)
71       as BooleanQueryHelper<E>? ?: throw IllegalStateException()
72     happenedBeforeQueryHelpers = parcel.readParcelable(NodeQueryHelper::class.java.classLoader)
73       as HashMap<OnboardingGraphNode, NodeSequenceQueryHelper<E>>? ?: throw IllegalStateException()
74     happenedAfterQueryHelpers = parcel.readParcelable(NodeQueryHelper::class.java.classLoader)
75       as HashMap<OnboardingGraphNode, NodeSequenceQueryHelper<E>>? ?: throw IllegalStateException()
76   }
77 
idnull78   override fun id() = idQueryHelper
79 
80   override fun name() = nameQueryHelper
81 
82   override fun component() = componentQueryHelper
83 
84   override fun isStarted() = startedQueryHelper
85 
86   override fun isFinished() = finishedQueryHelper
87 
88   override fun isFailed() = failedQueryHelper
89 
90   override fun happenedBefore(node: OnboardingGraphNode): NodeSequenceQuery<E> {
91     if (happenedBeforeQueryHelpers.containsKey(node)) {
92       return happenedBeforeQueryHelpers[node]!!
93     }
94 
95     val nodeSequenceQuery = NodeSequenceQueryHelper(query)
96     nodeSequenceQuery.nodeToCompareWith = node
97     happenedBeforeQueryHelpers[node] = nodeSequenceQuery
98 
99     return nodeSequenceQuery
100   }
101 
happenedAfternull102   override fun happenedAfter(node: OnboardingGraphNode): NodeSequenceQuery<E> {
103     if (happenedAfterQueryHelpers.containsKey(node)) {
104       return happenedAfterQueryHelpers[node]!!
105     }
106 
107     val nodeSequenceQuery = NodeSequenceQueryHelper(query)
108     nodeSequenceQuery.nodeToCompareWith = node
109     happenedAfterQueryHelpers[node] = nodeSequenceQuery
110 
111     return nodeSequenceQuery
112   }
113 
describeQuerynull114   override fun describeQuery(fieldName: String?): String {
115     val queryStrings = ArrayList<String>()
116 
117     queryStrings.add(idQueryHelper.describeQuery("$fieldName.id"))
118     queryStrings.add(componentQueryHelper.describeQuery("$fieldName.component"))
119     queryStrings.add(nameQueryHelper.describeQuery("$fieldName.name"))
120     queryStrings.add(startedQueryHelper.describeQuery("$fieldName.started"))
121     queryStrings.add(finishedQueryHelper.describeQuery("$fieldName.finished"))
122     queryStrings.add(failedQueryHelper.describeQuery("$fieldName.failed"))
123 
124     for (query in happenedBeforeQueryHelpers.values) {
125       queryStrings.add(query.describeQuery("$fieldName.happenedBefore")!!)
126     }
127 
128     for (query in happenedAfterQueryHelpers.values) {
129       queryStrings.add(query.describeQuery("$fieldName.happenedAfter")!!)
130     }
131 
132     return Queryable.joinQueryStrings(queryStrings)
133   }
134 
isEmptyQuerynull135   override fun isEmptyQuery(): Boolean {
136     val isEmptyQuery = Queryable.isEmptyQuery(idQueryHelper) &&
137       Queryable.isEmptyQuery(componentQueryHelper) &&
138       Queryable.isEmptyQuery(nameQueryHelper) &&
139       Queryable.isEmptyQuery(startedQueryHelper) &&
140       Queryable.isEmptyQuery(finishedQueryHelper) &&
141       Queryable.isEmptyQuery(failedQueryHelper)
142 
143     if (!isEmptyQuery) {
144       return false
145     }
146 
147     for (query in happenedBeforeQueryHelpers.values) {
148       if (!Queryable.isEmptyQuery(query)) {
149         return false
150       }
151     }
152 
153     for (query in happenedAfterQueryHelpers.values) {
154       if (!Queryable.isEmptyQuery(query)) {
155         return false
156       }
157     }
158 
159     return true
160   }
161 
describeContentsnull162   override fun describeContents(): Int {
163     return 0
164   }
165 
writeToParcelnull166   override fun writeToParcel(out: Parcel, flags: Int) {
167     out.writeParcelable(idQueryHelper, flags)
168     out.writeParcelable(componentQueryHelper, flags)
169     out.writeParcelable(nameQueryHelper, flags)
170     out.writeParcelable(startedQueryHelper, flags)
171     out.writeParcelable(finishedQueryHelper, flags)
172     out.writeParcelable(failedQueryHelper, flags)
173     out.writeMap(happenedBeforeQueryHelpers)
174     out.writeMap(happenedAfterQueryHelpers)
175   }
176 
matchesnull177   override fun matches(node: OnboardingGraphNode): Boolean {
178     val matches = idQueryHelper.matches(node.id) &&
179       componentQueryHelper.matches(node.component) &&
180       nameQueryHelper.matches(node.name) &&
181       startedQueryHelper.matches(isNodeStarted(node)) &&
182       finishedQueryHelper.matches(isNodeFinished(node)) &&
183       failedQueryHelper.matches(isNodeFailed(node))
184 
185     if (!matches) {
186       return false
187     }
188 
189     for (query in happenedBeforeQueryHelpers.values) {
190       if (!query.matches(isHappenedBefore(node))) {
191         return false
192       }
193     }
194 
195     for (query in happenedAfterQueryHelpers.values) {
196       if (!query.matches(isHappenedAfter(node))) {
197         return false
198       }
199     }
200 
201     return true
202   }
203 
isNodeStartednull204   private fun isNodeStarted(node: OnboardingGraphNode): Boolean {
205     return node.start < Instant.now()
206   }
207 
isNodeFinishednull208   private fun isNodeFinished(node: OnboardingGraphNode): Boolean {
209     return node.end < Instant.now() &&
210       !isAnotherNodeAttemptedToBeExecutedForResult(
211         node.events, ContractUtils.getContractIdentifier(node.component!!.name, node.name)) &&
212       node.outgoingEdgesOfValidNodes.isEmpty()
213   }
214 
isNodeFailednull215   private fun isNodeFailed(node: OnboardingGraphNode): Boolean {
216     return node.isFailed
217   }
218 
isHappenedBeforenull219   private fun isHappenedBefore(node: OnboardingGraphNode): Boolean {
220     if (Queryable.isEmptyQuery(happenedBeforeQueryHelpers[node])) {
221       return true
222     }
223     return node.start.isBefore(happenedBeforeQueryHelpers.getValue(node).nodeToCompareWith!!.start)
224   }
225 
isHappenedAfternull226   private fun isHappenedAfter(node: OnboardingGraphNode): Boolean {
227     if (Queryable.isEmptyQuery(happenedAfterQueryHelpers[node])) {
228       return true
229     }
230     return node.start.isAfter(happenedAfterQueryHelpers.getValue(node).nodeToCompareWith!!.start)
231   }
232 
isAnotherNodeAttemptedToBeExecutedForResultnull233   private fun isAnotherNodeAttemptedToBeExecutedForResult(
234     events: Collection<OnboardingGraphLog.OnboardingEventDelegate>,
235     contractIdentifierOfNode: String
236   ): Boolean {
237     return events.any {
238       val event = it.source
239       (event is OnboardingEvent.ActivityNodeStartExecuteSynchronously) &&
240         (ContractUtils.getContractIdentifier(event.nodeComponent, event.nodeName) !=
241           contractIdentifierOfNode)
242     }
243   }
244 
245   companion object CREATOR : Parcelable.Creator<NodeQueryHelper<Queryable>> {
createFromParcelnull246     override fun createFromParcel(parcel: Parcel): NodeQueryHelper<Queryable> {
247       return NodeQueryHelper(parcel)
248     }
249 
newArraynull250     override fun newArray(size: Int): Array<NodeQueryHelper<Queryable>?> {
251       return arrayOfNulls(size)
252     }
253   }
254 }
255