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

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

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

Применение семантических методик позволяет дать пользователям mashup-приложений возможность управлять сервисами, информацией и ее представлением

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

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

Обсудить

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


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

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


Новая форма ввода

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

Как будет работать форма

Перед тем, как приступить к чему-либо, хорошо бы понимать, что именно мы собираемся делать. Чтобы дать пользователю контроль, нам нужна форма, которая позволит ему вводить данные. Новая форма ввода фактически будет представлять собой несколько форм, собирающих информацию. (Конечно же, мы можем реализовать это в одной форме с помощью Ajax, но я оставлю это занятие для читателя в качестве упражнения.)

Форма будет выполнять следующие действия:

  1. Пользователь выбирает тип сервиса. Форма наполняется путем проверки подклассов класса Service.
  2. Пользователь выбирает сервис. Форма заполняется путем проверки экземпляров класса, выбранного на первом шаге.
  3. Пользователь вводит шаблон и выбирает, какие свойства нужно отображать. Эта форма состоит из сочетания свойств outputType выбранного сервиса и полей текстового ввода.

Итак, давайте приступим.

Перечисление типов сервисов

На первом шаге мы предоставляем форму, на которой перечисляются все соответствующие типы сервисов. Добавим следующий код к классу MashupClientServlet (см. листинг 12).


Листинг 12. Перечень типов сервисов
                    
...
public class MashupClientServlet 
             extends javax.servlet.http.HttpServlet 
             implements javax.servlet.Servlet {

   public MashupClientServlet() {
      super();
   }      

   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
      
      MashupOntologyReader reader = new MashupOntologyReader();
      
      response.getWriter().print("<html>");
      response.getWriter().print("<head></head>");
      response.getWriter().print("<body>");

      response.getWriter().print("<h1>The Mashup</h1>");
      
      response.getWriter().println(
              "<form action='MashupClientServlet' method='get'>");
      response.getWriter().print("<h1>Choose a sevice type</h1>");
      response.getWriter().print("<select name='serviceType'>");
      
      OntClass serviceClass = reader.getOnt()
                 .getOntClass("http://example.com/store#Service");
      for (ExtendedIterator i = serviceClass.listSubClasses();
              i.hasNext(); ) {
            OntClass thisClass = (OntClass)i.next();
            response.getWriter().print("<option value='"
                         +thisClass.getURI()+"'>"+
                         thisClass.getLocalName()+"</option>");
      }   
      response.getWriter().print("</select>");

      response.getWriter().println("<input type='submit' />");
      response.getWriter().print("</form>");
      
      response.getWriter().print("</body>");
      response.getWriter().print("</html>");
   }     
...

Форма ввода создается в методе doGet(). В данном случае мы создаем основу формы, после чего получаем ссылку на класс Service. После этого мы можем использовать метод listSubClasses() для получения ExtendedIterator подклассов. Мы можем вывести информацию о них, включая URI, который используется в качестве передаваемого значения, а также localName. (Чтобы сделать все более красиво, можно добавить метки для каждого из этих классов и впоследствии выводить именно их.)

В результате получаем форму, похожую на приведенную на рисунке 1.


Рисунок 1. Форма выбора типа
Форма выбора типа

У этой формы есть одна проблема. Вы можете заметить, что в форме выводится сервис Store, который является подклассом Service, и классы MappingService и NewsService, которые являются подклассами Service, но в ней нет ни одного подкласса класса Store, даже если они, по определению, являются подклассами Service.



В начало


Добавление рассуждений

Обозначенная здесь проблема не имеет отношения ни к вашему программному коду, ни к вашей онтологии. Проблема состоит в том, что при создании модели мы построили ее таким образом, что она просто считывает онтологию как она есть и не выполняет никаких рассуждений, за исключением интерпретации прямых конструкций RDF. Другими словами, модель понимает, что Bookstore является подклассом Store, но не видит, что так как Store является подклассом Service, bookstore является подклассом Service.

Чтобы сделать такую информацию (и аналогичную информацию, которая может относиться только к вашим свойствам, а не к стандартным свойствам OWL) доступной, при создании модели нам понадобится блок рассуждений. Для этого добавим приведенный ниже код к классу MashupOntologyReader (см. листинг 13).


Листинг 13. Добавление рассуждений
                    
...
public class MashupOntologyReader {

    private OntModel serviceOntModel;
       
    public MashupOntologyReader(){
       String source = "http://example.com/store";

       serviceOntModel =  
          ModelFactory.createOntologyModel(
                           OntModelSpec.OWL_MEM_MICRO_RULE_INF, null);
       serviceOntModel.getDocumentManager()
                 .addAltEntry(source, "file:c:/sw/stores.owl" );    
       serviceOntModel.read( source );
       
    }
...

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

Теперь, если обновить форму, видно, что все соответствующие подклассы находятся на своих местах, как показано на рисунке 2.


Рисунок 2. Все подклассы
Все подклассы

Однако теперь у нас есть другая проблема. Что за вариант "Nothing" и откуда он появился?



В начало


Исключение nothing

Эта проблема появилась в результате того, что блок рассуждений делает свою работу слишком хорошо. Так же, как каждый класс является подклассом owl:Thing, у каждого класса есть надкласс owl:Nothing, пустое множество экземпляров. Поэтому, когда мы говорим блоку рассуждений, что необходимо получить все подклассы, он просто делает это. Чтобы не смущать пользователей, мы можем указать на то, что некоторые варианты отображать не нужно (см. листинг 14):


Листинг 14. Исключение Nothing из списка вариантов
                    
....
      OntClass serviceClass = reader.getOnt()
                 .getOntClass("http://example.com/store#Service");
      for (ExtendedIterator i = serviceClass.listSubClasses();         
              i.hasNext(); ) {
            OntClass thisClass = (OntClass)i.next();
            if (!thisClass.getURI()
                 .equals("http://www.w3.org/2002/07/owl#Nothing")){
               response.getWriter().print("<option value='"
                         +thisClass.getURI()+"'>"+
                         thisClass.getLocalName()+"</option>");
            }
      }   

      response.getWriter().print("</select>");
...

Теперь результат должен быть похож на то, что мы ожидали, как видно из рисунка 3.


Рисунок 3. Окончательный набор типов сервисов
Окончательный набор типов сервисов


В начало


Перечисление сервисов

Когда пользователь отправляет форму, она возвращается методу doGet(), поскольку это указано в элементе form. Когда сервер получает этот запрос, он проверяет, передан ли параметр serviceType. Если его нет, он выводит исходную форму. С другой стороны, если он уже передан, мы должны быть готовы ко второму этапу формы (см. листинг 15).


Листинг15. Перечисление сервисов
                    
...
   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
      
      MashupOntologyReader reader = new MashupOntologyReader();
      
      response.getWriter().print("<html>");
      response.getWriter().print("<head></head>");
      response.getWriter().print("<body>");

      response.getWriter().print("<h1>The Mashup</h1>");
      
      String serviceType = request.getParameter("serviceType");
            
      if (serviceType == null) {
         response.getWriter().println(
              "<form action='MashupClientServlet' method='get'>");
...
         response.getWriter().print("</select>");
      } else {

         response.getWriter().println(
              "<form action='MashupClientServlet' method='get'>");

         Individual serviceTypeClass = 
              reader.getOnt().getIndividual(serviceType);
         String serviceTypeName = serviceTypeClass.getLocalName();
         
         Individual[] individuals = 
              reader.getIndividuals(serviceTypeName);
         
         response.getWriter().println(
              "<input type='hidden' value='"+serviceType+
                                      "' name='serviceType' />");

         
         response.getWriter().print("<p>Choose a service:</p>");
         response.getWriter().print("<select name=\"serviceURI\">");
         for (int i = 0; i < individuals.length; i++){
            Individual thisIndividual = individuals[i];
            if (thisIndividual != null){
               String id = thisIndividual.getURI();
               System.out.println("["+id+"]");
               String label = thisIndividual.getLocalName();
               System.out.println("["+label+"]");
               response.getWriter().print(
                  "<option value=\""+id+"\">"+label+"</option>");
            }
         }
         response.getWriter().print("</select>");
         
      }

        response.getWriter().println("<input type='submit' />");
        response.getWriter().print("</form>");
      
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
   }     
...

На втором этапе мы получаем ссылку на класс, представленный URI serviceType, после чего используем его localName для получения всех Individuals этого класса с помощью метода getIndividuals(), созданного нами в пятой части (см. раздел Ресурсы). Теперь мы можем создавать саму форму.

Начнем с создания скрытого поля, которое передает serviceType.

Создадим элемент select, отображающий элемент option, который снова использует URI в качестве значения и localName (или label, как вам больше нравится) как текст, видимый пользователю. Результат должен быть похож на представленный на рисунке 4.


Рисунок 4. Перечень сервисов
Перечень сервисов


В начало


Определение вывода

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


Листинг 16. Определение вывода
                    
...
   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
      
      MashupOntologyReader reader = new MashupOntologyReader();
      
...
      String serviceURI = request.getParameter("serviceURI");
            
      if (serviceType == null) {
...
      } else if (serviceURI == null){

         response.getWriter().println(
              "<form action='MashupClientServlet' method='get'>");
...
         response.getWriter().print("</select>");
         
      } else {

         response.getWriter().println(
            "<form action='MashupClientServlet' method='get'>");
         
         response.getWriter().println("<input type='hidden' value='"
                             +serviceType+"' name='serviceType' />");
         response.getWriter().println("<input type='hidden' value='"
                               +serviceURI+"' name='serviceURI' />");

         response.getWriter().println("<h2>Define your output</h2>");
         
         response.getWriter().println(
           "<p>Define a template and choose the data to go into it."+
           "For example, to create a link, you might create a "+
           "template of <p><a value='href'><value "+
           "/></a></p>.  From there, designate the order in "+
           "which you want properties to appear.</p>");
         
         response.getWriter().println("<textarea name='template' "+ 
           "rows='5' cols='80'></textarea>");
         
         System.out.println("serviceuri="+serviceURI);
         OntClass serviceClass = 
                 reader.getOnt().getOntClass(serviceType);
         Property outputProp = (Property)reader.getOnt()
              .getProperty("http://example.com/store#outputType");
         RDFNode outputPropVal = 
               serviceClass.getPropertyValue(outputProp);
         System.out.println("The service outputs items of type "
                                         +outputPropVal.toString());
          
     }

        response.getWriter().println("<input type='submit' />");
        response.getWriter().print("</form>");
      
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
   }     
...

Первая часть формы очень проста; это просто поле textarea, в которое пользователь может ввести шаблон, напоминающий те, которые мы использовали в этом проекте. После этого начинаются более сложные вещи. Прежде чем выводить свойства, нам нужно знать, какой класс мы ищем. Чтобы узнать это, получим ссылку на класс serviceType, и используем ее для получения свойства outputType.

That Property представляет собой класс, и у этого класса есть свои свойства.



В начало


Извлечение свойств

Теперь мы готовы извлечь свойства, но не имеет смысла включать все эти возможности в сервлет, особенно потому, что они очень похожи на то, что мы уже делали в классе MashupOntologyReader. А именно, создадим в этом классе новый метод под названием getAllProperties(), как показано в листинге 17.


Листинг 17. Метод getAllProperties()
...
public class MashupOntologyReader {
...
    public Vector getAllProperties(OntClass theClass){

        Vector properties = new Vector();
        
        String thisClassURI = theClass.getURI();
        
        for (ExtendedIterator i = theClass.listDeclaredProperties(); 
             i.hasNext(); ) {
               
            OntProperty thisProp = (OntProperty)i.next();
            Property labelProp = (Property)serviceOntModel.getProperty(
                        "http://www.w3.org/2000/01/rdf-schema#label");
            if (thisProp.hasProperty(labelProp)){
                System.out.println("Property: "+
                       thisProp.getProperty(labelProp).getLiteral());
            }
            if (thisProp.isObjectProperty()){
                   System.out.println(
                         "this bears further investigation: ");
            } else {
                   properties.add(thisProp);
            }
       }    
       return properties;
    }
...

Этот метод практически полностью идентичен созданному ранее методу showAllProperties(), за исключением того, что он возвращает Vector, который содержит все Property объекта. Мы можем использовать этот метод в сервлете.



В начало


Вывод свойств

Наша форма должна выполнять несколько задач. В дополнение к получению шаблона template пользователя, она должна не только перечислять свойства, но и дать пользователю возможность использования этих свойств и как атрибутов, и как элементов (см. листинг 18).


Листинг 18. Вывод свойств
                    
...
public class MashupClientServlet 
             extends javax.servlet.http.HttpServlet 
             implements javax.servlet.Servlet {

   public MashupClientServlet() {
      super();
   }      

   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
...
         OntClass serviceClass = 
                 reader.getOnt().getOntClass(serviceType);
         Property outputProp = (Property)reader.getOnt()
              .getProperty("http://example.com/store#outputType");
         RDFNode outputPropVal = 
               serviceClass.getPropertyValue(outputProp);
         System.out.println("The service outputs items of type "
                                         +outputPropVal.toString());
          
         OntClass returnObjectClass = reader.getOnt()
                              .getOntClass(outputPropVal.toString());
         Vector properties = 
                          reader.getAllProperties(returnObjectClass);

         
response.getWriter().println("<table><tr><th>Attribute"+
                 "<br />position</th><th>Element<br 
/>position</th>"+
                 "<th>Property name</th></tr>");
           
         for (int i = 0; i < properties.size(); i++) {
              String cleanPropName = 
                   ((Property)properties.elementAt(i)).getURI()
                                     .replaceAll("#", "_").toString()
                                     .replaceAll("http://", "_");
              response.getWriter().println("<tr><td><input "+
                   "type='text' size='2' name='attribute"+
                   cleanPropName+"' /></td>");
              response.getWriter().println("<td><input "+
                   "type='text' size='2' name='element"+
                   cleanPropName+"' /></td>");
              response.getWriter().print("<td>"+
               ((OntProperty)properties.elementAt(i))
                          .getLabel(null)+"</td></tr>");
        }
           
        response.getWriter().println("</table>");
          
     }

        response.getWriter().println("<input type='submit' />");
        response.getWriter().print("</form>");
      
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
   }     
...

Сначала форма получает ссылку на класс вывода и после этого вызывает getAllProperties() для получения Vector свойств этого класса. Теперь создадим основу таблицы HTML, в которой все это будет визуально организовано для пользователя.

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

Сделав это, мы можем создавать версии атрибута и элемента каждого текстового поля для каждого свойства. И, наконец, мы выводим метку, игнорируя возможность выбора между различными языками. (Конечно же, в рабочем приложении вам нужно будет либо сделать так, чтобы у всех свойств были метки, либо перехватывать ошибки, которые могут произойти в этот момент. Кроме того, вы, вероятно, пожелаете воспользоваться возможностью выбора языков, вместо того, чтобы игнорировать ее.) В итоге форма должна быть похожа на представленную на рисунке 5.


Рисунок 5. Форма свойств
Форма свойств


В начало


Создание окончательной формы

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


Листинг 19. Окончательная форма
                    
...
   protected void doGet(HttpServletRequest request, 
                        HttpServletResponse response) throws 
                                ServletException, IOException {
      
...
      String serviceType = request.getParameter("serviceType");
      String serviceURI = request.getParameter("serviceURI");
      String template = request.getParameter("template");
            
      if (serviceType == null) {
...
      } else if (template == null){
...
      } else {

        response.getWriter().println(
           "<form action='MashupClientServlet' method='post'>");
        response.getWriter().println(
           "<input type='hidden' value='"+serviceType+
           "' name='serviceType' />");
        response.getWriter().println(
           "<input type='hidden' value='"+serviceURI+
           "' name='serviceURI' />");
        response.getWriter().println(
           "<input type='hidden' value='"+
                template.replaceAll("<", "<")
                        .replaceAll("'", "'")
                        .replaceAll("\"", """)+
           "' name='template' />");

        OntClass serviceClass = 
                  reader.getOnt().getOntClass(serviceType);
        Property outputProp = (Property)reader.getOnt()
          .getProperty("http://example.com/store#outputType");
        RDFNode outputPropVal = 
                     serviceClass.getPropertyValue(outputProp);
          
        OntClass returnObjectClass = reader.getOnt()
                        .getOntClass(outputPropVal.toString());
        Vector properties = reader.getAllProperties(returnObjectClass);

        for (int i = 0; i < properties.size(); i++) {
           String cleanPropName = 
                ((Property)properties.elementAt(i)).getURI()
                     .replaceAll("#", "_").toString()
                     .replaceAll("http://", "_");
           response.getWriter().println(
              "<input type='hidden' name='attribute"+cleanPropName+
              "' value ='"+
              request.getParameter("attribute"+cleanPropName)+"'/>");
           response.getWriter().println(
              "<input type='hidden' name='element"+cleanPropName+
              "' value = '"+
              request.getParameter("element"+cleanPropName)+"'/>");
           }         

           response.getWriter().print("<p>Enter a keyword:</p>");
           response.getWriter().print(
                         "<input type='text' name='query' />");
      
        }

        response.getWriter().println("<input type='submit' />");
        response.getWriter().print("</form>");
      
        response.getWriter().print("</body>");
        response.getWriter().print("</html>");
   }     
...

Значения serviceType и serviceURI очень просты, но, поскольку шаблон выполнен в HTML, мы не можем просто выдать их в значения атрибутов элементов ввода, потому что браузер будет интерпретировать их как код. Поэтому, чтобы решить эту проблему, нам нужно заменить запрещенные символы сущностями, которые могут быть преобразованы обратно в символы, когда пользователь передаст форму.

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

И, наконец, создадим форму запроса.

Этот объемистый код в конечном итоге создает HTML, похожий на представленный в листинге 20.


Листинг 20. Получившаяся форма
                    
<html><head></head><body><h1>The 
Mashup</h1><form 
action='MashupClientServlet' method='post'>
<input type='hidden' value='http://example.com/store#Bookstore' 
name='serviceType' />
<input type='hidden' value='http://example.com/store#Amazon.com' 
name='serviceURI' />
<input type='hidden' value='<p><a 
value='href'><value /></a>, $<value />
</p>' 
name='template' />
<input type='hidden' name='attribute_example.com/store_itemPrice' 
value =''/>
<input type='hidden' name='element_example.com/store_itemPrice' 
value = '2'/>
<input type='hidden' name='attribute_example.com/store_itemDescription' 
value =''/>
<input type='hidden' name='element_example.com/store_itemDescription' 
value = '1'/>
<input type='hidden' name='attribute_example.com/store_itemDetailURL' 
value ='1'/>
<input type='hidden' name='element_example.com/store_itemDetailURL' 
value = ''/>
<p>Enter a keyword:</p><input type='text' name='query' 
/><input 
type='submit' />
</form></body></html>

Все, что вы увидите в браузере - это поле запроса, как показано на рисунке 6.


Рисунок 6. Результирующая форма запроса
Результирующая форма запроса

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



В начало



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

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