Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Разработка веб-сервисов


Автор: tux 15.9.2005, 14:16
Предлагаю альтернативный способ разработки веб-сервисов в сравнении с тем, что предлагал Domestic Cat в статье http://forum.vingrad.ru/index.php?showtopic=42367.
1. Что нужно для работы
Нужен Axis (у меня версия 1.2.1), Xerces (2.4.0), Jakarta Ant, какой-нибудь веб-контейнер. Изначальная цель – сделать все удобным для разработки, поэтому организуем весь код аккуратно по каталогам, пишем скрипт для Ant, который выполняет всю работу от компиляции до сборки приложения.
2. Создаем структуру каталогов
У меня весь проект организован таким образом:
  • bin – каталог, куда будут складывать откомпилированные классы
  • generate/wsdl – каталог, куда будут складываться файлы описания веб-сервиса (wsdl)
  • lib – нужные библиотеки
  • src/java – исходный код веб-сервиса
  • src/xml – xml-файлы, необходимые для развертывания приложения
  • target – каталог, куда будет собираться war веб-приложения
В каталог lib копируем нужные библиотеки из lib дистрибутива axis. У меня каталог lib выглядит следующим образом:
Код

bash-3.00$ ls -l
итого 3244
-rw-r--r-- 1 dan users 33506   2005-06-15 11:28  axis-ant.jar
-rw-r--r-- 1 dan users 1604162 2005-06-15 11:44  axis.jar
-rw-r--r-- 1 dan users 71442   2005-06-15 11:28  commons-discovery-0.2.jar
-rw-r--r-- 1 dan users 38015   2005-06-15 11:28  commons-logging-1.0.4.jar
-rw-r--r-- 1 dan users 32071   2005-06-15 11:28  jaxrpc.jar
-rw-r--r-- 1 dan users 352668  2005-06-15 11:28  log4j-1.2.8.jar
-rw-r--r-- 1 dan users 941     2005-06-15 11:28  log4j.properties
-rw-r--r-- 1 dan users 19427   2005-06-15 11:28  saaj.jar
-rw-r--r-- 1 dan users 126771  2005-06-15 11:28  wsdl4j-1.5.1.jar
-rw-r--r-- 1 dan users 895813  2004-09-06 08:06  xerces-2.4.0.jar
-rw-r--r-- 1 dan users 123705  2004-09-06 08:06  xml-apis.jar

3. Написание сборщика проекта
В корневом каталоге проекта создаем файл build.xml для Jakarta Ant, который и будет заниматься сборкой проекта. У меня файл имеет следующий вид:
Код

<?xml version="1.0" encoding="UTF-8"?>
<project basedir="." default="all" name="WebService">

    <target name="init">
        <property environment="env"/>
        <property file="ant.properties"/>
        <property name="wsdl.generate.dir" value="generate/wsdl" />
        <property name="java.generate.dir" value="src/java" />
        <property name="class.dir" value="./bin" />
        <property name="java.src.dir" value="interfaces/java" />
        <property name="xml.src.dir" value="src/xml" />
        <property name="target.dir" value="target" />
        <property name="war.name" value="testing-remote.war" />
        <property name="war.target" value="${target.dir}/${war.name}" />
        <property name="java.home" value="${env.JAVA_HOME}" />
        <property name="lib.dir" value="lib" />

        <path id="webservices.path">
            <fileset dir="${lib.dir}">
                <include name="*.jar" />
            </fileset>
            <pathelement path="${class.dir}"/>
        </path>

        <mkdir dir="${class.dir}"/>
        <mkdir dir="${target.dir}"/>
    </target>

    <target name="define-tasks" depends="init">
        <taskdef resource="axis-tasks.properties" classpathref="webservices.path" />
    </target>

    <target name="compile" depends="init">
        <javac destdir="${class.dir}" classpathref="webservices.path" debug="on">
            <src path="${java.generate.dir}"/>
            <include name="**/*.java"/>
        </javac>
    </target>

    <target name="generate-wsdd" depends="init, define-tasks">
        <antcall target="compile"/>

        <!-- Интерфейс TestWorker -->
        <property name="test.worker.service" value="TestWorker" />
        <axis-java2wsdl 
            classname="ru.esstu.testing.remote.TestWorker"
            classpathref="webservices.path"
            location="http://localhost:8080/${webapp.name}/services/${test.worker.service}"
            namespace="urn:${test.worker.service}"
            output="${wsdl.generate.dir}/${test.worker.service}.wsdl"
        />

        <axis-wsdl2java 
                output="${java.generate.dir}"
                verbose="on" 
                skeletondeploy="on" 
                serverside="on" 
                helpergen="on" 
                url="${wsdl.generate.dir}/${test.worker.service}.wsdl"
                implementationclassname="ru.esstu.testing.remote.TestWorker">
            <mapping
                  namespace="urn:${test.worker.service}"
                  package="ru.esstu.testing.remote.worker.stub" />
        </axis-wsdl2java>

        <echo message="Generating server deployer..." />

        <java classname="org.apache.axis.utils.Admin" 
            fork="true" dir="."
            classpathref="webservices.path">
            <arg value="server" />
            <arg
                value="${java.generate.dir}/ru/esstu/testing/remote/worker/stub/deploy.wsdd"
            />
        </java>
    </target>

    <target name="clean" depends="init">
        <delete file="${war.target}"/>
        <delete dir="${class.dir}"/>
    </target>

    <target name="pack-it" depends="init, generate-wsdd">
        <antcall target="compile"/>
        <delete file="${war.target}"/>
        <war destfile="${war.target}" webxml="${xml.src.dir}/web.xml">
            <lib dir="${lib.dir}">
                <include name="*.jar" />
            </lib>
            <classes dir="${class.dir}"/>
            <webinf dir=".">
                <include name="*.wsdd" />
            </webinf>
        </war>
        <delete file="server-config.wsdd"/>
    </target>

    <target name="release">
        <antcall target="clean" />
        <antcall target="compile-non-debug"/>
        <antcall target="pack-it"/>
    </target>

    <target depends="pack-it"name="all">
    </target>

</project>

Здесь цель init определяет набор используемых свойств. Цель define-tasks определяет тэги Axis, которые можно использовать внутри скриптов Ant, для того чтобы они работали нужна библиотека axis-ant.jar, входящая в состав Axis. В результате выполнения taskdef определятся три тэга – axis-java2wsdl, axis-wsdl2java и axis-admin, которые можно использовать для генерации разных нужных файликов. Цель compile используется для компиляции исходных и сгенерированных классов. Цель pack-it собирает все, что сгенерировано и написано в веб-приложение.
4. Процедура разработки веб-сервиса
Для того, чтобы было понятно что происходит в цели generate-wsdd опишу выбранную процедуру разработки. Описана она в документации по Axis и включает в себя следующие этапы:
  • пишем класс, который нужно будет сделать веб-сервисом. Сигнатуры публичных методов будут определять интерфейс веб-сервиса
  • из класса генерируем wsdl-документ, описывающий веб-сервис
  • из wsdl-документа генерируем серверные и клиентские заглушки и интерфейсы, а также дескрипторы развертывания веб-сервиса
  • генерируем из полученных дескрипторов серверный дескриптор развертывания веб-сервисов
  • собираем веб-приложение и деплоим его на веб-контейнере
Пункты 2-5 здесь выполняются build.xml.
Тэг axis-java2wsdl генерирует документ WSDL. В тэге определены такие атрибуты: classname – класс, для которого генерируется WSDL, classpathref – ссылка на переменную описания class-path в цели init, location – местоположение веб-сервиса, namespace – пространство имен, в котором находится веб-сервис и, наконец, output – файл WSDL, который должен получиться. Для генерации тэг испольет откомпилированный класс, поэтому компиляция в проекте вызывается дважды – перед генерацией WSDL (генерация должна основываться на актуальной информации) и перед сборкой веб-приложения.
Тэг axis-wsdl2java генерирует заглушки, интерфейсы и дескрипторы развертывания. Атрибуты означают следующее: output – каталог, куда будут генерироваться файлы, skeletondeploy, serverside, helpergen определяют что имеенно будет сгенерировано, url – ссылка на WSDL-файл, используемые для генерации, implementationclassname – имя класса реализации вебсервиса. На последнем остановлюсь подробнее. Если задать этот атрибут, Axis не будет перегенерировать класс реализации, соответственно, в противном случае ситуация чревата потерей изменений в классе. Тэг mapping внутри axis-wsdl2java определяет как пространства имен отражены на пакеты Java и, следовательно, то, в каком пакете окажутся сгенерированные файлы.
Далее запускается класс org.apache.axis.utils.Admin, который использует дескриптор развертывания deploy.wsdd для создания серверного дескриптора и который по какой-то причине не описан в документации. Ему передаются следующие параметры: «server» говорит о необходимости генерации серверного дескриптора, следующий далее дескриптор веб-сервиса используется для регистрации веб-сервиса. Если приложение включает в себя несколько веб-сервисов, то в существующий серверный дескриптор сведения о новых веб-сервисах будут добавлены.
К сожалению, поскольку классы вебсервисов нельзя указать пачкой, придется конструкцию в цели generate-wsdd выполнять для каждого класса реализации веб-сервиса.
5. Выполняем всё вместе
Пишем класс, который и будет веб-сервисом. Начнем с простого класса, который определяет интерфейс веб-сервиса. В дальнейшем методы в класс можно безболезненно добавлять.
Код

package ru.esstu.testing.remote;
public class TestWorker {

    public java.lang.String[] getTestNameList() {
        return null;
    }

}

Запускаем Jakarta Ant в корневом каталоге проекта. В результате получаем в пакете ru.esstu.testing.remote.worker.stub такой набор файлов:
Код

bash-3.00$ ls -l 
итого 40
-rw-r--r--  1 dan users 1621 2005-09-15 18:58 deploy.wsdd
-rw-r--r--  1 dan users  331 2005-09-15 18:58 TestWorker.java
-rw-r--r--  1 dan users  574 2005-09-15 18:58 TestWorkerService.java
-rw-r--r--  1 dan users 5337 2005-09-15 18:58 TestWorkerServiceLocator.java
-rw-r--r--  1 dan users 2296 2005-09-15 18:58 TestWorkerSoapBindingSkeleton.java
-rw-r--r--  1 dan users 8494 2005-09-15 18:58 TestWorkerSoapBindingStub.java
-rw-r--r--  1 dan users  670 2005-09-15 18:58 undeploy.wsdd

В каталоге generate/wsdl файл RemoteWorker.wsdl, в каталоге target веб-приложение в файле testing-remote.war, которое можно развернуть на веб-контейнере. Однако, пока у нас нет реализации вебсервиса. В процессе выполнения build.xml Axis сгенерировал в том числе и новый класс реализации. Пишем в нем, например, следующее:
Код

package ru.esstu.testing.remote;
public class TestWorker implements ru.esstu.testing.remote.worker.stub.TestWorker{

    public java.lang.String[] getTestNameList() throws java.rmi.RemoteException {
        return new String[] { "Hello", "I'm the walrus" };
    }

}

и пересобираем проект. Теперь веб-приложение действительно можно развернуть куда надо.
Теперь пишем клиент чтобы проверить как работает конструкция.
Код

package ru.esstu.testing.remote.client;

import java.net.URL;

import javax.xml.namespace.QName;
import javax.xml.rpc.Service;
import javax.xml.rpc.ServiceFactory;

import ru.esstu.testing.remote.worker.stub.TestWorker;

public class TestWorkerClient {

    public static void main(String[] args) throws Exception {
        URL urlWsdl = new URL("http://localhost:8080/testing-remote/services/TestWorker?wsdl");
        String nameSpaceUri = "urn:TestWorker";
        String serviceName = "TestWorkerService";
        String portName = "TestWorker";
        
        ServiceFactory factory =ServiceFactory.newInstance();
        Service service = factory.createService(urlWsdl, new QName(nameSpaceUri, serviceName));
        TestWorker twService = 
            (TestWorker) service.getPort(
                    new QName(nameSpaceUri, portName),TestWorker.class);
        String[] strList = twService.getTestNameList();
        for (int i=0; i<strList.length; i++) {
            System.out.println(strList[i]);
        }
    }
}

Результатом работы клиента должна быть пара нужных строк на экране.
Несмотря на относительную сложность, IMHO, способ обладает большей гибкостью в сравнении со способом, предложенным уважаемым Domestic Cat.

Автор: smbd 23.1.2006, 14:28
Гм, немного припозднился...

Тут пара вопрсоов появилась.

1) откуда берутся файлы web.xml (прежде всего! без него war не выполняется), server-config.wsdd (тоже непонятно). Просто web.xml у меня нет в принципе, а server-config.wsdd создаётся, но непонятно, кем, и главное, зачем.

2) вызов Wsdl2java создаёт кучу "заглушек". В том числе и интерфейс, который основан на моём классе, переданном Java2wsdl, и класс реализации web сервиса, наследующий от этого интерфейса. Нельзя ли как-то автоматизировать это дело так, чтоб мой изначальный класс (по которому строится) .wsdl файл, и был тем, кто реализует web сервис? Хотя с другой стороны, он должен наследовать интерфес, который ещё не сгенерирован. Криво как-то получается. Или всё же я недопонимаю?

Спасибо заранее!

P.S. если имеет значение, Axis у меня 1.3

Автор: tux 24.1.2006, 03:39
Цитата(smbd @ 23.1.2006, 19:28 Найти цитируемый пост)

Гм, немного припозднился...

Действительно smile И я уже многое забыл поскольку постоянно с веб-сервисами не работаю.

Ну, значится, по порядку.

1. web.xml придется написать ручками. В общем-то для Axis от приложения к приложению мало изменяется, я его приводить не стал. Должен быть примерно таким:
Код

<?xml version="1.0" encoding="ISO-8859-1"?>

<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>
    <display-name>Apache-Axis</display-name>

    <listener>
        <listener-class>
            org.apache.axis.transport.http.AxisHTTPSessionListener
        </listener-class>
    </listener>
    
    <servlet>
        <servlet-name>AxisServlet</servlet-name>
        <display-name>Apache-Axis Servlet</display-name>
        <servlet-class>
            org.apache.axis.transport.http.AxisServlet
        </servlet-class>
    </servlet>

    <servlet>
        <servlet-name>AdminServlet</servlet-name>
        <display-name>Axis Admin Servlet</display-name>
        <servlet-class>
            org.apache.axis.transport.http.AdminServlet
        </servlet-class>
        <load-on-startup>100</load-on-startup>
    </servlet>

    <servlet>
        <servlet-name>SOAPMonitorService</servlet-name>
        <display-name>SOAPMonitorService</display-name>
        <servlet-class>
            org.apache.axis.monitor.SOAPMonitorService
        </servlet-class>
        <init-param>
            <param-name>SOAPMonitorPort</param-name>
            <param-value>5001</param-value>
        </init-param>
        <load-on-startup>100</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>AxisServlet</servlet-name>
        <url-pattern>/servlet/AxisServlet</url-pattern>
    </servlet-mapping>
    
    <servlet-mapping>
        <servlet-name>AxisServlet</servlet-name>
        <url-pattern>*.jws</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>AxisServlet</servlet-name>
        <url-pattern>/services/*</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>SOAPMonitorService</servlet-name>
        <url-pattern>/SOAPMonitor</url-pattern>
    </servlet-mapping>

    <servlet-mapping>
        <servlet-name>AdminServlet</servlet-name>
        <url-pattern>/servlet/AdminServlet</url-pattern>
    </servlet-mapping>

    <session-config>
        <!-- Default to 5 minute session timeouts -->
        <session-timeout>5</session-timeout>
    </session-config>

    <mime-mapping>
        <extension>wsdl</extension>
        <mime-type>text/xml</mime-type>
    </mime-mapping>

    <mime-mapping>
        <extension>xsd</extension>
        <mime-type>text/xml</mime-type>
    </mime-mapping>

    <welcome-file-list id="WelcomeFileList">
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.jws</welcome-file>
    </welcome-file-list>

</web-app>


2. server-config.wsdd генерится вызовом класса org.apache.axis.utils.Admin. А потом удаляется в цели pack-it после того, как упаковывается в war. Поэтому наверное и не понятно откуда он берется. smile

3. Насчет возможности использования исходного класса как реализации веб-сервиса. Согласен, довольно криво получается, но когда я веб-сервисами занимался, другого способа не нашел. Возможно он есть, а может быть и нет, ничего точно утверждать не могу. Что навскидку приходит в голову - использовать паттерн Delegate. С другой стороны, интерфейс веб-сервиса ведь проектируется один раз и генерация класса реализации не должна быть проблемой.

Автор: YuG 20.2.2006, 17:30
2tux:
Огромное спасибо за такую подробную инструкцию!
Просто мега-спасибо!!!

Автор: Codename 5.4.2006, 07:43
Да действительно классная инструкция. Только вот у меня почему-то war-файл из Tomcat не запускается с чем это может быть связано?

Автор: tux 5.4.2006, 07:59
Что Tomcat при этом сообщает?

Автор: Codename 5.4.2006, 09:05
Сую war файл в weapps, захожу через менеджер и получаю

HTTP Status 404 - /testing-remote/
type Status report
message /testing-remote/
description The requested resource (/testing-remote/) is not available.
Apache Tomcat/5.0.28


Автор: tux 5.4.2006, 09:14
Цитата(Codename @ 5.4.2006, 14:05 Найти цитируемый пост)
Сую war файл в weapps, захожу через менеджер и получаю

HTTP Status 404 - /testing-remote/
type Status report
message /testing-remote/
description The requested resource (/testing-remote/) is not available.
Apache Tomcat/5.0.28

Это-то понятно, это уже следствие - приложение не развернулось. А что Tomcat выдает в консоль или логи касательно testing-remote?

Автор: Codename 5.4.2006, 10:05
War-файл он распечатывает, а логах пишет следующее:

- Installing web application at context path /testing-remote from URL file:C:/Program Files/Apache Software Foundation/Tomcat 5.0/webapps/testing-remote
- End event threw exception
java.lang.reflect.InvocationTargetException
at sun.reflect.GeneratedMethodAccessor46.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.commons.beanutils.MethodUtils.invokeMethod(MethodUtils.java:216)
at org.apache.commons.digester.CallMethodRule.end(CallMethodRule.java:505)
at org.apache.commons.digester.Rule.end(Rule.java:276)
at org.apache.commons.digester.Digester.endElement(Digester.java:1058)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endNamespaceScope(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.commons.digester.Digester.parse(Digester.java:1548)
at org.apache.catalina.startup.ContextConfig.applicationConfig(ContextConfig.java:263)
at org.apache.catalina.startup.ContextConfig.start(ContextConfig.java:624)
at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:216)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4290)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:823)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:807)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:595)
at org.apache.catalina.core.StandardHostDeployer.install(StandardHostDeployer.java:277)
at org.apache.catalina.core.StandardHost.install(StandardHost.java:832)
at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:625)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:431)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:983)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:349)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1091)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:789)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1083)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:478)
at org.apache.catalina.core.StandardService.start(StandardService.java:480)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:2313)
at org.apache.catalina.startup.Catalina.start(Catalina.java:556)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:287)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:425)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.commons.launcher.ChildMain.run(ChildMain.java:269)
Caused by: java.lang.IllegalArgumentException: Servlet mapping specifies an unknown servlet name BasicService
at org.apache.catalina.core.StandardContext.addServletMapping(StandardContext.java:2234)
at org.apache.catalina.core.StandardContext.addServletMapping(StandardContext.java:2214)
... 52 more
- Parse error in application web.xml
java.lang.IllegalArgumentException: Servlet mapping specifies an unknown servlet name BasicService
at org.apache.commons.digester.Digester.createSAXException(Digester.java:2540)
at org.apache.commons.digester.Digester.createSAXException(Digester.java:2566)
at org.apache.commons.digester.Digester.endElement(Digester.java:1061)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.endElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endNamespaceScope(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.handleEndElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.dtd.XMLDTDValidator.endElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanEndElement(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source)
at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(Unknown Source)
at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(Unknown Source)
at org.apache.commons.digester.Digester.parse(Digester.java:1548)
at org.apache.catalina.startup.ContextConfig.applicationConfig(ContextConfig.java:263)
at org.apache.catalina.startup.ContextConfig.start(ContextConfig.java:624)
at org.apache.catalina.startup.ContextConfig.lifecycleEvent(ContextConfig.java:216)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:4290)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:823)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:807)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:595)
at org.apache.catalina.core.StandardHostDeployer.install(StandardHostDeployer.java:277)
at org.apache.catalina.core.StandardHost.install(StandardHost.java:832)
at org.apache.catalina.startup.HostConfig.deployWARs(HostConfig.java:625)
at org.apache.catalina.startup.HostConfig.deployApps(HostConfig.java:431)
at org.apache.catalina.startup.HostConfig.start(HostConfig.java:983)
at org.apache.catalina.startup.HostConfig.lifecycleEvent(HostConfig.java:349)
at org.apache.catalina.util.LifecycleSupport.fireLifecycleEvent(LifecycleSupport.java:119)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1091)
at org.apache.catalina.core.StandardHost.start(StandardHost.java:789)
at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1083)
at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:478)
at org.apache.catalina.core.StandardService.start(StandardService.java:480)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:2313)
at org.apache.catalina.startup.Catalina.start(Catalina.java:556)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:287)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:425)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.commons.launcher.ChildMain.run(ChildMain.java:269)
Добавлено @ 10:06
да, еще не дописал

- Occurred at line 46 column 23
- Marking this application unavailable due to previous error(s)
- Error getConfigured
- Context startup failed due to previous errors

Автор: tux 5.4.2006, 10:12
Удали из web.xml вот этот фрагмент, все должно заработать.
Код

<servlet-mapping>
    <servlet-name>BasicService</servlet-name>
    <url-pattern>/service/BasicService</url-pattern>
</servlet-mapping>

Автор: Codename 5.4.2006, 11:50
Да, пошел как надо. А как насчет работы с базами данных. Если у меня скажем есть прога, которая работает с базой через hibernate, то возможно ли ее сделать веб-сервисом, который бы проверял наличие объекта в базе. То бишь реально ли, что бы клиент называл, что хочет найти, а веб-сервис делал всю грязную работу: рылся в базе данных и выводил результат?
Если да, то как засунуть методы создания и поиска объекта?

Автор: tux 5.4.2006, 12:12
Цитата(Codename @ 5.4.2006, 16:50 Найти цитируемый пост)
Да, пошел как надо. А как насчет работы с базами данных. Если у меня скажем есть прога, которая работает с базой через hibernate, то возможно ли ее сделать веб-сервисом, который бы проверял наличие объекта в базе. То бишь реально ли, что бы клиент называл, что хочет найти, а веб-сервис делал всю грязную работу: рылся в базе данных и выводил результат?
Если да, то как засунуть методы создания и поиска объекта?

Реально, конечно. Определяешь методы сервиса какие тебе нужно для создания и поиска объекта, реализуешь класс сервиса, в котором работаешь с hibernate. Вот, собственно, и все. Только учитывай, что в качестве параметров и возвращаемого результата методов могут быть только определенный набор типов данных (подробности в документации к Axis), так просто любой Java-класс передать не удастся. Если нужны все-таки сложные типы данных, то рекомендовал бы Hessian или Burlap (если конечно нет жесткого требования делать на Axis).

Автор: JUncle 15.4.2006, 10:47
Прочитал обе части данной темы. Действительно, тема очень важная.
Возник вопрос.
А вот если есть необходимость связать .NET клиента с Java сервером (обмениваются уведомлениями и не очень сложными данными - с легкостью приводимыми, скажем, к текстовому виду).
Причем подключение к серверу скорее всего, только http (в принципе, полагаю, что сервер может подключиться к клиенту и каким то иным способом), а клиента необходимо уведомлять о наступлении событий в сервере в некоторые недетерминированные моменты времени.
Подскажите пожалуйста, возможно ли это, и если да - то какие средства лучше использовать (и если можно, ссылки).
PS: мы бы конечно какой-нибудь велосипед и придумали бы, но хотелось бы все сделать красивым и общепринятым методом.

Автор: tux 15.4.2006, 16:03
В MSDN описываются способы взаимодействия .NET и J2EE, может быть поможет - http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnpag/html/jdni.asp.

Автор: JUncle 16.4.2006, 10:52
Благодарю. 

Автор: Stampede 19.4.2006, 23:02
Цитата(JUncle @  15.4.2006,  10:47 Найти цитируемый пост)
Причем подключение к серверу скорее всего, только http (в принципе, полагаю, что сервер может подключиться к клиенту и каким то иным способом), а клиента необходимо уведомлять о наступлении событий в сервере в некоторые недетерминированные моменты времени.


Уведомление (callback) HTTP клиентов о серверных событиях - это вообще давняя и больная тема. Решения существуют, но достаточно нетривиальные. Хотя сама по себе идея достаточно простая:

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

Задача приемной стороны - слушать канал и интерпретировать поступающие сообщения. В браузере это можно сделать посредством JavaScript объекта HttpXMLRequest (который вовсю используется для разработки AJAX приложений).

Если клиент не браузерный, то принцип остается все равно тот же, открывать HTTP соединение, слушать, интерпретировать и предпринимать какие-то действия. Вот тут я собрал ссылки на ряд ресурсов. в которых обсуждаются детали транспорта, серверного и клиентского программирования:

http://www.bluishcoder.co.nz/2005/11/more-on-ajax-and-server-push.html;
http://www.javaworld.com/jw-03-2000/jw-03-pushlet-p4.html (статья аж от 2000-го года, но при этом удивительно актуальная!);

Ну и там далее по ссылкам.

Теперь возвращаясь к теме взаимодействия Java сервера и .NET слиента. Поскольку никакой AXIS или SOAP не поможет организовать уведомление клиента штатными средствами, плюс учитывая, что формат данных, как ты говоришь, достаточно простой, то я бы на твоем месте разработал свой простенький XML-протокольчик, и взяв за основу описанный выше метод коммуникации наваял бы фреймворк для асинхронного двустороннего клиент-серверного взаимодействия.

Да, а в части сериализации объектов в XML формат, я бы воспользовался чем-нибудь типа http://xstream.codehaus.org/ или http://www.caucho.com/burlap/, тем более что для XStream и Hessian существуют порты на .NET:

http://www.jroller.com/page/CoBraLorD/20050427
http://www.caucho.com/hessian/ 

Автор: JUncle 27.4.2006, 20:56
Stampede, большое спасибо за такой развернутый ответ! То, что нужно!
(эхх... прав мало - плюс бы дать...  smile ).  

Автор: tux 28.4.2006, 02:59
Цитата(JUncle @  28.4.2006,  01:56 Найти цитируемый пост)
(эхх... прав мало - плюс бы дать...  smile ).  

Не проблема, дадим. 

Автор: Aazmandius 28.8.2006, 16:22
Вот собрал вышеприведенный пример, долго воевал с различными версиями библиотек, наконец-то нормально скомпилилось и отдеплоилось... Но когда попытался приконнектиться клиентом, получил вот это:
Код

Exception in thread "main" javax.xml.rpc.ServiceException: Only interfaces may be used for the proxy class argument
    at org.apache.axis.client.Service.getPort(Service.java:417)
    at org.apache.axis.client.Service.getPort(Service.java:324)

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

TestWorker twService =  (TestWorker) service.getPort(new QName(portName),TestWorker.class);


 smile забыл интерфейс проимплементить... 

Автор: Aazmandius 28.8.2006, 16:58
Теперь другая проблема - метод, который должен вернуть строку (наше любимое "Превед, мир!" smile ) возвращает null smile И никаких эксепшнов, все чисто...

Автор: Aazmandius 29.8.2006, 19:54
Зато по методу уважаемого Domestic Cat все работает великолепно =) Хотя хотелось бы конечно понять причину этого null в предыдущем случае...

Автор: y3u 10.9.2006, 16:39
а нет такой же инструкции по работе с вебсервисами на JBoss?  smile 
Уж больно там мануал сухой и не везде понятный. Вот, к примеру как сам сервис поднять я разобрался, а вот клиента к нему сделать не получилось (я пробвал RPC)  smile ... 

Автор: onsh76 2.10.2006, 10:51
[QUOTE=Stampede,19.4.2006,  23:02]
Цитата(JUncle @  15.4.2006,  10:47 Найти цитируемый пост)

Да, а в части сериализации объектов в XML формат, я бы воспользовался чем-нибудь типа http://xstream.codehaus.org/ или http://www.caucho.com/burlap/, тем более что для XStream и Hessian существуют порты на .NET:

Я согласен со Стампидом - веб сервис с Hessian/Burlap имплементацией просто песня, минимум кода и никаких плясок с бубном.  Испытал на своем проекте, рекомендую...

У меня вопрос к почтенной публике:
Коллеги, скажите, кому довелось поработать с Axis2? Меня интересует, тема асинхронных вызовов... 
Никак AJAX опять прикручивать надо? Нет наверное в мире чудес...   smile 
Проясните, заранее спасибо!

Автор: Stampede 2.10.2006, 19:11
onsh76,  а посмотри на http://labs.jboss.com/portal/jbossremoting

Судя по описанию, очень толковая и давно напрашивавшаяся штука: универсальный ремоутинг с конфигурируемым транспортом, подтыкаемыми сериализаторами, асинхронными вызовами, коллбаками (callbacks), интеграцией с JMX и т. д. и т. п.

Может поставляться изолированно, весит немного.

Очень интересно было бы услышать впечатления от использования в реальном проекте.

Автор: Slanix 11.10.2006, 15:36
Всем, доброго времечки.А вот такая проблемка. 
Есть Web service (AXIS 1.3, doc/literal) и java клиент. Всё прекрасно работает.
Потребовалось написать .NET клиента. Хорошо, написали запускаем. В итоге получем.
При обращеннии Net клиента SOAP сообщения ходят, но в качестве респонса всегда null (хотя ответ есть).
После такого обращения java клиент не работает, а в частности посылает реквест, а в ответ эксепшн:
org.xml.sax.SAXException: SimpleDeserializer encountered a child element, which is NOT expected, in something it was trying to deserialize.
Спасает только перезапуск приложения.

Автор: seth 8.12.2006, 16:39
В чем отличия между например POJO и AXIOM?

Автор: tux 8.12.2006, 16:58
Цитата(seth @  8.12.2006,  16:39 Найти цитируемый пост)
В чем отличия между например POJO и AXIOM? 

Во всем. У них нет совершенно ничего общего.

Автор: seth 8.12.2006, 18:23
Ну а в двух словах?

Автор: tux 8.12.2006, 18:41
POJO (Plain Old Java Object) - абревиатура, обозначающая простые классы Java, на которые не налагается никаких ограничений - они не реализуют никаких интерфейсов, к ним не предъявляется никаких требований, просто классы и все.
AXIOM - объектная модель представления XML-данных, аналогичная различным DOM-моделям. Разрабатывалась для Axis 2, но сейчас вроде бы отдельный проект.
Между POJO и AXIOM нет никакой связи, поэтому об отличиях или сходствах говорить как-то странно.

Автор: rrrookie 18.1.2007, 11:30
Я немного отойду от актуалЬных обсуждений... 
 У меня вопрос по субй...

РеалЬная ситуация с веб сервисами... 

Например у нас естЬ метод : 

Код

        public  lv.mebius.ws.xsd.GetPersonByNameResponseDocument getPersonByName
                  (
          lv.mebius.ws.xsd.GetPersonByNameDocument param0
          )
         
           {
            GetPersonByNameResponseDocument gpbnr = GetPersonByNameResponseDocument.Factory.newInstance();
            
            CallableStatement cs = null;
            ResultSet rs = null;
            Connection conn = null;
            
            Person personData = null;
            ArrayList personList = new ArrayList();
            
            
            String name = param0.getGetPersonByName().getParam0();
            
            try {
                conn = lv.mebius.ws.db.DBTools.getConnectionPOJO();
                if (conn != null) {
                
                    if (name == null || name.equals("")) {
                        cs = conn.prepareCall("{?=call testPackage.getAllPersons}");
                    } else {
                        cs = conn.prepareCall("{?=call testPackage.getPersonByname(?)}");
                        cs.setString(2, name);
                    }
                    
                    cs.registerOutParameter(1, OracleTypes.CURSOR); // OracleTypes.CURSOR == -10
                    cs.execute();
                    
                    for(rs = (ResultSet)cs.getObject(1);
                        rs.next(); 
                        personList.add(personData)) 
                    {
                            personData = Person.Factory.newInstance();
                            personData.setID(Integer.valueOf(rs.getInt("id")));
                            personData.setName(rs.getString("name"));
                            personData.setLastName(rs.getString("last_name"));
                            personData.setPersCode(rs.getString("pers_code"));
                            personData.setJob(rs.getString("job"));
                    }


                    Person personArray[] = new Person[personList.size()];
                    
                    for(int j = 0; j < personArray.length; j++)
                        personArray[j] = (Person)personList.get(j);
                    
                    gpbnr.getGetPersonByNameResponse().setReturnArray(personArray); 
                }  
            }
            catch(Exception e) {
                gpbnr.getGetPersonByNameResponse().setReturnArray(null); 
            }
            
            finally {
                try {
                    if(cs != null)cs.close();
                    if(rs != null)rs.close();
                    if(conn != null)conn.close();
                }   
                
                catch(Exception exception)
                {}
            }

            return gpbnr; 
                    }


Который отбирает из базы  персон, и кладёт их в обЬект класса GetPersonByNameResponseDocument , который соодержит в себе атрибут Person[].

Так вот, вопрос в том, как поведут себя веб сервисы, если в базе лежат 1 000 000 персон? Судя по архитектуре все ети персоны будут складыватся в оперативную памятЬ (в массив) и толЬко потом из етого будет создан ХМЛ... 

Такая ситуация как то обработана? 
В моём случае как Web Service engine исполЬзуется AXIS2, а веб сервер Tomcat6.

Автор: tux 18.1.2007, 11:39
Насколько я понимаю для таких случаев используются сообщения с аттачментами. Подробностей не знаю. 

Автор: sandello 18.4.2007, 07:18
Цитата(y3u @  10.9.2006,  19:39 Найти цитируемый пост)
клиента к нему сделать не получилось

C тех пор что-то изменилось?

Автор: Tony 7.6.2007, 19:34
Interrsnaja statejka: http://www.netbeans.org/kb/50/jaxws20.html
Cel' ne NetBeans,a ispol'zovanie JAX-WS tehnologii.

Автор: Киска 27.8.2007, 17:20
Здравствуйте!!!
Помогите, плиз, разобраться: при попытке запуска приложения, использующего шаблоны http страниц на Tomcat 4.1 столкнулась с тем, что они просто не работают. Томкат 4.1 на самом деле не умеет работать с шаблонами или это всё таки моя ошибка???

Автор: tux 27.8.2007, 18:03
Киска, о каких шаблонах речь?

Автор: kkorsakoff 29.11.2007, 20:58
Начал потихоньку разбираться с JWSDP.
Вопрос такой: как лучше организовать сессионность?
1. Искуственно: назначая при первом запросе некий sessionId, который клиент затем будет передавать в каждый метод
2. Вроде можно достучаться то HttpSession. Есть ли гарантии, что HttpSession будет работать так, как было бы логичноsmile, вне зависимости от реализации WS-клиента.

Поделитесь мнениямиsmile

P.S. С версиями конечно веселуха. Несколько часов убил, чтобы скрестить IDEA, JSWDP, идеевский плагин к нему и tomcat5!
Складывается впечатление излишне усложненной технологии или абсолютно черезжопной имплементации. Простите за мой французский

Автор: Maksym 29.11.2007, 21:20
kkorsakoff
Сори за офтоп, но когда название технологии -- это аббревиатура длинной более четырех букв, у меня почему то возникают подозрения о "черезжопной имплементации"...  smile 

Автор: powerOn 29.11.2007, 22:33
JWSDP - 'Java Web Service Developer Pack' - это название продукта, а не название технологии ;)

Автор: Maksym 30.11.2007, 12:50
Цитата(powerOn @  29.11.2007,  21:33 Найти цитируемый пост)
JWSDP - 'Java Web Service Developer Pack' - это название продукта, а не название технологии ;) 

Определяющее слово "аббревиатура длинной более четырех букв"..  smile .. возникает подозрение, что у авторов бедная фантазия... а вдруг это сказалось и на коде..?  smile 

Автор: kkorsakoff 4.12.2007, 01:25
Никто с WS не работает похоже smile 
Ладно, второй вопрос в пустоту...

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

Знаю, есть асинхронные вызовы (и два способа работы с ними, polling и callback), но прикол в том, что на сервере ничего не меняется.
Разница только на клиенте и то в том, что в случае async-работы мой поток может делать что-то полезное.
Мне в принципе это не надо, ...что говорится, не жалко...пусть повисит себе smile 
Или в случае async "транспортная часть" клиента (не знаю, как правильно назвать, короче реализация транспорта ws по http) знает, что запрос асинхронный и таймаут только в этом случае не устанавливает?

Автор: kkorsakoff 5.12.2007, 18:51
Цитата(kkorsakoff @ 29.11.2007,  20:58)
Начал потихоньку разбираться с JWSDP.
Вопрос такой: как лучше организовать сессионность?
1. Искуственно: назначая при первом запросе некий sessionId, который клиент затем будет передавать в каждый метод
2. Вроде можно достучаться то HttpSession. Есть ли гарантии, что HttpSession будет работать так, как было бы логичноsmile, вне зависимости от реализации WS-клиента.

Поделитесь мнениямиsmile

P.S. С версиями конечно веселуха. Несколько часов убил, чтобы скрестить IDEA, JSWDP, идеевский плагин к нему и tomcat5!
Складывается впечатление излишне усложненной технологии или абсолютно черезжопной имплементации. Простите за мой французский

Сам спрашиваю, сам отвечаю smile 

Может кому пригодится.

По-умолчанию сессия не поддерживается, то есть каждый запрос клиент посылает без поддержки сессии (куки, урл).
Чтобы включить поддержку сессии, необходимо на клиенте выполнить:

Код

Hello proxy = new HelloService().getHelloPort();
((BindingProvider)proxy).getRequestContext().put(BindingProvider.SESSION_MAINTAIN_PROPERTY,true);
int result = proxy.getCounter();
System.out.println(result);
result = proxy.getCounter();


На сервере ничего менять не надоsmile
До сессии можно достучаться из WebServiceContext 

Код

   @Resource
    private WebServiceContext wsContext;
    public int getCounter(){
        MessageContext mc = wsContext.getMessageContext();
        HttpSession session = ((javax.servlet.http.HttpServletRequest)mc.get(MessageContext.SERVLET_REQUEST)).getSession();
        // Get a session property "counter" from context
        if (session == null)
            throw new WebServiceException("No session in WebServiceContext");
        Integer counter = (Integer)session.getAttribute("counter");
        if (counter == null) {
            counter = new Integer(0);
            System.out.println("Starting the Session");
        }
        counter = new Integer(counter.intValue() + 1);
        session.setAttribute("counter", counter);
        return counter;

    }


Автор: kaa 15.7.2009, 22:23
Удалил что бы не было дублирования

Автор: Molodec 22.12.2010, 14:26
Здравствуйте, не хочется тем много создавать из-за своих вопросов. 
Возможно, кто-то сможет мне помочь. В общем хочу разобраться в Surf_Developer_Tools для Alfresco.
Нашёл очень интересную http://wiki.alfresco.com/wiki/Surf_Developer_Tools по настройке. Начал выполнять все, как там сказано, но у меня возникли проблемы на этапе:
Surf Addon for Spring Roo. 
Я пропустил его, решив, что возможно без него все заработает, но нет - результат отрицательный. Так что снова вернулся к нему. Вот собственно в чем тут дело:
Скачал я SpringSourse Tool Suite, в котором содержится Roo версии:
roo-1.1.0.RELEASE
На первый взгляд он нормально работает, но Spring Surf Roo Addon ставится на старую версию Roo:
/<sts_install>/roo-1.0.0.RC2/dist
А у меня более новая. И на этапе Set up a Spring Project manually.
При попытке выполнить это:
Type in project --topLevelPackage org.alfresco and press enter. This will generate a basic Spring project.
Roo выдаёт ошибку:
Command '--topLevelPackage org.alfresco' not found (for assistance press CTRL+SPACE or type "hint" then hit ENTER)
No remote OBR repositories have matching add-ons matching your request
Поэтому я подозреваю, что плагин на новой версии не работает. Пытаюсь найти старую версию Roo - не удаётся, так как все ссылки ведут на оффициальный сайт, где можно скачать самую последнюю версию. 
Пожалуйста, может если кто знает эту проблему и как её решить, или же знает где скачать более старую версию Roo, помогите. 
--------
Проблема все та же. Хотя вот это место прошёл:
Type in project --topLevelPackage org.alfresco and press enter. This will generate a basic Spring project.
Теперь она же обнаружилась при попытке:
roo> install surf
Command 'install surf' not found (for assistance press CTRL+SPACE or type "hint" then hit ENTER)
No remote OBR repositories have matching add-ons matching your request

То есть нужна старая версия... Которой нигде не могу найти. Кто может, пожалуйста, помогите. 
--------
Проблема решена!
По данной ссылке, можно скачать как и новую версию SpringSource Tool Suite так и старую, которая включает Roo 1.0.2. 
Удачи тем, у кого возникнет эта проблема!  smile 



Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)