001/**
002 *
003 * Copyright © 2014-2022 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.impl;
018
019import java.io.UnsupportedEncodingException;
020import java.net.URLDecoder;
021
022import org.jxmpp.JxmppContext;
023import org.jxmpp.jid.BareJid;
024import org.jxmpp.jid.EntityBareJid;
025import org.jxmpp.jid.DomainBareJid;
026import org.jxmpp.jid.DomainFullJid;
027import org.jxmpp.jid.EntityFullJid;
028import org.jxmpp.jid.EntityJid;
029import org.jxmpp.jid.FullJid;
030import org.jxmpp.jid.Jid;
031import org.jxmpp.jid.parts.Domainpart;
032import org.jxmpp.jid.parts.Localpart;
033import org.jxmpp.jid.parts.Resourcepart;
034import org.jxmpp.stringprep.XmppStringprep;
035import org.jxmpp.stringprep.XmppStringprepException;
036import org.jxmpp.util.cache.Cache;
037import org.jxmpp.util.cache.LruCache;
038import org.jxmpp.util.XmppStringUtils;
039
040/**
041 * API to create JIDs (XMPP addresses) from Strings and CharSequences.
042 * <p>
043 * If the input was user generated, e.g. captured from some sort of user
044 * interface, {@link #fromUnescaped(String)} should be used instead. This allows
045 * the user to enter unescaped JID values. You can use
046 * {@link org.jxmpp.jid.util.JidUtil#isValidEntityBareJid(CharSequence)} to
047 * query, e.g. while the user it entering it, if a given CharSequence is a valid
048 * bare JID.
049 * </p>
050 * <p>
051 * JIDs created from input received from an XMPP source should use
052 * {@link #from(String)}.
053 * </p>
054 * <p>
055 * JidCreate uses caches for efficient Jid construction, But it's not guaranteed
056 * that the same String or CharSequence will yield the same Jid instance.
057 * </p>
058 *
059 * @see Jid
060 */
061public class JidCreate {
062
063        private static class JidStringAndStringprep {
064                private final String jidString;
065                private final XmppStringprep stringprep;
066
067                private JidStringAndStringprep(String jidString, JxmppContext context) {
068                        this(jidString, context.xmppStringprep);
069                }
070
071                private JidStringAndStringprep(String jidString, XmppStringprep stringprep) {
072                        this.jidString = jidString;
073                        this.stringprep = stringprep;
074                }
075
076                @Override
077                public boolean equals(Object other) {
078                        if (!(other instanceof JidStringAndStringprep))
079                                return false;
080
081                        JidStringAndStringprep otherJidStringAndStringprep = (JidStringAndStringprep) other;
082                        return jidString.equals(otherJidStringAndStringprep.jidString) && stringprep.equals(otherJidStringAndStringprep.stringprep);
083                }
084
085                private transient Integer hashCode;
086
087                @Override
088                public int hashCode() {
089                        if (hashCode == null) {
090                                int result = 17;
091                                result = 31 * result + jidString.hashCode();
092                                result = 31 * result + stringprep.hashCode();
093                                hashCode = result;
094                        }
095                        return hashCode;
096                }
097        }
098
099        private static final Cache<JidStringAndStringprep, Jid> JID_CACHE = new LruCache<>(100);
100        private static final Cache<JidStringAndStringprep, BareJid> BAREJID_CACHE = new LruCache<>(100);
101        private static final Cache<JidStringAndStringprep, EntityJid> ENTITYJID_CACHE = new LruCache<>(100);
102        private static final Cache<JidStringAndStringprep, FullJid> FULLJID_CACHE = new LruCache<>(100);
103        private static final Cache<JidStringAndStringprep, EntityBareJid> ENTITY_BAREJID_CACHE = new LruCache<>(100);
104        private static final Cache<JidStringAndStringprep, EntityFullJid> ENTITY_FULLJID_CACHE = new LruCache<>(100);
105        private static final Cache<JidStringAndStringprep, DomainBareJid> DOMAINJID_CACHE = new LruCache<>(100);
106        private static final Cache<JidStringAndStringprep, DomainFullJid> DOMAINRESOURCEJID_CACHE = new LruCache<>(100);
107
108        /**
109         * Get a {@link Jid} from the given parts.
110         * <p>
111         * Only the domainpart is required.
112         * </p>
113         *
114         * @param localpart a optional localpart.
115         * @param domainpart a required domainpart.
116         * @param resource a optional resourcepart.
117         * @return a JID which consists of the given parts.
118         * @throws XmppStringprepException if an error occurs.
119         */
120        public static Jid from(CharSequence localpart, CharSequence domainpart, CharSequence resource)
121                        throws XmppStringprepException {
122                return from(localpart.toString(), domainpart.toString(), resource.toString());
123        }
124
125        /**
126         * Get a {@link Jid} from the given parts.
127         * <p>
128         * Only the domainpart is required.
129         * </p>
130         *
131         * @param localpart a optional localpart.
132         * @param domainpart a required domainpart.
133         * @param resource a optional resourcepart.
134         * @return a JID which consists of the given parts.
135         * @throws XmppStringprepException if an error occurs.
136         */
137        public static Jid from(String localpart, String domainpart, String resource) throws XmppStringprepException {
138                return from(localpart, domainpart, resource, JxmppContext.getDefaultContext());
139        }
140
141        /**
142         * Get a {@link Jid} from the given parts.
143         * <p>
144         * Only the domainpart is required.
145         * </p>
146         *
147         * @param localpart a optional localpart.
148         * @param domainpart a required domainpart.
149         * @param resource a optional resourcepart.
150         * @param context the JXMPP context.
151         * @return a JID which consists of the given parts.
152         * @throws XmppStringprepException if an error occurs.
153         */
154        public static Jid from(String localpart, String domainpart, String resource, JxmppContext context) throws XmppStringprepException {
155                String jid = XmppStringUtils.completeJidFrom(localpart, domainpart, resource);
156                return from(localpart, domainpart, resource, jid, context);
157        }
158
159        /**
160         * Get a {@link Jid} from the given parts.
161
162         *
163         * @param localpart a optional localpart.
164         * @param domainpart a required domainpart.
165         * @param resource a optional resourcepart.
166         * @param jidString the raw String of the as parsed.
167         * @param context the JXMPP context.
168         * @return a JID which consists of the given parts.
169         * @throws XmppStringprepException if an error occurs.
170         */
171        private static Jid from(String localpart, String domainpart, String resource, String jidString, JxmppContext context) throws XmppStringprepException {
172                // Every JID must come with an domainpart.
173                if (domainpart.isEmpty()) {
174                        throw XmppStringprepException.MissingDomainpart.from(localpart, resource);
175                }
176
177                // The provided jidString must be equal to the assembled parts.
178                assert jidString.equals(XmppStringUtils.completeJidFrom(localpart, domainpart, resource));
179
180                Jid jid;
181
182                JidStringAndStringprep jidStringAndStringprep = null;
183                if (context.isCachingEnabled()) {
184                        jidStringAndStringprep = new JidStringAndStringprep(jidString, context);
185                }
186                if (jidStringAndStringprep != null) {
187                        jid = JID_CACHE.lookup(jidStringAndStringprep);
188                        if (jid != null) {
189                                return jid;
190                        }
191                }
192
193                jid = null;
194                if (localpart != null && resource != null) {
195                        jid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource, context);
196                } else if (localpart != null && resource == null) {
197                        jid = new LocalAndDomainpartJid(localpart, domainpart, context);
198                } else if (localpart == null && resource == null) {
199                        jid = new DomainpartJid(domainpart, context);
200                } else if (localpart == null && resource != null) {
201                        jid = new DomainAndResourcepartJid(domainpart, resource, context);
202                }
203                assert jid != null;
204
205                if (jidStringAndStringprep != null) {
206                        JID_CACHE.put(jidStringAndStringprep, jid);
207                }
208                return jid;
209        }
210
211        /**
212         * Like {@link #from(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
213         * {@link XmppStringprepException}.
214         *
215         * @param cs the character sequence which should be transformed to a {@link Jid}
216         * @return the {@link Jid} if no exception occurs
217         * @throws IllegalArgumentException if the given input is not a valid JID
218         * @see #from(String)
219         * @since 0.6.2
220         */
221        public static Jid fromOrThrowUnchecked(CharSequence cs) {
222                try {
223                        return from(cs);
224                } catch (XmppStringprepException e) {
225                        throw new IllegalArgumentException(e);
226                }
227        }
228
229        /**
230         * Get a {@link Jid} from a CharSequence.
231         *
232         * @param jid the input CharSequence.
233         * @return the Jid represented by the input CharSequence.
234         * @throws XmppStringprepException if an error occurs.
235         * @see #from(String)
236         */
237        public static Jid from(CharSequence jid) throws XmppStringprepException {
238                return from(jid.toString());
239        }
240
241        /**
242         * Get a {@link Jid} from the given String.
243         *
244         * @param jidString the input String.
245         * @return the Jid represented by the input String.
246         * @throws XmppStringprepException if an error occurs.
247         * @see #from(CharSequence)
248         */
249        public static Jid from(String jidString) throws XmppStringprepException {
250                return from(jidString, JxmppContext.getDefaultContext());
251        }
252
253        /**
254         * Get a {@link Jid} from the given String.
255         *
256         * @param jidString the input String.
257         * @param context the JXMPP context.
258         * @return the Jid represented by the input String.
259         * @throws XmppStringprepException if an error occurs.
260         * @see #from(CharSequence)
261         */
262        public static Jid from(String jidString, JxmppContext context) throws XmppStringprepException {
263                String localpart = XmppStringUtils.parseLocalpart(jidString);
264                String domainpart = XmppStringUtils.parseDomain(jidString);
265                String resource = XmppStringUtils.parseResource(jidString);
266                try {
267                        return from(localpart, domainpart, resource, jidString, context);
268                } catch (XmppStringprepException e) {
269                        throw new XmppStringprepException(jidString, e);
270                }
271        }
272
273        /**
274         * Get a {@link Jid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
275         *
276         * @param cs the input {@link CharSequence}
277         * @return a JID or {@code null}
278         */
279        public static Jid fromOrNull(CharSequence cs) {
280                try {
281                        return from(cs);
282                } catch (XmppStringprepException e) {
283                        return null;
284                }
285        }
286
287        /**
288         * Like {@link #fromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
289         * {@link XmppStringprepException}.
290         *
291         * @param cs the character sequence which should be transformed to a {@link Jid}
292         * @return the {@link Jid} if no exception occurs
293         * @throws IllegalArgumentException if the given input is not a valid JID
294         * @see #fromUnescaped(CharSequence)
295         * @since 0.6.2
296         */
297        public static Jid fromUnescapedOrThrowUnchecked(CharSequence cs) {
298                try {
299                        return fromUnescaped(cs);
300                } catch (XmppStringprepException e) {
301                        throw new IllegalArgumentException(e);
302                }
303        }
304
305        /**
306         * Get a {@link Jid} from the given unescaped CharSequence.
307         *
308         * @param unescapedJid an unescaped CharSequence representing a JID.
309         * @return a JID.
310         * @throws XmppStringprepException if an error occurs.
311         */
312        public static Jid fromUnescaped(CharSequence unescapedJid) throws XmppStringprepException {
313                return fromUnescaped(unescapedJid.toString());
314        }
315
316        /**
317         * Get a {@link Jid} from the given unescaped String.
318         *
319         * @param unescapedJidString a unescaped String representing a JID.
320         * @return a JID.
321         * @throws XmppStringprepException if an error occurs.
322         */
323        public static Jid fromUnescaped(String unescapedJidString) throws XmppStringprepException {
324                String localpart = XmppStringUtils.parseLocalpart(unescapedJidString);
325                // Some as from(String), but we escape the localpart
326                localpart = XmppStringUtils.escapeLocalpart(localpart);
327
328                String domainpart = XmppStringUtils.parseDomain(unescapedJidString);
329                String resource = XmppStringUtils.parseResource(unescapedJidString);
330                try {
331                        return from(localpart, domainpart, resource);
332                } catch (XmppStringprepException e) {
333                        throw new XmppStringprepException(unescapedJidString, e);
334                }
335        }
336
337        /**
338         * Get a {@link Jid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
339         *
340         * @param cs the input {@link CharSequence}
341         * @return a JID or {@code null}
342         */
343        public static Jid fromUnescapedOrNull(CharSequence cs) {
344                try {
345                        return fromUnescaped(cs);
346                } catch (XmppStringprepException e) {
347                        return null;
348                }
349        }
350
351        /**
352         * Get a {@link Jid} from an URL encoded CharSequence.
353         *
354         * @param cs a CharSequence representing an URL encoded JID.
355         * @return a JID
356         * @throws XmppStringprepException if an error occurs.
357         * @see URLDecoder
358         */
359        public static Jid fromUrlEncoded(CharSequence cs) throws XmppStringprepException {
360                String decoded = urlDecode(cs);
361                return from(decoded);
362        }
363
364        /**
365         * Like {@link #bareFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
366         * {@link XmppStringprepException}.
367         *
368         * @param cs the character sequence which should be transformed to a {@link BareJid}
369         * @return the {@link BareJid} if no exception occurs
370         * @throws IllegalArgumentException if the given input is not a valid JID
371         * @see #bareFrom(CharSequence)
372         * @since 0.6.2
373         */
374        public static BareJid bareFromOrThrowUnchecked(CharSequence cs) {
375                try {
376                        return bareFrom(cs);
377                } catch (XmppStringprepException e) {
378                        throw new IllegalArgumentException(e);
379                }
380        }
381
382        /**
383         * Get a {@link BareJid} representing the given CharSequence.
384         *
385         * @param jid the input CharSequence.
386         * @return a bare JID representing the given CharSequence.
387         * @throws XmppStringprepException if an error occurs.
388         */
389        public static BareJid bareFrom(CharSequence jid) throws XmppStringprepException {
390                return bareFrom(jid.toString());
391        }
392
393        /**
394         * Get a {@link BareJid} representing the given String.
395         *
396         * @param jid the input String.
397         * @return a bare JID representing the given String.
398         * @throws XmppStringprepException if an error occurs.
399         */
400        public static BareJid bareFrom(String jid) throws XmppStringprepException {
401                return bareFrom(jid, JxmppContext.getDefaultContext());
402        }
403
404        /**
405         * Get a {@link BareJid} representing the given String.
406         *
407         * @param jid the input String.
408         * @param context the JXMPP context.
409         * @return a bare JID representing the given String.
410         * @throws XmppStringprepException if an error occurs.
411         */
412        public static BareJid bareFrom(String jid, JxmppContext context) throws XmppStringprepException {
413                BareJid bareJid;
414                JidStringAndStringprep jidStringAndStringprep = null;
415                if (context.isCachingEnabled()) {
416                        jidStringAndStringprep = new JidStringAndStringprep(jid, context);
417                }
418
419                if (jidStringAndStringprep != null) {
420                        bareJid = BAREJID_CACHE.lookup(jidStringAndStringprep);
421                        if (bareJid != null) {
422                                return bareJid;
423                        }
424                }
425
426                String localpart = XmppStringUtils.parseLocalpart(jid);
427                String domainpart = XmppStringUtils.parseDomain(jid);
428                try {
429                        if (localpart == null || localpart.length() == 0) {
430                                bareJid = new DomainpartJid(domainpart, context);
431                        } else {
432                                bareJid = new LocalAndDomainpartJid(localpart, domainpart, context);
433                        }
434                } catch (XmppStringprepException e) {
435                        throw new XmppStringprepException(jid, e);
436                }
437
438                if (jidStringAndStringprep != null) {
439                        BAREJID_CACHE.put(jidStringAndStringprep, bareJid);
440                }
441                return bareJid;
442        }
443
444        /**
445         * Get a {@link BareJid} constructed from the optionally given {@link Localpart} and {link DomainBareJid}.
446         *
447         * @param localpart a optional localpart.
448         * @param domainBareJid a domain bare JID.
449         * @return a bare JID.
450         */
451        public static BareJid bareFrom(Localpart localpart, DomainBareJid domainBareJid) {
452                return bareFrom(localpart, domainBareJid.getDomain());
453        }
454
455        /**
456         * Get a {@link BareJid} constructed from the optionally given {@link Localpart} and {@link Domainpart}.
457         *
458         * @param localpart a optional localpart.
459         * @param domain a domainpart.
460         * @return a bare JID constructed from the given parts.
461         */
462        public static BareJid bareFrom(Localpart localpart, Domainpart domain) {
463                if (localpart != null) {
464                        return new LocalAndDomainpartJid(localpart, domain);
465                } else {
466                        return new DomainpartJid(domain);
467                }
468        }
469
470        /**
471         * Get a {@link BareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
472         *
473         * @param cs the input {@link CharSequence}
474         * @return a JID or {@code null}
475         */
476        public static BareJid bareFromOrNull(CharSequence cs) {
477                try {
478                        return bareFrom(cs);
479                } catch (XmppStringprepException e) {
480                        return null;
481                }
482        }
483
484        /**
485         * Get a {@link BareJid} from an URL encoded CharSequence.
486         *
487         * @param cs a CharSequence representing an URL encoded bare JID.
488         * @return a bare JID
489         * @throws XmppStringprepException if an error occurs.
490         * @see URLDecoder
491         */
492        public static BareJid bareFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
493                String decoded = urlDecode(cs.toString());
494                return bareFrom(decoded);
495        }
496
497        /**
498         * Like {@link #fullFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
499         * {@link XmppStringprepException}.
500         *
501         * @param cs the character sequence which should be transformed to a {@link FullJid}
502         * @return the {@link FullJid} if no exception occurs
503         * @throws IllegalArgumentException if the given input is not a valid JID
504         * @see #fullFrom(CharSequence)
505         * @since 0.6.2
506         */
507        public static FullJid fullFromOrThrowUnchecked(CharSequence cs) {
508                try {
509                        return fullFrom(cs);
510                } catch (XmppStringprepException e) {
511                        throw new IllegalArgumentException(e);
512                }
513        }
514
515        /**
516         * Get a {@link FullJid} representing the given CharSequence.
517         *
518         * @param jid a CharSequence representing a JID.
519         * @return a full JID representing the given CharSequence.
520         * @throws XmppStringprepException if an error occurs.
521         */
522        public static FullJid fullFrom(CharSequence jid) throws XmppStringprepException {
523                return fullFrom(jid.toString());
524        }
525
526        /**
527         * Get a {@link FullJid} representing the given String.
528         *
529         * @param jid the JID's String.
530         * @return a full JID representing the input String.
531         * @throws XmppStringprepException if an error occurs.
532         */
533        public static FullJid fullFrom(String jid) throws XmppStringprepException {
534                return fullFrom(jid, JxmppContext.getDefaultContext());
535        }
536
537        /**
538         * Get a {@link FullJid} representing the given String.
539         *
540         * @param jid the JID's String.
541         * @param context the JXMPP context.
542         * @return a full JID representing the input String.
543         * @throws XmppStringprepException if an error occurs.
544         */
545        public static FullJid fullFrom(String jid, JxmppContext context) throws XmppStringprepException {
546                JidStringAndStringprep jidStringAndStringprep = null;
547                if (context.isCachingEnabled()) {
548                        jidStringAndStringprep = new JidStringAndStringprep(jid, context);
549                }
550
551                FullJid fullJid;
552                if (jidStringAndStringprep != null) {
553                        fullJid = FULLJID_CACHE.lookup(jidStringAndStringprep);
554                        if (fullJid != null) {
555                                return fullJid;
556                        }
557                }
558
559                String localpart = XmppStringUtils.parseLocalpart(jid);
560                String domainpart = XmppStringUtils.parseDomain(jid);
561                String resource = XmppStringUtils.parseResource(jid);
562                try {
563                        fullJid = fullFrom(localpart, domainpart, resource);
564                } catch (XmppStringprepException e) {
565                        throw new XmppStringprepException(jid, e);
566                }
567
568                if (jidStringAndStringprep != null) {
569                        FULLJID_CACHE.put(jidStringAndStringprep, fullJid);
570                }
571
572                return fullJid;
573        }
574
575        /**
576         * Get a {@link FullJid} constructed from the given parts.
577         *
578         * @param localpart a optional localpart.
579         * @param domainpart a domainpart.
580         * @param resource a resourcepart.
581         * @return a full JID.
582         * @throws XmppStringprepException if an error occurs.
583         */
584        public static FullJid fullFrom(String localpart, String domainpart, String resource) throws XmppStringprepException {
585                return fullFrom(localpart, domainpart, resource, JxmppContext.getDefaultContext());
586        }
587
588        /**
589         * Get a {@link FullJid} constructed from the given parts.
590         *
591         * @param localpart a optional localpart.
592         * @param domainpart a domainpart.
593         * @param resource a resourcepart.
594         * @param context the JXMPP context.
595         * @return a full JID.
596         * @throws XmppStringprepException if an error occurs.
597         */
598        public static FullJid fullFrom(String localpart, String domainpart, String resource, JxmppContext context) throws XmppStringprepException {
599                FullJid fullJid;
600                try {
601                        if (localpart == null || localpart.length() == 0) {
602                                fullJid = new DomainAndResourcepartJid(domainpart, resource, context);
603                        } else {
604                                fullJid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource, context);
605                        }
606                } catch (XmppStringprepException e) {
607                        throw new XmppStringprepException(localpart + '@' + domainpart + '/' + resource, e);
608                }
609                return fullJid;
610        }
611
612        /**
613         * Get a {@link FullJid} constructed from the given parts.
614         *
615         * @param localpart a optional localpart.
616         * @param domainBareJid a domain bare JID. 
617         * @param resource a resourcepart
618         * @return a full JID.
619         */
620        public static FullJid fullFrom(Localpart localpart, DomainBareJid domainBareJid, Resourcepart resource) {
621                return fullFrom(localpart, domainBareJid.getDomain(), resource);
622        }
623
624        /**
625         * Get a {@link FullJid} constructed from the given parts.
626         *
627         * @param localpart the optional localpart.
628         * @param domainpart the domainpart.
629         * @param resource the resourcepart.
630         * @return a full JID.
631         */
632        public static FullJid fullFrom(Localpart localpart, Domainpart domainpart, Resourcepart resource) {
633                return fullFrom(entityBareFrom(localpart, domainpart), resource);
634        }
635
636        /**
637         * Get a {@link FullJid} constructed from a {@link BareJid} and a {@link Resourcepart}.
638         *
639         * @param bareJid a entity bare JID.
640         * @param resource a resourcepart.
641         * @return a full JID.
642         */
643        public static FullJid fullFrom(BareJid bareJid, Resourcepart resource) {
644                if (bareJid.isEntityBareJid()) {
645                        EntityBareJid entityBareJid = (EntityBareJid) bareJid;
646                        return new LocalDomainAndResourcepartJid(entityBareJid, resource);
647                } else {
648                        DomainBareJid domainBareJid = (DomainBareJid) bareJid;
649                        return new DomainAndResourcepartJid(domainBareJid, resource);
650                }
651        }
652
653        /**
654         * Get a {@link FullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
655         *
656         * @param cs the input {@link CharSequence}
657         * @return a JID or {@code null}
658         */
659        public static FullJid fullFromOrNull(CharSequence cs) {
660                try {
661                        return fullFrom(cs);
662                } catch (XmppStringprepException e) {
663                        return null;
664                }
665        }
666
667        /**
668         * Get a {@link FullJid} from an URL encoded CharSequence.
669         *
670         * @param cs a CharSequence representing an URL encoded full JID.
671         * @return a full JID
672         * @throws XmppStringprepException if an error occurs.
673         * @see URLDecoder
674         */
675        public static FullJid fullFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
676                String decoded = urlDecode(cs);
677                return fullFrom(decoded);
678        }
679
680        /**
681         * Like {@link #entityFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
682         * {@link XmppStringprepException}.
683         *
684         * @param cs the character sequence which should be transformed to a {@link EntityJid}
685         * @return the {@link EntityJid} if no exception occurs
686         * @throws IllegalArgumentException if the given input is not a valid JID
687         * @see #entityFrom(CharSequence)
688         * @since 0.6.2
689         */
690        public static EntityJid entityFromOrThrowUnchecked(CharSequence cs) {
691                try {
692                        return entityFrom(cs);
693                } catch (XmppStringprepException e) {
694                        throw new IllegalArgumentException(e);
695                }
696        }
697
698        /**
699         * Get a {@link EntityJid} representing the given String.
700         *
701         * @param jid the JID's string.
702         * @return an entity JID representing the given String.
703         * @throws XmppStringprepException if an error occurs.
704         */
705        public static EntityJid entityFrom(CharSequence jid) throws XmppStringprepException {
706                return entityFrom(jid.toString());
707        }
708
709        /**
710         * Get a {@link EntityJid} representing the given String.
711         *
712         * @param jidString the JID's string.
713         * @return an entity JID representing the given String.
714         * @throws XmppStringprepException if an error occurs.
715         */
716        public static EntityJid entityFrom(String jidString) throws XmppStringprepException {
717                return entityFrom(jidString, JxmppContext.getDefaultContext());
718        }
719
720        /**
721         * Get a {@link EntityJid} representing the given String.
722         *
723         * @param jidString the JID's string.
724         * @param context the JXMPP context.
725         * @return an entity JID representing the given String.
726         * @throws XmppStringprepException if an error occurs.
727         */
728        public static EntityJid entityFrom(String jidString, JxmppContext context) throws XmppStringprepException {
729                return entityFrom(jidString, false, context);
730        }
731
732        /**
733         * Like {@link #entityFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
734         * {@link XmppStringprepException}.
735         *
736         * @param cs the character sequence which should be transformed to a {@link EntityJid}
737         * @return the {@link EntityJid} if no exception occurs
738         * @throws IllegalArgumentException if the given input is not a valid JID
739         * @see #entityFromUnescaped(CharSequence)
740         * @since 0.6.2
741         */
742        public static EntityJid entityFromUnescapedOrThrowUnchecked(CharSequence cs) {
743                return entityFromUnescapedOrThrowUnchecked(cs, JxmppContext.getDefaultContext());
744        }
745
746        /**
747         * Like {@link #entityFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
748         * {@link XmppStringprepException}.
749         *
750         * @param cs the character sequence which should be transformed to a {@link EntityJid}
751         * @param context the JXMPP context.
752         * @return the {@link EntityJid} if no exception occurs
753         * @throws IllegalArgumentException if the given input is not a valid JID
754         * @see #entityFromUnescaped(CharSequence)
755         * @since 0.6.2
756         */
757        public static EntityJid entityFromUnescapedOrThrowUnchecked(CharSequence cs, JxmppContext context) {
758                try {
759                        return entityFromUnescaped(cs, context);
760                } catch (XmppStringprepException e) {
761                        throw new IllegalArgumentException(e);
762                }
763        }
764
765        /**
766         * Get a {@link EntityJid} representing the given String.
767         *
768         * @param jid the JID.
769         * @return an entity JID representing the given input..
770         * @throws XmppStringprepException if an error occurs.
771         */
772        public static EntityJid entityFromUnescaped(CharSequence jid) throws XmppStringprepException {
773                return entityFromUnescaped(jid, JxmppContext.getDefaultContext());
774        }
775
776        /**
777         * Get a {@link EntityJid} representing the given String.
778         *
779         * @param jid the JID.
780         * @param context the JXMPP context.
781         * @return an entity JID representing the given input.
782         * @throws XmppStringprepException if an error occurs.
783         */
784        public static EntityJid entityFromUnescaped(CharSequence jid, JxmppContext context) throws XmppStringprepException {
785                return entityFromUnescaped(jid.toString(), context);
786        }
787
788        /**
789         * Get a {@link EntityJid} representing the given String.
790         *
791         * @param jidString the JID's string.
792         * @return an entity JID representing the given String.
793         * @throws XmppStringprepException if an error occurs.
794         */
795        public static EntityJid entityFromUnescaped(String jidString) throws XmppStringprepException {
796                return entityFromUnescaped(jidString, JxmppContext.getDefaultContext());
797        }
798
799        /**
800         * Get a {@link EntityJid} representing the given String.
801         *
802         * @param jidString the JID's string.
803         * @param context the JXMPP context.
804         * @return an entity JID representing the given String.
805         * @throws XmppStringprepException if an error occurs.
806         */
807        public static EntityJid entityFromUnescaped(String jidString, JxmppContext context) throws XmppStringprepException {
808                return entityFrom(jidString, true, context);
809        }
810
811        /**
812         * Get a {@link EntityJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
813         *
814         * @param cs the input {@link CharSequence}
815         * @return a JID or {@code null}
816         * @deprecated use {@link #entityFromUnescapedOrNull(CharSequence)} instead.
817         */
818        // TODO: remove in jxmpp 1.1
819        @Deprecated
820        public static EntityJid entityFromUnesacpedOrNull(CharSequence cs) {
821                return entityFromUnescapedOrNull(cs);
822        }
823
824        /**
825         * Get a {@link EntityJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
826         *
827         * @param cs the input {@link CharSequence}
828         * @return a JID or {@code null}
829         */
830        public static EntityJid entityFromUnescapedOrNull(CharSequence cs) {
831                try {
832                        return entityFromUnescaped(cs.toString());
833                } catch (XmppStringprepException e) {
834                        return null;
835                }
836        }
837
838        /**
839         * Get a {@link EntityJid} representing the given String.
840         *
841         * @param jidString the JID's string.
842         * @param unescaped if the JID string is unescaped.
843         * @return an entity JID representing the given String.
844         * @throws XmppStringprepException if an error occurs.
845         */
846        private static EntityJid entityFrom(String jidString, boolean unescaped, JxmppContext context) throws XmppStringprepException {
847                JidStringAndStringprep jidStringAndStringprep = null;
848                if (context.isCachingEnabled()) {
849                        jidStringAndStringprep = new JidStringAndStringprep(jidString, context);
850                }
851
852                EntityJid entityJid;
853                if (jidStringAndStringprep != null) {
854                        entityJid = ENTITYJID_CACHE.lookup(jidStringAndStringprep);
855                        if (entityJid != null) {
856                                return entityJid;
857                        }
858                }
859                String localpartString = XmppStringUtils.parseLocalpart(jidString);
860                if (localpartString == null) {
861                        throw new XmppStringprepException("Does not contain a localpart", jidString);
862                }
863                Localpart localpart;
864                try {
865                        if (unescaped) {
866                                localpart = Localpart.fromUnescaped(localpartString);
867                        } else {
868                                localpart = Localpart.from(localpartString);
869                        }
870                } catch (XmppStringprepException e) {
871                        throw new XmppStringprepException(jidString, e);
872                }
873
874                String domainpartString = XmppStringUtils.parseDomain(jidString);
875                Domainpart domainpart;
876                try {
877                        domainpart = Domainpart.from(domainpartString);
878                } catch (XmppStringprepException e) {
879                        throw new XmppStringprepException(jidString, e);
880                }
881
882                String resourceString = XmppStringUtils.parseResource(jidString);
883                if (resourceString != null) {
884                        Resourcepart resourcepart;
885                        try {
886                                resourcepart = Resourcepart.from(resourceString);
887                        } catch (XmppStringprepException e) {
888                                throw new XmppStringprepException(jidString, e);
889                        }
890                        entityJid = entityFullFrom(localpart, domainpart, resourcepart);
891                } else {
892                        entityJid = entityBareFrom(localpart, domainpart);
893                }
894
895                if (jidStringAndStringprep != null) {
896                        ENTITYJID_CACHE.put(jidStringAndStringprep, entityJid);
897                }
898                return entityJid;
899        }
900
901        /**
902         * Get a {@link EntityJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
903         *
904         * @param cs the input {@link CharSequence}
905         * @return a JID or {@code null}
906         */
907        public static EntityJid entityFromOrNull(CharSequence cs) {
908                try {
909                        return entityFrom(cs);
910                } catch (XmppStringprepException e) {
911                        return null;
912                }
913        }
914
915        /**
916         * Get a {@link EntityJid} from an URL encoded CharSequence.
917         *
918         * @param cs a CharSequence representing an URL encoded entity JID.
919         * @return an entity JID
920         * @throws XmppStringprepException if an error occurs.
921         * @see URLDecoder
922         */
923        public static EntityJid entityFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
924                String decoded = urlDecode(cs);
925                return entityFrom(decoded);
926        }
927
928        /**
929         * Like {@link #entityBareFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
930         * {@link XmppStringprepException}.
931         *
932         * @param cs the character sequence which should be transformed to a {@link EntityBareJid}
933         * @return the {@link EntityBareJid} if no exception occurs
934         * @throws IllegalArgumentException if the given input is not a valid JID
935         * @see #entityBareFrom(CharSequence)
936         * @since 0.6.2
937         */
938        public static EntityBareJid entityBareFromOrThrowUnchecked(CharSequence cs) {
939                try {
940                        return entityBareFrom(cs);
941                } catch (XmppStringprepException e) {
942                        throw new IllegalArgumentException(e);
943                }
944        }
945
946        /**
947         * Get a {@link EntityBareJid} representing the given CharSequence.
948         *
949         * @param jid the input CharSequence.
950         * @return a bare JID representing the given CharSequence.
951         * @throws XmppStringprepException if an error occurs.
952         */
953        public static EntityBareJid entityBareFrom(CharSequence jid) throws XmppStringprepException {
954                return entityBareFrom(jid.toString());
955        }
956
957        /**
958         * Get a {@link EntityBareJid} representing the given String.
959         *
960         * @param jid the input String.
961         * @return a bare JID representing the given String.
962         * @throws XmppStringprepException if an error occurs.
963         */
964        public static EntityBareJid entityBareFrom(String jid) throws XmppStringprepException {
965                return entityBareFrom(jid, JxmppContext.getDefaultContext());
966        }
967
968        /**
969         * Get a {@link EntityBareJid} representing the given String.
970         *
971         * @param jid the input String.
972         * @param context the JXMPP context.
973         * @return a bare JID representing the given String.
974         * @throws XmppStringprepException if an error occurs.
975         */
976        public static EntityBareJid entityBareFrom(String jid, JxmppContext context) throws XmppStringprepException {
977                JidStringAndStringprep jidStringAndStringprep = null;
978                if (context.isCachingEnabled()) {
979                        jidStringAndStringprep = new JidStringAndStringprep(jid, context);
980                }
981
982                EntityBareJid bareJid;
983                if (jidStringAndStringprep != null) {
984                        bareJid = ENTITY_BAREJID_CACHE.lookup(jidStringAndStringprep);
985                        if (bareJid != null) {
986                                return bareJid;
987                        }
988                }
989
990                String localpart = XmppStringUtils.parseLocalpart(jid);
991                String domainpart = XmppStringUtils.parseDomain(jid);
992                try {
993                        bareJid = new LocalAndDomainpartJid(localpart, domainpart, context);
994                } catch (XmppStringprepException e) {
995                        throw new XmppStringprepException(jid, e);
996                }
997
998                if (jidStringAndStringprep != null) {
999                        ENTITY_BAREJID_CACHE.put(jidStringAndStringprep, bareJid);
1000                }
1001                return bareJid;
1002        }
1003
1004        /**
1005         * Like {@link #entityBareFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1006         * {@link XmppStringprepException}.
1007         *
1008         * @param cs the character sequence which should be transformed to a {@link EntityBareJid}
1009         * @return the {@link EntityBareJid} if no exception occurs
1010         * @throws IllegalArgumentException if the given input is not a valid JID
1011         * @see #entityBareFromUnescaped(CharSequence)
1012         * @since 0.6.2
1013         */
1014        public static EntityBareJid entityBareFromUnescapedOrThrowUnchecked(CharSequence cs) {
1015                try {
1016                        return entityBareFromUnescaped(cs);
1017                } catch (XmppStringprepException e) {
1018                        throw new IllegalArgumentException(e);
1019                }
1020        }
1021
1022        /**
1023         * Get a {@link EntityBareJid} representing the given unescaped CharSequence.
1024         *
1025         * @param unescapedJid the input CharSequence.
1026         * @return a bare JID representing the given CharSequence.
1027         * @throws XmppStringprepException if an error occurs.
1028         */
1029        public static EntityBareJid entityBareFromUnescaped(CharSequence unescapedJid) throws XmppStringprepException {
1030                return entityBareFromUnescaped(unescapedJid.toString());
1031        }
1032
1033        /**
1034         * Get a {@link EntityBareJid} representing the given unescaped String.
1035         *
1036         * @param unescapedJidString the input String.
1037         * @return a bare JID representing the given String.
1038         * @throws XmppStringprepException if an error occurs.
1039         */
1040        public static EntityBareJid entityBareFromUnescaped(String unescapedJidString) throws XmppStringprepException {
1041                return entityBareFromUnescaped(unescapedJidString, JxmppContext.getDefaultContext());
1042        }
1043
1044        /**
1045         * Get a {@link EntityBareJid} representing the given unescaped String.
1046         *
1047         * @param unescapedJidString the input String.
1048         * @param context the JXMPP context.
1049         * @return a bare JID representing the given String.
1050         * @throws XmppStringprepException if an error occurs.
1051         */
1052        public static EntityBareJid entityBareFromUnescaped(String unescapedJidString, JxmppContext context) throws XmppStringprepException {
1053                JidStringAndStringprep jidStringAndStringprep = null;
1054                if (context.isCachingEnabled()) {
1055                        jidStringAndStringprep = new JidStringAndStringprep(unescapedJidString, context);
1056                }
1057
1058                EntityBareJid bareJid;
1059                if (jidStringAndStringprep != null) {
1060                        bareJid = ENTITY_BAREJID_CACHE.lookup(jidStringAndStringprep);
1061                        if (bareJid != null) {
1062                                return bareJid;
1063                        }
1064                }
1065
1066                String localpart = XmppStringUtils.parseLocalpart(unescapedJidString);
1067                // Some as from(String), but we escape the localpart
1068                localpart = XmppStringUtils.escapeLocalpart(localpart);
1069
1070                String domainpart = XmppStringUtils.parseDomain(unescapedJidString);
1071                try {
1072                        bareJid = new LocalAndDomainpartJid(localpart, domainpart, context);
1073                } catch (XmppStringprepException e) {
1074                        throw new XmppStringprepException(unescapedJidString, e);
1075                }
1076
1077                if (jidStringAndStringprep != null) {
1078                        ENTITY_BAREJID_CACHE.put(jidStringAndStringprep, bareJid);
1079                }
1080
1081                return bareJid;
1082        }
1083
1084        /**
1085         * Get a {@link EntityBareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1086         *
1087         * @param cs the input {@link CharSequence}
1088         * @return a JID or {@code null}
1089         */
1090        public static EntityBareJid entityBareFromUnescapedOrNull(CharSequence cs) {
1091                try {
1092                        return entityBareFromUnescaped(cs.toString());
1093                } catch (XmppStringprepException e) {
1094                        return null;
1095                }
1096        }
1097
1098        /**
1099         * Get a {@link EntityBareJid} constructed from the given {@link Localpart} and {link DomainBareJid}.
1100         *
1101         * @param localpart a localpart.
1102         * @param domainBareJid a domain bare JID.
1103         * @return a bare JID.
1104         */
1105        public static EntityBareJid entityBareFrom(Localpart localpart, DomainBareJid domainBareJid) {
1106                return entityBareFrom(localpart, domainBareJid.getDomain());
1107        }
1108
1109        /**
1110         * Get a {@link EntityBareJid} constructed from the given {@link Localpart} and {@link Domainpart}.
1111         *
1112         * @param localpart a localpart.
1113         * @param domain a domainpart.
1114         * @return a bare JID constructed from the given parts.
1115         */
1116        public static EntityBareJid entityBareFrom(Localpart localpart, Domainpart domain) {
1117                return new LocalAndDomainpartJid(localpart, domain);
1118        }
1119
1120        /**
1121         * Get a {@link EntityBareJid} constructed from the given {@link Localpart} and {@link Domainpart}.
1122         *
1123         * @param localpart a localpart.
1124         * @param domain a domainpart.
1125         * @return a bare JID constructed from the given parts.
1126         * @throws XmppStringprepException if an error occurs.
1127         */
1128        public static EntityBareJid entityBareFrom(CharSequence localpart, Domainpart domain) throws XmppStringprepException {
1129                return new LocalAndDomainpartJid(Localpart.fromUnescaped(localpart), domain);
1130        }
1131
1132        /**
1133         * Get a {@link EntityBareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1134         *
1135         * @param cs the input {@link CharSequence}
1136         * @return a JID or {@code null}
1137         */
1138        public static EntityBareJid entityBareFromOrNull(CharSequence cs) {
1139                try {
1140                        return entityBareFrom(cs);
1141                } catch (XmppStringprepException e) {
1142                        return null;
1143                }
1144        }
1145
1146        /**
1147         * Get a {@link EntityBareJid} from an URL encoded CharSequence.
1148         *
1149         * @param cs a CharSequence representing an URL encoded entity bare JID.
1150         * @return an entity bare JID
1151         * @throws XmppStringprepException if an error occurs.
1152         * @see URLDecoder
1153         */
1154        public static EntityBareJid entityBareFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
1155                String decoded = urlDecode(cs);
1156                return entityBareFrom(decoded);
1157        }
1158
1159        /**
1160         * Like {@link #entityFullFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1161         * {@link XmppStringprepException}.
1162         *
1163         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
1164         * @return the {@link EntityFullJid} if no exception occurs
1165         * @throws IllegalArgumentException if the given input is not a valid JID
1166         * @see #entityFullFrom(CharSequence)
1167         * @since 0.6.2
1168         */
1169        public static EntityFullJid entityFullFromOrThrowUnchecked(CharSequence cs) {
1170                try {
1171                        return entityFullFrom(cs);
1172                } catch (XmppStringprepException e) {
1173                        throw new IllegalArgumentException(e);
1174                }
1175        }
1176
1177        /**
1178         * Get a {@link EntityFullJid} representing the given CharSequence.
1179         *
1180         * @param jid a CharSequence representing a JID.
1181         * @return a full JID representing the given CharSequence.
1182         * @throws XmppStringprepException if an error occurs.
1183         */
1184        public static EntityFullJid entityFullFrom(CharSequence jid) throws XmppStringprepException {
1185                return entityFullFrom(jid.toString(), JxmppContext.getDefaultContext());
1186        }
1187
1188        /**
1189         * Get a {@link EntityFullJid} representing the given String.
1190         *
1191         * @param jid the JID's String.
1192         * @param context the JXMPP context.
1193         * @return a full JID representing the input String.
1194         * @throws XmppStringprepException if an error occurs.
1195         */
1196        public static EntityFullJid entityFullFrom(String jid, JxmppContext context) throws XmppStringprepException {
1197                JidStringAndStringprep jidStringAndStringprep = null;
1198                if (context.isCachingEnabled()) {
1199                        jidStringAndStringprep = new JidStringAndStringprep(jid, context);
1200                }
1201
1202                EntityFullJid fullJid;
1203                if (jidStringAndStringprep != null) {
1204                        fullJid = ENTITY_FULLJID_CACHE.lookup(jidStringAndStringprep);
1205                        if (fullJid != null) {
1206                                return fullJid;
1207                        }
1208                }
1209
1210                String localpart = XmppStringUtils.parseLocalpart(jid);
1211                String domainpart = XmppStringUtils.parseDomain(jid);
1212                String resource = XmppStringUtils.parseResource(jid);
1213                try {
1214                        fullJid = entityFullFrom(localpart, domainpart, resource);
1215                } catch (XmppStringprepException e) {
1216                        throw new XmppStringprepException(jid, e);
1217                }
1218
1219                if (jidStringAndStringprep != null) {
1220                        ENTITY_FULLJID_CACHE.put(jidStringAndStringprep, fullJid);
1221                }
1222
1223                return fullJid;
1224        }
1225
1226        /**
1227         * Get a {@link EntityFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1228         *
1229         * @param cs the input {@link CharSequence}
1230         * @return a JID or {@code null}
1231         */
1232        public static EntityFullJid entityFullFromOrNull(CharSequence cs) {
1233                try {
1234                        return entityFullFrom(cs);
1235                } catch (XmppStringprepException e) {
1236                        return null;
1237                }
1238        }
1239
1240        /**
1241         * Like {@link #entityFullFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1242         * {@link XmppStringprepException}.
1243         *
1244         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
1245         * @return the {@link EntityFullJid} if no exception occurs
1246         * @throws IllegalArgumentException if the given input is not a valid JID
1247         * @see #entityFullFromUnescaped(CharSequence)
1248         * @since 0.6.2
1249         */
1250        public static EntityFullJid entityFullFromUnescapedOrThrowUnchecked(CharSequence cs) {
1251                try {
1252                        return entityFullFromUnescaped(cs);
1253                } catch (XmppStringprepException e) {
1254                        throw new IllegalArgumentException(e);
1255                }
1256        }
1257
1258        /**
1259         * Get a {@link EntityFullJid} representing the given unescaped CharSequence.
1260         *
1261         * @param unescapedJid a CharSequence representing a JID.
1262         * @return a full JID representing the given CharSequence.
1263         * @throws XmppStringprepException if an error occurs.
1264         */
1265        public static EntityFullJid entityFullFromUnescaped(CharSequence unescapedJid) throws XmppStringprepException {
1266                return entityFullFromUnescaped(unescapedJid.toString());
1267        }
1268
1269        /**
1270         * Get a {@link EntityFullJid} representing the given unescaped String.
1271         *
1272         * @param unescapedJidString the JID's String.
1273         * @return a full JID representing the input String.
1274         * @throws XmppStringprepException if an error occurs.
1275         */
1276        public static EntityFullJid entityFullFromUnescaped(String unescapedJidString) throws XmppStringprepException {
1277                return entityFullFromUnescaped(unescapedJidString, JxmppContext.getDefaultContext());
1278        }
1279
1280        /**
1281         * Get a {@link EntityFullJid} representing the given unescaped String.
1282         *
1283         * @param unescapedJidString the JID's String.
1284         * @param context the JXMPP context.
1285         * @return a full JID representing the input String.
1286         * @throws XmppStringprepException if an error occurs.
1287         */
1288        public static EntityFullJid entityFullFromUnescaped(String unescapedJidString, JxmppContext context) throws XmppStringprepException {
1289                JidStringAndStringprep jidStringAndStringprep = null;
1290                if (context.isCachingEnabled()) {
1291                        jidStringAndStringprep = new JidStringAndStringprep(unescapedJidString, context);
1292                }
1293
1294                EntityFullJid fullJid;
1295                if (jidStringAndStringprep != null) {
1296                        fullJid = ENTITY_FULLJID_CACHE.lookup(jidStringAndStringprep);
1297                        if (fullJid != null) {
1298                                return fullJid;
1299                        }
1300                }
1301
1302                String localpart = XmppStringUtils.parseLocalpart(unescapedJidString);
1303                // Some as from(String), but we escape the localpart
1304                localpart = XmppStringUtils.escapeLocalpart(localpart);
1305
1306                String domainpart = XmppStringUtils.parseDomain(unescapedJidString);
1307                String resource = XmppStringUtils.parseResource(unescapedJidString);
1308                try {
1309                        fullJid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource, context);
1310                } catch (XmppStringprepException e) {
1311                        throw new XmppStringprepException(unescapedJidString, e);
1312                }
1313
1314                if (jidStringAndStringprep != null) {
1315                        ENTITY_FULLJID_CACHE.put(jidStringAndStringprep, fullJid);
1316                }
1317
1318                return fullJid;
1319        }
1320
1321        /**
1322         * Get a {@link EntityFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1323         *
1324         * @param cs the input {@link CharSequence}
1325         * @return a JID or {@code null}
1326         */
1327        public static EntityFullJid entityFullFromUnescapedOrNull(CharSequence cs) {
1328                try {
1329                        return entityFullFromUnescaped(cs.toString());
1330                } catch (XmppStringprepException e) {
1331                        return null;
1332                }
1333        }
1334
1335        /**
1336         * Get a {@link EntityFullJid} constructed from the given parts.
1337         *
1338         * @param localpart a localpart.
1339         * @param domainpart a domainpart.
1340         * @param resource a resourcepart.
1341         * @return a full JID.
1342         * @throws XmppStringprepException if an error occurs.
1343         */
1344        public static EntityFullJid entityFullFrom(String localpart, String domainpart, String resource) throws XmppStringprepException {
1345                return entityFullFrom(localpart, domainpart, resource, JxmppContext.getDefaultContext());
1346        }
1347
1348        /**
1349         * Get a {@link EntityFullJid} constructed from the given parts.
1350         *
1351         * @param localpart a localpart.
1352         * @param domainpart a domainpart.
1353         * @param resource a resourcepart.
1354         * @param context the JXMPP context.
1355         * @return a full JID.
1356         * @throws XmppStringprepException if an error occurs.
1357         */
1358        public static EntityFullJid entityFullFrom(String localpart, String domainpart, String resource, JxmppContext context) throws XmppStringprepException {
1359                EntityFullJid fullJid;
1360                try {
1361                        fullJid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource, context);
1362                } catch (XmppStringprepException e) {
1363                        throw new XmppStringprepException(localpart + '@' + domainpart + '/' + resource, e);
1364                }
1365                return fullJid;
1366        }
1367
1368        /**
1369         * Get a {@link EntityFullJid} constructed from the given parts.
1370         *
1371         * @param localpart a localpart.
1372         * @param domainBareJid a domain bare JID..
1373         * @param resource a resourcepart
1374         * @return a full JID.
1375         */
1376        public static EntityFullJid entityFullFrom(Localpart localpart, DomainBareJid domainBareJid, Resourcepart resource) {
1377                return entityFullFrom(localpart, domainBareJid.getDomain(), resource);
1378        }
1379
1380        /**
1381         * Get a {@link EntityFullJid} constructed from the given parts.
1382         *
1383         * @param localpart the localpart.
1384         * @param domainpart the domainpart.
1385         * @param resource the resourcepart.
1386         * @return a full JID.
1387         */
1388        public static EntityFullJid entityFullFrom(Localpart localpart, Domainpart domainpart, Resourcepart resource) {
1389                return entityFullFrom(entityBareFrom(localpart, domainpart), resource);
1390        }
1391
1392        /**
1393         * Get a {@link EntityFullJid} constructed from the given parts.
1394         *
1395         * @param localpart the localpart.
1396         * @param domainpart the domainpart.
1397         * @param resource the resourcepart.
1398         * @return a full JID.
1399         * @throws XmppStringprepException if an error occurs.
1400         */
1401        public static EntityFullJid entityFullFrom(CharSequence localpart, Domainpart domainpart, CharSequence resource) throws XmppStringprepException {
1402                return entityFullFrom(entityBareFrom(Localpart.fromUnescaped(localpart), domainpart), Resourcepart.from(resource));
1403        }
1404
1405        /**
1406         * Get a {@link EntityFullJid} constructed from a {@link EntityBareJid} and a {@link Resourcepart}.
1407         *
1408         * @param bareJid a bare JID.
1409         * @param resource a resourcepart.
1410         * @return a full JID.
1411         */
1412        public static EntityFullJid entityFullFrom(EntityBareJid bareJid, Resourcepart resource) {
1413                return new LocalDomainAndResourcepartJid(bareJid, resource);
1414        }
1415
1416        /**
1417         * Get a {@link EntityFullJid} from an URL encoded CharSequence.
1418         *
1419         * @param cs a CharSequence representing an URL encoded entity full JID.
1420         * @return an entity full JID
1421         * @throws XmppStringprepException if an error occurs.
1422         * @see URLDecoder
1423         */
1424        public static EntityFullJid entityFullFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
1425                String decoded = urlDecode(cs);
1426                return entityFullFrom(decoded);
1427        }
1428
1429        /**
1430         * Like {@link #domainBareFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1431         * {@link XmppStringprepException}.
1432         *
1433         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
1434         * @return the {@link EntityFullJid} if no exception occurs
1435         * @see #from(String)
1436         * @since 0.6.2
1437         */
1438        public static DomainBareJid domainBareFromOrThrowUnchecked(CharSequence cs) {
1439                try {
1440                        return domainBareFrom(cs);
1441                } catch (XmppStringprepException e) {
1442                        throw new IllegalArgumentException(e);
1443                }
1444        }
1445
1446        /**
1447         * Get a domain bare JID.
1448         *
1449         * @param jid the JID CharSequence.
1450         * @return a domain bare JID.
1451         * @throws XmppStringprepException if an error occurs.
1452         */
1453        public static DomainBareJid domainBareFrom(CharSequence jid) throws XmppStringprepException {
1454                return domainBareFrom(jid.toString());
1455        }
1456
1457        /**
1458         * Get a domain bare JID.
1459         *
1460         * @param jid the JID String.
1461         * @return a domain bare JID.
1462         * @throws XmppStringprepException if an error occurs.
1463         */
1464        public static DomainBareJid domainBareFrom(String jid) throws XmppStringprepException {
1465                return domainBareFrom(jid, JxmppContext.getDefaultContext());
1466        }
1467
1468        /**
1469         * Get a domain bare JID.
1470         *
1471         * @param jid the JID String.
1472         * @param context the JXMPP context.
1473         * @return a domain bare JID.
1474         * @throws XmppStringprepException if an error occurs.
1475         */
1476        public static DomainBareJid domainBareFrom(String jid, JxmppContext context) throws XmppStringprepException {
1477                JidStringAndStringprep jidStringAndStringprep = null;
1478                if (context.isCachingEnabled()) {
1479                        jidStringAndStringprep = new JidStringAndStringprep(jid, context);
1480                }
1481
1482                DomainBareJid domainJid;
1483                if (jidStringAndStringprep != null) {
1484                        domainJid = DOMAINJID_CACHE.lookup(jidStringAndStringprep);
1485                        if (domainJid != null) {
1486                                return domainJid;
1487                        }
1488                }
1489
1490                String domain = XmppStringUtils.parseDomain(jid);
1491                try {
1492                        domainJid = new DomainpartJid(domain, context);
1493                } catch (XmppStringprepException e) {
1494                        throw new XmppStringprepException(jid, e);
1495                }
1496
1497                if (context.isCachingEnabled()) {
1498                        DOMAINJID_CACHE.put(jidStringAndStringprep, domainJid);
1499                }
1500                return domainJid;
1501        }
1502
1503        /**
1504         * Get a {@link DomainBareJid} consisting of the given {@link Domainpart}.
1505         *
1506         * @param domainpart the domainpart.
1507         * @return a domain bare JID.
1508         */
1509        public static DomainBareJid domainBareFrom(Domainpart domainpart) {
1510                return new DomainpartJid(domainpart);
1511        }
1512
1513        /**
1514         * Get a {@link DomainBareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1515         *
1516         * @param cs the input {@link CharSequence}
1517         * @return a JID or {@code null}
1518         */
1519        public static DomainBareJid domainBareFromOrNull(CharSequence cs) {
1520                try {
1521                        return domainBareFrom(cs);
1522                } catch (XmppStringprepException e) {
1523                        return null;
1524                }
1525        }
1526
1527        /**
1528         * Get a {@link DomainBareJid} from an URL encoded CharSequence.
1529         *
1530         * @param cs a CharSequence representing an URL encoded domain bare JID.
1531         * @return a domain bare JID
1532         * @throws XmppStringprepException if an error occurs.
1533         * @see URLDecoder
1534         */
1535        public static DomainBareJid domainBareFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
1536                String decode = urlDecode(cs);
1537                return domainBareFrom(decode);
1538        }
1539
1540        /**
1541         * Like {@link #domainFullFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1542         * {@link XmppStringprepException}.
1543         *
1544         * @param cs the character sequence which should be transformed to a {@link DomainFullJid}
1545         * @return the {@link DomainFullJid} if no exception occurs
1546         * @throws IllegalArgumentException if the given input is not a valid JID
1547         * @see #domainFullFrom(CharSequence)
1548         * @since 0.6.2
1549         */
1550        public static DomainFullJid domainFullFromOrThrowUnchecked(CharSequence cs) {
1551                try {
1552                        return domainFullFrom(cs);
1553                } catch (XmppStringprepException e) {
1554                        throw new IllegalArgumentException(e);
1555                }
1556        }
1557
1558        /**
1559         * Get a domain full JID from the given CharSequence.
1560         *
1561         * @param jid the JID.
1562         * @return a domain full JID.
1563         * @throws XmppStringprepException if an error happens.
1564         */
1565        public static DomainFullJid domainFullFrom(CharSequence jid) throws XmppStringprepException {
1566                return domainFullFrom(jid.toString());
1567        }
1568
1569        /**
1570         * Get a domain full JID from the given String.
1571         *
1572         * @param jid the JID.
1573         * @return a DomainFullJid.
1574         * @throws XmppStringprepException if an error happens.
1575         */
1576        public static DomainFullJid domainFullFrom(String jid) throws XmppStringprepException {
1577                return domainFullFrom(jid, JxmppContext.getDefaultContext());
1578        }
1579
1580        /**
1581         * Get a domain full JID from the given String.
1582         *
1583         * @param jid the JID.
1584         * @param context the JXMPP context.
1585         * @return a DomainFullJid.
1586         * @throws XmppStringprepException if an error happens.
1587         */
1588        public static DomainFullJid domainFullFrom(String jid, JxmppContext context) throws XmppStringprepException {
1589                JidStringAndStringprep jidStringAndStringprep = null;
1590                if (context.isCachingEnabled()) {
1591                        jidStringAndStringprep = new JidStringAndStringprep(jid, context);
1592                }
1593
1594                DomainFullJid domainResourceJid;
1595                if (jidStringAndStringprep != null) {
1596                        domainResourceJid = DOMAINRESOURCEJID_CACHE.lookup(jidStringAndStringprep);
1597                        if (domainResourceJid != null) {
1598                                return domainResourceJid;
1599                        }
1600                }
1601
1602                String domain = XmppStringUtils.parseDomain(jid);
1603                String resource = XmppStringUtils.parseResource(jid);
1604                try {
1605                        domainResourceJid = new DomainAndResourcepartJid(domain, resource, context);
1606                } catch (XmppStringprepException e) {
1607                        throw new XmppStringprepException(jid, e);
1608                }
1609
1610                if (jidStringAndStringprep != null) {
1611                        DOMAINRESOURCEJID_CACHE.put(jidStringAndStringprep, domainResourceJid);
1612                }
1613
1614                return domainResourceJid;
1615        }
1616
1617        /**
1618         * Get a domain full JID.
1619         *
1620         * @param domainpart the domainpart.
1621         * @param resource the resourcepart.
1622         * @return a domain full JID.
1623         */
1624        public static DomainFullJid domainFullFrom(Domainpart domainpart, Resourcepart resource) {
1625                return domainFullFrom(domainBareFrom(domainpart), resource);
1626        }
1627
1628        /**
1629         * Get a domain full JID.
1630         *
1631         * @param domainBareJid a domain bare JID.
1632         * @param resource a resourcepart.
1633         * @return a domain full JID.
1634         */
1635        public static DomainFullJid domainFullFrom(DomainBareJid domainBareJid, Resourcepart resource) {
1636                return new DomainAndResourcepartJid(domainBareJid, resource);
1637        }
1638
1639        /**
1640         * Get a {@link DomainFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1641         *
1642         * @param cs the input {@link CharSequence}
1643         * @return a JID or {@code null}
1644         */
1645        public static DomainFullJid domainFullFromOrNull(CharSequence cs) {
1646                try {
1647                        return domainFullFrom(cs);
1648                } catch (XmppStringprepException e) {
1649                        return null;
1650                }
1651        }
1652
1653        /**
1654         * Get a {@link DomainFullJid} from an URL encoded CharSequence.
1655         *
1656         * @param cs a CharSequence representing an URL encoded domain full JID.
1657         * @return a domain full JID
1658         * @throws XmppStringprepException if an error occurs.
1659         * @see URLDecoder
1660         */
1661        public static DomainFullJid domainFullFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
1662                String decoded = urlDecode(cs);
1663                return domainFullFrom(decoded);
1664        }
1665
1666        private static String urlDecode(CharSequence cs) {
1667                try {
1668                        return URLDecoder.decode(cs.toString(), "UTF-8");
1669                } catch (UnsupportedEncodingException e) {
1670                        throw new AssertionError(e);
1671                }
1672        }
1673}