package android.mtp;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
import android.os.ParcelFileDescriptor;
import android.os.UserManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import java.io.IOException;

public final class MtpDevice {

    private static final String TAG = "MtpDevice";

    @GuardedBy("mLock")
    private CloseGuard mCloseGuard = CloseGuard.get();

    @GuardedBy("mLock")
    private UsbDeviceConnection mConnection;

    private final UsbDevice mDevice;

    private final Object mLock = new Object();

    private long mNativeContext;

    private native void native_close();

    private native boolean native_delete_object(int i);

    private native void native_discard_event_request(int i);

    private native MtpDeviceInfo native_get_device_info();

    private native byte[] native_get_object(int i, long j);

    private native int[] native_get_object_handles(int i, int i2, int i3);

    private native MtpObjectInfo native_get_object_info(int i);

    private native long native_get_object_size_long(int i, int i2) throws IOException;

    private native int native_get_parent(int i);

    private native long native_get_partial_object(int i, long j, long j2, byte[] bArr) throws IOException;

    private native int native_get_partial_object_64(int i, long j, long j2, byte[] bArr) throws IOException;

    private native int native_get_storage_id(int i);

    private native int[] native_get_storage_ids();

    private native MtpStorageInfo native_get_storage_info(int i);

    private native byte[] native_get_thumbnail(int i);

    private native boolean native_import_file(int i, int i2);

    private native boolean native_import_file(int i, String str);

    private native boolean native_open(String str, int i);

    private native MtpEvent native_reap_event_request(int i) throws IOException;

    private native boolean native_send_object(int i, long j, int i2);

    private native MtpObjectInfo native_send_object_info(MtpObjectInfo mtpObjectInfo);

    private native int native_submit_event_request() throws IOException;

    static {
        System.loadLibrary("media_jni");
    }

    public MtpDevice(UsbDevice device) {
        Preconditions.checkNotNull(device);
        this.mDevice = device;
    }

    public boolean open(UsbDeviceConnection connection) {
        boolean result = false;
        Context context = connection.getContext();
        synchronized (this.mLock) {
            if (context != null) {
                if (!((UserManager) context.getSystemService(Context.USER_SERVICE)).hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
                    result = native_open(this.mDevice.getDeviceName(), connection.getFileDescriptor());
                }
            }
            if (result) {
                this.mConnection = connection;
                this.mCloseGuard.open("close");
            } else {
                connection.close();
            }
        }
        return result;
    }

    public void close() {
        synchronized (this.mLock) {
            if (this.mConnection != null) {
                this.mCloseGuard.close();
                native_close();
                this.mConnection.close();
                this.mConnection = null;
            }
        }
    }

    protected void finalize() throws Throwable {
        try {
            if (this.mCloseGuard != null) {
                this.mCloseGuard.warnIfOpen();
            }
            close();
        } finally {
            super.finalize();
        }
    }

    public String getDeviceName() {
        return this.mDevice.getDeviceName();
    }

    public int getDeviceId() {
        return this.mDevice.getDeviceId();
    }

{
        return this.mDevice.getDeviceName();
    }

    public MtpDeviceInfo getDeviceInfo() {
        return native_get_device_info();
    }

    public int[] getStorageIds() {
        return native_get_storage_ids();
    }

    public int[] getObjectHandles(int storageId, int format, int objectHandle) {
        return native_get_object_handles(storageId, format, objectHandle);
    }

    public byte[] getObject(int objectHandle, int objectSize) {
        Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
        return native_get_object(objectHandle, (long) objectSize);
    }

    public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer) throws IOException {
        return native_get_partial_object(objectHandle, offset, size, buffer);
    }

    public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer) throws IOException {
        return (long) native_get_partial_object_64(objectHandle, offset, size, buffer);
    }

    public byte[] getThumbnail(int objectHandle) {
        return native_get_thumbnail(objectHandle);
    }

    public MtpStorageInfo getStorageInfo(int storageId) {
        return native_get_storage_info(storageId);
    }

    public MtpObjectInfo getObjectInfo(int objectHandle) {
        return native_get_object_info(objectHandle);
    }

    public boolean deleteObject(int objectHandle) {
        return native_delete_object(objectHandle);
    }

    public long getParent(int objectHandle) {
        return (long) native_get_parent(objectHandle);
    }

    public long getStorageId(int objectHandle) {
        return (long) native_get_storage_id(objectHandle);
    }

    public boolean importFile(int objectHandle, String destPath) {
        return native_import_file(objectHandle, destPath);
    }

    public boolean importFile(int objectHandle, ParcelFileDescriptor descriptor) {
        return native_import_file(objectHandle, descriptor.getFd());
    }

    public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
        return native_send_object(objectHandle, size, descriptor.getFd());
    }

    public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
        return native_send_object_info(info);
    }

    public MtpEvent readEvent(CancellationSignal signal) throws IOException {
        boolean z = false;
        final int handle = native_submit_event_request();
        if (handle >= 0) {
            z = true;
        }
        Preconditions.checkState(z, "Other thread is reading an event.");
        if (signal != null) {
            signal.setOnCancelListener(new OnCancelListener() {

                public void onCancel() {
                    MtpDevice.this.native_discard_event_request(handle);
                }
            });
        }
        try {
            MtpEvent native_reap_event_request = native_reap_event_request(handle);
            return native_reap_event_request;
        } finally {
            if (signal != null) {
                signal.setOnCancelListener(null);
            }
        }
    }

    public long getObjectSizeLong(int handle, int format) throws IOException {
        return native_get_object_size_long(handle, format);
    }
}


{
        return native_get_object_size_long(handle, format);
    }

package android.mtp;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
import android.os.ParcelFileDescriptor;
import android.os.UserManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import java.io.IOException;

public final class MtpDevice {

    private static final String TAG = "MtpDevice";

    @GuardedBy("mLock")
    private CloseGuard mCloseGuard = CloseGuard.get();

    @GuardedBy("mLock")
    private UsbDeviceConnection mConnection;

    private final UsbDevice mDevice;

    private final Object mLock = new Object();

    private long mNativeContext;

    private native void native_close();

    private native boolean native_delete_object(int i);

    private native void native_discard_event_request(int i);

    private native MtpDeviceInfo native_get_device_info();

    private native byte[] native_get_object(int i, long j);

    private native int[] native_get_object_handles(int i, int i2, int i3);

    private native MtpObjectInfo native_get_object_info(int i);

    private native long native_get_object_size_long(int i, int i2) throws IOException;

    private native int native_get_parent(int i);

    private native long native_get_partial_object(int i, long j, long j2, byte[] bArr) throws IOException;

    private native int native_get_partial_object_64(int i, long j, long j2, byte[] bArr) throws IOException;

    private native int native_get_storage_id(int i);

    private native int[] native_get_storage_ids();

    private native MtpStorageInfo native_get_storage_info(int i);

    private native byte[] native_get_thumbnail(int i);

    private native boolean native_import_file(int i, int i2);

    private native boolean native_import_file(int i, String str);

    private native boolean native_open(String str, int i);

    private native MtpEvent native_reap_event_request(int i) throws IOException;

    private native boolean native_send_object(int i, long j, int i2);

    private native MtpObjectInfo native_send_object_info(MtpObjectInfo mtpObjectInfo);

    private native int native_submit_event_request() throws IOException;

    static {
        System.loadLibrary("media_jni");
    }

    public MtpDevice(UsbDevice device) {
        Preconditions.checkNotNull(device);
        this.mDevice = device;
    }

    public boolean open(UsbDeviceConnection connection) {
        boolean result = false;
        Context context = connection.getContext();
        synchronized (this.mLock) {
            if (context != null) {
                if (!((UserManager) context.getSystemService(Context.USER_SERVICE)).hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
                    result = native_open(this.mDevice.getDeviceName(), connection.getFileDescriptor());
                }
            }
            if (result) {
                this.mConnection = connection;
                this.mCloseGuard.open("close");
            } else {
                connection.close();
            }
        }
        return result;
    }

    public void close() {
        synchronized (this.mLock) {
            if (this.mConnection != null) {
                this.mCloseGuard.close();
                native_close();
                this.mConnection.close();
                this.mConnection = null;
            }
        }
    }

    protected void finalize() throws Throwable {
        try {
            if (this.mCloseGuard != null) {
                this.mCloseGuard.warnIfOpen();
            }
            close();
        } finally {
            super.finalize();
        }
    }

    public String getDeviceName() {
        return this.mDevice.getDeviceName();
    }

    public int getDeviceId() {
        return this.mDevice.getDeviceId();
    }

    public String toString() {
        return this.mDevice.getDeviceName();
    }

    public MtpDeviceInfo getDeviceInfo() {
        return native_get_device_info();
    }

    public int[] getStorageIds() {
        return native_get_storage_ids();
    }

    public int[] getObjectHandles(int storageId, int format, int objectHandle) {
        return native_get_object_handles(storageId, format, objectHandle);
    }

    public byte[] getObject(int objectHandle, int objectSize) {
        Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
        return native_get_object(objectHandle, (long) objectSize);
    }

    public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer) throws IOException {
        return native_get_partial_object(objectHandle, offset, size, buffer);
    }

    public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer) throws IOException {
        return (long) native_get_partial_object_64(objectHandle, offset, size, buffer);
    }

    public byte[] getThumbnail(int objectHandle) {
        return native_get_thumbnail(objectHandle);
    }

    public MtpStorageInfo getStorageInfo(int storageId) {
        return native_get_storage_info(storageId);
    }

    public MtpObjectInfo getObjectInfo(int objectHandle) {
        return native_get_object_info(objectHandle);
    }

    public boolean deleteObject(int objectHandle) {
        return native_delete_object(objectHandle);
    }

    public long getParent(int objectHandle) {
        return (long) native_get_parent(objectHandle);
    }

    public long getStorageId(int objectHandle) {
        return (long) native_get_storage_id(objectHandle);
    }

    public boolean importFile(int objectHandle, String destPath) {
        return native_import_file(objectHandle, destPath);
    }

    public boolean importFile(int objectHandle, ParcelFileDescriptor descriptor) {
        return native_import_file(objectHandle, descriptor.getFd());
    }

    public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
        return native_send_object(objectHandle, size, descriptor.getFd());
    }

    public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
        return native_send_object_info(info);
    }

    public MtpEvent readEvent(CancellationSignal signal) throws IOException {
        boolean z = false;
        final int handle = native_submit_event_request();
        if (handle >= 0) {
            z = true;
        }
        Preconditions.checkState(z, "Other thread is reading an event.");
        if (signal != null) {
            signal.setOnCancelListener(new OnCancelListener() {

                public void onCancel() {
                    MtpDevice.this.native_discard_event_request(handle);
                }
            });
        }
        try {
            MtpEvent native_reap_event_request = native_reap_event_request(handle);
            return native_reap_event_request;
        } finally {
            if (signal != null) {
                signal.setOnCancelListener(null);
            }
        }
    }

    public long getObjectSizeLong(int handle, int format) throws IOException


package android.mtp;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
import android.os.ParcelFileDescriptor;
import android.os.UserManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import java.io.IOException;

public final class MtpDevice {

    private static final String TAG = "MtpDevice";

    @GuardedBy("mLock")
    private CloseGuard mCloseGuard = CloseGuard.get();

    @GuardedBy("mLock")
    private UsbDeviceConnection mConnection;

    private final UsbDevice mDevice;

    private final Object mLock = new Object();

    private long mNativeContext;

    private native void native_close();

    private native boolean native_delete_object(int i);

    private native void native_discard_event_request(int i);

    private native MtpDeviceInfo native_get_device_info();

    private native byte[] native_get_object(int i, long j);

    private native int[] native_get_object_handles(int i, int i2, int i3);

    private native MtpObjectInfo native_get_object_info(int i);

    private native long native_get_object_size_long(int i, int i2) throws IOException;

    private native int native_get_parent(int i);

    private native long native_get_partial_object(int i, long j, long j2, byte[] bArr) throws IOException;

    private native int native_get_partial_object_64(int i, long j, long j2, byte[] bArr) throws IOException;

    private native int native_get_storage_id(int i);

    private native int[] native_get_storage_ids();

    private native MtpStorageInfo native_get_storage_info(int i);

    private native byte[] native_get_thumbnail(int i);

    private native boolean native_import_file(int i, int i2);

    private native boolean native_import_file(int i, String str);

    private native boolean native_open(String str, int i);

    private native MtpEvent native_reap_event_request(int i) throws IOException;

    private native boolean native_send_object(int i, long j, int i2);

    private native MtpObjectInfo native_send_object_info(MtpObjectInfo mtpObjectInfo);

    private native int native_submit_event_request() throws IOException;

    static {
        System.loadLibrary("media_jni");
    }

    public MtpDevice(UsbDevice device) {
        Preconditions.checkNotNull(device);
        this.mDevice = device;
    }

    public boolean open(UsbDeviceConnection connection) {
        boolean result = false;
        Context context = connection.getContext();
        synchronized (this.mLock) {
            if (context != null) {
                if (!((UserManager) context.getSystemService(Context.USER_SERVICE)).hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
                    result = native_open(this.mDevice.getDeviceName(), connection.getFileDescriptor());
                }
            }
            if (result) {
                this.mConnection = connection;
                this.mCloseGuard.open("close");
            } else {
                connection.close();
            }
        }
        return result;
    }

    public void close() {
        synchronized (this.mLock) {
            if (this.mConnection != null) {
                this.mCloseGuard.close();
                native_close();
                this.mConnection.close();
                this.mConnection = null;
            }
        }
    }

    protected void finalize() throws Throwable {
        try {
            if (this.mCloseGuard != null) {
                this.mCloseGuard.warnIfOpen();
            }
            close();
        } finally {
            super.finalize();
        }
    }

    public String getDeviceName() {
        return this.mDevice.getDeviceName();
    }

    public int getDeviceId() {
        return this.mDevice.getDeviceId();
    }

    public String toString() {
        return this.mDevice.getDeviceName();
    }

    public MtpDeviceInfo getDeviceInfo() {
        return native_get_device_info();
    }

    public int[] getStorageIds() {
        return native_get_storage_ids();
    }

    public int[] getObjectHandles(int storageId, int format, int objectHandle) {
        return native_get_object_handles(storageId, format, objectHandle);
    }

    public byte[] getObject(int objectHandle, int objectSize) {
        Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
        return native_get_object(objectHandle, (long) objectSize);
    }

    public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer) throws IOException {
        return native_get_partial_object(objectHandle, offset, size, buffer);
    }

    public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer) throws IOException {
        return (long) native_get_partial_object_64(objectHandle, offset, size, buffer);
    }

    public byte[] getThumbnail(int objectHandle) {
        return native_get_thumbnail(objectHandle);
    }

    public MtpStorageInfo getStorageInfo(int storageId) {
        return native_get_storage_info(storageId);
    }

    public MtpObjectInfo getObjectInfo(int objectHandle) {
        return native_get_object_info(objectHandle);
    }

    public boolean deleteObject(int objectHandle) {

    }

    public long getParent(int objectHandle) {
        return (long) native_get_parent(objectHandle);
    }

    public long getStorageId(int objectHandle) {
        return (long) native_get_storage_id(objectHandle);
    }

    public boolean importFile(int objectHandle, String destPath) {
        return native_import_file(objectHandle, destPath);
    }

    public boolean importFile(int objectHandle, ParcelFileDescriptor descriptor) {
        return native_import_file(objectHandle, descriptor.getFd());
    }

    public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
        return native_send_object(objectHandle, size, descriptor.getFd());
    }

    public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
        return native_send_object_info(info);
    }

    public MtpEvent readEvent(CancellationSignal signal) throws IOException {
        boolean z = false;
        final int handle = native_submit_event_request();
        if (handle >= 0) {
            z = true;
        }
        Preconditions.checkState(z, "Other thread is reading an event.");
        if (signal != null) {
            signal.setOnCancelListener(new OnCancelListener() {

                public void onCancel() {
                    MtpDevice.this.native_discard_event_request(handle);
                }
            });
        }
        try {
            MtpEvent native_reap_event_request = native_reap_event_request(handle);
            return native_reap_event_request;
        } finally {
            if (signal != null) {
                signal.setOnCancelListener(null);
            }
        }
    }

    public long getObjectSizeLong(int handle, int format) throws IOException {
        return native_get_object_size_long(handle, format);
    }
}


try {
            MtpEvent native_reap_event_request = native_reap_event_request(handle);
            return native_reap_event_request;
        } finally {
            if (signal != null) {
                signal.setOnCancelListener(null);
            }
        }

package android.mtp;

import android.content.Context;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.os.CancellationSignal;
import android.os.CancellationSignal.OnCancelListener;
import android.os.ParcelFileDescriptor;
import android.os.UserManager;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
import dalvik.system.CloseGuard;
import java.io.IOException;

public final class MtpDevice {

    private static final String TAG = "MtpDevice";

    @GuardedBy("mLock")
    private CloseGuard mCloseGuard = CloseGuard.get();

    @GuardedBy("mLock")
    private UsbDeviceConnection mConnection;

    private final UsbDevice mDevice;

    private final Object mLock = new Object();

    private long mNativeContext;

    private native void native_close();

    private native boolean native_delete_object(int i);

    private native void native_discard_event_request(int i);

    private native MtpDeviceInfo native_get_device_info();

    private native byte[] native_get_object(int i, long j);

    private native int[] native_get_object_handles(int i, int i2, int i3);

    private native MtpObjectInfo native_get_object_info(int i);

    private native long native_get_object_size_long(int i, int i2) throws IOException;

    private native int native_get_parent(int i);

    private native long native_get_partial_object(int i, long j, long j2, byte[] bArr) throws IOException;

    private native int native_get_partial_object_64(int i, long j, long j2, byte[] bArr) throws IOException;

    private native int native_get_storage_id(int i);

    private native int[] native_get_storage_ids();

    private native MtpStorageInfo native_get_storage_info(int i);

    private native byte[] native_get_thumbnail(int i);

    private native boolean native_import_file(int i, int i2);

    private native boolean native_import_file(int i, String str);

    private native boolean native_open(String str, int i);

    private native MtpEvent native_reap_event_request(int i) throws IOException;

    private native boolean native_send_object(int i, long j, int i2);

    private native MtpObjectInfo native_send_object_info(MtpObjectInfo mtpObjectInfo);

    private native int native_submit_event_request() throws IOException;

    static {
        System.loadLibrary("media_jni");
    }

    public MtpDevice(UsbDevice device) {
        Preconditions.checkNotNull(device);
        this.mDevice = device;
    }

    public boolean open(UsbDeviceConnection connection) {
        boolean result = false;
        Context context = connection.getContext();
        synchronized (this.mLock) {
            if (context != null) {
                if (!((UserManager) context.getSystemService(Context.USER_SERVICE)).hasUserRestriction(UserManager.DISALLOW_USB_FILE_TRANSFER)) {
                    result = native_open(this.mDevice.getDeviceName(), connection.getFileDescriptor());
                }
            }
            if (result) {
                this.mConnection = connection;
                this.mCloseGuard.open("close");
            } else {
                connection.close();
            }
        }
        return result;
    }

    public void close() {
        synchronized (this.mLock) {
            if (this.mConnection != null) {
                this.mCloseGuard.close();
                native_close();
                this.mConnection.close();
                this.mConnection = null;
            }
        }
    }

    protected void finalize() throws Throwable {
        try {
            if (this.mCloseGuard != null) {
                this.mCloseGuard.warnIfOpen();
            }
            close();
        } finally {
            super.finalize();
        }
    }

    public String getDeviceName() {
        return this.mDevice.getDeviceName();
    }

    public int getDeviceId() {
        return this.mDevice.getDeviceId();
    }

    public String toString() {
        return this.mDevice.getDeviceName();
    }

    public MtpDeviceInfo getDeviceInfo() {
        return native_get_device_info();
    }

    public int[] getStorageIds() {
        return native_get_storage_ids();
    }

    public int[] getObjectHandles(int storageId, int format, int objectHandle) {
        return native_get_object_handles(storageId, format, objectHandle);
    }

    public byte[] getObject(int objectHandle, int objectSize) {
        Preconditions.checkArgumentNonnegative(objectSize, "objectSize should not be negative");
        return native_get_object(objectHandle, (long) objectSize);
    }

    public long getPartialObject(int objectHandle, long offset, long size, byte[] buffer) throws IOException {
        return native_get_partial_object(objectHandle, offset, size, buffer);
    }

    public long getPartialObject64(int objectHandle, long offset, long size, byte[] buffer) throws IOException {
        return (long) native_get_partial_object_64(objectHandle, offset, size, buffer);
    }

    public byte[] getThumbnail(int objectHandle) {
        return native_get_thumbnail(objectHandle);
    }

    public MtpStorageInfo getStorageInfo(int storageId) {
        return native_get_storage_info(storageId);
    }

    public MtpObjectInfo getObjectInfo(int objectHandle) {
        return native_get_object_info(objectHandle);
    }

    public boolean deleteObject(int objectHandle) {
        return native_delete_object(objectHandle);
    }

    public long getParent(int objectHandle) {
        return (long) native_get_parent(objectHandle);
    }

    public long getStorageId(int objectHandle) {
        return (long) native_get_storage_id(objectHandle);
    }

    public boolean importFile(int objectHandle, String destPath) {
        return native_import_file(objectHandle, destPath);
    }

    public boolean importFile(int objectHandle, ParcelFileDescriptor descriptor) {
        return native_import_file(objectHandle, descriptor.getFd());
    }

    public boolean sendObject(int objectHandle, long size, ParcelFileDescriptor descriptor) {
        return native_send_object(objectHandle, size, descriptor.getFd());
    }

    public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
        return native_send_object_info(info);
    }

    public MtpEvent readEvent(CancellationSignal signal) throws IOException {
        boolean z = false;
        final int handle = native_submit_event_request();
        if (handle >= 0) {
            z = true;
        }
        Preconditions.checkState(z, "Other thread is reading an event.");
        if (signal != null) {
            signal.setOnCancelListener(new OnCancelListener() {

                public void onCancel() {
                    MtpDevice.this.native_discard_event_request(handle);
                }
            });
        }

    }

    public long getObjectSizeLong(int handle, int format) throws IOException {
        return native_get_object_size_long(handle, format);
    }
}


package org.apache.flink.connector.file.src.assigners;

import org.apache.flink.annotation.PublicEvolving;
import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.connector.file.src.FileSourceSplit;
import org.apache.flink.metrics.SimpleCounter;
import org.apache.flink.util.MathUtils;
import org.apache.flink.util.NetUtils;
import org.apache.flink.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.flink.util.Preconditions.checkState;

/**
 * A {@link FileSplitAssigner} that assigns to each host preferably splits that are local, before
 * assigning splits that are not local.
 *
 * <p>Implementation Note: This class is an adjusted copy of the previous API's class {@link
 * org.apache.flink.api.common.io.LocatableInputSplitAssigner} and reproduces the same assignment
 * logic, for compatibility. The logic has not been changed or optimized.
 */
@PublicEvolving
public class LocalityAwareSplitAssigner implements FileSplitAssigner {

    private static final Logger LOG = LoggerFactory.getLogger(LocalityAwareSplitAssigner.class);

    /**
     * All unassigned input splits.
     */
    private final HashSet<SplitWithInfo> unassigned = new HashSet<>();

    /**
     * Input splits indexed by host for local assignment.
     */
    private final HashMap<String, LocatableSplitChooser> localPerHost = new HashMap<>();

    /**
     * Unassigned splits for remote assignment.
     */
    private final LocatableSplitChooser remoteSplitChooser;

    private final SimpleCounter localAssignments;

    private final SimpleCounter remoteAssignments;

    public LocalityAwareSplitAssigner(Collection<FileSourceSplit> splits) {
        for (FileSourceSplit split : splits) {
            this.unassigned.add(new SplitWithInfo(split));
        }
        this.remoteSplitChooser = new LocatableSplitChooser(unassigned);
        // this will be replaced with metrics registration once we can expose the metric group
        // properly to the assigners
        this.localAssignments = new SimpleCounter();
        this.remoteAssignments = new SimpleCounter();
    }

    @Override
    public Optional<FileSourceSplit> getNext(@Nullable String host) {
        // for a null host, we always return a remote split
        if (StringUtils.isNullOrWhitespaceOnly(host)) {
            final Optional<FileSourceSplit> split = getRemoteSplit();
            if (split.isPresent()) {
                LOG.info("Assigning split to non-localized request: {}", split);
            }
            return split;
        }
        host = normalizeHostName(host);
        // for any non-null host, we take the list of non-null splits
        final LocatableSplitChooser localSplits = localPerHost.computeIfAbsent(host, (theHost) -> buildChooserForHost(theHost, unassigned));
        final SplitWithInfo localSplit = localSplits.getNextUnassignedMinLocalCountSplit(unassigned);
        if (localSplit != null) {
            checkState(unassigned.remove(localSplit), "Selected split has already been assigned. This should not happen!");
            LOG.info("Assigning local split to requesting host '{}': {}", host, localSplit.getSplit());
            localAssignments.inc();
            return Optional.of(localSplit.getSplit());
        }
        // we did not find a local split, return a remote split
        final Optional<FileSourceSplit> remoteSplit = getRemoteSplit();
        if (remoteSplit.isPresent()) {
            LOG.info("Assigning remote split to requesting host '{}': {}", host, remoteSplit);
        }
        return remoteSplit;
    }

    @Override
    public void addSplits(Collection<FileSourceSplit> splits) {
        for (FileSourceSplit split : splits) {
            SplitWithInfo sc = new SplitWithInfo(split);
            remoteSplitChooser.addInputSplit(sc);
            unassigned.add(sc);
        }
    }

    @Override
    public Collection<FileSourceSplit> remainingSplits() {
        return unassigned.stream().map(SplitWithInfo::getSplit).collect(Collectors.toList());
    }

    private Optional<FileSourceSplit> getRemoteSplit() {
        final SplitWithInfo split = remoteSplitChooser.getNextUnassignedMinLocalCountSplit(unassigned);
        if (split == null) {
            return Optional.empty();
        }
        checkState(unassigned.remove(split), "Selected split has already been assigned. This should not happen!");
        remoteAssignments.inc();
        return Optional.of(split.getSplit());
    }

    @VisibleForTesting
    int getNumberOfLocalAssignments() {
        return MathUtils.checkedDownCast(localAssignments.getCount());
    }

    @VisibleForTesting
    int getNumberOfRemoteAssignments() {
        return MathUtils.checkedDownCast(remoteAssignments.getCount());
    }

    static String normalizeHostName(String hostName) {
        return hostName == null ? null : NetUtils.getHostnameFromFQDN(hostName).toLowerCase(Locale.US);
    }

    static String[] normalizeHostNames(String[] hostNames) {
        if (hostNames == null) {
            return null;
        }
        final String[] normalizedHostNames = new String[hostNames.length];
        boolean changed = false;
        for (int i = 0; i < hostNames.length; i++) {
            final String original = hostNames[i];
            final String normalized = normalizeHostName(original);
            normalizedHostNames[i] = normalized;
            // noinspection StringEquality
            changed |= (original != normalized);
        }
        return changed ? normalizedHostNames : hostNames;
    }

    private static boolean isLocal(String flinkHost, String[] hosts) {
        if (flinkHost == null || hosts == null) {
            return false;
        }
        for (String h : hosts) {
            if (h != null && h.equals(flinkHost)) {
                return true;
            }
        }
        return false;
    }

    private static LocatableSplitChooser buildChooserForHost(String host, Set<SplitWithInfo> splits) {
        final LocatableSplitChooser newChooser = new LocatableSplitChooser();
        for (SplitWithInfo splitWithInfo : splits) {
            if (isLocal(host, splitWithInfo.getNormalizedHosts())) {
                splitWithInfo.incrementLocalCount();
                newChooser.addInputSplit(splitWithInfo);
            }
        }
        return newChooser;
    }

    /**
     * Wraps a LocatableInputSplit and adds a count for the number of observed hosts that can access
     * the split locally.
     */
    private static class SplitWithInfo {

        private final FileSourceSplit split;

        private final String[] normalizedHosts;

        private int localCount;

        public SplitWithInfo(FileSourceSplit split) {
            this.split = split;
            this.normalizedHosts = normalizeHostNames(split.hostnames());
            this.localCount = 0;
        }

        public void incrementLocalCount() {
            this.localCount++;
        }

        public int getLocalCount() {
            return localCount;
        }

        public FileSourceSplit getSplit() {
            return split;
        }

{
            return normalizedHosts;
        }
    }

    /**
     * Holds a list of LocatableInputSplits and returns the split with the lowest local count. The
     * rational is that splits which are local on few hosts should be preferred over others which
     * have more degrees of freedom for local assignment.
     *
     * <p>Internally, the splits are stored in a linked list. Sorting the list is not a good
     * solution, as local counts are updated whenever a previously unseen host requests a split.
     * Instead, we track the minimum local count and iteratively look for splits with that minimum
     * count.
     */
    private static class LocatableSplitChooser {

        /**
         * list of all input splits.
         */
        private final LinkedList<SplitWithInfo> splits = new LinkedList<>();

        /**
         * The current minimum local count. We look for splits with this local count.
         */
        private int minLocalCount = -1;

        /**
         * The second smallest count observed so far.
         */
        private int nextMinLocalCount = -1;

        /**
         * number of elements we need to inspect for the minimum local count.
         */
        private int elementCycleCount = 0;

        LocatableSplitChooser() {
        }

        LocatableSplitChooser(Collection<SplitWithInfo> splits) {
            for (SplitWithInfo split : splits) {
                addInputSplit(split);
            }
        }

        /**
         * Adds a single input split.
         */
        void addInputSplit(SplitWithInfo split) {
            int localCount = split.getLocalCount();
            if (minLocalCount == -1) {
                // first split to add
                this.minLocalCount = localCount;
                this.elementCycleCount = 1;
                this.splits.offerFirst(split);
            } else if (localCount < minLocalCount) {
                // split with new min local count
                this.nextMinLocalCount = this.minLocalCount;
                this.minLocalCount = localCount;
                // all other splits have more local host than this one
                this.elementCycleCount = 1;
                splits.offerFirst(split);
            } else if (localCount == minLocalCount) {
                this.elementCycleCount++;
                this.splits.offerFirst(split);
            } else {
                if (localCount < nextMinLocalCount) {
                    nextMinLocalCount = localCount;
                }
                splits.offerLast(split);
            }
        }

        /**
         * Retrieves a LocatableInputSplit with minimum local count. InputSplits which have already
         * been assigned (i.e., which are not contained in the provided set) are filtered out. The
         * returned input split is NOT removed from the provided set.
         *
         * @param unassignedSplits Set of unassigned input splits.
         * @return An input split with minimum local count or null if all splits have been assigned.
         */
        @Nullable
        SplitWithInfo getNextUnassignedMinLocalCountSplit(Set<SplitWithInfo> unassignedSplits) {
            if (splits.size() == 0) {
                return null;
            }
            do {
                elementCycleCount--;
                // take first split of the list
                SplitWithInfo split = splits.pollFirst();
                if (unassignedSplits.contains(split)) {
                    int localCount = split.getLocalCount();
                    // still unassigned, check local count
                    if (localCount > minLocalCount) {
                        // re-insert at end of the list and continue to look for split with smaller
                        // local count
                        splits.offerLast(split);
                        // check and update second smallest local count
                        if (nextMinLocalCount == -1 || split.getLocalCount() < nextMinLocalCount) {
                            nextMinLocalCount = split.getLocalCount();
                        }
                        split = null;
                    }
                } else {
                    // split was already assigned
                    split = null;
                }
                if (elementCycleCount == 0) {
                    // one full cycle, but no split with min local count found
                    // update minLocalCnt and element cycle count for next pass over the splits
                    minLocalCount = nextMinLocalCount;
                    nextMinLocalCount = -1;
                    elementCycleCount = splits.size();
                }
                if (split != null) {
                    // found a split to assign
                    return split;
                }
            } while (elementCycleCount > 0);
            // no split left
            return null;
        }
    }
}


{
            return normalizedHosts;
        }

package org.apache.flink.connector.file.src.assigners;

import org.apache.flink.annotation.PublicEvolving;
import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.connector.file.src.FileSourceSplit;
import org.apache.flink.metrics.SimpleCounter;
import org.apache.flink.util.MathUtils;
import org.apache.flink.util.NetUtils;
import org.apache.flink.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.flink.util.Preconditions.checkState;

/**
 * A {@link FileSplitAssigner} that assigns to each host preferably splits that are local, before
 * assigning splits that are not local.
 *
 * <p>Implementation Note: This class is an adjusted copy of the previous API's class {@link
 * org.apache.flink.api.common.io.LocatableInputSplitAssigner} and reproduces the same assignment
 * logic, for compatibility. The logic has not been changed or optimized.
 */
@PublicEvolving
public class LocalityAwareSplitAssigner implements FileSplitAssigner {

    private static final Logger LOG = LoggerFactory.getLogger(LocalityAwareSplitAssigner.class);

    /**
     * All unassigned input splits.
     */
    private final HashSet<SplitWithInfo> unassigned = new HashSet<>();

    /**
     * Input splits indexed by host for local assignment.
     */
    private final HashMap<String, LocatableSplitChooser> localPerHost = new HashMap<>();

    /**
     * Unassigned splits for remote assignment.
     */
    private final LocatableSplitChooser remoteSplitChooser;

    private final SimpleCounter localAssignments;

    private final SimpleCounter remoteAssignments;

    public LocalityAwareSplitAssigner(Collection<FileSourceSplit> splits) {
        for (FileSourceSplit split : splits) {
            this.unassigned.add(new SplitWithInfo(split));
        }
        this.remoteSplitChooser = new LocatableSplitChooser(unassigned);
        // this will be replaced with metrics registration once we can expose the metric group
        // properly to the assigners
        this.localAssignments = new SimpleCounter();
        this.remoteAssignments = new SimpleCounter();
    }

    @Override
    public Optional<FileSourceSplit> getNext(@Nullable String host) {
        // for a null host, we always return a remote split
        if (StringUtils.isNullOrWhitespaceOnly(host)) {
            final Optional<FileSourceSplit> split = getRemoteSplit();
            if (split.isPresent()) {
                LOG.info("Assigning split to non-localized request: {}", split);
            }
            return split;
        }
        host = normalizeHostName(host);
        // for any non-null host, we take the list of non-null splits
        final LocatableSplitChooser localSplits = localPerHost.computeIfAbsent(host, (theHost) -> buildChooserForHost(theHost, unassigned));
        final SplitWithInfo localSplit = localSplits.getNextUnassignedMinLocalCountSplit(unassigned);
        if (localSplit != null) {
            checkState(unassigned.remove(localSplit), "Selected split has already been assigned. This should not happen!");
            LOG.info("Assigning local split to requesting host '{}': {}", host, localSplit.getSplit());
            localAssignments.inc();
            return Optional.of(localSplit.getSplit());
        }
        // we did not find a local split, return a remote split
        final Optional<FileSourceSplit> remoteSplit = getRemoteSplit();
        if (remoteSplit.isPresent()) {
            LOG.info("Assigning remote split to requesting host '{}': {}", host, remoteSplit);
        }
        return remoteSplit;
    }

    @Override
    public void addSplits(Collection<FileSourceSplit> splits) {
        for (FileSourceSplit split : splits) {
            SplitWithInfo sc = new SplitWithInfo(split);
            remoteSplitChooser.addInputSplit(sc);
            unassigned.add(sc);
        }
    }

    @Override
    public Collection<FileSourceSplit> remainingSplits() {
        return unassigned.stream().map(SplitWithInfo::getSplit).collect(Collectors.toList());
    }

    private Optional<FileSourceSplit> getRemoteSplit() {
        final SplitWithInfo split = remoteSplitChooser.getNextUnassignedMinLocalCountSplit(unassigned);
        if (split == null) {
            return Optional.empty();
        }
        checkState(unassigned.remove(split), "Selected split has already been assigned. This should not happen!");
        remoteAssignments.inc();
        return Optional.of(split.getSplit());
    }

    @VisibleForTesting
    int getNumberOfLocalAssignments() {
        return MathUtils.checkedDownCast(localAssignments.getCount());
    }

    @VisibleForTesting
    int getNumberOfRemoteAssignments() {
        return MathUtils.checkedDownCast(remoteAssignments.getCount());
    }

    static String normalizeHostName(String hostName) {
        return hostName == null ? null : NetUtils.getHostnameFromFQDN(hostName).toLowerCase(Locale.US);
    }

    static String[] normalizeHostNames(String[] hostNames) {
        if (hostNames == null) {
            return null;
        }
        final String[] normalizedHostNames = new String[hostNames.length];
        boolean changed = false;
        for (int i = 0; i < hostNames.length; i++) {
            final String original = hostNames[i];
            final String normalized = normalizeHostName(original);
            normalizedHostNames[i] = normalized;
            // noinspection StringEquality
            changed |= (original != normalized);
        }
        return changed ? normalizedHostNames : hostNames;
    }

    private static boolean isLocal(String flinkHost, String[] hosts) {
        if (flinkHost == null || hosts == null) {
            return false;
        }
        for (String h : hosts) {
            if (h != null && h.equals(flinkHost)) {
                return true;
            }
        }
        return false;
    }

    private static LocatableSplitChooser buildChooserForHost(String host, Set<SplitWithInfo> splits) {
        final LocatableSplitChooser newChooser = new LocatableSplitChooser();
        for (SplitWithInfo splitWithInfo : splits) {
            if (isLocal(host, splitWithInfo.getNormalizedHosts())) {
                splitWithInfo.incrementLocalCount();
                newChooser.addInputSplit(splitWithInfo);
            }
        }
        return newChooser;
    }

    /**
     * Wraps a LocatableInputSplit and adds a count for the number of observed hosts that can access
     * the split locally.
     */
    private static class SplitWithInfo {

        private final FileSourceSplit split;

        private final String[] normalizedHosts;

        private int localCount;

        public SplitWithInfo(FileSourceSplit split) {
            this.split = split;
            this.normalizedHosts = normalizeHostNames(split.hostnames());
            this.localCount = 0;
        }

        public void incrementLocalCount() {
            this.localCount++;
        }

        public int getLocalCount() {
            return localCount;
        }

        public FileSourceSplit getSplit() {
            return split;
        }

        public String[] getNormalizedHosts()

    }

    /**
     * Holds a list of LocatableInputSplits and returns the split with the lowest local count. The
     * rational is that splits which are local on few hosts should be preferred over others which
     * have more degrees of freedom for local assignment.
     *
     * <p>Internally, the splits are stored in a linked list. Sorting the list is not a good
     * solution, as local counts are updated whenever a previously unseen host requests a split.
     * Instead, we track the minimum local count and iteratively look for splits with that minimum
     * count.
     */
    private static class LocatableSplitChooser {

        /**
         * list of all input splits.
         */
        private final LinkedList<SplitWithInfo> splits = new LinkedList<>();

        /**
         * The current minimum local count. We look for splits with this local count.
         */
        private int minLocalCount = -1;

        /**
         * The second smallest count observed so far.
         */
        private int nextMinLocalCount = -1;

        /**
         * number of elements we need to inspect for the minimum local count.
         */
        private int elementCycleCount = 0;

        LocatableSplitChooser() {
        }

        LocatableSplitChooser(Collection<SplitWithInfo> splits) {
            for (SplitWithInfo split : splits) {
                addInputSplit(split);
            }
        }

        /**
         * Adds a single input split.
         */
        void addInputSplit(SplitWithInfo split) {
            int localCount = split.getLocalCount();
            if (minLocalCount == -1) {
                // first split to add
                this.minLocalCount = localCount;
                this.elementCycleCount = 1;
                this.splits.offerFirst(split);
            } else if (localCount < minLocalCount) {
                // split with new min local count
                this.nextMinLocalCount = this.minLocalCount;
                this.minLocalCount = localCount;
                // all other splits have more local host than this one
                this.elementCycleCount = 1;
                splits.offerFirst(split);
            } else if (localCount == minLocalCount) {
                this.elementCycleCount++;
                this.splits.offerFirst(split);
            } else {
                if (localCount < nextMinLocalCount) {
                    nextMinLocalCount = localCount;
                }
                splits.offerLast(split);
            }
        }

        /**
         * Retrieves a LocatableInputSplit with minimum local count. InputSplits which have already
         * been assigned (i.e., which are not contained in the provided set) are filtered out. The
         * returned input split is NOT removed from the provided set.
         *
         * @param unassignedSplits Set of unassigned input splits.
         * @return An input split with minimum local count or null if all splits have been assigned.
         */
        @Nullable
        SplitWithInfo getNextUnassignedMinLocalCountSplit(Set<SplitWithInfo> unassignedSplits) {
            if (splits.size() == 0) {
                return null;
            }
            do {
                elementCycleCount--;
                // take first split of the list
                SplitWithInfo split = splits.pollFirst();
                if (unassignedSplits.contains(split)) {
                    int localCount = split.getLocalCount();
                    // still unassigned, check local count
                    if (localCount > minLocalCount) {
                        // re-insert at end of the list and continue to look for split with smaller
                        // local count
                        splits.offerLast(split);
                        // check and update second smallest local count
                        if (nextMinLocalCount == -1 || split.getLocalCount() < nextMinLocalCount) {
                            nextMinLocalCount = split.getLocalCount();
                        }
                        split = null;
                    }
                } else {
                    // split was already assigned
                    split = null;
                }
                if (elementCycleCount == 0) {
                    // one full cycle, but no split with min local count found
                    // update minLocalCnt and element cycle count for next pass over the splits
                    minLocalCount = nextMinLocalCount;
                    nextMinLocalCount = -1;
                    elementCycleCount = splits.size();
                }
                if (split != null) {
                    // found a split to assign
                    return split;
                }
            } while (elementCycleCount > 0);
            // no split left
            return null;
        }
    }
}


package org.apache.flink.connector.file.src.assigners;

import org.apache.flink.annotation.PublicEvolving;
import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.connector.file.src.FileSourceSplit;
import org.apache.flink.metrics.SimpleCounter;
import org.apache.flink.util.MathUtils;
import org.apache.flink.util.NetUtils;
import org.apache.flink.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.flink.util.Preconditions.checkState;

/**
 * A {@link FileSplitAssigner} that assigns to each host preferably splits that are local, before
 * assigning splits that are not local.
 *
 * <p>Implementation Note: This class is an adjusted copy of the previous API's class {@link
 * org.apache.flink.api.common.io.LocatableInputSplitAssigner} and reproduces the same assignment
 * logic, for compatibility. The logic has not been changed or optimized.
 */
@PublicEvolving
public class LocalityAwareSplitAssigner implements FileSplitAssigner {

    private static final Logger LOG = LoggerFactory.getLogger(LocalityAwareSplitAssigner.class);

    /**
     * All unassigned input splits.
     */
    private final HashSet<SplitWithInfo> unassigned = new HashSet<>();

    /**
     * Input splits indexed by host for local assignment.
     */
    private final HashMap<String, LocatableSplitChooser> localPerHost = new HashMap<>();

    /**
     * Unassigned splits for remote assignment.
     */
    private final LocatableSplitChooser remoteSplitChooser;

    private final SimpleCounter localAssignments;

    private final SimpleCounter remoteAssignments;

    public LocalityAwareSplitAssigner(Collection<FileSourceSplit> splits) {
        for (FileSourceSplit split : splits) {
            this.unassigned.add(new SplitWithInfo(split));
        }
        this.remoteSplitChooser = new LocatableSplitChooser(unassigned);
        // this will be replaced with metrics registration once we can expose the metric group
        // properly to the assigners
        this.localAssignments = new SimpleCounter();
        this.remoteAssignments = new SimpleCounter();
    }

    @Override
    public Optional<FileSourceSplit> getNext(@Nullable String host) {
        // for a null host, we always return a remote split
        if (StringUtils.isNullOrWhitespaceOnly(host)) {
            final Optional<FileSourceSplit> split = getRemoteSplit();
            if (split.isPresent()) {
                LOG.info("Assigning split to non-localized request: {}", split);
            }
            return split;
        }
        host = normalizeHostName(host);
        // for any non-null host, we take the list of non-null splits
        final LocatableSplitChooser localSplits = localPerHost.computeIfAbsent(host, (theHost) -> buildChooserForHost(theHost, unassigned));
        final SplitWithInfo localSplit = localSplits.getNextUnassignedMinLocalCountSplit(unassigned);
        if (localSplit != null) {
            checkState(unassigned.remove(localSplit), "Selected split has already been assigned. This should not happen!");
            LOG.info("Assigning local split to requesting host '{}': {}", host, localSplit.getSplit());
            localAssignments.inc();
            return Optional.of(localSplit.getSplit());
        }
        // we did not find a local split, return a remote split
        final Optional<FileSourceSplit> remoteSplit = getRemoteSplit();
        if (remoteSplit.isPresent()) {
            LOG.info("Assigning remote split to requesting host '{}': {}", host, remoteSplit);
        }
        return remoteSplit;
    }

    @Override
    public void addSplits(Collection<FileSourceSplit> splits) {
        for (FileSourceSplit split : splits) {
            SplitWithInfo sc = new SplitWithInfo(split);
            remoteSplitChooser.addInputSplit(sc);
            unassigned.add(sc);
        }
    }

    @Override
    public Collection<FileSourceSplit> remainingSplits() {
        return unassigned.stream().map(SplitWithInfo::getSplit).collect(Collectors.toList());
    }

    private Optional<FileSourceSplit> getRemoteSplit() {
        final SplitWithInfo split = remoteSplitChooser.getNextUnassignedMinLocalCountSplit(unassigned);
        if (split == null) {
            return Optional.empty();
        }
        checkState(unassigned.remove(split), "Selected split has already been assigned. This should not happen!");
        remoteAssignments.inc();
        return Optional.of(split.getSplit());
    }

    @VisibleForTesting
    int getNumberOfLocalAssignments() {
        return MathUtils.checkedDownCast(localAssignments.getCount());
    }

    @VisibleForTesting
    int getNumberOfRemoteAssignments() {
        return MathUtils.checkedDownCast(remoteAssignments.getCount());
    }

    static String normalizeHostName(String hostName) {
        return hostName == null ? null : NetUtils.getHostnameFromFQDN(hostName).toLowerCase(Locale.US);
    }

    static String[] normalizeHostNames(String[] hostNames) {
        if (hostNames == null) {
            return null;
        }
        final String[] normalizedHostNames = new String[hostNames.length];
        boolean changed = false;
        for (int i = 0; i < hostNames.length; i++) {
            final String original = hostNames[i];
            final String normalized = normalizeHostName(original);
            normalizedHostNames[i] = normalized;
            // noinspection StringEquality
            changed |= (original != normalized);
        }
        return changed ? normalizedHostNames : hostNames;
    }

    private static boolean isLocal(String flinkHost, String[] hosts) {
        if (flinkHost == null || hosts == null) {
            return false;
        }
        for (String h : hosts) {
            if (h != null && h.equals(flinkHost)) {
                return true;
            }
        }
        return false;
    }

    private static LocatableSplitChooser buildChooserForHost(String host, Set<SplitWithInfo> splits) {
        final LocatableSplitChooser newChooser = new LocatableSplitChooser();
        for (SplitWithInfo splitWithInfo : splits) {
            if (isLocal(host, splitWithInfo.getNormalizedHosts())) {
                splitWithInfo.incrementLocalCount();
                newChooser.addInputSplit(splitWithInfo);
            }
        }
        return newChooser;
    }

    /**
     * Wraps a LocatableInputSplit and adds a count for the number of observed hosts that can access
     * the split locally.
     */
    private static class SplitWithInfo {

        private final FileSourceSplit split;

        private final String[] normalizedHosts;

        private int localCount;

        public SplitWithInfo(FileSourceSplit split) {
            this.split = split;
            this.normalizedHosts = normalizeHostNames(split.hostnames());
            this.localCount = 0;
        }

        public void incrementLocalCount() {
            this.localCount++;
        }

        public int getLocalCount() {
            return localCount;
        }

        public FileSourceSplit getSplit() {
            ret

        }

        public String[] getNormalizedHosts() {
            return normalizedHosts;
        }
    }

    /**
     * Holds a list of LocatableInputSplits and returns the split with the lowest local count. The
     * rational is that splits which are local on few hosts should be preferred over others which
     * have more degrees of freedom for local assignment.
     *
     * <p>Internally, the splits are stored in a linked list. Sorting the list is not a good
     * solution, as local counts are updated whenever a previously unseen host requests a split.
     * Instead, we track the minimum local count and iteratively look for splits with that minimum
     * count.
     */
    private static class LocatableSplitChooser {

        /**
         * list of all input splits.
         */
        private final LinkedList<SplitWithInfo> splits = new LinkedList<>();

        /**
         * The current minimum local count. We look for splits with this local count.
         */
        private int minLocalCount = -1;

        /**
         * The second smallest count observed so far.
         */
        private int nextMinLocalCount = -1;

        /**
         * number of elements we need to inspect for the minimum local count.
         */
        private int elementCycleCount = 0;

        LocatableSplitChooser() {
        }

        LocatableSplitChooser(Collection<SplitWithInfo> splits) {
            for (SplitWithInfo split : splits) {
                addInputSplit(split);
            }
        }

        /**
         * Adds a single input split.
         */
        void addInputSplit(SplitWithInfo split) {
            int localCount = split.getLocalCount();
            if (minLocalCount == -1) {
                // first split to add
                this.minLocalCount = localCount;
                this.elementCycleCount = 1;
                this.splits.offerFirst(split);
            } else if (localCount < minLocalCount) {
                // split with new min local count
                this.nextMinLocalCount = this.minLocalCount;
                this.minLocalCount = localCount;
                // all other splits have more local host than this one
                this.elementCycleCount = 1;
                splits.offerFirst(split);
            } else if (localCount == minLocalCount) {
                this.elementCycleCount++;
                this.splits.offerFirst(split);
            } else {
                if (localCount < nextMinLocalCount) {
                    nextMinLocalCount = localCount;
                }
                splits.offerLast(split);
            }
        }

        /**
         * Retrieves a LocatableInputSplit with minimum local count. InputSplits which have already
         * been assigned (i.e., which are not contained in the provided set) are filtered out. The
         * returned input split is NOT removed from the provided set.
         *
         * @param unassignedSplits Set of unassigned input splits.
         * @return An input split with minimum local count or null if all splits have been assigned.
         */
        @Nullable
        SplitWithInfo getNextUnassignedMinLocalCountSplit(Set<SplitWithInfo> unassignedSplits) {
            if (splits.size() == 0) {
                return null;
            }
            do {
                elementCycleCount--;
                // take first split of the list
                SplitWithInfo split = splits.pollFirst();
                if (unassignedSplits.contains(split)) {
                    int localCount = split.getLocalCount();
                    // still unassigned, check local count
                    if (localCount > minLocalCount) {
                        // re-insert at end of the list and continue to look for split with smaller
                        // local count
                        splits.offerLast(split);
                        // check and update second smallest local count
                        if (nextMinLocalCount == -1 || split.getLocalCount() < nextMinLocalCount) {
                            nextMinLocalCount = split.getLocalCount();
                        }
                        split = null;
                    }
                } else {
                    // split was already assigned
                    split = null;
                }
                if (elementCycleCount == 0) {
                    // one full cycle, but no split with min local count found
                    // update minLocalCnt and element cycle count for next pass over the splits
                    minLocalCount = nextMinLocalCount;
                    nextMinLocalCount = -1;
                    elementCycleCount = splits.size();
                }
                if (split != null) {
                    // found a split to assign
                    return split;
                }
            } while (elementCycleCount > 0);
            // no split left
            return null;
        }
    }
}


for (int i = 0; i < hostNames.length; i++) {
            final String original = hostNames[i];
            final String normalized = normalizeHostName(original);
            normalizedHostNames[i] = normalized;
            // noinspection StringEquality
            changed |= (original != normalized);
        }

package org.apache.flink.connector.file.src.assigners;

import org.apache.flink.annotation.PublicEvolving;
import org.apache.flink.annotation.VisibleForTesting;
import org.apache.flink.connector.file.src.FileSourceSplit;
import org.apache.flink.metrics.SimpleCounter;
import org.apache.flink.util.MathUtils;
import org.apache.flink.util.NetUtils;
import org.apache.flink.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import static org.apache.flink.util.Preconditions.checkState;

/**
 * A {@link FileSplitAssigner} that assigns to each host preferably splits that are local, before
 * assigning splits that are not local.
 *
 * <p>Implementation Note: This class is an adjusted copy of the previous API's class {@link
 * org.apache.flink.api.common.io.LocatableInputSplitAssigner} and reproduces the same assignment
 * logic, for compatibility. The logic has not been changed or optimized.
 */
@PublicEvolving
public class LocalityAwareSplitAssigner implements FileSplitAssigner {

    private static final Logger LOG = LoggerFactory.getLogger(LocalityAwareSplitAssigner.class);

    /**
     * All unassigned input splits.
     */
    private final HashSet<SplitWithInfo> unassigned = new HashSet<>();

    /**
     * Input splits indexed by host for local assignment.
     */
    private final HashMap<String, LocatableSplitChooser> localPerHost = new HashMap<>();

    /**
     * Unassigned splits for remote assignment.
     */
    private final LocatableSplitChooser remoteSplitChooser;

    private final SimpleCounter localAssignments;

    private final SimpleCounter remoteAssignments;

    public LocalityAwareSplitAssigner(Collection<FileSourceSplit> splits) {
        for (FileSourceSplit split : splits) {
            this.unassigned.add(new SplitWithInfo(split));
        }
        this.remoteSplitChooser = new LocatableSplitChooser(unassigned);
        // this will be replaced with metrics registration once we can expose the metric group
        // properly to the assigners
        this.localAssignments = new SimpleCounter();
        this.remoteAssignments = new SimpleCounter();
    }

    @Override
    public Optional<FileSourceSplit> getNext(@Nullable String host) {
        // for a null host, we always return a remote split
        if (StringUtils.isNullOrWhitespaceOnly(host)) {
            final Optional<FileSourceSplit> split = getRemoteSplit();
            if (split.isPresent()) {
                LOG.info("Assigning split to non-localized request: {}", split);
            }
            return split;
        }
        host = normalizeHostName(host);
        // for any non-null host, we take the list of non-null splits
        final LocatableSplitChooser localSplits = localPerHost.computeIfAbsent(host, (theHost) -> buildChooserForHost(theHost, unassigned));
        final SplitWithInfo localSplit = localSplits.getNextUnassignedMinLocalCountSplit(unassigned);
        if (localSplit != null) {
            checkState(unassigned.remove(localSplit), "Selected split has already been assigned. This should not happen!");
            LOG.info("Assigning local split to requesting host '{}': {}", host, localSplit.getSplit());
            localAssignments.inc();
            return Optional.of(localSplit.getSplit());
        }
        // we did not find a local split, return a remote split
        final Optional<FileSourceSplit> remoteSplit = getRemoteSplit();
        if (remoteSplit.isPresent()) {
            LOG.info("Assigning remote split to requesting host '{}': {}", host, remoteSplit);
        }
        return remoteSplit;
    }

    @Override
    public void addSplits(Collection<FileSourceSplit> splits) {
        for (FileSourceSplit split : splits) {
            SplitWithInfo sc = new SplitWithInfo(split);
            remoteSplitChooser.addInputSplit(sc);
            unassigned.add(sc);
        }
    }

    @Override
    public Collection<FileSourceSplit> remainingSplits() {
        return unassigned.stream().map(SplitWithInfo::getSplit).collect(Collectors.toList());
    }

    private Optional<FileSourceSplit> getRemoteSplit() {
        final SplitWithInfo split = remoteSplitChooser.getNextUnassignedMinLocalCountSplit(unassigned);
        if (split == null) {
            return Optional.empty();
        }
        checkState(unassigned.remove(split), "Selected split has already been assigned. This should not happen!");
        remoteAssignments.inc();
        return Optional.of(split.getSplit());
    }

    @VisibleForTesting
    int getNumberOfLocalAssignments() {
        return MathUtils.checkedDownCast(localAssignments.getCount());
    }

    @VisibleForTesting
    int getNumberOfRemoteAssignments() {
        return MathUtils.checkedDownCast(remoteAssignments.getCount());
    }

    static String normalizeHostName(String hostName) {
        return hostName == null ? null : NetUtils.getHostnameFromFQDN(hostName).toLowerCase(Locale.US);
    }

    static String[] normalizeHostNames(String[] hostNames) {
        if (hostNames == null) {
            return null;
        }
        final String[] normalizedHostNames = new String[hostNames.length];
        boolean changed = false;

        return changed ? normalizedHostNames : hostNames;
    }

    private static boolean isLocal(String flinkHost, String[] hosts) {
        if (flinkHost == null || hosts == null) {
            return false;
        }
        for (String h : hosts) {
            if (h != null && h.equals(flinkHost)) {
                return true;
            }
        }
        return false;
    }

    private static LocatableSplitChooser buildChooserForHost(String host, Set<SplitWithInfo> splits) {
        final LocatableSplitChooser newChooser = new LocatableSplitChooser();
        for (SplitWithInfo splitWithInfo : splits) {
            if (isLocal(host, splitWithInfo.getNormalizedHosts())) {
                splitWithInfo.incrementLocalCount();
                newChooser.addInputSplit(splitWithInfo);
            }
        }
        return newChooser;
    }

    /**
     * Wraps a LocatableInputSplit and adds a count for the number of observed hosts that can access
     * the split locally.
     */
    private static class SplitWithInfo {

        private final FileSourceSplit split;

        private final String[] normalizedHosts;

        private int localCount;

        public SplitWithInfo(FileSourceSplit split) {
            this.split = split;
            this.normalizedHosts = normalizeHostNames(split.hostnames());
            this.localCount = 0;
        }

        public void incrementLocalCount() {
            this.localCount++;
        }

        public int getLocalCount() {
            return localCount;
        }

        public FileSourceSplit getSplit() {
            return split;
        }

        public String[] getNormalizedHosts() {
            return normalizedHosts;
        }
    }

    /**
     * Holds a list of LocatableInputSplits and returns the split with the lowest local count. The
     * rational is that splits which are local on few hosts should be preferred over others which
     * have more degrees of freedom for local assignment.
     *
     * <p>Internally, the splits are stored in a linked list. Sorting the list is not a good
     * solution, as local counts are updated whenever a previously unseen host requests a split.
     * Instead, we track the minimum local count and iteratively look for splits with that minimum
     * count.
     */
    private static class LocatableSplitChooser {

        /**
         * list of all input splits.
         */
        private final LinkedList<SplitWithInfo> splits = new LinkedList<>();

        /**
         * The current minimum local count. We look for splits with this local count.
         */
        private int minLocalCount = -1;

        /**
         * The second smallest count observed so far.
         */
        private int nextMinLocalCount = -1;

        /**
         * number of elements we need to inspect for the minimum local count.
         */
        private int elementCycleCount = 0;

        LocatableSplitChooser() {
        }

        LocatableSplitChooser(Collection<SplitWithInfo> splits) {
            for (SplitWithInfo split : splits) {
                addInputSplit(split);
            }
        }

        /**
         * Adds a single input split.
         */
        void addInputSplit(SplitWithInfo split) {
            int localCount = split.getLocalCount();
            if (minLocalCount == -1) {
                // first split to add
                this.minLocalCount = localCount;
                this.elementCycleCount = 1;
                this.splits.offerFirst(split);
            } else if (localCount < minLocalCount) {
                // split with new min local count
                this.nextMinLocalCount = this.minLocalCount;
                this.minLocalCount = localCount;
                // all other splits have more local host than this one
                this.elementCycleCount = 1;
                splits.offerFirst(split);
            } else if (localCount == minLocalCount) {
                this.elementCycleCount++;
                this.splits.offerFirst(split);
            } else {
                if (localCount < nextMinLocalCount) {
                    nextMinLocalCount = localCount;
                }
                splits.offerLast(split);
            }
        }

        /**
         * Retrieves a LocatableInputSplit with minimum local count. InputSplits which have already
         * been assigned (i.e., which are not contained in the provided set) are filtered out. The
         * returned input split is NOT removed from the provided set.
         *
         * @param unassignedSplits Set of unassigned input splits.
         * @return An input split with minimum local count or null if all splits have been assigned.
         */
        @Nullable
        SplitWithInfo getNextUnassignedMinLocalCountSplit(Set<SplitWithInfo> unassignedSplits) {
            if (splits.size() == 0) {
                return null;
            }
            do {
                elementCycleCount--;
                // take first split of the list
                SplitWithInfo split = splits.pollFirst();
                if (unassignedSplits.contains(split)) {
                    int localCount = split.getLocalCount();
                    // still unassigned, check local count
                    if (localCount > minLocalCount) {
                        // re-insert at end of the list and continue to look for split with smaller
                        // local count
                        splits.offerLast(split);
                        // check and update second smallest local count
                        if (nextMinLocalCount == -1 || split.getLocalCount() < nextMinLocalCount) {
                            nextMinLocalCount = split.getLocalCount();
                        }
                        split = null;
                    }
                } else {
                    // split was already assigned
                    split = null;
                }
                if (elementCycleCount == 0) {
                    // one full cycle, but no split with min local count found
                    // update minLocalCnt and element cycle count for next pass over the splits
                    minLocalCount = nextMinLocalCount;
                    nextMinLocalCount = -1;
                    elementCycleCount = splits.size();
                }
                if (split != null) {
                    // found a split to assign
                    return split;
                }
            } while (elementCycleCount > 0);
            // no split left
            return null;
        }
    }
}


@Override
    public void doEndTag(FormEntrySession session, PrintWriter out, Node parent, Node node)

package org.openmrs.module.htmlformentry.handler;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import org.openmrs.module.htmlformentry.FormEntrySession;
import org.openmrs.module.htmlformentry.action.RepeatControllerAction;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * Currently not used--the {@code <repeat>} tag is currently handled by
 * {@see org.openmrs.module.htmlformentry.HtmlFormEntryGenerator#applyRepeats(String)}.
 */
public abstract class RepeatTagHandler implements IteratingTagHandler {

    @Override
    public boolean doStartTag(FormEntrySession session, PrintWriter out, Node parent, Node node) {
        Map<String, String> attributes = new HashMap<String, String>();
        NamedNodeMap map = node.getAttributes();
        for (int i = 0; i < map.getLength(); ++i) {
            Node attribute = map.item(i);
            attributes.put(attribute.getNodeName(), attribute.getNodeValue());
        }
        setupBefore(session, attributes);
        session.getSubmissionController().startRepeat(getRepeatAction(session, attributes));
        // recurse to children
        return true;
    }

{
        session.getSubmissionController().endRepeat();
    }

    protected abstract void setupBefore(FormEntrySession session, Map<String, String> attributes);

    protected abstract RepeatControllerAction getRepeatAction(FormEntrySession session, Map<String, String> attributes);
}


{
        session.getSubmissionController().endRepeat();
    }

package org.openmrs.module.htmlformentry.handler;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import org.openmrs.module.htmlformentry.FormEntrySession;
import org.openmrs.module.htmlformentry.action.RepeatControllerAction;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * Currently not used--the {@code <repeat>} tag is currently handled by
 * {@see org.openmrs.module.htmlformentry.HtmlFormEntryGenerator#applyRepeats(String)}.
 */
public abstract class RepeatTagHandler implements IteratingTagHandler {

    @Override
    public boolean doStartTag(FormEntrySession session, PrintWriter out, Node parent, Node node) {
        Map<String, String> attributes = new HashMap<String, String>();
        NamedNodeMap map = node.getAttributes();
        for (int i = 0; i < map.getLength(); ++i) {
            Node attribute = map.item(i);
            attributes.put(attribute.getNodeName(), attribute.getNodeValue());
        }
        setupBefore(session, attributes);
        session.getSubmissionController().startRepeat(getRepeatAction(session, attributes));
        // recurse to children
        return true;
    }

    @Override
    public void doEndTag(FormEntrySession session, PrintWriter out, Node parent, Node node)

    protected abstract void setupBefore(FormEntrySession session, Map<String, String> attributes);

    protected abstract RepeatControllerAction getRepeatAction(FormEntrySession session, Map<String, String> attributes);
}


package org.openmrs.module.htmlformentry.handler;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import org.openmrs.module.htmlformentry.FormEntrySession;
import org.openmrs.module.htmlformentry.action.RepeatControllerAction;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * Currently not used--the {@code <repeat>} tag is currently handled by
 * {@see org.openmrs.module.htmlformentry.HtmlFormEntryGenerator#applyRepeats(String)}.
 */
public abstract class RepeatTagHandler implements IteratingTagHandler {

    @Override
    public boolean doStartTag(FormEntrySession session, PrintWriter out, Node parent, Node node) {
        Map<String, String> attributes = new HashMap<String, String>();
        NamedNodeMap map = node.getAttributes();
        for (int i = 0; i < map.getLength(); ++i) {
            Node attribute = map.item(i);
            attributes.put(attribute.getNodeName(), attribute.getNodeValue());
        }
        setupBefore(session, attributes);
        session.getSubmissionController().startRepeat(getRepeatAction(session, attributes));
        // recurse to children
        return true;
    }

    @Override
    public void doEndTag(FormEntrySession session, PrintWriter out, Node parent, Node node) {
        session.getSubmissionCont

    }

    protected abstract void setupBefore(FormEntrySession session, Map<String, String> attributes);

    protected abstract RepeatControllerAction getRepeatAction(FormEntrySession session, Map<String, String> attributes);
}


for (int i = 0; i < map.getLength(); ++i) {
            Node attribute = map.item(i);
            attributes.put(attribute.getNodeName(), attribute.getNodeValue());
        }

package org.openmrs.module.htmlformentry.handler;

import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;
import org.openmrs.module.htmlformentry.FormEntrySession;
import org.openmrs.module.htmlformentry.action.RepeatControllerAction;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * Currently not used--the {@code <repeat>} tag is currently handled by
 * {@see org.openmrs.module.htmlformentry.HtmlFormEntryGenerator#applyRepeats(String)}.
 */
public abstract class RepeatTagHandler implements IteratingTagHandler {

    @Override
    public boolean doStartTag(FormEntrySession session, PrintWriter out, Node parent, Node node) {
        Map<String, String> attributes = new HashMap<String, String>();
        NamedNodeMap map = node.getAttributes();

        setupBefore(session, attributes);
        session.getSubmissionController().startRepeat(getRepeatAction(session, attributes));
        // recurse to children
        return true;
    }

    @Override
    public void doEndTag(FormEntrySession session, PrintWriter out, Node parent, Node node) {
        session.getSubmissionController().endRepeat();
    }

    protected abstract void setupBefore(FormEntrySession session, Map<String, String> attributes);

    protected abstract RepeatControllerAction getRepeatAction(FormEntrySession session, Map<String, String> attributes);
}


@Override
        public <T> Set<T> loadKeywordValueSet(Class<T> type)

package org.leadpony.justify.api.keyword;

import java.util.Collections;
import java.util.Set;

/**
 * A loader of the limited keyword value set.
 *
 * @author leadpony
 */
public interface KeywordValueSetLoader {

    /**
     * Loads the value set of the specified type.
     *
     * @param <T> the type of the value.
     * @param type the class of the value.
     * @return loaded set of values.
     */
    <T> Set<T> loadKeywordValueSet(Class<T> type);

    /**
     * A loader which will loads nothing.
     */
    KeywordValueSetLoader NEVER = new KeywordValueSetLoader() {

{
            return Collections.emptySet();
        }
    };
}


{
            return Collections.emptySet();
        }

package org.leadpony.justify.api.keyword;

import java.util.Collections;
import java.util.Set;

/**
 * A loader of the limited keyword value set.
 *
 * @author leadpony
 */
public interface KeywordValueSetLoader {

    /**
     * Loads the value set of the specified type.
     *
     * @param <T> the type of the value.
     * @param type the class of the value.
     * @return loaded set of values.
     */
    <T> Set<T> loadKeywordValueSet(Class<T> type);

    /**
     * A loader which will loads nothing.
     */
    KeywordValueSetLoader NEVER = new KeywordValueSetLoader() {

        @Override
        public <T> Set<T> loadKeywordValueSet(Class<T> type)


package org.leadpony.justify.api.keyword;

import java.util.Collections;
import java.util.Set;

/**
 * A loader of the limited keyword value set.
 *
 * @author leadpony
 */
public interface KeywordValueSetLoader {

    /**
     * Loads the value set of the specified type.
     *
     * @param <T> the type of the value.
     * @param type the class of the value.
     * @return loaded set of values.
     */
    <T> Set<T> loadKeywordValueSet(Class<T> type);

    /**
     * A loader which will loads nothing.
     */
    KeywordValueSetLoader NEVER = new KeywordValueSetLoader() {

        @Override
        public <T> Set<T> loadKeywordValueSet(Class<T> type) {
            return Collections


<T> Set<T> loadKeywordValueSet(Class<T> type);

package org.leadpony.justify.api.keyword;

import java.util.Collections;
import java.util.Set;

/**
 * A loader of the limited keyword value set.
 *
 * @author leadpony
 */
public interface KeywordValueSetLoader {

    /**
     * Loads the value set of the specified type.
     *
     * @param <T> the type of the value.
     * @param type the class of the value.
     * @return loaded set of values.
     */

    /**
     * A loader which will loads nothing.
     */
    KeywordValueSetLoader NEVER = new KeywordValueSetLoader() {

        @Override
        public <T> Set<T> loadKeywordValueSet(Class<T> type) {
            return Collections.emptySet();
        }
    };
}


/**
 * ****************************************************************************
 *
 *  Contributors:
 *     Thales - initial API and implementation
 * *****************************************************************************
 */
package org.polarsys.capella.core.platform.sirius.ui.project;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.PlatformUI;

public class NewProjectAction implements IViewActionDelegate {

    // The action site.
    private IWorkbenchSite _site;

    /**
     * Constructs the new project action.
     */
    public NewProjectAction() {
        // Do nothing.
    }

    /**
     * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
     */
    public void init(IViewPart view_p) {
        _site = view_p.getViewSite();
    }

    /**
     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
     */

{
        NewProjectWizard wizard = new NewProjectWizard();
        wizard.init(PlatformUI.getWorkbench(), StructuredSelection.EMPTY);
        WizardDialog dialog = new WizardDialog(_site.getShell(), wizard);
        dialog.open();
    }

    /**
     * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
     */
    public void selectionChanged(IAction action_p, ISelection selection_p) {
        // Do nothing.
    }

    /**
     * Set site.
     * @param site_p the site to set
     */
    public void setSite(IWorkbenchSite site_p) {
        _site = site_p;
    }
}


{
        _site = view_p.getViewSite();
    }

/**
 * ****************************************************************************
 *
 *  Contributors:
 *     Thales - initial API and implementation
 * *****************************************************************************
 */
package org.polarsys.capella.core.platform.sirius.ui.project;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.PlatformUI;

public class NewProjectAction implements IViewActionDelegate {

    // The action site.
    private IWorkbenchSite _site;

    /**
     * Constructs the new project action.
     */
    public NewProjectAction() {
        // Do nothing.
    }

    /**
     * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
     */
    public void init(IViewPart view_p)

    /**
     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
     */
    public void run(IAction action_p) {
        NewProjectWizard wizard = new NewProjectWizard();
        wizard.init(PlatformUI.getWorkbench(), StructuredSelection.EMPTY);
        WizardDialog dialog = new WizardDialog(_site.getShell(), wizard);
        dialog.open();
    }

    /**
     * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
     */
    public void selectionChanged(IAction action_p, ISelection selection_p) {
        // Do nothing.
    }

    /**
     * Set site.
     * @param site_p the site to set
     */
    public void setSite(IWorkbenchSite site_p) {
        _site = site_p;
    }
}


/**
 * ****************************************************************************
 *
 *  Contributors:
 *     Thales - initial API and implementation
 * *****************************************************************************
 */
package org.polarsys.capella.core.platform.sirius.ui.project;

import org.eclipse.jface.action.IAction;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
import org.eclipse.ui.IViewActionDelegate;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchSite;
import org.eclipse.ui.PlatformUI;

public class NewProjectAction implements IViewActionDelegate {

    // The action site.
    private IWorkbenchSite _site;

    /**
     * Constructs the new project action.
     */
    public NewProjectAction() {
        // Do nothing.
    }

    /**
     * @see org.eclipse.ui.IViewActionDelegate#init(org.eclipse.ui.IViewPart)
     */
    public void init(IViewPart view_p) {
        _site = view_p.getViewSite();
    }

    /**
     * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
     */
    public void run(IAction action_p) {
        NewProjectWizard wizard = new NewProjectWizard();
        wizard.init(PlatformUI.getWorkbench(), StructuredSelection.EMPTY);
        WizardDialog dialog = new WizardDialog(_site.getShell(), wizard);
        dialog.open();
    }

    /**
     * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
     */
    public void selectionChanged(IAction action_p, ISelection selection_p) {
        // Do nothing.
    }

    /**
     * Set site.
     * @param site_p the site to set
     */
    public void setSite(IWorkbenchSite site_p) {


public void run(IAction action_p) {
        NewProjectWizard wizard = new NewProjectWizard();
        wizard.init(PlatformUI.getWorkbench(), StructuredSelection.EMPTY);
        WizardDialog dialog = new WizardDialog(_site.getShell(), wizard);
        dialog.open();
    }

    /**
     * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
     */
    public void selectionChanged(IAction action_p, ISelection selection_p) {
        // Do nothing.
    }

    /**
     * Set site.
     * @param site_p the site to set
     */
    public void setSite(IWorkbenchSite site_p) {
        _site = site_p;
    }
}


/**
 *   Contributors:
 *      Thales - initial API and implementation
 */
package org.polarsys.capella.viatra.core.data.interaction.surrogate;

import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
import org.eclipse.viatra.query.runtime.api.impl.BaseGeneratedPatternGroup;
import org.polarsys.capella.viatra.core.data.interaction.surrogate.AbstractCapabilityRealization__realizedCapability;
import org.polarsys.capella.viatra.core.data.interaction.surrogate.AbstractCapabilityRealization__realizingCapability;

/**
 * A pattern group formed of all public patterns defined in AbstractCapabilityRealization.vql.
 *
 *
Use the static instance as any {@link interface org.eclipse.viatra.query.runtime.api.IQueryGroup}, to conveniently prepare
 * a VIATRA Query engine for matching all patterns originally defined in file AbstractCapabilityRealization.vql,
 * in order to achieve better performance than one-by-one on-demand matcher initialization.
 *
 *
 From package org.polarsys.capella.viatra.core.data.interaction.surrogate, the group contains the definition of the following patterns:

 *
AbstractCapabilityRealization__realizedCapability

 *
AbstractCapabilityRealization__realizingCapability

 *

 *
 * @see IQueryGroup
 */
@SuppressWarnings("all")
public final class AbstractCapabilityRealization extends BaseGeneratedPatternGroup {

    /**
     * Access the pattern group.
     *
     * @return the singleton instance of the group
     * @throws ViatraQueryRuntimeException if there was an error loading the generated code of pattern specifications
     */
    public static AbstractCapabilityRealization instance() {
        if (INSTANCE == null) {
            INSTANCE = new AbstractCapabilityRealization();
        }
        return INSTANCE;
    }

    private static AbstractCapabilityRealization INSTANCE;

    private AbstractCapabilityRealization() {
        querySpecifications.add(AbstractCapabilityRealization__realizedCapability.instance());
        querySpecifications.add(AbstractCapabilityRealization__realizingCapability.instance());
    }

{
        return AbstractCapabilityRealization__realizedCapability.instance();
    }

    public AbstractCapabilityRealization__realizedCapability.Matcher getAbstractCapabilityRealization__realizedCapability(final ViatraQueryEngine engine) {
        return AbstractCapabilityRealization__realizedCapability.Matcher.on(engine);
    }

    public AbstractCapabilityRealization__realizingCapability getAbstractCapabilityRealization__realizingCapability() {
        return AbstractCapabilityRealization__realizingCapability.instance();
    }

    public AbstractCapabilityRealization__realizingCapability.Matcher getAbstractCapabilityRealization__realizingCapability(final ViatraQueryEngine engine) {
        return AbstractCapabilityRealization__realizingCapability.Matcher.on(engine);
    }
}


{
        return AbstractCapabilityRealization__realizedCapability.instance();
    }

/**
 *   Contributors:
 *      Thales - initial API and implementation
 */
package org.polarsys.capella.viatra.core.data.interaction.surrogate;

import org.eclipse.viatra.query.runtime.api.ViatraQueryEngine;
import org.eclipse.viatra.query.runtime.api.impl.BaseGeneratedPatternGroup;
import org.polarsys.capella.viatra.core.data.interaction.surrogate.AbstractCapabilityRealization__realizedCapability;
import org.polarsys.capella.viatra.core.data.interaction.surrogate.AbstractCapabilityRealization__realizingCapability;

/**
 * A pattern group formed of all public patterns defined in AbstractCapabilityRealization.vql.
 *
 *
Use the static instance as any {@link interface org.eclipse.viatra.query.runtime.api.IQueryGroup}, to conveniently prepare
 * a VIATRA Query engine for matching all patterns originally defined in file AbstractCapabilityRealization.vql,
 * in order to achieve better performance than one-by-one on-demand matcher initialization.
 *
 *
 From package org.polarsys.capella.viatra.core.data.interaction.surrogate, the group contains the definition of the following patterns:

 *
AbstractCapabilityRealization__realizedCapability

 *
AbstractCapabilityRealization__realizingCapability

 *

 *
 * @see IQueryGroup
 */
@SuppressWarnings("all")
public final class AbstractCapabilityRealization extends BaseGeneratedPatternGroup {

    /**
     * Access the pattern group.
     *
     * @return the singleton instance of the group
     * @throws ViatraQueryRuntimeException if there was an error loading the generated code of pattern specifications
     */
    public static AbstractCapabilityRealization instance() {
        if (INSTANCE == null) {
            INSTANCE = new AbstractCapabilityRealization();
        }
        return INSTANCE;
    }

    private static AbstractCapabilityRealization INSTANCE;

    private AbstractCapabilityRealization() {
        querySpecifications.add(AbstractCapabilityRealization__realizedCapability.instance());
        querySpecifications.add(AbstractCapabilityRealization__realizingCapability.instance());
    }

    public AbstractCapabilityRealization__realizedCapability getAbstractCapabilityRealization__realizedCapability()

    public AbstractCapabilityRealization__realizedCapability.Matcher getAbstractCapabilityRealization__realizedCapability(final ViatraQueryEngine engine) {
        return AbstractCapabilityRealization__realizedCapability.Matcher.on(engine);
    }

    public AbstractCapabilityRealization__realizingCapability getAbstractCapabilityRealization__realizingCapability() {
        return AbstractCapabilityRealization__realizingCapability.instance();
    }

    public AbstractCapabilityRealization__realizingCapability.Matcher getAbstractCapabilityRealization__realizingCapability(final ViatraQueryEngine engine) {
        return AbstractCapabilityRealization__realizingCapability.Matcher.on(engine);
    }
}