aboutsummaryrefslogtreecommitdiffstats
path: root/container-core/src/test/java/com/yahoo/processing/processors/MockUserDatabaseClient.java
blob: 698e70f01e425b9542c866da53767fc02670452d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.processing.processors;

import com.yahoo.component.chain.dependencies.Provides;
import com.yahoo.container.jdisc.HttpRequest;
import com.yahoo.jdisc.handler.*;
import com.yahoo.processing.Processor;
import com.yahoo.processing.Request;
import com.yahoo.processing.Response;
import com.yahoo.processing.execution.Execution;

import java.net.URI;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

@Provides("User")
public class MockUserDatabaseClient extends Processor {

    @Override
    public Response process(Request request, Execution execution) {
        try {
            Dispatch.CompleteResponse response =
                    new Dispatch("pio://endpoint/parameters",request).get(request.properties().getInteger("timeout"), TimeUnit.MILLISECONDS);
            User user = decodeResponseToUser(response);
            request.properties().set("User", user);
            return execution.process(request);
        }
        catch (InterruptedException | ExecutionException | TimeoutException e) {
            throw new RuntimeException("Exception waiting for database", e);
        }
    }

    private User decodeResponseToUser(Dispatch.CompleteResponse response) {
        // Just a mock implementation ...
        String responseData = response.nextString();
        if ( ! responseData.startsWith("id="))
            throw new IllegalArgumentException("Unexpected response "  + responseData);
        int newLine = responseData.indexOf("\n");
        if (newLine<0)
            throw new IllegalArgumentException("Unexpected response "  + responseData);
        String id = responseData.substring(3,newLine);

        // Make sure to always consume all
        while ( (responseData=response.nextString()) !=null) { }

        return new User(id);
    }

    // TODO: Move this to a top-level class
    public static class User {

        // TODO: OO model of users

        private String id;

        public User(String id) {
            this.id = id;
        }

        public String getId() { return id; }

    }

    private static class Dispatch {

        private final SimpleRequestDispatch requestDispatch;

        public Dispatch(String requestUri,Request request) {
            this.requestDispatch = new SimpleRequestDispatch(requestUri, request);
        }

        public CompleteResponse get(int timeout, TimeUnit timeUnit) throws InterruptedException, ExecutionException, TimeoutException {
            return new CompleteResponse(requestDispatch.get(timeout, timeUnit),
                                        requestDispatch.getResponseContent());
        }

        public static class CompleteResponse {

            private final com.yahoo.jdisc.Response response;
            private final ReadableContentChannel responseData;

            public CompleteResponse(com.yahoo.jdisc.Response response, ReadableContentChannel responseData) {
                this.response = response;
                this.responseData = responseData;
            }

            public com.yahoo.jdisc.Response response() { return response; }

            public ReadableContentChannel responseData() { return responseData; }

            /**
             * Convenience which returns the next piece of content from the response data of this as a string, or
             * null if there is no more data. The channel must always be consumed until there is no more data.
             */
            private String nextString() {
                ByteBuffer nextBuffer = responseData.read();
                if (nextBuffer == null) return null; // end of transmission
                return Charset.forName("utf-8").decode(nextBuffer).toString();
            }

        }

        private static class SimpleRequestDispatch extends RequestDispatch {

            private final URI requestUri;
            private final com.yahoo.jdisc.Request parentRequest;
            private final ReadableContentChannel responseData = new ReadableContentChannel();

            public SimpleRequestDispatch(String requestUri,Request request) {
                this.requestUri = URI.create(requestUri);
                this.parentRequest = ((HttpRequest)request.properties().get("jdisc.request")).getJDiscRequest();
                dispatch();
            }

            @Override
            protected com.yahoo.jdisc.Request newRequest() {
                return new com.yahoo.jdisc.Request(parentRequest, requestUri);
            }

            @Override
            public ContentChannel handleResponse(com.yahoo.jdisc.Response response) {
                return responseData;
            }

            public ReadableContentChannel getResponseContent() {
                return responseData;
            }

        }

    }

}