001/**
002 *
003 * Copyright © 2014-2018 Florian Schmaus
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 */
017package org.jxmpp.jid.parts;
018
019import org.jxmpp.stringprep.XmppStringPrepUtil;
020import org.jxmpp.stringprep.XmppStringprepException;
021import org.jxmpp.util.XmppStringUtils;
022
023/**
024 * A <i>localpart</i> of an XMPP address (JID). The localpart is the part before the
025 * first @ sign in an XMPP address and usually identifies the user (or the XMPP
026 * entity) within an XMPP service. It is also often referred to as "username",
027 * but note that the actual username used to login may be different from the
028 * resulting localpart of the user's JID.
029 * <p>
030 * You can create instances of this class from Strings using {@link #from(String)}.
031 * </p>
032 *
033 * @see <a href="http://xmpp.org/rfcs/rfc6122.html#addressing-localpart">RFC
034 *      6122 § 2.3. Localpart</a>
035 */
036public class Localpart extends Part {
037
038        /**
039         *
040         */
041        private static final long serialVersionUID = 1L;
042
043        private transient String unescapedCache;
044
045        private Localpart(String localpart) {
046                super(localpart);
047        }
048
049        /**
050         * Return the <b>unescaped</b> String representation of this Localpart.
051         * <p>
052         * Since certain Unicode code points are disallowed in the localpart of a JID by the required stringprep profile,
053         * those need to get escaped when used in a real JID. The unescaped representation of the JID is only for
054         * presentation to a human user or for gatewaying to a non-XMPP system.
055         * </p>
056         *
057         * @return the unescaped String representation of this JID.
058         * @see org.jxmpp.jid.Jid#asUnescapedString()
059         * @since 0.6.1
060         */
061        public String asUnescapedString() {
062                if (unescapedCache != null) {
063                        return unescapedCache;
064                }
065                unescapedCache = XmppStringUtils.unescapeLocalpart(toString());
066                return unescapedCache;
067        }
068
069        /**
070         * Like {@link #from(String)} but does throw an unchecked {@link IllegalArgumentException} instead of a
071         * {@link XmppStringprepException}.
072         *
073         * @param cs the character sequence which should be transformed to a {@link Localpart}
074         * @return the {@link Localpart} if no exception occurs
075         * @throws IllegalArgumentException if the given input is not a valid {@link Localpart}
076         * @see #from(String)
077         * @since 0.6.2
078         */
079        public static Localpart fromOrThrowUnchecked(CharSequence cs) {
080                try {
081                        return from(cs.toString());
082                } catch (XmppStringprepException e) {
083                        throw new IllegalArgumentException(e);
084                }
085        }
086
087        /**
088         * Like {@link #fromUnescaped(String)} but does throw an unchecked {@link IllegalArgumentException} instead of a
089         * {@link XmppStringprepException}.
090         *
091         * @param cs the character sequence which should be transformed to a {@link Localpart}
092         * @return the {@link Localpart} if no exception occurs
093         * @see #from(String)
094         * @since 0.6.2
095         */
096        public static Localpart fromUnescapedOrThrowUnchecked(CharSequence cs) {
097                try {
098                        return fromUnescaped(cs.toString());
099                } catch (XmppStringprepException e) {
100                        throw new IllegalArgumentException(e);
101                }
102        }
103
104        /**
105         * Get a {@link Localpart} from a given {@link CharSequence} or {@code null} if the input is not a valid localpart.
106         *
107         * @param cs the input CharSequence
108         * @return a Localpart or {@code null}
109         */
110        public static Localpart formUnescapedOrNull(CharSequence cs) {
111                try {
112                        return fromUnescaped(cs);
113                } catch (XmppStringprepException e) {
114                        return null;
115                }
116        }
117
118        /**
119         * Get a {@link Localpart} from an unescaped String.
120         *
121         * @param unescapedLocalpart an unescaped String representing a Localpart.
122         * @return a Localpart
123         * @throws XmppStringprepException if an error occurs.
124         * @since 0.6.2
125         */
126        public static Localpart fromUnescaped(String unescapedLocalpart) throws XmppStringprepException {
127                String escapedLocalpartString = XmppStringUtils.escapeLocalpart(unescapedLocalpart);
128                return from(escapedLocalpartString);
129        }
130
131        /**
132         * Get a {@link Localpart} from an unescaped CharSequence.
133         *
134         * @param unescapedLocalpart an unescaped CharSequence representing a Localpart.
135         * @return a Localpart
136         * @throws XmppStringprepException if an error occurs.
137         * @since 0.6.2
138         */
139        public static Localpart fromUnescaped(CharSequence unescapedLocalpart) throws XmppStringprepException {
140                return fromUnescaped(unescapedLocalpart.toString());
141        }
142
143        /**
144         * Get a {@link Localpart} from a given {@link CharSequence} or {@code null} if the input is not a valid localpart.
145         *
146         * @param cs the input CharSequence
147         * @return a Localpart or {@code null}
148         */
149        public static Localpart fromOrNull(CharSequence cs) {
150                try {
151                        return from(cs.toString());
152                } catch (XmppStringprepException e) {
153                        return null;
154                }
155        }
156
157        /**
158         * Get the {@link Localpart} representing the input String.
159         *
160         * @param localpart the input String.
161         * @return the localpart.
162         * @throws XmppStringprepException if an error occurs.
163         */
164        public static Localpart from(String localpart) throws XmppStringprepException {
165                localpart = XmppStringPrepUtil.localprep(localpart);
166                // First prep the String, then assure the limits of the *result*
167                assertNotLongerThan1023BytesOrEmpty(localpart);
168                return new Localpart(localpart);
169        }
170}