- Вступление
- На практике
- Приложение libCurl
- Приложение libSSH2
- Заключительные Мысли
- Рекомендации
На прошлой неделе я наблюдал за довольно крутым выступлением НА конференции [1] с Микаэлем Видштедтом, директором по разработке программного обеспечения Oracle, где он представляет многие из предстоящих и разрабатываемых в настоящее время функций Java. Один из них, Проект Панама , показался мне особенно интересным.
Отказ от ответственности: Проект Панама все еще находится на ранних стадиях разработки, поэтому содержание этой статьи может не отражать его текущее состояние.
Project Panama, доступный в сборках JDK 13 с ранним доступом, предназначен для соединения Java и собственного кода. Чем это полезно? Существуют определенные случаи использования, когда часть функциональности доступна в виде библиотеки, написанной на C или C++, и требуется интегрировать ее в приложение Java. Текущее решение заключается в использовании собственного интерфейса Java (JNI) [2] что может потребовать огромного объема работы, а также довольно подвержено ошибкам. Вам нужно хорошо разбираться в внутренностях собственной библиотеки, а затем написать все необходимые реализации для соединения интерфейса Java с собственным кодом. По моему опыту, вызов встроенных библиотечных функций, которые могут измениться в какой-то более поздний момент времени, а также управление распределением памяти кучи может быть реальной проблемой с JNI. Процитировать Микаэля, как он говорит это на видео:
Сколько людей здесь написали JNI или, вы знаете, сделали ЭТО? Нам так жаль вас!
Вот тут-то и вступает в игру Панама. Он предоставляет новые инструменты и API для упрощения связи между Java и машинным кодом. В основном это сводится к следующим шагам:
- Создайте привязки Java (интерфейсы) из существующих заголовочных файлов C с помощью инструмента извлечь .
- Вызывайте функции C через извлеченный интерфейс Java с использованием java.foreign API.
Это позволяет вам сосредоточиться на написании основной логики вашего приложения, а не возиться с кодом клея и деталями интеграции.
Страницы документации проекта Панама [3] уже приведено солидное количество примеров для начала. Я просто бегло взгляну на то, как соединить и запустить libCurl Java-приложение а затем я хотел бы представить более подробный пример – простой SSH-клиент, который я написал на основе libSSH2 .
Я запускаю эти примеры на mac OS, но с помощью нескольких настроек вы также сможете запускать их на установке Linux.
Приложение libCurl
Как загрузить веб-страницу, используя реализацию собственной библиотеки Curl? Ну, сначала нам нужно достать и извлечь Панаму Сборка OpenJDK архив.
Давайте откроем оболочку и установим переменную среды JAVA_HOME
в то место, где извлекается архив сборки OpenJDK.
export JAVA_HOME=/opt/jdk-13.jdk
Теперь нам нужно сгенерировать интерфейсы Java, код клея, который свяжет код Java с родной библиотекой. Это приведет к curl.jar
файл:
$JAVA_HOME/bin/jextract -t org.unix -L /usr/lib -lcurl \ --record-library-path /usr/include/curl/curl.h \ -o curl.jar
Когда мы проверяем файл JAR, мы можем увидеть все вызовы API Curl, а также привязки зависимостей. API Curl доступен через новый java.foreign Java API.
Теперь для краткого примера. Вот фрагмент кода Java, который извлекает веб-страницу и отображает ее содержимое на экране.
import java.lang.invoke.*; import java.foreign.*; import java.foreign.memory.*; import org.unix.curl.*; import org.unix.curl_h; import static org.unix.curl_h.*; import static org.unix.easy_h.*; public class Main { public static void main(String[] args) { try (Scope s = curl_h.scope().fork()) { curl_global_init(CURL_GLOBAL_DEFAULT); Pointercurl = curl_easy_init(); if(!curl.isNull()) { Pointer url = s.allocateCString(args[0]); curl_easy_setopt(curl, CURLOPT_URL, url); int res = curl_easy_perform(curl); if (res != CURLE_OK) { System.err.println("Error fetching from: " + args[0] + " ERR: " + Pointer.toString(curl_easy_strerror(res))); curl_easy_cleanup(curl); } } curl_global_cleanup(); } } }
Здесь следует отметить пару вещей. Обратите внимание, что мы не можем напрямую передать Java Строка
для вызова curl_easy_setopt()
. Этот вызов принимает указатель адреса памяти в качестве параметра url
, поэтому сначала нам нужно выполнить операцию динамического выделения памяти с использованием Область действия
и вместо этого передайте экземпляр интерфейса Указатель
. Как вы можете найти в панамских технических документах [[5] , интерфейс Указатель
очень помогает, когда дело доходит до сложных C-подобных операций с указателями, таких как арифметика указателей, приведения, разыменование памяти и т.д. Область управляет жизненным циклом динамической выделенной памяти во время выполнения.
Хорошо, теперь, вооружившись этими знаниями, можете ли вы расширить этот код, чтобы записать содержимое веб-страницы, извлеченной Curl, в поток файлов?
Приложение libSSH2
Вот более полный пример приложения, которое использует libSSH2 [4] для реализации простого SSH-клиента.
петров/ява-Панама-ssh2
Java SSH-клиент, использующий libssh2 через project Panama
Простой клиент Java SSH2, использующий собственную библиотеку libssh2 и проект JDK 13 .
записка: Это экспериментальный проект. Стабильность не гарантируется.
Устанавливать
Клиент был протестирован на macOS и Linux. Также должна быть возможность запустить его в Windows, однако в этом направлении не было проделано никакой работы. Пиарщики приветствуются!
Установите libssh2
.
- macOS –
заваривать установку libssh2
- CentOS –
yum установить libssh2.x86_64 libssh2-devel.x86_64
Получите последнюю версию Панамы Сборка JDK .
Откройте консольную оболочку и настройте JAVA_HOME
var так, чтобы он указывал на JDK 13.
Создайте необходимые интерфейсы Java из собственных заголовков libssh2:
./gen_bindings.sh
Бежать
Для компиляции и запуска используйте:
./run.sh [-p|-k] hostname port username [path to ssh keys]
-p
использует пароль для входа в систему. Вам будет предложено ввести свой пароль.-k
использует логин с открытым ключом. Вам нужно будет указать путь к вашим ключам, например,~/.ssh
.
Лицензия
…
Если вы хотите попробовать и настроить его для работы в Windows, я буду вам очень признателен.
Несколько моментов с моей стороны, которые я узнал или о которых думал во время работы с Панамой.
- Область действия
/довольно мощная. Вы можете выделять указатели обратного вызова, структуры, массивы. Концепция макетов и типов макетов заслуживает большего времени для моего полного изучения и понимания.
Неудивительно, что написание кода Java с использованием собственной библиотеки является более обширным и требует особой осторожности, особенно когда дело доходит до того, чтобы не забывать вызывать вызовы API очистки, которые требуются библиотеке. - Для ввода-вывода в большинстве собственных библиотек требуется дескриптор файла, который нелегко получить в Java
- [6] . Это, однако, не имеет прямого отношения к API java.foreign . Некоторые библиотеки определяют прототипы функций в стиле C++ без аргументов в отличие от типов аргументов в стиле C
- Void
. Иностранные документы
[3] приведите пример этого случая при использовании API TensorFlow C. Я не исследовал, можно ли использовать Панаму с собственными библиотеками, созданными Go или Rust. Это было бы довольно круто.
Спасибо за чтение! 🍻
- GOTO 2019 • Проект Панамская часть
- Собственный интерфейс Java
- Панамские иностранные документы
- libSSH2 – библиотека C на стороне клиента, реализующая протокол SSH2
- Документы Панамского связующего v3
- Наиболее эффективный способ передачи дескриптора файла сокета Java в двоичный файл C
Оригинал: “https://dev.to/petarov/java-and-native-code-in-openjdk-13-18em”