All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.openhft.chronicle.wire.AbstractMethodWriterInvocationHandler Maven / Gradle / Ivy

There is a newer version: 2.27ea1
Show newest version
/*
 * Copyright 2016-2020 chronicle.software
 *
 *       https://chronicle.software
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package net.openhft.chronicle.wire;

import net.openhft.chronicle.bytes.MethodReader;
import net.openhft.chronicle.bytes.MethodWriterInvocationHandler;
import net.openhft.chronicle.core.io.InvalidMarshallableException;
import net.openhft.chronicle.core.util.AbstractInvocationHandler;
import org.jetbrains.annotations.NotNull;

import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * An abstract handler for method writer invocations that provides a base implementation.
 * It manages the invocation by mapping methods to their respective parameter holders and writing them to wires.
 * This class can handle both regular and generic events and supports method IDs for binary output.
 */
public abstract class AbstractMethodWriterInvocationHandler extends AbstractInvocationHandler implements MethodWriterInvocationHandler {

    // Map to cache the parameter holders for method invocations
    private final Map parameterMap = new ConcurrentHashMap<>();
    protected boolean recordHistory;

    // Name for the generic event, if any. A generic event take the event name as the first argument
    protected String genericEvent = "";

    // Flag to determine if method IDs should be used in binary output
    private boolean useMethodIds;

    /**
     * Constructor accepting the type of class the handler operates on.
     *
     * @param tClass The class type this handler is designed for.
     */
    protected AbstractMethodWriterInvocationHandler(Class tClass) {
        super(tClass);
    }

    @Override
    protected Object doInvoke(Object proxy, Method method, Object[] args) {
        handleInvoke(method, args);

        return method.getReturnType().isInterface() ? proxy : null;
    }

    @Override
    public void genericEvent(String genericEvent) {
        this.genericEvent = genericEvent;
    }

    /**
     * Abstract method to handle a method invocation with its respective arguments.
     *
     * @param method The method being invoked.
     * @param args   Arguments provided for the method invocation.
     */
    protected abstract void handleInvoke(Method method, Object[] args);

    /**
     * Handles the method invocation, writes the event details to the provided wire,
     * and supports optional recording of method history.
     *
     * @param method The method being invoked.
     * @param args   Arguments provided for the method invocation.
     * @param wire   The wire output to write the event details.
     * @throws InvalidMarshallableException If there's an error during marshalling.
     */
    protected void handleInvoke(@NotNull Method method, Object[] args, Wire wire) throws InvalidMarshallableException {
        if (recordHistory) {
            wire.writeEventName(MethodReader.HISTORY)
                    .marshallable(MessageHistory.get());
        }
        String methodName = method.getName();

        // Distinguish between a generic event and a regular one
        if (methodName.equals(genericEvent)) {
            writeGenericEvent(wire, method, args);
            return;
        }
        writeEvent(wire, method, methodName, args);
    }

    // Helper to write a regular event to the wire
    private void writeEvent(Wire wire, @NotNull Method method, String methodName, Object[] args) throws InvalidMarshallableException {
        writeEvent0(wire, method, args, methodName, 0);
    }

    // Helper to write a generic event to the wire
    private void writeGenericEvent(Wire wire, @NotNull Method method, Object[] args) throws InvalidMarshallableException {
        String methodName = args[0].toString();
        writeEvent0(wire, method, args, methodName, 1);
    }

    // Core logic to write events to the wire, distinguishing between methods with and without arguments
    @SuppressWarnings("unchecked")
    private void writeEvent0(Wire wire, @NotNull Method method, Object[] args, String methodName, int oneParam) throws InvalidMarshallableException {
        // Fetch or compute the parameter holder for the method
        final ParameterHolderSequenceWriter phsw = parameterMap.computeIfAbsent(method, ParameterHolderSequenceWriter::new);
        boolean useMethodId = useMethodIds && phsw.methodId >= 0 && wire.getValueOut().isBinary();
        ValueOut valueOut = useMethodId
                ? wire.writeEventId((int) phsw.methodId)
                : wire.writeEventName(methodName);

        // Write to the wire based on argument count
        switch (args.length - oneParam) {
            case 0:
                valueOut.text("");
                break;
            case 1:
                Object arg = args[oneParam];
                if (arg != null && arg.getClass() == RawText.class)
                    valueOut.rawText(((RawText) arg).text);
                else
                    valueOut.object(phsw.parameterTypes[oneParam], arg);
                break;
            default:
                valueOut.sequence(args, oneParam == 0 ? phsw.from0 : phsw.from1);
        }
    }

    @Override
    public void recordHistory(boolean recordHistory) {
        this.recordHistory = recordHistory;
    }

    @Override
    public void useMethodIds(boolean useMethodIds) {
        this.useMethodIds = useMethodIds;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy