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