JNLP API Java

JNLP API JavaJNLP API позволяет неподписанному приложению запускаться в "песочнице" и в то же время получать безопасный доступ к локальным ресурсам. Например, в нем предусмотрены службы для загрузки и сохранения файлов. Приложения не видит файловой системы и не может специфицировать имена файлов.

Вместо этого отображается файловый диалог, и пользователь программы выбирает файл. Перед появлением диалогового окна для выбора файлов пользователь получает предупреждение и должен выразить согласие на продолжение работы. Более того, на самом деле API не предоставляет программе доступа к объекту File.

В частности, приложение не может самостоятельно обнаружить файл. Поэтому программистам предоставляются инструменты для реализации действий открытия и сохранения файла, но системная информация максимально скрыта от сомнительных приложений.API предоставляет разработчику описанные ниже возможности:

  • Загрузка и сохранения файлов.
  • Доступ к буферу обмена.
  • Печать.
  • Отображение документа в стандартном браузере.
  • Хранение и извлечение конфигурационных данных.
  • Средства, позволяющие убедиться в том, что выполняется только один экземпляр приложения(данная возможность была реализована в Java SE 5.0).

Чтобы воспользоваться этими возможностями, необходимо применить класс ServiceManager, примерно так:

FileSaveService service = (FileSaveService)ServiceManager.lookup("javax.jnlp.FileSaveService");

Если соответствующая функция оказалась недоступной, генерируется исключение UnavailableServiceException.

Для компиляции программы, использующей интерфейс JNLP API, необходимо указать в составе пути для поиска классов файл javaws.jar. Этот файл находится в подкаталоге jre/lib каталога JDK.

Теперь перейдем к обсуждению наиболее полезных возможностей JNLP. Чтобы сохранить файл, следует указать в диалоговом окне предложения о первоначальном пути и расширения файлов, а также сохраняемые данные и предполагаемое имя файла. Рассмотрим пример:

service.saveFileDialog(".", new String[] { "txt" }, data, "calc.txt"};

Данные должны быть доставлены в поток InputStream. Иногда эта задача оказывается довольно сложной. Программа, приведенная в конце статьи, использует описанную ниже стратегию.

  1. Создается экземпляр класса ByteArrayOutputStream, предназначенный для хранения байтов, подлежащих записи на диск.
  2. Создается экземпляр класса PrintStream, посылающий эти данные в поток ByteArrayOutputStream.
  3. Информация, подлежащая сохранению в потоке печати, выводится в PrintStream.
  4. Создается экземпляр класса ByteArrayInputStream, считывающий сохраненные байты.
  5. Поток передается методу saveFileDialog().

Более подробно потоки описываются в данной рубрике. Пока же мы можем не обращать внимания на детали, указанные в демонстрационной программе в конце урока.

Чтобы считать данные из файла, используется класс FileOpenService. Его метод openFileDialog() получает первоначальный путь и расширения файлов и возвращает объект класса FileContents. Затем можно вызвать метод getInputStream() и считать данные из файла. Если пользователь не выбрал файл, метод openFileDialog() возвращает значение null.

FileSaveService service = (FileSaveService)ServiceManager.lookup("javax.jnlp.FileSaveService");
FileContents contents = service.openFileDialog(".", new String[] { "txt" });
if(contents != null)
{
InputStream in = contents.getInputStream();
...
}

Обратите внимание, что ваше приложение не знаете имени и места расположения файла. В противоположность этому, если вы хотите открыть определенный файл, то используете ExtendedService.

ExtendedService service = (ExtendedService)ServiceManager.lookup("javax.jnlp.ExtendedService");
FileContents contents = service.openFile(new File("C:\\autoexec.bat"));
if(contents != null)
{
OutputStream out = contents.getOutputStream();
...
}

Пользователь вашей программы должен разрешить доступ к файлу(смотрите рис.2).

JNLP API JavaРис.2. Предупреждение о доступе к файлу

Для того чтобы отобразить документ в стандартном браузере(аналогично методу showDocument() для аплетов), применяется интерфейс BasicService. Учтите, что в некоторых системах стандартный браузер не установлен.

BasicService service = (BasicService)ServiceManager.lookup("javax.jnlp.BasicService");
if(service.isWebBrowserSupported())
service.showDocument(url);
else...

Существует устаревший метод PersistentService(), позволяющий приложению сохранять небольшие объемы информации о настройках и извлекать ее, если приложение запускается вновь. Эта возможность напоминает механизм cookie, применяемый при работе с протоколом HTTP. В качестве ключей используются URL. Эти URL не обязательно должны ссылаться на реальные ресурсы. Они лишь представляют собой удобную иерархическую схему именования файлов.

По каждому URL-ключу приложение может записать произвольные двоичные данные. Объем записи может быть ограничен и размером блока.

Для того чтобы изолировать приложение друг от друга, каждое приложение должно использовать URL, начинающейся с имени сервера, содержащего его код который указан в JNLP-файле. Например, если приложение загружено с Web-страницы http://pro-java.ru/apps, то оно может использовать лишь ключи, имеющие вид http://pro-java.ru/apps/subkey1/subkey2/... Попытка получить доступ к другим ключам будет заведомо неудачной.

Чтобы определить адрес сервера, на котором хранится код, приложение может вызвать метод getCodebase() класса BasicService.

Новый ключ создается с помощью метода create() класса PersistenceService:

Url url = new URL(codebase, "mykey");
servise.create(url, maxSize);

Для доступа к информации, связанной с конкретным ключом, вызывается метод get(). Этот метод возвращает экземпляр класса FileContents, с помощью которого можно читать и записывать данные, соответствующие указанному ключу.

FileConents contents = service.get(url);
InputStream in = contents.getInputStream();
OutputStream out = contents.getOutputStream(true);
// true = перезапись

К сожалению, определить, существует указанный ключ или его нужно создать заново, довольно сложно. Мы может лишь надеяться, что ключ существует, и вызывать метод get. Если при этом генерируется исключение FileNotFoundException, необходимо создать новый ключ.

Начиная с Java SE 5.0, и приложение Java Web Start, и аплеты могут выводить данные на печать, используя обычные средства API. При этом отображается диалоговое окно, запрашивающее у пользователя согласие на доступ к принтеру.

Программа, код которой приведен ниже, представляет собой модификатор приложения, реализующего калькулятор. Этот калькулятор имеет виртуальную бумажную ленту, на которую записываются результаты всех вычислений. Список всех предыдущих вычислений можно сохранять и считывать из файла.

Для демонстрации постоянного хранения данных приложение позволяет задавать заголовок фрейма. Если программу запустить вновь, она извлечет этот заголовок из постоянного хранилища(смотрите рис.3).

jnlp-api-java-2Рис.3. Приложение WebStartCalculator

Вот исходный код программы:

import java.awt.EventQueue;
import java.awt.event.*;
import java.io.*;
import java.net.*;
import javax.swing.*;
import javax.jnlp.*;

/**
 *    . 
 *    Java Web Start.
 * @author pro-java.ru
 */
public class WebStartCalculator {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable()
        {
            public void run()
            {
                CalculatorFrame frame = new CalculatorFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }

}
/**
* ,     
*     .
*/
class CalculatorFrame extends JFrame
{
    public CalculatorFrame()
    {
        setTitle();
        panel = new CalculatorPanel();
        add(panel);
        
        JMenu fileMenu = new JMenu("File");
        
        JMenuItem openItem = fileMeni.add("Open");
        openItem.addActionListener(new ActionListener() {
            
            public void actionPerformed(ActionEvent event) {
                open();
            }
        });
        
        JMenuItem saveItem = fileMenu.add("Save");
        saveItem.addActionListener(new ActionListener() {
            
            public void actionPerformed(ActionEvent event) {
                save();
            }
        });
        
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(fileMenu);
        setJMenuBar(menuBar);
        
        pack();
    }
    
    /**
     *     .
     *      ,    .
     */
    
    public void setTitle()
    {
        try
        {
            String title = null;
            BasicService basic = (BasicService)
                    ServiceManager.lookup("javax.jnlp.BasicService");
            URL codeBase = basic.getCodeBase();
            
            PersistanceService service = (PersistanceService)
                    ServiceManager.lookup("java.jnlp.PersistanceService");
            URL key = new URL(codeBase, "title");
            
            try
            {
                FileContents contents = service.get(key);
                InputStream in = contents.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                title = reader.readLine();
                
            }
            catch(FileNotFountException e)
            {
                title = JOptionPane.showInputDialog("Please suply a frame title:");
                if(title == null) return;
                
                service.create(key, 100);
                FileContents contents = service.get(key);
                OutputStream out = contents.getOutputStream(true);
                PrintStream printOut = new PrintStream(out);
                printOut.print(title);
            }
            setTitle(title);
        }
        catch(UnavailableServiceException e)
        {
            JOptionPane.showMessageDialog(this, e);
        }
        catch(MalformedURLException e)
        {
            JOptionPane.showMessageDialog(this, e);
        }
        catch(IOException e)
        {
            JOptionPane.showMessageDialog(this, e);
        }
    }
    
    /**
     *      
     *  .
     */
    public voi open()
    {
        try
        {
            FileOpenService service = (FileOpenService)
                    ServiceManager.lookup("javax.jnlp.FileOpenService");
            FileContents conents = service.openFileDialog(".", new String[] { "txt" });
            
            JOptionPane.showMessageDialog(this, conents.getName());
            if(contents != null)
            {
                InputStream in = contents.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                String line;
                while((line = reader.readLine()) != null)
                {
                    panel.append(line);
                    panel.append("\n");
                }
            }
        }
        catch(UnavailableServiceException e)
        {
            JOptionPane.showMessageDialog(this, e);
        }
        catch(IOException e)
        {
            JOptionPane.showMessageDialog(this, e);
        }
    }
    /**
     *    .
     */
    
    public void save()
    {
        try
        {
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            PrintStream printOut = new PrintStream(out);
            printOut.print(panel.getText());
            InputStream data = new ByteArrayInputStream(out.toByteArray());
            
            FileSaveService service = (FileSaveService)
                    ServiceManager.lookup("javax.jnlp.FileSaveService");
            service.saveFileDialog(".", new String[] { "txt" }, data, "calc.txt");
            
        }
        catch(UnavailableServiceException e)
        {
            JOptionPane.showMessageDialog(this, e);
        }
        catch(IOException e)
        {
            JOptionPane.showMessageDialog(this, e);
        }
    }
    private CalculatorPanel panel;
}

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *