001/**
002 *
003 * Copyright © 2014-2018 Florian Schmaus
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.jxmpp.jid.impl;
018
019import org.jxmpp.jid.BareJid;
020import org.jxmpp.jid.EntityBareJid;
021import org.jxmpp.jid.DomainBareJid;
022import org.jxmpp.jid.DomainFullJid;
023import org.jxmpp.jid.EntityFullJid;
024import org.jxmpp.jid.EntityJid;
025import org.jxmpp.jid.FullJid;
026import org.jxmpp.jid.Jid;
027import org.jxmpp.jid.parts.Domainpart;
028import org.jxmpp.jid.parts.Localpart;
029import org.jxmpp.jid.parts.Resourcepart;
030import org.jxmpp.stringprep.XmppStringprepException;
031import org.jxmpp.util.cache.Cache;
032import org.jxmpp.util.cache.LruCache;
033import org.jxmpp.util.XmppStringUtils;
034
035/**
036 * API to create JIDs (XMPP addresses) from Strings and CharSequences.
037 * <p>
038 * If the input was user generated, e.g. captured from some sort of user
039 * interface, {@link #fromUnescaped(String)} should be used instead. This allows
040 * the user to enter unescaped JID values. You can use
041 * {@link org.jxmpp.jid.util.JidUtil#isValidEntityBareJid(CharSequence)} to
042 * query, e.g. while the user it entering it, if a given CharSequence is a valid
043 * bare JID.
044 * </p>
045 * <p>
046 * JIDs created from input received from an XMPP source should use
047 * {@link #from(String)}.
048 * </p>
049 * <p>
050 * JidCreate uses caches for efficient Jid construction, But it's not guaranteed
051 * that the same String or CharSequence will yield the same Jid instance.
052 * </p>
053 *
054 * @see Jid
055 */
056public class JidCreate {
057
058        private static final Cache<String, Jid> JID_CACHE = new LruCache<String, Jid>(100);
059        private static final Cache<String, BareJid> BAREJID_CACHE = new LruCache<>(100);
060        private static final Cache<String, EntityJid> ENTITYJID_CACHE = new LruCache<>(100);
061        private static final Cache<String, FullJid> FULLJID_CACHE = new LruCache<>(100);
062        private static final Cache<String, EntityBareJid> ENTITY_BAREJID_CACHE = new LruCache<>(100);
063        private static final Cache<String, EntityFullJid> ENTITY_FULLJID_CACHE = new LruCache<>(100);
064        private static final Cache<String, DomainBareJid> DOMAINJID_CACHE = new LruCache<String, DomainBareJid>(100);
065        private static final Cache<String, DomainFullJid> DOMAINRESOURCEJID_CACHE = new LruCache<String, DomainFullJid>(100);
066
067        /**
068         * Get a {@link Jid} from the given parts.
069         * <p>
070         * Only the domainpart is required.
071         * </p>
072         *
073         * @param localpart a optional localpart.
074         * @param domainpart a required domainpart.
075         * @param resource a optional resourcepart.
076         * @return a JID which consists of the given parts.
077         * @throws XmppStringprepException if an error occurs.
078         */
079        public static Jid from(CharSequence localpart, CharSequence domainpart, CharSequence resource)
080                        throws XmppStringprepException {
081                return from(localpart.toString(), domainpart.toString(), resource.toString());
082        }
083
084        /**
085         * Get a {@link Jid} from the given parts.
086         * <p>
087         * Only the domainpart is required.
088         * </p>
089         *
090         * @param localpart a optional localpart.
091         * @param domainpart a required domainpart.
092         * @param resource a optional resourcepart.
093         * @return a JID which consists of the given parts.
094         * @throws XmppStringprepException if an error occurs.
095         */
096        public static Jid from(String localpart, String domainpart, String resource) throws XmppStringprepException {
097                String jidString = XmppStringUtils.completeJidFrom(localpart, domainpart, resource);
098                Jid jid = JID_CACHE.lookup(jidString);
099                if (jid != null) {
100                        return jid;
101                }
102                if (localpart.length() > 0 && domainpart.length() > 0 && resource.length() > 0) {
103                        jid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource);
104                } else if (localpart.length() > 0 && domainpart.length() > 0 && resource.length() == 0) {
105                        jid = new LocalAndDomainpartJid(localpart, domainpart);
106                } else if (localpart.length() == 0 && domainpart.length() > 0 && resource.length() == 0) {
107                        jid = new DomainpartJid(domainpart);
108                } else if (localpart.length() == 0 && domainpart.length() > 0 && resource.length() > 0) {
109                        jid = new DomainAndResourcepartJid(domainpart, resource);
110                } else {
111                        throw new IllegalArgumentException("Not a valid combination of localpart, domainpart and resource");
112                }
113                JID_CACHE.put(jidString, jid);
114                return jid;
115        }
116
117        /**
118         * Like {@link #from(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
119         * {@link XmppStringprepException}.
120         *
121         * @param cs the character sequence which should be transformed to a {@link Jid}
122         * @return the {@link Jid} if no exception occurs
123         * @throws IllegalArgumentException if the given input is not a valid JID
124         * @see #from(String)
125         * @since 0.6.2
126         */
127        public static Jid fromOrThrowUnchecked(CharSequence cs) {
128                try {
129                        return from(cs);
130                } catch (XmppStringprepException e) {
131                        throw new IllegalArgumentException(e);
132                }
133        }
134
135        /**
136         * Get a {@link Jid} from a CharSequence.
137         *
138         * @param jid the input CharSequence.
139         * @return the Jid represented by the input CharSequence.
140         * @throws XmppStringprepException if an error occurs.
141         * @see #from(String)
142         */
143        public static Jid from(CharSequence jid) throws XmppStringprepException {
144                return from(jid.toString());
145        }
146
147        /**
148         * Get a {@link Jid} from the given String.
149         *
150         * @param jidString the input String.
151         * @return the Jid represented by the input String.
152         * @throws XmppStringprepException if an error occurs.
153         * @see #from(CharSequence)
154         */
155        public static Jid from(String jidString) throws XmppStringprepException {
156                String localpart = XmppStringUtils.parseLocalpart(jidString);
157                String domainpart = XmppStringUtils.parseDomain(jidString);
158                String resource = XmppStringUtils.parseResource(jidString);
159                try {
160                        return from(localpart, domainpart, resource);
161                } catch (XmppStringprepException e) {
162                        throw new XmppStringprepException(jidString, e);
163                }
164        }
165
166        /**
167         * Get a {@link Jid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
168         *
169         * @param cs the input {@link CharSequence}
170         * @return a JID or {@code null}
171         */
172        public static Jid fromOrNull(CharSequence cs) {
173                try {
174                        return from(cs);
175                } catch (XmppStringprepException e) {
176                        return null;
177                }
178        }
179
180        /**
181         * Like {@link #fromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
182         * {@link XmppStringprepException}.
183         *
184         * @param cs the character sequence which should be transformed to a {@link Jid}
185         * @return the {@link Jid} if no exception occurs
186         * @throws IllegalArgumentException if the given input is not a valid JID
187         * @see #fromUnescaped(CharSequence)
188         * @since 0.6.2
189         */
190        public static Jid fromUnescapedOrThrowUnchecked(CharSequence cs) {
191                try {
192                        return fromUnescaped(cs);
193                } catch (XmppStringprepException e) {
194                        throw new IllegalArgumentException(e);
195                }
196        }
197
198        /**
199         * Get a {@link Jid} from the given unescaped CharSequence.
200         *
201         * @param unescapedJid an unescaped CharSequence representing a JID.
202         * @return a JID.
203         * @throws XmppStringprepException if an error occurs.
204         */
205        public static Jid fromUnescaped(CharSequence unescapedJid) throws XmppStringprepException {
206                return fromUnescaped(unescapedJid.toString());
207        }
208
209        /**
210         * Get a {@link Jid} from the given unescaped String.
211         *
212         * @param unescapedJidString a unescaped String representing a JID.
213         * @return a JID.
214         * @throws XmppStringprepException if an error occurs.
215         */
216        public static Jid fromUnescaped(String unescapedJidString) throws XmppStringprepException {
217                String localpart = XmppStringUtils.parseLocalpart(unescapedJidString);
218                // Some as from(String), but we escape the localpart
219                localpart = XmppStringUtils.escapeLocalpart(localpart);
220
221                String domainpart = XmppStringUtils.parseDomain(unescapedJidString);
222                String resource = XmppStringUtils.parseResource(unescapedJidString);
223                try {
224                        return from(localpart, domainpart, resource);
225                } catch (XmppStringprepException e) {
226                        throw new XmppStringprepException(unescapedJidString, e);
227                }
228        }
229
230        /**
231         * Get a {@link Jid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
232         *
233         * @param cs the input {@link CharSequence}
234         * @return a JID or {@code null}
235         */
236        public static Jid fromUnescapedOrNull(CharSequence cs) {
237                try {
238                        return fromUnescaped(cs);
239                } catch (XmppStringprepException e) {
240                        return null;
241                }
242        }
243
244        /**
245         * Like {@link #bareFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
246         * {@link XmppStringprepException}.
247         *
248         * @param cs the character sequence which should be transformed to a {@link BareJid}
249         * @return the {@link BareJid} if no exception occurs
250         * @throws IllegalArgumentException if the given input is not a valid JID
251         * @see #bareFrom(CharSequence)
252         * @since 0.6.2
253         */
254        public static BareJid bareFromOrThrowUnchecked(CharSequence cs) {
255                try {
256                        return bareFrom(cs);
257                } catch (XmppStringprepException e) {
258                        throw new IllegalArgumentException(e);
259                }
260        }
261
262        /**
263         * Get a {@link BareJid} representing the given CharSequence.
264         *
265         * @param jid the input CharSequence.
266         * @return a bare JID representing the given CharSequence.
267         * @throws XmppStringprepException if an error occurs.
268         */
269        public static BareJid bareFrom(CharSequence jid) throws XmppStringprepException {
270                return bareFrom(jid.toString());
271        }
272
273        /**
274         * Get a {@link BareJid} representing the given String.
275         *
276         * @param jid the input String.
277         * @return a bare JID representing the given String.
278         * @throws XmppStringprepException if an error occurs.
279         */
280        public static BareJid bareFrom(String jid) throws XmppStringprepException {
281                BareJid bareJid = BAREJID_CACHE.lookup(jid);
282                if (bareJid != null) {
283                        return bareJid;
284                }
285
286                String localpart = XmppStringUtils.parseLocalpart(jid);
287                String domainpart = XmppStringUtils.parseDomain(jid);
288                try {
289                        if (localpart.length() != 0) {
290                                bareJid = new LocalAndDomainpartJid(localpart, domainpart);
291                        } else {
292                                bareJid = new DomainpartJid(domainpart);
293                        }
294                } catch (XmppStringprepException e) {
295                        throw new XmppStringprepException(jid, e);
296                }
297                BAREJID_CACHE.put(jid, bareJid);
298                return bareJid;
299        }
300
301        /**
302         * Get a {@link BareJid} constructed from the optionally given {@link Localpart} and {link DomainBareJid}.
303         *
304         * @param localpart a optional localpart.
305         * @param domainBareJid a domain bare JID.
306         * @return a bare JID.
307         */
308        public static BareJid bareFrom(Localpart localpart, DomainBareJid domainBareJid) {
309                return bareFrom(localpart, domainBareJid.getDomain());
310        }
311
312        /**
313         * Get a {@link BareJid} constructed from the optionally given {@link Localpart} and {@link Domainpart}.
314         *
315         * @param localpart a optional localpart.
316         * @param domain a domainpart.
317         * @return a bare JID constructed from the given parts.
318         */
319        public static BareJid bareFrom(Localpart localpart, Domainpart domain) {
320                if (localpart != null) {
321                        return new LocalAndDomainpartJid(localpart, domain);
322                } else {
323                        return new DomainpartJid(domain);
324                }
325        }
326
327        /**
328         * Get a {@link BareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
329         *
330         * @param cs the input {@link CharSequence}
331         * @return a JID or {@code null}
332         */
333        public static BareJid bareFromOrNull(CharSequence cs) {
334                try {
335                        return bareFrom(cs);
336                } catch (XmppStringprepException e) {
337                        return null;
338                }
339        }
340
341        /**
342         * Like {@link #fullFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
343         * {@link XmppStringprepException}.
344         *
345         * @param cs the character sequence which should be transformed to a {@link FullJid}
346         * @return the {@link FullJid} if no exception occurs
347         * @throws IllegalArgumentException if the given input is not a valid JID
348         * @see #fullFrom(CharSequence)
349         * @since 0.6.2
350         */
351        public static FullJid fullFromOrThrowUnchecked(CharSequence cs) {
352                try {
353                        return fullFrom(cs);
354                } catch (XmppStringprepException e) {
355                        throw new IllegalArgumentException(e);
356                }
357        }
358
359        /**
360         * Get a {@link FullJid} representing the given CharSequence.
361         *
362         * @param jid a CharSequence representing a JID.
363         * @return a full JID representing the given CharSequence.
364         * @throws XmppStringprepException if an error occurs.
365         */
366        public static FullJid fullFrom(CharSequence jid) throws XmppStringprepException {
367                return fullFrom(jid.toString());
368        }
369
370        /**
371         * Get a {@link FullJid} representing the given String.
372         *
373         * @param jid the JID's String.
374         * @return a full JID representing the input String.
375         * @throws XmppStringprepException if an error occurs.
376         */
377        public static FullJid fullFrom(String jid) throws XmppStringprepException {
378                FullJid fullJid = FULLJID_CACHE.lookup(jid);
379                if (fullJid != null) {
380                        return fullJid;
381                }
382
383                String localpart = XmppStringUtils.parseLocalpart(jid);
384                String domainpart = XmppStringUtils.parseDomain(jid);
385                String resource = XmppStringUtils.parseResource(jid);
386                try {
387                        fullJid = fullFrom(localpart, domainpart, resource);
388                } catch (XmppStringprepException e) {
389                        throw new XmppStringprepException(jid, e);
390                }
391                FULLJID_CACHE.put(jid, fullJid);
392                return fullJid;
393        }
394
395        /**
396         * Get a {@link FullJid} constructed from the given parts.
397         *
398         * @param localpart a optional localpart.
399         * @param domainpart a domainpart.
400         * @param resource a resourcepart.
401         * @return a full JID.
402         * @throws XmppStringprepException if an error occurs.
403         */
404        public static FullJid fullFrom(String localpart, String domainpart, String resource) throws XmppStringprepException {
405                FullJid fullJid;
406                try {
407                        if (localpart == null || localpart.length() == 0) {
408                                fullJid = new DomainAndResourcepartJid(domainpart, resource);
409                        } else {
410                                fullJid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource);
411                        }
412                } catch (XmppStringprepException e) {
413                        throw new XmppStringprepException(localpart + '@' + domainpart + '/' + resource, e);
414                }
415                return fullJid;
416        }
417
418        /**
419         * Get a {@link FullJid} constructed from the given parts.
420         *
421         * @param localpart a optional localpart.
422         * @param domainBareJid a domain bare JID. 
423         * @param resource a resourcepart
424         * @return a full JID.
425         */
426        public static FullJid fullFrom(Localpart localpart, DomainBareJid domainBareJid, Resourcepart resource) {
427                return fullFrom(localpart, domainBareJid.getDomain(), resource);
428        }
429
430        /**
431         * Get a {@link FullJid} constructed from the given parts.
432         *
433         * @param localpart the optional localpart.
434         * @param domainpart the domainpart.
435         * @param resource the resourcepart.
436         * @return a full JID.
437         */
438        public static FullJid fullFrom(Localpart localpart, Domainpart domainpart, Resourcepart resource) {
439                return fullFrom(entityBareFrom(localpart, domainpart), resource);
440        }
441
442        /**
443         * Get a {@link FullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
444         *
445         * @param cs the input {@link CharSequence}
446         * @return a JID or {@code null}
447         */
448        public static FullJid fullFromOrNull(CharSequence cs) {
449                try {
450                        return fullFrom(cs);
451                } catch (XmppStringprepException e) {
452                        return null;
453                }
454        }
455
456        /**
457         * Like {@link #entityFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
458         * {@link XmppStringprepException}.
459         *
460         * @param cs the character sequence which should be transformed to a {@link EntityJid}
461         * @return the {@link EntityJid} if no exception occurs
462         * @throws IllegalArgumentException if the given input is not a valid JID
463         * @see #entityFrom(CharSequence)
464         * @since 0.6.2
465         */
466        public static EntityJid entityFromOrThrowUnchecked(CharSequence cs) {
467                try {
468                        return entityFrom(cs);
469                } catch (XmppStringprepException e) {
470                        throw new IllegalArgumentException(e);
471                }
472        }
473
474        /**
475         * Get a {@link EntityFullJid} constructed from a {@link EntityBareJid} and a {@link Resourcepart}.
476         *
477         * @param bareJid a entity bare JID.
478         * @param resource a resourcepart.
479         * @return a full JID.
480         */
481        public static EntityFullJid fullFrom(EntityBareJid bareJid, Resourcepart resource) {
482                return new LocalDomainAndResourcepartJid(bareJid, resource);
483        }
484
485        /**
486         * Get a {@link EntityJid} representing the given String.
487         *
488         * @param jid the JID's string.
489         * @return an entity JID representing the given String.
490         * @throws XmppStringprepException if an error occurs.
491         */
492        public static EntityJid entityFrom(CharSequence jid) throws XmppStringprepException {
493                return entityFrom(jid.toString());
494        }
495
496        /**
497         * Get a {@link EntityJid} representing the given String.
498         *
499         * @param jidString the JID's string.
500         * @return an entity JID representing the given String.
501         * @throws XmppStringprepException if an error occurs.
502         */
503        public static EntityJid entityFrom(String jidString) throws XmppStringprepException {
504                return entityFrom(jidString, false);
505        }
506
507        /**
508         * Like {@link #entityFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
509         * {@link XmppStringprepException}.
510         *
511         * @param cs the character sequence which should be transformed to a {@link EntityJid}
512         * @return the {@link EntityJid} if no exception occurs
513         * @throws IllegalArgumentException if the given input is not a valid JID
514         * @see #entityFromUnescaped(CharSequence)
515         * @since 0.6.2
516         */
517        public static EntityJid entityFromUnescapedOrThrowUnchecked(CharSequence cs) {
518                try {
519                        return entityFromUnescaped(cs);
520                } catch (XmppStringprepException e) {
521                        throw new IllegalArgumentException(e);
522                }
523        }
524
525        /**
526         * Get a {@link EntityJid} representing the given String.
527         *
528         * @param jid the JID.
529         * @return an entity JID representing the given input..
530         * @throws XmppStringprepException if an error occurs.
531         */
532        public static EntityJid entityFromUnescaped(CharSequence jid) throws XmppStringprepException {
533                return entityFromUnescaped(jid.toString());
534        }
535
536        /**
537         * Get a {@link EntityJid} representing the given String.
538         *
539         * @param jidString the JID's string.
540         * @return an entity JID representing the given String.
541         * @throws XmppStringprepException if an error occurs.
542         */
543        public static EntityJid entityFromUnescaped(String jidString) throws XmppStringprepException {
544                return entityFrom(jidString, true);
545        }
546
547        /**
548         * Get a {@link EntityJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
549         *
550         * @param cs the input {@link CharSequence}
551         * @return a JID or {@code null}
552         */
553        public static EntityJid entityFromUnesacpedOrNull(CharSequence cs) {
554                try {
555                        return entityFromUnescaped(cs.toString());
556                } catch (XmppStringprepException e) {
557                        return null;
558                }
559        }
560
561        /**
562         * Get a {@link EntityJid} representing the given String.
563         *
564         * @param jidString the JID's string.
565         * @param unescaped if the JID string is unescaped.
566         * @return an entity JID representing the given String.
567         * @throws XmppStringprepException if an error occurs.
568         */
569        private static EntityJid entityFrom(String jidString, boolean unescaped) throws XmppStringprepException {
570                EntityJid entityJid = ENTITYJID_CACHE.lookup(jidString);
571                if (entityJid != null) {
572                        return entityJid;
573                }
574                String localpartString = XmppStringUtils.parseLocalpart(jidString);
575                if (localpartString.length() ==  0) {
576                        throw new XmppStringprepException("Does not contain a localpart", jidString);
577                }
578                Localpart localpart;
579                try {
580                        if (unescaped) {
581                                localpart = Localpart.fromUnescaped(localpartString);
582                        } else {
583                                localpart = Localpart.from(localpartString);
584                        }
585                } catch (XmppStringprepException e) {
586                        throw new XmppStringprepException(jidString, e);
587                }
588
589                String domainpartString = XmppStringUtils.parseDomain(jidString);
590                Domainpart domainpart;
591                try {
592                        domainpart = Domainpart.from(domainpartString);
593                } catch (XmppStringprepException e) {
594                        throw new XmppStringprepException(jidString, e);
595                }
596
597                String resourceString = XmppStringUtils.parseResource(jidString);
598                if (resourceString.length() > 0) {
599                        Resourcepart resourcepart;
600                        try {
601                                resourcepart = Resourcepart.from(resourceString);
602                        } catch (XmppStringprepException e) {
603                                throw new XmppStringprepException(jidString, e);
604                        }
605                        entityJid = entityFullFrom(localpart, domainpart, resourcepart);
606                } else {
607                        entityJid = entityBareFrom(localpart, domainpart);
608                }
609
610                ENTITYJID_CACHE.put(jidString, entityJid);
611                return entityJid;
612        }
613
614        /**
615         * Get a {@link EntityJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
616         *
617         * @param cs the input {@link CharSequence}
618         * @return a JID or {@code null}
619         */
620        public static EntityJid entityFromOrNull(CharSequence cs) {
621                try {
622                        return entityFrom(cs);
623                } catch (XmppStringprepException e) {
624                        return null;
625                }
626        }
627
628        /**
629         * Like {@link #entityBareFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
630         * {@link XmppStringprepException}.
631         *
632         * @param cs the character sequence which should be transformed to a {@link EntityBareJid}
633         * @return the {@link EntityBareJid} if no exception occurs
634         * @throws IllegalArgumentException if the given input is not a valid JID
635         * @see #entityBareFrom(CharSequence)
636         * @since 0.6.2
637         */
638        public static EntityBareJid entityBareFromOrThrowUnchecked(CharSequence cs) {
639                try {
640                        return entityBareFrom(cs);
641                } catch (XmppStringprepException e) {
642                        throw new IllegalArgumentException(e);
643                }
644        }
645
646        /**
647         * Get a {@link EntityBareJid} representing the given CharSequence.
648         *
649         * @param jid the input CharSequence.
650         * @return a bare JID representing the given CharSequence.
651         * @throws XmppStringprepException if an error occurs.
652         */
653        public static EntityBareJid entityBareFrom(CharSequence jid) throws XmppStringprepException {
654                return entityBareFrom(jid.toString());
655        }
656
657        /**
658         * Get a {@link EntityBareJid} representing the given String.
659         *
660         * @param jid the input String.
661         * @return a bare JID representing the given String.
662         * @throws XmppStringprepException if an error occurs.
663         */
664        public static EntityBareJid entityBareFrom(String jid) throws XmppStringprepException {
665                EntityBareJid bareJid = ENTITY_BAREJID_CACHE.lookup(jid);
666                if (bareJid != null) {
667                        return bareJid;
668                }
669
670                String localpart = XmppStringUtils.parseLocalpart(jid);
671                String domainpart = XmppStringUtils.parseDomain(jid);
672                try {
673                        bareJid = new LocalAndDomainpartJid(localpart, domainpart);
674                } catch (XmppStringprepException e) {
675                        throw new XmppStringprepException(jid, e);
676                }
677                ENTITY_BAREJID_CACHE.put(jid, bareJid);
678                return bareJid;
679        }
680
681        /**
682         * Like {@link #entityBareFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
683         * {@link XmppStringprepException}.
684         *
685         * @param cs the character sequence which should be transformed to a {@link EntityBareJid}
686         * @return the {@link EntityBareJid} if no exception occurs
687         * @throws IllegalArgumentException if the given input is not a valid JID
688         * @see #entityBareFromUnescaped(CharSequence)
689         * @since 0.6.2
690         */
691        public static EntityBareJid entityBareFromUnescapedOrThrowUnchecked(CharSequence cs) {
692                try {
693                        return entityBareFromUnescaped(cs);
694                } catch (XmppStringprepException e) {
695                        throw new IllegalArgumentException(e);
696                }
697        }
698
699        /**
700         * Get a {@link EntityBareJid} representing the given unescaped CharSequence.
701         *
702         * @param unescapedJid the input CharSequence.
703         * @return a bare JID representing the given CharSequence.
704         * @throws XmppStringprepException if an error occurs.
705         */
706        public static EntityBareJid entityBareFromUnescaped(CharSequence unescapedJid) throws XmppStringprepException {
707                return entityBareFromUnescaped(unescapedJid.toString());
708        }
709
710        /**
711         * Get a {@link EntityBareJid} representing the given unescaped String.
712         *
713         * @param unescapedJidString the input String.
714         * @return a bare JID representing the given String.
715         * @throws XmppStringprepException if an error occurs.
716         */
717        public static EntityBareJid entityBareFromUnescaped(String unescapedJidString) throws XmppStringprepException {
718                EntityBareJid bareJid = ENTITY_BAREJID_CACHE.lookup(unescapedJidString);
719                if (bareJid != null) {
720                        return bareJid;
721                }
722
723                String localpart = XmppStringUtils.parseLocalpart(unescapedJidString);
724                // Some as from(String), but we escape the localpart
725                localpart = XmppStringUtils.escapeLocalpart(localpart);
726
727                String domainpart = XmppStringUtils.parseDomain(unescapedJidString);
728                try {
729                        bareJid = new LocalAndDomainpartJid(localpart, domainpart);
730                } catch (XmppStringprepException e) {
731                        throw new XmppStringprepException(unescapedJidString, e);
732                }
733                ENTITY_BAREJID_CACHE.put(unescapedJidString, bareJid);
734                return bareJid;
735        }
736
737        /**
738         * Get a {@link EntityBareJid} 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 EntityBareJid entityBareFromUnescapedOrNull(CharSequence cs) {
744                try {
745                        return entityBareFromUnescaped(cs.toString());
746                } catch (XmppStringprepException e) {
747                        return null;
748                }
749        }
750
751        /**
752         * Get a {@link EntityBareJid} constructed from the given {@link Localpart} and {link DomainBareJid}.
753         *
754         * @param localpart a localpart.
755         * @param domainBareJid a domain bare JID.
756         * @return a bare JID.
757         */
758        public static EntityBareJid entityBareFrom(Localpart localpart, DomainBareJid domainBareJid) {
759                return entityBareFrom(localpart, domainBareJid.getDomain());
760        }
761
762        /**
763         * Get a {@link EntityBareJid} constructed from the given {@link Localpart} and {@link Domainpart}.
764         *
765         * @param localpart a localpart.
766         * @param domain a domainpart.
767         * @return a bare JID constructed from the given parts.
768         */
769        public static EntityBareJid entityBareFrom(Localpart localpart, Domainpart domain) {
770                return new LocalAndDomainpartJid(localpart, domain);
771        }
772
773        /**
774         * Get a {@link EntityBareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
775         *
776         * @param cs the input {@link CharSequence}
777         * @return a JID or {@code null}
778         */
779        public static EntityBareJid entityBareFromOrNull(CharSequence cs) {
780                try {
781                        return entityBareFrom(cs);
782                } catch (XmppStringprepException e) {
783                        return null;
784                }
785        }
786
787        /**
788         * Like {@link #entityFullFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
789         * {@link XmppStringprepException}.
790         *
791         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
792         * @return the {@link EntityFullJid} if no exception occurs
793         * @throws IllegalArgumentException if the given input is not a valid JID
794         * @see #entityFullFrom(CharSequence)
795         * @since 0.6.2
796         */
797        public static EntityFullJid entityFullFromOrThrowUnchecked(CharSequence cs) {
798                try {
799                        return entityFullFrom(cs);
800                } catch (XmppStringprepException e) {
801                        throw new IllegalArgumentException(e);
802                }
803        }
804
805        /**
806         * Get a {@link EntityFullJid} representing the given CharSequence.
807         *
808         * @param jid a CharSequence representing a JID.
809         * @return a full JID representing the given CharSequence.
810         * @throws XmppStringprepException if an error occurs.
811         */
812        public static EntityFullJid entityFullFrom(CharSequence jid) throws XmppStringprepException {
813                return entityFullFrom(jid.toString());
814        }
815
816        /**
817         * Get a {@link EntityFullJid} representing the given String.
818         *
819         * @param jid the JID's String.
820         * @return a full JID representing the input String.
821         * @throws XmppStringprepException if an error occurs.
822         */
823        public static EntityFullJid entityFullFrom(String jid) throws XmppStringprepException {
824                EntityFullJid fullJid = ENTITY_FULLJID_CACHE.lookup(jid);
825                if (fullJid != null) {
826                        return fullJid;
827                }
828
829                String localpart = XmppStringUtils.parseLocalpart(jid);
830                String domainpart = XmppStringUtils.parseDomain(jid);
831                String resource = XmppStringUtils.parseResource(jid);
832                try {
833                        fullJid = entityFullFrom(localpart, domainpart, resource);
834                } catch (XmppStringprepException e) {
835                        throw new XmppStringprepException(jid, e);
836                }
837                ENTITY_FULLJID_CACHE.put(jid, fullJid);
838                return fullJid;
839        }
840
841        /**
842         * Get a {@link EntityFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
843         *
844         * @param cs the input {@link CharSequence}
845         * @return a JID or {@code null}
846         */
847        public static EntityFullJid entityFullFromOrNull(CharSequence cs) {
848                try {
849                        return entityFullFrom(cs);
850                } catch (XmppStringprepException e) {
851                        return null;
852                }
853        }
854
855        /**
856         * Like {@link #entityFullFromUnescaped(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
857         * {@link XmppStringprepException}.
858         *
859         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
860         * @return the {@link EntityFullJid} if no exception occurs
861         * @throws IllegalArgumentException if the given input is not a valid JID
862         * @see #entityFullFromUnescaped(CharSequence)
863         * @since 0.6.2
864         */
865        public static EntityFullJid entityFullFromUnescapedOrThrowUnchecked(CharSequence cs) {
866                try {
867                        return entityFullFromUnescaped(cs);
868                } catch (XmppStringprepException e) {
869                        throw new IllegalArgumentException(e);
870                }
871        }
872
873        /**
874         * Get a {@link EntityFullJid} representing the given unescaped CharSequence.
875         *
876         * @param unescapedJid a CharSequence representing a JID.
877         * @return a full JID representing the given CharSequence.
878         * @throws XmppStringprepException if an error occurs.
879         */
880        public static EntityFullJid entityFullFromUnescaped(CharSequence unescapedJid) throws XmppStringprepException {
881                return entityFullFromUnescaped(unescapedJid.toString());
882        }
883
884        /**
885         * Get a {@link EntityFullJid} representing the given unescaped String.
886         *
887         * @param unescapedJidString the JID's String.
888         * @return a full JID representing the input String.
889         * @throws XmppStringprepException if an error occurs.
890         */
891        public static EntityFullJid entityFullFromUnescaped(String unescapedJidString) throws XmppStringprepException {
892                EntityFullJid fullJid = ENTITY_FULLJID_CACHE.lookup(unescapedJidString);
893                if (fullJid != null) {
894                        return fullJid;
895                }
896
897                String localpart = XmppStringUtils.parseLocalpart(unescapedJidString);
898                // Some as from(String), but we escape the localpart
899                localpart = XmppStringUtils.escapeLocalpart(localpart);
900
901                String domainpart = XmppStringUtils.parseDomain(unescapedJidString);
902                String resource = XmppStringUtils.parseResource(unescapedJidString);
903                try {
904                        fullJid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource);
905                } catch (XmppStringprepException e) {
906                        throw new XmppStringprepException(unescapedJidString, e);
907                }
908
909                ENTITY_FULLJID_CACHE.put(unescapedJidString, fullJid);
910                return fullJid;
911        }
912
913        /**
914         * Get a {@link EntityFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
915         *
916         * @param cs the input {@link CharSequence}
917         * @return a JID or {@code null}
918         */
919        public static EntityFullJid entityFullFromUnescapedOrNull(CharSequence cs) {
920                try {
921                        return entityFullFromUnescaped(cs.toString());
922                } catch (XmppStringprepException e) {
923                        return null;
924                }
925        }
926
927        /**
928         * Get a {@link EntityFullJid} constructed from the given parts.
929         *
930         * @param localpart a localpart.
931         * @param domainpart a domainpart.
932         * @param resource a resourcepart.
933         * @return a full JID.
934         * @throws XmppStringprepException if an error occurs.
935         */
936        public static EntityFullJid entityFullFrom(String localpart, String domainpart, String resource) throws XmppStringprepException {
937                EntityFullJid fullJid;
938                try {
939                        fullJid = new LocalDomainAndResourcepartJid(localpart, domainpart, resource);
940                } catch (XmppStringprepException e) {
941                        throw new XmppStringprepException(localpart + '@' + domainpart + '/' + resource, e);
942                }
943                return fullJid;
944        }
945
946        /**
947         * Get a {@link EntityFullJid} constructed from the given parts.
948         *
949         * @param localpart a localpart.
950         * @param domainBareJid a domain bare JID.. 
951         * @param resource a resourcepart
952         * @return a full JID.
953         */
954        public static EntityFullJid entityFullFrom(Localpart localpart, DomainBareJid domainBareJid, Resourcepart resource) {
955                return entityFullFrom(localpart, domainBareJid.getDomain(), resource);
956        }
957
958        /**
959         * Get a {@link EntityFullJid} constructed from the given parts.
960         * 
961         * @param localpart the localpart.
962         * @param domainpart the domainpart.
963         * @param resource the resourcepart.
964         * @return a full JID.
965         */
966        public static EntityFullJid entityFullFrom(Localpart localpart, Domainpart domainpart, Resourcepart resource) {
967                return entityFullFrom(entityBareFrom(localpart, domainpart), resource);
968        }
969
970        /**
971         * Get a {@link EntityFullJid} constructed from a {@link EntityBareJid} and a {@link Resourcepart}.
972         *
973         * @param bareJid a bare JID.
974         * @param resource a resourcepart.
975         * @return a full JID.
976         */
977        public static EntityFullJid entityFullFrom(EntityBareJid bareJid, Resourcepart resource) {
978                return new LocalDomainAndResourcepartJid(bareJid, resource);
979        }
980
981        /**
982         * Deprecated.
983         *
984         * @param jid the JID.
985         * @return a DopmainBareJid
986         * @throws XmppStringprepException if an error happens.
987         * @deprecated use {@link #domainBareFrom(String)} instead
988         */
989        @Deprecated
990        public static DomainBareJid serverBareFrom(String jid) throws XmppStringprepException {
991                return domainBareFrom(jid);
992        }
993
994        /**
995         * Like {@link #domainBareFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
996         * {@link XmppStringprepException}.
997         *
998         * @param cs the character sequence which should be transformed to a {@link EntityFullJid}
999         * @return the {@link EntityFullJid} if no exception occurs
1000         * @see #from(String)
1001         * @since 0.6.2
1002         */
1003        public static DomainBareJid domainBareFromOrThrowUnchecked(CharSequence cs) {
1004                try {
1005                        return domainBareFrom(cs);
1006                } catch (XmppStringprepException e) {
1007                        throw new IllegalArgumentException(e);
1008                }
1009        }
1010
1011        /**
1012         * Get a domain bare JID.
1013         *
1014         * @param jid the JID CharSequence.
1015         * @return a domain bare JID.
1016         * @throws XmppStringprepException if an error occurs.
1017         */
1018        public static DomainBareJid domainBareFrom(CharSequence jid) throws XmppStringprepException {
1019                return domainBareFrom(jid.toString());
1020        }
1021
1022        /**
1023         * Get a domain bare JID.
1024         *
1025         * @param jid the JID String.
1026         * @return a domain bare JID.
1027         * @throws XmppStringprepException if an error occurs.
1028         */
1029        public static DomainBareJid domainBareFrom(String jid) throws XmppStringprepException {
1030                DomainBareJid domainJid = DOMAINJID_CACHE.lookup(jid);
1031                if (domainJid != null) {
1032                        return domainJid;
1033                }
1034
1035                String domain = XmppStringUtils.parseDomain(jid);
1036                try {
1037                        domainJid = new DomainpartJid(domain);
1038                } catch (XmppStringprepException e) {
1039                        throw new XmppStringprepException(jid, e);
1040                }
1041                DOMAINJID_CACHE.put(jid, domainJid);
1042                return domainJid;
1043        }
1044
1045        /**
1046         * Get a {@link DomainBareJid} consisting of the given {@link Domainpart}.
1047         *
1048         * @param domainpart the domainpart.
1049         * @return a domain bare JID.
1050         */
1051        public static DomainBareJid domainBareFrom(Domainpart domainpart) {
1052                return new DomainpartJid(domainpart);
1053        }
1054
1055        /**
1056         * Get a {@link DomainBareJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1057         *
1058         * @param cs the input {@link CharSequence}
1059         * @return a JID or {@code null}
1060         */
1061        public static DomainBareJid domainBareFromOrNull(CharSequence cs) {
1062                try {
1063                        return domainBareFrom(cs);
1064                } catch (XmppStringprepException e) {
1065                        return null;
1066                }
1067        }
1068
1069        /**
1070         * Deprecated.
1071         *
1072         * @param jid the JID.
1073         * @return a DomainFullJid
1074         * @throws XmppStringprepException if an error happens.
1075         * @deprecated use {@link #domainFullFrom(String)} instead
1076         */
1077        @Deprecated
1078        public static DomainFullJid serverFullFrom(String jid) throws XmppStringprepException {
1079                return donmainFullFrom(jid);
1080        }
1081
1082        /**
1083         * Get a domain full JID from the given String.
1084         *
1085         * @param jid the JID.
1086         * @return a DomainFullJid.
1087         * @throws XmppStringprepException if an error happens.
1088         * @deprecated use {@link #domainFullFrom(String)} instead.
1089         */
1090        @Deprecated
1091        public static DomainFullJid donmainFullFrom(String jid) throws XmppStringprepException {
1092                return domainFullFrom(jid);
1093        }
1094
1095        /**
1096         * Like {@link #domainFullFrom(CharSequence)} but does throw an unchecked {@link IllegalArgumentException} instead of a
1097         * {@link XmppStringprepException}.
1098         *
1099         * @param cs the character sequence which should be transformed to a {@link DomainFullJid}
1100         * @return the {@link DomainFullJid} if no exception occurs
1101         * @throws IllegalArgumentException if the given input is not a valid JID
1102         * @see #domainFullFrom(CharSequence)
1103         * @since 0.6.2
1104         */
1105        public static DomainFullJid domainFullFromOrThrowUnchecked(CharSequence cs) {
1106                try {
1107                        return domainFullFrom(cs);
1108                } catch (XmppStringprepException e) {
1109                        throw new IllegalArgumentException(e);
1110                }
1111        }
1112
1113        /**
1114         * Get a domain full JID from the given CharSequence.
1115         *
1116         * @param jid the JID.
1117         * @return a domain full JID.
1118         * @throws XmppStringprepException if an error happens.
1119         */
1120        public static DomainFullJid domainFullFrom(CharSequence jid) throws XmppStringprepException {
1121                return domainFullFrom(jid.toString());
1122        }
1123
1124        /**
1125         * Get a domain full JID from the given String.
1126         *
1127         * @param jid the JID.
1128         * @return a DomainFullJid.
1129         * @throws XmppStringprepException if an error happens.
1130         */
1131        public static DomainFullJid domainFullFrom(String jid) throws XmppStringprepException {
1132                DomainFullJid domainResourceJid = DOMAINRESOURCEJID_CACHE.lookup(jid);
1133                if (domainResourceJid != null) {
1134                        return domainResourceJid;
1135                }
1136
1137                String domain = XmppStringUtils.parseDomain(jid);
1138                String resource = XmppStringUtils.parseResource(jid);
1139                try {
1140                        domainResourceJid = new DomainAndResourcepartJid(domain, resource);
1141                } catch (XmppStringprepException e) {
1142                        throw new XmppStringprepException(jid, e);
1143                }
1144                DOMAINRESOURCEJID_CACHE.put(jid, domainResourceJid);
1145                return domainResourceJid;
1146        }
1147
1148        /**
1149         * Get a domain full JID.
1150         *
1151         * @param domainpart the domainpart.
1152         * @param resource the resourcepart.
1153         * @return a domain full JID.
1154         */
1155        public static DomainFullJid domainFullFrom(Domainpart domainpart, Resourcepart resource) {
1156                return domainFullFrom(domainBareFrom(domainpart), resource);
1157        }
1158
1159        /**
1160         * Get a domain full JID.
1161         *
1162         * @param domainBareJid a domain bare JID.
1163         * @param resource a resourcepart.
1164         * @return a domain full JID.
1165         */
1166        public static DomainFullJid domainFullFrom(DomainBareJid domainBareJid, Resourcepart resource) {
1167                return new DomainAndResourcepartJid(domainBareJid, resource);
1168        }
1169
1170        /**
1171         * Get a {@link DomainFullJid} from a given {@link CharSequence} or {@code null} if the input does not represent a JID.
1172         *
1173         * @param cs the input {@link CharSequence}
1174         * @return a JID or {@code null}
1175         */
1176        public static DomainFullJid domainFullFromOrNull(CharSequence cs) {
1177                try {
1178                        return domainFullFrom(cs);
1179                } catch (XmppStringprepException e) {
1180                        return null;
1181                }
1182        }
1183}