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.stringprep;
018
019import org.jxmpp.JxmppContext;
020import org.jxmpp.XmppAddressParttype;
021import org.jxmpp.stringprep.simple.SimpleXmppStringprep;
022import org.jxmpp.util.cache.Cache;
023import org.jxmpp.util.cache.LruCache;
024
025public class XmppStringPrepUtil {
026
027        static {
028                // Ensure that there is always at least the simple XMPP stringprep implementation active
029                SimpleXmppStringprep.setup();
030        }
031
032        private static final Cache<String, String> NODEPREP_CACHE = new LruCache<String, String>(100);
033        private static final Cache<String, String> DOMAINPREP_CACHE = new LruCache<String, String>(100);
034        private static final Cache<String, String> RESOURCEPREP_CACHE = new LruCache<String, String>(100);
035
036        /**
037         * Set the XMPP Stringprep implementation to use.
038         *
039         * @param xmppStringprep the XMPP Stringprep implementation to use.
040         * @deprecated use {@link JxmppContext#setDefaultXmppStringprep(XmppStringprep)} instead.
041         */
042        @Deprecated
043        // TODO: Remove in JXMPP 0.8.
044        public static void setXmppStringprep(XmppStringprep xmppStringprep) {
045                JxmppContext.setDefaultXmppStringprep(xmppStringprep);
046        }
047
048        /**
049         * Perform localprep on the input String.
050         *
051         * @param string the input String.
052         * @return the localpreped String.
053         * @throws XmppStringprepException if the input String can not be transformed.
054         */
055        public static String localprep(String string) throws XmppStringprepException {
056                return localprep(string, JxmppContext.getDefaultContext());
057        }
058
059        /**
060         * Perform localprep on the input String.
061         *
062         * @param string the input String.
063         * @param context the JXMPP JID context.
064         * @return the localpreped String.
065         * @throws XmppStringprepException if the input String can not be transformed.
066         */
067        public static String localprep(String string, JxmppContext context) throws XmppStringprepException {
068                throwIfNullOrEmpty(string, XmppAddressParttype.localpart);
069                String res;
070                if (context.isCachingEnabled()) {
071                        res = NODEPREP_CACHE.lookup(string);
072                        if (res != null) {
073                                return res;
074                        }
075                }
076
077                res = context.xmppStringprep.localprep(string);
078
079                if (context.isCachingEnabled()) {
080                        NODEPREP_CACHE.put(string, res);
081                }
082                return res;
083        }
084
085        /**
086         * Perform domainprep on the input String.
087         *
088         * @param string the input String.
089         * @return the domainprep String.
090         * @throws XmppStringprepException if the input String can not be transformed.
091         */
092        public static String domainprep(String string) throws XmppStringprepException {
093                return domainprep(string, JxmppContext.getDefaultContext());
094        }
095
096
097        /**
098         * Perform domainprep on the input String.
099         *
100         * @param string the input String.
101         * @param context the JXMPP JID context.
102         * @return the domainprep String.
103         * @throws XmppStringprepException if the input String can not be transformed.
104         */
105        public static String domainprep(String string, JxmppContext context) throws XmppStringprepException {
106                throwIfNullOrEmpty(string, XmppAddressParttype.domainpart);
107                String res;
108                if (context.isCachingEnabled()) {
109                        res = DOMAINPREP_CACHE.lookup(string);
110                        if (res != null) {
111                                return res;
112                        }
113                }
114
115                res = context.xmppStringprep.domainprep(string);
116
117                if (context.isCachingEnabled()) {
118                        DOMAINPREP_CACHE.put(string, res);
119                }
120                return res;
121        }
122
123        /**
124         * Perform resourceprep on the input String.
125         *
126         * @param string the input String.
127         * @return the resourceprep String.
128         * @throws XmppStringprepException if the input String can not be transformed.
129         */
130        public static String resourceprep(String string) throws XmppStringprepException {
131                return resourceprep(string, JxmppContext.getDefaultContext());
132        }
133
134        /**
135         * Perform resourceprep on the input String.
136         *
137         * @param string the input String.
138         * @param context the JXMPP JID context.
139         * @return the resourceprep String.
140         * @throws XmppStringprepException if the input String can not be transformed.
141         */
142        public static String resourceprep(String string, JxmppContext context) throws XmppStringprepException {
143                throwIfNullOrEmpty(string, XmppAddressParttype.resourcepart);
144                String res;
145                if (context.isCachingEnabled()) {
146                        res = RESOURCEPREP_CACHE.lookup(string);
147                        if (res != null) {
148                                return res;
149                        }
150                }
151
152                res = context.xmppStringprep.resourceprep(string);
153
154                if (context.isCachingEnabled()) {
155                        RESOURCEPREP_CACHE.put(string, res);
156                }
157                return res;
158        }
159
160        /**
161         * Set the maximum cache sizes.
162         *
163         * @param size the maximum cache size.
164         */
165        public static void setMaxCacheSizes(int size) {
166                NODEPREP_CACHE.setMaxCacheSize(size);
167                DOMAINPREP_CACHE.setMaxCacheSize(size);
168                RESOURCEPREP_CACHE.setMaxCacheSize(size);
169        }
170
171        /**
172         * Throws a XMPP Stringprep exception if string is the empty string.
173         *
174         * @param string the string to check
175         * @throws XmppStringprepException exception telling that the argument was the empty string
176         */
177        private static void throwIfNullOrEmpty(String string, XmppAddressParttype type) throws XmppStringprepException {
178                if (string == null) {
179                        throw new XmppStringprepException(string, type + " can't be null");
180                }
181                if (string.isEmpty()) {
182                        throw new XmppStringprepException(string, type + " can't be the empty string");
183                }
184        }
185}