001// Licensed under the Apache License, Version 2.0 (the "License");
002// you may not use this file except in compliance with the License.
003// You may obtain a copy of the License at
004//
005//     http://www.apache.org/licenses/LICENSE-2.0
006//
007// Unless required by applicable law or agreed to in writing, software
008// distributed under the License is distributed on an "AS IS" BASIS,
009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
010// See the License for the specific language governing permissions and
011// limitations under the License.
012
013package org.apache.tapestry5.beaneditor;
014
015import org.apache.tapestry5.PropertyConduit;
016
017import java.util.List;
018
019/**
020 * Provides the information necessary to build a user interface to view, create or edit an instance of a particular
021 * type.
022 *
023 * BeanModels are not thread-safe, they are also not serializable.
024 *
025 * Here, and in {@link org.apache.tapestry5.beaneditor.PropertyModel}, the term "propertyName" is used for simplicitly.
026 * However, a full {@linkplain org.apache.tapestry5.services.PropertyConduitSource#create(Class, String) property
027 * expression} may be utilized when {@linkplain #add(String) adding new properties to an existing BeanModel}.
028 *
029 * @see org.apache.tapestry5.services.BeanModelSource
030 */
031public interface BeanModel<T>
032{
033    /**
034     * Returns the type of bean for which this model was initially created.
035     */
036    Class<T> getBeanType();
037
038
039    /**
040     * Creates a new bean instance.  This is based on {@link org.apache.tapestry5.ioc.ObjectLocator#autobuild(Class)},
041     * so a public constructor will be used, and dependencies injected.
042     *
043     * @return new instance of the bean
044     */
045    T newInstance();
046
047    /**
048     * Returns a list of the editable properties of the bean, in <em>presentation</em> order.
049     */
050    List<String> getPropertyNames();
051
052    /**
053     * Returns the named model.
054     *
055     * @param propertyName name of property to retrieve model for (case is ignored)
056     * @return the model for the property
057     * @throws RuntimeException if the bean editor model does not have a property model for the provided name
058     */
059    PropertyModel get(String propertyName);
060
061    /**
062     * Returns the identified model.  Property ids are a stripped version of the property name. Case is ignored.
063     *
064     * @param propertyId matched caselessly against {@link org.apache.tapestry5.beaneditor.PropertyModel#getId()}
065     * @throws RuntimeException if the bean editor model does not have a property model with the indicated id
066     */
067    PropertyModel getById(String propertyId);
068
069    /**
070     * Adds a new property to the model, returning its mutable model for further refinement. The property is added to
071     * the <em>end</em> of the list of properties. The property must be real (but may have been excluded if there was no
072     * {@linkplain org.apache.tapestry5.beaneditor.DataType datatype} associated with the property). To add a synthetic
073     * property, use {@link #add(String, org.apache.tapestry5.PropertyConduit)}
074     *
075     * @param propertyName name of property to add
076     * @return the new property model (for further configuration)
077     * @throws RuntimeException if the property already exists
078     */
079    PropertyModel add(String propertyName);
080
081
082    /**
083     * Adds a new synthetic property to the model, returning its mutable model for further refinement. The property is added to
084     * the <em>end</em> of the list of properties.
085     *
086     * @param propertyName name of property to add
087     * @param expression   expression for the property
088     * @return the new property model (for further configuration)
089     * @throws RuntimeException if the property already exists
090     * @since 5.3
091     */
092    PropertyModel addExpression(String propertyName, String expression);
093
094    /**
095     * Adds an empty property (one with no property conduit).
096     *
097     * @param propertyName name of property to add
098     * @return the new property model (for further configuration)
099     * @throws RuntimeException if the property already exists
100     * @since 5.3
101     */
102    PropertyModel addEmpty(String propertyName);
103
104    /**
105     * Adds a new property to the model (as with {@link #add(String)}), ordered before or after an existing property.
106     *
107     * @param position             controls whether the new property is ordered before or after the existing property
108     * @param existingPropertyName the name of an existing property (this must exist)
109     * @param propertyName         the new property to add
110     * @return the new property model (for further configuration)
111     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
112     */
113    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName);
114
115    /**
116     * Adds a new property to the model, ordered before or after an existing property.
117     *
118     * @param position             controls whether the new property is ordered before or after the existing property
119     * @param existingPropertyName the name of an existing property (this must exist)
120     * @param propertyName         the new property to add
121     * @param conduit              conduit used to read or update the property; this may be null for a synthetic or
122     *                             placeholder property
123     * @return the new property model (for further configuration)
124     * @throws RuntimeException if the existing property does not exist, or if the new property already does exist
125     */
126    PropertyModel add(RelativePosition position, String existingPropertyName, String propertyName,
127                      PropertyConduit conduit);
128
129    /**
130     * Adds a new, synthetic property to the model, returning its mutable model for further refinement.
131     *
132     * @param propertyName name of property to add
133     * @param conduit      the conduit used to read or update the property; this may be null for a synthetic or
134     *                     placeholder property.  Instead of passing null, please invoke {@link #addEmpty(String)}.
135     * @return the model for the property
136     * @throws RuntimeException if the property already exists
137     * @see #addExpression(String, String)
138     */
139    PropertyModel add(String propertyName, PropertyConduit conduit);
140
141    /**
142     * Removes the named properties from the model, if present. It is not considered an error to remove a property that
143     * does not exist.
144     *
145     * @param propertyNames the names of properties to be removed (case insensitive)
146     * @return the model for further modifications
147     */
148    BeanModel<T> exclude(String... propertyNames);
149
150    /**
151     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
152     * retained, but ordered to the end of the list.
153     *
154     * @param propertyNames property names in order they should be displayed (case insensitive)
155     * @return the model for further modifications
156     */
157    BeanModel<T> reorder(String... propertyNames);
158
159    /**
160     * Re-orders the properties of the model into the specified order. Existing properties that are not indicated are
161     * removed.
162     *
163     * @param propertyNames the names of properties to be retained
164     * @return the model for further modifications
165     */
166    BeanModel<T> include(String... propertyNames);
167}