Search in sources :

Example 6 with ProcedureSignature

use of org.neo4j.internal.kernel.api.procs.ProcedureSignature in project neo4j by neo4j.

the class ProcedureSignatureTest method shouldHonorVoidInEquals.

@Test
void shouldHonorVoidInEquals() {
    ProcedureSignature sig1 = procedureSignature("foo").in("a", Neo4jTypes.NTAny).build();
    ProcedureSignature sig2 = procedureSignature("foo").in("a", Neo4jTypes.NTAny).out(ProcedureSignature.VOID).build();
    ProcedureSignature sig2clone = procedureSignature("foo").in("a", Neo4jTypes.NTAny).out(ProcedureSignature.VOID).build();
    assertEquals(sig2, sig2clone);
    assertNotEquals(sig1, sig2);
}
Also used : ProcedureSignature(org.neo4j.internal.kernel.api.procs.ProcedureSignature) Test(org.junit.jupiter.api.Test)

Example 7 with ProcedureSignature

use of org.neo4j.internal.kernel.api.procs.ProcedureSignature in project neo4j by neo4j.

the class ProcedureCompilation method compileProcedure.

/**
 * Generates code for a user-defined procedure.
 * <p>
 * Given a user-defined function defined by
 *
 * <pre>
 *     class MyClass {
 *       {@literal @}Context
 *        public Log log;
 *
 *       {@literal @}Procedure
 *        public Stream<MyOut> myStream(long value) {
 *            ...
 *        }
 *     }
 * </pre>
 * <p>
 * we will generate something like
 *
 * <pre>
 *     class GeneratedMyStream implements CallableProcedure {
 *         public static ProcedureSignature SIGNATURE;
 *         public static FieldSetter SETTER_0;
 *
 *          RawIterator<AnyValue[], ProcedureException> apply( Context ctx, AnyValue[] in, ResourceTracker tracker ) throws ProcedureException {
 *              try {
 *                  MyClass userClass = new MyClass();
 *                  userClass.log = (Log) SETTER_0.get(ctx);
 *                  Stream<MyOut> fromUser = userClass.myStream(((NumberValue) input[0]).longValue() );
 *                  return new GeneratedIterator(fromUser, tracker, SIGNATURE);
 *              } catch (Throwable T) {
 *                  throw new ProcedureException([appropriate error msg], T);
 *              }
 *         }
 *
 *         public ProcedureSignature signature() {return SIGNATURE;}
 *     }
 * </pre>
 * <p>
 * where the static fields are set once during loading via reflection and where the <tt>GeneratedIterator</tt>
 * implements the appropriate mapping from user-types Object[] to AnyValue[].
 *
 * @param signature the signature of the procedure
 * @param fieldSetters the fields to set before each call.
 * @param methodToCall the method to call
 * @return a CallableProcedure delegating to the underlying procedure method.
 * @throws ProcedureException if something went wrong when compiling the user-defined function.
 */
static CallableProcedure compileProcedure(ProcedureSignature signature, List<FieldSetter> fieldSetters, Method methodToCall) throws ProcedureException {
    ClassHandle handle;
    try {
        CodeGenerator codeGenerator = codeGenerator();
        Class<?> iterator = generateIterator(codeGenerator, procedureType(methodToCall));
        try (ClassGenerator generator = codeGenerator.generateClass(PACKAGE, className(signature), CallableProcedure.class)) {
            // static fields
            FieldReference signatureField = generator.publicStaticField(typeReference(ProcedureSignature.class), SIGNATURE_NAME);
            List<FieldReference> fieldsToSet = createContextSetters(fieldSetters, generator);
            // CallableProcedure::apply
            try (CodeBlock method = generator.generate(USER_PROCEDURE)) {
                method.tryCatch(body -> procedureBody(body, fieldSetters, fieldsToSet, signatureField, methodToCall, iterator), onError -> onError(onError, format("procedure `%s`", signature.name())), param(Throwable.class, "T"));
            }
            // CallableUserFunction::signature
            try (CodeBlock method = generator.generateMethod(ProcedureSignature.class, "signature")) {
                method.returns(getStatic(signatureField));
            }
            handle = generator.handle();
        }
        Class<?> clazz = handle.loadClass();
        // set all static fields
        setAllStaticFields(signature, fieldSetters, methodToCall, clazz);
        return (CallableProcedure) clazz.getConstructor().newInstance();
    } catch (Throwable e) {
        throw new ProcedureException(Status.Procedure.ProcedureRegistrationFailed, e, "Failed to compile procedure defined in `%s`: %s", methodToCall.getDeclaringClass().getSimpleName(), e.getMessage());
    }
}
Also used : ProcedureSignature(org.neo4j.internal.kernel.api.procs.ProcedureSignature) ClassGenerator(org.neo4j.codegen.ClassGenerator) FieldReference(org.neo4j.codegen.FieldReference) CodeBlock(org.neo4j.codegen.CodeBlock) CallableProcedure(org.neo4j.kernel.api.procedure.CallableProcedure) CodeGenerator(org.neo4j.codegen.CodeGenerator) ProcedureException(org.neo4j.internal.kernel.api.exceptions.ProcedureException) ClassHandle(org.neo4j.codegen.ClassHandle)

Example 8 with ProcedureSignature

use of org.neo4j.internal.kernel.api.procs.ProcedureSignature in project neo4j by neo4j.

the class ProcedureCompiler method compileProcedure.

private CallableProcedure compileProcedure(Class<?> procDefinition, Method method, String warning, boolean fullAccess, QualifiedName procName) throws ProcedureException {
    List<FieldSignature> inputSignature = inputSignatureDeterminer.signatureFor(method);
    List<FieldSignature> outputSignature = outputSignatureCompiler.fieldSignatures(method);
    String description = description(method);
    Procedure procedure = method.getAnnotation(Procedure.class);
    Mode mode = procedure.mode();
    boolean admin = method.isAnnotationPresent(Admin.class);
    boolean systemProcedure = method.isAnnotationPresent(SystemProcedure.class);
    boolean allowExpiredCredentials = systemProcedure ? method.getAnnotation(SystemProcedure.class).allowExpiredCredentials() : false;
    boolean internal = method.isAnnotationPresent(Internal.class);
    String deprecated = deprecated(method, procedure::deprecatedBy, "Use of @Procedure(deprecatedBy) without @Deprecated in " + procName);
    List<FieldSetter> setters = allFieldInjections.setters(procDefinition);
    if (!fullAccess && !config.fullAccessFor(procName.toString())) {
        try {
            setters = safeFieldInjections.setters(procDefinition);
        } catch (ComponentInjectionException e) {
            description = describeAndLogLoadFailure(procName);
            ProcedureSignature signature = new ProcedureSignature(procName, inputSignature, outputSignature, Mode.DEFAULT, admin, null, new String[0], description, warning, procedure.eager(), false, systemProcedure, internal, allowExpiredCredentials);
            return new FailedLoadProcedure(signature);
        }
    }
    ProcedureSignature signature = new ProcedureSignature(procName, inputSignature, outputSignature, mode, admin, deprecated, config.rolesFor(procName.toString()), description, warning, procedure.eager(), false, systemProcedure, internal, allowExpiredCredentials);
    return ProcedureCompilation.compileProcedure(signature, setters, method);
}
Also used : ProcedureSignature(org.neo4j.internal.kernel.api.procs.ProcedureSignature) FailedLoadProcedure(org.neo4j.kernel.api.procedure.FailedLoadProcedure) Mode(org.neo4j.procedure.Mode) SystemProcedure(org.neo4j.kernel.api.procedure.SystemProcedure) Procedure(org.neo4j.procedure.Procedure) FailedLoadProcedure(org.neo4j.kernel.api.procedure.FailedLoadProcedure) CallableProcedure(org.neo4j.kernel.api.procedure.CallableProcedure) FieldSignature(org.neo4j.internal.kernel.api.procs.FieldSignature) ComponentInjectionException(org.neo4j.kernel.api.exceptions.ComponentInjectionException)

Example 9 with ProcedureSignature

use of org.neo4j.internal.kernel.api.procs.ProcedureSignature in project neo4j by neo4j.

the class ProcedureRegistry method register.

/**
 * Register a new procedure.
 *
 * @param proc the procedure.
 */
public void register(CallableProcedure proc, boolean overrideCurrentImplementation) throws ProcedureException {
    ProcedureSignature signature = proc.signature();
    QualifiedName name = signature.name();
    String descriptiveName = signature.toString();
    validateSignature(descriptiveName, signature.inputSignature(), "input");
    validateSignature(descriptiveName, signature.outputSignature(), "output");
    if (!signature.isVoid() && signature.outputSignature().isEmpty()) {
        throw new ProcedureException(Status.Procedure.ProcedureRegistrationFailed, "Procedures with zero output fields must be declared as VOID");
    }
    CallableProcedure oldImplementation = procedures.get(name);
    if (oldImplementation == null) {
        procedures.put(name, proc, signature.caseInsensitive());
    } else {
        if (overrideCurrentImplementation) {
            procedures.put(name, proc, signature.caseInsensitive());
        } else {
            throw new ProcedureException(Status.Procedure.ProcedureRegistrationFailed, "Unable to register procedure, because the name `%s` is already in use.", name);
        }
    }
}
Also used : ProcedureSignature(org.neo4j.internal.kernel.api.procs.ProcedureSignature) QualifiedName(org.neo4j.internal.kernel.api.procs.QualifiedName) CallableProcedure(org.neo4j.kernel.api.procedure.CallableProcedure) ProcedureException(org.neo4j.internal.kernel.api.exceptions.ProcedureException)

Example 10 with ProcedureSignature

use of org.neo4j.internal.kernel.api.procs.ProcedureSignature in project neo4j by neo4j.

the class ProceduresKernelIT method shouldGetBuiltInProcedureByName.

@Test
void shouldGetBuiltInProcedureByName() throws Throwable {
    // When
    ProcedureSignature found = procs().procedureGet(procedureName("db", "labels")).signature();
    // Then
    assertThat(found).isEqualTo(procedureSignature(procedureName("db", "labels")).out("label", NTString).build());
    commit();
}
Also used : ProcedureSignature(org.neo4j.internal.kernel.api.procs.ProcedureSignature) Test(org.junit.jupiter.api.Test)

Aggregations

ProcedureSignature (org.neo4j.internal.kernel.api.procs.ProcedureSignature)18 Test (org.junit.jupiter.api.Test)14 CallableProcedure (org.neo4j.kernel.api.procedure.CallableProcedure)12 ProcedureException (org.neo4j.internal.kernel.api.exceptions.ProcedureException)5 URL (java.net.URL)4 QualifiedName (org.neo4j.internal.kernel.api.procs.QualifiedName)3 AnyValue (org.neo4j.values.AnyValue)3 Context (org.neo4j.kernel.api.procedure.Context)2 Method (java.lang.reflect.Method)1 Random (java.util.Random)1 Stream (java.util.stream.Stream)1 BeforeAll (org.junit.jupiter.api.BeforeAll)1 ClassGenerator (org.neo4j.codegen.ClassGenerator)1 ClassHandle (org.neo4j.codegen.ClassHandle)1 CodeBlock (org.neo4j.codegen.CodeBlock)1 CodeGenerator (org.neo4j.codegen.CodeGenerator)1 FieldReference (org.neo4j.codegen.FieldReference)1 FieldSignature (org.neo4j.internal.kernel.api.procs.FieldSignature)1 NTString (org.neo4j.internal.kernel.api.procs.Neo4jTypes.NTString)1 ProcedureHandle (org.neo4j.internal.kernel.api.procs.ProcedureHandle)1