Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Build on & fully support JDK 17 #1655

Closed
timtebeek opened this issue Oct 16, 2021 · 19 comments · Fixed by #1695
Closed

Build on & fully support JDK 17 #1655

timtebeek opened this issue Oct 16, 2021 · 19 comments · Fixed by #1695

Comments

@timtebeek
Copy link
Contributor

Had a brief look at building on JDK 17, branched off the work Jamie's done for Gradle 7 in #1633.

It appears the use of sun.security.x509 crypto is problematic on JDK 17.
From what I can see this was mostly contributed mid last year by @Mahoney
Hoping he can advice on what's best to future proof this bit of code.
Bouncy castle seems rather hefty; perhaps we can spin this off into a separate extension?

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 18, 2021

We need to be able to generate self signed TLS certificates on the fly for the HTTPS interception feature.

Bouncy castle did indeed seem rather hefty, hence the decision to use the internal sun package. I am not aware of any alternative to bouncy castle, but I can't claim to have looked much recently.

Other alternatives... we could call out to the keytool? Not sure how easy that will be... I note that our example script uses openssl rather than the keytool to create a certificate:
https://github.com/wiremock/wiremock/blob/master/scripts/create-ca-keystore.sh

In the absence of an alternative way to generate them:

  • We can fix the compilation by adding --add-exports=java.base/sun.security.x509=ALL-UNNAMED as a compiler argument.
  • We can add Add-Exports: java.base/sun.security.x509 to WireMock's META-INF/MANIFEST.MF - this should fix running WireMock standalone. However it isn't transitive - anything running using WireMock as a library will not be fixed by this.
  • apps using WireMock can add Add-Exports: java.base/sun.security.x509 to their META-INF/MANIFEST.MF or can be run with --add-exports=java.base/sun.security.x509=ALL-UNNAMED
    This would include all the people running WireMock via JUnit - they'll have to add that argument to their run configurations. We can add documentation, including how to change the default JUnit configuration on IntelliJ to include that argument, but that doesn't really scale... certainly makes a big barrier to "just works".

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 18, 2021

We could certainly look into spinning it off - I don't think it's needed for anything other than HTTPS traffic proxying.

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 18, 2021

Might be useful info on generating via keytool:
https://stackoverflow.com/a/61674251

@tomakehurst
Copy link
Member

Presumably by calling out to keytool you mean via a shell?

If so, I'd worry a bit about OS foibles and ability to run on a minimal JRE.

@tomakehurst
Copy link
Member

I've just run a standalone build (built with JDK11) on JDK17 without any changes or extra CLI flags and it worked OK.

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 20, 2021

Presumably by calling out to keytool you mean via a shell?

If so, I'd worry a bit about OS foibles and ability to run on a minimal JRE.

Yes, that was what I meant. I agree, not ideal.

I've just run a standalone build (built with JDK11) on JDK17 without any changes or extra CLI flags and it worked OK.

Interesting - perhaps the classes don't load unless you are forward/browser proxying? I can't remember without digging in.

@tomakehurst
Copy link
Member

Sorry, should have mentioned - I enabled browser proxying and downloaded (and checked) the CA cert. All worked fine.

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 20, 2021

Just did likewise - it starts OK, but fails to proxy to an https website. Precisely the same commands work under Java 11. Stops working in Java 13 (haven't got Java 12 installed). No errors logged to the console.

java -jar wiremock-jre8-standalone-2.31.0.jar --enable-browser-proxying
curl -v -x localhost:8080 https://www.example.com/

curl: (35) LibreSSL SSL_connect: SSL_ERROR_ZERO_RETURN in connection to www.example.com:443

@tomakehurst
Copy link
Member

Ah, I didn't try that bit. Strange that it generates the cert OK but fails on the actual proxying.

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 20, 2021

I'm fairly sure it is the certificate generation that's causing the failure, using a debugger.

So tentatively it looks like we're OK unless you are browser/forward proxying HTTPS?

@tomakehurst
Copy link
Member

I'm fairly sure it is the certificate generation that's causing the failure, using a debugger.

I'd forgotten that we cache the CA cert. As soon as I deleted my cached copy it failed to start, so that makes sense now at least.

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 20, 2021

But only if you enable browser proxying, at least - it starts OK otherwise. So the damage is relatively limited. And we can fix it for anyone running standalone by adding the manifest entry, which just leaves people programatically starting WireMock with browser proxying.

@tomakehurst
Copy link
Member

So tentatively it looks like we're OK unless you are browser/forward proxying HTTPS?

As far as I can tell, yes.

And adding --add-exports=java.base/sun.security.x509=ALL-UNNAMED to the standalone command fixes it so we can add this to the docs for the time being.

Long term, I'm starting to like @timtebeek's suggestion that we spin cert generation off into a library. We could possibly still use Bouncycastle, but shade and Proguard it to make it small.

Unless there are new crypto APIs available in Java 11+ we could use instead?

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 20, 2021

No, just the same old sun.security.x509 ones as far as I can see.

@Mahoney
Copy link
Collaborator

Mahoney commented Oct 20, 2021

Raised #1665

@EmilyStacy
Copy link

We need to be able to generate self signed TLS certificates on the fly for the HTTPS interception feature.

Bouncy castle did indeed seem rather hefty, hence the decision to use the internal sun package. I am not aware of any alternative to bouncy castle, but I can't claim to have looked much recently.

Other alternatives... we could call out to the keytool? Not sure how easy that will be... I note that our example script uses openssl rather than the keytool to create a certificate: https://github.com/wiremock/wiremock/blob/master/scripts/create-ca-keystore.sh

In the absence of an alternative way to generate them:

  • We can fix the compilation by adding --add-exports=java.base/sun.security.x509=ALL-UNNAMED as a compiler argument.
  • We can add Add-Exports: java.base/sun.security.x509 to WireMock's META-INF/MANIFEST.MF - this should fix running WireMock standalone. However it isn't transitive - anything running using WireMock as a library will not be fixed by this.
  • apps using WireMock can add Add-Exports: java.base/sun.security.x509 to their META-INF/MANIFEST.MF or can be run with --add-exports=java.base/sun.security.x509=ALL-UNNAMED
    This would include all the people running WireMock via JUnit - they'll have to add that argument to their run configurations. We can add documentation, including how to change the default JUnit configuration on IntelliJ to include that argument, but that doesn't really scale... certainly makes a big barrier to "just works".

It didn't work in our case. Is it because we are using testng? Or we need to wait for some changes merged to wiremock first? BTW we are using version jre8-2.31.0 now.

@tomakehurst
Copy link
Member

@EmilyStacy can you post details so we can try to reproduce the error you're seeing?

@EmilyStacy
Copy link

EmilyStacy commented Nov 1, 2021

@EmilyStacy can you post details so we can try to reproduce the error you're seeing?

This is the dependency in our build.gradle:
testImplementation "com.github.tomakehurst:wiremock-jre8:2.31.0"

This is the test case setting with dependencies:

`
import java.net.URI;
import java.util.UUID;

import javax.ws.rs.client.Client;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.UriBuilder;

import org.mockito.Mockito;
import org.testng.Assert;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import com.github.tomakehurst.wiremock.WireMockServer;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.core.WireMockConfiguration;

private WireMockServer mockServer;
private Client client;
private String wiremockUrl;

@BeforeClass
public void setup() {
mockServer = new WireMockServer(WireMockConfiguration.options().dynamicPort());
mockServer.start();
client = getClient();
WireMock.configureFor("localhost", mockServer.port());
wiremockUrl = "http://localhost:" + mockServer.port();
}

@afterclass
public void tearDown() {
mockServer.stop();
}

@test
public void randomTestCase(){
UUID deviceId = UUID.randomUUID();
URI uri = UriBuilder.fromUri(URIConstant)
.resolveTemplate("deviceId", deviceId)
.build();

mockServer.stubFor(WireMock.patch(WireMock.urlEqualTo(uri.toString()))
.willReturn(WireMock.aResponse()
.withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON)
.withStatus(Response.Status.OK.getStatusCode())));

(some specific mocking for our logic)
WireMock.verify(WireMock.patchRequestedFor(WireMock.urlEqualTo(uri.toString())));
}

`

this is the read-only WiremockServer class:

`/

  • Copyright (C) 2011 Thomas Akehurst

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 com.github.tomakehurst.wiremock;

import com.github.tomakehurst.wiremock.admin.model.;
import com.github.tomakehurst.wiremock.client.CountMatchingStrategy;
import com.github.tomakehurst.wiremock.client.MappingBuilder;
import com.github.tomakehurst.wiremock.client.VerificationException;
import com.github.tomakehurst.wiremock.client.WireMock;
import com.github.tomakehurst.wiremock.common.
;
import com.github.tomakehurst.wiremock.core.Admin;
import com.github.tomakehurst.wiremock.core.Container;
import com.github.tomakehurst.wiremock.core.Options;
import com.github.tomakehurst.wiremock.core.WireMockApp;
import com.github.tomakehurst.wiremock.global.GlobalSettings;
import com.github.tomakehurst.wiremock.global.GlobalSettingsHolder;
import com.github.tomakehurst.wiremock.http.HttpServer;
import com.github.tomakehurst.wiremock.http.HttpServerFactory;
import com.github.tomakehurst.wiremock.http.RequestListener;
import com.github.tomakehurst.wiremock.http.StubRequestHandler;
import com.github.tomakehurst.wiremock.junit.Stubbing;
import com.github.tomakehurst.wiremock.matching.RequestPattern;
import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder;
import com.github.tomakehurst.wiremock.matching.StringValuePattern;
import com.github.tomakehurst.wiremock.recording.RecordingStatusResult;
import com.github.tomakehurst.wiremock.recording.SnapshotRecordResult;
import com.github.tomakehurst.wiremock.recording.RecordSpec;
import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder;
import com.github.tomakehurst.wiremock.standalone.MappingsLoader;
import com.github.tomakehurst.wiremock.stubbing.ServeEvent;
import com.github.tomakehurst.wiremock.stubbing.StubImport;
import com.github.tomakehurst.wiremock.stubbing.StubMapping;
import com.github.tomakehurst.wiremock.stubbing.StubMappingJsonRecorder;
import com.github.tomakehurst.wiremock.verification.*;

import java.util.List;
import java.util.UUID;

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig;
import static com.google.common.base.Preconditions.checkState;

public class WireMockServer implements Container, Stubbing, Admin {

private final WireMockApp wireMockApp;
private final StubRequestHandler stubRequestHandler;
private final HttpServer httpServer;
private final Notifier notifier;
protected final Options options;
protected final WireMock client;
public WireMockServer(Options options) {
this.options = options;
this.notifier = options.notifier();

    wireMockApp = new WireMockApp(options, this);

    this.stubRequestHandler = wireMockApp.buildStubRequestHandler();
    HttpServerFactory httpServerFactory = options.httpServerFactory();
    httpServer = httpServerFactory.buildHttpServer(
            options,
            wireMockApp.buildAdminRequestHandler(),
            stubRequestHandler
    );

    client = new WireMock(wireMockApp);
}

public WireMockServer(int port, Integer httpsPort, FileSource fileSource, boolean 

enableBrowserProxying, ProxySettings proxySettings, Notifier notifier) {
this(wireMockConfig()
.port(port)
.httpsPort(httpsPort)
.fileSource(fileSource)
.enableBrowserProxying(enableBrowserProxying)
.proxyVia(proxySettings)
.notifier(notifier));
}

public WireMockServer(int port, FileSource fileSource, boolean enableBrowserProxying, ProxySettings proxySettings) {
    this(wireMockConfig()
            .port(port)
            .fileSource(fileSource)
            .enableBrowserProxying(enableBrowserProxying)
            .proxyVia(proxySettings));
}

public WireMockServer(int port, FileSource fileSource, boolean enableBrowserProxying) {
    this(wireMockConfig()
            .port(port)
            .fileSource(fileSource)
            .enableBrowserProxying(enableBrowserProxying));
}

public WireMockServer(int port) {
	this(wireMockConfig().port(port));
}

public WireMockServer(int port, Integer httpsPort) {
    this(wireMockConfig().port(port).httpsPort(httpsPort));
}

public WireMockServer() {
	this(wireMockConfig());
}

public void loadMappingsUsing(final MappingsLoader mappingsLoader) {
    wireMockApp.loadMappingsUsing(mappingsLoader);
}

public GlobalSettingsHolder getGlobalSettingsHolder() {
    return wireMockApp.getGlobalSettingsHolder();
}

public void addMockServiceRequestListener(RequestListener listener) {
	stubRequestHandler.addRequestListener(listener);
}

public void enableRecordMappings(FileSource mappingsFileSource, FileSource filesFileSource) {
    addMockServiceRequestListener(
            new StubMappingJsonRecorder(mappingsFileSource, filesFileSource, wireMockApp, options.matchingHeaders()));
    notifier.info("Recording mappings to " + mappingsFileSource.getPath());
}

public void stop() {
    httpServer.stop();
}

public void start() {
    // Try to ensure this is warmed up on the main thread so that it's inherited by worker threads
    Json.getObjectMapper();
    try {
	    httpServer.start();
    } catch (Exception e) {
        throw new FatalStartupException(e);
    }
}

/*
 * Gracefully shutdown the server.
  This method assumes it is being called as the result of an incoming HTTP request.
 */
@Override
public void shutdown() {
    final WireMockServer server = this;
    Thread shutdownThread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                // We have to sleep briefly to finish serving the shutdown request before stopping the server, as
                // there's no support in Jetty for shutting down after the current request.
                // See http://stackoverflow.com/questions/4650713
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            server.stop();
        }
    });
    shutdownThread.start();
}

public boolean isHttpEnabled() {
    return !options.getHttpDisabled();
}

public boolean isHttpsEnabled() {
    return options.httpsSettings().enabled();
}

public int port() {
    checkState(
        isRunning() && !options.getHttpDisabled(),
        "Not listening on HTTP port. Either HTTP is not enabled or the WireMock server is stopped."
    );
    return httpServer.port();
}

public int httpsPort() {
    checkState(
            isRunning() && options.httpsSettings().enabled(),
            "Not listening on HTTPS port. Either HTTPS is not enabled or the WireMock server is stopped."
    );
    return httpServer.httpsPort();
}

public String url(String path) {
    if (!path.startsWith("/")) {
        path = "/" + path;
    }

    return String.format("%s%s", baseUrl(), path);
}

public String baseUrl() {
    boolean https = options.httpsSettings().enabled();
    String protocol = https ? "https" : "http";
    int port = https ? httpsPort() : port();

    return String.format("%s://localhost:%d", protocol, port);
}

public boolean isRunning() {
    return httpServer.isRunning();
}

@Override
public StubMapping givenThat(MappingBuilder mappingBuilder) {
    return client.register(mappingBuilder);
}

@Override
public StubMapping stubFor(MappingBuilder mappingBuilder) {
    return givenThat(mappingBuilder);
}

@Override
public void editStub(MappingBuilder mappingBuilder) {
    client.editStubMapping(mappingBuilder);
}

@Override
public void removeStub(MappingBuilder mappingBuilder) {
    client.removeStubMapping(mappingBuilder);
}

@Override
public void removeStub(StubMapping stubMapping) {
    client.removeStubMapping(stubMapping);
}

@Override
public List<StubMapping> getStubMappings() {
    return client.allStubMappings().getMappings();
}

@Override
public StubMapping getSingleStubMapping(UUID id) {
    return client.getStubMapping(id).getItem();
}

@Override
public List<StubMapping> findStubMappingsByMetadata(StringValuePattern pattern) {
    return client.findAllStubsByMetadata(pattern);
}

@Override
public void removeStubMappingsByMetadata(StringValuePattern pattern) {
    client.removeStubsByMetadataPattern(pattern);
}

@Override
public void removeStubMapping(StubMapping stubMapping){
    wireMockApp.removeStubMapping(stubMapping);
}

@Override
public void verify(RequestPatternBuilder requestPatternBuilder) {
    client.verifyThat(requestPatternBuilder);
}

@Override
public void verify(int count, RequestPatternBuilder requestPatternBuilder) {
    client.verifyThat(count, requestPatternBuilder);
}

@Override
public void verify(CountMatchingStrategy countMatchingStrategy, RequestPatternBuilder requestPatternBuilder) {
    client.verifyThat(countMatchingStrategy, requestPatternBuilder);
}

@Override
public List<LoggedRequest> findAll(RequestPatternBuilder requestPatternBuilder) {
    return client.find(requestPatternBuilder);
}

@Override
public List<ServeEvent> getAllServeEvents() {
    return client.getServeEvents();
}

@Override
public void setGlobalFixedDelay(int milliseconds) {
    client.setGlobalFixedDelayVariable(milliseconds);
}

@Override
public List<LoggedRequest> findAllUnmatchedRequests() {
    return client.findAllUnmatchedRequests();
}

@Override
public List<NearMiss> findNearMissesForAllUnmatchedRequests() {
    return client.findNearMissesForAllUnmatchedRequests();
}

@Override
public List<NearMiss> findAllNearMissesFor(RequestPatternBuilder requestPatternBuilder) {
    return client.findAllNearMissesFor(requestPatternBuilder);
}

@Override
public List<NearMiss> findNearMissesFor(LoggedRequest loggedRequest) {
    return client.findTopNearMissesFor(loggedRequest);
}

@Override
public void addStubMapping(StubMapping stubMapping) {
    wireMockApp.addStubMapping(stubMapping);
}

@Override
public void editStubMapping(StubMapping stubMapping) {
    wireMockApp.editStubMapping(stubMapping);
}

@Override
public ListStubMappingsResult listAllStubMappings() {
    return wireMockApp.listAllStubMappings();
}

@Override
public SingleStubMappingResult getStubMapping(UUID id) {
    return wireMockApp.getStubMapping(id);
}

@Override
public void saveMappings() {
    wireMockApp.saveMappings();
}

@Override
public void resetAll() {
    wireMockApp.resetAll();
}

@Override
public void resetRequests() {
    wireMockApp.resetRequests();
}

@Override
public void resetToDefaultMappings() {
    wireMockApp.resetToDefaultMappings();
}

@Override
public GetServeEventsResult getServeEvents() {
    return wireMockApp.getServeEvents();
}

@Override
public SingleServedStubResult getServedStub(UUID id) {
    return wireMockApp.getServedStub(id);
}

@Override
public void resetScenarios() {
    wireMockApp.resetScenarios();
}

@Override
public void resetMappings() {
    wireMockApp.resetMappings();
}

@Override
public VerificationResult countRequestsMatching(RequestPattern requestPattern) {
    return wireMockApp.countRequestsMatching(requestPattern);
}

@Override
public FindRequestsResult findRequestsMatching(RequestPattern requestPattern) {
    return wireMockApp.findRequestsMatching(requestPattern);
}

@Override
public FindRequestsResult findUnmatchedRequests() {
    return wireMockApp.findUnmatchedRequests();
}

@Override
public void removeServeEvent(UUID eventId) {
    wireMockApp.removeServeEvent(eventId);
}

@Override
public FindServeEventsResult removeServeEventsMatching(RequestPattern requestPattern) {
    return wireMockApp.removeServeEventsMatching(requestPattern);
}

@Override
public FindServeEventsResult removeServeEventsForStubsMatchingMetadata(StringValuePattern metadataPattern) {
    return wireMockApp.removeServeEventsForStubsMatchingMetadata(metadataPattern);
}

@Override
public void updateGlobalSettings(GlobalSettings newSettings) {
    wireMockApp.updateGlobalSettings(newSettings);
}

@Override
public FindNearMissesResult findNearMissesForUnmatchedRequests() {
    return wireMockApp.findNearMissesForUnmatchedRequests();
}

@Override
public GetScenariosResult getAllScenarios() {
    return wireMockApp.getAllScenarios();
}

@Override
public FindNearMissesResult findTopNearMissesFor(LoggedRequest loggedRequest) {
    return wireMockApp.findTopNearMissesFor(loggedRequest);
}

@Override
public FindNearMissesResult findTopNearMissesFor(RequestPattern requestPattern) {
    return wireMockApp.findTopNearMissesFor(requestPattern);
}

@Override
public void startRecording(String targetBaseUrl) {
    wireMockApp.startRecording(targetBaseUrl);
}

@Override
public void startRecording(RecordSpec spec) {
    wireMockApp.startRecording(spec);
}

@Override
public void startRecording(RecordSpecBuilder recordSpec) {
    wireMockApp.startRecording(recordSpec);
}

@Override
public SnapshotRecordResult stopRecording() {
    return wireMockApp.stopRecording();
}

@Override
public RecordingStatusResult getRecordingStatus() {
    return wireMockApp.getRecordingStatus();
}

@Override
public SnapshotRecordResult snapshotRecord() {
    return wireMockApp.snapshotRecord();
}

@Override
public SnapshotRecordResult snapshotRecord(RecordSpecBuilder spec) {
    return wireMockApp.snapshotRecord(spec);
}

@Override
public SnapshotRecordResult snapshotRecord(RecordSpec spec) {
    return wireMockApp.snapshotRecord(spec);
}

@Override
public Options getOptions() {
    return options;
}

@Override
public void shutdownServer() {
    shutdown();
}

@Override
public ListStubMappingsResult findAllStubsByMetadata(StringValuePattern pattern) {
    return wireMockApp.findAllStubsByMetadata(pattern);
}

@Override
public void removeStubsByMetadata(StringValuePattern pattern) {
    wireMockApp.removeStubsByMetadata(pattern);
}

@Override
public void importStubs(StubImport stubImport) {
    wireMockApp.importStubs(stubImport);
}

@Override
public GetGlobalSettingsResult getGlobalSettings() {
    return wireMockApp.getGlobalSettings();
}

public void checkForUnmatchedRequests() {
    List<LoggedRequest> unmatchedRequests = findAllUnmatchedRequests();
    if (!unmatchedRequests.isEmpty()) {
        List<NearMiss> nearMisses = findNearMissesForAllUnmatchedRequests();
        if (nearMisses.isEmpty()) {
            throw VerificationException.forUnmatchedRequests(unmatchedRequests);
        } else {
            throw VerificationException.forUnmatchedNearMisses(nearMisses);
        }
    }
}

}
`
and this is the readonly Wiremock class:

`/ Copyright (C) 2011 Thomas Akehurst

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 com.github.tomakehurst.wiremock.client;

import com.github.tomakehurst.wiremock.admin.model.ListStubMappingsResult;
import com.github.tomakehurst.wiremock.admin.model.SingleStubMappingResult;
import com.github.tomakehurst.wiremock.common.;
import com.github.tomakehurst.wiremock.stubbing.
;
import com.github.tomakehurst.wiremock.core.Admin;
import com.github.tomakehurst.wiremock.extension.Parameters;
import com.github.tomakehurst.wiremock.global.GlobalSettings;
import com.github.tomakehurst.wiremock.global.GlobalSettingsHolder;
import com.github.tomakehurst.wiremock.http.DelayDistribution;
import com.github.tomakehurst.wiremock.http.Request;
import com.github.tomakehurst.wiremock.http.RequestMethod;
import com.github.tomakehurst.wiremock.matching.;
import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder;
import com.github.tomakehurst.wiremock.recording.RecordingStatusResult;
import com.github.tomakehurst.wiremock.recording.SnapshotRecordResult;
import com.github.tomakehurst.wiremock.security.ClientAuthenticator;
import com.github.tomakehurst.wiremock.standalone.RemoteMappingsLoader;
import com.github.tomakehurst.wiremock.verification.
;
import com.github.tomakehurst.wiremock.verification.diff.Diff;

import java.io.File;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import static com.github.tomakehurst.wiremock.matching.RequestPattern.thatMatch;
import static com.github.tomakehurst.wiremock.matching.RequestPatternBuilder.allRequests;
import static com.google.common.collect.FluentIterable.from;
import static com.google.common.net.HttpHeaders.CONTENT_TYPE;
import static com.google.common.net.HttpHeaders.LOCATION;

public class WireMock {

private static final int DEFAULT_PORT = 8080;
private static final String DEFAULT_HOST = "localhost";

private final Admin admin;
private final GlobalSettingsHolder globalSettingsHolder = new GlobalSettingsHolder();

private static InheritableThreadLocal<WireMock> defaultInstance = new InheritableThreadLocal<WireMock>(){
        @Override
        protected WireMock initialValue() {
        	return WireMock.create().build();
        }
};

public static WireMockBuilder create() {
    return new WireMockBuilder();
}

public WireMock(Admin admin) {
    this.admin = admin;
}

public WireMock(int port) {
    this(DEFAULT_HOST, port);
}

public WireMock(String host, int port) {
	admin = new HttpAdminClient(host, port);
}

public WireMock(String host, int port, String urlPathPrefix) {
	admin = new HttpAdminClient(host, port, urlPathPrefix);
}

public WireMock(String scheme, String host, int port) {
	admin = new HttpAdminClient(scheme, host, port);
}

public WireMock(String scheme, String host, int port, String urlPathPrefix) {
	admin = new HttpAdminClient(scheme, host, port, urlPathPrefix);
}

public WireMock(String scheme, String host, int port, String urlPathPrefix, String hostHeader, String proxyHost, int proxyPort, ClientAuthenticator authenticator) {
    admin = new HttpAdminClient(scheme, host, port, urlPathPrefix, hostHeader, proxyHost, proxyPort, authenticator);
}

public WireMock() {
	admin = new HttpAdminClient(DEFAULT_HOST, DEFAULT_PORT);
}

public static StubMapping givenThat(MappingBuilder mappingBuilder) {
	return defaultInstance.get().register(mappingBuilder);
}

public static StubMapping stubFor(MappingBuilder mappingBuilder) {
	return givenThat(mappingBuilder);
}

public static void editStub(MappingBuilder mappingBuilder) {
	defaultInstance.get().editStubMapping(mappingBuilder);
}

public static void removeStub(MappingBuilder mappingBuilder) {
	defaultInstance.get().removeStubMapping(mappingBuilder);
}

public static void removeStub(StubMapping stubMapping) {
    defaultInstance.get().removeStubMapping(stubMapping);
}

public static ListStubMappingsResult listAllStubMappings() {
    return defaultInstance.get().allStubMappings();
}

public static StubMapping getSingleStubMapping(UUID id) {
    return defaultInstance.get().getStubMapping(id).getItem();
}

public static void configureFor(int port) {
    defaultInstance.set(WireMock.create().port(port).build());
}

public static void configureFor(String host, int port) {
	defaultInstance.set(WireMock.create().host(host).port(port).build());
}

public static void configureFor(String host, int port, String urlPathPrefix) {
	defaultInstance.set(WireMock.create().host(host).port(port).urlPathPrefix(urlPathPrefix).build());
}

public static void configureFor(String scheme, String host, int port, String urlPathPrefix) {
	defaultInstance.set(WireMock.create().scheme(scheme).host(host).port(port).urlPathPrefix(urlPathPrefix).build());
}

public static void configureFor(String scheme, String host, int port) {
	defaultInstance.set(WireMock.create().scheme(scheme).host(host).port(port).build());
}

public static void configureFor(String scheme, String host, int port, String proxyHost, int proxyPort) {
    defaultInstance.set(WireMock.create().scheme(scheme).host(host).port(port).urlPathPrefix("").hostHeader(null).proxyHost(proxyHost).proxyPort(proxyPort).build());
}

public static void configureFor(WireMock client) {
    defaultInstance.set(client);
}

public static void configure() {
	defaultInstance.set(WireMock.create().build());
}

public static StringValuePattern equalTo(String value) {
    return new EqualToPattern(value);
}

public static BinaryEqualToPattern binaryEqualTo(byte[] content) {
    return new BinaryEqualToPattern(content);
}

public static BinaryEqualToPattern binaryEqualTo(String content) {
    return new BinaryEqualToPattern(content);
}

public static StringValuePattern equalToIgnoreCase(String value) {
	return new EqualToPattern(value, true);
}

public static StringValuePattern equalToJson(String value) {
    return new EqualToJsonPattern(value, null, null);
}

public static StringValuePattern equalToJson(String value, boolean ignoreArrayOrder, boolean ignoreExtraElements) {
    return new EqualToJsonPattern(value, ignoreArrayOrder, ignoreExtraElements);
}

public static StringValuePattern matchingJsonPath(String value) {
    return new MatchesJsonPathPattern(value);
}

public static StringValuePattern matchingJsonPath(String value, StringValuePattern valuePattern) {
    return new MatchesJsonPathPattern(value, valuePattern);
}

public static EqualToXmlPattern equalToXml(String value) {
    return new EqualToXmlPattern(value);
}

public static EqualToXmlPattern equalToXml(String value, boolean enablePlaceholders) {
    return new EqualToXmlPattern(value, enablePlaceholders, null, null, null);
}

public static EqualToXmlPattern equalToXml(String value, boolean enablePlaceholders, String placeholderOpeningDelimiterRegex, String placeholderClosingDelimiterRegex) {
    return new EqualToXmlPattern(value, enablePlaceholders, placeholderOpeningDelimiterRegex, placeholderClosingDelimiterRegex, null);
}

public static MatchesXPathPattern matchingXPath(String value) {
    return new MatchesXPathPattern(value, Collections.<String, String>emptyMap());
}

public static StringValuePattern matchingXPath(String value, Map<String, String> namespaces) {
    return new MatchesXPathPattern(value, namespaces);
}

public static StringValuePattern matchingXPath(String value, StringValuePattern valuePattern) {
    return new MatchesXPathPattern(value, valuePattern);
}

// Use this with the date/time matchers to avoid an explicit cast
public static MatchesXPathPattern matchesXPathWithSubMatcher(String value, StringValuePattern valuePattern) {
    return new MatchesXPathPattern(value, valuePattern);
}

public static StringValuePattern containing(String value) {
    return new ContainsPattern(value);
}

public static StringValuePattern matching(String regex) {
    return new RegexPattern(regex);
}

public static StringValuePattern notMatching(String regex) {
    return new NegativeRegexPattern(regex);
}

public static BeforeDateTimePattern before(String dateTimeSpec) {
    return new BeforeDateTimePattern(dateTimeSpec);
}

public static BeforeDateTimePattern before(ZonedDateTime dateTime) {
    return new BeforeDateTimePattern(dateTime);
}

public static BeforeDateTimePattern before(LocalDateTime dateTime) {
    return new BeforeDateTimePattern(dateTime);
}

public static BeforeDateTimePattern beforeNow() {
    return new BeforeDateTimePattern("now");
}

public static EqualToDateTimePattern equalToDateTime(String dateTimeSpec) {
    return new EqualToDateTimePattern(dateTimeSpec);
}

public static EqualToDateTimePattern equalToDateTime(ZonedDateTime dateTime) {
    return new EqualToDateTimePattern(dateTime);
}

public static EqualToDateTimePattern equalToDateTime(LocalDateTime dateTime) {
    return new EqualToDateTimePattern(dateTime);
}

public static EqualToDateTimePattern isNow() {
    return new EqualToDateTimePattern("now");
}

public static AfterDateTimePattern after(String dateTimeSpec) {
    return new AfterDateTimePattern(dateTimeSpec);
}

public static AfterDateTimePattern after(ZonedDateTime dateTime) {
    return new AfterDateTimePattern(dateTime);
}

public static AfterDateTimePattern after(LocalDateTime dateTime) {
    return new AfterDateTimePattern(dateTime);
}

public static AfterDateTimePattern afterNow() {
    return new AfterDateTimePattern("now");
}

public static StringValuePattern absent() {
    return AbsentPattern.ABSENT;
}

public static StringValuePattern and(StringValuePattern... matchers) {
    return new LogicalAnd(matchers);
}

public static StringValuePattern or(StringValuePattern... matchers) {
    return new LogicalOr(matchers);
}

public void saveMappings() {
    admin.saveMappings();
}

public static void saveAllMappings() {
    defaultInstance.get().saveMappings();
}

public void removeMappings() {
    admin.resetMappings();
}

public static void removeAllMappings() {
    defaultInstance.get().removeMappings();
}

public void resetMappings() {
	admin.resetAll();
}

public static void reset() {
	defaultInstance.get().resetMappings();
}

public static void resetAllRequests() {
	defaultInstance.get().resetRequests();
}

public void resetRequests() {
	admin.resetRequests();
}

public void resetScenarios() {
	admin.resetScenarios();
}

public static List<Scenario> getAllScenarios() {
    return defaultInstance.get().getScenarios();
}

private List<Scenario> getScenarios() {
    return admin.getAllScenarios().getScenarios();
}

public static void resetAllScenarios() {
	defaultInstance.get().resetScenarios();
}

public void resetToDefaultMappings() {
    admin.resetToDefaultMappings();
}

public static void resetToDefault() {
    defaultInstance.get().resetToDefaultMappings();
}

public StubMapping register(MappingBuilder mappingBuilder) {
	StubMapping mapping = mappingBuilder.build();
	register(mapping);
	return mapping;
}

public void register(StubMapping mapping) {
    admin.addStubMapping(mapping);
}

public void editStubMapping(MappingBuilder mappingBuilder) {
	admin.editStubMapping(mappingBuilder.build());
}

public void removeStubMapping(MappingBuilder mappingBuilder) {
	admin.removeStubMapping(mappingBuilder.build());
}

public void removeStubMapping(StubMapping stubMapping) {
	admin.removeStubMapping(stubMapping);
}

public ListStubMappingsResult allStubMappings() {
    return admin.listAllStubMappings();
}

public SingleStubMappingResult getStubMapping(UUID id) {
    return admin.getStubMapping(id);
}

public static UrlPattern urlEqualTo(String testUrl) {
    return new UrlPattern(equalTo(testUrl), false);
}

public static UrlPattern urlMatching(String urlRegex) {
    return new UrlPattern(matching(urlRegex), true);
}

public static UrlPathPattern urlPathEqualTo(String testUrl) {
    return new UrlPathPattern(equalTo(testUrl), false);
}

public static UrlPathPattern urlPathMatching(String urlRegex) {
    return new UrlPathPattern(matching(urlRegex), true);
}

public static UrlPattern anyUrl() {
    return UrlPattern.ANY;
}

public static CountMatchingStrategy lessThan(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.LESS_THAN, expected);
}

public static CountMatchingStrategy lessThanOrExactly(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.LESS_THAN_OR_EQUAL, expected);
}

public static CountMatchingStrategy exactly(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.EQUAL_TO, expected);
}

public static CountMatchingStrategy moreThanOrExactly(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.GREATER_THAN_OR_EQUAL, expected);
}

public static CountMatchingStrategy moreThan(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.GREATER_THAN, expected);
}

public static MappingBuilder get(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.GET, urlPattern);
}

public static MappingBuilder post(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.POST, urlPattern);
}

public static MappingBuilder put(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.PUT, urlPattern);
}

public static MappingBuilder delete(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.DELETE, urlPattern);
}

public static MappingBuilder patch(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.PATCH, urlPattern);
}

public static MappingBuilder head(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.HEAD, urlPattern);
}

public static MappingBuilder options(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.OPTIONS, urlPattern);
}

public static MappingBuilder trace(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.TRACE, urlPattern);
}

public static MappingBuilder any(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.ANY, urlPattern);
}

public static MappingBuilder request(String method, UrlPattern urlPattern) {
    return new BasicMappingBuilder(RequestMethod.fromString(method), urlPattern);
}

public static MappingBuilder requestMatching(String customRequestMatcherName) {
	return new BasicMappingBuilder(customRequestMatcherName, Parameters.empty());
}

public static MappingBuilder requestMatching(String customRequestMatcherName, Parameters parameters) {
	return new BasicMappingBuilder(customRequestMatcherName, parameters);
}

public static MappingBuilder requestMatching(ValueMatcher<Request> requestMatcher) {
	return new BasicMappingBuilder(requestMatcher);
}

public static ResponseDefinitionBuilder aResponse() {
	return new ResponseDefinitionBuilder();
}

public static ResponseDefinitionBuilder ok() {
    return aResponse().withStatus(200);
}

public static ResponseDefinitionBuilder ok(String body) {
    return aResponse().withStatus(200).withBody(body);
}

public static ResponseDefinitionBuilder okForContentType(String contentType, String body) {
    return aResponse()
        .withStatus(200)
        .withHeader(CONTENT_TYPE, contentType)
        .withBody(body);
}

public static ResponseDefinitionBuilder okJson(String body) {
    return okForContentType("application/json", body);
}

public static ResponseDefinitionBuilder okXml(String body) {
    return okForContentType("application/xml", body);
}

public static ResponseDefinitionBuilder okTextXml(String body) {
    return okForContentType("text/xml", body);
}

public static MappingBuilder proxyAllTo(String url) {
    return any(anyUrl()).willReturn(aResponse().proxiedFrom(url));
}

public static MappingBuilder get(String url) {
    return get(urlEqualTo(url));
}

public static MappingBuilder post(String url) {
    return post(urlEqualTo(url));
}

public static MappingBuilder put(String url) {
    return put(urlEqualTo(url));
}

public static MappingBuilder delete(String url) {
    return delete(urlEqualTo(url));
}

public static ResponseDefinitionBuilder created() {
    return aResponse().withStatus(201);
}

public static ResponseDefinitionBuilder noContent() {
    return aResponse().withStatus(204);
}

public static ResponseDefinitionBuilder permanentRedirect(String location) {
    return aResponse().withStatus(301).withHeader(LOCATION, location);
}

public static ResponseDefinitionBuilder temporaryRedirect(String location) {
    return aResponse().withStatus(302).withHeader(LOCATION, location);
}

public static ResponseDefinitionBuilder seeOther(String location) {
    return aResponse().withStatus(303).withHeader(LOCATION, location);
}

public static ResponseDefinitionBuilder badRequest() {
    return aResponse().withStatus(400);
}

public static ResponseDefinitionBuilder badRequestEntity() {
    return aResponse().withStatus(422);
}

public static ResponseDefinitionBuilder unauthorized() {
    return aResponse().withStatus(401);
}

public static ResponseDefinitionBuilder forbidden() {
    return aResponse().withStatus(403);
}

public static ResponseDefinitionBuilder notFound() {
    return aResponse().withStatus(404);
}

public static ResponseDefinitionBuilder serverError() {
    return aResponse().withStatus(500);
}

public static ResponseDefinitionBuilder serviceUnavailable() {
    return aResponse().withStatus(503);
}

public static ResponseDefinitionBuilder status(int status) {
    return aResponse().withStatus(status);
}

public void verifyThat(RequestPatternBuilder requestPatternBuilder) {
	verifyThat(moreThanOrExactly(1), requestPatternBuilder);
}

public void verifyThat(int expectedCount, RequestPatternBuilder requestPatternBuilder) {
	verifyThat(exactly(expectedCount), requestPatternBuilder);
}

public void verifyThat(CountMatchingStrategy expectedCount, RequestPatternBuilder requestPatternBuilder) {
	final RequestPattern requestPattern = requestPatternBuilder.build();

	int actualCount;
	if (requestPattern.hasInlineCustomMatcher()) {
        List<LoggedRequest> requests = admin.findRequestsMatching(RequestPattern.everything()).getRequests();
        actualCount = from(requests).filter(thatMatch(requestPattern)).size();
    } else {
        VerificationResult result = admin.countRequestsMatching(requestPattern);
        result.assertRequestJournalEnabled();
        actualCount = result.getCount();
    }

    if (!expectedCount.match(actualCount)) {
        throw actualCount == 0 ?
            verificationExceptionForNearMisses(requestPatternBuilder, requestPattern) :
		    new VerificationException(requestPattern, expectedCount, actualCount);
	}
}

private VerificationException verificationExceptionForNearMisses(RequestPatternBuilder requestPatternBuilder, RequestPattern requestPattern) {
    List<NearMiss> nearMisses = findAllNearMissesFor(requestPatternBuilder);
    if (nearMisses.size() > 0) {
        Diff diff = new Diff(requestPattern, nearMisses.get(0).getRequest());
        return VerificationException.forUnmatchedRequestPattern(diff);
    }

    return new VerificationException(requestPattern, find(allRequests()));
}

public static void verify(RequestPatternBuilder requestPatternBuilder) {
	defaultInstance.get().verifyThat(requestPatternBuilder);
}

public static void verify(int count, RequestPatternBuilder requestPatternBuilder) {
	defaultInstance.get().verifyThat(count, requestPatternBuilder);
}

public static void verify(CountMatchingStrategy countMatchingStrategy, RequestPatternBuilder requestPatternBuilder) {
	defaultInstance.get().verifyThat(countMatchingStrategy, requestPatternBuilder);
}

public List<LoggedRequest> find(RequestPatternBuilder requestPatternBuilder) {
    FindRequestsResult result = admin.findRequestsMatching(requestPatternBuilder.build());
    result.assertRequestJournalEnabled();
    return result.getRequests();
}

public static List<LoggedRequest> findAll(RequestPatternBuilder requestPatternBuilder) {
    return defaultInstance.get().find(requestPatternBuilder);
}

public static List<ServeEvent> getAllServeEvents() {
    return defaultInstance.get().getServeEvents();
}

public List<ServeEvent> getServeEvents() {
    return admin.getServeEvents().getRequests();
}

public static void removeServeEvent(UUID eventId) {
    defaultInstance.get().removeEvent(eventId);
}

public void removeEvent(UUID eventId) {
    admin.removeServeEvent(eventId);
}

public List<ServeEvent> removeEvents(RequestPatternBuilder requestPatternBuilder) {
    return admin.removeServeEventsMatching(requestPatternBuilder.build()).getServeEvents();
}

public static List<ServeEvent> removeServeEvents(RequestPatternBuilder requestPatternBuilder) {
    return defaultInstance.get().removeEvents(requestPatternBuilder);
}

public static List<ServeEvent> removeEventsByStubMetadata(StringValuePattern pattern) {
    return defaultInstance.get().removeEventsByMetadata(pattern);
}

public List<ServeEvent> removeEventsByMetadata(StringValuePattern pattern) {
    return admin.removeServeEventsForStubsMatchingMetadata(pattern).getServeEvents();
}

public static RequestPatternBuilder getRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.GET, urlPattern);
}

public static RequestPatternBuilder postRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.POST, urlPattern);
}

public static RequestPatternBuilder putRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.PUT, urlPattern);
}

public static RequestPatternBuilder deleteRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.DELETE, urlPattern);
}

public static RequestPatternBuilder patchRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.PATCH, urlPattern);
}

public static RequestPatternBuilder headRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.HEAD, urlPattern);
}

public static RequestPatternBuilder optionsRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.OPTIONS, urlPattern);
}

public static RequestPatternBuilder traceRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.TRACE, urlPattern);
}

public static RequestPatternBuilder anyRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.ANY, urlPattern);
}

public static RequestPatternBuilder requestMadeFor(String customMatcherName, Parameters parameters) {
    return RequestPatternBuilder.forCustomMatcher(customMatcherName, parameters);
}

public static RequestPatternBuilder requestMadeFor(ValueMatcher<Request> requestMatcher) {
	return RequestPatternBuilder.forCustomMatcher(requestMatcher);
}

public static void setGlobalFixedDelay(int milliseconds) {
	defaultInstance.get().setGlobalFixedDelayVariable(milliseconds);
}

public void setGlobalFixedDelayVariable(int milliseconds) {
	GlobalSettings settings = globalSettingsHolder.get()
            .copy()
            .fixedDelay(milliseconds)
            .build();
	updateGlobalSettings(settings);
}

public static void setGlobalRandomDelay(DelayDistribution distribution) {
	defaultInstance.get().setGlobalRandomDelayVariable(distribution);
}

public void setGlobalRandomDelayVariable(DelayDistribution distribution) {
	GlobalSettings settings = globalSettingsHolder.get()
            .copy()
            .delayDistribution(distribution)
            .build();
	updateGlobalSettings(settings);
}

public static void updateSettings(GlobalSettings settings) {
    defaultInstance.get().updateGlobalSettings(settings);
}

public void updateGlobalSettings(GlobalSettings settings) {
	globalSettingsHolder.replaceWith(settings);
	admin.updateGlobalSettings(settings);
}

public void shutdown() {
    admin.shutdownServer();
}

public static void shutdownServer() {
    defaultInstance.get().shutdown();
}

public static List<NearMiss> findNearMissesForAllUnmatched() {
    return defaultInstance.get().findNearMissesForAllUnmatchedRequests();
}

public List<NearMiss> findNearMissesForAllUnmatchedRequests() {
    FindNearMissesResult nearMissesResult = admin.findNearMissesForUnmatchedRequests();
    return nearMissesResult.getNearMisses();
}

public static List<LoggedRequest> findUnmatchedRequests() {
    return defaultInstance.get().findAllUnmatchedRequests();
}

public List<LoggedRequest> findAllUnmatchedRequests() {
    FindRequestsResult unmatchedResult = admin.findUnmatchedRequests();
    return unmatchedResult.getRequests();
}

public static List<NearMiss> findNearMissesFor(LoggedRequest loggedRequest) {
    return defaultInstance.get().findTopNearMissesFor(loggedRequest);
}

public List<NearMiss> findTopNearMissesFor(LoggedRequest loggedRequest) {
    FindNearMissesResult nearMissesResult = admin.findTopNearMissesFor(loggedRequest);
    return nearMissesResult.getNearMisses();
}

public static List<NearMiss> findNearMissesFor(RequestPatternBuilder requestPatternBuilder) {
    return defaultInstance.get().findAllNearMissesFor(requestPatternBuilder);
}

public List<NearMiss> findAllNearMissesFor(RequestPatternBuilder requestPatternBuilder) {
    FindNearMissesResult nearMissesResult = admin.findTopNearMissesFor(requestPatternBuilder.build());
    return nearMissesResult.getNearMisses();
}

public void loadMappingsFrom(String rootDir) {
    loadMappingsFrom(new File(rootDir));
}

public void loadMappingsFrom(File rootDir) {
	FileSource mappingsSource = new SingleRootFileSource(rootDir);
	new RemoteMappingsLoader(mappingsSource, this).load();
}

public static List<StubMapping> snapshotRecord() {
    return defaultInstance.get().takeSnapshotRecording();
}

public static List<StubMapping> snapshotRecord(RecordSpecBuilder spec) {
    return defaultInstance.get().takeSnapshotRecording(spec);
}

public List<StubMapping> takeSnapshotRecording() {
    return admin.snapshotRecord().getStubMappings();
}

public List<StubMapping> takeSnapshotRecording(RecordSpecBuilder spec) {
    return admin.snapshotRecord(spec.build()).getStubMappings();
}

public static MultipartValuePatternBuilder aMultipart() {
    return new MultipartValuePatternBuilder();
}

public static MultipartValuePatternBuilder aMultipart(String name) {
    return new MultipartValuePatternBuilder(name);
}

public static void startRecording(String targetBaseUrl) {
    defaultInstance.get().startStubRecording(targetBaseUrl);
}

public static void startRecording(RecordSpecBuilder spec) {
    defaultInstance.get().startStubRecording(spec);
}

public void startStubRecording(String targetBaseUrl) {
    admin.startRecording(targetBaseUrl);
}

public void startStubRecording(RecordSpecBuilder spec) {
    admin.startRecording(spec.build());
}

public static SnapshotRecordResult stopRecording() {
    return defaultInstance.get().stopStubRecording();
}

public SnapshotRecordResult stopStubRecording() {
    return admin.stopRecording();
}

public static RecordingStatusResult getRecordingStatus() {
    return defaultInstance.get().getStubRecordingStatus();
}

public RecordingStatusResult getStubRecordingStatus() {
    return admin.getRecordingStatus();
}

public static RecordSpecBuilder recordSpec() {
    return new RecordSpecBuilder();
}

public List<StubMapping> findAllStubsByMetadata(StringValuePattern pattern) {
    return admin.findAllStubsByMetadata(pattern).getMappings();
}

public static List<StubMapping> findStubsByMetadata(StringValuePattern pattern) {
    return defaultInstance.get().findAllStubsByMetadata(pattern);
}

public void removeStubsByMetadataPattern(StringValuePattern pattern) {
    admin.removeStubsByMetadata(pattern);
}

public static void removeStubsByMetadata(StringValuePattern pattern) {
    defaultInstance.get().removeStubsByMetadataPattern(pattern);
}

public void importStubMappings(StubImport stubImport) {
    admin.importStubs(stubImport);
}

public void importStubMappings(StubImportBuilder stubImport) {
    importStubMappings(stubImport.build());
}

public static void importStubs(StubImportBuilder stubImport) {
    importStubs(stubImport.build());
}

public static void importStubs(StubImport stubImport) {
    defaultInstance.get().importStubMappings(stubImport);
}

public GlobalSettings getGlobalSettings() {
    return admin.getGlobalSettings().getSettings();
}

public static GlobalSettings getSettings() {
    return defaultInstance.get().getGlobalSettings();
}

}
`
and the error is:

`
Caused by:
2021-10-20T13:21:16.702-0500 [DEBUG] [TestEventLogger] javax.ws.rs.ProcessingException: java.lang.reflect.InaccessibleObjectException: Unable to make field protected java.lang.String java.net.HttpURLConnection.method accessible: module java.base does not "opens java.net" to unnamed module @543c6f6d

`

I tried to add args in gradle test task and it didn't work
test { useTestNG() def addOpenArgs = ['--add-exports','java.base/sun.security.x509=ALL-UNNAMED'] jvmArgs+=addOpenArgs; }

@tomakehurst tomakehurst added this to To do in WireMock 2.32.0 Nov 2, 2021
@EmilyStacy
Copy link

EmilyStacy commented Nov 2, 2021

@EmilyStacy can you post details so we can try to reproduce the error you're seeing?

This is the dependency in our build.gradle: testImplementation "com.github.tomakehurst:wiremock-jre8:2.31.0"

This is the test case setting with dependencies:

` import java.net.URI; import java.util.UUID;

import javax.ws.rs.client.Client; import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.UriBuilder;

import org.mockito.Mockito; import org.testng.Assert; import org.testng.annotations.AfterClass; import org.testng.annotations.BeforeClass; import org.testng.annotations.Test;

import com.github.tomakehurst.wiremock.WireMockServer; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.core.WireMockConfiguration;

private WireMockServer mockServer; private Client client; private String wiremockUrl;

@BeforeClass public void setup() { mockServer = new WireMockServer(WireMockConfiguration.options().dynamicPort()); mockServer.start(); client = getClient(); WireMock.configureFor("localhost", mockServer.port()); wiremockUrl = "http://localhost:" + mockServer.port(); }

@afterclass public void tearDown() { mockServer.stop(); }

@test public void randomTestCase(){ UUID deviceId = UUID.randomUUID(); URI uri = UriBuilder.fromUri(URIConstant) .resolveTemplate("deviceId", deviceId) .build();

mockServer.stubFor(WireMock.patch(WireMock.urlEqualTo(uri.toString())) .willReturn(WireMock.aResponse() .withHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON) .withStatus(Response.Status.OK.getStatusCode())));

(some specific mocking for our logic) WireMock.verify(WireMock.patchRequestedFor(WireMock.urlEqualTo(uri.toString()))); }

`

this is the read-only WiremockServer class:

`/

  • Copyright (C) 2011 Thomas Akehurst

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 com.github.tomakehurst.wiremock;

import com.github.tomakehurst.wiremock.admin.model.; import com.github.tomakehurst.wiremock.client.CountMatchingStrategy; import com.github.tomakehurst.wiremock.client.MappingBuilder; import com.github.tomakehurst.wiremock.client.VerificationException; import com.github.tomakehurst.wiremock.client.WireMock; import com.github.tomakehurst.wiremock.common.; import com.github.tomakehurst.wiremock.core.Admin; import com.github.tomakehurst.wiremock.core.Container; import com.github.tomakehurst.wiremock.core.Options; import com.github.tomakehurst.wiremock.core.WireMockApp; import com.github.tomakehurst.wiremock.global.GlobalSettings; import com.github.tomakehurst.wiremock.global.GlobalSettingsHolder; import com.github.tomakehurst.wiremock.http.HttpServer; import com.github.tomakehurst.wiremock.http.HttpServerFactory; import com.github.tomakehurst.wiremock.http.RequestListener; import com.github.tomakehurst.wiremock.http.StubRequestHandler; import com.github.tomakehurst.wiremock.junit.Stubbing; import com.github.tomakehurst.wiremock.matching.RequestPattern; import com.github.tomakehurst.wiremock.matching.RequestPatternBuilder; import com.github.tomakehurst.wiremock.matching.StringValuePattern; import com.github.tomakehurst.wiremock.recording.RecordingStatusResult; import com.github.tomakehurst.wiremock.recording.SnapshotRecordResult; import com.github.tomakehurst.wiremock.recording.RecordSpec; import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder; import com.github.tomakehurst.wiremock.standalone.MappingsLoader; import com.github.tomakehurst.wiremock.stubbing.ServeEvent; import com.github.tomakehurst.wiremock.stubbing.StubImport; import com.github.tomakehurst.wiremock.stubbing.StubMapping; import com.github.tomakehurst.wiremock.stubbing.StubMappingJsonRecorder; import com.github.tomakehurst.wiremock.verification.*;

import java.util.List; import java.util.UUID;

import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.wireMockConfig; import static com.google.common.base.Preconditions.checkState;

public class WireMockServer implements Container, Stubbing, Admin {

private final WireMockApp wireMockApp; private final StubRequestHandler stubRequestHandler; private final HttpServer httpServer; private final Notifier notifier; protected final Options options; protected final WireMock client; public WireMockServer(Options options) { this.options = options; this.notifier = options.notifier();

    wireMockApp = new WireMockApp(options, this);

    this.stubRequestHandler = wireMockApp.buildStubRequestHandler();
    HttpServerFactory httpServerFactory = options.httpServerFactory();
    httpServer = httpServerFactory.buildHttpServer(
            options,
            wireMockApp.buildAdminRequestHandler(),
            stubRequestHandler
    );

    client = new WireMock(wireMockApp);
}

public WireMockServer(int port, Integer httpsPort, FileSource fileSource, boolean 

enableBrowserProxying, ProxySettings proxySettings, Notifier notifier) { this(wireMockConfig() .port(port) .httpsPort(httpsPort) .fileSource(fileSource) .enableBrowserProxying(enableBrowserProxying) .proxyVia(proxySettings) .notifier(notifier)); }

public WireMockServer(int port, FileSource fileSource, boolean enableBrowserProxying, ProxySettings proxySettings) {
    this(wireMockConfig()
            .port(port)
            .fileSource(fileSource)
            .enableBrowserProxying(enableBrowserProxying)
            .proxyVia(proxySettings));
}

public WireMockServer(int port, FileSource fileSource, boolean enableBrowserProxying) {
    this(wireMockConfig()
            .port(port)
            .fileSource(fileSource)
            .enableBrowserProxying(enableBrowserProxying));
}

public WireMockServer(int port) {
	this(wireMockConfig().port(port));
}

public WireMockServer(int port, Integer httpsPort) {
    this(wireMockConfig().port(port).httpsPort(httpsPort));
}

public WireMockServer() {
	this(wireMockConfig());
}

public void loadMappingsUsing(final MappingsLoader mappingsLoader) {
    wireMockApp.loadMappingsUsing(mappingsLoader);
}

public GlobalSettingsHolder getGlobalSettingsHolder() {
    return wireMockApp.getGlobalSettingsHolder();
}

public void addMockServiceRequestListener(RequestListener listener) {
	stubRequestHandler.addRequestListener(listener);
}

public void enableRecordMappings(FileSource mappingsFileSource, FileSource filesFileSource) {
    addMockServiceRequestListener(
            new StubMappingJsonRecorder(mappingsFileSource, filesFileSource, wireMockApp, options.matchingHeaders()));
    notifier.info("Recording mappings to " + mappingsFileSource.getPath());
}

public void stop() {
    httpServer.stop();
}

public void start() {
    // Try to ensure this is warmed up on the main thread so that it's inherited by worker threads
    Json.getObjectMapper();
    try {
	    httpServer.start();
    } catch (Exception e) {
        throw new FatalStartupException(e);
    }
}

/*
 * Gracefully shutdown the server.
  This method assumes it is being called as the result of an incoming HTTP request.
 */
@Override
public void shutdown() {
    final WireMockServer server = this;
    Thread shutdownThread = new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                // We have to sleep briefly to finish serving the shutdown request before stopping the server, as
                // there's no support in Jetty for shutting down after the current request.
                // See http://stackoverflow.com/questions/4650713
                Thread.sleep(100);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            server.stop();
        }
    });
    shutdownThread.start();
}

public boolean isHttpEnabled() {
    return !options.getHttpDisabled();
}

public boolean isHttpsEnabled() {
    return options.httpsSettings().enabled();
}

public int port() {
    checkState(
        isRunning() && !options.getHttpDisabled(),
        "Not listening on HTTP port. Either HTTP is not enabled or the WireMock server is stopped."
    );
    return httpServer.port();
}

public int httpsPort() {
    checkState(
            isRunning() && options.httpsSettings().enabled(),
            "Not listening on HTTPS port. Either HTTPS is not enabled or the WireMock server is stopped."
    );
    return httpServer.httpsPort();
}

public String url(String path) {
    if (!path.startsWith("/")) {
        path = "/" + path;
    }

    return String.format("%s%s", baseUrl(), path);
}

public String baseUrl() {
    boolean https = options.httpsSettings().enabled();
    String protocol = https ? "https" : "http";
    int port = https ? httpsPort() : port();

    return String.format("%s://localhost:%d", protocol, port);
}

public boolean isRunning() {
    return httpServer.isRunning();
}

@Override
public StubMapping givenThat(MappingBuilder mappingBuilder) {
    return client.register(mappingBuilder);
}

@Override
public StubMapping stubFor(MappingBuilder mappingBuilder) {
    return givenThat(mappingBuilder);
}

@Override
public void editStub(MappingBuilder mappingBuilder) {
    client.editStubMapping(mappingBuilder);
}

@Override
public void removeStub(MappingBuilder mappingBuilder) {
    client.removeStubMapping(mappingBuilder);
}

@Override
public void removeStub(StubMapping stubMapping) {
    client.removeStubMapping(stubMapping);
}

@Override
public List<StubMapping> getStubMappings() {
    return client.allStubMappings().getMappings();
}

@Override
public StubMapping getSingleStubMapping(UUID id) {
    return client.getStubMapping(id).getItem();
}

@Override
public List<StubMapping> findStubMappingsByMetadata(StringValuePattern pattern) {
    return client.findAllStubsByMetadata(pattern);
}

@Override
public void removeStubMappingsByMetadata(StringValuePattern pattern) {
    client.removeStubsByMetadataPattern(pattern);
}

@Override
public void removeStubMapping(StubMapping stubMapping){
    wireMockApp.removeStubMapping(stubMapping);
}

@Override
public void verify(RequestPatternBuilder requestPatternBuilder) {
    client.verifyThat(requestPatternBuilder);
}

@Override
public void verify(int count, RequestPatternBuilder requestPatternBuilder) {
    client.verifyThat(count, requestPatternBuilder);
}

@Override
public void verify(CountMatchingStrategy countMatchingStrategy, RequestPatternBuilder requestPatternBuilder) {
    client.verifyThat(countMatchingStrategy, requestPatternBuilder);
}

@Override
public List<LoggedRequest> findAll(RequestPatternBuilder requestPatternBuilder) {
    return client.find(requestPatternBuilder);
}

@Override
public List<ServeEvent> getAllServeEvents() {
    return client.getServeEvents();
}

@Override
public void setGlobalFixedDelay(int milliseconds) {
    client.setGlobalFixedDelayVariable(milliseconds);
}

@Override
public List<LoggedRequest> findAllUnmatchedRequests() {
    return client.findAllUnmatchedRequests();
}

@Override
public List<NearMiss> findNearMissesForAllUnmatchedRequests() {
    return client.findNearMissesForAllUnmatchedRequests();
}

@Override
public List<NearMiss> findAllNearMissesFor(RequestPatternBuilder requestPatternBuilder) {
    return client.findAllNearMissesFor(requestPatternBuilder);
}

@Override
public List<NearMiss> findNearMissesFor(LoggedRequest loggedRequest) {
    return client.findTopNearMissesFor(loggedRequest);
}

@Override
public void addStubMapping(StubMapping stubMapping) {
    wireMockApp.addStubMapping(stubMapping);
}

@Override
public void editStubMapping(StubMapping stubMapping) {
    wireMockApp.editStubMapping(stubMapping);
}

@Override
public ListStubMappingsResult listAllStubMappings() {
    return wireMockApp.listAllStubMappings();
}

@Override
public SingleStubMappingResult getStubMapping(UUID id) {
    return wireMockApp.getStubMapping(id);
}

@Override
public void saveMappings() {
    wireMockApp.saveMappings();
}

@Override
public void resetAll() {
    wireMockApp.resetAll();
}

@Override
public void resetRequests() {
    wireMockApp.resetRequests();
}

@Override
public void resetToDefaultMappings() {
    wireMockApp.resetToDefaultMappings();
}

@Override
public GetServeEventsResult getServeEvents() {
    return wireMockApp.getServeEvents();
}

@Override
public SingleServedStubResult getServedStub(UUID id) {
    return wireMockApp.getServedStub(id);
}

@Override
public void resetScenarios() {
    wireMockApp.resetScenarios();
}

@Override
public void resetMappings() {
    wireMockApp.resetMappings();
}

@Override
public VerificationResult countRequestsMatching(RequestPattern requestPattern) {
    return wireMockApp.countRequestsMatching(requestPattern);
}

@Override
public FindRequestsResult findRequestsMatching(RequestPattern requestPattern) {
    return wireMockApp.findRequestsMatching(requestPattern);
}

@Override
public FindRequestsResult findUnmatchedRequests() {
    return wireMockApp.findUnmatchedRequests();
}

@Override
public void removeServeEvent(UUID eventId) {
    wireMockApp.removeServeEvent(eventId);
}

@Override
public FindServeEventsResult removeServeEventsMatching(RequestPattern requestPattern) {
    return wireMockApp.removeServeEventsMatching(requestPattern);
}

@Override
public FindServeEventsResult removeServeEventsForStubsMatchingMetadata(StringValuePattern metadataPattern) {
    return wireMockApp.removeServeEventsForStubsMatchingMetadata(metadataPattern);
}

@Override
public void updateGlobalSettings(GlobalSettings newSettings) {
    wireMockApp.updateGlobalSettings(newSettings);
}

@Override
public FindNearMissesResult findNearMissesForUnmatchedRequests() {
    return wireMockApp.findNearMissesForUnmatchedRequests();
}

@Override
public GetScenariosResult getAllScenarios() {
    return wireMockApp.getAllScenarios();
}

@Override
public FindNearMissesResult findTopNearMissesFor(LoggedRequest loggedRequest) {
    return wireMockApp.findTopNearMissesFor(loggedRequest);
}

@Override
public FindNearMissesResult findTopNearMissesFor(RequestPattern requestPattern) {
    return wireMockApp.findTopNearMissesFor(requestPattern);
}

@Override
public void startRecording(String targetBaseUrl) {
    wireMockApp.startRecording(targetBaseUrl);
}

@Override
public void startRecording(RecordSpec spec) {
    wireMockApp.startRecording(spec);
}

@Override
public void startRecording(RecordSpecBuilder recordSpec) {
    wireMockApp.startRecording(recordSpec);
}

@Override
public SnapshotRecordResult stopRecording() {
    return wireMockApp.stopRecording();
}

@Override
public RecordingStatusResult getRecordingStatus() {
    return wireMockApp.getRecordingStatus();
}

@Override
public SnapshotRecordResult snapshotRecord() {
    return wireMockApp.snapshotRecord();
}

@Override
public SnapshotRecordResult snapshotRecord(RecordSpecBuilder spec) {
    return wireMockApp.snapshotRecord(spec);
}

@Override
public SnapshotRecordResult snapshotRecord(RecordSpec spec) {
    return wireMockApp.snapshotRecord(spec);
}

@Override
public Options getOptions() {
    return options;
}

@Override
public void shutdownServer() {
    shutdown();
}

@Override
public ListStubMappingsResult findAllStubsByMetadata(StringValuePattern pattern) {
    return wireMockApp.findAllStubsByMetadata(pattern);
}

@Override
public void removeStubsByMetadata(StringValuePattern pattern) {
    wireMockApp.removeStubsByMetadata(pattern);
}

@Override
public void importStubs(StubImport stubImport) {
    wireMockApp.importStubs(stubImport);
}

@Override
public GetGlobalSettingsResult getGlobalSettings() {
    return wireMockApp.getGlobalSettings();
}

public void checkForUnmatchedRequests() {
    List<LoggedRequest> unmatchedRequests = findAllUnmatchedRequests();
    if (!unmatchedRequests.isEmpty()) {
        List<NearMiss> nearMisses = findNearMissesForAllUnmatchedRequests();
        if (nearMisses.isEmpty()) {
            throw VerificationException.forUnmatchedRequests(unmatchedRequests);
        } else {
            throw VerificationException.forUnmatchedNearMisses(nearMisses);
        }
    }
}

} ` and this is the readonly Wiremock class:

`/ Copyright (C) 2011 Thomas Akehurst

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 com.github.tomakehurst.wiremock.client;

import com.github.tomakehurst.wiremock.admin.model.ListStubMappingsResult; import com.github.tomakehurst.wiremock.admin.model.SingleStubMappingResult; import com.github.tomakehurst.wiremock.common.; import com.github.tomakehurst.wiremock.stubbing.; import com.github.tomakehurst.wiremock.core.Admin; import com.github.tomakehurst.wiremock.extension.Parameters; import com.github.tomakehurst.wiremock.global.GlobalSettings; import com.github.tomakehurst.wiremock.global.GlobalSettingsHolder; import com.github.tomakehurst.wiremock.http.DelayDistribution; import com.github.tomakehurst.wiremock.http.Request; import com.github.tomakehurst.wiremock.http.RequestMethod; import com.github.tomakehurst.wiremock.matching.; import com.github.tomakehurst.wiremock.recording.RecordSpecBuilder; import com.github.tomakehurst.wiremock.recording.RecordingStatusResult; import com.github.tomakehurst.wiremock.recording.SnapshotRecordResult; import com.github.tomakehurst.wiremock.security.ClientAuthenticator; import com.github.tomakehurst.wiremock.standalone.RemoteMappingsLoader; import com.github.tomakehurst.wiremock.verification.; import com.github.tomakehurst.wiremock.verification.diff.Diff;

import java.io.File; import java.time.LocalDateTime; import java.time.ZonedDateTime; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID;

import static com.github.tomakehurst.wiremock.matching.RequestPattern.thatMatch; import static com.github.tomakehurst.wiremock.matching.RequestPatternBuilder.allRequests; import static com.google.common.collect.FluentIterable.from; import static com.google.common.net.HttpHeaders.CONTENT_TYPE; import static com.google.common.net.HttpHeaders.LOCATION;

public class WireMock {

private static final int DEFAULT_PORT = 8080;
private static final String DEFAULT_HOST = "localhost";

private final Admin admin;
private final GlobalSettingsHolder globalSettingsHolder = new GlobalSettingsHolder();

private static InheritableThreadLocal<WireMock> defaultInstance = new InheritableThreadLocal<WireMock>(){
        @Override
        protected WireMock initialValue() {
        	return WireMock.create().build();
        }
};

public static WireMockBuilder create() {
    return new WireMockBuilder();
}

public WireMock(Admin admin) {
    this.admin = admin;
}

public WireMock(int port) {
    this(DEFAULT_HOST, port);
}

public WireMock(String host, int port) {
	admin = new HttpAdminClient(host, port);
}

public WireMock(String host, int port, String urlPathPrefix) {
	admin = new HttpAdminClient(host, port, urlPathPrefix);
}

public WireMock(String scheme, String host, int port) {
	admin = new HttpAdminClient(scheme, host, port);
}

public WireMock(String scheme, String host, int port, String urlPathPrefix) {
	admin = new HttpAdminClient(scheme, host, port, urlPathPrefix);
}

public WireMock(String scheme, String host, int port, String urlPathPrefix, String hostHeader, String proxyHost, int proxyPort, ClientAuthenticator authenticator) {
    admin = new HttpAdminClient(scheme, host, port, urlPathPrefix, hostHeader, proxyHost, proxyPort, authenticator);
}

public WireMock() {
	admin = new HttpAdminClient(DEFAULT_HOST, DEFAULT_PORT);
}

public static StubMapping givenThat(MappingBuilder mappingBuilder) {
	return defaultInstance.get().register(mappingBuilder);
}

public static StubMapping stubFor(MappingBuilder mappingBuilder) {
	return givenThat(mappingBuilder);
}

public static void editStub(MappingBuilder mappingBuilder) {
	defaultInstance.get().editStubMapping(mappingBuilder);
}

public static void removeStub(MappingBuilder mappingBuilder) {
	defaultInstance.get().removeStubMapping(mappingBuilder);
}

public static void removeStub(StubMapping stubMapping) {
    defaultInstance.get().removeStubMapping(stubMapping);
}

public static ListStubMappingsResult listAllStubMappings() {
    return defaultInstance.get().allStubMappings();
}

public static StubMapping getSingleStubMapping(UUID id) {
    return defaultInstance.get().getStubMapping(id).getItem();
}

public static void configureFor(int port) {
    defaultInstance.set(WireMock.create().port(port).build());
}

public static void configureFor(String host, int port) {
	defaultInstance.set(WireMock.create().host(host).port(port).build());
}

public static void configureFor(String host, int port, String urlPathPrefix) {
	defaultInstance.set(WireMock.create().host(host).port(port).urlPathPrefix(urlPathPrefix).build());
}

public static void configureFor(String scheme, String host, int port, String urlPathPrefix) {
	defaultInstance.set(WireMock.create().scheme(scheme).host(host).port(port).urlPathPrefix(urlPathPrefix).build());
}

public static void configureFor(String scheme, String host, int port) {
	defaultInstance.set(WireMock.create().scheme(scheme).host(host).port(port).build());
}

public static void configureFor(String scheme, String host, int port, String proxyHost, int proxyPort) {
    defaultInstance.set(WireMock.create().scheme(scheme).host(host).port(port).urlPathPrefix("").hostHeader(null).proxyHost(proxyHost).proxyPort(proxyPort).build());
}

public static void configureFor(WireMock client) {
    defaultInstance.set(client);
}

public static void configure() {
	defaultInstance.set(WireMock.create().build());
}

public static StringValuePattern equalTo(String value) {
    return new EqualToPattern(value);
}

public static BinaryEqualToPattern binaryEqualTo(byte[] content) {
    return new BinaryEqualToPattern(content);
}

public static BinaryEqualToPattern binaryEqualTo(String content) {
    return new BinaryEqualToPattern(content);
}

public static StringValuePattern equalToIgnoreCase(String value) {
	return new EqualToPattern(value, true);
}

public static StringValuePattern equalToJson(String value) {
    return new EqualToJsonPattern(value, null, null);
}

public static StringValuePattern equalToJson(String value, boolean ignoreArrayOrder, boolean ignoreExtraElements) {
    return new EqualToJsonPattern(value, ignoreArrayOrder, ignoreExtraElements);
}

public static StringValuePattern matchingJsonPath(String value) {
    return new MatchesJsonPathPattern(value);
}

public static StringValuePattern matchingJsonPath(String value, StringValuePattern valuePattern) {
    return new MatchesJsonPathPattern(value, valuePattern);
}

public static EqualToXmlPattern equalToXml(String value) {
    return new EqualToXmlPattern(value);
}

public static EqualToXmlPattern equalToXml(String value, boolean enablePlaceholders) {
    return new EqualToXmlPattern(value, enablePlaceholders, null, null, null);
}

public static EqualToXmlPattern equalToXml(String value, boolean enablePlaceholders, String placeholderOpeningDelimiterRegex, String placeholderClosingDelimiterRegex) {
    return new EqualToXmlPattern(value, enablePlaceholders, placeholderOpeningDelimiterRegex, placeholderClosingDelimiterRegex, null);
}

public static MatchesXPathPattern matchingXPath(String value) {
    return new MatchesXPathPattern(value, Collections.<String, String>emptyMap());
}

public static StringValuePattern matchingXPath(String value, Map<String, String> namespaces) {
    return new MatchesXPathPattern(value, namespaces);
}

public static StringValuePattern matchingXPath(String value, StringValuePattern valuePattern) {
    return new MatchesXPathPattern(value, valuePattern);
}

// Use this with the date/time matchers to avoid an explicit cast
public static MatchesXPathPattern matchesXPathWithSubMatcher(String value, StringValuePattern valuePattern) {
    return new MatchesXPathPattern(value, valuePattern);
}

public static StringValuePattern containing(String value) {
    return new ContainsPattern(value);
}

public static StringValuePattern matching(String regex) {
    return new RegexPattern(regex);
}

public static StringValuePattern notMatching(String regex) {
    return new NegativeRegexPattern(regex);
}

public static BeforeDateTimePattern before(String dateTimeSpec) {
    return new BeforeDateTimePattern(dateTimeSpec);
}

public static BeforeDateTimePattern before(ZonedDateTime dateTime) {
    return new BeforeDateTimePattern(dateTime);
}

public static BeforeDateTimePattern before(LocalDateTime dateTime) {
    return new BeforeDateTimePattern(dateTime);
}

public static BeforeDateTimePattern beforeNow() {
    return new BeforeDateTimePattern("now");
}

public static EqualToDateTimePattern equalToDateTime(String dateTimeSpec) {
    return new EqualToDateTimePattern(dateTimeSpec);
}

public static EqualToDateTimePattern equalToDateTime(ZonedDateTime dateTime) {
    return new EqualToDateTimePattern(dateTime);
}

public static EqualToDateTimePattern equalToDateTime(LocalDateTime dateTime) {
    return new EqualToDateTimePattern(dateTime);
}

public static EqualToDateTimePattern isNow() {
    return new EqualToDateTimePattern("now");
}

public static AfterDateTimePattern after(String dateTimeSpec) {
    return new AfterDateTimePattern(dateTimeSpec);
}

public static AfterDateTimePattern after(ZonedDateTime dateTime) {
    return new AfterDateTimePattern(dateTime);
}

public static AfterDateTimePattern after(LocalDateTime dateTime) {
    return new AfterDateTimePattern(dateTime);
}

public static AfterDateTimePattern afterNow() {
    return new AfterDateTimePattern("now");
}

public static StringValuePattern absent() {
    return AbsentPattern.ABSENT;
}

public static StringValuePattern and(StringValuePattern... matchers) {
    return new LogicalAnd(matchers);
}

public static StringValuePattern or(StringValuePattern... matchers) {
    return new LogicalOr(matchers);
}

public void saveMappings() {
    admin.saveMappings();
}

public static void saveAllMappings() {
    defaultInstance.get().saveMappings();
}

public void removeMappings() {
    admin.resetMappings();
}

public static void removeAllMappings() {
    defaultInstance.get().removeMappings();
}

public void resetMappings() {
	admin.resetAll();
}

public static void reset() {
	defaultInstance.get().resetMappings();
}

public static void resetAllRequests() {
	defaultInstance.get().resetRequests();
}

public void resetRequests() {
	admin.resetRequests();
}

public void resetScenarios() {
	admin.resetScenarios();
}

public static List<Scenario> getAllScenarios() {
    return defaultInstance.get().getScenarios();
}

private List<Scenario> getScenarios() {
    return admin.getAllScenarios().getScenarios();
}

public static void resetAllScenarios() {
	defaultInstance.get().resetScenarios();
}

public void resetToDefaultMappings() {
    admin.resetToDefaultMappings();
}

public static void resetToDefault() {
    defaultInstance.get().resetToDefaultMappings();
}

public StubMapping register(MappingBuilder mappingBuilder) {
	StubMapping mapping = mappingBuilder.build();
	register(mapping);
	return mapping;
}

public void register(StubMapping mapping) {
    admin.addStubMapping(mapping);
}

public void editStubMapping(MappingBuilder mappingBuilder) {
	admin.editStubMapping(mappingBuilder.build());
}

public void removeStubMapping(MappingBuilder mappingBuilder) {
	admin.removeStubMapping(mappingBuilder.build());
}

public void removeStubMapping(StubMapping stubMapping) {
	admin.removeStubMapping(stubMapping);
}

public ListStubMappingsResult allStubMappings() {
    return admin.listAllStubMappings();
}

public SingleStubMappingResult getStubMapping(UUID id) {
    return admin.getStubMapping(id);
}

public static UrlPattern urlEqualTo(String testUrl) {
    return new UrlPattern(equalTo(testUrl), false);
}

public static UrlPattern urlMatching(String urlRegex) {
    return new UrlPattern(matching(urlRegex), true);
}

public static UrlPathPattern urlPathEqualTo(String testUrl) {
    return new UrlPathPattern(equalTo(testUrl), false);
}

public static UrlPathPattern urlPathMatching(String urlRegex) {
    return new UrlPathPattern(matching(urlRegex), true);
}

public static UrlPattern anyUrl() {
    return UrlPattern.ANY;
}

public static CountMatchingStrategy lessThan(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.LESS_THAN, expected);
}

public static CountMatchingStrategy lessThanOrExactly(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.LESS_THAN_OR_EQUAL, expected);
}

public static CountMatchingStrategy exactly(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.EQUAL_TO, expected);
}

public static CountMatchingStrategy moreThanOrExactly(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.GREATER_THAN_OR_EQUAL, expected);
}

public static CountMatchingStrategy moreThan(int expected) {
	return new CountMatchingStrategy(CountMatchingStrategy.GREATER_THAN, expected);
}

public static MappingBuilder get(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.GET, urlPattern);
}

public static MappingBuilder post(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.POST, urlPattern);
}

public static MappingBuilder put(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.PUT, urlPattern);
}

public static MappingBuilder delete(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.DELETE, urlPattern);
}

public static MappingBuilder patch(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.PATCH, urlPattern);
}

public static MappingBuilder head(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.HEAD, urlPattern);
}

public static MappingBuilder options(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.OPTIONS, urlPattern);
}

public static MappingBuilder trace(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.TRACE, urlPattern);
}

public static MappingBuilder any(UrlPattern urlPattern) {
	return new BasicMappingBuilder(RequestMethod.ANY, urlPattern);
}

public static MappingBuilder request(String method, UrlPattern urlPattern) {
    return new BasicMappingBuilder(RequestMethod.fromString(method), urlPattern);
}

public static MappingBuilder requestMatching(String customRequestMatcherName) {
	return new BasicMappingBuilder(customRequestMatcherName, Parameters.empty());
}

public static MappingBuilder requestMatching(String customRequestMatcherName, Parameters parameters) {
	return new BasicMappingBuilder(customRequestMatcherName, parameters);
}

public static MappingBuilder requestMatching(ValueMatcher<Request> requestMatcher) {
	return new BasicMappingBuilder(requestMatcher);
}

public static ResponseDefinitionBuilder aResponse() {
	return new ResponseDefinitionBuilder();
}

public static ResponseDefinitionBuilder ok() {
    return aResponse().withStatus(200);
}

public static ResponseDefinitionBuilder ok(String body) {
    return aResponse().withStatus(200).withBody(body);
}

public static ResponseDefinitionBuilder okForContentType(String contentType, String body) {
    return aResponse()
        .withStatus(200)
        .withHeader(CONTENT_TYPE, contentType)
        .withBody(body);
}

public static ResponseDefinitionBuilder okJson(String body) {
    return okForContentType("application/json", body);
}

public static ResponseDefinitionBuilder okXml(String body) {
    return okForContentType("application/xml", body);
}

public static ResponseDefinitionBuilder okTextXml(String body) {
    return okForContentType("text/xml", body);
}

public static MappingBuilder proxyAllTo(String url) {
    return any(anyUrl()).willReturn(aResponse().proxiedFrom(url));
}

public static MappingBuilder get(String url) {
    return get(urlEqualTo(url));
}

public static MappingBuilder post(String url) {
    return post(urlEqualTo(url));
}

public static MappingBuilder put(String url) {
    return put(urlEqualTo(url));
}

public static MappingBuilder delete(String url) {
    return delete(urlEqualTo(url));
}

public static ResponseDefinitionBuilder created() {
    return aResponse().withStatus(201);
}

public static ResponseDefinitionBuilder noContent() {
    return aResponse().withStatus(204);
}

public static ResponseDefinitionBuilder permanentRedirect(String location) {
    return aResponse().withStatus(301).withHeader(LOCATION, location);
}

public static ResponseDefinitionBuilder temporaryRedirect(String location) {
    return aResponse().withStatus(302).withHeader(LOCATION, location);
}

public static ResponseDefinitionBuilder seeOther(String location) {
    return aResponse().withStatus(303).withHeader(LOCATION, location);
}

public static ResponseDefinitionBuilder badRequest() {
    return aResponse().withStatus(400);
}

public static ResponseDefinitionBuilder badRequestEntity() {
    return aResponse().withStatus(422);
}

public static ResponseDefinitionBuilder unauthorized() {
    return aResponse().withStatus(401);
}

public static ResponseDefinitionBuilder forbidden() {
    return aResponse().withStatus(403);
}

public static ResponseDefinitionBuilder notFound() {
    return aResponse().withStatus(404);
}

public static ResponseDefinitionBuilder serverError() {
    return aResponse().withStatus(500);
}

public static ResponseDefinitionBuilder serviceUnavailable() {
    return aResponse().withStatus(503);
}

public static ResponseDefinitionBuilder status(int status) {
    return aResponse().withStatus(status);
}

public void verifyThat(RequestPatternBuilder requestPatternBuilder) {
	verifyThat(moreThanOrExactly(1), requestPatternBuilder);
}

public void verifyThat(int expectedCount, RequestPatternBuilder requestPatternBuilder) {
	verifyThat(exactly(expectedCount), requestPatternBuilder);
}

public void verifyThat(CountMatchingStrategy expectedCount, RequestPatternBuilder requestPatternBuilder) {
	final RequestPattern requestPattern = requestPatternBuilder.build();

	int actualCount;
	if (requestPattern.hasInlineCustomMatcher()) {
        List<LoggedRequest> requests = admin.findRequestsMatching(RequestPattern.everything()).getRequests();
        actualCount = from(requests).filter(thatMatch(requestPattern)).size();
    } else {
        VerificationResult result = admin.countRequestsMatching(requestPattern);
        result.assertRequestJournalEnabled();
        actualCount = result.getCount();
    }

    if (!expectedCount.match(actualCount)) {
        throw actualCount == 0 ?
            verificationExceptionForNearMisses(requestPatternBuilder, requestPattern) :
		    new VerificationException(requestPattern, expectedCount, actualCount);
	}
}

private VerificationException verificationExceptionForNearMisses(RequestPatternBuilder requestPatternBuilder, RequestPattern requestPattern) {
    List<NearMiss> nearMisses = findAllNearMissesFor(requestPatternBuilder);
    if (nearMisses.size() > 0) {
        Diff diff = new Diff(requestPattern, nearMisses.get(0).getRequest());
        return VerificationException.forUnmatchedRequestPattern(diff);
    }

    return new VerificationException(requestPattern, find(allRequests()));
}

public static void verify(RequestPatternBuilder requestPatternBuilder) {
	defaultInstance.get().verifyThat(requestPatternBuilder);
}

public static void verify(int count, RequestPatternBuilder requestPatternBuilder) {
	defaultInstance.get().verifyThat(count, requestPatternBuilder);
}

public static void verify(CountMatchingStrategy countMatchingStrategy, RequestPatternBuilder requestPatternBuilder) {
	defaultInstance.get().verifyThat(countMatchingStrategy, requestPatternBuilder);
}

public List<LoggedRequest> find(RequestPatternBuilder requestPatternBuilder) {
    FindRequestsResult result = admin.findRequestsMatching(requestPatternBuilder.build());
    result.assertRequestJournalEnabled();
    return result.getRequests();
}

public static List<LoggedRequest> findAll(RequestPatternBuilder requestPatternBuilder) {
    return defaultInstance.get().find(requestPatternBuilder);
}

public static List<ServeEvent> getAllServeEvents() {
    return defaultInstance.get().getServeEvents();
}

public List<ServeEvent> getServeEvents() {
    return admin.getServeEvents().getRequests();
}

public static void removeServeEvent(UUID eventId) {
    defaultInstance.get().removeEvent(eventId);
}

public void removeEvent(UUID eventId) {
    admin.removeServeEvent(eventId);
}

public List<ServeEvent> removeEvents(RequestPatternBuilder requestPatternBuilder) {
    return admin.removeServeEventsMatching(requestPatternBuilder.build()).getServeEvents();
}

public static List<ServeEvent> removeServeEvents(RequestPatternBuilder requestPatternBuilder) {
    return defaultInstance.get().removeEvents(requestPatternBuilder);
}

public static List<ServeEvent> removeEventsByStubMetadata(StringValuePattern pattern) {
    return defaultInstance.get().removeEventsByMetadata(pattern);
}

public List<ServeEvent> removeEventsByMetadata(StringValuePattern pattern) {
    return admin.removeServeEventsForStubsMatchingMetadata(pattern).getServeEvents();
}

public static RequestPatternBuilder getRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.GET, urlPattern);
}

public static RequestPatternBuilder postRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.POST, urlPattern);
}

public static RequestPatternBuilder putRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.PUT, urlPattern);
}

public static RequestPatternBuilder deleteRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.DELETE, urlPattern);
}

public static RequestPatternBuilder patchRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.PATCH, urlPattern);
}

public static RequestPatternBuilder headRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.HEAD, urlPattern);
}

public static RequestPatternBuilder optionsRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.OPTIONS, urlPattern);
}

public static RequestPatternBuilder traceRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.TRACE, urlPattern);
}

public static RequestPatternBuilder anyRequestedFor(UrlPattern urlPattern) {
	return new RequestPatternBuilder(RequestMethod.ANY, urlPattern);
}

public static RequestPatternBuilder requestMadeFor(String customMatcherName, Parameters parameters) {
    return RequestPatternBuilder.forCustomMatcher(customMatcherName, parameters);
}

public static RequestPatternBuilder requestMadeFor(ValueMatcher<Request> requestMatcher) {
	return RequestPatternBuilder.forCustomMatcher(requestMatcher);
}

public static void setGlobalFixedDelay(int milliseconds) {
	defaultInstance.get().setGlobalFixedDelayVariable(milliseconds);
}

public void setGlobalFixedDelayVariable(int milliseconds) {
	GlobalSettings settings = globalSettingsHolder.get()
            .copy()
            .fixedDelay(milliseconds)
            .build();
	updateGlobalSettings(settings);
}

public static void setGlobalRandomDelay(DelayDistribution distribution) {
	defaultInstance.get().setGlobalRandomDelayVariable(distribution);
}

public void setGlobalRandomDelayVariable(DelayDistribution distribution) {
	GlobalSettings settings = globalSettingsHolder.get()
            .copy()
            .delayDistribution(distribution)
            .build();
	updateGlobalSettings(settings);
}

public static void updateSettings(GlobalSettings settings) {
    defaultInstance.get().updateGlobalSettings(settings);
}

public void updateGlobalSettings(GlobalSettings settings) {
	globalSettingsHolder.replaceWith(settings);
	admin.updateGlobalSettings(settings);
}

public void shutdown() {
    admin.shutdownServer();
}

public static void shutdownServer() {
    defaultInstance.get().shutdown();
}

public static List<NearMiss> findNearMissesForAllUnmatched() {
    return defaultInstance.get().findNearMissesForAllUnmatchedRequests();
}

public List<NearMiss> findNearMissesForAllUnmatchedRequests() {
    FindNearMissesResult nearMissesResult = admin.findNearMissesForUnmatchedRequests();
    return nearMissesResult.getNearMisses();
}

public static List<LoggedRequest> findUnmatchedRequests() {
    return defaultInstance.get().findAllUnmatchedRequests();
}

public List<LoggedRequest> findAllUnmatchedRequests() {
    FindRequestsResult unmatchedResult = admin.findUnmatchedRequests();
    return unmatchedResult.getRequests();
}

public static List<NearMiss> findNearMissesFor(LoggedRequest loggedRequest) {
    return defaultInstance.get().findTopNearMissesFor(loggedRequest);
}

public List<NearMiss> findTopNearMissesFor(LoggedRequest loggedRequest) {
    FindNearMissesResult nearMissesResult = admin.findTopNearMissesFor(loggedRequest);
    return nearMissesResult.getNearMisses();
}

public static List<NearMiss> findNearMissesFor(RequestPatternBuilder requestPatternBuilder) {
    return defaultInstance.get().findAllNearMissesFor(requestPatternBuilder);
}

public List<NearMiss> findAllNearMissesFor(RequestPatternBuilder requestPatternBuilder) {
    FindNearMissesResult nearMissesResult = admin.findTopNearMissesFor(requestPatternBuilder.build());
    return nearMissesResult.getNearMisses();
}

public void loadMappingsFrom(String rootDir) {
    loadMappingsFrom(new File(rootDir));
}

public void loadMappingsFrom(File rootDir) {
	FileSource mappingsSource = new SingleRootFileSource(rootDir);
	new RemoteMappingsLoader(mappingsSource, this).load();
}

public static List<StubMapping> snapshotRecord() {
    return defaultInstance.get().takeSnapshotRecording();
}

public static List<StubMapping> snapshotRecord(RecordSpecBuilder spec) {
    return defaultInstance.get().takeSnapshotRecording(spec);
}

public List<StubMapping> takeSnapshotRecording() {
    return admin.snapshotRecord().getStubMappings();
}

public List<StubMapping> takeSnapshotRecording(RecordSpecBuilder spec) {
    return admin.snapshotRecord(spec.build()).getStubMappings();
}

public static MultipartValuePatternBuilder aMultipart() {
    return new MultipartValuePatternBuilder();
}

public static MultipartValuePatternBuilder aMultipart(String name) {
    return new MultipartValuePatternBuilder(name);
}

public static void startRecording(String targetBaseUrl) {
    defaultInstance.get().startStubRecording(targetBaseUrl);
}

public static void startRecording(RecordSpecBuilder spec) {
    defaultInstance.get().startStubRecording(spec);
}

public void startStubRecording(String targetBaseUrl) {
    admin.startRecording(targetBaseUrl);
}

public void startStubRecording(RecordSpecBuilder spec) {
    admin.startRecording(spec.build());
}

public static SnapshotRecordResult stopRecording() {
    return defaultInstance.get().stopStubRecording();
}

public SnapshotRecordResult stopStubRecording() {
    return admin.stopRecording();
}

public static RecordingStatusResult getRecordingStatus() {
    return defaultInstance.get().getStubRecordingStatus();
}

public RecordingStatusResult getStubRecordingStatus() {
    return admin.getRecordingStatus();
}

public static RecordSpecBuilder recordSpec() {
    return new RecordSpecBuilder();
}

public List<StubMapping> findAllStubsByMetadata(StringValuePattern pattern) {
    return admin.findAllStubsByMetadata(pattern).getMappings();
}

public static List<StubMapping> findStubsByMetadata(StringValuePattern pattern) {
    return defaultInstance.get().findAllStubsByMetadata(pattern);
}

public void removeStubsByMetadataPattern(StringValuePattern pattern) {
    admin.removeStubsByMetadata(pattern);
}

public static void removeStubsByMetadata(StringValuePattern pattern) {
    defaultInstance.get().removeStubsByMetadataPattern(pattern);
}

public void importStubMappings(StubImport stubImport) {
    admin.importStubs(stubImport);
}

public void importStubMappings(StubImportBuilder stubImport) {
    importStubMappings(stubImport.build());
}

public static void importStubs(StubImportBuilder stubImport) {
    importStubs(stubImport.build());
}

public static void importStubs(StubImport stubImport) {
    defaultInstance.get().importStubMappings(stubImport);
}

public GlobalSettings getGlobalSettings() {
    return admin.getGlobalSettings().getSettings();
}

public static GlobalSettings getSettings() {
    return defaultInstance.get().getGlobalSettings();
}

} ` and the error is:

` Caused by: 2021-10-20T13:21:16.702-0500 [DEBUG] [TestEventLogger] javax.ws.rs.ProcessingException: java.lang.reflect.InaccessibleObjectException: Unable to make field protected java.lang.String java.net.HttpURLConnection.method accessible: module java.base does not "opens java.net" to unnamed module @543c6f6d

`

I tried to add args in gradle test task and it didn't work test { useTestNG() def addOpenArgs = ['--add-exports','java.base/sun.security.x509=ALL-UNNAMED'] jvmArgs+=addOpenArgs; }

actually I forgot one part: in our logic we also used the following code to get the response
(Response response = client.target(ourConfig.getBaseUrl())
.path(a random url)
.resolveTemplate("a random uuid", a random uuid)
.property(HttpUrlConnectorProvider.SET_METHOD_WORKAROUND, true)
.request(MediaType.APPLICATION_JSON_TYPE)
so it can be the jersey client that blocks us, but no matter what we will appreciate it if the remote wiremock can be fixed with the proxy issues. I am using the standalone one now and it seems to do what it should do. But we probably cannot use standalone for other environments

@timtebeek timtebeek mentioned this issue Nov 5, 2021
2 tasks
@tomakehurst tomakehurst moved this from To do to In progress in WireMock 2.32.0 Nov 22, 2021
@tomakehurst tomakehurst moved this from In progress to Done in WireMock 2.32.0 Nov 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Development

Successfully merging a pull request may close this issue.

4 participants