diff --git a/external-providers/java-external-provider/pkg/java_external_provider/filter.go b/external-providers/java-external-provider/pkg/java_external_provider/filter.go index 3e33d14d..385bb5a0 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/filter.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/filter.go @@ -8,6 +8,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "strconv" "strings" @@ -21,6 +22,8 @@ const ( KIND_EXTRA_KEY = "kind" SYMBOL_NAME_KEY = "name" FILE_KEY = "file" + PACKAGE = "package" + CONTAINER_NAME = "containerName" ) func (p *javaServiceClient) filterVariableDeclaration(symbols []protocol.WorkspaceSymbol) ([]provider.IncidentContext, error) { @@ -91,6 +94,40 @@ func (p *javaServiceClient) filterDefault(symbols []protocol.WorkspaceSymbol) ([ return incidents, nil } +func (p *javaServiceClient) filterAnnotated(cond *javaCondition, symbols []protocol.WorkspaceSymbol) ([]provider.IncidentContext, error) { + incidents := []provider.IncidentContext{} + for _, symbol := range symbols { + incident, err := p.convertToIncidentContext(symbol) + if err != nil { + return nil, err + } + // TODO: problem: for kind == METHOD || kind == CLASS, the containerName returns name of the method or the class, which is fine, but when + // kind == FIELD we would probably want to look for the type of the field, not the name. That is not possible atm + kind := strings.ToLower(incident.Variables[KIND_EXTRA_KEY].(string)) + containerName := incident.Variables[CONTAINER_NAME].(string) + pkg := incident.Variables[PACKAGE].(string) + pattern := regexp.MustCompile(cond.Referenced.Pattern) + if kind == strings.ToLower(cond.Referenced.Location) { + // pattern for annotated classes or methods could be a regex + if kind == "class" { + // for classes, we need the fully qualified name (package + class name) + fqn := strings.Join([]string{pkg, containerName}, ".") + if pattern.Match([]byte(fqn)) && kind == strings.ToLower(cond.Referenced.Location) { + incidents = append(incidents, incident) + } + } else if kind == "method" { + if pattern.Match([]byte(containerName)) && kind == strings.ToLower(cond.Referenced.Location) { + incidents = append(incidents, incident) + } + } else if incident.Variables[CONTAINER_NAME] == pattern && kind == strings.ToLower(cond.Referenced.Location) { + incidents = append(incidents, incident) + } + } + } + return incidents, nil + +} + // TODO: we will probably want to filter symbols bassed on if in any way the method is being used in the code directly. // This will need to be part of a "filtration" concept that windup has. Searching partiular subsets of things (just the application, applicatoin + corp libraries and the everything.) // Today this is just giving everything. @@ -152,7 +189,8 @@ func (p *javaServiceClient) convertToIncidentContext(symbol protocol.WorkspaceSy KIND_EXTRA_KEY: symbolKindToString(symbol.Kind), SYMBOL_NAME_KEY: symbol.Name, FILE_KEY: string(u), - "package": n, + PACKAGE: n, + CONTAINER_NAME: symbol.ContainerName, }, } diff --git a/external-providers/java-external-provider/pkg/java_external_provider/provider.go b/external-providers/java-external-provider/pkg/java_external_provider/provider.go index e329a63a..b0197a5e 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/provider.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/provider.go @@ -82,8 +82,13 @@ type javaCondition struct { } type referenceCondition struct { - Pattern string `yaml:"pattern"` - Location string `yaml:"location"` + Pattern string `yaml:"pattern"` + Location string `yaml:"location"` + Annotated annotatedCondition `yaml:"annotated""` +} + +type annotatedCondition struct { + Pattern string `yaml:"pattern"` } func NewJavaProvider(log logr.Logger, lspServerName string, contextLines int) *javaProvider { @@ -291,6 +296,7 @@ func (p *javaProvider) Init(ctx context.Context, log logr.Logger, config provide "-Djava.net.useSystemProxies=true", "-configuration", "./", + //"--jvm-arg=-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:1044", "-data", workspace, } diff --git a/external-providers/java-external-provider/pkg/java_external_provider/service_client.go b/external-providers/java-external-provider/pkg/java_external_provider/service_client.go index ccb83704..bd1fdfeb 100644 --- a/external-providers/java-external-provider/pkg/java_external_provider/service_client.go +++ b/external-providers/java-external-provider/pkg/java_external_provider/service_client.go @@ -7,6 +7,7 @@ import ( "os" "os/exec" "path/filepath" + "reflect" "regexp" "strings" "sync" @@ -51,14 +52,24 @@ func (p *javaServiceClient) Evaluate(ctx context.Context, cap string, conditionI return provider.ProviderEvaluateResponse{}, fmt.Errorf("unable to get query info: %v", err) } - if cond.Referenced.Pattern == "" { + // if "annotated" is present, do look for the annotation instead and then filter out according to the + // original location and reference + location := cond.Referenced.Location + pattern := cond.Referenced.Pattern + isAnnotated := !reflect.DeepEqual(cond.Referenced.Annotated, annotatedCondition{}) + if isAnnotated { + location = "annotation" + pattern = cond.Referenced.Annotated.Pattern + } + + if pattern == "" { return provider.ProviderEvaluateResponse{}, fmt.Errorf("provided query pattern empty") } - symbols := p.GetAllSymbols(ctx, cond.Referenced.Pattern, cond.Referenced.Location) + symbols := p.GetAllSymbols(ctx, pattern, location) p.log.V(5).Info("Symbols retrieved", "symbols", symbols) incidents := []provider.IncidentContext{} - switch locationToCode[strings.ToLower(cond.Referenced.Location)] { + switch locationToCode[strings.ToLower(location)] { case 0: // Filter handle for type, find all the referneces to this type. incidents, err = p.filterDefault(symbols) @@ -69,7 +80,11 @@ func (p *javaServiceClient) Evaluate(ctx context.Context, cap string, conditionI case 3: incidents, err = p.filterConstructorSymbols(ctx, symbols) case 4: - incidents, err = p.filterDefault(symbols) + if isAnnotated { + incidents, err = p.filterAnnotated(cond, symbols) + } else { + incidents, err = p.filterDefault(symbols) + } case 7: incidents, err = p.filterMethodSymbols(symbols) case 8: