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

developerWorks Россия  >  XML | Information Management | Технология Java | Open source | SOA и Web-сервисы  >

Основы создания mashup-приложений - Web-сервисы и семантический Web: Часть 5. Смена Web-сервисов

Дайте пользователям mashup-приложений возможность выбора сервисов в вашем приложении

developerWorks
На предыдущую страницуСтраница 2 из 11 На предыдущую страницу

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

Обсудить

Исходные тексты примера


Выскажите мнение об этом учебном пособии

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


Общий обзор

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

Повторение пройденного: определение сервисов

К этому моменту у нас есть совсем немного кода, составляющего рабочее приложение, и множество понятий. В первой части мы создали базовое mashup-приложение. Пользователь вводит ключевое слово, а форма передает его сервлету. Сервлет передает ключевое слово любому из сервисов, определенных в произвольном классе Service. Результат работы каждого из этих сервисов обрабатывается на основе информации, предоставляемой в определении этого сервиса. Например, класс Service определяет сервис Yahoo! News следующим образом (см. листинг 1).


Листинг 1. Определение сервиса
                    
...
    Service thisService = new Service();
    Service subService = new Service();
            
    subService.name = "Technorati";
    subService.baseURL = 
       "http://api.technorati.com/cosmos?key=mydeveloperskey&url=";
    subService.template = "<span><value/></span>";
    subService.elementValues[0] = "inboundlinks";
    subService.elementValues[1] = "bogus";
    subService.attributeValues[0] = "thumbnail_url";
    subService.recordExp = "/tapi/document/result";

      
    thisService.name = "Yahoo! Search";
    thisService.baseURL =  "http://api.search.yahoo.com/NewsSear"+
      "chService/V1/newsSearch?appid=mashupid&type=all&query=";
    thisService.template = "<p><b><a 
value='href'><value/></a>"+
            "</b>: <value/> (Linked <subService/> 
times)</p>";
    thisService.elementValues[0] = "Title";
    thisService.elementValues[1] = "Summary";
    thisService.attributeValues[0] = "ClickUrl";
    thisService.recordExp = "/ResultSet/Result";
      
    thisService.subSvc = subService;
    thisService.filterExp = "ClickUrl";
...

Service определяет название и базовый URL для запросов REST. Когда вы делаете запрос, вы просто добавляете к концу адреса ключевое слово. Сервис также определяет выражение XPath, которое определяет место расположения отдельных записей в результате. Например, в этом случае выражение XPath /ResultSet/Result представляет каждую новую статью. И, наконец, сервис содержит информацию о том, как отображать результирующие данные. Шаблон представляет выводимый HTML, при этом значения элементов и атрибутов служат полями для подстановки, которые заменяются данными из выражений XPath, находящимися в массивах elementValues и attributeValues.

В этом случае вы также можете увидеть внедрение второго сервиса, представленного элементом subservice.



В начало


Повторение пройденного: украшения

Во второй части вы улучшили приложение таким образом, что теперь вместо того чтобы делать новый Web-запрос для каждого вызова сервиса - процесс, который может затянуться на несколько минут, если mashup обрабатывает много запросов, - вы начинаете кэшировать результаты запроса в базе данных XML с помощью новых возможностей pureXML системы DB2. Это позволяет вам перед тем, как mashup создаст новый запрос, проверить, есть ли такой запрос в базе данных.

Однако общая цель состоит в создании сервиса со встроенным интеллектом, чтобы пользователь мог запрашивать определенный "тип" данных, например, книгу, цену и так далее, а mashup понимал, как найти этот тип, независимо от того, какой сервис вы используете.

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

В четвертой части вы создали онтологию книжного магазина (bookstore), которая определяла концепты, которые можно найти в онлайновых магазинах, например, книгу (book), DVD, автора (author) и так далее. В этом руководстве вы начнете добавлять к созданной онтологии реальные данные.



В начало


Базовая онтология

Базовая онтология выглядит следующим образом (см. листинг 2).


Листинг 2. Базовая онтология
                    
<?xml version="1.0"?>
<!DOCTYPE rdf:RDF [
     <!ENTITY store  "http://example.com/stores#" >
     <!ENTITY owl  "http://www.w3.org/2002/07/owl#" >
     <!ENTITY xsd  "http://www.w3.org/2001/XMLSchema#" >
]>

<rdf:RDF
  xmlns     = "http://example.com/store#"
  xmlns:store = "http://example.com/store#"
  xml:base  = "http://example.com/store#"
  xmlns:owl = "http://www.w3.org/2002/07/owl#"
  xmlns:rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
  xmlns:rdfs= "http://www.w3.org/2000/01/rdf-schema#"
  xmlns:xsd = "http://www.w3.org/2001/XMLSchema#"
>

<owl:Ontology rdf:about="">
  <rdfs:comment>An example OWL ontology for Online Bookstores (The 
Ultimate Mashup: Part #4)</rdfs:comment>
  <rdfs:label>BookStore Ontology</rdfs:label>
</owl:Ontology>
  
<owl:Class rdf:ID="Service">
   <rdfs:label>Web Service</rdfs:label>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#endpoint" />
       <owl:minCardinality 
rdf:datatype="&xsd;nonNegativeInteger">1</owl:minCardinality>
     </owl:Restriction>
   </rdfs:subClassOf>
</owl:Class>
<owl:DatatypeProperty  rdf:ID="endpoint">
   <rdfs:domain rdf:resource="#Service"/>
   <rdfs:range rdf:resource="http://www.w3.org/2001/XMLSchema#anyURI"/>
</owl:DatatypeProperty>

<owl:Class rdf:ID="Store">
   <rdfs:subClassOf rdf:resource="#Service"/>
   <rdfs:label>Online Store</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="Bookstore">
   <rdfs:subClassOf rdf:resource="#Store"/>
   <rdfs:label>Bookstore</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="Product">
   <rdfs:label>Product sold at online store</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="Book">
   <rdfs:subClassOf rdf:resource="#Product"/>
   <rdfs:label>Book</rdfs:label>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#writtenBy" />
       <owl:minCardinality 
rdf:datatype="&xsd;nonNegativeInteger">1</owl:minCardinality>
     </owl:Restriction>
   </rdfs:subClassOf>
</owl:Class>

<owl:DatatypeProperty rdf:ID="title"> 
  <rdfs:domain rdf:resource="#Book"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>

<owl:Class rdf:ID="ISBN">
</owl:Class>
<owl:InverseFunctionalProperty  rdf:ID="isbn">
   <rdfs:domain rdf:resource="#ISBN"/>
   <rdfs:range rdf:resource="#Book"/>
</owl:InverseFunctionalProperty>

<owl:Class rdf:ID="Movie">
   <rdfs:subClassOf rdf:resource="#Product"/>
   <rdfs:label>Movie</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="Person">
   <rdfs:label>Person</rdfs:label>
</owl:Class>
<owl:DatatypeProperty rdf:ID="name"> 
  <rdfs:domain rdf:resource="#Person"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>

<owl:Class rdf:ID="Author">
   <rdfs:subClassOf rdf:resource="#Person"/>
   <rdfs:label>Author</rdfs:label>
   <rdfs:subClassOf>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#writerOf" />
       <owl:minCardinality 
rdf:datatype="&xsd;nonNegativeInteger">1</owl:minCardinality>
     </owl:Restriction>
   </rdfs:subClassOf>
</owl:Class>
<owl:Class rdf:ID="Writer">
   <owl:equivalentClass rdf:resource="#Author"/>
</owl:Class>


<owl:ObjectProperty rdf:ID="writtenBy"> 
  <rdfs:domain rdf:resource="#Book"/>
  <rdfs:range rdf:resource="#Author"/> 
</owl:ObjectProperty>
<owl:ObjectProperty rdf:ID="writerOf">
  <owl:inverseOf rdf:resource="#writtenBy"/>
</owl:ObjectProperty>
<owl:ObjectProperty rdf:ID="authorOf">
  <owl:equivalentProperty rdf:resource="#writerOf"/>
</owl:ObjectProperty>

<owl:Class rdf:ID="Director">
   <rdfs:subClassOf rdf:resource="#Person"/>
   <rdfs:label>Director</rdfs:label>
</owl:Class>

<owl:Class rdf:ID="GenreList" />
<owl:Class rdf:ID="Genre" />
<Genre rdf:ID="Fiction"/>
<Genre rdf:ID="Nonfiction"/>
<Genre rdf:ID="History"/>
<Genre rdf:ID="Philosophy"/>
<Genre rdf:ID="Memoir"/>

<owl:Class rdf:ID="BookGenre">
   <rdfs:subClassOf>
     <owl:AllDifferent rdf:about="#GenreList">
      <owl:distinctMembers rdf:parseType="Collection">
        <Genre rdf:about="#Fiction" />
        <Genre rdf:about="#Nonfiction" />
        <Genre rdf:about="#History" />
        <Genre rdf:about="#Philosophy" />
        <Genre rdf:about="#Memoir" />
      </owl:distinctMembers>
     </owl:AllDifferent>
   </rdfs:subClassOf>
</owl:Class>

<owl:SymmetricProperty rdf:ID="bundledWith">
  <rdfs:domain rdf:resource="#Product"/>
  <rdfs:range rdf:resource="#Product"/> 
</owl:SymmetricProperty>

<owl:TransitiveProperty rdf:ID="genreOf"> 
  <rdfs:domain rdf:resource="#Book"/>
  <rdfs:range rdf:resource="#BookGenre"/> 
</owl:TransitiveProperty>

<owl:Class rdf:ID="FictionBook">
   <owl:equivalentClass>
     <owl:Restriction>
       <owl:onProperty rdf:resource="#genreOf" />
     <owl:hasValue rdf:resource="#Fiction" />
     </owl:Restriction>
   </owl:equivalentClass>
</owl:Class>

<owl:Class rdf:ID="StockItem">
</owl:Class>
<owl:DatatypeProperty rdf:ID="itemPrice"> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;double"/> 
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="itemDescription"> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>
<owl:DatatypeProperty rdf:ID="itemDetailURL"> 
  <rdfs:domain rdf:resource="#StockItem"/>
  <rdfs:range rdf:resource="&xsd;string"/> 
</owl:DatatypeProperty>

<owl:ObjectProperty  rdf:ID="stockedProduct">
   <rdfs:domain rdf:resource="#StockItem"/>
   <rdfs:range rdf:resource="#Product"/>
</owl:ObjectProperty>

<owl:ObjectProperty  rdf:ID="stocks">
   <rdfs:domain rdf:resource="#Store"/>
   <rdfs:range rdf:resource="#StockItem"/>
</owl:ObjectProperty>
</rdf:RDF>

Мы не будем использовать в этом руководстве все определения, но нам важно знать структуру; в состав магазина Store входят товарные позиции StockItems, которыми могут быть экземпляры Book, Movie и т.п. Таким образом, мы можем определить общий концепт книги book, установить его автора, издательство и так далее, но цена и информация о доставке будет различна в зависимости от того, в каком магазине пользователь приобретает книгу.

Помните, что это всего лишь определения. Фактические данные состоят из индивидных концептов, или экземпляров каждого класса. Пример приведен в листинге 3.


Листинг 3. Индивидные концепты онтологии
                    
...
<Bookstore rdf:ID="Amazon.com">
    <endpoint>http://webservices.amazon.com/onca/xml</endpoint>
</Bookstore>

<Bookstore rdf:ID="BarnesAndNoble.com"/>

<Author rdf:ID="J_K_Rowling"/>

<Author rdf:ID="Joanne_Rowling">
    <owl:sameAs rdf:resource="#J_K_Rowling" />
</Author>
<Author rdf:ID="Fyodor_Dostoevsky"/>

<Book rdf:ID="Harry_Potter_and_the_Sorcerers_Stone">
    <writtenBy rdf:resource="#J_K_Rowling"/>
</Book>

<StockItem rdf:ID="Harry_Potter_and_the_Sorcerers_Stone_amazon">
   <itemPrice rdf:datatype="http://www.w3.org/2001/XMLSchema#double"
                                                >29.99</itemPrice>
   <itemDescription>Harry Potter and the Sorcerers 
                                       Stone</itemDescription>
   <itemDetailURL>http://www.amazonurlforbook</itemDetailURL>
   <stockedProduct 
            rdf:resource="#Harry_Potter_and_the_Sorcerers_Stone" />
</StockItem>

<Book rdf:ID="Crime_and_Punishment">
    <writtenBy rdf:resource="#Fyodor_Dostoevsky"/>
      <bundledWith 
          rdf:resource="#Harry_Potter_and_the_Sorcerers_Stone"/>
</Book>
...

Вы можете хранить эти индивидные концепты в отдельных файлах или в одном файле с определениями; важно только, чтобы при этом совпадали пространства имен.

В этом руководстве вы создадите индивидные концепты из данных, полученных из отдельных Web-сервисов.



В начало


Настройка

Это руководство предполагает, что у вас уже есть рабочая mashup-система, с кэшированием в базе данных DB2 или без него. Дополнительную информацию о настройке Tomcat и других компонентов можно найти в первых двух руководствах этой серии (см. раздел Ресурсы).

Кроме того, для исполнения кода, приведенного в этом руководстве, вам понадобится Jena API. Вы можете загрузить его с сайта http://jena.sourceforge.net/. Чтобы установить этот интерфейс, добавьте его файлы *.jar к пути ваших классов.

В качестве примера в этом руководстве используется интерфейс Web-сервиса Amazon. Чтобы этот код заработал, вам нужно получить собственный идентификатор разработчика и заменить им строчку нулей (000000000000000) в коде. Информацию о получении идентификатора разработчика можно найти на сайте http://www.amazon.com/aws.



В начало



На предыдущую страницуСтраница 2 из 11 На предыдущую страницу

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