ContainerFlowSearchPlan.java
/*******************************************************************************
* Copyright (c) 2026 Carsten Hammer.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.sandbox.jdt.container.api;
import java.util.List;
import java.util.Objects;
/**
* Stable search requests derived from a container flow graph.
*
* <p>This model does not execute JDT searches. The Eclipse-dependent multi-file layer
* resolves these seeds to source compilation units and repeats planning to a fixed
* point.</p>
*
* @param seeds deterministic, duplicate-free search requests
*/
public record ContainerFlowSearchPlan(List<SearchSeed> seeds) {
public ContainerFlowSearchPlan {
seeds= List.copyOf(Objects.requireNonNull(seeds, "seeds")); //$NON-NLS-1$
}
/** Returns whether no further source-scope search is requested. */
public boolean isEmpty() {
return seeds.isEmpty();
}
/** One JDT-search intention independent of Eclipse UI classes. */
public record SearchSeed(
String sourceNodeId,
SearchKind kind,
String bindingKey,
String ownerKey,
String javaElementHandle,
int signatureIndex,
String reason) {
public SearchSeed {
sourceNodeId= requiredText(sourceNodeId, "sourceNodeId"); //$NON-NLS-1$
Objects.requireNonNull(kind, "kind"); //$NON-NLS-1$
bindingKey= optionalText(bindingKey);
ownerKey= optionalText(ownerKey);
javaElementHandle= optionalText(javaElementHandle);
if (signatureIndex < -1) {
throw new IllegalArgumentException("signatureIndex must be -1 or a parameter index"); //$NON-NLS-1$
}
reason= requiredText(reason, "reason"); //$NON-NLS-1$
if (kind == SearchKind.FIELD_REFERENCES && bindingKey.isEmpty()) {
throw new IllegalArgumentException("Field reference search requires a binding key"); //$NON-NLS-1$
}
if (kind != SearchKind.FIELD_REFERENCES && ownerKey.isEmpty()) {
throw new IllegalArgumentException("Method search requires an owner key"); //$NON-NLS-1$
}
}
/** Stable key for deterministic de-duplication. */
public String stableKey() {
return kind + "|" + bindingKey + '|' + ownerKey + '|'
+ javaElementHandle + '|' + signatureIndex; //$NON-NLS-1$
}
/** Returns whether the workspace layer can resolve the exact Java element. */
public boolean hasJavaElementHandle() {
return !javaElementHandle.isEmpty();
}
}
public enum SearchKind {
FIELD_REFERENCES,
METHOD_DECLARATION,
METHOD_CALLERS,
METHOD_OVERRIDE_FAMILY
}
private static String requiredText(String value, String fieldName) {
String text= Objects.requireNonNull(value, fieldName).strip();
if (text.isEmpty()) {
throw new IllegalArgumentException(fieldName + " must not be empty"); //$NON-NLS-1$
}
return text;
}
private static String optionalText(String value) {
return value == null ? "" : value.strip(); //$NON-NLS-1$
}
}