func (a *workloads) dereferenceAllScopes(ctx context.Context, namespace string, status []v1alpha2.WorkloadStatus) error {
	for _, st := range status {
		for _, sc := range st.Scopes {
			if err := a.applyScopeRemoval(ctx, namespace, st.Reference, sc); err != nil {
				return err
			}
		}
	}
	return nil
}
dereferenceAllScope dereferences workloads owned by the appConfig being deleted from the scopes they belong to.
package applicationconfiguration
import (
	"context"
	"encoding/json"
	"fmt"
	"reflect"
	"strings"
	runtimev1alpha1 "github.com/crossplane/crossplane-runtime/apis/core/v1alpha1"
	"github.com/crossplane/crossplane-runtime/pkg/fieldpath"
	"github.com/crossplane/crossplane-runtime/pkg/meta"
	"github.com/crossplane/crossplane-runtime/pkg/resource"
	jsonpatch "github.com/evanphx/json-patch"
	"github.com/pkg/errors"
	"github.com/tidwall/gjson"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/types"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"github.com/crossplane/oam-kubernetes-runtime/apis/core/v1alpha2"
	"github.com/crossplane/oam-kubernetes-runtime/pkg/oam/discoverymapper"
	"github.com/crossplane/oam-kubernetes-runtime/pkg/oam/util"
)
const (
	errFmtApplyWorkload            = "cannot apply workload %q"
	errFmtSetWorkloadRef           = "cannot set trait %q reference to %q"
	errFmtSetScopeWorkloadRef      = "cannot set scope %q reference to %q"
	errFmtGetTraitDefinition       = "cannot find trait definition %q %q %q"
	errFmtGetScopeDefinition       = "cannot find scope definition %q %q %q"
	errFmtGetScopeWorkloadRef      = "cannot find scope workloadRef %q %q %q with workloadRefsPath %q"
	errFmtGetScopeWorkloadRefsPath = "cannot get workloadRefsPath for scope to be dereferenced %q %q %q"
	errFmtApplyTrait               = "cannot apply trait %q %q %q"
	errFmtApplyScope               = "cannot apply scope %q %q %q"
	workloadScopeFinalizer      = "scope.finalizer.core.oam.dev"
	dot                    byte = '.'
	slash                  byte = '/'
	dQuotes                byte = '"'
)
var (
	ErrInvaildOperationType = errors.New("invaild type in operation")
	ErrInvaildOperationValueAndValueFrom = errors.New("invaild value and valueFrom in operation: both are empty")
)
type WorkloadApplicator interface {
	Apply(ctx context.Context, status []v1alpha2.WorkloadStatus, w []Workload, ao ...resource.ApplyOption) error
	Finalize(ctx context.Context, ac *v1alpha2.ApplicationConfiguration) error
}
type WorkloadApplyFns struct {
	ApplyFn    func(ctx context.Context, status []v1alpha2.WorkloadStatus, w []Workload, ao ...resource.ApplyOption) error
	FinalizeFn func(ctx context.Context, ac *v1alpha2.ApplicationConfiguration) error
}
func (fn WorkloadApplyFns) Apply(ctx context.Context, status []v1alpha2.WorkloadStatus, w []Workload, ao ...resource.ApplyOption) error {
	return fn.ApplyFn(ctx, status, w, ao...)
}
func (fn WorkloadApplyFns) Finalize(ctx context.Context, ac *v1alpha2.ApplicationConfiguration) error {
	return fn.FinalizeFn(ctx, ac)
}
type workloads struct {
	patchingClient resource.Applicator
	updatingClient resource.Applicator
	rawClient      client.Client
	dm             discoverymapper.DiscoveryMapper
}
func (a *workloads) Apply(ctx context.Context, status []v1alpha2.WorkloadStatus, w []Workload, ao ...resource.ApplyOption) error {
	if len(w) == 0 {
		return errors.New("The number of workloads in appConfig is 0")
	}
	var namespace = w[0].Workload.GetNamespace()
	for _, wl := range w {
		if !wl.HasDep {
			if err := a.ApplyInputRef(ctx, wl.Workload, wl.DataInputs, namespace, ao...); err != nil {
				return err
			}
			err := a.patchingClient.Apply(ctx, wl.Workload, ao...)
			if err != nil {
				if _, ok := err.(*GenerationUnchanged); !ok {
					return errors.Wrapf(err, errFmtApplyWorkload, wl.Workload.GetName())
				}
			}
		}
		if err := a.ApplyOutputRef(ctx, wl.Workload, wl.DataOutputs, namespace, ao...); err != nil {
			return err
		}
		for _, trait := range wl.Traits {
			if !trait.HasDep {
				if err := a.ApplyInputRef(ctx, &trait.Object, trait.DataInputs, namespace, ao...); err != nil {
					return err
				}
				t := trait.Object
				if err := a.updatingClient.Apply(ctx, &trait.Object, ao...); err != nil {
					if _, ok := err.(*GenerationUnchanged); !ok {
						return errors.Wrapf(err, errFmtApplyTrait, t.GetAPIVersion(), t.GetKind(), t.GetName())
					}
				}
			}
			if err := a.ApplyOutputRef(ctx, &trait.Object, trait.DataOutputs, namespace, ao...); err != nil {
				return err
			}
		}
		workloadRef := runtimev1alpha1.TypedReference{
			APIVersion: wl.Workload.GetAPIVersion(),
			Kind:       wl.Workload.GetKind(),
			Name:       wl.Workload.GetName(),
		}
		for _, s := range wl.Scopes {
			if err := a.applyScope(ctx, wl, s, workloadRef); err != nil {
				return err
			}
		}
	}
	return a.dereferenceScope(ctx, namespace, status, w)
}
func (a *workloads) ApplyOutputRef(ctx context.Context, w *unstructured.Unstructured, outputs map[string]v1alpha2.DataOutput, namespace string, ao ...resource.ApplyOption) error {
	for _, output := range outputs {
		if reflect.DeepEqual(output, v1alpha2.DataOutput{}) || reflect.DeepEqual(output.OutputStore, v1alpha2.StoreReference{}) {
			continue
		}
		runningW := &unstructured.Unstructured{}
		runningW.SetAPIVersion(w.GetAPIVersion())
		runningW.SetKind(w.GetKind())
		key := types.NamespacedName{
			Namespace: w.GetNamespace(),
			Name:      w.GetName(),
		}
		if err := a.rawClient.Get(ctx, key, runningW); err != nil {
			return err
		}
		ref := &unstructured.Unstructured{}
		ref.SetAPIVersion(output.OutputStore.APIVersion)
		ref.SetKind(output.OutputStore.Kind)
		key = types.NamespacedName{
			Namespace: namespace,
			Name:      output.OutputStore.Name,
		}
		if err := a.rawClient.Get(ctx, key, ref); err != nil {
			if resource.IgnoreNotFound(err) != nil {
				return err
			}
			ref.SetNamespace(namespace)
			ref.SetName(output.OutputStore.Name)
			ref.SetOwnerReferences(runningW.GetOwnerReferences())
			if err := a.updatingClient.Apply(ctx, ref, ao...); err != nil {
				return err
			}
			if err = a.rawClient.Get(ctx, key, ref); err != nil {
				return err
			}
		}
		for _, oper := range output.OutputStore.Operations {
			if err := operationProcess(ref, runningW, oper); err != nil {
				return err
			}
		}
		if err := a.updatingClient.Apply(ctx, ref, ao...); err != nil {
			return err
		}
	}
	return nil
}
func (a *workloads) ApplyInputRef(ctx context.Context, w *unstructured.Unstructured, inputs []v1alpha2.DataInput, namespace string, ao ...resource.ApplyOption) error {
	for _, input := range inputs {
		if reflect.DeepEqual(input, v1alpha2.DataInput{}) || reflect.DeepEqual(input.InputStore, v1alpha2.StoreReference{}) {
			continue
		}
		ref := &unstructured.Unstructured{}
		ref.SetAPIVersion(input.InputStore.APIVersion)
		ref.SetKind(input.InputStore.Kind)
		key := types.NamespacedName{
			Namespace: namespace,
			Name:      input.InputStore.Name,
		}
		if err := a.rawClient.Get(ctx, key, ref); err != nil {
			return err
		}
		for _, oper := range input.InputStore.Operations {
			if err := operationProcess(w, ref, oper); err != nil {
				return err
			}
		}
	}
	return nil
}
func operationProcess(inputObj *unstructured.Unstructured, outputObj *unstructured.Unstructured, oper v1alpha2.DataOperation) error {
	switch oper.Type {
	case "jsonPatch":
		jsonBytes, err := json.Marshal(inputObj)
		if err != nil {
			return err
		}
		targetJSON := []byte(gjson.GetBytes(jsonBytes, oper.ToFieldPath).String())
		value := ""
		switch {
		case len(oper.Value) != 0:
			value = oper.Value
		case len(oper.ValueFrom.FieldPath) != 0:
			v, err := getValueFromPath(outputObj, oper.ValueFrom.FieldPath)
			if err != nil {
				return err
			}
			vJSON, err := json.Marshal(v)
			if err != nil {
				return err
			}
			value = string(vJSON)
		default:
			return ErrInvaildOperationValueAndValueFrom
		}
		targetJSON, err = jsonOperation(targetJSON, oper.Operator, oper.ToDataPath, value, oper.ToDataPath)
		if err != nil {
			return err
		}
		jsonBytes, err = jsonOperation(jsonBytes, v1alpha2.ReplaceOperator, oper.ToFieldPath, string(targetJSON), oper.ToDataPath)
		if err != nil {
			return err
		}
		if err := json.Unmarshal(jsonBytes, inputObj); err != nil {
			return errors.Wrap(err, errUnmarshalWorkload)
		}
		return nil
	default:
		return ErrInvaildOperationType
	}
}
func (a *workloads) Finalize(ctx context.Context, ac *v1alpha2.ApplicationConfiguration) error {
	var namespace = ac.GetNamespace()
	if meta.FinalizerExists(&ac.ObjectMeta, workloadScopeFinalizer) {
		if err := a.dereferenceAllScopes(ctx, namespace, ac.Status.Workloads); err != nil {
			return err
		}
		meta.RemoveFinalizer(&ac.ObjectMeta, workloadScopeFinalizer)
	}
	return nil
}
func (a *workloads) dereferenceScope(ctx context.Context, namespace string, status []v1alpha2.WorkloadStatus, w []Workload) error {
	for _, st := range status {
		toBeDeferenced := st.Scopes
		for _, wl := range w {
			if (st.Reference.APIVersion == wl.Workload.GetAPIVersion()) &&
				(st.Reference.Kind == wl.Workload.GetKind()) &&
				(st.Reference.Name == wl.Workload.GetName()) {
				toBeDeferenced = findDereferencedScopes(st.Scopes, wl.Scopes)
			}
		}
		for _, s := range toBeDeferenced {
			if err := a.applyScopeRemoval(ctx, namespace, st.Reference, s); err != nil {
				return err
			}
		}
	}
	return nil
}