// Path: rsimulator-core/src/main/java/com/github/bjuvensjo/rsimulator/core/Simulator.java
// @ImplementedBy(SimulatorImpl.class)
// public interface Simulator {
// 
//     /**
//      * Returns a SimulatorResponse that matches the specified request.
//      *
//      * @param rootPath         the root path on which to search recursively for matches to the specified request
//      * @param rootRelativePath the path on which to search recursively for matches to the specified request
//      * @param request          the request
//      * @param contentType      the content type of the request, e.g. txt or xml
//      * @param vars             vars that can be used in for example scripts
//      * @return a SimulatorResponse that matches the specified request
//      */
//     Optional<SimulatorResponse> service(String rootPath, String rootRelativePath, String request, String contentType, Map<String, Object>... vars);
// }
// 
// Path: rsimulator-core/src/main/java/com/github/bjuvensjo/rsimulator/core/SimulatorResponse.java
// public interface SimulatorResponse {
// 
//     /**
//      * Returns the properties of a specific test data request and response pair. If the name of the test data request
//      * file for instance is Test1Request.xml, the properties file must be named Test1.properties. For supported
//      * properties, see *PropertiesInterceptor classes.
//      *
//      * @return the properties of a specific test data request and response pair
//      */
//     Optional<Properties> getProperties();
// 
//     /**
//      * Sets the specified properties.
//      *
//      * @param properties the properties to set
//      */
//     void setProperties(Optional<Properties> properties);
// 
//     /**
//      * Returns the test data response.
//      *
//      * @return the test data response
//      */
//     String getResponse();
// 
//     /**
//      * Sets the specified response.
//      *
//      * @param response the response to set
//      */
//     void setResponse(String response);
// 
//     /**
//      * Returns the matching request path.
//      *
//      * @return the matching request path
//      */
//     Path getMatchingRequest();
// 
//     /**
//      * Sets the specified path.
//      *
//      * @param path the path to set
//      */
//     void setMatchingRequest(Path path);
// }


import com.github.bjuvensjo.rsimulator.core.Simulator;
import com.github.bjuvensjo.rsimulator.core.SimulatorResponse;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.thoughtworks.xstream.XStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;
     * @param declaringClassCanonicalName the class that declares the intercepted method
     * @param methodName                  the name of the intercepted method
     * @param arguments                   the arguments to the intercepted method
     * @param rootPath                    the root path in which to (recursively) find simulator test data
     * @param useRootRelativePath         true if the declaringClassCanonicalName and methodName should be used as an relative path extension of rootPath, otherwise false
     * @return some simulation response
     * @throws Exception if something goes wrong
     */
    @SuppressWarnings("unchecked")
    public Object service(String declaringClassCanonicalName, String methodName, Object[] arguments, String rootPath, boolean useRootRelativePath)
            throws Exception {
        String rootRelativePath = useRootRelativePath ? getRootRelativePath(declaringClassCanonicalName, methodName) : "";
        String simulatorRequest = createRequest(arguments);

        Optional<SimulatorResponse> simulatorResponseOptional = simulator.service(rootPath, rootRelativePath, simulatorRequest, CONTENT_TYPE);

        Object response = simulatorResponseOptional
                .map(sr -> createResponse(sr.getResponse()))
                .orElse(null);

        if (response instanceof Throwable) {
            throw (Exception) response;
        }
        return response;
    }

    private String createRequest(Object[] arguments) {
        XStream xstream = new XStream();
        StringBuilder request = new StringBuilder();
        request.append(XML_VERSION);
// Path: rsimulator-core/src/main/java/com/github/bjuvensjo/rsimulator/core/Simulator.java
// @ImplementedBy(SimulatorImpl.class)
// public interface Simulator {
// 
//     /**
//      * Returns a SimulatorResponse that matches the specified request.
//      *
//      * @param rootPath         the root path on which to search recursively for matches to the specified request
//      * @param rootRelativePath the path on which to search recursively for matches to the specified request
//      * @param request          the request
//      * @param contentType      the content type of the request, e.g. txt or xml
//      * @param vars             vars that can be used in for example scripts
//      * @return a SimulatorResponse that matches the specified request
//      */
//     Optional<SimulatorResponse> service(String rootPath, String rootRelativePath, String request, String contentType, Map<String, Object>... vars);
// }
// 
// Path: rsimulator-core/src/main/java/com/github/bjuvensjo/rsimulator/core/SimulatorResponse.java
// public interface SimulatorResponse {
// 
//     /**
//      * Returns the properties of a specific test data request and response pair. If the name of the test data request
//      * file for instance is Test1Request.xml, the properties file must be named Test1.properties. For supported
//      * properties, see *PropertiesInterceptor classes.
//      *
//      * @return the properties of a specific test data request and response pair
//      */
//     Optional<Properties> getProperties();
// 
//     /**
//      * Sets the specified properties.
//      *
//      * @param properties the properties to set
//      */
//     void setProperties(Optional<Properties> properties);
// 
//     /**
//      * Returns the test data response.
//      *
//      * @return the test data response
//      */
//     String getResponse();
// 
//     /**
//      * Sets the specified response.
//      *
//      * @param response the response to set
//      */
//     void setResponse(String response);
// 
//     /**
//      * Returns the matching request path.
//      *
//      * @return the matching request path
//      */
//     Path getMatchingRequest();
// 
//     /**
//      * Sets the specified path.
//      *
//      * @param path the path to set
//      */
//     void setMatchingRequest(Path path);
// }


// Path: rsimulator-aop/src/main/java/com/github/bjuvensjo/rsimulator/aop/SimulatorAdapter.java
import com.github.bjuvensjo.rsimulator.core.Simulator;
import com.github.bjuvensjo.rsimulator.core.SimulatorResponse;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.thoughtworks.xstream.XStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Optional;

     * @param declaringClassCanonicalName the class that declares the intercepted method
     * @param methodName                  the name of the intercepted method
     * @param arguments                   the arguments to the intercepted method
     * @param rootPath                    the root path in which to (recursively) find simulator test data
     * @param useRootRelativePath         true if the declaringClassCanonicalName and methodName should be used as an relative path extension of rootPath, otherwise false
     * @return some simulation response
     * @throws Exception if something goes wrong
     */
    @SuppressWarnings("unchecked")
    public Object service(String declaringClassCanonicalName, String methodName, Object[] arguments, String rootPath, boolean useRootRelativePath)
            throws Exception {
        String rootRelativePath = useRootRelativePath ? getRootRelativePath(declaringClassCanonicalName, methodName) : "";
        String simulatorRequest = createRequest(arguments);

        Optional<SimulatorResponse> simulatorResponseOptional = simulator.service(rootPath, rootRelativePath, simulatorRequest, CONTENT_TYPE);

        Object response = simulatorResponseOptional
                .map(sr -> createResponse(sr.getResponse()))
                .orElse(null);

        if (response instanceof Throwable) {
            throw (Exception) response;
        }
        return response;
    }

    private String createRequest(Object[] arguments) {
        XStream xstream = new XStream();
        StringBuilder request = new StringBuilder();
        request.append(XML_VERSION);
        request.append(REQUEST_BEGIN);