Email.java
001 /*
002  * Java GPX Library (jpx-3.1.0).
003  * Copyright (c) 2016-2023 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.jpx;
021 
022 import static java.lang.String.format;
023 import static java.util.Objects.hash;
024 import static java.util.Objects.requireNonNull;
025 
026 import java.io.DataInput;
027 import java.io.DataOutput;
028 import java.io.IOException;
029 import java.io.InvalidObjectException;
030 import java.io.ObjectInputStream;
031 import java.io.Serial;
032 import java.io.Serializable;
033 import java.util.Objects;
034 
035 /**
036  * An email address. Broken into two parts (id and domain) to help prevent email
037  * harvesting.
038  *
039  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
040  @version 1.2
041  @since 1.0
042  */
043 public final class Email implements Comparable<Email>, Serializable {
044 
045     @Serial
046     private static final long serialVersionUID = 2L;
047 
048     private final String _id;
049     private final String _domain;
050 
051     /**
052      * Create a new {@code Email} object with the given {@code id} and
053      * {@code domain}.
054      *
055      @param id id half of email address (billgates2004)
056      @param domain domain half of email address (hotmail.com)
057      @throws NullPointerException if one of the argument is {@code null}
058      */
059     private Email(final String id, final String domain) {
060         _id = requireNonNull(id);
061         _domain = requireNonNull(domain);
062     }
063 
064     /**
065      * Return the id half of the email address.
066      *
067      @return the id half of the email address
068      */
069     public String getID() {
070         return _id;
071     }
072 
073     /**
074      * Return the domain half of the email address.
075      *
076      @return the domain half of the email address
077      */
078     public String getDomain() {
079         return _domain;
080     }
081 
082     /**
083      * Return the full EMail address: id + "@" + domain.
084      *
085      @return the full EMail address: id + "@" + domain
086      */
087     public String getAddress() {
088         return _id + "@" + _domain;
089     }
090 
091     @Override
092     public int compareTo(final Email other) {
093         int cmp = _domain.compareTo(other._domain);
094         if (cmp == 0) {
095             cmp = _id.compareTo(other._id);
096         }
097 
098         return cmp;
099     }
100 
101     @Override
102     public int hashCode() {
103         return hash(_id, _domain);
104     }
105 
106     @Override
107     public boolean equals(final Object obj) {
108         return obj == this ||
109             obj instanceof Email email &&
110             Objects.equals(email._id, _id&&
111             Objects.equals(email._domain, _domain);
112     }
113 
114     @Override
115     public String toString() {
116         return getAddress();
117     }
118 
119 
120     /* *************************************************************************
121      *  Static object creation methods
122      * ************************************************************************/
123 
124     /**
125      * Create a new {@code Email} object with the given {@code id} and
126      * {@code domain}.
127      *
128      @param id id half of email address (billgates2004)
129      @param domain domain half of email address (hotmail.com)
130      @return a new {@code Email} object with the given values
131      @throws NullPointerException if one of the argument is {@code null}
132      */
133     public static Email of(final String id, final String domain) {
134         return new Email(id, domain);
135     }
136 
137     /**
138      * Create a new {@code Email} from the given {@code address} string.
139      *
140      @param address the email address string
141      @return a new {@code Email} object with {@code address}
142      @throws NullPointerException if one of the argument is {@code null}
143      @throws IllegalArgumentException if the given {@code address} is invalid
144      */
145     public static Email of(final String address) {
146         if (address.length() 3) {
147             throw new IllegalArgumentException(format(
148                 "Invalid email: '%s'.", address
149             ));
150         }
151 
152         final int index = address.indexOf('@');
153         if (index == -|| index == || index == address.length()) {
154             throw new IllegalArgumentException(format(
155                 "Invalid email: '%s'.", address
156             ));
157         }
158 
159         return new Email(
160             address.substring(0, index),
161             address.substring(index + 1)
162         );
163     }
164 
165 
166     /* *************************************************************************
167      *  Java object serialization
168      * ************************************************************************/
169 
170     @Serial
171     private Object writeReplace() {
172         return new SerialProxy(SerialProxy.EMAIL, this);
173     }
174 
175     @Serial
176     private void readObject(final ObjectInputStream stream)
177         throws InvalidObjectException
178     {
179         throw new InvalidObjectException("Serialization proxy required.");
180     }
181 
182     void write(final DataOutput outthrows IOException {
183         IO.writeString(getAddress(), out);
184     }
185 
186     static Email read(final DataInput inthrows IOException {
187         return Email.of(IO.readString(in));
188     }
189 
190     /* *************************************************************************
191      *  XML stream object serialization
192      * ************************************************************************/
193 
194     static final XMLWriter<Email> WRITER = XMLWriter.elem("email",
195         XMLWriter.attr("id").map(email -> email._id),
196         XMLWriter.attr("domain").map(email -> email._domain)
197     );
198 
199     static final XMLReader<Email> READER = XMLReader.elem(
200         v -> Email.of((String)v[0](String)v[1]),
201         "email",
202         XMLReader.attr("id"),
203         XMLReader.attr("domain")
204     );
205 
206 }