001package co.codewizards.cloudstore.core.objectfactory;
002
003import java.lang.reflect.ParameterizedType;
004import java.lang.reflect.Type;
005
006/**
007 * Abstract base-class for the much easier implementation of a {@link ClassExtension}.
008 * <p>
009 * It is highly recommended <i>not</i> to implement the interface {@code ClassExtension} directly. Instead,
010 * implementors should always extend this abstract base-class.
011 * <p>
012 * In most cases, an implementation of a {@code ClassExtension} looks simply like this example:
013 * <pre>
014 *  public class SsSymlinkClassExtension extends AbstractClassExtension&lt;Symlink, SsSymlink&gt; {
015 *  }
016 * </pre>
017 * <p>
018 * It is recommended to use the naming scheme "${extendingClassName}" + "ClassExtension" as shown in
019 * the example above.
020 *
021 * @author Marco หงุ่ยตระกูล-Schulze - marco at codewizards dot co
022 *
023 * @param <T> the type of the base-class. Automatically assigned to the property {@link #getBaseClass() baseClass}.
024 * @param <E> the type of the extending class. Automatically assigned to the property {@link #getExtendingClass() extendingClass}.
025 */
026public abstract class AbstractClassExtension<T, E extends T> implements ClassExtension<T> {
027
028        private final Class<T> baseClass;
029
030        private final Class<E> extendingClass;
031
032        public AbstractClassExtension() {
033                final ParameterizedType superclass = (ParameterizedType) getClass().getGenericSuperclass();
034                final Type[] actualTypeArguments = superclass.getActualTypeArguments();
035                if (actualTypeArguments == null || actualTypeArguments.length < 2)
036                        throw new IllegalStateException("Subclass " + getClass().getName() + " has no generic type argument!");
037
038                @SuppressWarnings("unchecked")
039                final Class<T> c1 = (Class<T>) actualTypeArguments[0];
040                this.baseClass = c1;
041                if (this.baseClass == null)
042                        throw new IllegalStateException("Subclass " + getClass().getName() + " has no generic type argument!");
043
044                @SuppressWarnings("unchecked")
045                final Class<E> c2 = (Class<E>) actualTypeArguments[1];
046                this.extendingClass = c2;
047                if (this.extendingClass == null)
048                        throw new IllegalStateException("Subclass " + getClass().getName() + " has no generic type argument!");
049        }
050
051        /**
052         * {@inheritDoc}
053         * <p>
054         * The default implementation in {@link AbstractClassExtension} returns 0. Override and return
055         * either a negative value, if you want to provide a fallback-implementation (that is likely to be
056         * replaced by a different {@code ClassExtension}) or a positive value in order to override
057         * another {@code ClassExtension} (make sure your priority is greater than the other extension's priority).
058         */
059        @Override
060        public int getPriority() {
061                return 0;
062        }
063
064        @Override
065        public Class<T> getBaseClass() {
066                return baseClass;
067        }
068
069        @Override
070        public Class<E> getExtendingClass() {
071                return extendingClass;
072        }
073
074}