/* * Beanfabrics Framework Copyright (C) by Michael Karneim, beanfabrics.org * Use is subject to license terms. See license.txt. */ package org.beanfabrics; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.EventListener; import org.beanfabrics.event.ModelProviderEvent; import org.beanfabrics.event.ModelProviderListener; import org.beanfabrics.log.Logger; import org.beanfabrics.log.LoggerFactory; import org.beanfabrics.model.PresentationModel; /** * The Link is a view decorator that helps connecting a {@link View} to a * {@link PresentationModel} provided by a {@link IModelProvider} at a given * {@link Path}. * * @author Michael Karneim */ public class Link implements ModelSubscriber, Serializable { private static final Logger LOG = LoggerFactory.getLogger(Link.class); private final View view; private final ViewClassDecorator viewClassDecorator; private IModelProvider provider; private Path path; private ModelProviderListener providerListener; /** * Creates a Link for the given view. * * @param view */ public Link(View view) { if (view == null) { throw new IllegalArgumentException("view==null"); } this.view = view; this.viewClassDecorator = new ViewClassDecorator(view.getClass()); installProviderListener(); link(); } /** * {@inheritDoc} */ public void setModelProvider(IModelProvider provider) { unlink(); this.provider = provider; link(); } /** * {@inheritDoc} */ public IModelProvider getModelProvider() { return this.provider; } /** * {@inheritDoc} */ public void setPath(Path path) { unlink(); this.path = path; link(); } /** * {@inheritDoc} */ public Path getPath() { return this.path; } /** * Returns the view. * * @return the view */ public View getView() { return this.view; } private void installProviderListener() { providerListener = new MyModelProviderListener(); } private class MyModelProviderListener implements ModelProviderListener, Serializable { public void modelGained(ModelProviderEvent evt) { PathEvaluation eval = new PathEvaluation(provider.getPresentationModel(), path); assert (eval.isCompletelyResolved()); PresentationModel pModel = eval.getResult().getValue(); setPresentationModel(pModel); } public void modelLost(ModelProviderEvent evt) { setPresentationModel(null); } } private void link() { if (provider != null && path != null) { provider.addModelProviderListener(path, providerListener); } } private void unlink() { if (provider != null && path != null) { provider.removeModelProviderListener(path, providerListener); } if (view != null) { view.setPresentationModel(null); } } private void setPresentationModel(PresentationModel model) { if (view != null) { if (accept(model)) { view.setPresentationModel(model); return; } else { if (LOG.isWarnEnabled()) { LOG.warn("Can't set UI model of " + view.getClass().getName() + ". Expected model type is " + getExpectedModelType().getName() + ", but got " + model.getClass().getName() + ". Setting UI model to null."); } view.setPresentationModel(null); } } } private boolean accept(PresentationModel model) { Class expected = getExpectedModelType(); return (expected == null || model == null || expected.isInstance(model)); } private Class getExpectedModelType() { return this.viewClassDecorator.getExpectedModelType(); } // Serialization support. private void writeObject(ObjectOutputStream s) throws IOException { s.defaultWriteObject(); } private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); } }