com.github.peholmst.mvp4vaadin.AbstractViewComponent.java Source code

Java tutorial

Introduction

Here is the source code for com.github.peholmst.mvp4vaadin.AbstractViewComponent.java

Source

/*
 * Copyright (c) 2011 Petter Holmstrm
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.peholmst.mvp4vaadin;

import java.lang.reflect.Constructor;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

import javax.annotation.PostConstruct;

import com.github.peholmst.mvp4vaadin.events.DescriptionChangedViewEvent;
import com.github.peholmst.mvp4vaadin.events.DisplayNameChangedViewEvent;
import com.github.peholmst.stuff4vaadin.adapter.AdaptableSupport;
import com.github.peholmst.stuff4vaadin.adapter.UnsupportedAdapterException;
import com.vaadin.ui.Component;
import com.vaadin.ui.ComponentContainer;
import com.vaadin.ui.CustomComponent;

/**
 * This is a sibling to {@link AbstractView} and is intended for view
 * implementations that are themselves Vaadin components. It has been designed
 * to be used together with concrete {@link Presenter} implementations. It
 * delegates all {@link View}-methods to a {@link ViewDelegate}.
 * 
 * @see AbstractI18NViewComponent
 * 
 * @author Petter Holmstrm
 * @since 1.0
 * 
 * @param <V>
 *            the type of the View.
 * @param <P>
 *            the type of the Presenter.
 */
public abstract class AbstractViewComponent<V extends View, P extends Presenter<V>> extends CustomComponent
        implements ViewDelegateOwner<V, P>, VaadinView {

    private static final long serialVersionUID = 8990003143642848504L;

    private final ViewDelegate<V, P> viewDelegate = new ViewDelegate<V, P>(this);

    private final Class<P> presenterClass;

    private final Class<V> viewClass;

    /**
     * Creates a new <code>AbstractViewComponent</code>. The presenter- and view
     * classes are determined by introspection and will be used to create the
     * presenter.
     * 
     * @see #createPresenter()
     */
    @SuppressWarnings("unchecked")
    public AbstractViewComponent() {
        Type[] actualTypeArguments = ((ParameterizedType) getClass().getGenericSuperclass())
                .getActualTypeArguments();
        this.viewClass = (Class<V>) actualTypeArguments[0];
        this.presenterClass = (Class<P>) actualTypeArguments[1];
        setCompositionRoot(createCompositionRoot());
    }

    /**
     * Creates a new <code>AbstractViewComponent</code>. The presenter- and view
     * classes will be used to create the presenter. If any of them are
     * <code>null</code>, the presenter must be specified by either overriding
     * {@link #createPresenter()} or calling {@link #setPresenter(Presenter)}
     * before the view is initialized.
     * 
     * @see #createPresenter()
     */
    public AbstractViewComponent(Class<P> presenterClass, Class<V> viewClass) {
        this.presenterClass = presenterClass;
        this.viewClass = viewClass;
        setCompositionRoot(createCompositionRoot());
    }

    /**
     * Creates the composition root that will be passed to
     * {@link #setCompositionRoot(Component)} upon component creation.
     */
    protected abstract Component createCompositionRoot();

    /**
     * {@inheritDoc}
     * <p>
     * If this view component has knowledge of the presenter class and view
     * class, this implementation will try to create a new instance using the
     * {@link Presenter#Presenter(View)} constructor or the
     * {@link Presenter#Presenter()} constructor. In all other cases an
     * exception will be thrown. Subclasses may override.
     */
    @Override
    public P createPresenter() {
        if (presenterClass == null) {
            throw new IllegalStateException("No presenterClass set - override createPresenter()");
        }
        if (viewClass == null) {
            throw new IllegalStateException("No viewClass set - override createPresenter()");
        }
        try {
            try {
                Constructor<P> constructor = presenterClass.getConstructor(viewClass);
                return constructor.newInstance(viewClass.cast(this));
            } catch (NoSuchMethodException e) {
                // Try the default constructor instead.
                Constructor<P> constructor = presenterClass.getConstructor();
                P presenter = constructor.newInstance();
                presenter.setView(viewClass.cast(this));
                return presenter;
            }
        } catch (Exception e) {
            throw new UnsupportedOperationException(
                    "Cannot create a new presenter instance - override createPresenter()", e);
        }
    }

    @Override
    public String getDisplayName() {
        return viewDelegate.getDisplayName();
    }

    /**
     * Sets the display name of this view and fires a
     * {@link DisplayNameChangedViewEvent}.
     */
    protected void setDisplayName(String displayName) {
        viewDelegate.setDisplayName(displayName);
    }

    @Override
    public String getViewDescription() {
        return viewDelegate.getViewDescription();
    }

    /**
     * Sets the description of this view and fires a
     * {@link DescriptionChangedViewEvent}.
     */
    protected void setViewDescription(String description) {
        viewDelegate.setViewDescription(description);
    }

    /**
     * {@inheritDoc}
     * <p>
     * Please note that this method has been annotated with the
     * {@link PostConstruct @PostConstruct} annotation. If the view is created
     * using a container such as Spring or CDI, this method will be
     * automatically invoked after the view has been created and all the
     * dependencies have been injected.
     * <p>
     * Subclasses should preferably override {@link #initView()} or
     * {@link #finalizeInitialization()} instead of this method.
     */
    @Override
    @PostConstruct
    public void init() {
        viewDelegate.init();
    }

    /**
     * {@inheritDoc}
     * <p>
     * This implementation is empty, subclasses may override.
     */
    @Override
    public void initView() {
    }

    /**
     * {@inheritDoc}
     * <p>
     * This implementation is empty, subclasses may override.
     */
    @Override
    public void finalizeInitialization() {
    }

    @Override
    public boolean isInitialized() {
        return viewDelegate.isInitialized();
    }

    @Override
    public void addListener(ViewListener listener) {
        viewDelegate.addListener(listener);
    }

    @Override
    public void removeListener(ViewListener listener) {
        viewDelegate.removeListener(listener);
    }

    @Override
    public void fireViewEvent(ViewEvent event) {
        viewDelegate.fireViewEvent(event);
    }

    /**
     * {@inheritDoc}
     * <p>
     * This implementation returns the view component itself (<code>this</code>
     * ).
     */
    @Override
    public ComponentContainer getViewComponent() {
        return this;
    }

    /**
     * Returns the presenter of this view, or <code>null</code> if none has been
     * specified or created yet.
     */
    public P getPresenter() {
        return viewDelegate.getPresenter();
    }

    /**
     * Sets the presenter of this view. If the view is already initialized, an
     * exception will be thrown.
     */
    public void setPresenter(P presenter) {
        viewDelegate.setPresenter(presenter);
    }

    @Override
    public boolean supportsAdapter(Class<?> adapterClass) {
        return viewDelegate.supportsAdapter(adapterClass);
    }

    @Override
    public <T> T adapt(Class<T> adapterClass) throws UnsupportedAdapterException {
        return viewDelegate.adapt(adapterClass);
    }

    /**
     * Returns the <code>AdaptableSupport</code> instance used by the view.
     */
    protected AdaptableSupport getAdaptableSupport() {
        return viewDelegate.getAdaptableSupport();
    }

}