Java tutorial
/* * 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(); } }