# Webservices mit Spring und AXIS



## Thomas Darimont (16. Februar 2006)

Hallo!

hier mal ein kleines Beispiel für einen kleinen Benutzerauthentifizierungs Webservice auf Basis von Spring 1.2.6, Axis 1.3, Tomcat 5.0.28 
und JDBC. Der Webservice wird eine Methode namens authenticateUser(username,password) anbieten und intern gegen eine MySQL Datenbank prüfen,
ob ein entsprechender Benutzer in der Datenbank existiert. Die Anwendung läuft in Form einer WebApp im Tomcat.
Als Entwicklungsumgebung verwende ich Eclipse 3.1.1 (http://www.eclipse.org/downloads/) und das aktuelle Sysdeo Tomcat Plugin (http://www.sysdeo.com/eclipse/tomcatplugin)

Unser interner Service zur Benutzerauthentifizierung:

```
package de.tutorials.spring.service;

/**
 * @author Tom
 * 
 */
public interface IAuthenticationService {
    public static final String AUTHENTICATION_SERVICE_ID = "authenticationService";
    boolean authenticateUser(String username, String password);
}
```

...und dessen Implementierung:

```
package de.tutorials.spring.service.impl;

import de.tutorials.spring.persistence.IUserAuthenticationDAO;
import de.tutorials.spring.service.IAuthenticationService;

/**
 * @author Tom
 * 
 */
public class AuthenticationServiceImpl implements IAuthenticationService {

    IUserAuthenticationDAO userAuthenticationDAO;

    public boolean authenticateUser(String username, String password) {
        return userAuthenticationDAO.userExists(username, password);
    }

    public IUserAuthenticationDAO getUserAuthenticationDAO() {
        return userAuthenticationDAO;
    }

    public void setUserAuthenticationDAO(
            IUserAuthenticationDAO userAuthenticationDAO) {
        this.userAuthenticationDAO = userAuthenticationDAO;
    }
}
```

Unser DAO (Data Access Object) Interface:

```
package de.tutorials.spring.persistence;

/**
 * @author Tom
 * 
 */
public interface IUserAuthenticationDAO {
    boolean userExists(String username, String password);
}
```

...und dessen auf Spring JDBC basierende Implementierung:

```
package de.tutorials.spring.persistence.impl;

import org.springframework.jdbc.core.support.JdbcDaoSupport;

import de.tutorials.spring.persistence.IUserAuthenticationDAO;

/**
 * @author Tom
 * 
 */
public class JDBCUserAuthenticationDAOImpl extends JdbcDaoSupport implements
        IUserAuthenticationDAO {

    public final static String SELECT_USER = "SELECT count(*) FROM user WHERE username=? and password=?";

    public boolean userExists(String username, String password) {
        return getJdbcTemplate().queryForInt(SELECT_USER,
                new Object[] { username, password }) == 1;
    }
}
```

Hier noch unser Webservice Endpoint welcher von "außen" angesprochen werden kann:

```
package de.tutorials.spring.webservice;

import org.springframework.remoting.jaxrpc.ServletEndpointSupport;

import de.tutorials.spring.service.IAuthenticationService;

/**
 * @author Tom
 * 
 */
public class UserAuthenticationEndpoint extends ServletEndpointSupport
        implements IAuthenticationService {

    private IAuthenticationService authenticationService;

    public void onInit() {
        this.authenticationService = (IAuthenticationService) getWebApplicationContext()
                .getBean(AUTHENTICATION_SERVICE_ID);
    }

    public boolean authenticateUser(String username, String password) {
        return authenticationService.authenticateUser(username, password);
    }
}
```

nun müssen wir unsere Beans nur noch zusammenführen. Das erledigen wir über Springs applicationContext.xml File:
(Welches wir im WEB-INF Verzeichnis unserer Webanwendung hinterlegen)
(Siehe Übersicht im Anhang)

```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="authenticationService"
        class="de.tutorials.spring.service.impl.AuthenticationServiceImpl">
        <property name="userAuthenticationDAO"
            ref="userAuthenticationDAO" />
    </bean>

    <bean id="userAuthenticationDAO"
        class="de.tutorials.spring.persistence.impl.JDBCUserAuthenticationDAOImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate" />
    </bean>

    <bean id="jdbcTemplate"
        class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource" />
    </bean>

    <bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource">
        <property name="driverClassName" value="${db.driverClassName}" />
        <property name="username" value="${db.username}" />
        <property name="password" value="${db.password}" />
        <property name="url" value="${db.url}" />
    </bean>


    <bean id="propertyConfigurer"
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>/WEB-INF/authenticationService.properties</value>
            </list>
        </property>
    </bean>
</beans>
```

Die Daten für die Datenbank legen wir in der Datei authenticationService.properties ab:
(Ebenfalls im WEB-INF Verzeichnis)

```
db.driverClassName=com.mysql.jdbc.Driver
db.username=root
db.password=
db.url=jdbc:mysql://localhost:3306/test
```

Die web.xml:

```
<?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>
        Tutorials User Authentication Webservice
    </display-name>
    <description>Tutorials User Authentication Example</description>
    
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/applicationContext.xml</param-value>
    </context-param>

    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>

    <servlet>
        <servlet-name>axis</servlet-name>
        <servlet-class>
            org.apache.axis.transport.http.AxisServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>axis</servlet-name>
        <url-pattern>/axis/*</url-pattern>
    </servlet-mapping>
</web-app>
```

...und zum Schluß noch der AXIS spezifische wsdd (Web Service Deployment Descriptor):

```
<?xml version="1.0" encoding="UTF-8"?>
<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
    <globalConfiguration>
        <parameter name="adminPassword" value="admin"/>
        <parameter name="sendXsiTypes" value="true"/>
        <parameter name="sendMultiRefs" value="true"/>
        <parameter name="sendXMLDeclaration" value="true"/>
        <parameter name="axis.sendMinimizedElements" value="true"/>
        <requestFlow>
            <handler type="java:org.apache.axis.handlers.JWSHandler">
                <parameter name="scope" value="session"/>
            </handler>
            <handler type="java:org.apache.axis.handlers.JWSHandler">
                <parameter name="scope" value="request"/>
                <parameter name="extension" value=".jwr"/>
            </handler>
        </requestFlow>
    </globalConfiguration>
    <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
    <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
    <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
    <service name="AdminService" provider="java:MSG">
        <parameter name="allowedMethods" value="AdminService"/>
        <parameter name="enableRemoteAdmin" value="false"/>
        <parameter name="className" value="org.apache.axis.utils.Admin"/>
        <namespace>http://xml.apache.org/axis/wsdd/</namespace>
    </service>
    <service name="UserAuthenticationService" provider="java:RPC">
        <parameter name="allowedMethods" value="*"/>
        <parameter name="className" value="de.tutorials.spring.webservice.UserAuthenticationEndpoint"/>
    </service>
    <service name="Version" provider="java:RPC">
        <parameter name="allowedMethods" value="getVersion"/>
        <parameter name="className" value="org.apache.axis.Version"/>
    </service>
    <transport name="http">
        <requestFlow>
            <handler type="URLMapper"/>
            <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
        </requestFlow>
    </transport>
    <transport name="local">
        <responseFlow>
            <handler type="LocalResponder"/>
        </responseFlow>
    </transport>
</deployment>
```

Nun muss man nur noch die Datenbank bevölkern:

```
drop table user;
create table user( username varchar(32) not null, password varchar(32) not null, primary key(username), unique key(username,password));
insert into user values ('thomas','foobar');
insert into user values ('richard','abcdef');
commit;
```

... und schon kann der Spaß losgehen 
Am besten das beiliegende Projekt zu ausprobieren verwenden.

Den Webservice kann man nun auf vielfältige Art und Weise testen. Auf die schnelle geht das am besten über den Webbrowser.
Um zu testen ob der AXIS Webservice aktiv ist, ruft man einfach folgende URL im Browser auf:
http://localhost:8080/de.tutorials.spring.webservices.example/axis/UserAuthenticationService

Hat alles geklappt so erscheint:

```
UserAuthenticationService
Hi there, this is an AXIS service!

Perhaps there will be a form for invoking the service here...
```
als Ausgabe.

Wollen wir uns das von AXIS generierte WSDL Dokument anzeigen lassen, so müssen wir einfach nur ?wsdl an die URL hängen.
http://localhost:8080/de.tutorials.spring.webservices.example/axis/UserAuthenticationService?wsdl

Das ergibt dann folgendes:

```
<?xml version="1.0" encoding="UTF-8" ?> 
- <wsdl:definitions targetNamespace="http://localhost:8080/de.tutorials.spring.webservices.example/axis/UserAuthenticationService" xmlns:apachesoap="http://xml.apache.org/xml-soap" xmlns:impl="http://localhost:8080/de.tutorials.spring.webservices.example/axis/UserAuthenticationService" xmlns:intf="http://localhost:8080/de.tutorials.spring.webservices.example/axis/UserAuthenticationService" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:wsdlsoap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <!-- 
WSDL created by Apache Axis version: 1.3
Built on Oct 05, 2005 (05:23:37 EDT)

  --> 
- <wsdl:message name="authenticateUserRequest">
  <wsdl:part name="username" type="soapenc:string" /> 
  <wsdl:part name="password" type="soapenc:string" /> 
  </wsdl:message>
- <wsdl:message name="authenticateUserResponse">
  <wsdl:part name="authenticateUserReturn" type="xsd:boolean" /> 
  </wsdl:message>
- <wsdl:portType name="UserAuthenticationEndpoint">
- <wsdl:operation name="authenticateUser" parameterOrder="username password">
  <wsdl:input message="impl:authenticateUserRequest" name="authenticateUserRequest" /> 
  <wsdl:output message="impl:authenticateUserResponse" name="authenticateUserResponse" /> 
  </wsdl:operation>
  </wsdl:portType>
- <wsdl:binding name="UserAuthenticationServiceSoapBinding" type="impl:UserAuthenticationEndpoint">
  <wsdlsoap:binding style="rpc" transport="http://schemas.xmlsoap.org/soap/http" /> 
- <wsdl:operation name="authenticateUser">
  <wsdlsoap:operation soapAction="" /> 
- <wsdl:input name="authenticateUserRequest">
  <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://webservice.spring.tutorials.de" use="encoded" /> 
  </wsdl:input>
- <wsdl:output name="authenticateUserResponse">
  <wsdlsoap:body encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" namespace="http://localhost:8080/de.tutorials.spring.webservices.example/axis/UserAuthenticationService" use="encoded" /> 
  </wsdl:output>
  </wsdl:operation>
  </wsdl:binding>
- <wsdl:service name="UserAuthenticationEndpointService">
- <wsdl:port binding="impl:UserAuthenticationServiceSoapBinding" name="UserAuthenticationService">
  <wsdlsoap:address location="http://localhost:8080/de.tutorials.spring.webservices.example/axis/UserAuthenticationService" /> 
  </wsdl:port>
  </wsdl:service>
  </wsdl:definitions>
```

Wollen wir nun unseren Webservice einmal Aufrufen, dann können wir das durch Anhängen des Query Strings (?method=authenticateUser&username=thomas&password=foobar) so machen:
http://localhost:8080/de.tutorials....henticateUser&username=thomas&password=foobar
Als Ausgabe/Antwort erhalten wir dann:

```
<?xml version="1.0" encoding="UTF-8" ?> 
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <soapenv:Body>
- <authenticateUserResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <authenticateUserReturn href="#id0" /> 
  </authenticateUserResponse>
  <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:boolean" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">true</multiRef> 
  </soapenv:Body>
  </soapenv:Envelope>
```

Geben wir die falschen Benutzerdaten ein:
http://localhost:8080/de.tutorials....enticateUser&username=thomas&password=abcdddd

Erhalten wir folgende Antwort:

```
<?xml version="1.0" encoding="UTF-8" ?> 
- <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
- <soapenv:Body>
- <authenticateUserResponse soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <authenticateUserReturn href="#id0" /> 
  </authenticateUserResponse>
  <multiRef id="id0" soapenc:root="0" soapenv:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" xsi:type="xsd:boolean" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/">false</multiRef> 
  </soapenv:Body>
  </soapenv:Envelope>
```

Ich finde es immer wieder interessant, wie leicht und schnell doch alles von der Hand geht, wenn das Springframework mit von der Partie ist 

Gruß Tom


----------



## reichemi (24. April 2007)

Hallo,

vielen Dank für das ausführliche Beispiel, das hat mich ein ganzes Stück weitergebracht!!

Darauf aufbauend will ich den Webservice allerdings so erweitern, dass dieser "stateful" wird. Dies ist nötig, da er Methoden wie "login", "logout" und eben Methoden für autorisierte User beinhalten soll.

Ich habe schon herausgefunden, dass dafür wohl die Einstellung "scope=session" in der server-config.wsdd nötig ist:


```
<service name="UserAuthenticationService" provider="java:RPC">
		<parameter name="allowedMethods" value="*"/>
		<parameter name="className" value="de.tutorials.spring.webservice.UserAuthenticationEndpoint"/>
		<parameter name="scope" value="session"/>
	</service>
```

Allerdings finde ich keine Dokus, wie man nun innerhalb einer Session Werte speichert/auslesen kann.

Ist dies überhaupt so ohne weiteres möglich?


mfg, Michael


----------

