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.insync.live;
042:
043: import org.netbeans.modules.visualweb.insync.beans.BeansUnit;
044: import java.beans.PropertyDescriptor;
045:
046: import javax.faces.application.Application;
047: import javax.faces.component.UIComponent;
048: import javax.faces.el.ValueBinding;
049:
050: import com.sun.rave.designtime.DesignBean;
051: import com.sun.rave.designtime.DesignContext;
052: import com.sun.rave.designtime.faces.FacesBindingPropertyEditor;
053: import com.sun.rave.designtime.faces.FacesDesignContext;
054: import org.netbeans.modules.visualweb.insync.faces.FacesPageUnit;
055:
056: /**
057: * A BeansDesignProperty subclass that knows how to handle the additional processing for JSF Value
058: * Binding when used. Property field is always in markup, thus always a MarkupProperty.
059: *
060: * @author Carl Quinn
061: */
062: public class FacesDesignProperty extends BeansDesignProperty implements
063: com.sun.rave.designtime.faces.FacesDesignProperty {
064:
065: /**
066: * @return whether or not the property is allowed to be an EL value binding expression
067: */
068: public static final boolean isBindingProperty(PropertyDescriptor pd) {
069: String name = pd.getName();
070: return name != null
071: && !(name.equals("id") || name.equals("parent")
072: || name.equals("var") || name
073: .equals("rowIndex"));
074: }
075:
076: /**
077: * Construct a new FacesDesignProperty given a descriptor and a bean.
078: * @param descriptor
079: * @param lbean
080: */
081: FacesDesignProperty(PropertyDescriptor descriptor,
082: BeansDesignBean lbean) {
083: super (descriptor, lbean);
084: }
085:
086: /*
087: * Initialize out live property value if we have a persisted property.
088: */
089: protected void initLive() {
090: ClassLoader oldContextClassLoader = Thread.currentThread()
091: .getContextClassLoader();
092: try {
093: Thread.currentThread().setContextClassLoader(
094: ((LiveUnit) getDesignBean().getDesignContext())
095: .getBeansUnit().getClassLoader());
096: if (property != null) {
097: // intercept if the source is a string that we know is a binding EL
098: String source = getValueSource();
099: if (isBindingValue(source))
100: invokeSetter(fromSource(source));
101: else
102: super .initLive();
103: }
104: } finally {
105: Thread.currentThread().setContextClassLoader(
106: oldContextClassLoader);
107: }
108: }
109:
110: /*
111: * @see org.netbeans.modules.visualweb.insync.live.SourceDesignProperty#getClipImage()
112: */
113: public ClipImage getClipImage() {
114: String name = descriptor.getName();
115: if (!isModified() || name.equals("id")) // don't bother saving id props
116: return null;
117: Object value = getValueBinding();
118: if (value == null)
119: value = getValue();
120: return new ClipImage(name, value);
121: }
122:
123: //----------------------------------------------------------------------------------- Conversion
124:
125: /*
126: * @see org.netbeans.modules.visualweb.insync.live.BeansDesignProperty#toSource(java.lang.Object)
127: */
128: protected String toSource(Object value) {
129: if (value instanceof ValueBinding)
130: return ((ValueBinding) value).getExpressionString();
131: return super .toSource(value);
132: }
133:
134: /*
135: * @see org.netbeans.modules.visualweb.insync.live.BeansDesignProperty#fromSource(java.lang.String)
136: */
137: protected Object fromSourceIncludeUnknown(String sourceValue) {
138: if (isBindingValue(sourceValue)) {
139: Application app = ((FacesPageUnit) liveBean.unit.sourceUnit)
140: .getFacesApplication();
141: return app.createValueBinding(sourceValue);
142: }
143: return super .fromSourceIncludeUnknown(sourceValue);
144: }
145:
146: //-------------------------------------------------------------------------------------- Getters
147:
148: /*
149: * Get this live property value by using the faces UIComponent getValueBinding method instead of
150: * the usuall bean property getter
151: * @see org.netbeans.modules.visualweb.insync.live.SourceDesignProperty#invokeGetter()
152: */
153: protected Object invokeGetter() {
154: ValueBinding vb = getValueBinding();
155: if (vb != null)
156: return vb;
157: return super .invokeGetter();
158: }
159:
160: /*
161: * Automatically dereference VBs here to make them transparent
162: * @see com.sun.rave.designtime.DesignProperty#getValue()
163: */
164: public Object getValue() {
165: ClassLoader oldContextClassLoader = Thread.currentThread()
166: .getContextClassLoader();
167: try {
168: Thread.currentThread().setContextClassLoader(
169: ((LiveUnit) getDesignBean().getDesignContext())
170: .getBeansUnit().getClassLoader());
171: Object v = invokeGetter();
172: if (v instanceof ValueBinding) {
173: try {
174: if (liveBean.unit.getModel().isBusted()) {
175: return null;
176: }
177: return ((ValueBinding) v).getValue(liveBean.unit
178: .getFacesContext());
179: } catch (Exception e) {
180: return null;
181: }
182: }
183: return v;
184: } finally {
185: Thread.currentThread().setContextClassLoader(
186: oldContextClassLoader);
187: }
188: }
189:
190: //-------------------------------------------------------------------------------------- Setters
191:
192: protected boolean invokeSetter(Object value) {
193: boolean wasBound = isBound();
194: UIComponent uic = (UIComponent) liveBean.getInstance();
195: if (value instanceof ValueBinding) {
196: ValueBinding vb = (ValueBinding) value;
197: if (!wasBound) {
198: unloadPropertyEditor();
199: }
200: try {
201: uic.setValueBinding(descriptor.getName(), vb);
202: if (!descriptor.getPropertyType().isPrimitive())
203: super .invokeSetter(null); // clear out any object values so that the binding is used
204: setModified(true);
205: return true;
206: } catch (Exception e) {
207: e.printStackTrace();
208: return false;
209: }
210: } else {
211: if (wasBound) {
212: unloadPropertyEditor();
213: uic.setValueBinding(descriptor.getName(), null); // clear out bindings so that they are not used
214: }
215: return super .invokeSetter(value);
216: }
217: }
218:
219: /*
220: * @see com.sun.rave.designtime.DesignProperty#setValue(java.lang.Object)
221: */
222: public boolean setValue(Object value) {
223: ClassLoader oldContextClassLoader = Thread.currentThread()
224: .getContextClassLoader();
225: try {
226: Thread.currentThread().setContextClassLoader(
227: ((LiveUnit) getDesignBean().getDesignContext())
228: .getBeansUnit().getClassLoader());
229: // intercept strings that look like ValueBindings and convert them first
230: if (value instanceof String
231: && isBindingValue((String) value)) {
232: value = fromSource((String) value);
233: } else {
234: // for value referencable objects, generate the reference
235: DesignBean lb = liveBean.unit.getBeanForInstance(value);
236: if (lb != null) {
237: DesignContext lc = lb.getDesignContext();
238: String contextName = liveBean.unit
239: .getRootContainer().getInstanceName();
240: if (lc instanceof FacesDesignContext) {
241: FacesDesignContext flc = (FacesDesignContext) lc;
242: contextName = flc.getReferenceName();
243: }
244: String valueSource = "#{" + contextName + "."
245: + lb.getInstanceName() + "}";
246: //return setValueBinding(null, valueSource);
247: return super .setValue(fromSource(valueSource));
248: }
249: }
250: // default: allow super to set something sensible, calling us back to invoke setter
251: return super .setValue(value);
252: } finally {
253: Thread.currentThread().setContextClassLoader(
254: oldContextClassLoader);
255: }
256: }
257:
258: //-------------------------------------------------- com.sun.rave.designtime.faces.FacesDesignProperty
259:
260: /*
261: * @see com.sun.rave.designtime.faces.FacesDesignProperty#isBound()
262: */
263: public boolean isBound() {
264: return getValueBinding() != null;
265: }
266:
267: /*
268: * @see com.sun.rave.designtime.faces.FacesDesignProperty#getValueBinding()
269: */
270: public ValueBinding getValueBinding() {
271: ClassLoader oldContextClassLoader = Thread.currentThread()
272: .getContextClassLoader();
273: try {
274: DesignBean designBean = getDesignBean();
275: if (designBean == null) {
276: return null;
277: }
278: DesignContext designContext = designBean.getDesignContext();
279: if (designBean == null) {
280: return null;
281: }
282: BeansUnit beansUnit = ((LiveUnit) designContext)
283: .getBeansUnit();
284: // XXX Possible NPE, when this gets invalid, and still in use.
285: if (beansUnit == null) {
286: return null;
287: }
288:
289: Thread.currentThread().setContextClassLoader(
290: beansUnit.getClassLoader());
291: UIComponent uic = (UIComponent) liveBean.getInstance();
292: ValueBinding vb = uic.getValueBinding(descriptor.getName());
293: return vb;
294: } finally {
295: Thread.currentThread().setContextClassLoader(
296: oldContextClassLoader);
297: }
298: }
299:
300: /*
301: * @see com.sun.rave.designtime.faces.FacesDesignProperty#setValueBinding(javax.faces.el.ValueBinding)
302: */
303: public void setValueBinding(ValueBinding binding) {
304: ClassLoader oldContextClassLoader = Thread.currentThread()
305: .getContextClassLoader();
306: try {
307: Thread.currentThread().setContextClassLoader(
308: ((LiveUnit) getDesignBean().getDesignContext())
309: .getBeansUnit().getClassLoader());
310: super .setValue(binding);
311: } finally {
312: Thread.currentThread().setContextClassLoader(
313: oldContextClassLoader);
314: }
315: }
316:
317: //--------------------------------------------------------------------------------------- SourceLiveProperty
318:
319: protected Class getIsBoundPropertyEditorClass() {
320: // INTEGRATION
321: // Need to figure out how we provide the PropertySheet functionality we want, such
322: // as the bound property editor case
323: // return PropertySheet.TriggerBoundCusomEditorActionProperty.boundPropertyEditorClass;
324: return null;
325: }
326:
327: /**
328: * Load the property editor for this property and cache it for internal use.
329: */
330: protected void loadEditor() {
331: // Boolean ignoreIsBound = Boolean.valueOf((String) descriptor.getValue("ignoreIsBound"));
332: // Class clazz = descriptor.getPropertyEditorClass();
333: // if (clazz != null && FacesBindingPropertyEditor.class.isAssignableFrom(clazz))
334: // ignoreIsBound = Boolean.TRUE;
335: // if (!ignoreIsBound.booleanValue() && isBound() ) {
336: // // initialize a different kind of property editor for bound case
337: // clazz = getIsBoundPropertyEditorClass();
338: // if (clazz != null) {
339: // loadEditor(clazz);
340: // return;
341: // }
342: // }
343: super .loadEditor();
344: }
345:
346: //--------------------------------------------------------------------------------------- Object
347:
348: /**
349: *
350: */
351: public String toString() {
352: return "[FLP name:" + descriptor.getName() + " type:"
353: + descriptor.getPropertyType() + " value:" + getValue()
354: + " valueSource:" + getValueSource() + "]";
355: }
356: }
|