class ValidatorDetector extends OpcodeStackDetector {

    private static final String XXE_VALIDATOR_TYPE = "XXE_VALIDATOR";

    private static final String VALIDATOR_CLASS_NAME = "javax/xml/validation/Validator";

    private static final String SET_FEATURE_METHOD = "setFeature";

    private static final String SET_PROPERTY_METHOD = "setProperty";

    private static final String VALIDATE_METHOD_NAME = "validate";

    private static final Number BOOLEAN_TRUE_VALUE = 1;

    private static final String EXTERNAL_REFERENCES_DISABLED = "";

    private final BugReporter bugReporter;

    public ValidatorDetector(final BugReporter bugReporter) {
        this.bugReporter = bugReporter;
    }

    @Override
    public void sawOpcode(final int opcode) {<FILL_FUNCTION_BODY>}

    private boolean isNotValidateMethod(final int opcode) {
        boolean notValidateInvocation = true;

        if (Const.INVOKEVIRTUAL == opcode) {
            final String slashedClassName = getClassConstantOperand();
            final String methodName = getNameConstantOperand();
            if (VALIDATOR_CLASS_NAME.equals(slashedClassName) && VALIDATE_METHOD_NAME.equals(methodName)) {
                notValidateInvocation = false;
            }
        }

        return notValidateInvocation;
    }

    private boolean isSecureProcessingEnabled(final Location location, final ConstantPoolGen cpg) {
        boolean enabled = false;
        final Instruction instruction = location.getHandle().getInstruction();

        if (instruction instanceof INVOKEVIRTUAL) {
            final InvokeInstruction invokeInstruction = (InvokeInstruction) instruction;
            final String instructionMethodName = invokeInstruction.getMethodName(cpg);
            final InstructionHandle handle = location.getHandle();
            if (SET_FEATURE_METHOD.equals(instructionMethodName)) {
                final Object ldcValue = getLdcValue(handle, cpg);
                if (XMLConstants.FEATURE_SECURE_PROCESSING.equals(ldcValue)) {
                    final ICONST constant = ByteCode.getPrevInstruction(handle, ICONST.class);
                    enabled = constant != null && BOOLEAN_TRUE_VALUE.equals(constant.getValue());
                }
            }
        }

        return enabled;
    }

    private boolean isAccessPropertyDisabled(final Location location, final ConstantPoolGen cpg, final String accessPropertyName) {
        boolean enabled = false;
        final Instruction instruction = location.getHandle().getInstruction();

        if (instruction instanceof INVOKEVIRTUAL) {
            final InvokeInstruction invokeInstruction = (InvokeInstruction) instruction;
            final String instructionMethodName = invokeInstruction.getMethodName(cpg);
            final InstructionHandle handle = location.getHandle();
            if (SET_PROPERTY_METHOD.equals(instructionMethodName)) {
                final Object propertyName = getLdcValue(handle.getPrev(), cpg);
                final Object propertyValue = getLdcValue(handle, cpg);
                if (accessPropertyName.equals(propertyName)) {
                    enabled = EXTERNAL_REFERENCES_DISABLED.equals(propertyValue);
                }
            }
        }

        return enabled;
    }

    private Object getLdcValue(final InstructionHandle instructionHandle, final ConstantPoolGen cpg) {
        final LDC ldc = ByteCode.getPrevInstruction(instructionHandle, LDC.class);
        return ldc == null ? null : ldc.getValue(cpg);
    }
}

        if (isNotValidateMethod(opcode)) {
            return;
        }

        final ClassContext classContext = getClassContext();
        final CFG cfg;
        try {
            cfg = classContext.getCFG(getMethod());
        } catch (final CFGBuilderException e) {
            AnalysisContext.logError("Cannot get CFG", e);
            return;
        }

        final ConstantPoolGen cpg = classContext.getConstantPoolGen();

        boolean secureProcessingEnabled = false;
        boolean accessExternalDtdDisabled = false;
        boolean accessExternalSchemaDisabled = false;

        for (final Location location : cfg.locations()) {
            if (isSecureProcessingEnabled(location, cpg)) {
                secureProcessingEnabled = true;
            } else if (isAccessPropertyDisabled(location, cpg, XMLConstants.ACCESS_EXTERNAL_DTD)) {
                accessExternalDtdDisabled = true;
            } else if (isAccessPropertyDisabled(location, cpg, XMLConstants.ACCESS_EXTERNAL_SCHEMA)) {
                accessExternalSchemaDisabled = true;
            }
        }

        // Enabling Secure Processing or disabling both Access External DTD and Access External Schema are solutions
        if (secureProcessingEnabled || (accessExternalDtdDisabled && accessExternalSchemaDisabled)) {
            return;
        }

        bugReporter.reportBug(new BugInstance(this, XXE_VALIDATOR_TYPE, Priorities.HIGH_PRIORITY)
                .addClass(this).addMethod(this).addSourceLine(this));
    
<no_super_class>