// Path: src/main/java/org/codelibs/fess/suggest/concurrent/Deferred.java
// public class Deferred<RESPONSE extends Response> {
//     private RESPONSE response = null;
// 
//     private Throwable error = null;
// 
//     private final Promise promise = new Promise();
// 
//     private final Queue<Consumer<RESPONSE>> doneCallbacks = new LinkedBlockingQueue<>();
// 
//     private final Queue<Consumer<Throwable>> errorCallbacks = new LinkedBlockingQueue<>();
// 
//     private final CountDownLatch latch = new CountDownLatch(1);
// 
//     public void resolve(final RESPONSE r) {
//         final ArrayList<Consumer<RESPONSE>> executeCallbacks;
//         synchronized (Deferred.this) {
//             if (response != null || error != null) {
//                 return;
//             }
//             response = r;
// 
//             executeCallbacks = new ArrayList<>(doneCallbacks.size());
//             Consumer<RESPONSE> callback;
//             while ((callback = doneCallbacks.poll()) != null) {
//                 executeCallbacks.add(callback);
//             }
//         }
//         if (executeCallbacks.size() > 0) {
//             try {
//                 executeCallbacks.stream().forEach(callback -> callback.accept(response));
//             } catch (final Exception ignore) {}
//         }
//         latch.countDown();
//     }
// 
//     public void reject(final Throwable t) {
//         final ArrayList<Consumer<Throwable>> executeCallbacks;
//         synchronized (Deferred.this) {
//             if (response != null || error != null) {
//                 return;
//             }
//             error = t;
// 
//             executeCallbacks = new ArrayList<>(errorCallbacks.size());
//             Consumer<Throwable> callback;
//             while ((callback = errorCallbacks.poll()) != null) {
//                 executeCallbacks.add(callback);
//             }
//         }
//         if (executeCallbacks.size() > 0) {
//             try {
//                 executeCallbacks.stream().forEach(callback -> callback.accept(error));
//             } catch (final Exception ignore) {}
//         }
//         latch.countDown();
//     }
// 
//     public Promise then(final Consumer<RESPONSE> consumer) {
//         return promise.then(consumer);
//     }
// 
//     public Promise error(final Consumer<Throwable> consumer) {
//         return promise.error(consumer);
//     }
// 
//     public Promise promise() {
//         return promise;
//     }
// 
//     public class Promise {
//         public Promise then(final Consumer<RESPONSE> consumer) {
//             final ArrayList<Consumer<RESPONSE>> executeCallbacks;
//             synchronized (Deferred.this) {
//                 doneCallbacks.add(consumer);
//                 executeCallbacks = new ArrayList<>(doneCallbacks.size());
//                 if (response != null) {
//                     Consumer<RESPONSE> callback;
//                     while ((callback = doneCallbacks.poll()) != null) {
//                         executeCallbacks.add(callback);
//                     }
//                 }
//             }
//             if (executeCallbacks.size() > 0) {
//                 executeCallbacks.stream().forEach(callback -> callback.accept(response));
//             }
//             return this;
//         }
// 
//         public Promise error(final Consumer<Throwable> consumer) {
//             final ArrayList<Consumer<Throwable>> executeCallbacks;
//             synchronized (Deferred.this) {
//                 errorCallbacks.add(consumer);
//                 executeCallbacks = new ArrayList<>(errorCallbacks.size());
//                 if (error != null) {
//                     Consumer<Throwable> callback;
//                     while ((callback = errorCallbacks.poll()) != null) {
//                         executeCallbacks.add(callback);
//                     }
//                 }
//             }
//             if (executeCallbacks.size() > 0) {
//                 executeCallbacks.stream().forEach(callback -> callback.accept(error));
//             }
//             return this;
//         }
// 
//         public RESPONSE getResponse() {
//             return getResponse(1, TimeUnit.MINUTES);
//         }
// 
//         public RESPONSE getResponse(final long time, final TimeUnit unit) {
//             try {
//                 final boolean isTimeout = !latch.await(time, unit);
//                 if (isTimeout) {
//                     throw new SuggesterException("Request timeout. time:" + time + " unit:" + unit.name());
//                 }
//                 if (error != null) {
//                     throw new SuggesterException(error);
//                 }
//                 return response;
//             } catch (final InterruptedException e) {
//                 throw new SuggesterException(e);
//             }
//         }
//     }
// }
// 
// Path: src/main/java/org/codelibs/fess/suggest/exception/SuggesterException.java
// public class SuggesterException extends RuntimeException {
// 
//     private static final long serialVersionUID = 1L;
// 
//     public SuggesterException(final String msg) {
//         super(msg);
//     }
// 
//     public SuggesterException(final Throwable cause) {
//         super(cause);
//     }
// 
//     public SuggesterException(final String msg, final Throwable cause) {
//         super(msg, cause);
//     }
// }


import org.codelibs.fess.suggest.concurrent.Deferred;
import org.codelibs.fess.suggest.exception.SuggesterException;
import org.opensearch.client.Client;
import org.opensearch.common.Strings;
/*
 * Copyright 2012-2022 CodeLibs Project and the Others.
 *
 * 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 org.codelibs.fess.suggest.request;


public abstract class Request<T extends Response> {
    public Deferred<T>.Promise execute(final Client client) {
        final String error = getValidationError();
        if (!Strings.isNullOrEmpty(error)) {
            throw new IllegalArgumentException(error);
        }

        final Deferred<T> deferred = new Deferred<>();
        try {
            processRequest(client, deferred);
        } catch (final Exception e) {
// Path: src/main/java/org/codelibs/fess/suggest/concurrent/Deferred.java
// public class Deferred<RESPONSE extends Response> {
//     private RESPONSE response = null;
// 
//     private Throwable error = null;
// 
//     private final Promise promise = new Promise();
// 
//     private final Queue<Consumer<RESPONSE>> doneCallbacks = new LinkedBlockingQueue<>();
// 
//     private final Queue<Consumer<Throwable>> errorCallbacks = new LinkedBlockingQueue<>();
// 
//     private final CountDownLatch latch = new CountDownLatch(1);
// 
//     public void resolve(final RESPONSE r) {
//         final ArrayList<Consumer<RESPONSE>> executeCallbacks;
//         synchronized (Deferred.this) {
//             if (response != null || error != null) {
//                 return;
//             }
//             response = r;
// 
//             executeCallbacks = new ArrayList<>(doneCallbacks.size());
//             Consumer<RESPONSE> callback;
//             while ((callback = doneCallbacks.poll()) != null) {
//                 executeCallbacks.add(callback);
//             }
//         }
//         if (executeCallbacks.size() > 0) {
//             try {
//                 executeCallbacks.stream().forEach(callback -> callback.accept(response));
//             } catch (final Exception ignore) {}
//         }
//         latch.countDown();
//     }
// 
//     public void reject(final Throwable t) {
//         final ArrayList<Consumer<Throwable>> executeCallbacks;
//         synchronized (Deferred.this) {
//             if (response != null || error != null) {
//                 return;
//             }
//             error = t;
// 
//             executeCallbacks = new ArrayList<>(errorCallbacks.size());
//             Consumer<Throwable> callback;
//             while ((callback = errorCallbacks.poll()) != null) {
//                 executeCallbacks.add(callback);
//             }
//         }
//         if (executeCallbacks.size() > 0) {
//             try {
//                 executeCallbacks.stream().forEach(callback -> callback.accept(error));
//             } catch (final Exception ignore) {}
//         }
//         latch.countDown();
//     }
// 
//     public Promise then(final Consumer<RESPONSE> consumer) {
//         return promise.then(consumer);
//     }
// 
//     public Promise error(final Consumer<Throwable> consumer) {
//         return promise.error(consumer);
//     }
// 
//     public Promise promise() {
//         return promise;
//     }
// 
//     public class Promise {
//         public Promise then(final Consumer<RESPONSE> consumer) {
//             final ArrayList<Consumer<RESPONSE>> executeCallbacks;
//             synchronized (Deferred.this) {
//                 doneCallbacks.add(consumer);
//                 executeCallbacks = new ArrayList<>(doneCallbacks.size());
//                 if (response != null) {
//                     Consumer<RESPONSE> callback;
//                     while ((callback = doneCallbacks.poll()) != null) {
//                         executeCallbacks.add(callback);
//                     }
//                 }
//             }
//             if (executeCallbacks.size() > 0) {
//                 executeCallbacks.stream().forEach(callback -> callback.accept(response));
//             }
//             return this;
//         }
// 
//         public Promise error(final Consumer<Throwable> consumer) {
//             final ArrayList<Consumer<Throwable>> executeCallbacks;
//             synchronized (Deferred.this) {
//                 errorCallbacks.add(consumer);
//                 executeCallbacks = new ArrayList<>(errorCallbacks.size());
//                 if (error != null) {
//                     Consumer<Throwable> callback;
//                     while ((callback = errorCallbacks.poll()) != null) {
//                         executeCallbacks.add(callback);
//                     }
//                 }
//             }
//             if (executeCallbacks.size() > 0) {
//                 executeCallbacks.stream().forEach(callback -> callback.accept(error));
//             }
//             return this;
//         }
// 
//         public RESPONSE getResponse() {
//             return getResponse(1, TimeUnit.MINUTES);
//         }
// 
//         public RESPONSE getResponse(final long time, final TimeUnit unit) {
//             try {
//                 final boolean isTimeout = !latch.await(time, unit);
//                 if (isTimeout) {
//                     throw new SuggesterException("Request timeout. time:" + time + " unit:" + unit.name());
//                 }
//                 if (error != null) {
//                     throw new SuggesterException(error);
//                 }
//                 return response;
//             } catch (final InterruptedException e) {
//                 throw new SuggesterException(e);
//             }
//         }
//     }
// }
// 
// Path: src/main/java/org/codelibs/fess/suggest/exception/SuggesterException.java
// public class SuggesterException extends RuntimeException {
// 
//     private static final long serialVersionUID = 1L;
// 
//     public SuggesterException(final String msg) {
//         super(msg);
//     }
// 
//     public SuggesterException(final Throwable cause) {
//         super(cause);
//     }
// 
//     public SuggesterException(final String msg, final Throwable cause) {
//         super(msg, cause);
//     }
// }


// Path: src/main/java/org/codelibs/fess/suggest/request/Request.java
import org.codelibs.fess.suggest.concurrent.Deferred;
import org.codelibs.fess.suggest.exception.SuggesterException;
import org.opensearch.client.Client;
import org.opensearch.common.Strings;

/*
 * Copyright 2012-2022 CodeLibs Project and the Others.
 *
 * 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 org.codelibs.fess.suggest.request;


public abstract class Request<T extends Response> {
    public Deferred<T>.Promise execute(final Client client) {
        final String error = getValidationError();
        if (!Strings.isNullOrEmpty(error)) {
            throw new IllegalArgumentException(error);
        }

        final Deferred<T> deferred = new Deferred<>();
        try {
            processRequest(client, deferred);
        } catch (final Exception e) {
            throw new SuggesterException(e);