12.1.1. Пример использования Rhino

В примере 12.1 приводится простое приложение для интерпретатора Rhino, демонстрирующее большую часть возможностей и приемов, описанных выше. Пример использует пакет javax.swing со средствами построения графических интерфейсов, пакет java.net с инструментами организации сетевых взаимодействий, пакет java.io потокового ввода/вывода и инструменты языка Java многопоточного выполнения для реализации простого приложения менеджера загрузки, которое загружает файлы по адресам URL и отображает ход выполнения загрузки. На рис. 12.1 показано, как выглядит окно приложения в процессе загрузки двух файлов.

Пример 12.1. Приложение менеджера загрузки для Rhino

/*

* Приложение менеджера загрузки с простым графическим интерфейсом,

* построенным средствами языка Java

*/

// Импортировать графические компоненты из библиотеки Swing

// и несколько других классов

importPackage(javax.swing);

importClass(javax.swing.border.EmptyBorder);

importClass(java.awt.event.ActionListener);

importClass(java.net.URL);

importClass(java.io.FileOutputStream);

importClass(java.lang.Thread);

// Создать графические элементы управления

var frame = new JFrame("Rhino URL Fetcher"); // Окно приложения

var urlfield = new JTextField(30);  // Поле ввода URL

var button = new JButton("Download"); // Кнопка запуска загрузки

var fil-echooser = new JFileChooser(); // Диалог выбора файла

var row = Box.createHorizontalBox(); // Контейнер для поля и кнопки

var col = Box.createVerticalBox(); // Для строки и индикатора хода

                                   // выполнения операции

var padding = new EmptyBorder(3.3,3,3); // Отступы для строк

// Объединить все компоненты и отобразить графический интерфейс

row.add(urlfield); // Поместить поле ввода в строку

row.add(button); // Поместить кнопку в строку

col.add(row);// Поместить строку в колонку

frame.add(col); // Поместить колонку во фрейм

row.setBorder(padding); // Добавить отступы вокруг строки

frame.pack(); // Определить минимальный размер

frame.visible = true; // Вывести окно

// Эта функция вызывается, когда в окне что-то происходит,

frame.addWindowListener(function(e, name) {

  // Если пользователь закрыл окно, завершить приложение,

  if (name === "windowclosing") // Rhino добавляет аргумент name

  java.lang.System.exit(0);

});

// Эта функция вызывается, когда пользователь щелкает на кнопке

button.addActionListener(function() {

  try {

    // Создать объект java.net.URL для представления URL источника.

    // (Автоматически будет проверена корректность ввода пользователя)

    var url = new URL(urlfield.text);

    // Предложить пользователю выбрать файл для сохранения содержимого URL

    var response = filechooser.showSaveDialog(fгате);

    // Завершить, если пользователь щелкнул на кнопке Cancel

    if (response != JFileChooser.APPROVE.OPTION) return;

    // Иначе получить объект java.io.File, представляющий файл назначения

    var file = filechooser.getSelectedFile();

    // Запустить новый поток выполнения для загрузки url

    new java.lang.Thread(function() {

      download(url,file); }).start();

  }

  catch(e) {

    // Вывести диалог, если что-то пошло не так

    JOptionPane.showMessageDialog(frame, е.message, "Exception",

      JOptionPane.ERROR.MESSAGE);

  }

});

// Использует java.net.URL и др. для загрузки содержимого URL и использует java.io.File

// и др. для сохранения этого содержимого в файле. Отображает ход выполнения загрузки

// в компоненте JProgressBar. Эта функция вызывается в новом потоке выполнения,

function download(url, file) {

  try {

    // Каждый раз, когда запускается загрузка очередного файла,

    // необходимо добавить в окно новую строку для отображения URL,

    // имени файла и индикатора хода выполнения операции

    var row = Box.createHorizontalBox(); // Создать строку

row.setBorder(padding); // Добавить отступы

var label = url.toString() + ": ";// Отобразить URL

row.add(new JLabel(label)); // в компоненте JLabel

var bar = new JProgressBar(0, 100); // Создать полосу индикатора

bar.stringPainted = true; // Отобразить имя файла

bar.string = file.toString(); // в полосе индикатора

row.add(bar);// Добавить индикатор в строку

col.add(row);// Добавить строку в колонку

frame.pack(); // Изменить размер окна

    // Здесь еще не известен размер загружаемого файла, поэтому изначально

    // индикатор просто воспроизводит анимационный эффект

    bar.indeterminate = true;

    // Установить соединение с сервером и получить размер загружаемого

    // файла, если это возможно

    var conn = url.openConnection();  // Получить java.net.URLConnection

    conn.connect();     // Подключиться и ждать заголовки

    var len = conn.contentLength;      // Проверить, получена ли длина файла

    if (len) {     // Если длина известна, тогда

      bar.maximum = len;     // настроить индикатор на вывод

      bar.indeterminate = false;     // процента выполнения задания

    }

    // Получить потоки ввода и вывода

    var input = conn.inputStream; // Прочитать байты с сервера

    var output = new FileOutputStream(file); // Записать в файл

    // Создать входной буфер в виде массива размером 4 Кбайта

    var buffer = java.lang.reflect.Array.newlnstance(java.lang.Byte.TYPE,4096);

    var num;

    while((num=input.read(buffer)) != -1) { // Читать до признака EOF

       output.write(buffer, 0, num); // Записать байты в файл

       bar.value += num; // Обновить индикатор

    }

    output.close(); // Закрыть потоки по завершении

    input.close();

  }

  catch(e) { // Если что-то пошло не так, вывести ошибку в индикаторе

    if (bar) {

      bar.indeterminate = false; // Остановить анимацию

      bar.string = e.toString(); // Заменить имя файла сообщением

    }

  }

}