001/**
002 *
003 * Copyright 2019-2021 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.jivesoftware.smack.provider;
018
019import java.io.IOException;
020import java.lang.reflect.ParameterizedType;
021import java.lang.reflect.Type;
022import java.lang.reflect.TypeVariable;
023import java.text.ParseException;
024
025import org.jivesoftware.smack.packet.Element;
026import org.jivesoftware.smack.parsing.SmackParsingException;
027import org.jivesoftware.smack.xml.XmlPullParserException;
028
029public class AbstractProvider<E extends Element> {
030
031    private final Class<E> elementClass;
032
033    @SuppressWarnings("unchecked")
034    protected AbstractProvider() {
035        Type currentType = getClass().getGenericSuperclass();
036        while (!(currentType instanceof ParameterizedType)) {
037            Class<?> currentClass = (Class<?>) currentType;
038            currentType = currentClass.getGenericSuperclass();
039        }
040        ParameterizedType parameterizedGenericSuperclass = (ParameterizedType) currentType;
041        Type[] actualTypeArguments = parameterizedGenericSuperclass.getActualTypeArguments();
042        Type elementType = actualTypeArguments[0];
043
044
045        if (elementType instanceof Class) {
046            elementClass = (Class<E>) elementType;
047        } else if (elementType instanceof ParameterizedType) {
048            ParameterizedType parameteriezedElementType = (ParameterizedType) elementType;
049            elementClass = (Class<E>) parameteriezedElementType.getRawType();
050        } else if (elementType instanceof TypeVariable) {
051            TypeVariable<?> typeVariableElementType = (TypeVariable<?>) elementType;
052            elementClass = (Class<E>) typeVariableElementType.getClass();
053        } else {
054            throw new AssertionError("Element type '" + elementType + "' (" + elementType.getClass()
055                            + ") is neither of type Class, ParameterizedType or TypeVariable");
056        }
057    }
058
059    public final Class<E> getElementClass() {
060        return elementClass;
061    }
062
063    public static final class TextParseException extends SmackParsingException {
064        /**
065         *
066         */
067        private static final long serialVersionUID = 1L;
068
069        private final ParseException parseException;
070
071        private TextParseException(ParseException parseException) {
072            super(parseException);
073            this.parseException = parseException;
074        }
075
076        public ParseException getParseException() {
077            return parseException;
078        }
079    }
080
081    public static final class NumberFormatParseException extends SmackParsingException {
082        /**
083         *
084         */
085        private static final long serialVersionUID = 1L;
086
087        private NumberFormatParseException(NumberFormatException numberFormatException) {
088            super(numberFormatException);
089        }
090    }
091
092    protected interface WrappableParser<E> {
093        E parse() throws XmlPullParserException, IOException, SmackParsingException, ParseException;
094    }
095
096    protected static <E> E wrapExceptions(WrappableParser<E> parser)
097                    throws XmlPullParserException, IOException, SmackParsingException {
098        E e;
099        try {
100            e = parser.parse();
101        } catch (ParseException parseException) {
102            throw new TextParseException(parseException);
103        } catch (NumberFormatException numberFormatException) {
104            throw new NumberFormatParseException(numberFormatException);
105        }
106
107        return e;
108    }
109}