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.parts;
018
019import java.io.Serializable;
020import java.nio.charset.StandardCharsets;
021
022import org.jxmpp.stringprep.XmppStringprepException;
023
024public abstract class Part implements CharSequence, Serializable {
025
026        /**
027         *
028         */
029        private static final long serialVersionUID = 1L;
030
031        private final String part;
032
033        protected Part(String part) {
034                this.part = part;
035        }
036
037        @Override
038        public final int length() {
039                return part.length();
040        }
041
042        @Override
043        public final char charAt(int index) {
044                return part.charAt(index);
045        }
046
047        @Override
048        public final CharSequence subSequence(int start, int end) {
049                return part.subSequence(start, end);
050        }
051
052        @Override
053        public final String toString() {
054                return part;
055        }
056
057        @Override
058        public final boolean equals(Object other) {
059                if (this == other) {
060                        return true;
061                }
062                if (other == null) {
063                        return false;
064                }
065                return part.equals(other.toString());
066        }
067
068        @Override
069        public final int hashCode() {
070                return part.hashCode();
071        }
072
073        protected static void assertNotLongerThan1023BytesOrEmpty(String string) throws XmppStringprepException {
074                byte[] bytes = string.getBytes(StandardCharsets.UTF_8);
075
076                // Better throw XmppStringprepException instead of IllegalArgumentException here, because users don't expect an
077                // IAE and it also makes the error handling for users easier.
078                if (bytes.length > 1023) {
079                        throw new XmppStringprepException(string, "Given string is longer then 1023 bytes");
080                } else if (bytes.length == 0) {
081                        throw new XmppStringprepException(string, "Argument can't be the empty string");
082                }
083        }
084
085        /**
086         * The cache holding the internalized value of this part. This needs to be transient so that the
087         * cache is recreated once the data was de-serialized.
088         */
089        private transient String internalizedCache;
090
091        /**
092         * Returns the canonical String representation of this Part. See {@link String#intern} for details.
093         * 
094         * @return the canonical String representation.
095         */
096        public final String intern() {
097                if (internalizedCache == null) {
098                        internalizedCache = toString().intern();
099                }
100                return internalizedCache;
101        }
102}