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

zone.gryphon.screech.ScreechBuilder Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2018-2018 Gryphon Zone
 *
 * 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 zone.gryphon.screech;

import lombok.NonNull;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import zone.gryphon.screech.internal.AsyncInvocationHandler;
import zone.gryphon.screech.internal.ScreechThreadFactory;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

@Slf4j
@ToString
public class ScreechBuilder {

    private final int numCores = Runtime.getRuntime().availableProcessors();

    private final Supplier executorSupplier = () -> new ThreadPoolExecutor(numCores, numCores,
            Long.MAX_VALUE, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(), new ScreechThreadFactory("ScreechClient"));

    private RequestEncoder requestEncoder = new RequestEncoder.StringRequestEncoder();

    private List requestInterceptors = new ArrayList<>();

    private ResponseDecoderFactory responseDecoder = new ResponseDecoderFactory.SuccessResponseDecoderFactory();

    private ResponseDecoderFactory errorDecoder = new ResponseDecoderFactory.ErrorResponseDecoderFactory();

    private Executor requestExecutor = null;

    private Executor responseExecutor = null;

    private Client client;

    public ScreechBuilder(@NonNull Client client) {
        this.client = client;
    }

    public ScreechBuilder requestEncoder(@NonNull RequestEncoder requestEncoder) {
        this.requestEncoder = requestEncoder;
        return this;
    }

    public ScreechBuilder addRequestInterceptor(@NonNull RequestInterceptor requestInterceptor) {
        this.requestInterceptors.add(requestInterceptor);
        return this;
    }

    public ScreechBuilder addRequestInterceptors(@NonNull Iterable requestInterceptors) {
        requestInterceptors.forEach(this::addRequestInterceptor);
        return this;
    }

    public ScreechBuilder responseDecoder(@NonNull ResponseDecoderFactory responseDecoder) {
        this.responseDecoder = responseDecoder;
        return this;
    }

    public ScreechBuilder errorDecoder(@NonNull ResponseDecoderFactory errorDecoder) {
        this.errorDecoder = errorDecoder;
        return this;
    }

    public ScreechBuilder requestExecutor(@NonNull Executor executor) {
        this.requestExecutor = executor;
        return this;
    }

    public ScreechBuilder responseExecutor(@NonNull Executor executor) {
        this.responseExecutor = executor;
        return this;
    }

    private Executor getOrDefaultRequestExecutor() {
        return requestExecutor == null ? executorSupplier.get() : requestExecutor;
    }

    private Executor getOrDefaultResponseExecutor() {
        return responseExecutor == null ? executorSupplier.get() : responseExecutor;
    }

    public  T build(Class clazz, Target target) {

        Map map = new HashMap<>();

        Executor requestExecutor = getOrDefaultRequestExecutor();

        Executor responseExecutor = getOrDefaultResponseExecutor();

        for (Method method : clazz.getMethods()) {
            map.put(method, AsyncInvocationHandler.from(method, requestEncoder, requestInterceptors, responseDecoder, errorDecoder, client, target, requestExecutor, responseExecutor));
        }

        InvocationHandler handler = (proxy, method, args) -> map.get(method).invoke(proxy, method, args);

        //noinspection unchecked
        T proxy = (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[]{clazz}, handler);

        try {
            final String toStringValue = String.format("%s{%s}", clazz.getSimpleName(), target.getClass().getSimpleName());
            Method toString = Object.class.getDeclaredMethod("toString");
            map.put(toString, (x, y, z) -> toStringValue);

            final int hashCodeValue = Objects.hash(map);
            Method hashCode = Object.class.getDeclaredMethod("hashCode");
            map.put(hashCode, (x, y, z) -> hashCodeValue);

            Method equals = Object.class.getDeclaredMethod("equals", Object.class);
            map.put(equals, (x, y, z) -> z[0] == proxy);

        } catch (Exception e) {
            throw new RuntimeException("Failed to construct proxy", e);
        }

        return proxy;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy