001/**
002 *
003 * Copyright © 2014-2016 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.stringprep.simple.SimpleXmppStringprep;
020import org.jxmpp.util.cache.Cache;
021import org.jxmpp.util.cache.LruCache;
022
023public class XmppStringPrepUtil {
024
025        static {
026                // Ensure that there is always at least the simple XMPP stringprep implementation active
027                SimpleXmppStringprep.setup();
028        }
029
030        private static final Cache<String, String> NODEPREP_CACHE = new LruCache<String, String>(100);
031        private static final Cache<String, String> DOMAINPREP_CACHE = new LruCache<String, String>(100);
032        private static final Cache<String, String> RESOURCEPREP_CACHE = new LruCache<String, String>(100);
033
034        private static XmppStringprep xmppStringprep;
035
036        /**
037         * Set the XMPP Stringprep implementation to use.
038         *
039         * @param xmppStringprep the XMPP Stringprep implementation to use.
040         */
041        public static void setXmppStringprep(XmppStringprep xmppStringprep) {
042                XmppStringPrepUtil.xmppStringprep = xmppStringprep;
043        }
044
045        /**
046         * Perform localprep on the input String.
047         *
048         * @param string the input String.
049         * @return the localpreped String.
050         * @throws XmppStringprepException if the input String can not be transformed.
051         */
052        public static String localprep(String string) throws XmppStringprepException {
053                if (xmppStringprep == null) {
054                        return string;
055                }
056                // Avoid cache lookup if string is the empty string
057                throwIfEmptyString(string);
058                String res = NODEPREP_CACHE.lookup(string);
059                if (res != null) {
060                        return res;
061                }
062                res = xmppStringprep.localprep(string);
063                NODEPREP_CACHE.put(string, res);
064                return res;
065        }
066
067        /**
068         * Perform domainprep on the input String.
069         *
070         * @param string the input String.
071         * @return the domainprep String.
072         * @throws XmppStringprepException if the input String can not be transformed.
073         */
074        public static String domainprep(String string) throws XmppStringprepException {
075                if (xmppStringprep == null) {
076                        return string;
077                }
078                // Avoid cache lookup if string is the empty string
079                throwIfEmptyString(string);
080                String res = DOMAINPREP_CACHE.lookup(string);
081                if (res != null) {
082                        return res;
083                }
084                res = xmppStringprep.domainprep(string);
085                DOMAINPREP_CACHE.put(string, res);
086                return res;
087        }
088
089        /**
090         * Perform resourceprep on the input String.
091         *
092         * @param string the input String.
093         * @return the resourceprep String.
094         * @throws XmppStringprepException if the input String can not be transformed.
095         */
096        public static String resourceprep(String string) throws XmppStringprepException {
097                if (xmppStringprep == null) {
098                        return string;
099                }
100                // Avoid cache lookup if string is the empty string
101                throwIfEmptyString(string);
102                String res = RESOURCEPREP_CACHE.lookup(string);
103                if (res != null) {
104                        return res;
105                }
106                res = xmppStringprep.resourceprep(string);
107                RESOURCEPREP_CACHE.put(string, res);
108                return res;
109        }
110
111        /**
112         * Set the maximum cache sizes.
113         *
114         * @param size the maximum cache size.
115         */
116        public static void setMaxCacheSizes(int size) {
117                NODEPREP_CACHE.setMaxCacheSize(size);
118                DOMAINPREP_CACHE.setMaxCacheSize(size);
119                RESOURCEPREP_CACHE.setMaxCacheSize(size);
120        }
121
122        /**
123         * Throws a XMPP Stringprep exception if string is the empty string.
124         *
125         * @param string
126         * @throws XmppStringprepException
127         */
128        private static void throwIfEmptyString(String string) throws XmppStringprepException {
129                // TODO replace with string.isEmpty() once Smack's min Android SDK level is > 8
130                if (string.length() == 0) {
131                        throw new XmppStringprepException(string, "Argument can't be the empty string");
132                }
133        }
134}