001: /*
002: * Copyright (c) 2004 JETA Software, Inc. All rights reserved.
003: *
004: * Redistribution and use in source and binary forms, with or without modification,
005: * are permitted provided that the following conditions are met:
006: *
007: * o Redistributions of source code must retain the above copyright notice,
008: * this list of conditions and the following disclaimer.
009: *
010: * o Redistributions in binary form must reproduce the above copyright notice,
011: * this list of conditions and the following disclaimer in the documentation
012: * and/or other materials provided with the distribution.
013: *
014: * o Neither the name of JETA Software nor the names of its contributors may
015: * be used to endorse or promote products derived from this software without
016: * specific prior written permission.
017: *
018: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019: * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
020: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
021: * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
022: * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
023: * INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
024: * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
025: * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
026: * INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
027: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
028: */
029:
030: package com.jeta.forms.gui.beans;
031:
032: import java.awt.BorderLayout;
033: import java.awt.Component;
034: import java.beans.BeanInfo;
035: import java.beans.Introspector;
036: import java.beans.XMLDecoder;
037: import java.io.ByteArrayInputStream;
038: import java.util.Collection;
039: import java.util.HashMap;
040: import java.util.Iterator;
041:
042: import javax.swing.JList;
043: import javax.swing.JPanel;
044:
045: import com.jeta.forms.components.panel.FormPanel;
046: import com.jeta.forms.gui.common.FormException;
047: import com.jeta.forms.gui.common.FormUtils;
048: import com.jeta.forms.logger.FormsLogger;
049: import com.jeta.forms.store.bean.BeanDeserializer;
050: import com.jeta.forms.store.bean.BeanSerializer;
051: import com.jeta.forms.store.bean.BeanSerializerFactory;
052: import com.jeta.forms.store.memento.BeanMemento;
053: import com.jeta.forms.store.memento.PropertiesMemento;
054: import com.jeta.forms.store.memento.StateRequest;
055: import com.jeta.forms.store.properties.JETAProperty;
056: import com.jeta.forms.store.properties.TransformProperty;
057: import com.jeta.open.registry.JETARegistry;
058: import com.jeta.open.support.EmptyCollection;
059:
060: /**
061: * A <code>JETABean</code> is a container and a proxy for a regular JavaBean.
062: * However, a <code>JETABean</code> also supports the notion of dynamic
063: * properties. These are properties that can be added at design time to the
064: * delegate bean. For example, components such as JList, JTable, JTextArea, etc.
065: * are normally contained within a scroll pane. Instead of requiring the user to
066: * create a JScrollPane and adding the child component, we create a scroll
067: * property and attach at design-runtime to the list, table, and text areas.
068: * This is much easier for the user to work with.
069: *
070: * All Java Bean components are contained within a JETABean instance in this
071: * architecture.
072: *
073: * @author Jeff Tassin
074: */
075: public class JETABean extends JPanel {
076: /**
077: * This is the Java Bean component.
078: *
079: * @directed
080: * @supplierCardinality 1
081: */
082: private Component m_delegate;
083:
084: /**
085: * The Bean Information for the component. This includes standard and custom
086: * properties.
087: *
088: * @undirected
089: */
090: private DynamicBeanInfo m_beaninfo;
091:
092: /**
093: * A map of custom property *values* associated with this bean.
094: * m_custom_properties<String,Object> where String is the custom property
095: * name Object is the custom property value.
096: */
097: private HashMap m_custom_properties = new HashMap();
098:
099: /**
100: * Creates a <code>JETABean</code> instance.
101: */
102: public JETABean() {
103: setOpaque(false);
104: }
105:
106: /**
107: * Creates a <code>JETABean</code> instance with the specified Java Bean
108: * delegate and dynamic properties.
109: *
110: * @param delegate
111: * the Swing component that we are a proxy for
112: * @param customProps
113: * a collection of default JETAProperty objects that we wish to
114: * add to this bean. These are the dynamic properties for the
115: * bean (if any).
116: */
117: public JETABean(Component delegate, BeanProperties customProperties)
118: throws FormException {
119: setOpaque(false);
120:
121: try {
122: m_delegate = delegate;
123:
124: if (customProperties != null) {
125: m_beaninfo = customProperties.getBeanInfo();
126:
127: Iterator iter = customProperties.getPropertyValues()
128: .iterator();
129: while (iter.hasNext()) {
130: JETAProperty prop = (JETAProperty) iter.next();
131: m_custom_properties.put(prop.getName(), prop);
132: }
133: }
134:
135: /**
136: * the delegate can be null when we are deserializing
137: */
138: if (delegate != null) {
139: initialize();
140: }
141: } catch (Exception e) {
142: FormsLogger.severe(e);
143: }
144: }
145:
146: /**
147: * Creates a <code>JETABean</code> instance with the specified Java Bean
148: * delegate and no custom properties.
149: *
150: * @param delegate
151: * the Swing component that we are a wrapper for
152: */
153: public JETABean(Component delegate) throws FormException {
154: try {
155: setOpaque(false);
156:
157: m_delegate = delegate;
158: initialize();
159: } catch (Exception e) {
160: System.out
161: .println(">>>>>> JETABean initialized failed for delegate: "
162: + m_delegate);
163: e.printStackTrace();
164: }
165: }
166:
167: /**
168: * Returns the Bean information for the Java Bean. Normally, the BeanFactory
169: * provides the Bean Information. However, if this is not the case, then we
170: * generate a default BeanInfo using the Introspector.
171: *
172: * @return the BeanInfo object that describes the properties for the
173: * delegate
174: */
175: public DynamicBeanInfo getBeanInfo() {
176: if (m_beaninfo == null) {
177: try {
178: if (m_delegate != null) {
179: BeanInfo info = Introspector.getBeanInfo(m_delegate
180: .getClass());
181: m_beaninfo = new DynamicBeanInfo(info, null);
182: }
183: } catch (Exception e) {
184: FormsLogger.severe(e);
185: }
186: }
187: return m_beaninfo;
188: }
189:
190: /**
191: * Return the custom property associated with this bean.
192: *
193: * @param propName
194: * the name of the property to get.
195: * @return the custom property associated with this bean. Null is returned
196: * if the property is not found
197: */
198: public JETAProperty getCustomProperty(String propName) {
199: return (JETAProperty) m_custom_properties.get(propName);
200: }
201:
202: /**
203: * Returns the underlying Java Bean component. This is the actual Swing
204: * component that will be visible on the form.
205: *
206: * @return the underlying Java Bean component.
207: */
208: public Component getDelegate() {
209: return m_delegate;
210: }
211:
212: /**
213: * This returns the child component of this bean. Normally, this is the same
214: * object as the m_delegate. However, in some cases it can be different. For
215: * example, if the delegate is contained in a scrollpane.
216: */
217: public Component getBeanChildComponent() {
218: if (getComponentCount() > 0) {
219: return getComponent(0);
220: } else if ((getComponentCount() == 0)
221: && (getDelegate() != null)) {
222: return getDelegate();
223: } else {
224: return null;
225: }
226: }
227:
228: /**
229: * Returns the name of the Java Bean. This is the same as the 'name'
230: * property.
231: *
232: * @return the name of the delegate
233: */
234: public String getBeanName() {
235: if (m_delegate == null)
236: return null;
237: else
238: return m_delegate.getName();
239: }
240:
241: /**
242: * Return the property descriptors associated with this bean. This includes
243: * all standard and custom properties.
244: *
245: * @return a collection of JETAPropertyDescriptor objects
246: */
247: public Collection getPropertyDescriptors() {
248: DynamicBeanInfo binfo = getBeanInfo();
249: if (binfo != null)
250: return binfo.getPropertyDescriptors();
251: else
252: return EmptyCollection.getInstance();
253: }
254:
255: /**
256: * Stores this bean's state into the given memento object.
257: *
258: * @param memento
259: * the object used to hold the bean state. This includes all
260: * property values.
261: * @param sr
262: * a request object that gives hints on how the state should be
263: * stored.
264: */
265: public void getState(BeanMemento memento, StateRequest sr)
266: throws FormException {
267: try {
268: memento.setJETABeanClass(getClass().getName());
269: if (m_delegate != null && m_delegate.getClass() != null) {
270: memento.setBeanClass(m_delegate.getClass().getName());
271: BeanSerializerFactory fac = (BeanSerializerFactory) JETARegistry
272: .lookup(BeanSerializerFactory.COMPONENT_ID);
273: if (fac != null) {
274: /** store the bean properties */
275: BeanSerializer bs = fac.createSerializer();
276: memento.setProperties(bs.writeBean(this ));
277: } else {
278: FormUtils.safeAssert(false);
279: }
280: }
281: } catch (Exception e) {
282: e.printStackTrace();
283: }
284: }
285:
286: /**
287: * Called after instantiation or deserialization. Initializes the bean as
288: * well as the custom properties associated with the bean.
289: */
290: private void initialize() throws FormException {
291: try {
292: removeAll();
293: if (m_delegate != null) {
294: setLayout(new BorderLayout());
295: add(m_delegate, BorderLayout.CENTER);
296:
297: /** tell each custom property to updateBean */
298: Collection props = m_custom_properties.values();
299: Iterator iter = props.iterator();
300: while (iter.hasNext()) {
301: JETAProperty jprop = (JETAProperty) iter.next();
302: jprop.updateBean(this );
303: }
304: }
305: } catch (Exception e) {
306: e.printStackTrace();
307: }
308: }
309:
310: /**
311: * Sets a custom property associated with this bean.
312: */
313: public void setCustomProperty(String propName, JETAProperty prop) {
314: m_custom_properties.put(propName, prop);
315: }
316:
317: /**
318: * This should never be called.
319: */
320: public void setName(String name) {
321: FormUtils.safeAssert(false);
322: }
323:
324: /**
325: * Sets this bean's state using the given memento object.
326: *
327: * @param memento
328: * the bean state. This was created by calling getState.
329: *
330: * @see #getState
331: */
332: public void setState(BeanMemento memento) throws FormException {
333: try {
334: PropertiesMemento props_memento = memento.getProperties();
335: if (props_memento != null)
336: setState(props_memento);
337: else
338: setStateOld(memento);
339: } catch (Exception e) {
340: e.printStackTrace();
341: }
342: }
343:
344: /**
345: * Sets this bean's state using the given properties memento object.
346: *
347: * @param memento
348: * the bean state.
349: */
350: public void setState(PropertiesMemento props_memento)
351: throws FormException {
352: try {
353: if (props_memento != null) {
354: removeAll();
355: setLayout(new BorderLayout());
356: m_delegate = null;
357:
358: BeanSerializerFactory fac = (BeanSerializerFactory) JETARegistry
359: .lookup(BeanSerializerFactory.COMPONENT_ID);
360: if (fac != null) {
361: BeanDeserializer bds = fac
362: .createDeserializer(props_memento);
363: m_delegate = bds.createBean();
364: if (m_delegate != null) {
365: add(m_delegate, BorderLayout.CENTER);
366:
367: /** tell each custom property to updateBean */
368: Collection props = m_custom_properties.values();
369: Iterator iter = props.iterator();
370: while (iter.hasNext()) {
371: JETAProperty jprop = (JETAProperty) iter
372: .next();
373: if (jprop instanceof TransformProperty)
374: ((TransformProperty) jprop)
375: .setBean(this );
376: }
377:
378: bds.initializeBean(this );
379: }
380: } else {
381: FormUtils.safeAssert(false);
382: }
383: }
384: } catch (Exception e) {
385: e.printStackTrace();
386: }
387: }
388:
389: /**
390: * Sets the bean state using deprecated file format.
391: */
392: private void setStateOld(BeanMemento memento) {
393: try {
394: /** this is a deprecated format that we still support */
395: byte[] xml_data = memento.getBeanXML();
396: byte[] xml = memento.getBeanXML();
397: if (xml == null)
398: return;
399:
400: XMLDecoder d = new XMLDecoder(new ByteArrayInputStream(xml));
401: m_delegate = (Component) d.readObject();
402: if (m_delegate == null)
403: return;
404:
405: // special handling for JList because we need to set the list model
406: // to DefaultListModel
407: // this is for the custom ItemsProperty
408: if (m_delegate instanceof JList) {
409: ((JList) m_delegate)
410: .setModel(new javax.swing.DefaultListModel());
411: }
412: Collection custom_props = memento.getCustomProperties();
413: if (custom_props != null) {
414: Iterator iter = custom_props.iterator();
415: while (iter.hasNext()) {
416: /**
417: * Here we are changing the default custom properties to any
418: * saved values.
419: */
420: JETAProperty prop = (JETAProperty) iter.next();
421: JETAProperty default_prop = getCustomProperty(prop
422: .getName());
423: if (default_prop != null) {
424: if (!(default_prop instanceof TransformProperty)) {
425: default_prop.setValue(prop);
426: }
427: } else {
428: if (!(prop instanceof TransformProperty)) {
429: FormsLogger
430: .debug("JETABean.setState getCustomProperty failed: "
431: + prop.getName()
432: + " "
433: + prop);
434: }
435: }
436: }
437: }
438: initialize();
439: } catch (Exception e) {
440: e.printStackTrace();
441: }
442: }
443:
444: /**
445: * PostInitialize is called once after all components in a form have been
446: * re-instantiated at runtime (not design time). This gives each property
447: * and component a chance to do some last minute initializations that might
448: * depend on the top level parent. An example of this is using ButtonGroups.
449: * Groups for JRadioButtons are global to a FormPanel and not specific to
450: * each FormComponent instance.
451: */
452: public void postInitialize(FormPanel panel) {
453: Collection props = m_custom_properties.values();
454: Iterator iter = props.iterator();
455: while (iter.hasNext()) {
456: JETAProperty jprop = (JETAProperty) iter.next();
457: jprop.postInitialize(panel, this);
458: }
459: }
460: }
|