001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.propertyeditors;
042:
043: import com.sun.faces.util.ConstantMethodBinding;
044: import com.sun.rave.designtime.ContextMethod;
045: import com.sun.rave.designtime.DesignBean;
046: import com.sun.rave.designtime.DesignContext;
047: import com.sun.rave.designtime.DesignProperty;
048: import com.sun.rave.designtime.faces.FacesDesignContext;
049: import com.sun.rave.designtime.faces.FacesDesignProject;
050: import com.sun.rave.designtime.faces.ResolveResult;
051: import org.netbeans.modules.visualweb.propertyeditors.util.Bundle;
052: import java.awt.Component;
053: import java.lang.reflect.Method;
054: import javax.el.MethodExpression;
055: import javax.faces.application.Application;
056: import javax.faces.context.FacesContext;
057: import javax.faces.el.MethodBinding;
058: import javax.faces.el.ReferenceSyntaxException;
059:
060: /**
061: * An editor for properties on JSF components that take a binding to a method. The
062: * property type must be {@link javax.faces.el.MethodBinding}. Note: this editor was
063: * brought over, modus modendum, from the deprecated jsfcl module.
064: *
065: * @author eric
066: */
067:
068: public class MethodBindingPropertyEditor extends PropertyEditorBase
069: implements
070: com.sun.rave.propertyeditors.MethodBindingPropertyEditor {
071:
072: private static final Bundle bundle = Bundle
073: .getBundle(MethodBindingPropertyEditor.class);
074:
075: public void setAsText(String text) throws IllegalArgumentException {
076: setValue(getAsMethodBinding(text));
077: }
078:
079: public String getAsText() {
080: Object value = getValue();
081: if (value instanceof MethodBinding) {
082: if (value instanceof ConstantMethodBinding) {
083: return (String) ((MethodBinding) value).invoke(null,
084: null); // Hack to get the constant value
085: } else {
086: return ((MethodBinding) value).getExpressionString();
087: }
088: } else if (value instanceof MethodExpression) {
089: return ((MethodExpression) value).getExpressionString();
090: }
091: return (value == null) ? "" : value.toString(); //NOI18N
092: }
093:
094: public String getJavaInitializationString() {
095: return "\"" + getAsText() + "\""; //NOI18N
096: }
097:
098: /**
099: * Attempts to convert the expression specified into a method binding or method
100: * expression.
101: */
102: Object getAsMethodBinding(String string)
103: throws IllegalArgumentException {
104: if (string == null)
105: return null;
106: string = string.trim();
107: if (string.startsWith("#{") && string.endsWith("}")) { //NOI18N
108: String expr = string.substring(2, string.length() - 1);
109: FacesDesignProject facesDesignProject = (FacesDesignProject) designProperty
110: .getDesignBean().getDesignContext().getProject();
111: ClassLoader oldContextClassLoader = Thread.currentThread()
112: .getContextClassLoader();
113: try {
114: DesignProperty designProperty = this
115: .getDesignProperty();
116: FacesDesignContext pcontext = (FacesDesignContext) designProperty
117: .getDesignBean().getDesignContext();
118: Application application = pcontext.getFacesContext()
119: .getApplication();
120: Class propertyType = designProperty
121: .getPropertyDescriptor().getPropertyType();
122: if (MethodExpression.class
123: .isAssignableFrom(propertyType)
124: || MethodBinding.class
125: .isAssignableFrom(propertyType)) {
126: DesignContext[] contextsTmp = facesDesignProject
127: .findDesignContexts(new String[] {
128: "session", "application" });
129: FacesDesignContext[] contexts = new FacesDesignContext[contextsTmp.length + 1];
130: System.arraycopy(contextsTmp, 0, contexts, 1,
131: contextsTmp.length);
132: contexts[0] = pcontext;
133: int firstDotIndex = expr.indexOf('.');
134: boolean twoOrMoreDots = firstDotIndex != -1
135: && firstDotIndex != expr.lastIndexOf('.');
136: FacesContext facesContext = null;
137: Class returnType = null;
138: Class[] parameterTypes = null;
139: if (firstDotIndex != -1) { //if we have at least one dot
140: for (FacesDesignContext context : contexts) {
141: //try to discover returnType and parameterTypes for this expression
142: if (twoOrMoreDots) {
143: ResolveResult result = context
144: .resolveBindingExprToBean(string);
145: DesignBean resultDesignBean = result
146: .getDesignBean();
147: if (resultDesignBean != null) { //will be null if "context" is Page1 and string begins with "#{SessionBean1", for instance
148: //we have the right context
149: Object beanInstance = resultDesignBean
150: .getInstance();
151: if (beanInstance != null) { //will be null if, say, foo can't be resolved in the string "#{SessionBean1.foo.bar}"
152: Class beanClass = beanInstance
153: .getClass();
154: String methodName = result
155: .getRemainder();
156: for (Method method : beanClass
157: .getMethods()) {
158: if (method.getName()
159: .equals(methodName)) {
160: facesContext = context
161: .getFacesContext();
162: returnType = method
163: .getReturnType();
164: parameterTypes = method
165: .getParameterTypes();
166: break;
167: }
168: }
169: }
170: break; //we've examined the right context. none of the remaining contexts will match.
171: }
172: } else { //one dot
173: String exprPrefix = expr.substring(0,
174: firstDotIndex);
175: if (exprPrefix.equals(context
176: .getReferenceName())) {
177: //we have the right context
178: //get exprSuffix, keeping in mind that the dot could be the last character
179: String exprSuffix = (firstDotIndex == expr
180: .length() - 1) ? ""
181: : expr
182: .substring(firstDotIndex + 1);
183: ContextMethod[] contextMethods = context
184: .getContextMethods();
185: for (ContextMethod contextMethod : contextMethods) {
186: if (exprSuffix
187: .equals(contextMethod
188: .getName())) {
189: facesContext = context
190: .getFacesContext();
191: returnType = contextMethod
192: .getReturnType();
193: parameterTypes = contextMethod
194: .getParameterTypes();
195: break;
196: }
197: }
198: break; //we've examined the right context. none of the remaining contexts will match.
199: }
200: }
201: }
202: }
203: if (facesContext != null && returnType != null
204: && parameterTypes != null) {
205: if (MethodExpression.class
206: .isAssignableFrom(propertyType)) {
207: return application
208: .getExpressionFactory()
209: .createMethodExpression(
210: facesContext.getELContext(),
211: string, returnType,
212: parameterTypes);
213: }
214: if (MethodBinding.class
215: .isAssignableFrom(propertyType)) {
216: return application.createMethodBinding(
217: string, parameterTypes);
218: }
219: }
220: }
221: return string;
222: } catch (ReferenceSyntaxException e) {
223: throw new IllegalTextArgumentException(
224: bundle
225: .getMessage(
226: "MethodBindingPropertyEditor.formatErrorMessage",
227: string), e); //NOI18N
228: } finally {
229: Thread.currentThread().setContextClassLoader(
230: oldContextClassLoader);
231: }
232: } else if (string.length() > 0) {
233: return new ConstantMethodBinding(string);
234: } else {
235: return null;
236: }
237: }
238:
239: public Component getCustomEditor() {
240: return new MethodBindingPropertyPanel(this );
241: }
242:
243: public boolean supportsCustomEditor() {
244: return true;
245: }
246:
247: }
|