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 == -1 || index == 0 || 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 out) throws IOException {
183 IO.writeString(getAddress(), out);
184 }
185
186 static Email read(final DataInput in) throws 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 }
|