001    package org.trails.component;
002    
003    import org.apache.tapestry.IRequestCycle;
004    import org.apache.tapestry.annotations.Parameter;
005    import org.apache.tapestry.form.IPropertySelectionModel;
006    import org.trails.descriptor.annotation.InitialValueDescriptorExtension;
007    import org.trails.descriptor.annotation.PossibleValuesDescriptorExtension;
008    
009    import java.util.ArrayList;
010    import java.util.Collection;
011    import java.util.List;
012    
013    /** imports for javadocs **/
014    import org.trails.descriptor.annotation.InitialValue;
015    import org.trails.descriptor.annotation.PossibleValues;
016    import ognl.OgnlException;
017    
018    /**
019     * Component that renders a select element based on the annotations
020     * {@link InitialValue} and {@link PossibleValues}.
021     * <p/>
022     * If the property has a {@link PossibleValues} annotation, the select will
023     * render its options evaluating the expression passed as the value of the
024     * annotation.<br>
025     * <p/>
026     * If the property has a {@link InitialValue} it will render all
027     * instances of that property type and resubmit the form every time the value
028     * changes, so the related select values can be filtered.<br>
029     *
030     * @author pruggia
031     */
032    public abstract class FilteredAssociationSelect extends AssociationSelect
033    {
034    
035            @Parameter(required = true)
036            public abstract Object getPageModel();
037    
038            /**
039             * Sets the initial value for the property based on the expression declared
040             * in the {@link InitialValue} annotation.
041             *
042             * @param cycle the request cycle, it's never null.
043             */
044            @Override
045            protected void prepareForRender(final IRequestCycle cycle)
046            {
047                    InitialValueDescriptorExtension extension = (InitialValueDescriptorExtension) getPropertyDescriptor()
048                                    .getExtension(InitialValueDescriptorExtension.class.getName());
049                    if (extension != null)
050                    {
051                            if (getValue() == null)
052                            {
053                                    try
054                                    {
055                                            setValue(extension.evaluateExpresion(getPageModel()));
056                                    } catch (OgnlException e)
057                                    {
058                                            // do nothing, don't worry about it
059                                    }
060                            }
061                    }
062                    super.prepareForRender(cycle);
063            }
064    
065            /**
066             * Creates an {@link IPropertySelectionModel} based on properties annotated
067             * with {@link PossibleValues} and {@link InitialValue}.
068             *
069             * @return Returns the selection model, it never returns null.
070             */
071            @Override
072            @SuppressWarnings("unchecked")
073            public IPropertySelectionModel buildSelectionModel()
074            {
075                    PossibleValuesDescriptorExtension extension = (PossibleValuesDescriptorExtension) getPropertyDescriptor()
076                                    .getExtension(PossibleValuesDescriptorExtension.class.getName());
077    
078                    /* instances passed directly from a collection to the component, no need to build a list. */
079                    if (extension != null && getInstances() == null)
080                    {
081                            // If it's filtered by a "PossibleValues" annotation, we need to
082                            // retrieve the list evaluating the ognl expression of the annotation.
083                            Collection<Object> col = null;
084                            List allObjects = null;
085                            try
086                            {
087                                    col = (Collection) extension.evaluateExpresion(getPageModel());
088                            } catch (OgnlException e)
089                            {
090                                    col = new ArrayList();
091                            }
092                            if (col instanceof List)
093                            {
094                                    allObjects = (List) col;
095                            } else
096                            {
097                                    allObjects = new ArrayList();
098                                    allObjects.addAll(col);
099                            }
100    
101                            if (!allObjects.isEmpty())
102                            {
103    
104                                    IdentifierSelectionModel selectionModel = new IdentifierSelectionModel(allObjects,
105                                                    getClassDescriptor().getIdentifierDescriptor().getName(), isAllowNone());
106                                    selectionModel.setNoneLabel(getNoneLabel());
107                                    return selectionModel;
108                            }
109                    }
110    
111                    return super.buildSelectionModel();
112            }
113    
114            /**
115             * If the property is annotated with {@link InitialValue}, this
116             * method generates javascript code to submit the form and update the options
117             * for the filtered property.
118             *
119             * @return a fragment of javascript. It never returns null.
120             */
121            public String getOnChangeJavascript()
122            {
123                    InitialValueDescriptorExtension extension = (InitialValueDescriptorExtension) getPropertyDescriptor()
124                                    .getExtension(InitialValueDescriptorExtension.class.getName());
125                    if (extension != null)
126                    {
127                            return "tapestry.form.refresh('form')";
128                            /*
129                                      return "tapestry.form.registerForm('form');tapestry.form.refresh('form')";
130                                      */
131                    } else
132                    {
133                            return "";
134                    }
135            }
136    }