Source Code Cross Referenced for ObjectListDataProvider.java in  » IDE-Netbeans » visualweb.api.designer » com » sun » data » provider » impl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » IDE Netbeans » visualweb.api.designer » com.sun.data.provider.impl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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:
0042:        package com.sun.data.provider.impl;
0043:
0044:        import java.io.Serializable;
0045:        import java.lang.reflect.Constructor;
0046:        import java.lang.reflect.Modifier;
0047:        import java.util.ArrayList;
0048:        import java.util.HashMap;
0049:        import java.util.Iterator;
0050:        import java.util.List;
0051:        import java.util.Map;
0052:        import java.util.ResourceBundle;
0053:        import java.util.Set;
0054:        import java.util.TreeSet;
0055:        import com.sun.data.provider.DataProviderException;
0056:        import com.sun.data.provider.FieldKey;
0057:        import com.sun.data.provider.RowKey;
0058:        import com.sun.data.provider.TransactionalDataListener;
0059:        import com.sun.data.provider.TransactionalDataProvider;
0060:
0061:        /**
0062:         * <p>This {@link com.sun.data.provider.TableDataProvider} wraps access to a
0063:         * list of Java Objects.  The {@link FieldKey}s correspond to the JavaBean
0064:         * properties and optionally the public member fields of the Java Object.</p>
0065:         *
0066:         * <p>This class implements {@link TransactionalDataProvider} semantics,
0067:         * meaning that all updates to existing fields, as well as inserted and
0068:         * deleted rows, are cached until <code>commitChanges()</code> is called.
0069:         * Once that call is made, any <code>RowKey</code> you have retrieved from
0070:         * this instance is invalid, and must be reacquired.</p>
0071:         *
0072:         * <p><strong>WARNING</strong> - Until you call <code>setList()</code> or
0073:         * <code>setObjectType()</code> with a non-null parameter, or use a constructor
0074:         * variant that accepts an non-null non-empty list, no information about field keys will
0075:         * be available.  Therefore, any attempt to reference a <code>FieldKey</code>
0076:         * or field identifier in a method call will throw
0077:         * <code>IllegalArgumentException</code>.</p>
0078:         *
0079:         * <p>NOTE about Serializable:  This class wraps access to a list of any Java
0080:         * Objects. The Objects can be swapped out using the <code>setObject(Object)</code>
0081:         * method.  For this class to remain Serializable, the contained Objects must
0082:         * also be Serializable.</p>
0083:         *
0084:         * @author Joe Nuxoll
0085:         *         Winston Prakash (bug fixes)
0086:         */
0087:        public class ObjectListDataProvider extends AbstractTableDataProvider
0088:                implements  Serializable, TransactionalDataProvider {
0089:
0090:            // ------------------------------------------------------------ Constructors
0091:
0092:            /**
0093:             * <p>Construct a new ObjectListDataProvider with no known object type.  The
0094:             * <code>setObjectType()</code> method can be used to set the object type.
0095:             * If not set, the first added object will automatically define the object
0096:             * type.</p>
0097:             */
0098:            public ObjectListDataProvider() {
0099:
0100:                setObjectType(null);
0101:
0102:            }
0103:
0104:            /**
0105:             * <p>Constructs a new ObjectListDataProvider wrapping the specified list.
0106:             * </p>
0107:             *
0108:             * @param list List to be wrapped
0109:             */
0110:            public ObjectListDataProvider(List list) {
0111:
0112:                setList(list);
0113:
0114:            }
0115:
0116:            /**
0117:             * <p>Constructs a new ObjectListDataProvider wrapping the specified list
0118:             * with the specified include fields flag.</p>
0119:             *
0120:             * @param list List to be wrapped
0121:             * @param includeFields Desired include fields property setting
0122:             */
0123:            public ObjectListDataProvider(List list, boolean includeFields) {
0124:
0125:                setList(list);
0126:                setIncludeFields(includeFields);
0127:
0128:            }
0129:
0130:            /**
0131:             * <p>Constructs a new ObjectListDataProvider for the specified object type.
0132:             * </p>
0133:             *
0134:             * @param objectType Desired object type Class
0135:             */
0136:            public ObjectListDataProvider(Class objectType) {
0137:
0138:                setObjectType(objectType);
0139:
0140:            }
0141:
0142:            /**
0143:             * <p>Constructs a new ObjectListDataProvider for the specified object type
0144:             * and <code>includeFields</code> property value.</p>
0145:             *
0146:             * @param objectType Desired object type Class
0147:             * @param includeFields Desired include fields property setting
0148:             */
0149:            public ObjectListDataProvider(Class objectType,
0150:                    boolean includeFields) {
0151:
0152:                setObjectType(objectType);
0153:                setIncludeFields(includeFields);
0154:
0155:            }
0156:
0157:            // ------------------------------------------------------ Instance Variables
0158:
0159:            /**
0160:             * <p>List of object instances to be appended to the underlying
0161:             * list when changes are committed.  The {@link RowKey} values
0162:             * that correspond to these rows will have row index values starting
0163:             * with the number of rows in the underlying list.  That is, if there
0164:             * are five rows in the list already, the first appended row will have
0165:             * an index of five, the second will have a row index of six, and
0166:             * so on.</p>
0167:             */
0168:            private List appends = new ArrayList();
0169:
0170:            /**
0171:             * <p>Resource bundle containing our localized messages.</p>
0172:             */
0173:            private transient ResourceBundle bundle = null;
0174:
0175:            /**
0176:             * <p>Set of {@link RowKey}s of rows that have been marked to be
0177:             * deleted.  An <code>Iterator</code> over this set will return
0178:             * the corresponding {@link RowKey}s in ascending order.</p>
0179:             */
0180:            private Set deletes = new TreeSet();
0181:
0182:            /**
0183:             * <p>Storage for the <code>includeFields</code> property.  By default,
0184:             * this is true.</p>
0185:             */
0186:            private boolean includeFields = true;
0187:
0188:            /**
0189:             * <p>Storage for the internal list of objects wrapped by this
0190:             * data provider.</p>
0191:             */
0192:            private List list = new ArrayList();
0193:
0194:            /**
0195:             * <p>Storage for the object type contained in this data provider.</p>
0196:             */
0197:            private Class objectType;
0198:
0199:            /**
0200:             * <p>Map keyed by {@link RowKey}, whose elements are themselves
0201:             * Maps keyed by {@link FieldKey} of each field for which an
0202:             * updated value has been cached.</p>
0203:             */
0204:            private Map updates = new HashMap();
0205:
0206:            /**
0207:             * <p>Storage for the userResizable property (default value is
0208:             * <code>true</true>).</p>
0209:             */
0210:            private boolean userResizable = true;
0211:
0212:            // -------------------------------------------------------------- Private Static Variables
0213:
0214:            /**
0215:             * <p>The maximum number of rows that can be displayed at designtime.</p>
0216:             */
0217:            private static final int MAX_DESIGNTIME_ROWCOUNT = 25;
0218:
0219:            /**
0220:             * <p>When showing fake data, the number of rows to show.</p>
0221:             */
0222:            private static final int FAKE_DATA_ROWCOUNT = 3;
0223:
0224:            // -------------------------------------------------------------- Properties
0225:
0226:            /**
0227:             * <p>Return the state of the <code>includeFields</code> property.</p>
0228:             */
0229:            public boolean isIncludeFields() {
0230:
0231:                return this .includeFields;
0232:
0233:            }
0234:
0235:            /**
0236:             * <p>Set the <code>includeFields</code> property.  This affects the set of
0237:             * {@link FieldKey}s that this {@link com.sun.data.provider.DataProvider}
0238:             * emits.  If the property is set to <code>true</code> (the default), then
0239:             * public fields will be included in the list of available keys (intermixed
0240:             * with the public properties).  Otherwise, only the public properties will
0241:             * be available.</p>
0242:             *
0243:             * @param includeFields The new include fields value
0244:             */
0245:            public void setIncludeFields(boolean includeFields) {
0246:
0247:                this .includeFields = includeFields;
0248:                this .support = null;
0249:
0250:            }
0251:
0252:            /**
0253:             * <code>Return the <code>List</code> that we are wrapping.</p>
0254:             */
0255:            public List getList() {
0256:
0257:                return this .list;
0258:
0259:            }
0260:
0261:            /**
0262:             * <p>Replace the <code>List</code> that we are wrapping.  In addition,
0263:             * the <code>objectType</code> property will be reset based on the
0264:             * class of the first element in the list (if any).  If the list is
0265:             * empty, <code>objectType</code> will be set to <code>null</code>.
0266:             *
0267:             * @param list The new list to be wrapped
0268:             */
0269:            public void setList(List list) {
0270:                this .list = list;
0271:                if (list != null && list.size() > 0) {
0272:                    setObjectType(list.get(0).getClass());
0273:                } else {
0274:                    setObjectType(null);
0275:                }
0276:            }
0277:
0278:            /**
0279:             * <p>Return the object type that this data provider contains.  This
0280:             * determines the list of {@link FieldKey}s that this provider supplies.</p>
0281:             */
0282:            public Class getObjectType() {
0283:
0284:                return objectType;
0285:
0286:            }
0287:
0288:            /**
0289:             * <p>Set the object type contained in this ObjectListDataProvider.  This
0290:             * type determines the list of public properties and fields to expose as
0291:             * {@link FieldKey}s.  If no object type is specified, the first added
0292:             * object's class will be used as the object type.</p>
0293:             *
0294:             * @param objectType The desired Class type to be contained in this
0295:             *        ObjectDataProvider
0296:             */
0297:            public void setObjectType(Class objectType) {
0298:
0299:                this .objectType = objectType;
0300:                this .objectTypeConstructor = null;
0301:                this .support = null;
0302:                fireProviderChanged();
0303:
0304:            }
0305:
0306:            /**
0307:             * <p>Return the current state of the userResizable property.  Note that
0308:             * the wrapped list will not be actually resizable unless there is a
0309:             * public no-args constructor on the <code>objectType</code> class.</p>
0310:             */
0311:            public boolean isUserResizable() {
0312:
0313:                return this .userResizable;
0314:
0315:            }
0316:
0317:            /**
0318:             * <p>Set the user resizable property.  If set to <code>true</code> (the
0319:             * default), the resizability of this ObjectListDataProvider is based on
0320:             * wether or not a public default constructor exists in the object type.
0321:             * If the userResizable propert is set to <code>false</code>, then this
0322:             * ObjectListDataProvider will not be resizable, regardless of the existence
0323:             * of a public default constructor on the object type.</p>
0324:             *
0325:             * @param resizable <code>true</code> to make this ObjectListDataProvider
0326:             *        resizable, pending the existence of a public default constructor
0327:             *        on the contained object type, or <code>false</code> to make it
0328:             *        non-resizable.
0329:             * @see com.sun.data.provider.TableDataProvider#canInsertRow(RowKey beforeRow)
0330:             */
0331:            public void setUserResizable(boolean resizable) {
0332:
0333:                this .userResizable = resizable;
0334:
0335:            }
0336:
0337:            // ---------------------------------------------------------- Public Methods
0338:
0339:            /**
0340:             * <p>Append the specified object to the list of contained objects.</p>
0341:             *
0342:             * @param object The Object to store in the list
0343:             */
0344:            public void addObject(Object object) {
0345:
0346:                if (objectType == null) {
0347:                    setObjectType(object.getClass());
0348:                }
0349:                appendRow(object);
0350:
0351:            }
0352:
0353:            /**
0354:             * <p>Add the specified object to the list of contained objects
0355:             * at the specified row.</p>
0356:             *
0357:             * @param row The desired index for the new object
0358:             * @param object The Object to store in the list
0359:             */
0360:            /* FIXME - inserts not currently supported
0361:            public void addObject(RowKey row, Object object) {
0362:             
0363:                if (objectType == null) {
0364:                    setObjectType(object.getClass());
0365:                }
0366:                int index = ((IndexRowKey) row).getIndex();
0367:                list.add(index, object);
0368:                fireRowAdded(row);
0369:                if (getCursorIndex() == index) {
0370:                    fireValueChanged(null, null, object);
0371:                }
0372:             
0373:            }
0374:             */
0375:
0376:            /**
0377:             * <p>Clear the list of contained objects.</p>
0378:             */
0379:            // FIXME - probably remove as being redundant
0380:            public void clearObjectList() {
0381:
0382:                list.clear();
0383:                fireProviderChanged();
0384:
0385:            }
0386:
0387:            /**
0388:             * <p>Returns the object stored at the specified row.</p>
0389:             *
0390:             * @param row The desired row to retrieve the contained object from
0391:             */
0392:            public Object getObject(RowKey row) {
0393:
0394:                return list.get(getRowIndex(row));
0395:
0396:            }
0397:
0398:            /**
0399:             * <p>Return the contained objects as an array.</p>
0400:             */
0401:            public Object[] getObjects() {
0402:
0403:                return list.toArray(new Object[list.size()]);
0404:
0405:            }
0406:
0407:            /**
0408:             * <p>Return <code>true</code> if the specified row has been
0409:             * marked for removal on the next call to <code>commitChanges()</code>.</p>
0410:             *
0411:             * @param row The {@link RowKey} of the row to check
0412:             */
0413:            public boolean isRemoved(RowKey row) {
0414:
0415:                return deletes.contains(row);
0416:
0417:            }
0418:
0419:            /**
0420:             * <p>Remove the specified object from the list of contained objects.</p>
0421:             *
0422:             * @param object The Object to remove from the list
0423:             */
0424:            public void removeObject(Object object) {
0425:
0426:                int index = list.indexOf(object);
0427:                if (index > -1) {
0428:                    removeObject(getRowKey(index));
0429:                }
0430:
0431:            }
0432:
0433:            /**
0434:             * <p>Remove the object at the specified row from the list
0435:             * of contained objects.</p>
0436:             *
0437:             * @param row The desired Object row to remove from the list
0438:             */
0439:            public void removeObject(RowKey row) {
0440:
0441:                removeRow(row);
0442:
0443:            }
0444:
0445:            /**
0446:             * <p>Replace the object at the specified row.</p>
0447:             *
0448:             * @param row The desired row to set the contained object
0449:             * @param object The new object to set at the specified row
0450:             */
0451:            public void setObject(RowKey row, Object object) {
0452:
0453:                Object previous = getObject(row);
0454:                list.set(getRowIndex(row), object);
0455:                fireValueChanged(null, row, previous, object);
0456:                if (getCursorRow() == row) {
0457:                    fireValueChanged(null, previous, object);
0458:                }
0459:
0460:            }
0461:
0462:            // ---------------------------------------------------- DataProvider Methods
0463:
0464:            /** {@inheritDoc} */
0465:            public FieldKey getFieldKey(String fieldId)
0466:                    throws DataProviderException {
0467:                FieldKey fieldKey = null;
0468:                if (getSupport() != null) {
0469:                    fieldKey = getSupport().getFieldKey(fieldId);
0470:                }
0471:                if (fieldKey != null) {
0472:                    return fieldKey;
0473:                } else {
0474:                    throw new IllegalArgumentException(fieldId);
0475:                }
0476:            }
0477:
0478:            /** {@inheritDoc} */
0479:            public FieldKey[] getFieldKeys() throws DataProviderException {
0480:
0481:                if (getSupport() != null) {
0482:                    return getSupport().getFieldKeys();
0483:                }
0484:                return FieldKey.EMPTY_ARRAY;
0485:
0486:            }
0487:
0488:            /** {@inheritDoc} */
0489:            public Class getType(FieldKey fieldKey)
0490:                    throws DataProviderException {
0491:                if ((getSupport() == null)
0492:                        || (getSupport().getFieldKey(fieldKey.getFieldId()) == null)) {
0493:                    throw new IllegalArgumentException(fieldKey.toString());
0494:                } else {
0495:                    return getSupport().getType(fieldKey);
0496:                }
0497:            }
0498:
0499:            /** {@inheritDoc} */
0500:            public Object getValue(FieldKey fieldKey)
0501:                    throws DataProviderException {
0502:
0503:                return getValue(fieldKey, getCursorRow());
0504:
0505:            }
0506:
0507:            /** {@inheritDoc} */
0508:            public void setValue(FieldKey fieldKey, Object value)
0509:                    throws DataProviderException {
0510:
0511:                setValue(fieldKey, getCursorRow(), value);
0512:
0513:            }
0514:
0515:            /** {@inheritDoc} */
0516:            public boolean isReadOnly(FieldKey fieldKey)
0517:                    throws DataProviderException {
0518:                if ((getSupport() == null)
0519:                        || (getSupport().getFieldKey(fieldKey.getFieldId()) == null)) {
0520:                    throw new IllegalArgumentException(fieldKey.toString());
0521:                } else {
0522:                    return getSupport().isReadOnly(fieldKey);
0523:                }
0524:            }
0525:
0526:            // --------------------------------------- TableDataProvider Methods (Basic)
0527:
0528:            /** {@inheritDoc} */
0529:            public int getRowCount() throws DataProviderException {
0530:                //at designtime, if there are no field keys
0531:                //prevent ELExceptions from being thrown by showing zero rows
0532:                if (java.beans.Beans.isDesignTime()
0533:                        && getFieldKeys().length < 1) {
0534:                    return 0;
0535:                }
0536:
0537:                //calculate how many rows currently exist in the wrapped data
0538:                int currentRowCount = calculateRowCount();
0539:
0540:                if (java.beans.Beans.isDesignTime()) {
0541:                    if (currentRowCount < 1) {
0542:                        //we have no rows to show
0543:                        //so show FAKE_DATA_ROWCOUNT rows of fake data
0544:                        return FAKE_DATA_ROWCOUNT;
0545:                    } else if (currentRowCount > MAX_DESIGNTIME_ROWCOUNT) {
0546:                        //we have too many rows to show
0547:                        //only show the maximum permitted
0548:                        return MAX_DESIGNTIME_ROWCOUNT;
0549:                    } else {
0550:                        return currentRowCount;
0551:                    }
0552:                } else {
0553:                    return currentRowCount;
0554:                }
0555:            }
0556:
0557:            /** {@inheritDoc} */
0558:            public Object getValue(FieldKey fieldKey, RowKey rowKey)
0559:                    throws DataProviderException {
0560:                if (java.beans.Beans.isDesignTime()) {
0561:                    //calculate how many rows currently exist in the wrapped data
0562:                    int currentRowCount = calculateRowCount();
0563:                    if (currentRowCount < 1) {
0564:                        //we have no actual rows
0565:                        //so show fake data
0566:                        return AbstractDataProvider
0567:                                .getFakeData(getType(fieldKey));
0568:                    }
0569:                }
0570:
0571:                if ((getSupport() == null)
0572:                        || (getSupport().getFieldKey(fieldKey.getFieldId()) == null)) {
0573:                    throw new IllegalArgumentException(fieldKey.toString());
0574:                }
0575:
0576:                // Return pending update value (if any)
0577:                Map fieldUpdates = (Map) updates.get(rowKey);
0578:                if ((fieldUpdates != null)
0579:                        && (fieldUpdates.containsKey(fieldKey))) {
0580:                    return fieldUpdates.get(fieldKey);
0581:                }
0582:
0583:                // Otherwise, return the value from the underlying list
0584:                if (!isRowAvailable(rowKey) && !deletes.contains(rowKey)) {
0585:                    throw new IndexOutOfBoundsException("" + rowKey);
0586:                }
0587:
0588:                int index = getRowIndex(rowKey);
0589:                // getRowCount()  returns list.size()-deletes.size()
0590:                // So index could be list.size()-1 (last index) - Winston
0591:                //if (index < getRowCount()) {
0592:                if (index < list.size()) {
0593:                    return getSupport().getValue(fieldKey, list.get(index));
0594:                } else {
0595:                    return getSupport().getValue(fieldKey,
0596:                            appends.get(index - getRowCount()));
0597:                }
0598:            }
0599:
0600:            /**
0601:             * <p>Return <code>true</code> if the specified {@link RowKey} represents
0602:             * a row in the original list, or a row that has been appended.  FIXME -
0603:             * deal with {@link RowKey}s for inserted rows too, when inserts are
0604:             * supported.</p>
0605:             *
0606:             * @param row {@link RowKey} to test for availability
0607:             */
0608:            public boolean isRowAvailable(RowKey row)
0609:                    throws DataProviderException {
0610:
0611:                if (deletes.contains(row)) {
0612:                    return false;
0613:                }
0614:                if (row instanceof  IndexRowKey) {
0615:                    //return (getRowCount() + appends.size()) > ((IndexRowKey) row).getIndex();
0616:                    // Bug Fix: 6348255 - Delete two rows including the last row, exception thrown
0617:                    return (list.size() + appends.size()) > ((IndexRowKey) row)
0618:                            .getIndex();
0619:                }
0620:                return false;
0621:            }
0622:
0623:            /** {@inheritDoc} */
0624:            public void setValue(FieldKey fieldKey, RowKey rowKey, Object value)
0625:                    throws DataProviderException {
0626:
0627:                if ((getSupport() == null)
0628:                        || (getSupport().getFieldKey(fieldKey.getFieldId()) == null)) {
0629:                    throw new IllegalArgumentException(fieldKey.toString());
0630:                }
0631:                if (getSupport().isReadOnly(fieldKey)) {
0632:                    throw new IllegalStateException(fieldKey.toString() + " "
0633:                            + getBundle().getString("IS_READ_ONLY"));
0634:                }
0635:                if (!isRowAvailable(rowKey) && !deletes.contains(rowKey)) {
0636:                    throw new IndexOutOfBoundsException(rowKey.toString());
0637:                }
0638:
0639:                // Retrieve the previous value and determine if it has changed
0640:                Object previous = getValue(fieldKey, rowKey);
0641:                if (((previous == null) && (value == null))
0642:                        || ((previous != null) && (value != null) && previous
0643:                                .equals(value))) {
0644:                    return; // No change
0645:                }
0646:
0647:                // Verify type compatibility of the proposed new value
0648:                if (!getSupport().isAssignable(fieldKey, value)) {
0649:                    throw new IllegalArgumentException(fieldKey + " = " + value); // NOI18N
0650:                }
0651:
0652:                // Record a pending change for this row and field
0653:                Map fieldUpdates = (Map) updates.get(rowKey);
0654:                if (fieldUpdates == null) {
0655:                    fieldUpdates = new HashMap();
0656:                    updates.put(rowKey, fieldUpdates);
0657:                }
0658:                fieldUpdates.put(fieldKey, value);
0659:                fireValueChanged(fieldKey, rowKey, previous, value);
0660:                fireValueChanged(fieldKey, previous, value);
0661:
0662:            }
0663:
0664:            // -------------------------------------- TableDataProvider Methods (Cursor)
0665:
0666:            // Base class definitions are sufficient
0667:
0668:            // ------------------------ TableDataProvider Methods (Append/Insert/Delete)
0669:
0670:            /**
0671:             * <p>Return true if the <code>userResizable</code> property is set to
0672:             * <code>true</code>, and there is a public zero-args constructor for the
0673:             * class specified by the <code>objectType</code> property.</p>
0674:             *
0675:             * {@inheritDoc}
0676:             */
0677:            public boolean canAppendRow() throws DataProviderException {
0678:
0679:                if (!userResizable) {
0680:                    return false;
0681:                }
0682:                if (objectType != null) {
0683:                    return getObjectTypeConstructor() != null;
0684:                }
0685:                return false;
0686:
0687:            }
0688:
0689:            /**
0690:             * <p>Construct a new instance of the specified object type and append it
0691:             * to the end of the list.</p>
0692:             *
0693:             * {@inheritDoc}
0694:             */
0695:            public RowKey appendRow() throws DataProviderException {
0696:
0697:                if (!canAppendRow()) {
0698:                    throw new IllegalStateException(getBundle().getString(
0699:                            "OLDP_NOT_RESIZABLE"));
0700:                }
0701:                try {
0702:                    Constructor con = getObjectTypeConstructor();
0703:                    appends.add(con.newInstance(new Object[0]));
0704:                    RowKey rowKey = getRowKey(list.size() + appends.size() - 1);
0705:                    fireRowAdded(rowKey);
0706:                    return rowKey;
0707:                } catch (Exception x) {
0708:                    throw new IllegalStateException(getBundle().getString(
0709:                            "OLDP_NOT_RESIZABLE")
0710:                            + ":" + x.getMessage());
0711:                }
0712:
0713:            }
0714:
0715:            /**
0716:             * <p>Append the specified object to the end of the list.</p>
0717:             *
0718:             * @param object Object to be appended
0719:             */
0720:            public RowKey appendRow(Object object) throws DataProviderException {
0721:
0722:                if (!userResizable) {
0723:                    throw new IllegalStateException(getBundle().getString(
0724:                            "OLDP_NOT_RESIZABLE"));
0725:                }
0726:                appends.add(object);
0727:                RowKey rowKey = getRowKey(list.size() + appends.size() - 1);
0728:                fireRowAdded(rowKey);
0729:                return rowKey;
0730:
0731:            }
0732:
0733:            /**
0734:             * <p>Return true if the <code>userResizable</code> property is set to
0735:             * <code>true</code>, and there is a public zero-args constructor for the
0736:             * class specified by the <code>objectType</code> property.</p>
0737:             *
0738:             * {@inheritDoc}
0739:             */
0740:            public boolean canInsertRow(RowKey beforeRow)
0741:                    throws DataProviderException {
0742:
0743:                // FIXME - inserts are not currently supported
0744:                return false;
0745:
0746:            }
0747:
0748:            /**
0749:             * <p>Construct a new instance of the specified object type and insert it
0750:             * at the specified position in the list.</p>
0751:             *
0752:             * @param beforeRow Row before which to insert the new row
0753:             *
0754:             * {@inheritDoc}
0755:             */
0756:            public RowKey insertRow(RowKey beforeRow)
0757:                    throws DataProviderException {
0758:
0759:                throw new UnsupportedOperationException();
0760:
0761:                /*
0762:                 * FIXME - inserts are not currently supported, and when they
0763:                 * are supported will need to be cached until commit or revert.
0764:                if (!canInsertRow(beforeRow)) {
0765:                    throw new IllegalStateException("This ObjectListDataProvider is not resizable.");
0766:                }
0767:                try {
0768:                    Constructor con = getObjectTypeConstructor();
0769:                    if (con != null) {
0770:                        Object o = con.newInstance(new Object[0]);
0771:                        if (o != null) {
0772:                            addObject(beforeRow, o);
0773:                            return beforeRow;
0774:                        }
0775:                    }
0776:                } catch (Exception x) {
0777:                    throw new IllegalStateException("This ObjectListDataProvider is not resizable: " + x.getMessage());
0778:                }
0779:                return null;
0780:                 */
0781:
0782:            }
0783:
0784:            /**
0785:             * <p>Return <code>true</code> if the <code>userResizable</code>
0786:             * property is set to <code>true</code>.</p>
0787:             *
0788:             * {@inheritDoc}
0789:             */
0790:            public boolean canRemoveRow(RowKey row)
0791:                    throws DataProviderException {
0792:
0793:                return userResizable;
0794:
0795:            }
0796:
0797:            /**
0798:             * <p>Remove the object at the specified row from the list.</p>
0799:             *
0800:             * {@inheritDoc}
0801:             */
0802:            public void removeRow(RowKey row) throws DataProviderException {
0803:
0804:                // Verify that we can actually remove this row
0805:                if (!canRemoveRow(row)) {
0806:                    throw new IllegalStateException(getBundle().getString(
0807:                            "OLDP_NOT_RESIZABLE")); // NOI18N
0808:                }
0809:                if (!isRowAvailable(row)) {
0810:                    throw new IllegalArgumentException(getBundle().getString(
0811:                            "CAN_NOT_DELETE_ROW_KEY")
0812:                            + row); // NOI18N
0813:                }
0814:
0815:                // Record the fact that we are going to delete this row
0816:                deletes.add(row);
0817:
0818:                // Fire appropriate events regarding this deletion
0819:                fireRowRemoved(row);
0820:                if (getCursorRow() == row) {
0821:                    fireValueChanged(null, list.get(getRowIndex(row)), null);
0822:                }
0823:
0824:            }
0825:
0826:            // --------------------------------------- TransactionalDataProvider Methods
0827:
0828:            /**
0829:             * <p>Cause any cached updates to existing field values, as well as
0830:             * inserted and deleted rows, to be flowed through to the underlying
0831:             * <code>List</code> wrapped by this
0832:             * {@link com.sun.data.provider.DataProvider}.</p>
0833:             */
0834:            public void commitChanges() throws DataProviderException {
0835:
0836:                // Commit all pending updates to the underlying list
0837:                Iterator rowUpdates = updates.entrySet().iterator();
0838:                while (rowUpdates.hasNext()) {
0839:                    Map.Entry rowUpdate = (Map.Entry) rowUpdates.next();
0840:                    RowKey rowKey = (RowKey) rowUpdate.getKey();
0841:                    int index = getRowIndex(rowKey);
0842:                    Object row = null;
0843:                    if (index < list.size()) {
0844:                        row = list.get(index);
0845:                    } else {
0846:                        row = appends.get(index - list.size());
0847:                    }
0848:                    Iterator fieldUpdates = ((Map) rowUpdate.getValue())
0849:                            .entrySet().iterator();
0850:                    while (fieldUpdates.hasNext()) {
0851:                        Map.Entry fieldUpdate = (Map.Entry) fieldUpdates.next();
0852:                        getSupport().setValue((FieldKey) fieldUpdate.getKey(),
0853:                                row, fieldUpdate.getValue());
0854:                    }
0855:                }
0856:                updates.clear();
0857:
0858:                // Commit all pending deletes to the underlying list
0859:                RowKey deletes[] = (RowKey[]) this .deletes
0860:                        .toArray(new RowKey[this .deletes.size()]);
0861:                for (int i = (deletes.length - 1); i >= 0; i--) {
0862:                    list.remove(getRowIndex(deletes[i]));
0863:                }
0864:                this .deletes.clear();
0865:
0866:                // FIXME - inserts will need to be interwoven to avoid indexing errors
0867:
0868:                // Commit all pending appends to the underlying list
0869:                Iterator appendInstances = appends.iterator();
0870:                while (appendInstances.hasNext()) {
0871:                    list.add(appendInstances.next());
0872:                }
0873:                appends.clear();
0874:
0875:                // Notify interested listeners that we have committed
0876:                fireChangesCommitted();
0877:
0878:            }
0879:
0880:            /** {@inheritDoc} */
0881:            public void revertChanges() throws DataProviderException {
0882:
0883:                // Erase any cached information about pending changes
0884:                updates.clear();
0885:                deletes.clear();
0886:                appends.clear();
0887:
0888:                // Notify interested listeners that we are reverting
0889:                fireChangesReverted();
0890:
0891:            }
0892:
0893:            /** {@inheritDoc} */
0894:            public void addTransactionalDataListener(
0895:                    TransactionalDataListener listener) {
0896:
0897:                super .addDataListener(listener);
0898:
0899:            }
0900:
0901:            /** {@inheritDoc} */
0902:            public TransactionalDataListener[] getTransactionalDataListeners() {
0903:
0904:                if (dpListeners == null) {
0905:                    return new TransactionalDataListener[0];
0906:                } else {
0907:                    ArrayList tdpList = new ArrayList();
0908:                    for (int i = 0; i < dpListeners.length; i++) {
0909:                        if (dpListeners[i] instanceof  TransactionalDataListener) {
0910:                            tdpList.add(dpListeners[i]);
0911:                        }
0912:                    }
0913:                    return (TransactionalDataListener[]) tdpList
0914:                            .toArray(new TransactionalDataListener[tdpList
0915:                                    .size()]);
0916:                }
0917:
0918:            }
0919:
0920:            /** {@inheritDoc} */
0921:            public void removeTransactionalDataListener(
0922:                    TransactionalDataListener listener) {
0923:
0924:                super .removeDataListener(listener);
0925:
0926:            }
0927:
0928:            // --------------------------------------------------------- Private Methods
0929:
0930:            /**
0931:             * <p>Fire a <code>changesCommitted</code> method to all registered
0932:             * listeners.</p>
0933:             */
0934:            private void fireChangesCommitted() {
0935:
0936:                TransactionalDataListener listeners[] = getTransactionalDataListeners();
0937:                for (int i = 0; i < listeners.length; i++) {
0938:                    listeners[i].changesCommitted(this );
0939:                }
0940:
0941:            }
0942:
0943:            /**
0944:             * <p>Fire a <code>changesReverted</code> method to all registered
0945:             * listeners.</p>
0946:             */
0947:            private void fireChangesReverted() {
0948:
0949:                TransactionalDataListener listeners[] = getTransactionalDataListeners();
0950:                for (int i = 0; i < listeners.length; i++) {
0951:                    listeners[i].changesReverted(this );
0952:                }
0953:
0954:            }
0955:
0956:            /**
0957:             * <p>Return the resource bundle containing our localized messages.</p>
0958:             */
0959:            private ResourceBundle getBundle() {
0960:
0961:                if (bundle == null) {
0962:                    bundle = ResourceBundle
0963:                            .getBundle("com/sun/data/provider/impl/Bundle");
0964:                }
0965:                return bundle;
0966:
0967:            }
0968:
0969:            /**
0970:             * <p>The zero-args public constructor for the <code>objectType</code>
0971:             * class (lazily instantiated by getObjectTypeConstructor(), marked
0972:             * as transient because Constructor instances are not Serializable).</p>
0973:             */
0974:            private transient Constructor objectTypeConstructor = null;
0975:
0976:            /**
0977:             * <p>Return the zero-arguments public constructor for the class
0978:             * specified by the <code>objectType</code> property, if there is one.</p>
0979:             */
0980:            private Constructor getObjectTypeConstructor() {
0981:
0982:                if (objectTypeConstructor != null) {
0983:                    return objectTypeConstructor;
0984:                }
0985:                try {
0986:                    Constructor con = objectType.getConstructor(new Class[0]);
0987:                    if ((con != null) && Modifier.isPublic(con.getModifiers())) {
0988:                        objectTypeConstructor = con;
0989:                    }
0990:                } catch (NoSuchMethodException e) {
0991:                    objectTypeConstructor = null;
0992:                }
0993:                return objectTypeConstructor;
0994:
0995:            }
0996:
0997:            /**
0998:             * <p>Return the row index corresponding to the specified row key.</p>
0999:             *
1000:             * @param rowKey Row key for which to extract an index
1001:             */
1002:            private int getRowIndex(RowKey rowKey) {
1003:
1004:                return ((IndexRowKey) rowKey).getIndex();
1005:
1006:            }
1007:
1008:            /**
1009:             * <p>Return a suitable {@link RowKey} for the specified row index.</p>
1010:             */
1011:            private RowKey getRowKey(int index) {
1012:
1013:                return new IndexRowKey(index);
1014:
1015:            }
1016:
1017:            /**
1018:             * <p>The cached support object for field key manipulation.  Must be
1019:             * transient because its content is not Serializable.</p>
1020:             */
1021:            private transient ObjectFieldKeySupport support = null;
1022:
1023:            /**
1024:             * <p>Return the {@link ObjectFieldKeySupport} instance for the
1025:             * object class we are wrapping.</p>
1026:             */
1027:            private ObjectFieldKeySupport getSupport() {
1028:
1029:                if ((support == null) && (objectType != null)) {
1030:                    support = new ObjectFieldKeySupport(objectType,
1031:                            includeFields);
1032:                }
1033:                return support;
1034:
1035:            }
1036:
1037:            /**
1038:             * <p>Calculate how many rows exist in the wrapped data.</p>
1039:             */
1040:            private int calculateRowCount() {
1041:                int currentRowCount = 0;
1042:                if (list != null) {
1043:                    currentRowCount = list.size() - deletes.size();
1044:                }
1045:                return currentRowCount;
1046:            }
1047:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.