1 /* <lambda>null2 * 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.analysis.impl 18 19 import com.android.libraries.pcc.chronicle.analysis.CantripFactory 20 import com.android.libraries.pcc.chronicle.analysis.ChronicleContext 21 import com.android.libraries.pcc.chronicle.api.ConnectionRequest 22 import com.android.libraries.pcc.chronicle.api.DataTypeDescriptor 23 import com.android.libraries.pcc.chronicle.api.DataTypeDescriptorSet 24 import com.android.libraries.pcc.chronicle.api.ProcessorNode 25 import com.android.libraries.pcc.chronicle.api.cantrip.Cantrip 26 import com.android.libraries.pcc.chronicle.api.cantrip.MultiCantrip 27 import com.android.libraries.pcc.chronicle.api.cantrip.OpticalCantrip 28 import com.android.libraries.pcc.chronicle.api.operation.Operation 29 import com.android.libraries.pcc.chronicle.api.operation.OperationLibrary 30 import com.android.libraries.pcc.chronicle.api.optics.OpticalAccessPath 31 import com.android.libraries.pcc.chronicle.api.optics.OpticsManifest 32 import com.android.libraries.pcc.chronicle.api.policy.Policy 33 import com.android.libraries.pcc.chronicle.api.policy.PolicyField 34 import com.android.libraries.pcc.chronicle.api.policy.builder.UsageType 35 36 /** 37 * Implementation of [CantripFactory] which composes its [Cantrips][Cantrip] using the provided 38 * [OpticsManifest] and [OperationLibrary]. 39 * 40 * The [ChronicleContext] provides a means to look up the [DataTypeDescriptor] associated with the 41 * [ConnectionRequest.connectionType] of the [ConnectionRequest] passed to [buildCantrip]. 42 */ 43 class CantripFactoryImpl( 44 private val optics: OpticsManifest, 45 private val operations: OperationLibrary, 46 private val dtds: DataTypeDescriptorSet 47 ) : CantripFactory { 48 49 @Suppress("UNCHECKED_CAST") // Types are checked via alternate mechanisms. 50 override fun <Data> buildCantrip( 51 dtd: DataTypeDescriptor, 52 requester: ProcessorNode, 53 policy: Policy?, 54 usageType: UsageType 55 ): Cantrip<Data> { 56 val noOp = MultiCantrip<Data>() 57 val policyTarget = policy?.targets?.find { it.schemaName == dtd.name } ?: return noOp 58 59 val conditionalUsages = 60 policyTarget.fields.flatMap { collectConditionalUsages(dtd, it, usageType) } 61 62 val innerCantrips = 63 conditionalUsages.map { 64 val dtdClass = dtd.cls.java 65 val traversal = 66 optics.composeTraversal(it.accessPath, dtdClass, dtdClass, it.fieldType, it.fieldType) 67 val op = 68 requireNotNull(operations.findOperation(it.tag, it.fieldType, it.fieldType)) { 69 "No Operation found with name: ${it.tag} for type: ${it.fieldType}" 70 } 71 OpticalCantrip(traversal, op as Operation<Any, Any>) as Cantrip<Data> 72 } 73 74 return MultiCantrip(innerCantrips) 75 } 76 77 /** 78 * Does a traversal to collect [ConditionalUsage] from the [PolicyField], composing a pre-order 79 * list as a result. 80 */ 81 private fun collectConditionalUsages( 82 baseDtd: DataTypeDescriptor, 83 field: PolicyField, 84 usageType: UsageType 85 ): List<ConditionalUsage> { 86 val innerUsages = field.subfields.flatMap { collectConditionalUsages(baseDtd, it, usageType) } 87 88 val pathToField = OpticalAccessPath(baseDtd, field.fieldPath) 89 val localUsages = 90 field.redactedUsages.entries 91 .filter { (_, types) -> usageType in types || UsageType.ANY in types } 92 .map { 93 ConditionalUsage( 94 accessPath = pathToField, 95 tag = it.key, 96 fieldType = dtds.findFieldTypeAsClass(baseDtd, field.fieldPath) 97 ) 98 } 99 100 return localUsages + innerUsages 101 } 102 103 private data class ConditionalUsage( 104 val accessPath: OpticalAccessPath, 105 val tag: String, 106 val fieldType: Class<*>, 107 ) 108 } 109