commit e5847d637fc0df3fa41ab482586c44acd56a407e Author: Dominik Adam Przybysz <alien11689@gmail.com> Date: Sun Dec 7 20:07:31 2014 +0100 Initial commit diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..ed657e2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,71 @@ +<?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.blogspot.przybyszd.mockserver</groupId> + <artifactId>http-mock-server</artifactId> + <version>1.0.0-SNAPSHOT</version> + + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> + <maven-compiler-plugin.version>3.1</maven-compiler-plugin.version> + <groovy-eclipse-compiler.version>2.8.0-01</groovy-eclipse-compiler.version> + <groovy-eclipse-batch.version>2.1.8-01</groovy-eclipse-batch.version> + <groovy.version>2.3.3</groovy.version> + <httpclient.version>4.3.5</httpclient.version> + </properties> + + <dependencies> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy-all</artifactId> + <version>${groovy.version}</version> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents</groupId> + <artifactId>httpclient</artifactId> + <version>${httpclient.version}</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <artifactId>maven-compiler-plugin</artifactId> + <version>${maven-compiler-plugin.version}</version> + <configuration> + <compilerId>groovy-eclipse-compiler</compilerId> + </configuration> + <dependencies> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy-eclipse-compiler</artifactId> + <version>${groovy-eclipse-compiler.version}</version> + </dependency> + <dependency> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy-eclipse-batch</artifactId> + <version>${groovy-eclipse-batch.version}</version> + </dependency> + </dependencies> + </plugin> + <plugin> + <groupId>org.codehaus.groovy</groupId> + <artifactId>groovy-eclipse-compiler</artifactId> + <version>${groovy-eclipse-compiler.version}</version> + <extensions>true</extensions> + </plugin> + </plugins> + </build> + + <repositories> + <repository> + <id>sonatype-snapshots</id> + <url>https://oss.sonatype.org/content/repositories/snapshots/</url> + </repository> + </repositories> + +</project> \ No newline at end of file diff --git a/src/main/groovy/com/blogspot/przybyszd/mockserver/SoapMockServer.groovy b/src/main/groovy/com/blogspot/przybyszd/mockserver/SoapMockServer.groovy new file mode 100644 index 0000000..c48907c --- /dev/null +++ b/src/main/groovy/com/blogspot/przybyszd/mockserver/SoapMockServer.groovy @@ -0,0 +1,153 @@ +package com.blogspot.przybyszd.mockserver + +import com.sun.net.httpserver.HttpExchange +import com.sun.net.httpserver.HttpHandler +import com.sun.net.httpserver.HttpServer +import groovy.util.slurpersupport.GPathResult + +import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.CopyOnWriteArraySet +import java.util.concurrent.Executors + +class SoapMockServer { + + HttpServerWraper httpServerWraper + List<HttpServerWraper> childServers = new CopyOnWriteArrayList<>() + Set<String> actionsNames = new CopyOnWriteArraySet<>() + + SoapMockServer(int port = 9999){ + httpServerWraper= new HttpServerWraper(port) + + httpServerWraper.createContext('/serverControl', { + HttpExchange ex -> + ex.sendResponseHeaders(200, 0) + try{ + GPathResult request = new XmlSlurper().parse(ex.requestBody) + if(ex.requestMethod== 'POST' && request.name() == 'addMock'){ + String name = request.name + if(name in actionsNames){ + throw new RuntimeException('action already registered') + } + println "Adding $name" + String mockPath = request.path + int mockPort = Integer.valueOf(request.port as String) + Closure predicate = Eval.me(request.predicate as String) as Closure + Closure okResponse = Eval.me(request.response as String) as Closure + Action action = new Action(name, predicate, okResponse) + HttpServerWraper child = childServers.find {it.port == mockPort} + if(!child){ + child = new HttpServerWraper(mockPort) + childServers << child + } + child.addAction(mockPath, action) + actionsNames << name + ex.responseBody << '<addedAction/>' + ex.responseBody.close() + } + }catch(Exception e){ + ex.responseBody << """<exceptionOccured>${e.message}</exceptionOccured>""" + ex.responseBody.close() + } + //TODO add delete mock + //TODO add list mock + }) + } + + void stop(){ + childServers.each {it.stop()} + httpServerWraper.stop() + } + + private static final class HttpServerWraper{ + final HttpServer httpServer + final int port + + List<ContextExecutor> executors = [] + + HttpServerWraper(int port){ + this.port = port + InetSocketAddress addr = new InetSocketAddress(Inet4Address.getByName("0.0.0.0"), port) + httpServer = HttpServer.create(addr, 0) + httpServer.executor = Executors.newCachedThreadPool() + println "Http server statrting on port $port..." + httpServer.start() + println 'Http server is started' + } + + void createContext(String context, HttpHandler handler){ + httpServer.createContext(context, handler) + } + + void addAction(String path, Action action){ + ContextExecutor executor = executors.find {it.path == path} + if(executor){ + executor.actions.add(action) + }else { + executors.add(new ContextExecutor(this, path, action)) + } + } + + void removeAction(String name){ + //TODO delete action by name + } + + void stop(){ + executors.each {httpServer.removeContext(it.path)} + httpServer.stop(0) + } + } + + private static final class ContextExecutor{ + final HttpServerWraper httpServerWraper + final String path + List<Action> actions + + ContextExecutor(HttpServerWraper httpServerWraper, String path, Action initialAction) { + this.httpServerWraper = httpServerWraper + this.path = path + this.actions = new CopyOnWriteArrayList<>([initialAction]) + httpServerWraper.createContext(path,{ + HttpExchange ex -> + ex.sendResponseHeaders(200, 0) + String input = ex.requestBody.text + println "Mock received input" + GPathResult xml = new XmlSlurper().parseText(input) + for (Action action : actions){ + if(action.predicate(xml)){ + ex.responseBody << action.responseOk(xml) + ex.responseBody.close() + return + } + } + ex.responseBody << "<invalidInput/>" + ex.responseBody.close() + }) + } + } + + private static final class Action{ + final String name + final Closure predicate + final Closure responseOk + + Action(String name, Closure predicate, Closure responseOk) { + this.name = name + this.predicate = predicate + this.responseOk = responseOk + } + } + + static void main(String [] args) { + SoapMockServer soapMockServer = new SoapMockServer() + + Runtime.runtime.addShutdownHook(new Thread({ + println 'Http server is stopping...' + soapMockServer.stop() + println 'Http server is stopped' + } as Runnable)) + + while(true){ + Thread.sleep(10000) + } + } +}