IBM®
Перейти к тексту
    в России и странах СНГ [изменить]    Условия использования
 
 
   
    Главная страница    Продукты    Услуги и решения    Поддержка и загрузка    Мой профиль    
Перейти к тексту

developerWorks Россия  >  XML | Технология Java  >

Углубитесь в Hierarchical Inherited Rule-Interpreted XML

Используйте эту новую XML-технологию для создания динамических свойств Java

developerWorks
Опции документа

Опции документа, требующие включения JavaScript, не отображаются

Обсудить


Выскажите мнение об этой странице

Помогите нам улучшить содержание


Уровень сложности: средний

Чэд Медоуз, ведущий инженер, IBM

30.08.2007

При помощи новой XML-технологии, именуемой Hierarchical Inherited Rule-Interpreted XML (далее HIRIX), вы можете заменить стандартные свойства Java на их динамическую версию. Эта технология позволяет определять свойства, которым можно задать значения, основываясь на состоянии приложения с помощью простых выражений или даже сценариев Groovy. Она также позволяет использовать только один файл свойств для нескольких экземпляров приложения. На простом, практическом примере научитесь применять данную технологию вместо файлов свойств Java.

Свойства Java (java.lang.Properties) являются наиболее распространенным методом конфигурации приложения, используемым в Java-программировании. Свойства Java обычно используются для определения того, как сконфигурировано приложение при инициализации, а также чтобы определить некоторые типы поведения при выполнении. Например, свойства часто указывают серверы и порты, необходимые приложению для установки связи при инициализации. Они также могут указывать свойства приложения при выполнении, которые определяют поведение, например максимальное количество статей для отображения на домашней странице или просто текст для отображения заголовка страницы.

Несмотря на частое использование, свойства всегда статичны. Они определяются внутри файла свойств, который затем хранится в файловой системе. Приложение запускается и считывает файл свойств, инициализируя все значения свойств содержащимися внутри файла значениями. В данном случае у вас нет возможности изменять значения до тех пор, пока приложение не будет перезапущено. Можно добавить пусковой механизм для упаковки свойств, чтобы их можно было повторно загрузить без перезапуска приложения. Однако значения свойств по-прежнему будут точно такими же, как в файле свойств, до тех пор, пока пусковой механизм не даст сигнал на перезагрузку или перезапуск. Приложение может быть установлено много раз, например могут быть отдельные инсталляции для разработки, тестирования, производства или же просто установленные в разных географических точках. Каждому экземпляру обычно требуется особый набор параметров конфигурации для надлежащей работы. Для того, чтобы разместить каждый индивидуальный экземпляр, необходимо организовать дополнительный файл свойств.

Проблема традиционного использования свойств Java состоит в том, что у вас имеется жесткая конфигурация, которая требует больших затрат при эксплуатации. Этих ограничений можно избежать, используя HIRIX. Его можно использовать для замены стандартных свойств Java на их динамическую версию. Это позволяет определять свойства, которым можно присваивать значения, основываясь на состоянии приложения. Hierarchical Inherited Rule-Interpreted XML также дает вам возможность использовать один файл свойств для различных экземпляров приложения.

Пример основного свойства

Начнем с простого файла свойств с двумя свойствами, как показано в Листинге 1. На примере этого файла свойств я продемонстрирую разницу между использованием нормальных свойств и расширенных свойств Java.


Листинг 1. Пример файла свойств
                
news_source = mynews.myserver.com
news_max_items = 5

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


Листинг 2. Код приложения для загрузки и отображения свойств
                
public static void main(String[] args) {
   // Получаем URL из файла свойств
   URL propertiesURL = StandardExample.class.getClassLoader().
                       getResource("example1/properties.properties") ;

   try {
      // Показываем значения системных свойств с целью демонстрации и ссылок
      System.out.println("Current system properties:") ;
      System.out.println(System.getProperties().toString()) ;
      System.out.println("Executing example \n\n") ;

      // Создаём экземпляр объекта свойств
      Properties properties = new Properties() ;

      // Загружаем свойства как обычно
      properties.load( propertiesURL.openStream() ) ;

      // Получаем значения свойств для данного примера и выводим их на консоль
      System.out.println( properties.get("news_source")) ;
      System.out.println( properties.get("news_max_items")) ;

   } catch (IOException e) {
      e.printStackTrace() ;
   }

}

В Листинге 3 демонстрируется XML-представление того же файла свойств. Все свойства перечислены с использованием элемента <property>. Атрибут id является ключевым, а атрибут value содержит значение для ключа. В этом конкретном примере свойство 'news_max_items' имеет значение ${5}, а не просто 5. Это наглядно показывает, что с расширенными свойствами значение может содержать величины, отличные от типа java.lang.String. В данном случае значение выражено как java.lang.Integer.


Листинг 3. Файл XML-свойств с теми же значениями, что и в Листинге 1
                
<properties>
        <property id='news_source'    value='mynews.myserver.com' />
        <property id='news_max_items' value="${5}" />
<properties>

Далее, в Листинге 4 показано изменение, необходимое для использования расширенных свойств для выполнения той же самой функции. От вас требуется замена лишь одной строки первоначального кода в Листинге 2. Замените первоначальный java.lang.Properties на com.ibm.dolphin.hirix.properties.HirixProperties, который является классом расширенных свойств.


Листинг 4. Замена в исходном приложении для использования расширенных свойств
                
// Create the instance of the properties object
Properties properties = new HirixProperties() ;

Это все, что вам нужно сделать, чтобы начать использовать расширенные свойства. Их удобно использовать их в качестве замены стандартных java.lang.Properties. По замыслу, существующие реализации свойств должны без труда заменяться расширенными свойствами. При необходимости, можно легко начать использовать более продвинутые возможности расширенных свойств в существующих приложениях.



В начало


Определение динамических свойств

Вы можете использовать HIRIX при определении этих же расширенных свойств для того, чтобы динамически их интерпретировать во время выполнении. Значения динамических свойств являются выражениями, которые в качестве интерпретатора выражений используют Java Expression Language (JEXL) (см. Ресурсы для получения дополнительной информации о JEXL-выражениях). В Листинге 5 показано, как составить файл свойств, который использует эти выражения для анализа значений при запуске.


Листинг 5. Файл свойств, содержащий динамические значения
                
<!-- Файл свойств показывает, как изменить значения, основываясь на состоянии приложения.
     Переменная 'user' размещается в контексте приложением -->
<!-- system['key'] является эквивалентом System.getProperties.get("key") -->

<properties>
<!-- Добавление атрибута 'if' позволяет контролировать случаи, когда используется значение
          Свойства.
          Первое свойство, значением которого будет true, вернёт своё значение -->

     <property id='news_source'     value='developer_news.myserver.com'
                                    if="${user.job == 'developer'}"/>

     <property id='news_source'     value='architect_news.myserver.com'
                                    if="${user.job == 'architect'}"/>

     <property id='news_max_items'  value="${5}"
                                    if="${user.job == 'developer'}"/>

     <property id='news_max_items'  value="${10}"
                                    if="${user.job == 'architect'}"/>

     <Демонстрация использования объединения значений в одно значение -->
     <property id="greeting"
               value="Hello ${user.name}
                      мы извлекаем элементы ${news_max_items} для ${user.job}"/>

     <Данное свойство использует объединение значений, 
          а также свойств системы -->

     <property id="resource_directory" value="${system['user.dir']}/${user.name}" />

<properties>

В Листинге 5 определяются следующие динамические свойства и значения.

news_source

Кажется, что свойство news_source определяется дважды. При считывании свойства первое найденное значение проверяется на наличие каких-либо условий. Условие описывается с использованием атрибута if элемента <property>. Если условие существует, то оно должно быть истинным, чтобы в результате возвращалось значение. Иначе, затем тестируется следующее свойство news_source. Данный процесс продолжается до тех пор, пока выполняется условие, или пока не останется никаких свойств news_source, в этом случае выдается нулевой результат.

Условие, используемое в Листинге 5 проверяет равенство свойства job объекта user значению developer. Если условие выполняется, то в качестве результата выдается developer_news.myserver.com. Иначе, если свойство job равно architect, то в качестве результата выдается значение architect_news.myserver.com.

news_max_items

Свойство news_max_items имеет те же условия, что и news_source. В этом случае, если значение свойства job объекта user равно developer, то java.lang.Integer возвращается со значеним 5. Иначе, если значением свойства job является architect, то java.lang.Integer возвращается со значением 10.

greeting

Свойство greeting не имеет условий; однако, данное свойство демонстрирует возможность подстановки значений в строке. Для данного свойства в строку вставлены следующие три значения:

  • ${user.name}: помещает в строку имя пользователя.
  • ${news_max_items}: это значение свойства news_max_items. Свойства могут также ссылаться на другие свойства.
  • ${user.job}: помещает в строку должность пользователя.

resource_directory

Значение свойства resource_directory использует определенное системное свойство user.dir, наряду с именем пользователя, включенном в значение строки.

Обратите внимание, что файл свойств использует переменную, именуемую user. Она устанавливается приложением в контекст. Для совместного использования информации из приложения внутри файла свойств XML, небходимо хранить все ссылки в контексте общего пользования, как показано в Листинге 6. Метод getUserInfo1() возвращает объект Map, который затем хранится в контексте с ключом user.


Листинг 6. Установка значений в контекст из приложения
                
// обновляем текущий контекст текущим пользователем
properties.getContext().put("user", getUserInfo1()) ;

После сохранения Map в контексте, к нему можно обращаться во всем файле свойств, используя синтаксис ${user}. Вы можете вызывать все публичные методы объекта с помощью ${user.methodName()}. Можно также получить доступ к значениям в объекте Map, используя краткую форму ${user.propertyName}, эквивалентную вызову метода ${user.get('propertyName')}. В Листинге 7 переменная user устанавливается в контексте с Map, созданным методом getUserInfo1(). Все значения свойств извлекаются и выводятся на консоль. Все значения свойств генерируются с использованием текущего состояния user, установленного непосредственно перед получением свойств. После вывода значений на консоль, значение контекста user обновляется на значение Map, которое возвращается getUserInfo2(). Запрашиваются те же значения, что и раньше, но теперь вы получите результаты, отличные от значений свойств, поскольку теперь они задаются другим user.


Листинг 7. Код приложения для демонстрации динамических значений свойств
                
/**
 * @author cmeadows
 *
 * В данном примере наглядно демонстрируется использование HirixProperties,
 * где значения делаются динамическими, основываясь на состоянии приложения.
 * В данном примере текущий пользователь меняется во время выполнения.
 * После смены текущего пользователя извлекаются те же значения свойств,
 * но результаты будут другими.
 */
public class HirixExample {

   public static void main(String[] args) {
	   // Получаем URL из файла свойств
      URL propertiesURL = HirixExample.class.getClassLoader().
                          getResource("example2/properties.xml");
      try {

         // Создаём экземпляр объекта свойств
         HirixProperties properties = new HirixProperties() ;

         // Загружаем свойства как обычно
         properties.load( propertiesURL.openStream() ) ;

         // обновляем текущий контекст текущим пользователем
         properties.getContext().put("user", getUserInfo1()) ;

         // Получаем значения свойств для данного примера и выводим на консоль
         System.out.println( properties.get("news_source")) ;
         System.out.println( properties.get("news_max_items")) ;
         System.out.println( properties.getProperty("greeting")) ;
         System.out.println( "we will save your news in: " +
                              properties.getProperty("resource_directory")) ;

         // обновляем текущий контекст текущим пользователем
         properties.getContext().put("user", getUserInfo2()) ;

         // Получаем значения свойств для данного примера и выводим на консоль
         System.out.println( properties.get("news_source")) ;
         System.out.println( properties.get("news_max_items")) ;
         System.out.println( properties.getProperty("greeting")) ;
         System.out.println( "we will save your news in: " +
                              properties.getProperty("resource_directory")) ;

      } catch (IOException e) {
         // TODO автоматически сгенерированный блок catch
         e.printStackTrace();
      }
   }
   /**
    * Создаём пример пользователя-разработчика
    * @return
    */
   public static Map getUserInfo1 () {
      Map user = new HashMap() ;
      user.put("name", "Chad") ;
      user.put("job", "developer") ;
      return user;
   }
   /**
    * Создаём пример пользователя-архитектора
    * @return
    */
   public static Map getUserInfo2 () {
      Map user = new HashMap() ;
      user.put("name", "John") ;
      user.put("job", "architect") ;
      return user;
   }
}

В Листинге 8 показан реальный вывод выполнения кода приложения Листинга 7. Значения получены из файла свойств в Листинге 5 для двух различных экземпляров user. Можно видеть, как различные экземпляры user дают в результате различные значения, полученные из свойств. Строки 1-4 - это вывод, который использует объект Map, возвращаемый из getUserInfo1(), а строки 5-8 - это вывод при использовании объекта Map, возвращаемого из getUserInfo2().


Листинг 8. Вывод на консоль при выполнении кода приложения в Листинге 5
                
//1//   developer_news.myserver.com
//2//   5
//3//   Hello Chad we are retrieving 5 items for developer
//4//   we will save your news in:
        W:\workspace-callisto\dolphin\dolphin-hirix-example-properties/Chad
//5//   architect_news.myserver.com
//6//   10
//7//   Hello John we are retrieving 10 items for architect
//8//   we will save your news in:
        W:\workspace-callisto\dolphin\dolphin-hirix-example-properties/John



В начало


Использование свойств с созданием скрипта Groovy

Hierarchical Inherited Rule-Interpreted XML также позволяет вам включать динамический скрипт в файл свойств XML, что обеспечивает возможность создавать значения любого типа. Groovy является мощным скриптовым языком, который позволяет использовать Java (и не только) практически на полную мощность в качестве выражений (см. Ресурсы для получения дополнительной информации). В примере из Листинга 9 используется скрипт Groovy для создания объекта Map для свойства user1 и для создания фактического класса в свойстве user2.


Листинг 9. Файл свойств со скриптом Groovy
                
<!-- system['key'] эквивалентен System.getProperties.get("key") -->

<!-- Это эквивалентный файл свойств со свойствами, сгруппированными по условиям -->

<properties>

     <!-- Определяем объект Map для информации о пользователе.
          С помощью Groovy можно использовать здесь простое
          выражение для определения map и values.

          HirixProperties позволяет возвращать как объекты, так и строки. -->

   <property id="user1">
      <value>${groovy: [name:'Chad', job:'developer']}<value>
   </property>



   <!-- Определяем класс с помощью скрипта Groovy.
        Класс создаётся с помощью методов, которые будут совместимы
        с Map, используя доступ в стиле свойства. -->

   <property id="user2">
      <value>${groovy:
         class UserInfo {
            public getName() {
               return ("John") ;
            }
            public getJob() {
               return ("architect") ;
            }
         }
         return new UserInfo() ;}
      <value>
   </property>

</properties>

В Листинге 10 показано, как получить доступ к определенным значениям из вашего Java-кода, а результаты выводятся на консоль.


Листинг 10. Код приложения для обработки свойств
                
   ...
         // Получаем значения свойств для данного примера и выводим на консоль
         System.out.println( properties.get("user1")) ;
         System.out.println( properties.get("user2")) ;
   ...

В Листинге 11 показан вывод на консоль при выполнении кода приложения Листинга 10. Первая строка - это вывод объекта Map, а вторая строка является ссылкой на объект UserInfo.


Листинг 11. Вывод на консоль при выполнении кода приложения в Листинге 10
                
{name=Chad, job=developer}
UserInfo@63026302



В начало


Заключение

Поделитесь с другими...

digg Отправить на Digg
del.icio.us Отправить на del.icio.us
Slashdot Отправить на Slashdot!

Hierarchical Inherited Rule-Interpreted XML дает вам новый и мощный способ конфигурирования приложений. При использовании реализованных в данной технологии свойств Java, можно без труда применять мощную и усовершенствованную конструкцию свойств и при этом не испытывать проблем с совместимостью со стандартным объектом java.lang.Properties. Эта новая технология позволяет построить динамические, гибкие приложения, способные к быстрой адаптации к изменяющимся требованием и нуждам бизнеса.

В данной статье только поверхностно излагается потенциал применения технологии Hierarchical Inherited Rule-Interpreted XML и предоставляемых ей возможностей. В следующих статьях будет продемонстрировано использование других скриптовых языков, совместное использование контекста сервлета в Web-приложениях, построение модульных компонентов и использование на полную мощность динамической конфигурации XML.



Ресурсы

Научиться

Получить продукты и технологии
  • Hierarchical Inherited Rule-Interpreted XML: загрузите и начните работу с данной новой технологией.

  • Пробное ПО IBM: создайте свой следующий проект с помощью пробного ПО, доступного для загрузки прямо с developerWorks.


Обсудить


Об авторе

Чэд Медоуз (Chad Meadows) является ведущим инженером по повторному использованию в IBM Global Account. Он углубленно занимается разработкой стратегий систематического тиражирования и ресурсов многоразового использования во всей компании. Он работает в компании IBM в отделе информационных технологий с 1993 г. Г-н Медоуз также является рационализатором IBM (Innovation Catalyst), содействующим разработке и внедрению новых идей и технологий в компании.




Выскажите мнение об этой странице


Пожалуйста, найдите минутку и заполните форму, чтобы повысить уровень сервиса.



ДаНетНе знаю
 


 


12345
 


В начало


IBM обладает всеми авторскими правами касательно информации, расположенной на developerWorks. Использование информации приведенной на этом ресурсе без явного письменного разрешения от IBM или первоначального автора запрещены. Если Вы желаете использовать информацию с developerWorks, пожалуйста воспользуйтесь регистрационной формой для того, чтобы связаться с нами запрос на использование материалов developerWorks Россия.

    IBM в России Конфиденциальность Контакты