001package gudusoft.gsqlparser.runtime;
002
003/**
004 * Thrown when an entitlement-gated build is used without a valid entitlement.
005 *
006 * <p><b>This build fails explicitly rather than returning a wrong answer.</b>
007 * An earlier design silently deleted a statement from every parse, so an
008 * unlicensed user got plausible but incomplete results. That is worse than a
009 * refusal in every direction that matters: it is indistinguishable from a
010 * parser bug, it corrupts downstream lineage and impact analysis without
011 * anyone noticing, and it costs the vendor the support calls too. Supportability
012 * wins over covertness.</p>
013 *
014 * <p>Extends {@link IllegalStateException} so existing callers that already
015 * handle unchecked failures from {@code parse()} keep working.</p>
016 *
017 * @see GspRuntime#activate(byte[])
018 */
019public class GspNotActivatedException extends IllegalStateException {
020
021    private static final long serialVersionUID = 1L;
022
023    private final GspActivation activation;
024
025    GspNotActivatedException(GspActivation activation) {
026        super("GSP is not activated: this build requires a signed entitlement. "
027            + "reason=" + activation.reasonCode()
028            + " audit=" + activation.auditId()
029            + ". Call GspRuntime.activate(byte[]) with a valid entitlement "
030            + "before parsing.");
031        this.activation = activation;
032    }
033
034    /** The activation state that caused the refusal, for logging and support. */
035    public GspActivation getActivation() {
036        return activation;
037    }
038
039    /** Stable machine-readable reason, e.g. {@code EXPIRED}, {@code MISSING}. */
040    public String reasonCode() {
041        return activation.reasonCode();
042    }
043
044    /** Correlates this refusal with the GSP_ENTITLEMENT_REFUSED log line. */
045    public String auditId() {
046        return activation.auditId();
047    }
048}