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 == null || localpart.length() == 0) {
364                                bareJid = new DomainpartJid(domainpart, context);
365                        } else {
366                                bareJid = new LocalAndDomainpartJid(localpart, 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         * @deprecated use {@link #entityFromUnescapedOrNull(CharSequence)} instead.
676         */
677        // TODO: remove in jxmpp 1.1
678        @Deprecated
679        public static EntityJid entityFromUnesacpedOrNull(CharSequence cs) {
680                return entityFromUnescapedOrNull(cs);
681        }
682
683        /**
684         * Get a {@link EntityJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
685         *
686         * @param cs the input {@link CharSequence}
687         * @return a JID or {@code null}
688         */
689        public static EntityJid entityFromUnescapedOrNull(CharSequence cs) {
690                try {
691                        return entityFromUnescaped(cs.toString());
692                } catch (XmppStringprepException e) {
693                        return null;
694                }
695        }
696
697        /**
698         * Get a {@link EntityJid} representing the given String.
699         *
700         * @param jidString the JID's string.
701         * @param unescaped if the JID string is unescaped.
702         * @return an entity JID representing the given String.
703         * @throws XmppStringprepException if an error occurs.
704         */
705        private static EntityJid entityFrom(String jidString, boolean unescaped) throws XmppStringprepException {
706                EntityJid entityJid = ENTITYJID_CACHE.lookup(jidString);
707                if (entityJid != null) {
708                        return entityJid;
709                }
710                String localpartString = XmppStringUtils.parseLocalpart(jidString);
711                if (localpartString == null) {
712                        throw new XmppStringprepException("Does not contain a localpart", jidString);
713                }
714                Localpart localpart;
715                try {
716                        if (unescaped) {
717                                localpart = Localpart.fromUnescaped(localpartString);
718                        } else {
719                                localpart = Localpart.from(localpartString);
720                        }
721                } catch (XmppStringprepException e) {
722                        throw new XmppStringprepException(jidString, e);
723                }
724
725                String domainpartString = XmppStringUtils.parseDomain(jidString);
726                Domainpart domainpart;
727                try {
728                        domainpart = Domainpart.from(domainpartString);
729                } catch (XmppStringprepException e) {
730                        throw new XmppStringprepException(jidString, e);
731                }
732
733                String resourceString = XmppStringUtils.parseResource(jidString);
734                if (resourceString != null) {
735                        Resourcepart resourcepart;
736                        try {
737                                resourcepart = Resourcepart.from(resourceString);
738                        } catch (XmppStringprepException e) {
739                                throw new XmppStringprepException(jidString, e);
740                        }
741                        entityJid = entityFullFrom(localpart, domainpart, resourcepart);
742                } else {
743                        entityJid = entityBareFrom(localpart, domainpart);
744                }
745
746                ENTITYJID_CACHE.put(jidString, entityJid);
747                return entityJid;
748        }
749
750        /**
751         * Get a {@link EntityJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
752         *
753         * @param cs the input {@link CharSequence}
754         * @return a JID or {@code null}
755         */
756        public static EntityJid entityFromOrNull(CharSequence cs) {
757                try {
758                        return entityFrom(cs);
759                } catch (XmppStringprepException e) {
760                        return null;
761                }
762        }
763
764        /**
765         * Get a {@link EntityJid} from an URL encoded CharSequence.
766         *
767         * @param cs a CharSequence representing an URL encoded entity JID.
768         * @return an entity JID
769         * @throws XmppStringprepException if an error occurs.
770         * @see URLDecoder
771         */
772        public static EntityJid entityFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
773                String decoded = urlDecode(cs);
774                return entityFrom(decoded);
775        }
776
777        /**
778         * Like {@link #entityBareFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
779         * {@link XmppStringprepException}.
780         *
781         * @param cs the character sequence which should be transformed to a {@link EntityBareJid}
782         * @return the {@link EntityBareJid} if no exception occurs
783         * @throws IllegalArgumentException if the given input is not a valid JID
784         * @see #entityBareFrom(CharSequence)
785         * @since 0.6.2
786         */
787        public static EntityBareJid entityBareFromOrThrowUnchecked(CharSequence cs) {
788                try {
789                        return entityBareFrom(cs);
790                } catch (XmppStringprepException e) {
791                        throw new IllegalArgumentException(e);
792                }
793        }
794
795        /**
796         * Get a {@link EntityBareJid} representing the given CharSequence.
797         *
798         * @param jid the input CharSequence.
799         * @return a bare JID representing the given CharSequence.
800         * @throws XmppStringprepException if an error occurs.
801         */
802        public static EntityBareJid entityBareFrom(CharSequence jid) throws XmppStringprepException {
803                return entityBareFrom(jid.toString());
804        }
805
806        /**
807         * Get a {@link EntityBareJid} representing the given String.
808         *
809         * @param jid the input String.
810         * @return a bare JID representing the given String.
811         * @throws XmppStringprepException if an error occurs.
812         */
813        public static EntityBareJid entityBareFrom(String jid) throws XmppStringprepException {
814                return entityBareFrom(jid, JxmppContext.getDefaultContext());
815        }
816
817        /**
818         * Get a {@link EntityBareJid} representing the given String.
819         *
820         * @param jid the input String.
821         * @param context the JXMPP context.
822         * @return a bare JID representing the given String.
823         * @throws XmppStringprepException if an error occurs.
824         */
825        public static EntityBareJid entityBareFrom(String jid, JxmppContext context) throws XmppStringprepException {
826                EntityBareJid bareJid;
827                if (context.isCachingEnabled()) {
828                        bareJid = ENTITY_BAREJID_CACHE.lookup(jid);
829                        if (bareJid != null) {
830                                return bareJid;
831                        }
832                }
833
834                String localpart = XmppStringUtils.parseLocalpart(jid);
835                String domainpart = XmppStringUtils.parseDomain(jid);
836                try {
837                        bareJid = new LocalAndDomainpartJid(localpart, domainpart, context);
838                } catch (XmppStringprepException e) {
839                        throw new XmppStringprepException(jid, e);
840                }
841
842                if (context.isCachingEnabled()) {
843                        ENTITY_BAREJID_CACHE.put(jid, bareJid);
844                }
845                return bareJid;
846        }
847
848        /**
849         * Like {@link #entityBareFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
850         * {@link XmppStringprepException}.
851         *
852         * @param cs the character sequence which should be transformed to a {@link EntityBareJid}
853         * @return the {@link EntityBareJid} if no exception occurs
854         * @throws IllegalArgumentException if the given input is not a valid JID
855         * @see #entityBareFromUnescaped(CharSequence)
856         * @since 0.6.2
857         */
858        public static EntityBareJid entityBareFromUnescapedOrThrowUnchecked(CharSequence cs) {
859                try {
860                        return entityBareFromUnescaped(cs);
861                } catch (XmppStringprepException e) {
862                        throw new IllegalArgumentException(e);
863                }
864        }
865
866        /**
867         * Get a {@link EntityBareJid} representing the given unescaped CharSequence.
868         *
869         * @param unescapedJid the input CharSequence.
870         * @return a bare JID representing the given CharSequence.
871         * @throws XmppStringprepException if an error occurs.
872         */
873        public static EntityBareJid entityBareFromUnescaped(CharSequence unescapedJid) throws XmppStringprepException {
874                return entityBareFromUnescaped(unescapedJid.toString());
875        }
876
877        /**
878         * Get a {@link EntityBareJid} representing the given unescaped String.
879         *
880         * @param unescapedJidString the input String.
881         * @return a bare JID representing the given String.
882         * @throws XmppStringprepException if an error occurs.
883         */
884        public static EntityBareJid entityBareFromUnescaped(String unescapedJidString) throws XmppStringprepException {
885                return entityBareFromUnescaped(unescapedJidString, JxmppContext.getDefaultContext());
886        }
887
888        /**
889         * Get a {@link EntityBareJid} representing the given unescaped String.
890         *
891         * @param unescapedJidString the input String.
892         * @param context the JXMPP context.
893         * @return a bare JID representing the given String.
894         * @throws XmppStringprepException if an error occurs.
895         */
896        public static EntityBareJid entityBareFromUnescaped(String unescapedJidString, JxmppContext context) throws XmppStringprepException {
897                EntityBareJid bareJid;
898                if (context.isCachingEnabled()) {
899                        bareJid = ENTITY_BAREJID_CACHE.lookup(unescapedJidString);
900                        if (bareJid != null) {
901                                return bareJid;
902                        }
903                }
904
905                String localpart = XmppStringUtils.parseLocalpart(unescapedJidString);
906                // Some as from(String), but we escape the localpart
907                localpart = XmppStringUtils.escapeLocalpart(localpart);
908
909                String domainpart = XmppStringUtils.parseDomain(unescapedJidString);
910                try {
911                        bareJid = new LocalAndDomainpartJid(localpart, domainpart, context);
912                } catch (XmppStringprepException e) {
913                        throw new XmppStringprepException(unescapedJidString, e);
914                }
915
916                if (context.isCachingEnabled()) {
917                        ENTITY_BAREJID_CACHE.put(unescapedJidString, bareJid);
918                }
919                return bareJid;
920        }
921
922        /**
923         * Get a {@link EntityBareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
924         *
925         * @param cs the input {@link CharSequence}
926         * @return a JID or {@code null}
927         */
928        public static EntityBareJid entityBareFromUnescapedOrNull(CharSequence cs) {
929                try {
930                        return entityBareFromUnescaped(cs.toString());
931                } catch (XmppStringprepException e) {
932                        return null;
933                }
934        }
935
936        /**
937         * Get a {@link EntityBareJid} constructed from the given {@link Localpart} and {link DomainBareJid}.
938         *
939         * @param localpart a localpart.
940         * @param domainBareJid a domain bare JID.
941         * @return a bare JID.
942         */
943        public static EntityBareJid entityBareFrom(Localpart localpart, DomainBareJid domainBareJid) {
944                return entityBareFrom(localpart, domainBareJid.getDomain());
945        }
946
947        /**
948         * Get a {@link EntityBareJid} constructed from the given {@link Localpart} and {@link Domainpart}.
949         *
950         * @param localpart a localpart.
951         * @param domain a domainpart.
952         * @return a bare JID constructed from the given parts.
953         */
954        public static EntityBareJid entityBareFrom(Localpart localpart, Domainpart domain) {
955                return new LocalAndDomainpartJid(localpart, domain);
956        }
957
958        /**
959         * Get a {@link EntityBareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
960         *
961         * @param cs the input {@link CharSequence}
962         * @return a JID or {@code null}
963         */
964        public static EntityBareJid entityBareFromOrNull(CharSequence cs) {
965                try {
966                        return entityBareFrom(cs);
967                } catch (XmppStringprepException e) {
968                        return null;
969                }
970        }
971
972        /**
973         * Get a {@link EntityBareJid} from an URL encoded CharSequence.
974         *
975         * @param cs a CharSequence representing an URL encoded entity bare JID.
976         * @return an entity bare JID
977         * @throws XmppStringprepException if an error occurs.
978         * @see URLDecoder
979         */
980        public static EntityBareJid entityBareFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
981                String decoded = urlDecode(cs);
982                return entityBareFrom(decoded);
983        }
984
985        /**
986         * Like {@link #entityFullFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
987         * {@link XmppStringprepException}.
988         *
989         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
990         * @return the {@link EntityFullJid} if no exception occurs
991         * @throws IllegalArgumentException if the given input is not a valid JID
992         * @see #entityFullFrom(CharSequence)
993         * @since 0.6.2
994         */
995        public static EntityFullJid entityFullFromOrThrowUnchecked(CharSequence cs) {
996                try {
997                        return entityFullFrom(cs);
998                } catch (XmppStringprepException e) {
999                        throw new IllegalArgumentException(e);
1000                }
1001        }
1002
1003        /**
1004         * Get a {@link EntityFullJid} representing the given CharSequence.
1005         *
1006         * @param jid a CharSequence representing a JID.
1007         * @return a full JID representing the given CharSequence.
1008         * @throws XmppStringprepException if an error occurs.
1009         */
1010        public static EntityFullJid entityFullFrom(CharSequence jid) throws XmppStringprepException {
1011                return entityFullFrom(jid.toString());
1012        }
1013
1014        /**
1015         * Get a {@link EntityFullJid} representing the given String.
1016         *
1017         * @param jid the JID's String.
1018         * @return a full JID representing the input String.
1019         * @throws XmppStringprepException if an error occurs.
1020         */
1021        public static EntityFullJid entityFullFrom(String jid) throws XmppStringprepException {
1022                EntityFullJid fullJid = ENTITY_FULLJID_CACHE.lookup(jid);
1023                if (fullJid != null) {
1024                        return fullJid;
1025                }
1026
1027                String localpart = XmppStringUtils.parseLocalpart(jid);
1028                String domainpart = XmppStringUtils.parseDomain(jid);
1029                String resource = XmppStringUtils.parseResource(jid);
1030                try {
1031                        fullJid = entityFullFrom(localpart, domainpart, resource);
1032                } catch (XmppStringprepException e) {
1033                        throw new XmppStringprepException(jid, e);
1034                }
1035                ENTITY_FULLJID_CACHE.put(jid, fullJid);
1036                return fullJid;
1037        }
1038
1039        /**
1040         * Get a {@link EntityFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1041         *
1042         * @param cs the input {@link CharSequence}
1043         * @return a JID or {@code null}
1044         */
1045        public static EntityFullJid entityFullFromOrNull(CharSequence cs) {
1046                try {
1047                        return entityFullFrom(cs);
1048                } catch (XmppStringprepException e) {
1049                        return null;
1050                }
1051        }
1052
1053        /**
1054         * Like {@link #entityFullFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1055         * {@link XmppStringprepException}.
1056         *
1057         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
1058         * @return the {@link EntityFullJid} if no exception occurs
1059         * @throws IllegalArgumentException if the given input is not a valid JID
1060         * @see #entityFullFromUnescaped(CharSequence)
1061         * @since 0.6.2
1062         */
1063        public static EntityFullJid entityFullFromUnescapedOrThrowUnchecked(CharSequence cs) {
1064                try {
1065                        return entityFullFromUnescaped(cs);
1066                } catch (XmppStringprepException e) {
1067                        throw new IllegalArgumentException(e);
1068                }
1069        }
1070
1071        /**
1072         * Get a {@link EntityFullJid} representing the given unescaped CharSequence.
1073         *
1074         * @param unescapedJid a CharSequence representing a JID.
1075         * @return a full JID representing the given CharSequence.
1076         * @throws XmppStringprepException if an error occurs.
1077         */
1078        public static EntityFullJid entityFullFromUnescaped(CharSequence unescapedJid) throws XmppStringprepException {
1079                return entityFullFromUnescaped(unescapedJid.toString());
1080        }
1081
1082        /**
1083         * Get a {@link EntityFullJid} representing the given unescaped String.
1084         *
1085         * @param unescapedJidString the JID's String.
1086         * @return a full JID representing the input String.
1087         * @throws XmppStringprepException if an error occurs.
1088         */
1089        public static EntityFullJid entityFullFromUnescaped(String unescapedJidString) throws XmppStringprepException {
1090                return entityFullFromUnescaped(unescapedJidString, JxmppContext.getDefaultContext());
1091        }
1092
1093        /**
1094         * Get a {@link EntityFullJid} representing the given unescaped String.
1095         *
1096         * @param unescapedJidString the JID's String.
1097         * @param context the JXMPP context.
1098         * @return a full JID representing the input String.
1099         * @throws XmppStringprepException if an error occurs.
1100         */
1101        public static EntityFullJid entityFullFromUnescaped(String unescapedJidString, JxmppContext context) throws XmppStringprepException {
1102                EntityFullJid fullJid;
1103                if (context.isCachingEnabled()) {
1104                        fullJid = ENTITY_FULLJID_CACHE.lookup(unescapedJidString);
1105                        if (fullJid != null) {
1106                                return fullJid;
1107                        }
1108                }
1109
1110                String localpart = XmppStringUtils.parseLocalpart(unescapedJidString);
1111                // Some as from(String), but we escape the localpart
1112                localpart = XmppStringUtils.escapeLocalpart(localpart);
1113
1114                String domainpart = XmppStringUtils.parseDomain(unescapedJidString);
1115                String resource = XmppStringUtils.parseResource(unescapedJidString);
1116                try {
1117                        fullJid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource, context);
1118                } catch (XmppStringprepException e) {
1119                        throw new XmppStringprepException(unescapedJidString, e);
1120                }
1121
1122                if (context.isCachingEnabled()) {
1123                        ENTITY_FULLJID_CACHE.put(unescapedJidString, fullJid);
1124                }
1125                return fullJid;
1126        }
1127
1128        /**
1129         * Get a {@link EntityFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1130         *
1131         * @param cs the input {@link CharSequence}
1132         * @return a JID or {@code null}
1133         */
1134        public static EntityFullJid entityFullFromUnescapedOrNull(CharSequence cs) {
1135                try {
1136                        return entityFullFromUnescaped(cs.toString());
1137                } catch (XmppStringprepException e) {
1138                        return null;
1139                }
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         * @return a full JID.
1149         * @throws XmppStringprepException if an error occurs.
1150         */
1151        public static EntityFullJid entityFullFrom(String localpart, String domainpart, String resource) throws XmppStringprepException {
1152                return entityFullFrom(localpart, domainpart, resource, JxmppContext.getDefaultContext());
1153        }
1154
1155        /**
1156         * Get a {@link EntityFullJid} constructed from the given parts.
1157         *
1158         * @param localpart a localpart.
1159         * @param domainpart a domainpart.
1160         * @param resource a resourcepart.
1161         * @param context the JXMPP context.
1162         * @return a full JID.
1163         * @throws XmppStringprepException if an error occurs.
1164         */
1165        public static EntityFullJid entityFullFrom(String localpart, String domainpart, String resource, JxmppContext context) throws XmppStringprepException {
1166                EntityFullJid fullJid;
1167                try {
1168                        fullJid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource, context);
1169                } catch (XmppStringprepException e) {
1170                        throw new XmppStringprepException(localpart + '@' + domainpart + '/' + resource, e);
1171                }
1172                return fullJid;
1173        }
1174
1175        /**
1176         * Get a {@link EntityFullJid} constructed from the given parts.
1177         *
1178         * @param localpart a localpart.
1179         * @param domainBareJid a domain bare JID.. 
1180         * @param resource a resourcepart
1181         * @return a full JID.
1182         */
1183        public static EntityFullJid entityFullFrom(Localpart localpart, DomainBareJid domainBareJid, Resourcepart resource) {
1184                return entityFullFrom(localpart, domainBareJid.getDomain(), resource);
1185        }
1186
1187        /**
1188         * Get a {@link EntityFullJid} constructed from the given parts.
1189         * 
1190         * @param localpart the localpart.
1191         * @param domainpart the domainpart.
1192         * @param resource the resourcepart.
1193         * @return a full JID.
1194         */
1195        public static EntityFullJid entityFullFrom(Localpart localpart, Domainpart domainpart, Resourcepart resource) {
1196                return entityFullFrom(entityBareFrom(localpart, domainpart), resource);
1197        }
1198
1199        /**
1200         * Get a {@link EntityFullJid} constructed from a {@link EntityBareJid} and a {@link Resourcepart}.
1201         *
1202         * @param bareJid a bare JID.
1203         * @param resource a resourcepart.
1204         * @return a full JID.
1205         */
1206        public static EntityFullJid entityFullFrom(EntityBareJid bareJid, Resourcepart resource) {
1207                return new LocalDomainAndResourcepartJid(bareJid, resource);
1208        }
1209
1210        /**
1211         * Get a {@link EntityFullJid} from an URL encoded CharSequence.
1212         *
1213         * @param cs a CharSequence representing an URL encoded entity full JID.
1214         * @return an entity full JID
1215         * @throws XmppStringprepException if an error occurs.
1216         * @see URLDecoder
1217         */
1218        public static EntityFullJid entityFullFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
1219                String decoded = urlDecode(cs);
1220                return entityFullFrom(decoded);
1221        }
1222
1223        /**
1224         * Like {@link #domainBareFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1225         * {@link XmppStringprepException}.
1226         *
1227         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
1228         * @return the {@link EntityFullJid} if no exception occurs
1229         * @see #from(String)
1230         * @since 0.6.2
1231         */
1232        public static DomainBareJid domainBareFromOrThrowUnchecked(CharSequence cs) {
1233                try {
1234                        return domainBareFrom(cs);
1235                } catch (XmppStringprepException e) {
1236                        throw new IllegalArgumentException(e);
1237                }
1238        }
1239
1240        /**
1241         * Get a domain bare JID.
1242         *
1243         * @param jid the JID CharSequence.
1244         * @return a domain bare JID.
1245         * @throws XmppStringprepException if an error occurs.
1246         */
1247        public static DomainBareJid domainBareFrom(CharSequence jid) throws XmppStringprepException {
1248                return domainBareFrom(jid.toString());
1249        }
1250
1251        /**
1252         * Get a domain bare JID.
1253         *
1254         * @param jid the JID String.
1255         * @return a domain bare JID.
1256         * @throws XmppStringprepException if an error occurs.
1257         */
1258        public static DomainBareJid domainBareFrom(String jid) throws XmppStringprepException {
1259                return domainBareFrom(jid, JxmppContext.getDefaultContext());
1260        }
1261
1262        /**
1263         * Get a domain bare JID.
1264         *
1265         * @param jid the JID String.
1266         * @param context the JXMPP context.
1267         * @return a domain bare JID.
1268         * @throws XmppStringprepException if an error occurs.
1269         */
1270        public static DomainBareJid domainBareFrom(String jid, JxmppContext context) throws XmppStringprepException {
1271                DomainBareJid domainJid;
1272                if (context.isCachingEnabled()) {
1273                        domainJid = DOMAINJID_CACHE.lookup(jid);
1274                        if (domainJid != null) {
1275                                return domainJid;
1276                        }
1277                }
1278
1279                String domain = XmppStringUtils.parseDomain(jid);
1280                try {
1281                        domainJid = new DomainpartJid(domain, context);
1282                } catch (XmppStringprepException e) {
1283                        throw new XmppStringprepException(jid, e);
1284                }
1285
1286                if (context.isCachingEnabled()) {
1287                        DOMAINJID_CACHE.put(jid, domainJid);
1288                }
1289                return domainJid;
1290        }
1291
1292        /**
1293         * Get a {@link DomainBareJid} consisting of the given {@link Domainpart}.
1294         *
1295         * @param domainpart the domainpart.
1296         * @return a domain bare JID.
1297         */
1298        public static DomainBareJid domainBareFrom(Domainpart domainpart) {
1299                return new DomainpartJid(domainpart);
1300        }
1301
1302        /**
1303         * Get a {@link DomainBareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1304         *
1305         * @param cs the input {@link CharSequence}
1306         * @return a JID or {@code null}
1307         */
1308        public static DomainBareJid domainBareFromOrNull(CharSequence cs) {
1309                try {
1310                        return domainBareFrom(cs);
1311                } catch (XmppStringprepException e) {
1312                        return null;
1313                }
1314        }
1315
1316        /**
1317         * Get a {@link DomainBareJid} from an URL encoded CharSequence.
1318         *
1319         * @param cs a CharSequence representing an URL encoded domain bare JID.
1320         * @return a domain bare JID
1321         * @throws XmppStringprepException if an error occurs.
1322         * @see URLDecoder
1323         */
1324        public static DomainBareJid domainBareFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
1325                String decode = urlDecode(cs);
1326                return domainBareFrom(decode);
1327        }
1328
1329        /**
1330         * Like {@link #domainFullFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1331         * {@link XmppStringprepException}.
1332         *
1333         * @param cs the character sequence which should be transformed to a {@link DomainFullJid}
1334         * @return the {@link DomainFullJid} if no exception occurs
1335         * @throws IllegalArgumentException if the given input is not a valid JID
1336         * @see #domainFullFrom(CharSequence)
1337         * @since 0.6.2
1338         */
1339        public static DomainFullJid domainFullFromOrThrowUnchecked(CharSequence cs) {
1340                try {
1341                        return domainFullFrom(cs);
1342                } catch (XmppStringprepException e) {
1343                        throw new IllegalArgumentException(e);
1344                }
1345        }
1346
1347        /**
1348         * Get a domain full JID from the given CharSequence.
1349         *
1350         * @param jid the JID.
1351         * @return a domain full JID.
1352         * @throws XmppStringprepException if an error happens.
1353         */
1354        public static DomainFullJid domainFullFrom(CharSequence jid) throws XmppStringprepException {
1355                return domainFullFrom(jid.toString());
1356        }
1357
1358        /**
1359         * Get a domain full JID from the given String.
1360         *
1361         * @param jid the JID.
1362         * @return a DomainFullJid.
1363         * @throws XmppStringprepException if an error happens.
1364         */
1365        public static DomainFullJid domainFullFrom(String jid) throws XmppStringprepException {
1366                return domainFullFrom(jid, JxmppContext.getDefaultContext());
1367        }
1368
1369        /**
1370         * Get a domain full JID from the given String.
1371         *
1372         * @param jid the JID.
1373         * @param context the JXMPP context.
1374         * @return a DomainFullJid.
1375         * @throws XmppStringprepException if an error happens.
1376         */
1377        public static DomainFullJid domainFullFrom(String jid, JxmppContext context) throws XmppStringprepException {
1378                DomainFullJid domainResourceJid;
1379                if (context.isCachingEnabled()) {
1380                        domainResourceJid = DOMAINRESOURCEJID_CACHE.lookup(jid);
1381                        if (domainResourceJid != null) {
1382                                return domainResourceJid;
1383                        }
1384                }
1385
1386                String domain = XmppStringUtils.parseDomain(jid);
1387                String resource = XmppStringUtils.parseResource(jid);
1388                try {
1389                        domainResourceJid = new DomainAndResourcepartJid(domain, resource, context);
1390                } catch (XmppStringprepException e) {
1391                        throw new XmppStringprepException(jid, e);
1392                }
1393
1394                if (context.isCachingEnabled()) {
1395                        DOMAINRESOURCEJID_CACHE.put(jid, domainResourceJid);
1396                }
1397                return domainResourceJid;
1398        }
1399
1400        /**
1401         * Get a domain full JID.
1402         *
1403         * @param domainpart the domainpart.
1404         * @param resource the resourcepart.
1405         * @return a domain full JID.
1406         */
1407        public static DomainFullJid domainFullFrom(Domainpart domainpart, Resourcepart resource) {
1408                return domainFullFrom(domainBareFrom(domainpart), resource);
1409        }
1410
1411        /**
1412         * Get a domain full JID.
1413         *
1414         * @param domainBareJid a domain bare JID.
1415         * @param resource a resourcepart.
1416         * @return a domain full JID.
1417         */
1418        public static DomainFullJid domainFullFrom(DomainBareJid domainBareJid, Resourcepart resource) {
1419                return new DomainAndResourcepartJid(domainBareJid, resource);
1420        }
1421
1422        /**
1423         * Get a {@link DomainFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1424         *
1425         * @param cs the input {@link CharSequence}
1426         * @return a JID or {@code null}
1427         */
1428        public static DomainFullJid domainFullFromOrNull(CharSequence cs) {
1429                try {
1430                        return domainFullFrom(cs);
1431                } catch (XmppStringprepException e) {
1432                        return null;
1433                }
1434        }
1435
1436        /**
1437         * Get a {@link DomainFullJid} from an URL encoded CharSequence.
1438         *
1439         * @param cs a CharSequence representing an URL encoded domain full JID.
1440         * @return a domain full JID
1441         * @throws XmppStringprepException if an error occurs.
1442         * @see URLDecoder
1443         */
1444        public static DomainFullJid domainFullFromUrlEncoded(CharSequence cs) throws XmppStringprepException {
1445                String decoded = urlDecode(cs);
1446                return domainFullFrom(decoded);
1447        }
1448
1449        private static String urlDecode(CharSequence cs) {
1450                try {
1451                        return URLDecoder.decode(cs.toString(), "UTF-8");
1452                } catch (UnsupportedEncodingException e) {
1453                        throw new AssertionError(e);
1454                }
1455        }
1456}