I made two apps with similar code on Spring Boot.
Reactive Netty spring boot webflux r2dbc.
Nonreactive Tomcat spring boot postgres.
I expect reactive one is faster or has the same speed. But it is slower 6th time.
I don't see any blocks there. In my opinion it is fully nonblocking app. Why so slowly?
For testing I have been using J-METER.
200 threads 200 times
getAll 400 strings
Latency of response nonreactive app - 190-240 ms.
Latency of response reactive app - 1290-1350 ms.
reactive pom
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>reactive</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>reactive</name>
<description>reactive</description>
<properties>
<java.version>1.8</java.version>
<mapstruct.version>1.4.2.Final</mapstruct.version>
<lombok-mapstruct-binding.version>0.2.0</lombok-mapstruct-binding.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-r2dbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>io.r2dbc</groupId>
<artifactId>r2dbc-postgresql</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${mapstruct.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<releases>
<enabled>false</enabled>
</releases>
</pluginRepository>
</pluginRepositories>
</project>
Spring boot entry point
#SpringBootApplication(exclude = {ReactiveSecurityAutoConfiguration.class})
#Configuration
#EnableR2dbcRepositories
public class ReactiveApplication {
public static void main(String[] args) {
SpringApplication.run(ReactiveApplication.class, args);
}
}
application.yml
server:
port : 8083
spring:
data:
r2dbc:
repositories:
enabled: true
r2dbc:
url: r2dbc:postgresql://localhost:5432/reactive
username: postgres
password: 12345
properties:
schema: bookshop
logging:
level:
org:
springframework:
r2dbc: DEBUG
Controller
package com.example.reactive.controller;
import com.example.reactive.entity.Book;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#RequestMapping("/book")
public interface BookController {
#ResponseStatus(code = HttpStatus.OK)
#PostMapping(consumes = MediaType.APPLICATION_JSON_VALUE)
Mono<Book> saveBook(#RequestBody Book book);
#ResponseStatus(code = HttpStatus.OK)
#GetMapping("/{id}")
Mono<Book> getBookById(#PathVariable Long id);
#ResponseStatus(code = HttpStatus.OK)
#GetMapping("/all")
Flux<Book> getAllBooks();
}
ControllerImpl
package com.example.reactive.controller.impl;
import com.example.reactive.controller.BookController;
import com.example.reactive.entity.Book;
import com.example.reactive.repository.BookRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
#RestController
#RequiredArgsConstructor
public class BookControllerImpl implements BookController {
private final BookRepository bookRepository;
#Override
public Mono<Book> saveBook(Book book) {
return bookRepository.save(book);
}
#Override
public Mono<Book> getBookById(Long id) {
return bookRepository.findById(id);
}
#Override
public Flux<Book> getAllBooks() {
return bookRepository.findAll();
}
}
Entity
package com.example.reactive.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.data.annotation.Id;
#Data
#NoArgsConstructor
#AllArgsConstructor
#Builder
public class Book {
#Id
private Long id;
private String name;
private String author;
private String text;
}
Repository
package com.example.reactive.repository;
import com.example.reactive.entity.Book;
import org.springframework.data.repository.reactive.ReactiveCrudRepository;
public interface BookRepository extends ReactiveCrudRepository<Book, Long> {
}
If you need more information, feel free to write comments.
EDITED
After adding thread-pool parameters of min value 50 and max value 100, reactive app become faster.
I don't use get All property to compare apps.
For testing I have been using J-METER.200 threads 200 times
get 1 different string
Latency of response nonreactive app - middle 6 ms.
Latency of response reactive app - middle 10 ms.
post 1 string
Latency of response nonreactive app - middle 37 ms.
Latency of response reactive app - middle 6 ms!!!!!!!!
Computer parameters
Processor Intel® Core™ i 5-10400 CPU # 2.90 GHz × 12.
RAM 16,0 GB.
First, to answer in a more general sense, the reactive stack is - unfortunately - not a one-size-fits-all shortcut to make applications perform better. One of the main benefits of using WebFlux is its ability to handle more concurrent requests when compared to servlet.
Now to the problem at hand. I will assume that the latency values you have given are averages obtained from a fairly heavy load test.
One thing that comes to mind is that the first couple of requests served by a reactive application after its startup always take extra time - this can be attributed to Netty initialization. For this reason, in busy production environments, we have always had some form of automated warmup in place. Although I assume your load tests send so many requests that this should not be a factor.
For the above reason, I am inclined to believe that the cause of this slowdown could be simply down to excessive logging - setting the package org.springframework.r2dbc to DEBUG level logs every single SQL statement executed - and in the context of a load test, excessive logging wreaks havoc on performance and pollutes results.
Edit
For reference, I have built two similar apps with postgres based on your post. One servlet with JPA, and one reactive with R2DBC.
I have executed a 30-second Gatling load test on both, simulating 200 constant concurrent users. The actual request sent was either an insert or a get operation, both had equal weight when it came to choosing.
The load test in question:
public class ReactiveApplicationLoadTest extends Simulation {
private static final String BASE_URL = "http://localhost:8083";
private static final String BOOK_URI = "/book";
HttpProtocolBuilder httpProtocol = http
.baseUrl(BASE_URL);
ScenarioBuilder scenario = scenario("Get All Books").randomSwitch()
.on(
Choice.withWeight(1, exec(
http("GET_ONE")
.get(BOOK_URI + "/1")
)),
Choice.withWeight(1, exec(
http("INSERT")
.post(BOOK_URI)
.header("Content-Type", "application/json")
.body(StringBody("{\"name\": \"book\", \"author\": \"author\", \"text\": \"text\"}"))
))
);
{
setUp(
scenario.injectClosed(constantConcurrentUsers(200).during(30)).protocols(httpProtocol)
);
}
}
My computer's relevant specifications:
CPU: intel i7 11700K
RAM: 32GB DDR4 # 3600MHz
The source code of the two apps:
GitHub
The results:
Reactive
Servlet
My results lean heavily in the favor of the reactive application, both in response times and the number of KO'd requests.
You might notice that I did not include a "get all" request in the load test. The reason for this is that the sheer amount of items created in the load test don't mix well with this broad query, especially in a reactive context - this might be the source of the results you are seeing.
Takeaway
Consider adding some form of pagination to your "get all" endpoints in both apps OR omit these calls from your load test, and then try again.
This issue was solved by adding properties of thread-pool to
application.yml
spring:
r2dbc:
pool:
initial-size: 10
max-size: 20
Also There is was used non-blocking subscription to repository
Mono.defer(()-> Mono.from(bookRepository.findAllBookWithDelayById(id)
.subscribeOn(Schedulers.boundedElastic())));
Application became 1.8 times faster then non-reactive.
Related
Hello I'm working with a Spring boot App connecting to a mongo db, my problem is that my endpoint are not working it seems that they are not found by Component scan. I'm have been crazy because I'm blocked to continue developing and I'm not able to identify the issue. All seems to be ok. I suppose that maybe is something related with the versions, but not pretty sure.
This is my controller:
package com.mercadolibre.mutants.controllers;
import com.mercadolibre.mutants.entities.Product;
import java.util.concurrent.CompletableFuture;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class ProductController {
private static final Logger LOGGER = LoggerFactory.getLogger(ProductController.class);
public static final String SHORTEN_URL_PATH = "/shorten";
public static final String URL_PATH = "/{id}";
#RequestMapping(value = SHORTEN_URL_PATH, method = RequestMethod.POST)
#ResponseStatus(HttpStatus.CREATED)
public CompletableFuture<String> shortenUrl(#RequestBody #Valid final Product shortenUrlDto, HttpServletRequest request) throws Exception {
LOGGER.info("Url to shorten: " );
CompletableFuture<String> shortenedUrl = null;
String localURL = request.getRequestURL().toString();
//shortenedUrl = shortUrlService.shortenURL(localURL, shortenUrlDto.getUrl());
LOGGER.info("Shortened url to: " + shortenedUrl);
return shortenedUrl;
}
#GetMapping(URL_PATH)
public CompletableFuture<String> retrieveOriginalUrl(#PathVariable String id) throws Exception {
LOGGER.info("short url to redirect: " + id);
//CompletableFuture<String> redirectUrlString = shortUrlService.getLongURLFromID(id);
// LOGGER.info("Original URL: " + redirectUrlString);
return null;
}
}
This is my Application class:
package com.mercadolibre.mutants;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication()
public class MutantsApplication {
public static void main(String[] args) {
SpringApplication.run(MutantsApplication.class, args);
}
}
my pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.16.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.mercadolibre</groupId>
<artifactId>mutants</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mutants</name>
<description>Project for Java Challengue</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-mongodb -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-releasetrain</artifactId>
<version>Lovelace-SR9</version>
<type>pom</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</repository>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
</pluginRepository>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
From the comments, I would say you have a problem with the docker configuration where you are deploying your api, I would do the next validations:
Check your api is being served in the 8080 inside your docker container.
Check if you have correctly configured your docker container so the 8080 port (or the one used by your api) is open.
Check if (for some strange reason) you don't have another api running in 8080 in the docker container.
Finally, get into the SSH of your container and then (if you are running some UNIX SO) make a CURL request to the url and check the answer.
Hopes this helps.
I'm currently trying to set up automated testing for a Maven project, but I've run into a problem. When running my tests using mvn test, I get the following result:
-------------------------------------------------------------------------------
Test set: no.digipat.patornat.servlets.ServletTests
-------------------------------------------------------------------------------
Tests run: 1, Failures: 0, Errors: 1, Skipped: 0, Time elapsed: 0.398 s <<< FAILURE! - in no.digipat.patornat.servlets.ServletTests
no.digipat.patornat.servlets.ServletTests Time elapsed: 0.368 s <<< ERROR!
java.lang.NoClassDefFoundError: com/mongodb/OperationExecutor
Caused by: java.lang.ClassNotFoundException: com.mongodb.OperationExecutor
I get the same error when running the tests in Eclipse.
This is my pom.xml:
<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">
<modelVersion>4.0.0</modelVersion>
<groupId>no.digipat.patornat</groupId>
<artifactId>backend</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Pat or Nat Backend</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.target>11</maven.compiler.target>
<maven.compiler.source>11</maven.compiler.source>
</properties>
<repositories>
<repository>
<id>cytomine-uliege-Cytomine-java-client</id>
<url>https://packagecloud.io/cytomine-uliege/Cytomine-java-client/maven2</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.lordofthejars</groupId>
<artifactId>nosqlunit-mongodb</artifactId>
<version>1.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.fakemongo</groupId>
<artifactId>fongo</artifactId>
<version>2.2.0-RC2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.github.stefanbirkner</groupId>
<artifactId>system-rules</artifactId>
<version>1.19.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>be.cytomine.client</groupId>
<artifactId>cytomine-java-client</artifactId>
<version>2.0.7-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.1</version>
<scope>compile</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.0.0-M4</version>
<configuration>
<includes>
<include>ServletTests.java</include>
</includes>
</configuration>
</plugin>
</plugins>
</build>
</project>
The relevant Java files:
ServletTests.java:
package no.digipat.patornat.servlets;
import org.junit.BeforeClass;
import org.junit.ClassRule;
import org.junit.contrib.java.lang.system.EnvironmentVariables;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
import static com.lordofthejars.nosqlunit.mongodb.InMemoryMongoDb.InMemoryMongoRuleBuilder.newInMemoryMongoDbRule;
#RunWith(Suite.class)
#SuiteClasses({MyTest.class})
public class ServletTests {
private static final EnvironmentVariables environmentVariables = new EnvironmentVariables();
#ClassRule
public static final TestRule chain = RuleChain
.outerRule(newInMemoryMongoDbRule().build())
.around(environmentVariables);
#BeforeClass
public static void setUpClass() {
environmentVariables.set("MY_VARIABLE", "some value");
}
}
MyTest.java:
package no.digipat.patornat.servlets;
import static org.junit.Assert.*;
import org.junit.Test;
public class MyTest {
#Test
public void test() {
fail("Not yet implemented");
}
}
Any ideas on how to solve this? I tried running mvn clean (which previously helped me fix a similar issue), but to no avail.
I think you need the maven-compiler-plugin in your pom.xml
<build>
<!-- put here the path of your test source directory -->
<testSourceDirectory>src/test</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>${maven.compiler.source}</source>
<target>${maven.compiler.target}</target>
</configuration>
</plugin>
</plugins>
...
It seems that the issue was that the latest versions of Fongo and mongo-java-driver are incompatible. When I change the dependencies of Fongo and/or the Mongo Java driver to older versions (I specifically tried versions 2.1.0 and 3.6.3, respectively), the error disappears. However, since this solution seems rather fragile and inflexible, the best bet is probably to switch to an alternative to Fongo. According to this GitHub comment, mongo-java-server could be a good option. A perhaps more robust alternative, and the one I'll probably end up using, is to use a "real" test database. This article has information about a couple of ways to do this.
I'm currently working on a Spring-boot project in which I have to send files (one at a time) through a REST Web Service to a server, which sends it to a Cassandra cluster.
This part works, but my problem appeared when I began to do stress tests (with Gatling) on my project.
Here it is :
- When I tested my work without sending files, I had latency ~10-15 ms ;
- When I tested my work sending a file in the body of the request, I had latency ~10-15 ms too (maybe a little higher by 5 or 10 ms, I don't remember);
- BUT, and my problem shows up here, when I tested the Web Service by sending files with an input, and getting it with MultipartFile, the latency was very variable, from 10 ms for the fastest requests, to 12000ms (!!) for the longest.
I tried to set the files in memory limit to 1Go (it was originaly ~10ko), but it didn't change anything.
I don't get any error while executing the tests, it's just very long...
Plus, this project is being made to modernize the existing webservice, which runs as a JAX-WS, with WSDL and all. The team working on the old project (we are switching from a DBMS to an other) has response times of ~10 in mean !
Here's my conf (this is for a POC, the machines are cheap) :
- Web server : Wildfly 9-0-1.FINAL out of the box, on CentOS Server 7.1;
- Stress tests machine : Gatling 2.1.7, on the same CentOS version as Wildfly, but on an other machine;
- An 8 nodes Cassandra cluster.
Here is my pom (without company's secrets | concerning the spring-boot dependency, it's not my project's parent, it already has one):
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>1.3.0.RELEASE</version>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-websocket</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>1.3.0.RELEASE</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
</dependencies>
<properties>
<java.version>1.8</java.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<failOnMissingWebXml>false</failOnMissingWebXml>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
<repository>
<id>oss-jfrog-artifactory</id>
<name>oss-jfrog-artifactory-releases</name>
<url>http://oss.jfrog.org/artifactory/oss-release-local</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-releases</id>
<url>https://repo.spring.io/libs-release</>
</pluginRepository>
</pluginRepositories>
<dependencyManagement>
<dependencies>
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.3.0.RELEASE</version>
<type>pom</type>
</dependency>
</dependencies>
</dependencyManagement>
StartApp.java:
package foo.bar;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.web.MultipartAutoConfiguration;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.context.web.SpringBootServletInitializer;
import org.springframework.context.annotation.Bean;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
#SpringBootApplication
#EnableAutoConfiguration(exclude = MultipartAutoConfiguration.class)
public class StartApp extends SpringBootServletInitializer {
#Override
protected SpringApplicationBuilder configure(
SpringApplicationBuilder application) {
return application.sources(StartApp.class);
}
public static void main(String[] args) {
SpringApplication.run(StartApp.class, args);
}
#Bean(name = "multipartResolver")
public MultipartResolver multipartResolver() {
CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver();
multipartResolver.setMaxInMemorySize(1024 * 1024 * 1024); // 1Go
return multipartResolver;
}
}
WS.java (only the relevant function) :
import static org.springframework.web.bind.annotation.RequestMethod.POST;
import java.io.IOException;
import java.io.InputStream;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
import service.DaoException;
import service.ErrCode;
import service.IService;
...
#Inject IService service;
...
#RequestMapping(path = "/insert/{foo}/{bar}", method = POST)
public ResponseEntity<Void> insert(#PathVariable String foo,
#PathVariable String bar,
#RequestParam MultipartFile document) {
HttpStatus httpCode = HttpStatus.CREATED;
try (InputStream is = document.getInputStream()) {
service.insert(foo, bar, is);
} catch (DaoException e) {
logger.error("Problème lors de l'insertion du document : "
+ e.getMessage());
httpCode = handleError(e.getCode());
} catch (IOException e1) {
logger.error("Problème lors du traitement du document envoyé : "
+ e1.getMessage());
httpCode = handleError(ErrCode.PB_TECHNIQUE);
}
return ResponseEntity.status(httpCode).build();
}
Simulation.scala :
import io.gatling.core.Predef._
import io.gatling.http.Predef._
import scala.concurrent.duration._
import java.nio.file.Files
import java.nio.file.Paths
import java.nio.file.Path
import java.util.Base64
import java.io.File
import java.lang.String
class RestSimulation1 extends Simulation {
val DEBIT = 30 //Clients per second
val DUREE = 300 //Duration
val httpConf = http
.baseURL("http://myserver:8080") // Here is the root for all relative urls
.acceptHeader("text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8") // Here are the common headers
.doNotTrackHeader("1")
.acceptLanguageHeader("en-US,en;q=0.5")
.acceptEncodingHeader("gzip, deflate")
.userAgentHeader("Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0")
//Feeders creation
val feeder = csv("9k_rest.csv").queue
object Insert {
val insert = feed(feeder)
.exec(http("insertion")
.post("/webservice/ws/insert/${fooo}/${bar}")
.formUpload("document", "rest_insert_${format}.txt")
.check(status.is(201)))
}
val scn = scenario("").exec(Insert.insert)
setUp(scn.inject( constantUsersPerSec(DEBIT) during(DUREE seconds))).protocols(httpConf)
}
What do I do wrong ?
Thank you for your help :)
I start with learning Spring and I create basic project which creates database, insert values and next print it in web browser.
My problem is that when I have RestController in the same package like main class - its OK, but I want distribute it to other package and when I create new package, move the RestController it doesn't work. Let met explain:
My project looks like:
|-Springtestv_01
|-src/main/java
|--com.person <-- it's a main package
|-Main.java
|-Person.java
|-PersonLineRunner.java
|-PersonRepository.java
|-PersonController.java
|-com.controller <-- second package, I want put here PersonController.java
|-src/main/resources
|-data.sql
pom.xml
My controller looks:
#RestController
public class PersonController {
#Autowired PersonRepository personRepository;
#RequestMapping("/persons")
Collection<Person> persons(){
return this.personRepository.findAll();
}
}
When everything is in com.person package, I write in web brower http://localhost:8080/persons and it works correctly...
But I Want move PersonController.java to com.controller package, and when I moved it, my webbrowers calls me
There was an unexpected error (type=Not Found, status=404). No message
available
and I have no idea what I should do to repair it. Maybe I should change something in my pom.xml ??
My pom.xml looks like
<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.person</groupId>
<artifactId>person</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpringTest_v0_1</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.3.0.BUILD-SNAPSHOT</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>com.h2database</groupId><artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>
spring-boot-starter-data-elasticsearch
</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>spring-snapshots</id>
<name>Spring Snapshots</name>
<url>https://repo.spring.io/snapshot</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</pluginRepository>
<pluginRepository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</pluginRepository>
</pluginRepositories>
</project>
It is generated automatically, I write only one dependency
<dependency>
<groupId>com.h2database</groupId><artifactId>h2</artifactId>
</dependency>
Use basePackages:
#ComponentScan(basePackages = { "com.person","com.controller"} )
I had the same problem the answers provided here worked for me but i had to add another spring annotation and it's more general in case dealing with a lot of repositories.
We have the following structure :
|-src/main/java
|--com.person
|--repositories
|--controllers
|--...
This then should be added in th main
#SpringBootApplication(scanBasePackages = {"com.person"})
#EnableMongoRepositories(basePackages = "com.person.repositories")
public class MainDemoApplication { //
}
Using a #SpringBootApplication annotation is equivalent to using #Configuration, #EnableAutoConfiguration and #ComponentScan.
From the documentation:
ComponentScan configures component scanning directives for use with
#Configuration classes. Provides support parallel with Spring XML's
element.
One of basePackageClasses(), basePackages() or its alias value() may
be specified to define specific packages to scan. If specific packages
are not defined scanning will occur from the package of the class with
this annotation.
You can either move it as you did or specify basePackages in #ComponentScan.
We can use #ComponentScan (basePackages = {"include your package name here"}).
Also if you have some common package naming format, then we can include just common part of package name with * like #ComponentScan(basePackages = { "com.*"}, so that all packages having that common package name will get scanned.
I had the same problem but suddenly found that my Application.java class (the class with main method and #SpringBootApplication annotation) located in different but parallel package with #Controller class.
The thing is that Application.java class should be in same or on top of all other packages, then we don't need any #ComponentScan and all beans will be scanned automatically. For example: if Application.java located in com.person and all application beans located in com.person, then it will work without #ComponentScan.
Assuming the main method is in the package called com.setech.app and a controller is in a package called com.setech.controller.
For spring-boot 1.3.x upwards try this by adding "scanBasePackages" like this.
#SpringBootApplication(scanBasePackages = { "com.setech"} )
public class ResttanslatorApplication {
public static void main(String[] args) {
SpringApplication.run(ResttanslatorApplication.class, args);
}
}
Credit goes to Kamil Wozniak from here.
Instead of using ComponentsScan, we can use #Import.
#Configuration
#Import({PersonController.class})
public class MainClassHome {
public static void main(String[] args) {
SpringApplication.run(MainClassHome.class, args);
}
}
For Maven Case: if you put the controller in another different sub-module(not same as main class), you should add dependency in pom.xml.
Moving the Springbootapplication(application.java) file to another package resolved the issue for me. Keep it separate from the controllers and repositories. You can use any number of packages and have multiple controllers.But use #ComponenScan(basePackages={" "," "}) and mention all the packages.
Also, you may face this issue Consider defining a bean of type.. click here!
You just only define a package name in #ComponentScan
like :
#SpringBootApplication
#ComponentScan({"com.project.pck_name"})
public class MainClassHome {
public static void main(String[] args) {
SpringApplication.run(MainClassHome.class, args);
}
}
and update project after that:- right click on Your project -> maven -> update project
As the one who has struggled with the issue, if you found provided solution didn't work.
Please check whether you put source files at the root level directly, for instance,
src\main\java\xxx.java
It has negative effect to project but I don't know the root cause. Anyway,
Please put source files to at least a self-created package like:
src\main\java\pack1\xxx.java
Try other settings again. It did solve my problem.
I find, that if you put the Controller classes in a separate jar, #Componentscan does not find the #RestControllers.
However, #SpringBootApplication(scanBasePackages =..
does that trick much better.
I used release train springboot spring-cloud-starter-parent, Greenwich.SR4
This resolves to spring boot 2.1.10.Release
So, in this release, #SpringBootApplication <> #Componentscan behaviour on that matter.
I'm trying to implement a custom mediator for WSO2 ESB (4.5.1) using its own XML configuration. I'm able to use the mediator just fine as a class mediator with the following config:
<class name="test.synapse.mediator.TestMediator"/>
However, what I'm trying to achieve is being able to call the mediator with a syntax like this:
<t:TestMediator xmlns:t="test:mediator" />
Having followed the available help on the matter for WSO2 ESB to the letter, I'm getting the following error as I try to create a proxy using the mediator with its own XML config:
ERROR - MediatorFactoryFinder Unknown mediator referenced by configuration element : {test:mediator}TestMediator
Needless to say, I've written the two text files containing the fully qualified class names of the mediator factory and serializer classes respectively and placed them in the META-INF/services directory in the bundle jar file.
This is the source code for my mediator class:
package test.synapse.mediator;
import org.apache.synapse.MessageContext;
import org.apache.synapse.mediators.AbstractMediator;
public class TestMediator extends AbstractMediator {
public boolean mediate(MessageContext context) {
System.out.println("TestMediator mediating!");
return true;
}
}
Here's the code for my mediator factory:
package test.synapse.mediator;
import java.util.Properties;
import javax.xml.namespace.QName;
import org.apache.axiom.om.OMElement;
import org.apache.synapse.Mediator;
import org.apache.synapse.config.xml.MediatorFactory;
public class TestMediatorFactory implements MediatorFactory {
public static final QName QNAME = new QName("test:mediator", "TestMediator");
#Override
public Mediator createMediator(OMElement omElement, Properties properties) {
return new TestMediator();
}
#Override
public QName getTagQName() {
return QNAME;
}
}
And the following is the code for my mediator serializer:
package test.synapse.mediator;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMFactory;
import org.apache.synapse.Mediator;
import org.apache.synapse.config.xml.MediatorSerializer;
public class TestMediatorSerializer implements MediatorSerializer {
public static final String MEDIATOR_CLASS_NAME = TestMediator.class.getName();
#Override
public String getMediatorClassName() {
return MEDIATOR_CLASS_NAME;
}
#Override
public OMElement serializeMediator(OMElement parent, Mediator mediator) {
OMFactory factory = OMAbstractFactory.getOMFactory();
OMElement element = factory.createOMElement(TestMediatorFactory.QNAME);
parent.addChild(element);
return element;
}
}
And finally, the somewhat lengthy content of the project's pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>test.synapse.mediator.TestMediator</groupId>
<artifactId>TestMediator</artifactId>
<version>1.0.0</version>
<packaging>bundle</packaging>
<name>TestMediator</name>
<description>TestMediator</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.4</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>TestMediator</Bundle-SymbolicName>
<Bundle-Name>TestMediator</Bundle-Name>
<Bundle-ClassPath>.</Bundle-ClassPath>
<Export-Package>test.synapse.mediator</Export-Package>
<Import-Package>*; resolution:=optional</Import-Package>
<Fragment-Host>synapse-core</Fragment-Host>
</instructions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<buildcommands>
<buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
</buildcommands>
<projectnatures>
<projectnature>org.wso2.developerstudio.eclipse.artifact.mediator.project.nature</projectnature>
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
</projectnatures>
</configuration>
</plugin>
</plugins>
<resources>
<resource>
<directory>src/main/resources/services</directory>
<targetPath>META-INF/services</targetPath>
</resource>
</resources>
</build>
<repositories>
<repository>
<releases>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>commons-httpclient.wso2</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1.0.wso2v2</version>
</dependency>
<dependency>
<groupId>commons-codec.wso2</groupId>
<artifactId>commons-codec</artifactId>
<version>1.4.0.wso2v1</version>
</dependency>
<dependency>
<groupId>org.apache.synapse</groupId>
<artifactId>synapse-core</artifactId>
<version>2.1.0-wso2v7</version>
</dependency>
<dependency>
<groupId>wsdl4j.wso2</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2.wso2v4</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.schema.wso2</groupId>
<artifactId>XmlSchema</artifactId>
<version>1.4.7.wso2v2</version>
</dependency>
<dependency>
<groupId>org.apache.abdera.wso2</groupId>
<artifactId>abdera</artifactId>
<version>1.0.0.wso2v3</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs.wso2</groupId>
<artifactId>geronimo-stax-api_1.0_spec</artifactId>
<version>1.0.1.wso2v2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.wso2</groupId>
<artifactId>httpcore</artifactId>
<version>4.1.0-wso2v1</version>
</dependency>
<dependency>
<groupId>org.apache.neethi.wso2</groupId>
<artifactId>neethi</artifactId>
<version>2.0.4.wso2v4</version>
</dependency>
<dependency>
<groupId>org.apache.axis2.wso2</groupId>
<artifactId>axis2</artifactId>
<version>1.6.1.wso2v6</version>
</dependency>
<dependency>
<groupId>org.apache.woden.wso2</groupId>
<artifactId>woden</artifactId>
<version>1.0.0.M8-wso2v1</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.axiom.wso2</groupId>
<artifactId>axiom</artifactId>
<version>1.2.11.wso2v3</version>
</dependency>
<dependency>
<groupId>commons-io.wso2</groupId>
<artifactId>commons-io</artifactId>
<version>2.0.0.wso2v2</version>
</dependency>
</dependencies>
<properties>
<CApp.type>lib/synapse/mediator</CApp.type>
</properties>
</project>
I've been experimenting for a long time changing various aspects of the pom-file and the code. I've come to notice, that I can call the mediator using the class-mediator if I leave out the Fragment-Host part of the configuration. If the Fragment-Host element is present, neither way of calling the mediator works.
As expected I'm using apache Maven to build a jar-file of the project. I'm dropping the jar to the <ESB_HOME>/repository/components/dropins-directory.
I've tried using WSO2 ESB 4.5.1 and 4.7.0 with the exact same results.
What must I change to get the custom XML configuration to work?
Any input would be greatly appreciated!
Attachments:
Zipped source at Dropbox: TestMediator.zip
Jar built using maven at Dropbox: TestMediator-1.0.0.jar
Seeing as there apparently is some bug in the WSO2 ESB itself, which causes the bundle containing the mediator and its factory and serializer not to get loaded in the case that its manifest contains a Fragment-Host definition I went for a slightly more complicated scenario to get my mediator to function using custom XML config.
Having used an activator class in the bundle to confirm that it doesn't get loaded it occurred to me that I could also use the activator to manually register the MediatorFactory and MediatorSerializer classes in the ESB.
I did this by writing the following activator for my OSGI bundle:
package test;
import java.text.MessageFormat;
import java.util.Map;
import org.apache.synapse.config.xml.MediatorFactoryFinder;
import org.apache.synapse.config.xml.MediatorSerializer;
import org.apache.synapse.config.xml.MediatorSerializerFinder;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import test.synapse.mediator.TestMediator;
import test.synapse.mediator.TestMediatorFactory;
import test.synapse.mediator.TestMediatorSerializer;
public class Activator implements BundleActivator {
public void start(BundleContext context) throws Exception {
{
Map<javax.xml.namespace.QName, java.lang.Class> mediatorFactoryMap = MediatorFactoryFinder.getInstance().getFactoryMap();
mediatorFactoryMap.put(TestMediatorFactory.QNAME, TestMediatorFactory.class);
}
{
Map<String, MediatorSerializer> mediatorSerializerMap = MediatorSerializerFinder.getInstance().getSerializerMap();
mediatorSerializerMap.put(TestMediator.class.getName(), TestMediatorSerializer.class.newInstance());
}
}
public void stop(BundleContext context) throws Exception {
// Maybe undo what was done in the start(BundleContext) method..?
System.out.println(this.getClass().getName() + ".stop(BundleContext) called");
}
}
Obviously the Activator class needs to be defined to be the activator for the bundle. This is done by adding the following node to the pom.xml bundle plugin configuration under the Instructions element:
<Bundle-Activator>test.Activator</Bundle-Activator>
Using this manual way of registering the factory and serializer classes the org.apache.synapse.config.xml.MediatorFactory and org.apache.synapse.config.xml.MediatorSerializer files are not needed and can be removed from the final jar.
Additionally the Fragment-Host element needs to be removed from the same parent node to actually have the activator class' start method get called.
Also the osgi core dependency containing the BundleActivator interface needs to be added.
By doing that we're left with the following complete pom.xml file:
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>test.synapse.mediator.TestMediator</groupId>
<artifactId>TestMediator</artifactId>
<version>1.0.0</version>
<packaging>bundle</packaging>
<name>TestMediator</name>
<description>TestMediator</description>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.4</version>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>TestMediator</Bundle-SymbolicName>
<Bundle-Name>TestMediator</Bundle-Name>
<Bundle-ClassPath>.</Bundle-ClassPath>
<Bundle-Activator>test.Activator</Bundle-Activator>
<Export-Package>test.synapse.mediator</Export-Package>
<Import-Package>*; resolution:=optional</Import-Package>
<!-- <Fragment-Host>synapse-core</Fragment-Host> -->
</instructions>
</configuration>
</plugin>
<plugin>
<artifactId>maven-eclipse-plugin</artifactId>
<version>2.9</version>
<configuration>
<buildcommands>
<buildcommand>org.eclipse.jdt.core.javabuilder</buildcommand>
</buildcommands>
<projectnatures>
<projectnature>org.wso2.developerstudio.eclipse.artifact.mediator.project.nature</projectnature>
<projectnature>org.eclipse.jdt.core.javanature</projectnature>
</projectnatures>
</configuration>
</plugin>
</plugins>
</build>
<repositories>
<repository>
<releases>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<releases>
<updatePolicy>daily</updatePolicy>
<checksumPolicy>ignore</checksumPolicy>
</releases>
<id>wso2-nexus</id>
<url>http://maven.wso2.org/nexus/content/groups/wso2-public/</url>
</pluginRepository>
</pluginRepositories>
<dependencies>
<dependency>
<groupId>commons-httpclient.wso2</groupId>
<artifactId>commons-httpclient</artifactId>
<version>3.1.0.wso2v2</version>
</dependency>
<dependency>
<groupId>commons-codec.wso2</groupId>
<artifactId>commons-codec</artifactId>
<version>1.4.0.wso2v1</version>
</dependency>
<dependency>
<groupId>org.apache.synapse</groupId>
<artifactId>synapse-core</artifactId>
<version>2.1.0-wso2v7</version>
</dependency>
<dependency>
<groupId>wsdl4j.wso2</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2.wso2v4</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.schema.wso2</groupId>
<artifactId>XmlSchema</artifactId>
<version>1.4.7.wso2v2</version>
</dependency>
<dependency>
<groupId>org.apache.abdera.wso2</groupId>
<artifactId>abdera</artifactId>
<version>1.0.0.wso2v3</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs.wso2</groupId>
<artifactId>geronimo-stax-api_1.0_spec</artifactId>
<version>1.0.1.wso2v2</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents.wso2</groupId>
<artifactId>httpcore</artifactId>
<version>4.1.0-wso2v1</version>
</dependency>
<dependency>
<groupId>org.apache.neethi.wso2</groupId>
<artifactId>neethi</artifactId>
<version>2.0.4.wso2v4</version>
</dependency>
<dependency>
<groupId>org.apache.axis2.wso2</groupId>
<artifactId>axis2</artifactId>
<version>1.6.1.wso2v6</version>
</dependency>
<dependency>
<groupId>org.apache.woden.wso2</groupId>
<artifactId>woden</artifactId>
<version>1.0.0.M8-wso2v1</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.ws.commons.axiom.wso2</groupId>
<artifactId>axiom</artifactId>
<version>1.2.11.wso2v3</version>
</dependency>
<dependency>
<groupId>commons-io.wso2</groupId>
<artifactId>commons-io</artifactId>
<version>2.0.0.wso2v2</version>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>5.0.0</version>
</dependency>
</dependencies>
<properties>
<CApp.type>lib/synapse/mediator</CApp.type>
</properties>
</project>
Having done these modifications and dropping the Maven built jar to the /repository/components/dropins directory the mediator finally works with its custom configuration.
I've zipped the complete final project source code. That archive also is available on Dropbox: TestMediator-final.zip
Edit
Upon additional experimentation it became apparent that the above approach doesn't work in WSO2 ESB 4.5.1, which is the platform I was originally trying to get this to work on. The code performs as expected in WSO2 4.7.0.
I haven't been able to get WSO2 ESB 4.5.1 (or 4.6.0) to call the activator's start(BundleContext) method no matter what I've tried.