0001: /*
0002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
0003: *
0004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
0005: *
0006: * The contents of this file are subject to the terms of either the GNU
0007: * General Public License Version 2 only ("GPL") or the Common
0008: * Development and Distribution License("CDDL") (collectively, the
0009: * "License"). You may not use this file except in compliance with the
0010: * License. You can obtain a copy of the License at
0011: * http://www.netbeans.org/cddl-gplv2.html
0012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
0013: * specific language governing permissions and limitations under the
0014: * License. When distributing the software, include this License Header
0015: * Notice in each file and include the License file at
0016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
0017: * particular file as subject to the "Classpath" exception as provided
0018: * by Sun in the GPL Version 2 section of the License file that
0019: * accompanied this code. If applicable, add the following below the
0020: * License Header, with the fields enclosed by brackets [] replaced by
0021: * your own identifying information:
0022: * "Portions Copyrighted [year] [name of copyright owner]"
0023: *
0024: * Contributor(s):
0025: *
0026: * The Original Software is NetBeans. The Initial Developer of the Original
0027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
0028: * Microsystems, Inc. All Rights Reserved.
0029: *
0030: * If you wish your version of this file to be governed by only the CDDL
0031: * or only the GPL Version 2, indicate your decision by adding
0032: * "[Contributor] elects to include this software in this distribution
0033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
0034: * single choice of license, a recipient has the option to distribute
0035: * your version of this file under either the CDDL, the GPL Version 2 or
0036: * to extend the choice of license to its licensees as provided above.
0037: * However, if you add GPL Version 2 code and therefore, elected the GPL
0038: * Version 2 license, then the option applies only if the new code is
0039: * made subject to such option by the copyright holder.
0040: */
0041: package org.netbeans.modules.visualweb.web.ui.dt;
0042:
0043: import com.sun.data.provider.DataProvider;
0044: import com.sun.rave.designtime.DesignContext;
0045: import com.sun.rave.designtime.DisplayAction;
0046: import com.sun.rave.designtime.DesignBean;
0047: import com.sun.rave.designtime.DesignInfo;
0048: import com.sun.rave.designtime.DesignEvent;
0049: import com.sun.rave.designtime.DesignProperty;
0050: import com.sun.rave.designtime.ext.DesignInfoExt;
0051: import com.sun.rave.designtime.faces.ResolveResult;
0052: import com.sun.rave.designtime.markup.MarkupDesignBean;
0053: import com.sun.rave.designtime.Result;
0054: import com.sun.rave.designtime.faces.FacesDesignContext;
0055: import com.sun.data.provider.FieldKey;
0056: import com.sun.rave.designtime.DisplayActionSet;
0057: import com.sun.rave.designtime.faces.FacesDesignProperty;
0058: import java.awt.Image;
0059: import org.netbeans.modules.visualweb.web.ui.dt.component.FormDesignInfo;
0060:
0061: import com.sun.rave.web.ui.component.Alert;
0062: import com.sun.rave.web.ui.component.Form;
0063: import com.sun.rave.web.ui.component.ImageComponent;
0064: import com.sun.rave.web.ui.component.Label;
0065: import com.sun.rave.web.ui.component.ListManager;
0066: import com.sun.rave.web.ui.component.Page;
0067: import com.sun.rave.web.ui.component.ListSelector;
0068: import com.sun.rave.web.ui.component.Selector;
0069: import com.sun.rave.web.ui.component.RbCbSelector;
0070: import com.sun.rave.web.ui.component.StaticText;
0071: import org.netbeans.modules.visualweb.web.ui.dt.component.customizers.AutoSubmitOnChangeAction;
0072: import org.netbeans.modules.visualweb.web.ui.dt.component.customizers.OptionsListCustomizerAction;
0073: import com.sun.rave.web.ui.model.DefaultOptionsList;
0074: import com.sun.rave.web.ui.component.BreadcrumbsBase;
0075: import com.sun.rave.web.ui.component.ButtonBase;
0076: import com.sun.rave.web.ui.component.HyperlinkBase;
0077: import com.sun.rave.web.ui.component.SkipHyperlinkBase;
0078: import com.sun.rave.web.ui.component.DropDown;
0079: import javax.faces.component.html.HtmlCommandLink;
0080: import javax.faces.component.html.HtmlCommandButton;
0081:
0082: import java.beans.BeanDescriptor;
0083: import java.beans.BeanInfo;
0084: import java.beans.IntrospectionException;
0085: import java.beans.Introspector;
0086: import java.beans.PropertyDescriptor;
0087: import java.math.BigDecimal;
0088: import java.sql.Date;
0089: import java.sql.Time;
0090: import java.util.ArrayList;
0091: import java.util.Calendar;
0092:
0093: import java.util.HashMap;
0094: import java.util.List;
0095: import java.util.Map;
0096:
0097: import javax.faces.application.Application;
0098: import javax.faces.component.ActionSource;
0099: import javax.faces.component.EditableValueHolder;
0100: import javax.faces.component.NamingContainer;
0101: import javax.faces.component.UIComponent;
0102: import javax.faces.component.UIViewRoot;
0103: import javax.faces.component.ValueHolder;
0104: import javax.faces.context.FacesContext;
0105: import javax.faces.convert.Converter;
0106: import javax.faces.el.MethodBinding;
0107: import javax.faces.validator.Validator;
0108: import javax.faces.el.ValueBinding;
0109: import org.w3c.dom.Element;
0110:
0111: import java.util.regex.Matcher;
0112: import java.util.regex.Pattern;
0113: import javax.swing.ImageIcon;
0114: import org.netbeans.modules.visualweb.propertyeditors.binding.data.DataBindingHelper;
0115:
0116: /**
0117: * <p>Convenience base class for <code>DesignInfo</code> implementations
0118: * that provide design time behavior for JSF components inside Creator.
0119: * Any <code>DesignInfo</code> implementation that extends this class
0120: * will receive the default behavior described for each method, unless that
0121: * method is overridden.</p>
0122: */
0123: public abstract class AbstractDesignInfo implements DesignInfo,
0124: DesignInfoExt {
0125: public static final String DECORATION_ICON = "/org/netbeans/modules/visualweb/web/ui/dt/resources/Decoration.png";
0126:
0127: // ------------------------------------------------------------- Constructor
0128:
0129: /**
0130: * <p>Construct a <code>DesignInfo</code> instance for the specified
0131: * JavaBean class.</p>
0132: *
0133: * @param clazz Class of the JavaBean for which this instance is created
0134: */
0135: public AbstractDesignInfo(Class clazz) {
0136: this .beanClass = clazz;
0137: }
0138:
0139: // ------------------------------------------------------ Instance Variables
0140:
0141: /**
0142: * <p>The JavaBean class this <code>DesignInfo</code> instance is
0143: * designed to wrap.</p>
0144: */
0145: private Class beanClass = null;
0146:
0147: // ------------------------------------------------------ DesignInfo Methods
0148:
0149: /**
0150: * Returns the class type of the JavaBean that was passed to our constructor.
0151: */
0152: public Class getBeanClass() {
0153: return this .beanClass;
0154: }
0155:
0156: /**
0157: * By default, components are allowed to nest, one with another, unless any
0158: * of the following conditions apply:
0159: * <ul>
0160: * <li>The parent and child component are the same component type.
0161: * <li>The parent component implements {@link javax.faces.component.EditableValueHolder}
0162: * <li>
0163: * </ul>
0164: */
0165: public boolean acceptParent(DesignBean parentBean,
0166: DesignBean childBean, Class childClass) {
0167: if (parentBean == null || parentBean.getInstance() == null)
0168: return false;
0169:
0170: Class parentClass = parentBean.getInstance().getClass();
0171: return acceptFiliation(parentBean, parentClass, childBean,
0172: childClass);
0173: }
0174:
0175: public boolean acceptChild(DesignBean parentBean,
0176: DesignBean childBean, Class childClass) {
0177: if (parentBean == null || parentBean.getInstance() == null)
0178: return false;
0179:
0180: Class parentClass = parentBean.getInstance().getClass();
0181: return acceptFiliation(parentBean, parentClass, childBean,
0182: childClass);
0183: }
0184:
0185: /**
0186: * Returns true is the design bean specified is on a Braveheart page or a
0187: * page fragment.
0188: */
0189: protected static boolean isSunWebUIContext(DesignBean bean) {
0190: DesignBean this Bean = bean;
0191: while (this Bean.getBeanParent() != null) {
0192: if (this Bean.getInstance() instanceof Page)
0193: return true;
0194: else if (this Bean instanceof MarkupDesignBean) {
0195: Element element = ((MarkupDesignBean) this Bean)
0196: .getElement();
0197: if (element.getTagName().compareTo("div") == 0
0198: && this Bean.getBeanParent().getInstance() instanceof UIViewRoot)
0199: return true;
0200: }
0201: this Bean = this Bean.getBeanParent();
0202: }
0203: return false;
0204: }
0205:
0206: private static boolean acceptFiliation(DesignBean parentBean,
0207: Class parentClass, DesignBean childBean, Class childClass) {
0208: if (parentClass.equals(childClass))
0209: return false;
0210: if (!isSunWebUIContext(parentBean))
0211: return false;
0212: if (EditableValueHolder.class.isAssignableFrom(parentClass))
0213: return false;
0214: if (ValueHolder.class.isAssignableFrom(parentClass)) {
0215: if (Label.class.equals(parentClass)
0216: && EditableValueHolder.class
0217: .isAssignableFrom(childClass))
0218: return false;
0219: if (ValueHolder.class.isAssignableFrom(childClass))
0220: return false;
0221: }
0222: if (BreadcrumbsBase.class.isAssignableFrom(parentClass)) {
0223: return false; //StaticText and ImageComponent cannot be children of Breadcrumbs
0224: }
0225: if (ButtonBase.class.isAssignableFrom(parentClass)
0226: || //just defensive, not strictly necessary
0227: HyperlinkBase.class.isAssignableFrom(parentClass)
0228: || SkipHyperlinkBase.class
0229: .isAssignableFrom(parentClass)
0230: || //just defensive, not strictly necessary
0231: HtmlCommandLink.class.isAssignableFrom(parentClass)
0232: || DropDown.class.isAssignableFrom(parentClass) || //just defensive, not strictly necessary
0233: HtmlCommandButton.class.isAssignableFrom(parentClass)) { //just defensive, not strictly necessary
0234: if (!childClass.equals(StaticText.class)
0235: && !childClass.equals(ImageComponent.class))
0236: return false;
0237: }
0238: return true;
0239: }
0240:
0241: /**
0242: * <p>Take no action by default. Return <code>Result.SUCCESS</code>.</p>
0243: *
0244: * @param bean The bean that was just created
0245: */
0246: public Result beanCreatedSetup(DesignBean bean) {
0247: return Result.SUCCESS;
0248: }
0249:
0250: /**
0251: * Find the containing Form component and remove the id of the bean that is
0252: * about to be deleted from the virtual form configuration. Also, if this
0253: * component implements {@link javax.faces.component.ValueHolder}, search
0254: * for any components that reference it (ie. that have a <code>for</code>
0255: * property whose value is this component's instance name), and clear the
0256: * reference.
0257: *
0258: * @param bean The <code>DesignBean</code> that has been renamed.
0259: * @param oldInstanceName The prior instance name of the bean.
0260: */
0261: public Result beanDeletedCleanup(DesignBean bean) {
0262: modifyVirtualFormsOnBeanDeletedCleanup(bean);
0263: if (ValueHolder.class.isAssignableFrom(bean.getInstance()
0264: .getClass())) {
0265: DesignContext context = bean.getDesignContext();
0266: DesignBean[] designBeans = context.getBeans();
0267: String instanceName = bean.getInstanceName();
0268: for (int i = 0; i < designBeans.length; i++) {
0269: DesignProperty property = designBeans[i]
0270: .getProperty("for"); //NOI18N
0271: if (property != null
0272: && instanceName.equals(property.getValue())) {
0273: property.setValue(null);
0274: }
0275: }
0276: }
0277: return Result.SUCCESS;
0278: }
0279:
0280: /** Find the containing form, if it exists. */
0281: /*
0282: * Be sure to keep this method in sync with the version in
0283: * <code>javax.faces.component.html.HtmlDesignInfoBase</code>
0284: * (in jsfcl).</p>
0285: */
0286: private DesignBean findFormBean(DesignBean bean) {
0287: DesignBean formBean = null;
0288: DesignBean testBean = null;
0289: if (bean != null) {
0290: testBean = bean.getBeanParent();
0291: }
0292: while (testBean != null) {
0293: Object testInstance = testBean.getInstance();
0294: if (testInstance instanceof Form) {
0295: formBean = testBean;
0296: break;
0297: }
0298: testBean = testBean.getBeanParent();
0299: }
0300: return formBean;
0301: }
0302:
0303: /*
0304: * Be sure to keep this method in sync with the version in
0305: * <code>javax.faces.component.html.HtmlDesignInfoBase</code>
0306: * (in jsfcl).</p>
0307: */
0308: private void modifyVirtualFormsOnBeanDeletedCleanup(DesignBean bean) {
0309: //find the containing form, if it exists
0310: DesignBean formBean = findFormBean(bean);
0311: //make sure the id for the bean being deleted is removed from the virtualFormsConfig property
0312: if (formBean != null) {
0313: DesignProperty vformsConfigProp = formBean
0314: .getProperty("virtualFormsConfig"); //NOI18N
0315: if (vformsConfigProp != null) {
0316: Object vformsConfigValueObj = vformsConfigProp
0317: .getValue();
0318: if (vformsConfigValueObj instanceof String) {
0319: String vfc = (String) vformsConfigValueObj;
0320: Form.VirtualFormDescriptor[] descriptors = Form
0321: .generateVirtualForms(vfc);
0322: String beanId = FormDesignInfo
0323: .getFullyQualifiedId(bean);
0324: boolean modified = false;
0325: if (beanId != null) {
0326: modified = removeIdFromVirtualFormDescriptors(
0327: descriptors, beanId); //potentially modifies descriptors object
0328: }
0329: if (modified) {
0330: String newVfc = Form
0331: .generateVirtualFormsConfig(descriptors);
0332: vformsConfigProp.setValue(newVfc);
0333: }
0334: }
0335: }
0336: }
0337: }
0338:
0339: /*
0340: * Be sure to keep this method in sync with the version in
0341: * <code>javax.faces.component.html.HtmlDesignInfoBase</code>
0342: * (in jsfcl).</p>
0343: */
0344: private boolean removeIdFromVirtualFormDescriptors(
0345: Form.VirtualFormDescriptor[] descriptors, String idToRemove) {
0346: boolean modified = false;
0347: for (int d = 0; descriptors != null && d < descriptors.length; d++) {
0348: Form.VirtualFormDescriptor vfd = descriptors[d];
0349:
0350: String[] pids = vfd.getParticipatingIds();
0351: String[] newPids = removeIdFromArray(pids, idToRemove);
0352: if (pids != null && newPids != null
0353: && pids.length != newPids.length) {
0354: modified = true;
0355: }
0356: vfd.setParticipatingIds(newPids);
0357:
0358: String[] sids = vfd.getSubmittingIds();
0359: String[] newSids = removeIdFromArray(sids, idToRemove);
0360: if (sids != null && newSids != null
0361: && sids.length != newSids.length) {
0362: modified = true;
0363: }
0364: vfd.setSubmittingIds(newSids);
0365: }
0366: return modified;
0367: }
0368:
0369: /*
0370: * Be sure to keep this method in sync with the version in
0371: * <code>javax.faces.component.html.HtmlDesignInfoBase</code>
0372: * (in jsfcl).</p>
0373: */
0374: private String[] removeIdFromArray(String[] ids, String idToRemove) {
0375: if (ids == null || ids.length == 0) {
0376: return ids;
0377: }
0378: List list = new ArrayList();
0379: for (int i = 0; i < ids.length; i++) {
0380: String id = ids[i]; //might be namespaced
0381: if (id != null
0382: && id.length() > 0
0383: && !Form.fullyQualifiedIdMatchesPattern(idToRemove,
0384: id)) { //id in array does not represent fqId being removed
0385: list.add(id);
0386: }
0387: }
0388: return (String[]) list.toArray(new String[list.size()]);
0389: }
0390:
0391: /**
0392: * <p>Take no action by default. Return <code>Result.SUCCESS</code>.</p>
0393: *
0394: * @param bean The bean that has been pasted
0395: */
0396: public Result beanPastedSetup(DesignBean bean) {
0397: return Result.SUCCESS;
0398: }
0399:
0400: public DisplayActionSet getContextItemsExt(DesignBean bean) {
0401: DesignProperty property = getDefaultBindingProperty(bean);
0402: if (property == null) {
0403: return null;
0404: }
0405: final List displayActions = new ArrayList();
0406: if (EditableValueHolder.class.isAssignableFrom(beanClass))
0407: displayActions.add(new AutoSubmitOnChangeAction(bean));
0408: Class beanClass = bean.getInstance().getClass();
0409: Class bindingPanelClass = null;
0410: if (Selector.class.isAssignableFrom(beanClass)) {
0411: if (RbCbSelector.class.isAssignableFrom(beanClass))
0412: bindingPanelClass = DataBindingHelper.BIND_VALUE_TO_DATAPROVIDER;
0413: else
0414: bindingPanelClass = DataBindingHelper.BIND_OPTIONS_TO_DATAPROVIDER;
0415: } else {
0416: bindingPanelClass = DataBindingHelper.BIND_VALUE_TO_DATAPROVIDER;
0417: }
0418: displayActions.add(DataBindingHelper.getDataBindingAction(bean,
0419: property.getPropertyDescriptor().getName(),
0420: new Class[] { bindingPanelClass,
0421: DataBindingHelper.BIND_VALUE_TO_OBJECT }));
0422: return new DisplayActionSet() {
0423:
0424: public DisplayAction[] getDisplayActions() {
0425: return (DisplayAction[]) displayActions
0426: .toArray(new DisplayAction[displayActions
0427: .size()]);
0428: }
0429:
0430: public boolean isPopup() {
0431: return true;
0432: }
0433:
0434: public boolean isEnabled() {
0435: return true;
0436: }
0437:
0438: public Result invoke() {
0439: throw new UnsupportedOperationException(
0440: "Not supported yet."); //NOI18N
0441: }
0442:
0443: public String getDisplayName() {
0444: return "";
0445: }
0446:
0447: public String getDescription() {
0448: return "";
0449: }
0450:
0451: public Image getLargeIcon() {
0452: return new ImageIcon(getClass().getResource(
0453: DECORATION_ICON)).getImage();
0454: }
0455:
0456: public Image getSmallIcon() {
0457: return new ImageIcon(getClass().getResource(
0458: DECORATION_ICON)).getImage();
0459: }
0460:
0461: public String getHelpKey() {
0462: throw new UnsupportedOperationException(
0463: "Not supported yet."); //NOI18N
0464: }
0465: };
0466: }
0467:
0468: /**
0469: * <p>Return <code>null</code>, indicating that no context menu items
0470: * will be provided.</p>
0471: *
0472: * @param bean The DesignBean that a user has right-clicked on
0473: */
0474: public DisplayAction[] getContextItems(DesignBean bean) {
0475: DesignProperty property = getDefaultBindingProperty(bean);
0476: if (property == null) {
0477: return new DisplayAction[0];
0478: }
0479: ArrayList displayActions = new ArrayList();
0480: if (EditableValueHolder.class.isAssignableFrom(beanClass))
0481: displayActions.add(new AutoSubmitOnChangeAction(bean));
0482: Class beanClass = bean.getInstance().getClass();
0483: Class bindingPanelClass = null;
0484: if (Selector.class.isAssignableFrom(beanClass)) {
0485: if (RbCbSelector.class.isAssignableFrom(beanClass))
0486: bindingPanelClass = DataBindingHelper.BIND_VALUE_TO_DATAPROVIDER;
0487: else
0488: bindingPanelClass = DataBindingHelper.BIND_OPTIONS_TO_DATAPROVIDER;
0489: } else {
0490: bindingPanelClass = DataBindingHelper.BIND_VALUE_TO_DATAPROVIDER;
0491: }
0492: displayActions.add(DataBindingHelper.getDataBindingAction(bean,
0493: property.getPropertyDescriptor().getName(),
0494: new Class[] { bindingPanelClass,
0495: DataBindingHelper.BIND_VALUE_TO_OBJECT }));
0496:
0497: if (Selector.class.isAssignableFrom(beanClass)) {
0498: DesignProperty itemsProperty = bean.getProperty("items");
0499: if (itemsProperty instanceof FacesDesignProperty
0500: && ((FacesDesignProperty) itemsProperty).isBound()) {
0501: String expression = ((FacesDesignProperty) itemsProperty)
0502: .getValueBinding().getExpressionString();
0503: ResolveResult resolveResult = ((FacesDesignContext) bean
0504: .getDesignContext())
0505: .resolveBindingExprToBean(expression);
0506: if (resolveResult != null
0507: && resolveResult.getDesignBean() != null
0508: && resolveResult.getDesignBean().getInstance() instanceof DefaultOptionsList)
0509: displayActions.add(new OptionsListCustomizerAction(
0510: bean));
0511: }
0512: }
0513:
0514: return (DisplayAction[]) displayActions
0515: .toArray(new DisplayAction[displayActions.size()]);
0516: }
0517:
0518: // FIXME - HtmlDesignInfoBase returns true if target is-a ValueHolder
0519: // and source is-a ResultSet
0520: /**
0521: * <p>Return <code>true</code> for the specific cases listed below,
0522: * else return <code>false</code>.</p>
0523: *
0524: * <table border="1">
0525: * <tr>
0526: * <th>Target Bean Class Is-A</th>
0527: * <th>Source Bean Class Is-A</th>
0528: * </tr>
0529: * <tr>
0530: * <td><code>javax.faces.component.EditableValueHolder</code></td>
0531: * <td><code>javax.faces.validator.Validator</code></td>
0532: * </tr>
0533: * <tr>
0534: * <td><code>javax.faces.component.ValueHolder</code></td>
0535: * <td><code>javax.faces.convert.Converter</code></td>
0536: * </tr>
0537: * </table>
0538: *
0539: * @param targetBean The <code>DesignBean</code> instance that the user
0540: * is 'hovering' the mouse over
0541: * @param sourceBean Optional <code>DesignBean</code> instance describing
0542: * a preexisting source bean that is being dragged or linked, or
0543: * <code>null</code> if no such bean exists
0544: * @param sourceClass The class type of the object that the user may
0545: * potentially 'drop' to link
0546: *
0547: * @see #linkBeans
0548: */
0549: public boolean acceptLink(DesignBean targetBean,
0550: DesignBean sourceBean, Class sourceClass) {
0551:
0552: Class targetClass = targetBean.getInstance().getClass();
0553: if (Converter.class.isAssignableFrom(sourceClass)
0554: && ValueHolder.class.isAssignableFrom(targetClass)) {
0555: return true;
0556: } else if (Validator.class.isAssignableFrom(sourceClass)
0557: && EditableValueHolder.class
0558: .isAssignableFrom(targetClass)) {
0559: return true;
0560: } else if (DataProvider.class.isAssignableFrom(sourceClass)) {
0561: if (this .getDefaultBindingProperty(targetBean) != null)
0562: return true;
0563: }
0564: return false;
0565: }
0566:
0567: // FIXME - HtmlDesignInfoBase does ResultSet and RowSetDataModel too
0568: /**
0569: * <p>For the cases where the default <code>acceptLink()</code>
0570: * returns true, attempt to set the appropriate property and return
0571: * a <code>Result</code> reflecting the outcome. Otherwise, just
0572: * return <code>Result.SUCCESS</code>.</p>
0573: *
0574: * @param targetBean The target <code>DesignBean</code> instance that the
0575: * user has 'dropped' an object onto to establish a link
0576: * @param sourceBean The <code>DesignBean</code> instance that has
0577: * been 'dropped'
0578: *
0579: * @see #acceptLink
0580: */
0581: public Result linkBeans(DesignBean targetBean, DesignBean sourceBean) {
0582:
0583: Class sourceClass = sourceBean.getInstance().getClass();
0584: Class targetClass = targetBean.getInstance().getClass();
0585: if (!acceptLink(targetBean, sourceBean, sourceClass))
0586: return Result.FAILURE;
0587:
0588: if (Converter.class.isAssignableFrom(sourceClass)) {
0589: DesignProperty property = targetBean
0590: .getProperty("converter"); //NOI18N
0591: property.setValue(sourceBean.getInstance());
0592: } else if (Validator.class.isAssignableFrom(sourceClass)) {
0593: DesignProperty property = targetBean
0594: .getProperty("validator"); //NOI18N
0595: FacesDesignContext fdc = (FacesDesignContext) targetBean
0596: .getDesignContext();
0597: String validateBinding = fdc.getBindingExpr(sourceBean,
0598: ".validate"); //NOI18N
0599: Application app = fdc.getFacesContext().getApplication();
0600: MethodBinding mb = app.createMethodBinding(validateBinding,
0601: VALIDATE_PARAMS);
0602: property.setValue(mb);
0603: } else if (DataProvider.class.isAssignableFrom(sourceClass)) {
0604: DesignProperty property = getDefaultBindingProperty(targetBean);
0605: if (property != null
0606: && property instanceof FacesDesignProperty) {
0607: if (Selector.class.isAssignableFrom(targetClass)) {
0608: // Listbox, DropDown, CheckboxGroup, RadioButtonGroup, AddRemove
0609: if (RbCbSelector.class
0610: .isAssignableFrom(targetClass))
0611: linkDataProviderToSingleton(
0612: (FacesDesignProperty) property,
0613: sourceBean);
0614: else
0615: linkDataProviderToListSelector(
0616: (FacesDesignProperty) property,
0617: sourceBean);
0618: } else if (ListManager.class
0619: .isAssignableFrom(targetClass)) {
0620: // OrderableList, EditableList
0621: linkDataProviderToStringListSelector(
0622: (FacesDesignProperty) property, sourceBean);
0623: } else {
0624: linkDataProviderToSingleton(
0625: (FacesDesignProperty) property, sourceBean);
0626: }
0627: }
0628: }
0629: return Result.SUCCESS;
0630: }
0631:
0632: /**
0633: * Returns a property descriptor for the property which should be bound to
0634: * a data source by default (e.g. whan a data source is linked to the component).
0635: * If data binding is not appropriate for this component, returns null.
0636: */
0637: protected DesignProperty getDefaultBindingProperty(
0638: DesignBean targetBean) {
0639: Class targetClass = targetBean.getInstance().getClass();
0640: DesignProperty property = null;
0641: if (Alert.class.isAssignableFrom(targetClass)) {
0642: property = targetBean.getProperty("summary"); //NOI18N
0643: } else if (ListSelector.class.isAssignableFrom(targetClass)) {
0644: property = targetBean.getProperty("items"); //NOI18N
0645: } else if (ValueHolder.class.isAssignableFrom(targetClass)) {
0646: property = targetBean.getProperty("text"); //NOI18N
0647: } else if (ActionSource.class.isAssignableFrom(targetClass)) {
0648: property = targetBean.getProperty("text"); //NOI18N
0649: }
0650: if (property == null) {
0651: property = targetBean.getProperty("value"); //NOI18N
0652: }
0653: return property;
0654: }
0655:
0656: public Result linkDataProviderToSingleton(
0657: FacesDesignProperty property, DesignBean dataBean) {
0658: FacesDesignContext fdc = (FacesDesignContext) property
0659: .getDesignBean().getDesignContext();
0660: DataProvider provider = (DataProvider) dataBean.getInstance();
0661: FieldKey[] fieldKeys = provider.getFieldKeys();
0662: if (fieldKeys != null && fieldKeys.length > 0) {
0663: FieldKey fieldKey = null;
0664: Class propertyClass = property.getPropertyDescriptor()
0665: .getPropertyType();
0666: for (int i = 0; i < fieldKeys.length && fieldKey == null; i++) {
0667: if (provider.getType(fieldKeys[i]).isAssignableFrom(
0668: propertyClass))
0669: fieldKey = fieldKeys[i];
0670: }
0671: if (fieldKey == null)
0672: fieldKey = fieldKeys[0];
0673: StringBuffer expr = new StringBuffer();
0674: expr.append("#{");
0675: expr.append(fdc.getReferenceName());
0676: expr.append(".");
0677: expr.append(dataBean.getInstanceName());
0678: expr.append(".value['");
0679: expr.append(fieldKey.getFieldId());
0680: expr.append("']}");
0681: ValueBinding vb = fdc.getFacesContext().getApplication()
0682: .createValueBinding(expr.toString());
0683: property.setValueBinding(vb);
0684: return Result.SUCCESS;
0685: }
0686: return Result.FAILURE;
0687: }
0688:
0689: public Result linkDataProviderToListSelector(
0690: FacesDesignProperty property, DesignBean dataBean) {
0691: FacesDesignContext fdc = (FacesDesignContext) property
0692: .getDesignBean().getDesignContext();
0693: DataProvider provider = (DataProvider) dataBean.getInstance();
0694: FieldKey[] fieldKeys = provider.getFieldKeys();
0695:
0696: if (fieldKeys != null && fieldKeys.length > 0) {
0697: String valueField = null;
0698: String displayField = null;
0699: Class valueFieldType = null;
0700: for (int i = 0; i < fieldKeys.length; i++) {
0701: if ((valueField == null)
0702: && isTypeOf(Integer.class, "int", provider
0703: .getType(fieldKeys[i]))) {
0704: valueField = fieldKeys[i].getFieldId();
0705: valueFieldType = provider.getType(fieldKeys[i]);
0706: }
0707: if ((displayField == null)
0708: && provider.getType(fieldKeys[i])
0709: .isAssignableFrom(String.class)) {
0710: displayField = fieldKeys[i].getFieldId();
0711: }
0712: }
0713: if (valueField == null) {
0714: valueField = fieldKeys[0].getFieldId();
0715: valueFieldType = provider.getType(fieldKeys[0]);
0716: }
0717: if (displayField == null) {
0718: displayField = fieldKeys[0].getFieldId();
0719: }
0720: StringBuffer expr = new StringBuffer();
0721: expr.append("#{");
0722: expr.append(fdc.getReferenceName());
0723: expr.append(".");
0724: expr.append(dataBean.getInstanceName());
0725: expr.append(".options['");
0726: expr.append(valueField);
0727: expr.append(",");
0728: expr.append(displayField);
0729: expr.append("']}");
0730: ValueBinding vb = fdc.getFacesContext().getApplication()
0731: .createValueBinding(expr.toString());
0732: property.setValueBinding(vb);
0733: return Result.SUCCESS;
0734: }
0735: return Result.FAILURE;
0736: }
0737:
0738: public Result linkDataProviderToStringListSelector(
0739: FacesDesignProperty property, DesignBean dataBean) {
0740: FacesDesignContext fdc = (FacesDesignContext) property
0741: .getDesignBean().getDesignContext();
0742: DataProvider provider = (DataProvider) dataBean.getInstance();
0743: FieldKey[] fieldKeys = provider.getFieldKeys();
0744: if (fieldKeys != null && fieldKeys.length > 0) {
0745: FieldKey fieldKey = null;
0746: for (int i = 0; i < fieldKeys.length && fieldKey == null; i++) {
0747: if (provider.getType(fieldKeys[i]).isAssignableFrom(
0748: String.class))
0749: fieldKey = fieldKeys[i];
0750: }
0751: if (fieldKey == null)
0752: fieldKey = fieldKeys[0];
0753: StringBuffer expr = new StringBuffer();
0754: expr.append("#{");
0755: expr.append(fdc.getReferenceName());
0756: expr.append(".");
0757: expr.append(dataBean.getInstanceName());
0758: expr.append(".stringList['");
0759: expr.append(fieldKey.getFieldId());
0760: expr.append("']}");
0761: ValueBinding vb = fdc.getFacesContext().getApplication()
0762: .createValueBinding(expr.toString());
0763: property.setValueBinding(vb);
0764: return Result.SUCCESS;
0765: }
0766: return Result.FAILURE;
0767: }
0768:
0769: public static Class getConverterClass(Class type) {
0770:
0771: if (isTypeOf(Integer.class, "int", type)) {
0772: return javax.faces.convert.IntegerConverter.class;
0773: } else if (isTypeOf(Byte.class, "byte", type)) {
0774: return javax.faces.convert.ByteConverter.class;
0775: } else if (isTypeOf(Long.class, "long", type)) {
0776: return javax.faces.convert.LongConverter.class;
0777: } else if (isTypeOf(Boolean.class, "boolean", type)) {
0778: return javax.faces.convert.BooleanConverter.class;
0779: } else if (isTypeOf(Short.class, "short", type)) {
0780: return javax.faces.convert.ShortConverter.class;
0781: } else if (type.isAssignableFrom(Date.class)) {
0782: return com.sun.rave.faces.converter.SqlDateConverter.class;
0783: } else if (type.isAssignableFrom(Time.class)) {
0784: return com.sun.rave.faces.converter.SqlTimeConverter.class;
0785: } else if (type.isAssignableFrom(BigDecimal.class)) {
0786: return javax.faces.convert.BigDecimalConverter.class;
0787: } else if (isTypeOf(Double.class, "double", type)) {
0788: return javax.faces.convert.DoubleConverter.class;
0789: } else if (isTypeOf(Float.class, "float", type)) {
0790: return javax.faces.convert.FloatConverter.class;
0791: } else if (type.isAssignableFrom(Calendar.class)) {
0792: return com.sun.rave.faces.converter.CalendarConverter.class;
0793: }
0794:
0795: return null;
0796: }
0797:
0798: // ---------------------------------------------- DesignBeanListener Methods
0799:
0800: /**
0801: * <p>Take no action by default.</p>
0802: *
0803: * @param bean The <code>DesignBean</code> whose context has been activated
0804: */
0805: public void beanContextActivated(DesignBean bean) {
0806: ;
0807: }
0808:
0809: /**
0810: * <p>Take no action by default.</p>
0811: *
0812: * @param bean The <code>DesignBean</code> whose context has been deactivated
0813: */
0814: public void beanContextDeactivated(DesignBean bean) {
0815: ;
0816: }
0817:
0818: /**
0819: * If this component implements {@link javax.faces.component.ValueHolder},
0820: * search for any components that reference it (ie. that have a <code>for</code>
0821: * property whose value is this component's instance name), and update the
0822: * reference.
0823: *
0824: * @param bean The <code>DesignBean</code> that has been renamed.
0825: * @param oldInstanceName The prior instance name of the bean.
0826: */
0827: public void instanceNameChanged(DesignBean bean,
0828: String oldInstanceName) {
0829: if (ValueHolder.class.isAssignableFrom(bean.getInstance()
0830: .getClass())) {
0831: DesignContext context = bean.getDesignContext();
0832: DesignBean[] designBeans = context.getBeans();
0833: for (int i = 0; i < designBeans.length; i++) {
0834: DesignProperty property = designBeans[i]
0835: .getProperty("for"); //NOI18N
0836: if (property != null
0837: && oldInstanceName.equals(property.getValue())) {
0838: property.setValue(bean.getInstanceName());
0839: }
0840: }
0841: }
0842: }
0843:
0844: /**
0845: * <p>Take no action by default.</p>
0846: *
0847: * @param bean The <code>DesignBean</code> that has changed.
0848: */
0849: public void beanChanged(DesignBean bean) {
0850: ;
0851: }
0852:
0853: /**
0854: * <p>Take no action by default.</p>
0855: *
0856: * @param event The <code>DesignEvent</code> that has changed.
0857: */
0858: public void eventChanged(DesignEvent event) {
0859: ;
0860: }
0861:
0862: /**
0863: * <p>By default, if the id property changed, modify the virtual forms
0864: * configuration and any autosubmit scripting to reflect the change.</p>
0865: *
0866: * @param property The <code>DesignProperty</code> that has changed.
0867: * @param oldValue Optional oldValue, or <code>null</code> if the
0868: * previous value is not known
0869: */
0870: public void propertyChanged(DesignProperty property, Object oldValue) {
0871: modifyVirtualFormsOnPropertyChanged(property, oldValue);
0872: modifyAutoSubmitOnPropertyChanged(property);
0873: }
0874:
0875: private static Pattern fieldKeysPattern = Pattern
0876: .compile("options\\s*\\[\\s*'\\s*([\\w.]+)\\s*(,\\s*([\\w.]+)\\s*)?'\\s*\\]"); //NOI18N
0877: static final String CONVERTER = "converter"; //NOI18N
0878:
0879: /**
0880: * Create, modify or delete converters as needed
0881: * based on the type of the Field Key bound to the
0882: * property.
0883: */
0884: public void modifyConverter(DesignProperty property) {
0885: // If new value is a value binding to options supplied by a dataprovider,
0886: // create or modify any converters needed
0887: DesignBean designBean = property.getDesignBean();
0888: DesignProperty converterProp = designBean
0889: .getProperty(CONVERTER);
0890: if (converterProp != null) {
0891: FacesDesignContext context = (FacesDesignContext) designBean
0892: .getDesignContext();
0893: if (((FacesDesignProperty) property).isBound()) {
0894: String expression = ((FacesDesignProperty) property)
0895: .getValueBinding().getExpressionString();
0896: ResolveResult resolveResult = context
0897: .resolveBindingExprToBean(expression);
0898: if (resolveResult == null
0899: || resolveResult.getDesignBean() == null
0900: || !DataProvider.class
0901: .isAssignableFrom(resolveResult
0902: .getDesignBean().getInstance()
0903: .getClass()))
0904: return;
0905: DataProvider dataProvider = (DataProvider) resolveResult
0906: .getDesignBean().getInstance();
0907: Matcher matcher = fieldKeysPattern
0908: .matcher(resolveResult.getRemainder());
0909: if (!matcher.matches())
0910: return;
0911: FieldKey valueKey = dataProvider.getFieldKey(matcher
0912: .group(1));
0913: Class converterClass = getConverterClass(dataProvider
0914: .getType(valueKey));
0915:
0916: if (converterProp.isModified()) {
0917: DesignBean oldConverterBean = getConverterBean(designBean);
0918: if (oldConverterBean != null) {
0919: context.deleteBean(oldConverterBean);
0920: }
0921: }
0922: if (converterClass != null) {
0923: DesignBean converterBean = context.createBean(
0924: converterClass.getName(), null, null);
0925: if (converterBean != null) {
0926: converterBean
0927: .setInstanceName(getConverterName(designBean));
0928: converterProp.setValue(converterBean
0929: .getInstance());
0930: }
0931: }
0932: }
0933: }
0934: }
0935:
0936: public void deleteConverter(DesignBean designBean) {
0937: // If bound to a converter, and no other components are bound to it, delete it
0938: DesignBean converter = getConverterBean(designBean);
0939: if (converter != null) {
0940: FacesDesignProperty converterProperty = (FacesDesignProperty) designBean
0941: .getProperty(CONVERTER);
0942: String oldExpression = converterProperty.getValueBinding()
0943: .getExpressionString();
0944: converterProperty.unset();
0945: DesignBean[] beans = designBean.getDesignContext()
0946: .getBeansOfType(EditableValueHolder.class);
0947: int referenceCount = 0;
0948: for (int i = 0; i < beans.length; i++) {
0949: DesignProperty p = beans[i].getProperty(CONVERTER);
0950: if (p != null && p instanceof FacesDesignProperty) {
0951: String expression = ((FacesDesignProperty) p)
0952: .getValueBinding().getExpressionString();
0953: if (oldExpression.equals(expression))
0954: referenceCount++;
0955: }
0956: }
0957: if (referenceCount == 0)
0958: designBean.getDesignContext().deleteBean(converter);
0959: }
0960: }
0961:
0962: /**
0963: * Returns the name of the default options bean.
0964: */
0965: protected static String getConverterName(DesignBean designBean) {
0966: return designBean.getInstanceName() + "Converter"; //NOI18N
0967: }
0968:
0969: /**
0970: * If the selector component for the bean specified is bound to a converter,
0971: * returns the design bean for the converter. Otherwise returns null.
0972: */
0973: protected static DesignBean getConverterBean(DesignBean designBean) {
0974: FacesDesignContext context = (FacesDesignContext) designBean
0975: .getDesignContext();
0976: FacesDesignProperty converterProperty = (FacesDesignProperty) designBean
0977: .getProperty(CONVERTER);
0978: if (converterProperty == null || !converterProperty.isBound())
0979: return null;
0980: String expression = converterProperty.getValueBinding()
0981: .getExpressionString();
0982: return getConverterBean(context, expression);
0983: }
0984:
0985: protected static DesignBean getConverterBean(
0986: FacesDesignContext context, String expression) {
0987: ResolveResult resolveResult = context
0988: .resolveBindingExprToBean(expression);
0989: if (resolveResult == null
0990: || resolveResult.getDesignBean() == null)
0991: return null;
0992: DesignBean converterBean = resolveResult.getDesignBean();
0993: if (Converter.class.isAssignableFrom(converterBean
0994: .getInstance().getClass()))
0995: return converterBean;
0996: return null;
0997: }
0998:
0999: private static boolean isTypeOf(Class ofType, String primitiveType,
1000: Class tobecheckType) {
1001: if (tobecheckType.isAssignableFrom(ofType)
1002: || (tobecheckType.isPrimitive() && tobecheckType
1003: .getName().equals(primitiveType)))
1004: return true;
1005: else
1006: return false;
1007: }
1008:
1009: /*
1010: * Be sure to keep this method in sync with the version in
1011: * <code>javax.faces.component.html.HtmlDesignInfoBase</code>
1012: * (in jsfcl).</p>
1013: */
1014: private void modifyAutoSubmitOnPropertyChanged(
1015: DesignProperty property) {
1016: PropertyDescriptor pd = property.getPropertyDescriptor();
1017: String propertyName = pd.getName();
1018: if ("id".equals(propertyName)) { //NOI18N
1019: DesignBean bean = property.getDesignBean();
1020: if (bean != null
1021: && bean.getInstance() instanceof EditableValueHolder) {
1022: AutoSubmitOnChangeAction autoSubmitAction = new AutoSubmitOnChangeAction(
1023: bean);
1024: if (autoSubmitAction.isAutoSubmit()) {
1025: //toggle twice
1026: autoSubmitAction.toggleAutoSubmit();
1027: autoSubmitAction.toggleAutoSubmit();
1028: }
1029: }
1030: }
1031: }
1032:
1033: /*
1034: * Be sure to keep this method in sync with the version in
1035: * <code>javax.faces.component.html.HtmlDesignInfoBase</code>
1036: * (in jsfcl).</p>
1037: */
1038: private void modifyVirtualFormsOnPropertyChanged(
1039: DesignProperty property, Object oldValue) {
1040: PropertyDescriptor pd = property.getPropertyDescriptor();
1041: String propertyName = pd.getName();
1042: if ("id".equals(propertyName) && oldValue instanceof String) { //NOI18N
1043: //get virtual form descriptors
1044: DesignBean bean = property.getDesignBean();
1045: if (bean != null) {
1046: String fqId = FormDesignInfo.getFullyQualifiedId(bean);
1047: String replacementId = fqId;
1048: if (replacementId == null) {
1049: //try using just straight id
1050: Object replacementIdObj = property.getValue();
1051: if (replacementIdObj instanceof String) {
1052: replacementId = (String) replacementIdObj;
1053: }
1054: } else if (replacementId.startsWith(String
1055: .valueOf(NamingContainer.SEPARATOR_CHAR))
1056: && replacementId.length() > 1) {
1057: //fully qualified replacementId (starting with ":") could look intimidating to users. so just chop off leading ":"
1058: replacementId = replacementId.substring(1,
1059: replacementId.length());
1060: }
1061: if (replacementId != null) {
1062: DesignBean formBean = findFormBean(bean);
1063: if (formBean != null) {
1064: DesignProperty vfcProp = formBean
1065: .getProperty("virtualFormsConfig"); //NOI18N
1066: if (vfcProp != null) {
1067: Object vfcObj = vfcProp.getValue();
1068: if (vfcObj instanceof String) {
1069: String vfc = (String) vfcObj;
1070: Form.VirtualFormDescriptor[] vfds = Form
1071: .generateVirtualForms(vfc);
1072: if (vfds != null && vfds.length > 0) {
1073: //get old fully qualified id
1074: DesignBean parentBean = bean
1075: .getBeanParent();
1076: if (parentBean != null) {
1077: String parentBeanFqId = FormDesignInfo
1078: .getFullyQualifiedId(parentBean);
1079: if (parentBeanFqId != null
1080: && parentBeanFqId
1081: .length() > 0) {
1082: String oldFqId = parentBeanFqId;
1083: String sep = String
1084: .valueOf(NamingContainer.SEPARATOR_CHAR);
1085: if (!sep.equals(oldFqId))
1086: oldFqId += sep;
1087: oldFqId += oldValue;
1088: boolean vfdsModified = false;
1089: for (int v = 0; v < vfds.length; v++) {
1090: String[] participants = vfds[v]
1091: .getParticipatingIds();
1092: String[] submitters = vfds[v]
1093: .getSubmittingIds();
1094: boolean pMod = modifyIdArray(
1095: participants,
1096: oldFqId,
1097: replacementId);
1098: boolean sMod = modifyIdArray(
1099: submitters,
1100: oldFqId,
1101: replacementId);
1102: if (pMod || sMod)
1103: vfdsModified = true;
1104: }
1105: if (vfdsModified) {
1106: String newVfc = Form
1107: .generateVirtualFormsConfig(vfds);
1108: vfcProp
1109: .setValue(newVfc);
1110: }
1111: }
1112: }
1113: }
1114: }
1115: }
1116: }
1117: }
1118: }
1119: }
1120: }
1121:
1122: /*
1123: * Be sure to keep this method in sync with the version in
1124: * <code>javax.faces.component.html.HtmlDesignInfoBase</code>
1125: * (in jsfcl).</p>
1126: */
1127: private boolean modifyIdArray(String[] ids, String oldFqId,
1128: String replacementId) {
1129: if (ids == null || ids.length < 1)
1130: return false;
1131: boolean modified = false;
1132: ;
1133: for (int i = 0; i < ids.length; i++) {
1134: String id = ids[i]; //could be qualified
1135: boolean idRepresentsOldFqId = Form
1136: .fullyQualifiedIdMatchesPattern(oldFqId, id);
1137: if (idRepresentsOldFqId) {
1138: ids[i] = replacementId;
1139: modified = true;
1140: }
1141: }
1142: return modified;
1143: }
1144:
1145: // ------------------------------------------------------- Protected Methods
1146:
1147: // FIXME - deal with component bundle and associated utility class
1148:
1149: /**
1150: * <p>Return the <code>BeanDescriptor</code> for the class this
1151: * <code>DesignInfo</code> is designed to wrap, if possible;
1152: * otherwise, return <code>null</code>.</p>
1153: */
1154: protected BeanDescriptor getBeanDescriptor() {
1155: try {
1156: return getBeanInfo().getBeanDescriptor();
1157: } catch (IntrospectionException e) {
1158: return null;
1159: }
1160: }
1161:
1162: /**
1163: * <p>Return the <code>BeanInfo</code> for the class this
1164: * <code>DesignInfo</code> is designed to wrap.</p>
1165: *
1166: * @exception IntrospectionException if an error occurs during introspection
1167: */
1168: protected BeanInfo getBeanInfo() throws IntrospectionException {
1169: return Introspector.getBeanInfo(getBeanClass());
1170: }
1171:
1172: /**
1173: * <p>Return the <code>PropertyDescriptor</code> for the specified
1174: * property of the class this <code>DesignInfo</code> is designed
1175: * to wrap, if possible and if it exists; otherwise, return
1176: * <code>null</code>.</p>
1177: */
1178: protected PropertyDescriptor getPropertyDescriptor(String name) {
1179: Map map = getPropertyDescriptorMap();
1180: if (map != null) {
1181: return (PropertyDescriptor) map.get(name);
1182: } else {
1183:
1184: return null;
1185: }
1186: }
1187:
1188: /**
1189: * <p>Return an array of <code>PropertyDescriptor</code>s for the class
1190: * this <code>DesignInfo</code> is designed to wrap, if possible;
1191: * otherwise, return <code>null</code>.</p>
1192: */
1193: protected PropertyDescriptor[] getPropertyDescriptors() {
1194: try {
1195: return getBeanInfo().getPropertyDescriptors();
1196: } catch (IntrospectionException e) {
1197: return null;
1198: }
1199: }
1200:
1201: // --------------------------------------------------------- Private Methods
1202:
1203: /**
1204: * <p>Cache key for the property descriptor map, cached in the
1205: * <code>BeanDescriptor</code> on first access.</p>
1206: */
1207: private static final String PROPERTY_DESCRIPTOR_MAP = "com.sun.rave.designtime.PROPERTY_DESCRIPTOR_MAP"; //NOI18N
1208:
1209: /**
1210: * <p>Method signature for a <code>Validator.validate()</code> method.</p>
1211: */
1212: private static final Class[] VALIDATE_PARAMS = {
1213: FacesContext.class, UIComponent.class, Object.class };
1214:
1215: /**
1216: * <p>Return the <code>Map</code> of <code>PropertyDescriptor</code>s for
1217: * the class this <code>DesignInfo</code> is designed to wrap, if
1218: * possible; otherwise, return <code>null</code>.</p>
1219: */
1220: private Map getPropertyDescriptorMap() {
1221: BeanDescriptor bd = getBeanDescriptor();
1222: if (bd == null) {
1223: return null;
1224: }
1225: Map map = (Map) bd.getValue(PROPERTY_DESCRIPTOR_MAP);
1226: if (map == null) {
1227: PropertyDescriptor pd[] = getPropertyDescriptors();
1228: if (pd == null) {
1229: return null;
1230: }
1231: map = new HashMap(pd.length);
1232: for (int i = 0; i < pd.length; i++) {
1233: map.put(pd[i].getName(), pd[i]);
1234: }
1235: bd.setValue(PROPERTY_DESCRIPTOR_MAP, map);
1236: }
1237: return map;
1238: }
1239:
1240: }
|