SWS-249
This commit is contained in:
2
samples/pox/client/curl/client.sh
Executable file
2
samples/pox/client/curl/client.sh
Executable file
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
curl --header "Content-type: application/xml" -v --data @contactsRequest.xml http://localhost:8080/pox/
|
||||
11
samples/pox/client/curl/contactsRequest.xml
Normal file
11
samples/pox/client/curl/contactsRequest.xml
Normal file
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Contacts xmlns="http://www.springframework.org/spring-ws/samples/pox">
|
||||
<Contact>
|
||||
<Name>John Doe</Name>
|
||||
<Phone>626-555-3456</Phone>
|
||||
</Contact>
|
||||
<Contact>
|
||||
<Name>Jane Doe</Name>
|
||||
<Phone>626-555-6543</Phone>
|
||||
</Contact>
|
||||
</Contacts>
|
||||
46
samples/pox/client/spring-ws/build.xml
Normal file
46
samples/pox/client/spring-ws/build.xml
Normal file
@@ -0,0 +1,46 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<project name="spring-ws-pox-sample-spring-ws-client" default="build" xmlns:artifact="urn:maven-artifact-ant">
|
||||
<property name="bin.dir" value="bin"/>
|
||||
<property name="src.dir" value="src"/>
|
||||
|
||||
<target name="init">
|
||||
<typedef resource="org/apache/maven/artifact/ant/antlib.xml" uri="urn:maven-artifact-ant">
|
||||
<classpath>
|
||||
<pathelement location="${basedir}/../../../maven-ant-tasks-2.0.7.jar"/>
|
||||
</classpath>
|
||||
</typedef>
|
||||
|
||||
<artifact:dependencies pathId="classpath">
|
||||
<dependency groupId="org.springframework.ws" artifactId="spring-ws-core" version="1.5.0-m2"/>
|
||||
<dependency groupId="log4j" artifactId="log4j" version="1.2.13"/>
|
||||
</artifact:dependencies>
|
||||
|
||||
</target>
|
||||
|
||||
<target name="build" depends="init">
|
||||
<mkdir dir="${bin.dir}"/>
|
||||
<javac srcdir="${src.dir}" destdir="${bin.dir}">
|
||||
<classpath refid="classpath"/>
|
||||
</javac>
|
||||
<copy todir="${bin.dir}">
|
||||
<fileset dir="${src.dir}">
|
||||
<exclude name="**/*.java"/>
|
||||
</fileset>
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="clean">
|
||||
<delete dir="${bin.dir}"/>
|
||||
</target>
|
||||
|
||||
<target name="run" depends="contacts"/>
|
||||
|
||||
<target name="contacts" depends="build">
|
||||
<java classname="org.springframework.ws.samples.pox.client.sws.ContactsClient" fork="true" failonerror="true">
|
||||
<classpath refid="classpath"/>
|
||||
<classpath location="${bin.dir}"/>
|
||||
</java>
|
||||
</target>
|
||||
|
||||
</project>
|
||||
7
samples/pox/client/spring-ws/src/log4j.properties
Normal file
7
samples/pox/client/spring-ws/src/log4j.properties
Normal file
@@ -0,0 +1,7 @@
|
||||
log4j.rootLogger=WARN, stdout
|
||||
log4j.logger.org.springframework.ws=DEBUG
|
||||
log4j.logger.org.springframework.xml=DEBUG
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ws.samples.pox.client.sws;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.ws.WebServiceMessageFactory;
|
||||
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
|
||||
import org.springframework.xml.transform.ResourceSource;
|
||||
import org.springframework.xml.transform.StringResult;
|
||||
import org.springframework.xml.xpath.XPathExpression;
|
||||
|
||||
public class ContactsClient extends WebServiceGatewaySupport {
|
||||
|
||||
private Resource request;
|
||||
|
||||
private XPathExpression expression;
|
||||
|
||||
public ContactsClient(WebServiceMessageFactory messageFactory) {
|
||||
super(messageFactory);
|
||||
}
|
||||
|
||||
public void setRequest(Resource request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
public void setExpression(XPathExpression expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public void contacts() throws IOException {
|
||||
Source requestSource = new ResourceSource(request);
|
||||
DOMResult result = new DOMResult();
|
||||
getWebServiceTemplate().sendSourceAndReceiveToResult(requestSource, result);
|
||||
int contactCount = (int) expression.evaluateAsNumber(result.getNode());
|
||||
System.out.println("contactCount = " + contactCount);
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
ApplicationContext applicationContext =
|
||||
new ClassPathXmlApplicationContext("applicationContext.xml", ContactsClient.class);
|
||||
ContactsClient contactsClient = (ContactsClient) applicationContext.getBean("contactsClient");
|
||||
contactsClient.contacts();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
|
||||
|
||||
<bean id="contactsClient" class="org.springframework.ws.samples.pox.client.sws.ContactsClient">
|
||||
<constructor-arg ref="messageFactory"/>
|
||||
<property name="defaultUri" value="http://localhost:8080/pox/"/>
|
||||
<property name="request" value="classpath:org/springframework/ws/samples/pox/client/sws/contactsRequest.xml"/>
|
||||
<property name="expression" ref="expression"/>
|
||||
</bean>
|
||||
|
||||
<bean id="messageFactory" class="org.springframework.ws.pox.dom.DomPoxMessageFactory"/>
|
||||
|
||||
<bean id="expression" class="org.springframework.xml.xpath.XPathExpressionFactoryBean">
|
||||
<property name="namespaces">
|
||||
<props>
|
||||
<prop key="tns">http://www.springframework.org/spring-ws/samples/pox</prop>
|
||||
</props>
|
||||
</property>
|
||||
<property name="expression" value="/tns:ContactCount/text()"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Contacts xmlns="http://www.springframework.org/spring-ws/samples/pox">
|
||||
<Contact>
|
||||
<Name>John Doe</Name>
|
||||
<Phone>626-555-3456</Phone>
|
||||
</Contact>
|
||||
<Contact>
|
||||
<Name>Jane Doe</Name>
|
||||
<Phone>626-555-6543</Phone>
|
||||
</Contact>
|
||||
</Contacts>
|
||||
50
samples/pox/pom.xml
Normal file
50
samples/pox/pom.xml
Normal file
@@ -0,0 +1,50 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<parent>
|
||||
<artifactId>spring-ws-samples</artifactId>
|
||||
<groupId>org.springframework.ws</groupId>
|
||||
<version>1.5.0-rc1-SNAPSHOT</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>pox</artifactId>
|
||||
<packaging>war</packaging>
|
||||
<name>Spring WS POX Sample</name>
|
||||
<description>A Spring-WS sample that uses Plain Old XML, rather than SOAP.</description>
|
||||
<profiles>
|
||||
<profile>
|
||||
<id>jdk14-jdk15</id>
|
||||
<activation>
|
||||
<jdk>!1.6</jdk>
|
||||
</activation>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>stax</groupId>
|
||||
<artifactId>stax-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<stylesheetfile>${basedir}/../../src/main/javadoc/javadoc.css</stylesheetfile>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
<dependencies>
|
||||
<!-- Spring-WS dependencies -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.ws</groupId>
|
||||
<artifactId>spring-ws-core</artifactId>
|
||||
</dependency>
|
||||
<!-- Test dependencies -->
|
||||
<dependency>
|
||||
<groupId>easymock</groupId>
|
||||
<artifactId>easymock</artifactId>
|
||||
<version>1.2_Java1.3</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
13
samples/pox/readme.txt
Normal file
13
samples/pox/readme.txt
Normal file
@@ -0,0 +1,13 @@
|
||||
=========================================================
|
||||
== Spring Web Service Plain Old XML sample application ==
|
||||
=========================================================
|
||||
|
||||
|
||||
1. INTRODUCTION
|
||||
|
||||
This sample shows a service that uses Plain Old XML rather than SOAP. Incoming
|
||||
messages are handled via SAX, and a response is created using DOM.
|
||||
|
||||
2. INSTALLATION
|
||||
|
||||
Simply run "mvn package" and deploy the war file generated in target
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright 2008 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ws.samples.pox.ws;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Element;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
|
||||
import org.springframework.ws.server.endpoint.AbstractSaxPayloadEndpoint;
|
||||
|
||||
public class ContactCountEndpoint extends AbstractSaxPayloadEndpoint {
|
||||
|
||||
private static final String NAMESPACE_URI = "http://www.springframework.org/spring-ws/samples/pox";
|
||||
|
||||
private static final String CONTANT_NAME = "Contact";
|
||||
|
||||
private static final String CONTANT_COUNT_NAME = "ContactCount";
|
||||
|
||||
private DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
|
||||
public ContactCountEndpoint() {
|
||||
documentBuilderFactory.setNamespaceAware(true);
|
||||
}
|
||||
|
||||
protected ContentHandler createContentHandler() throws Exception {
|
||||
return new ContactCounter();
|
||||
}
|
||||
|
||||
protected Source getResponse(ContentHandler contentHandler) throws Exception {
|
||||
ContactCounter counter = (ContactCounter) contentHandler;
|
||||
|
||||
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
Document response = documentBuilder.newDocument();
|
||||
Element contactCountElement = response.createElementNS(NAMESPACE_URI, CONTANT_COUNT_NAME);
|
||||
response.appendChild(contactCountElement);
|
||||
contactCountElement.setTextContent(Integer.toString(counter.contactCount));
|
||||
|
||||
return new DOMSource(response);
|
||||
}
|
||||
|
||||
private static class ContactCounter extends DefaultHandler {
|
||||
|
||||
private int contactCount = 0;
|
||||
|
||||
public void startElement(String uri, String localName, String qName, Attributes attributes)
|
||||
throws SAXException {
|
||||
if (NAMESPACE_URI.equals(uri) && CONTANT_NAME.equals(localName)) {
|
||||
contactCount++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
7
samples/pox/src/main/resources/log4j.properties
Normal file
7
samples/pox/src/main/resources/log4j.properties
Normal file
@@ -0,0 +1,7 @@
|
||||
log4j.rootLogger=WARN, stdout
|
||||
log4j.logger.org.springframework.ws=DEBUG
|
||||
log4j.logger.org.springframework.xml=DEBUG
|
||||
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
|
||||
28
samples/pox/src/main/webapp/WEB-INF/contacts.xsd
Normal file
28
samples/pox/src/main/webapp/WEB-INF/contacts.xsd
Normal file
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"
|
||||
targetNamespace="http://www.springframework.org/spring-ws/samples/pox">
|
||||
|
||||
<xsd:element name="Contacts">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Defines a contact-list, with names and phone numbers.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="Contact" minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:complexType>
|
||||
<xsd:all>
|
||||
<xsd:element name="Name" type="xsd:string"/>
|
||||
<xsd:element name="Phone" type="xsd:string"/>
|
||||
</xsd:all>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:sequence>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
<xsd:element name="ContactCount" type="xsd:integer"/>
|
||||
|
||||
|
||||
</xsd:schema>
|
||||
35
samples/pox/src/main/webapp/WEB-INF/spring-ws-servlet.xml
Executable file
35
samples/pox/src/main/webapp/WEB-INF/spring-ws-servlet.xml
Executable file
@@ -0,0 +1,35 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<description>
|
||||
This web application context contains Spring-WS beans. The beans defined in this context are automatically
|
||||
detected by Spring-WS, similar to the way Controllers are picked up in Spring Web MVC.
|
||||
</description>
|
||||
|
||||
<bean id="payloadMapping" class="org.springframework.ws.server.endpoint.mapping.PayloadRootQNameEndpointMapping">
|
||||
<description>
|
||||
This endpoint mapping uses the qualified name of the payload (body contents) to determine the endpoint for
|
||||
an incoming message. Every message is passed to the default endpoint. Additionally, messages are logged
|
||||
using the logging interceptor.
|
||||
</description>
|
||||
<property name="defaultEndpoint" ref="contactCountEndpoint"/>
|
||||
<property name="interceptors" ref="validatingInterceptor"/>
|
||||
</bean>
|
||||
|
||||
<bean id="validatingInterceptor"
|
||||
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
|
||||
<description>
|
||||
This interceptor validates both incoming and outgoing message contents according to the 'contacts.xsd' XML
|
||||
Schema file.
|
||||
</description>
|
||||
<property name="schema" value="/WEB-INF/contacts.xsd"/>
|
||||
<property name="validateRequest" value="true"/>
|
||||
<property name="validateResponse" value="true"/>
|
||||
</bean>
|
||||
|
||||
<bean id="contactCountEndpoint" class="org.springframework.ws.samples.pox.ws.ContactCountEndpoint"/>
|
||||
|
||||
<bean id="messageFactory" class="org.springframework.ws.pox.dom.DomPoxMessageFactory"/>
|
||||
|
||||
</beans>
|
||||
25
samples/pox/src/main/webapp/WEB-INF/web.xml
Executable file
25
samples/pox/src/main/webapp/WEB-INF/web.xml
Executable file
@@ -0,0 +1,25 @@
|
||||
<?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>
|
||||
POX WebService
|
||||
</display-name>
|
||||
<description>A Spring-WS sample that uses Plain Old XML, rather than SOAP.</description>
|
||||
|
||||
<!-- Defines the Spring-WS MessageDispatcherServlet -->
|
||||
<servlet>
|
||||
<servlet-name>spring-ws</servlet-name>
|
||||
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
|
||||
</servlet>
|
||||
|
||||
<!-- Map all requests to this servlet -->
|
||||
<servlet-mapping>
|
||||
<servlet-name>spring-ws</servlet-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright ${YEAR} the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.ws.samples.pox.ws;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.transform.dom.DOMSource;
|
||||
import javax.xml.transform.dom.DOMResult;
|
||||
import javax.xml.transform.Source;
|
||||
import javax.xml.transform.TransformerFactory;
|
||||
import javax.xml.transform.Transformer;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
|
||||
import org.springframework.ws.samples.pox.ws.ContactCountEndpoint;
|
||||
import org.springframework.xml.sax.SaxUtils;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
|
||||
import org.custommonkey.xmlunit.XMLTestCase;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
public class ContactCountEndpointTest extends XMLTestCase {
|
||||
|
||||
private ContactCountEndpoint endpoint;
|
||||
|
||||
private Transformer transformer;
|
||||
|
||||
private DocumentBuilder documentBuilder;
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
endpoint = new ContactCountEndpoint();
|
||||
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
documentBuilderFactory.setNamespaceAware(true);
|
||||
documentBuilder = documentBuilderFactory.newDocumentBuilder();
|
||||
TransformerFactory transformerFactory = TransformerFactory.newInstance();
|
||||
transformer = transformerFactory.newTransformer();
|
||||
}
|
||||
|
||||
public void testInvoke() throws Exception {
|
||||
Document request = documentBuilder
|
||||
.parse(SaxUtils.createInputSource(new ClassPathResource("contactsRequest.xml", getClass())));
|
||||
Document expected = documentBuilder
|
||||
.parse(SaxUtils.createInputSource(new ClassPathResource("contactCountResponse.xml", getClass())));
|
||||
|
||||
Source source = endpoint.invoke(new DOMSource(request));
|
||||
DOMResult result = new DOMResult();
|
||||
transformer.transform(source, result);
|
||||
assertXMLEqual("Invalid resonse", expected, (Document) result.getNode());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ContactCount xmlns="http://www.springframework.org/spring-ws/samples/pox">2</ContactCount>
|
||||
@@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Contacts xmlns="http://www.springframework.org/spring-ws/samples/pox">
|
||||
<Contact>
|
||||
<Name>John Doe</Name>
|
||||
<Phone>626-555-3456</Phone>
|
||||
</Contact>
|
||||
<Contact>
|
||||
<Name>Jane Doe</Name>
|
||||
<Phone>626-555-6543</Phone>
|
||||
</Contact>
|
||||
</Contacts>
|
||||
Reference in New Issue
Block a user