aboutsummaryrefslogtreecommitdiffstats
path: root/controller-api/src/main/java/com/yahoo/vespa/hosted/controller/tenant/TenantContacts.java
blob: 6447e83113fbde55e050b607ca081b36fb220a10 (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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.hosted.controller.tenant;

import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * Tenant contacts are targets of the notification system.  Sometimes they
 * are a person with an email address, other times they are a Slack channel,
 * IRC plugin, etc.
 *
 * @author ogronnesby
 */
public class TenantContacts {
    private final List<? extends Contact> contacts;

    public TenantContacts(List<? extends Contact> contacts) {
        this.contacts = List.copyOf(contacts);
        for (int i = 0; i < contacts.size(); i++) {
            for (int j = 0; j < i; j++) {
                if (contacts.get(i).equals(contacts.get(j))) {
                    throw new IllegalArgumentException("Duplicate contact: " + contacts.get(i));
                }
            }
        }
    }

    public static TenantContacts empty() {
        return new TenantContacts(List.of());
    }

    public List<? extends Contact> all() {
        return contacts;
    }

    public <T extends Contact> List<T> ofType(Class<T> type) {
        return contacts.stream()
                .filter(type::isInstance)
                .map(type::cast)
                .toList();
    }

    public boolean isEmpty() {
        return contacts.isEmpty();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        TenantContacts that = (TenantContacts) o;
        return contacts.equals(that.contacts);
    }

    @Override
    public int hashCode() {
        return Objects.hash(contacts);
    }

    @Override
    public String toString() {
        return "TenantContacts{" +
                "contacts=" + contacts +
                '}';
    }

    public abstract static class Contact {
        private final List<Audience> audiences;

        public Contact(List<Audience> audiences) {
            this.audiences = List.copyOf(audiences);
            if (audiences.isEmpty()) throw new IllegalArgumentException("At least one notification activity must be enabled");
        }

        public List<Audience> audiences() { return audiences; }

        public abstract Type type();

        public abstract boolean equals(Object o);
        public abstract int hashCode();
        public abstract String toString();
    }

    public static class EmailContact extends Contact {
        private final Email email;

        public EmailContact(List<Audience> audiences, Email email) {
            super(audiences);
            this.email = email;
        }

        public Email email() { return email; }

        public EmailContact withEmail(Email email) {
            return new EmailContact(audiences(), email);
        }

        @Override
        public Type type() {
            return Type.EMAIL;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            EmailContact that = (EmailContact) o;
            return email.equals(that.email);
        }

        @Override
        public int hashCode() {
            return Objects.hash(email);
        }

        @Override
        public String toString() {
            return "email '" + email + '\'';
        }
    }

    public enum Type {
        EMAIL("email");

        private final String value;

        Type(String value) {
            this.value = value;
        }

        public String value() {
            return this.value;
        }

        public static Optional<Type> from(String value) {
            return Arrays.stream(Type.values()).filter(x -> x.value().equals(value)).findAny();
        }
    }

    public enum Audience {
        // tenant admin type updates about billing etc.
        TENANT("tenant"),

        // system notifications like deployment failures etc.
        NOTIFICATIONS("notifications");

        private final String value;

        Audience(String value) {
            this.value = value;
        }

        public String value() {
            return value;
        }

        public static Optional<Audience> from(String value) {
            return Arrays.stream(Audience.values()).filter((x -> x.value().equals(value))).findAny();
        }
    }
}