001/*
002 * Copyright c 2018 Rusi Popov, MDA Tools.net All rights reserved.
003 *
004 * This program and the accompanying materials are made available under the terms of the
005 * Eclipse Public License v2.0 which accompanies this distribution, and is available at
006 * http://www.eclipse.org/legal/epl-v20.html
007 */
008package net.mdatools.modelant.core.wrap;
009
010import java.io.Serializable;
011import java.util.Collection;
012import java.util.List;
013
014import net.mdatools.modelant.core.api.wrap.Wrapper;
015import net.mdatools.modelant.core.api.wrap.WrapperFactory;
016
017
018/**
019 * <b>This class is the root class for all wrapper classes.</b><br>
020 * INVARIANT:<ul>
021 * <li> the wrapped object is never null
022 * <li> the factory object is never null
023 * <li> the factory is exactly one that created this object
024 * </ul>
025 * Additional methods (not related actually to the wrapping function of this class) are added to ease the
026 * use of this class for code generation.
027 * @author Rusi Popov (popovr@mdatools.net)
028 */
029public abstract class BaseWrapper<A> implements Serializable, Wrapper<A> {
030
031  /**
032   * The object this wrapper class wraps to allow its rendering. The reflective
033   * interface of the model element is used in oder to make this class
034   * independent of the actual model and interface.
035   */
036  private final A wrapped;
037
038  /**
039   * This is the factory the subclasses must use to build wrappers of
040   * the model objects reachable through the current wrapped model object.
041   * It makes sure the proper class is instantiated reflecting the actual
042   * interface of the model object.
043   */
044  private final WrapperFactory factory;
045
046  /**
047   * @param wrapped is non-null object to wrap
048   * @param factory is the non-null factory that created this
049   */
050  protected BaseWrapper(A wrapped, WrapperFactory factory) {
051
052    assert wrapped != null : "Expected a non-null wrapped object";
053    assert factory != null : "Expected a non-null factory";
054
055    this.wrapped = wrapped;
056    this.factory = factory;
057  }
058
059
060  /**
061   * CONVENTION:<ul>
062   * <li> when the wrapper is used to create a new wrapped object, it might happen that this method needs public access.
063   * <li> when wrapping a wrapper, this method is overridden, this way granting the outer-most wrapper
064   *      access to the nested-most wrapped object (bypassing the wrappers)
065   * </ul>
066   * @return the deepest wrapped object
067   */
068  public final A getWrapped() {
069    return wrapped;
070  }
071
072  /**
073   * The factory for this instance
074   * @return the wrapper factory this was constructed with
075   */
076  protected final WrapperFactory getFactory() {
077    return factory;
078  }
079
080  /**
081   * Call this method in subclasses in order to instantiate the wrapper class
082   * that actually corresponds to the class of the object toWrap
083   * @param toWrap is the object to wrap in another wrapper class. Might be null;
084   * @return null, when null provided, otherwise a properly initialized
085   *         wrapper class that wraps toWrap
086   * @throws IllegalArgumentException when mapping is not possible
087   * @see Wrapper#wrap(Object)
088   */
089  public final Wrapper<A> wrap(A toWrap) throws IllegalArgumentException {
090    return factory.wrap( toWrap );
091  }
092
093  /**
094   * Call this method in subclasses in order to instantiate the wrapper class
095   * that actually corresponds to the class of the object toWrap
096   * @param toWrap is the object to wrap in another wrapper class. Might be null;
097   * @return null, when null provided, otherwise a properly initialized
098   *         collection of wrappers that wrap the elements of toWrap
099   * @throws IllegalArgumentException when mapping is not possible
100   * @see Wrapper#wrap(Collection)
101   */
102  public final List<Wrapper<A>> wrap(Collection<A> toWrap) throws IllegalArgumentException {
103    return factory.wrap( toWrap );
104  }
105}