Source Code Cross Referenced for FolderInstance.java in  » IDE-Netbeans » openide » org » openide » loaders » 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 » openide » org.openide.loaders 
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-2006 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 org.openide.loaders;
0043:
0044:        import java.beans.PropertyChangeListener;
0045:        import java.beans.PropertyChangeEvent;
0046:        import java.io.IOException;
0047:        import java.util.*;
0048:        import java.util.logging.Level;
0049:        import java.util.logging.Logger;
0050:
0051:        import org.openide.*;
0052:        import org.openide.filesystems.*;
0053:        import org.openide.cookies.InstanceCookie;
0054:        import org.openide.util.Task;
0055:        import org.openide.util.TaskListener;
0056:        import org.openide.util.RequestProcessor;
0057:        import org.openide.util.WeakListeners;
0058:
0059:        /** Support class for creation of an object from the content
0060:         * of a {@link DataObject.Container}. It implements
0061:         * {@link InstanceCookie}, so it
0062:         * can be used as a cookie for a node or data object.
0063:         * <P>
0064:         * When created on a container and started by invoking run method,
0065:         * it scans its content (in a separate
0066:         * thread) and creates a list of instances from which the new
0067:         * instance of this object should be composed. The object
0068:         * automatically listens to changes of components
0069:         * in the container, and if some change occurs, it allows the subclass to create
0070:         * a new object.
0071:         * </p>
0072:         *
0073:         * <p>Subclasses shall override the following methods:</p>
0074:         *
0075:         * <ol>
0076:         *  <li>{@link #createInstance(InstanceCookie[])} (required): this method is
0077:         *      called whenever the content has been changed. Its implementation
0078:         *      shall build up the data structures and perform the actions required
0079:         *      by this implementation.</li>
0080:         *  <li>The filter methods {@link #acceptDataObject(DataObject)}, {@link
0081:         *       #acceptCookie(InstanceCookie)},
0082:         *       {@link #acceptFolder(DataFolder)} and
0083:         *       {@link #acceptContainer(DataObject.Container)} (optional): the standard
0084:         *       way is to override one or several of the latter methods. Overriding
0085:         *       {@link #acceptDataObject(DataObject)} more deeply
0086:         *       modifies the default behavior, because the default implementation of
0087:         *       {@link #acceptDataObject(DataObject)} calls the
0088:         *       other 3 filter methods. See the method documentation for details.</li>
0089:         *  <li>The {@link InstanceCookie} methods 
0090:         *          {@link #instanceClass()} (optional but recommended)
0091:         *           to inform about the class implemented by the return value of
0092:         *          {@link #instanceCreate()}.</li>
0093:         *  <li>Advanced subclasses may need to override {@link #postCreationTask}
0094:         *      and/or {@link #instanceForCookie}, but it is not common to need these.</li>
0095:         * </ol>
0096:         *
0097:         * @author Jaroslav Tulach
0098:         */
0099:        public abstract class FolderInstance extends Task implements 
0100:                InstanceCookie { // XXX add generic type params?
0101:
0102:            /* -------------------------------------------------------------------- */
0103:            /* -- Constants ------------------------------------------------------- */
0104:            /* -------------------------------------------------------------------- */
0105:
0106:            /** a queue to run requests in */
0107:            private static final RequestProcessor PROCESSOR = new RequestProcessor(
0108:                    "Folder Instance Processor" // NOI18N
0109:            );
0110:
0111:            /** static variable to hold current value for callbacks to tasks 
0112:             * Also used to synchronize access to map field on.
0113:             */
0114:            private static final ThreadLocal<Object> CURRENT = new ThreadLocal<Object>();
0115:
0116:            /** The last finished folder instance in this thread. Works together
0117:             * with CURRENT, because sometimes more than one FolderInstance.instanceCreate
0118:             * can be called on the same thread.
0119:             */
0120:            private static final ThreadLocal<Object> LAST_CURRENT = new ThreadLocal<Object>();
0121:
0122:            /* -------------------------------------------------------------------- */
0123:            /* -- Instance attributes --------------------------------------------- */
0124:            /* -------------------------------------------------------------------- */
0125:
0126:            /** Folder to work with. Non null only if a constructor with DataFolder
0127:             * is used to construct this object.
0128:             */
0129:            protected DataFolder folder;
0130:
0131:            /** container to work with */
0132:            private DataObject.Container container;
0133:
0134:            /** map of primary file to their cookies (FileObject, HoldInstance) */
0135:            private HashMap<FileObject, HoldInstance> map = new HashMap<FileObject, HoldInstance>(
0136:                    17);
0137:
0138:            /** Array of tasks that we have to check before we are ok. These are the tasks
0139:             *  associated with children of the current folder.
0140:             */
0141:            private Task[] waitFor;
0142:
0143:            /** object for this cookie. Either the right instance of object or
0144:             * an instance of IOException or ClassNotFoundException. By default 
0145:             * it is assigned to some private object in this class to signal that
0146:             * it is uninitialized.
0147:             */
0148:            private Object object = CURRENT;
0149:
0150:            /** Listener and runner  for this object */
0151:            private Listener listener;
0152:
0153:            /** error manager for this instance */
0154:            private Logger err;
0155:
0156:            /** Task that computes the children list of the folder */
0157:            private Task recognizingTask;
0158:
0159:            /** A task that gets objects from InstanceCookie's and calls createInstance.
0160:             *  Started immediately after the <code>recognizingTask</code> is finished.
0161:             */
0162:            private Task creationTask;
0163:
0164:            /* -------------------------------------------------------------------- */
0165:            /* -- Constructor(s) -------------------------------------------------- */
0166:            /* -------------------------------------------------------------------- */
0167:
0168:            /** Create new folder instance.
0169:             * @param df data folder to create instances from
0170:             */
0171:            public FolderInstance(DataFolder df) {
0172:                this ((DataObject.Container) df);
0173:            }
0174:
0175:            /** A new object that listens on changes in a container.
0176:             * @param container the object to associate with
0177:             * @since 1.11
0178:             */
0179:            public FolderInstance(DataObject.Container container) {
0180:                this (container, null);
0181:            }
0182:
0183:            /** Constructs everything.
0184:             * @param container container
0185:             * @param logName the name to use for logging purposes
0186:             */
0187:            private FolderInstance(DataObject.Container container,
0188:                    String logName) {
0189:                if (container instanceof  DataFolder) {
0190:                    folder = (DataFolder) container;
0191:                    if (logName == null) {
0192:                        logName = folder.getPrimaryFile().getPath().replace(
0193:                                '/', '.');
0194:                    }
0195:                    container = FolderList.find(folder.getPrimaryFile(), true);
0196:                }
0197:
0198:                listener = new Listener();
0199:
0200:                if (logName == null) {
0201:                    logName = "org.openide.loaders.FolderInstance"; // NOI18N
0202:                } else {
0203:                    logName = "org.openide.loaders.FolderInstance" + '.'
0204:                            + logName; // NOI18N
0205:                }
0206:
0207:                err = Logger.getLogger(logName);
0208:
0209:                this .container = container;
0210:                container
0211:                        .addPropertyChangeListener(org.openide.util.WeakListeners
0212:                                .propertyChange(listener, container));
0213:
0214:                if (err.isLoggable(Level.FINE)) {
0215:                    err.fine("new " + this ); // NOI18N
0216:                }
0217:            }
0218:
0219:            /* -------------------------------------------------------------------- */
0220:            /* -- Implementation of org.openide.Cookies.InstanceCookie ------------ */
0221:            /* -------------------------------------------------------------------- */
0222:
0223:            /** The name of the class that we create.
0224:             * @return the name
0225:             */
0226:            public String instanceName() {
0227:                try {
0228:                    return instanceClass().getName();
0229:                } catch (java.io.IOException ex) {
0230:                    return "java.lang.Object"; // NOI18N
0231:                } catch (ClassNotFoundException ex) {
0232:                    return "java.lang.Object"; // NOI18N
0233:                }
0234:            }
0235:
0236:            /** Returns the root class of all objects.
0237:             * Supposed to be overriden in subclasses.
0238:             *
0239:             * @return Object.class
0240:             * @exception IOException an I/O error occured
0241:             * @exception ClassNotFoundException the class has not been found
0242:             */
0243:            public Class<?> instanceClass() throws java.io.IOException,
0244:                    ClassNotFoundException {
0245:                Object object = this .object;
0246:                if (object != null) {
0247:                    if (object instanceof  java.io.IOException) {
0248:                        throw (java.io.IOException) object;
0249:                    }
0250:                    if (object instanceof  ClassNotFoundException) {
0251:                        throw (ClassNotFoundException) object;
0252:                    }
0253:                    return object.getClass();
0254:                }
0255:
0256:                return Object.class;
0257:            }
0258:
0259:            /** Creates instance.
0260:             * @return an object to work with
0261:             * @exception IOException an I/O error occured
0262:             * @exception ClassNotFoundException the class has not been found
0263:             */
0264:            public Object instanceCreate() throws java.io.IOException,
0265:                    ClassNotFoundException {
0266:                Object object = CURRENT.get();
0267:
0268:                if (object == null || LAST_CURRENT.get() != this ) {
0269:                    err.fine("do into waitFinished"); // NOI18N
0270:                    waitFinished();
0271:
0272:                    object = FolderInstance.this .object;
0273:                }
0274:
0275:                if (err.isLoggable(Level.FINE)) {
0276:                    err.fine("instanceCreate: " + object); // NOI18N
0277:                }
0278:
0279:                if (object instanceof  java.io.IOException) {
0280:                    throw (java.io.IOException) object;
0281:                }
0282:                if (object instanceof  ClassNotFoundException) {
0283:                    throw (ClassNotFoundException) object;
0284:                }
0285:
0286:                if (object == CURRENT) {
0287:                    // uninitialized
0288:                    throw new IOException(
0289:                            "Cyclic reference. Somebody is trying to get value from FolderInstance ("
0290:                                    + getClass().getName()
0291:                                    + ") from the same thread that is processing the instance"); // NOI18N
0292:                }
0293:
0294:                return object;
0295:            }
0296:
0297:            /* -------------------------------------------------------------------- */
0298:            /* -- Wait ------------------------------------------------------------ */
0299:            /* -------------------------------------------------------------------- */
0300:
0301:            /** Wait for instance initialization to finish.
0302:             */
0303:            public final void instanceFinished() {
0304:                waitFinished();
0305:            }
0306:
0307:            /* -------------------------------------------------------------------- */
0308:            /* -- Extends org.openide.util.Task ----------------------------------- */
0309:            /* -------------------------------------------------------------------- */
0310:
0311:            /** Overrides the instance finished to deal with
0312:             * internal state correctly.
0313:             */
0314:            public @Override
0315:            void waitFinished() {
0316:                boolean isLog = err.isLoggable(Level.FINE);
0317:                for (;;) {
0318:                    err.fine("waitProcessingFinished on container"); // NOI18N
0319:                    waitProcessingFinished(container);
0320:
0321:                    Task originalRecognizing = checkRecognizingStarted();
0322:                    if (isLog) {
0323:                        err.fine("checkRecognizingStarted: "
0324:                                + originalRecognizing); // NOI18N
0325:                    }
0326:                    originalRecognizing.waitFinished();
0327:
0328:                    Task t = creationTask;
0329:                    if (isLog) {
0330:                        err.fine("creationTask: " + creationTask); // NOI18N
0331:                    }
0332:                    if (t != null) {
0333:                        t.waitFinished();
0334:                    }
0335:
0336:                    Task[] toWait = waitFor;
0337:                    if (isLog) {
0338:                        err.fine("toWait: " + toWait); // NOI18N
0339:                    }
0340:                    if (toWait != null) {
0341:                        for (int i = 0; i < toWait.length; i++) {
0342:                            if (isLog) {
0343:                                err.fine("  wait[" + i + "]: " + toWait[i]); // NOI18N
0344:                            }
0345:                            toWait[i].waitFinished();
0346:                        }
0347:                    }
0348:
0349:                    // loop if there was yet another task started to compute the
0350:                    // children list
0351:                    if (originalRecognizing == checkRecognizingStarted()) {
0352:                        if (isLog) {
0353:                            err.fine("breaking the wait loop"); // NOI18N
0354:                        }
0355:                        break;
0356:                    }
0357:
0358:                    //
0359:                    // otherwise go on an try it once more
0360:                    //
0361:                }
0362:            }
0363:
0364:            /** Synchronously starts the creation of the instance. */
0365:            public @Override
0366:            void run() {
0367:                recreate();
0368:                instanceFinished();
0369:            }
0370:
0371:            /* -------------------------------------------------------------------- */
0372:            /* -- Filter methods (protected, may be overridden by sub-classes) ---- */
0373:            /* -------------------------------------------------------------------- */
0374:
0375:            /** Allows subclasses to decide whether they want to work with the specified
0376:             * <code>DataObject</code> or not.
0377:             *
0378:             * <p>The default implementation roughly performs the following steps:</p>
0379:             *
0380:             * <ol>
0381:             *  <li>if <code>dob</code> has an <code>InstanceCookie</code>
0382:             *    {@link #acceptCookie(InstanceCookie)} is called on that cookie</li>
0383:             *  <li>if <code>dob</code> has a <code>DataFolder</code> cookie,
0384:             *    {@link #acceptFolder(DataFolder)} is called on that folder</li>
0385:             *  <li>if <code>dob</code> has a <code>DataObject.Container</code> cookie,
0386:             *    {@link #acceptContainer(DataObject.Container)} is called on that
0387:             *    container</li>
0388:             * </ol>
0389:             *
0390:             * <p>The first of the aforementioned steps which returns a non-<code>null</code>
0391:             *   cookie and does not throw an exception determines the return value. If
0392:             *   none of the steps succeeds, <code>null</code> is returned.</p>
0393:             *
0394:             * @param dob a <code>DataObject</code> to test
0395:             * @return the cookie for the <code>DataObject</code> or <code>null</code>
0396:             * if it should not be used
0397:             */
0398:            protected InstanceCookie acceptDataObject(DataObject dob) {
0399:                int acceptType = -1;
0400:
0401:                InstanceCookie cookie;
0402:                //Order of checking reversed first check cookie and then folder
0403:                // test if we accept the instance
0404:                cookie = dob.getCookie(InstanceCookie.class);
0405:                try {
0406:                    cookie = cookie == null ? null : acceptCookie(cookie);
0407:                    acceptType = 1;
0408:                } catch (IOException ex) {
0409:                    // an error during a call to acceptCookie
0410:                    err.log(Level.WARNING, null, ex);
0411:                    cookie = null;
0412:                } catch (ClassNotFoundException ex) {
0413:                    // an error during a call to acceptCookie
0414:                    err.log(Level.WARNING, null, ex);
0415:                    cookie = null;
0416:                }
0417:
0418:                if (cookie == null) {
0419:                    DataFolder folder = dob.getCookie(DataFolder.class);
0420:                    if (folder != null) {
0421:                        HoldInstance previous = map
0422:                                .get(folder.getPrimaryFile());
0423:                        if (previous != null && previous.cookie != null) {
0424:                            // the old cookie will be returned if the folder is already registered
0425:                            cookie = previous;
0426:                            acceptType = 2;
0427:                        } else {
0428:                            cookie = acceptFolder(folder);
0429:                            acceptType = 3;
0430:                        }
0431:                    }
0432:                }
0433:
0434:                if (cookie == null) {
0435:                    // try also the container
0436:                    DataObject.Container c = dob
0437:                            .getCookie(DataObject.Container.class);
0438:                    if (c != null) {
0439:                        cookie = acceptContainer(c);
0440:                        acceptType = 4;
0441:                    }
0442:                }
0443:
0444:                if (err.isLoggable(Level.FINE)) {
0445:                    err.fine("acceptDataObject: " + dob + " cookie: " + cookie
0446:                            + " acceptType: " + acceptType); // NOI18N
0447:                }
0448:
0449:                return cookie;
0450:            }
0451:
0452:            /** Allows subclasses to decide whether they want to work with
0453:             * the specified <code>InstanceCookie</code> or not.
0454:             * <p>The default implementation simply
0455:             * returns the same cookie, but subclasses may
0456:             * decide to return <code>null</code> or a different cookie.
0457:             * </p>
0458:             * <p>Compare {@link #acceptDataObject(DataObject)} to learn when this method
0459:             * is called.</p>
0460:             *
0461:             * @param cookie the instance cookie to test
0462:             * @return the cookie to use or <code>null</code> if this cookie should not
0463:             *    be used
0464:             * @exception IOException if an I/O error occurred calling a cookie method
0465:             * @exception ClassNotFoundException if a class is not found in a call to a cookie method
0466:             */
0467:            protected InstanceCookie acceptCookie(InstanceCookie cookie)
0468:                    throws java.io.IOException, ClassNotFoundException {
0469:                return cookie;
0470:            }
0471:
0472:            /** Allows subclasses to decide how they want to work with a
0473:             * provided folder.
0474:             *
0475:             * <p>The default implementation simply calls {@link #acceptContainer(DataObject.Container)}.</p>
0476:             *
0477:             * <p>A common override of this method is to return a new
0478:             * <code>FolderInstance</code> based on the subfolder, permitting
0479:             * recursion.</p>
0480:             *
0481:             * <p>Compare {@link #acceptDataObject(DataObject)} to learn when this method
0482:             * is called.</p>
0483:             *
0484:             * @param df data folder to create cookie for
0485:             * @return the cookie for this folder or <code>null</code> if this folder should not
0486:             *    be used
0487:             */
0488:            protected InstanceCookie acceptFolder(DataFolder df) {
0489:                return acceptContainer(df);
0490:            }
0491:
0492:            /** Allows subclasses to decide how they want to work with an object
0493:             * that implements a DataObject.Container.
0494:             * 
0495:             * <p>By default this returns <code>null</code> to indicated that subfolders
0496:             * (as well as {@link DataShadow}s, etc.) should be ignored.</p>
0497:             *
0498:             * <p>A common override of this method is to return a new
0499:             * <code>FolderInstance</code> based on the subfolder, permitting
0500:             * recursion.</p>
0501:             *
0502:             * <p>Compare {@link #acceptDataObject(DataObject)} to learn when this method
0503:             * is called.</p>
0504:             *
0505:             * @param container the container to accept or not
0506:             * @return cookie for this container or <code>null</code> if this object should
0507:             * be ignored
0508:             *
0509:             * @since 1.11
0510:             */
0511:            protected InstanceCookie acceptContainer(
0512:                    DataObject.Container container) {
0513:                return null;
0514:            }
0515:
0516:            /* ----------------------------------------------------------------------------- */
0517:            /* -- Instances creation method (protected, must be overridden by sub-classes) - */
0518:            /* ----------------------------------------------------------------------------- */
0519:
0520:            /** Notifies subclasses that the set of cookies for this folder
0521:             * has changed.
0522:             * A new object representing the folder should
0523:             * be created (or the old one updated).
0524:             * Called both upon initialization of the class, and change of its cookies.
0525:             *
0526:             * <p>It may be poor style for this method to have side-effects. A
0527:             * common way to use <code>FolderInstance</code> is to have this
0528:             * method set some global state which is then used as the resulting
0529:             * instance. Better is to treat the <code>FolderInstance</code> as
0530:             * pure SPI and assign it to a variable of type
0531:             * <code>InstanceCookie</code>. Then use the {@link
0532:             * #instanceCreate} method to get the final result. However in some
0533:             * cases there is a singleton live object which must be updated
0534:             * in-place, and it only makes sense to do so here (in which case
0535:             * the <code>InstanceCookie</code> methods are unused).</p>
0536:             *
0537:             * @param cookies updated array of instance cookies for the folder
0538:             * @return object to represent these cookies
0539:             *
0540:             * @exception IOException an I/O error occured
0541:             * @exception ClassNotFoundException a class has not been found
0542:             */
0543:            protected abstract Object createInstance(InstanceCookie[] cookies)
0544:                    throws java.io.IOException, ClassNotFoundException;
0545:
0546:            /* ----------------------------------------------------------------------------- */
0547:            /* -- Instances creation method (protected, may be overridden by sub-classes) - */
0548:            /* ----------------------------------------------------------------------------- */
0549:
0550:            /** Method that is called when a the folder instance really wants to
0551:             * create an object from provided cookie.
0552:             * It allows subclasses to overwrite the default behaviour (which is
0553:             * to call {@link InstanceCookie#instanceCreate}).
0554:             *
0555:             * @param obj the data object that is the source of the cookie
0556:             * @param cookie the instance cookie to read the instance from
0557:             * @exception IOException when there I/O error
0558:             * @exception ClassNotFoundException if the class cannot be found
0559:             */
0560:            protected Object instanceForCookie(DataObject obj,
0561:                    InstanceCookie cookie) throws IOException,
0562:                    ClassNotFoundException {
0563:                return cookie.instanceCreate();
0564:            }
0565:
0566:            /* ----------------------------------------------------------------------------- */
0567:            /* -- Recreation --------------------------------------------------------------- */
0568:            /* ----------------------------------------------------------------------------- */
0569:
0570:            /** Starts recreation of the instance in special thread.
0571:             */
0572:            public synchronized void recreate() {
0573:                // this method should be synchronized so the recognizingTask is created
0574:                // together with notification that we are running.
0575:                // Fix of #16136 => sometimes it happened that the thread started in 
0576:                // the recognizer task was finished sooner then notifyRunning called.
0577:                // In such case notifyFinished could be called before notifyRunning 
0578:                // and everything was completely broken
0579:                err.fine("recreate");
0580:                recognizingTask = computeChildrenList(container, listener);
0581:                if (err.isLoggable(Level.FINE)) {
0582:                    err.fine("  recognizing task is now " + recognizingTask);
0583:                }
0584:                notifyRunning();
0585:            }
0586:
0587:            /** Checks whether recreation of this instance is running already 
0588:             * and in that case does nothing, otherwise calls 
0589:             * {@link #recreate() recreate} method.
0590:             * This prevents from redundant recreation tasks of this instance caused by 
0591:             * first creation of underlying items which are also of {@link org.openide.util.Task Task}
0592:             * type (e.g. sub-FolderInstances, sub-FolderLookups etc.). */
0593:            final void checkRecreate() {
0594:                if (isFinished()) {
0595:                    recreate();
0596:                }
0597:            }
0598:
0599:            /** Checks whether recreation has already started and starts it if if was
0600:             *  was not yet started during the live of this <code>FolderInstance</code>.
0601:             * @return the latest started task for children computation */
0602:            private final synchronized Task checkRecognizingStarted() {
0603:                if (recognizingTask == null) {
0604:                    recreate();
0605:                }
0606:
0607:                return recognizingTask;
0608:            }
0609:
0610:            /* ----------------------------------------------------------------------------- */
0611:            /* -- Static helper methods (abstract away the differences between different --- */
0612:            /* ------------------------- DataObject.Container types) ----------------------- */
0613:            /* ----------------------------------------------------------------------------- */
0614:
0615:            /** Waits until the task to compute the children of the currents folder is
0616:             * finished. This methods provides a unified interface which allows to
0617:             * treat <code>FolderList</code>s and general <code>DataObject.Container</code>s
0618:             * is a uniform way.
0619:             */
0620:            private static void waitProcessingFinished(DataObject.Container c) {
0621:                if (c instanceof  FolderList) {
0622:                    ((FolderList) c).waitProcessingFinished();
0623:                }
0624:            }
0625:
0626:            /** Starts and returns the task to compute the children of the current
0627:             * folder. This methods provides a unified interface which allows to
0628:             * treat <code>FolderList</code>s and general <code>DataObject.Container</code>s
0629:             * is a uniform way.
0630:             *
0631:             * <p>The task returned uses the {@link #listener} to process the children.</p>
0632:             */
0633:            private static Task computeChildrenList(
0634:                    final DataObject.Container container,
0635:                    final FolderListListener listener) {
0636:                if (container instanceof  FolderList) {
0637:                    FolderList list = (FolderList) container;
0638:                    return list.computeChildrenList(listener);
0639:                }
0640:
0641:                // otherwise we have to simulate the listener by container methods
0642:                // itself
0643:                return PROCESSOR.post(new Runnable() {
0644:                    public void run() {
0645:                        DataObject[] arr = container.getChildren();
0646:                        ArrayList<DataObject> list = new ArrayList<DataObject>(
0647:                                arr.length);
0648:                        for (int i = 0; i < arr.length; i++) {
0649:                            listener.process(arr[i], list);
0650:                        }
0651:                        listener.finished(list);
0652:                    }
0653:                });
0654:            }
0655:
0656:            /* ----------------------------------------------------------------------------- */
0657:            /* -- Processing --------------------------------------------------------------- */
0658:            /* ----------------------------------------------------------------------------- */
0659:
0660:            /** A method that starts <code>creationTask</code>, the task which really
0661:             *  creates the instances from given objects. The task is started by a
0662:             * call to {@link #postCreationTask(Runnable)}.
0663:             * 
0664:             * @param arr collection of DataObjects
0665:             */
0666:            final void processObjects(final Collection<DataObject> arr) {
0667:                creationTask = postCreationTask(new Runnable() {
0668:                    public void run() {
0669:                        defaultProcessObjects(arr);
0670:                    }
0671:                });
0672:            }
0673:
0674:            /** Default processing of objects.
0675:             * @param arr array of objects to process
0676:             */
0677:            private final void defaultProcessObjects(Collection<DataObject> arr) {
0678:                err.fine("defaultProcessObjects");
0679:                HashSet<FileObject> toRemove;
0680:                ArrayList<HoldInstance> cookies = new ArrayList<HoldInstance>();
0681:
0682:                // synchronized for safe access to map field
0683:                synchronized (CURRENT) {
0684:                    toRemove = new HashSet<FileObject>(map.keySet());
0685:                }
0686:
0687:                for (DataObject obj : arr) {
0688:                    if (!obj.isValid()) {
0689:                        // #12960: skip over it, probably invalidated while we were
0690:                        // waiting for this task to be run...
0691:                        continue;
0692:                    }
0693:
0694:                    // testing
0695:                    InstanceCookie cookie = acceptDataObject(obj);
0696:                    if (cookie != null) {
0697:                        // cookie accepted
0698:                        FileObject fo = obj.getPrimaryFile();
0699:
0700:                        boolean attachListener = true;
0701:                        HoldInstance prevCookie = null;
0702:                        if (toRemove.remove(fo)) {
0703:                            // if the fo is in the map than try to find its cookie
0704:                            prevCookie = map.get(fo);
0705:                            if (prevCookie != null
0706:                                    && (prevCookie.cookie == null || !prevCookie.cookie
0707:                                            .equals(cookie))) {
0708:                                prevCookie = null;
0709:                                // #49199 - do not add second listener
0710:                                attachListener = false;
0711:                            }
0712:                        }
0713:
0714:                        if (prevCookie == null) {
0715:                            // such cookie is not there yet
0716:                            HoldInstance hold;
0717:
0718:                            if (cookie instanceof  HoldInstance) {
0719:                                hold = (HoldInstance) cookie;
0720:                            } else {
0721:                                hold = new HoldInstance(obj, cookie);
0722:                            }
0723:
0724:                            // synchronized for safe access to map field
0725:                            synchronized (CURRENT) {
0726:                                map.put(fo, hold);
0727:                            }
0728:
0729:                            // register for changes of PROP_COOKIE property
0730:                            if (attachListener) {
0731:                                obj
0732:                                        .addPropertyChangeListener(org.openide.util.WeakListeners
0733:                                                .propertyChange(listener, obj));
0734:                            }
0735:
0736:                            cookies.add(hold);
0737:                        } else {
0738:                            // old cookie, already there => only add it to the list of cookies
0739:                            cookies.add(prevCookie);
0740:                        }
0741:                    } else {
0742:                        // empty instance placeholder
0743:                        synchronized (CURRENT) {
0744:                            FileObject fo = obj.getPrimaryFile();
0745:                            toRemove.remove(fo);
0746:
0747:                            HoldInstance hold = map.get(fo);
0748:                            if (hold != null && hold.cookie == null) {
0749:                                // already registered do not do any changes
0750:                                continue;
0751:                            }
0752:
0753:                            // not yet registered, add new
0754:
0755:                            hold = new HoldInstance(obj, null);
0756:
0757:                            map.put(fo, hold);
0758:                        }
0759:
0760:                        // register for changes of PROP_COOKIE property
0761:                        obj
0762:                                .addPropertyChangeListener(org.openide.util.WeakListeners
0763:                                        .propertyChange(listener, obj));
0764:
0765:                    }
0766:
0767:                }
0768:
0769:                // synchronized for safe access to map field
0770:                synchronized (CURRENT) {
0771:                    // now remove the cookies that are no longer in the folder
0772:                    map.keySet().removeAll(toRemove);
0773:                }
0774:
0775:                // create the list of cookies
0776:                HoldInstance[] all = new HoldInstance[cookies.size()];
0777:                cookies.toArray(all);
0778:
0779:                updateWaitFor(all);
0780:
0781:                Object result = null;
0782:                try {
0783:                    result = createInstance(all);
0784:                } catch (IOException ex) {
0785:                    result = ex;
0786:                } catch (ClassNotFoundException ex) {
0787:                    result = ex;
0788:                } finally {
0789:                    if (err.isLoggable(Level.FINE)) {
0790:                        err.fine("notifying finished"); // NOI18N
0791:                        for (int log = 0; log < all.length; log++) {
0792:                            err.fine("  #" + log + ": " + all[log]); // NOI18N
0793:                        }
0794:                    }
0795:                    object = result;
0796:
0797:                    Object prevResult = CURRENT.get();
0798:                    CURRENT.set(result);
0799:                    Object prevLast = LAST_CURRENT.get();
0800:                    LAST_CURRENT.set(this );
0801:
0802:                    try {
0803:                        notifyFinished();
0804:                    } finally {
0805:                        CURRENT.set(prevResult);
0806:                        LAST_CURRENT.set(prevLast);
0807:                    }
0808:                }
0809:            }
0810:
0811:            /** Recomputes the list of tasks we should wait for (i.e. the tasks associated
0812:             *  with the children of the folder).
0813:             */
0814:            private void updateWaitFor(HoldInstance[] arr) {
0815:                ArrayList<Task> out = new ArrayList<Task>(arr.length);
0816:                for (int i = 0; i < arr.length; i++) {
0817:                    Task t = arr[i].getTask();
0818:                    if (t != null) {
0819:                        out.add(t);
0820:                    }
0821:                }
0822:                waitFor = out.toArray(new Task[out.size()]);
0823:            }
0824:
0825:            /* ----------------------------------------------------------------------------- */
0826:            /* -- Processing: Start the creation task (protected, may be overridden) ------- */
0827:            /* ----------------------------------------------------------------------------- */
0828:
0829:            /** Invokes the creation of objects in a "safe" thread. This method is
0830:             * for expert subclasses that want to control the thread that the 
0831:             * instance is created in.
0832:             *
0833:             * <p>The default implementation invokes the creation logic in the
0834:             * request processor in non-blocking mode (no other tasks will
0835:             * block on this).</p>
0836:             *
0837:             * @param run runnable to run
0838:             * @return task to control the execution of the runnable or null if 
0839:             *    the runnable is run immediatelly
0840:             * @since 1.5
0841:             */
0842:            protected Task postCreationTask(Runnable run) {
0843:                return PROCESSOR.post(run);
0844:            }
0845:
0846:            /* ----------------------------------------------------------------------------- */
0847:            /* -- Getters ------------------------------------------------------------------ */
0848:            /* ----------------------------------------------------------------------------- */
0849:
0850:            /** Access to error manager for FolderLookup.
0851:             */
0852:            final Logger err() {
0853:                return err;
0854:            }
0855:
0856:            public @Override
0857:            String toString() {
0858:                return getClass().getName() + "@"
0859:                        + Integer.toHexString(System.identityHashCode(this ))
0860:                        + "(" + this .container + ")"; // NOI18N
0861:            }
0862:
0863:            /* -------------------------------------------------------------------- */
0864:            /* -- Inner class Listener -------------------------------------------- */
0865:            /* -------------------------------------------------------------------- */
0866:
0867:            /** Listener on change of folder's children and a starter for the task.
0868:             *
0869:             * <p>Each instance of {@link FolderInstance} has one instance of this class
0870:             *  associated with it. The latter serves for three purposes:</p>
0871:             *
0872:             * <ol>
0873:             *   <li>to listen for property changes of the {@link DataObject.Container}
0874:             *        this {@link FolderInstance} was created for (by implementing
0875:             *        {@link java.beans.PropertyChangeListener})</li>
0876:             *    <li>to listen for changes of the cookies of the children of this folder</li>
0877:             *   <li>to process the results of the computation of a child list
0878:             *      (by implementing {@link FolderListListener#finished(java.util.List)})
0879:             *   </li>
0880:             * </ol>
0881:             */
0882:            private class Listener implements  PropertyChangeListener,
0883:                    FolderListListener {
0884:
0885:                Listener() {
0886:                }
0887:
0888:                /** Recreates the {@link FolderInstance} if the children list of
0889:                 *  its container was changed.
0890:                 *
0891:                 * <p>Additionally ...</p>
0892:                 */
0893:                public void propertyChange(PropertyChangeEvent ev) {
0894:                    Object s = ev.getSource();
0895:                    if (s == container) {
0896:                        if (DataObject.Container.PROP_CHILDREN.equals(ev
0897:                                .getPropertyName())) {
0898:                            err.fine("PROP_CHILDREN");
0899:
0900:                            recreate();
0901:                        }
0902:                        return;
0903:                    }
0904:
0905:                    if (DataObject.PROP_NAME.equals(ev.getPropertyName())) {
0906:                        if (s instanceof  DataObject) {
0907:                            err.fine("PROP_NAME");
0908:                            recreate();
0909:                        }
0910:                    }
0911:
0912:                    // change of cookie in one of children of the container
0913:
0914:                    if (DataObject.PROP_COOKIE.equals(ev.getPropertyName())) {
0915:                        if (s instanceof  DataObject) {
0916:                            DataObject source = (DataObject) s;
0917:                            err.fine("PROP_COOKIE: " + source); // NOI18N
0918:
0919:                            InstanceCookie ic = acceptDataObject(source);
0920:
0921:                            HoldInstance hi;
0922:                            FileObject fo = source.getPrimaryFile();
0923:                            synchronized (CURRENT) {
0924:                                hi = map.get(fo);
0925:                            }
0926:
0927:                            if (hi != null) {
0928:                                err.fine("previous instance: " + hi
0929:                                        + " new instance " + ic); // NOI18N
0930:                                /* Recreate if the new instance cookie is null or differs
0931:                                 * from the previous one.
0932:                                 * When the default implementation of acceptDataObject is
0933:                                 * used ic == hi is the case if source is a folder.
0934:                                 * [XXX] Why not:
0935:                                 * if ((ic == null && hi.cookie != null) || (ic != hi && !ic.equals (hi.cookie))) { 
0936:                                 */
0937:                                if (ic == null
0938:                                        || (ic != hi && !ic.equals(hi.cookie))) {
0939:                                    hi = new HoldInstance(source, ic);
0940:
0941:                                    // synchronized for safe access to map field
0942:                                    synchronized (CURRENT) {
0943:                                        map.put(fo, hi);
0944:                                    }
0945:                                    recreate();
0946:                                }
0947:                            }
0948:                        }
0949:                    }
0950:                }
0951:
0952:                /** Callback for object processing after all children are computed.
0953:                 *  This implementation starts a new task for the creation of the
0954:                 *  child objects.
0955:                 * @param arr list of DataObjects
0956:                 */
0957:                public void finished(java.util.List<DataObject> arr) {
0958:                    processObjects(arr);
0959:                }
0960:
0961:                /** Default implementation without filtering.
0962:                 * @param obj the object recognized
0963:                 * @param arr array where the implementation should add the 
0964:                 *   object
0965:                 */
0966:                public void process(DataObject obj,
0967:                        java.util.List<DataObject> arr) {
0968:                    arr.add(obj);
0969:                }
0970:
0971:            }
0972:
0973:            /* -------------------------------------------------------------------- */
0974:            /* -- Inner class HoldInstance ---------------------------------------- */
0975:            /* -------------------------------------------------------------------- */
0976:
0977:            /** A instance cookie that holds the result of first
0978:             * invocation of the provided cookie.
0979:             *
0980:             */
0981:            private class HoldInstance extends Object implements 
0982:                    InstanceCookie.Of, TaskListener {
0983:                /** the data object -> source of this instance */
0984:                private final DataObject source;
0985:                /** the cookie to delegate to */
0986:                protected final InstanceCookie cookie;
0987:
0988:                public HoldInstance(DataObject source, InstanceCookie cookie) {
0989:                    this .cookie = cookie;
0990:                    this .source = source;
0991:
0992:                    if (cookie instanceof  Task) {
0993:                        // for example FolderInstance ;-) attach itself for changes
0994:                        // in the cookie
0995:                        Task t = (Task) cookie;
0996:                        t.addTaskListener(WeakListeners.create(
0997:                                TaskListener.class, this , t));
0998:                    }
0999:                }
1000:
1001:                /** Full name of the data folder's primary file separated by dots.
1002:                 * @return the name
1003:                 */
1004:                public String instanceName() {
1005:                    return cookie.instanceName();
1006:                }
1007:
1008:                /** Query to find out if the object created by this cookie is 
1009:                 * instance of given type. The same code as:
1010:                 * <pre>
1011:                 *   Class actualClass = instanceClass ();
1012:                 *   result = type.isAsignableFrom (actualClass);
1013:                 * </pre>
1014:                 * But this can prevent the class <code>actualClass</code> to be
1015:                 * loaded into the <em>JavaVM</em>.
1016:                 *
1017:                 * @param type the class type we want to check
1018:                 * @return true if this cookie can produce object of given type
1019:                 */
1020:                public boolean instanceOf(Class<?> type) {
1021:                    if (cookie instanceof  InstanceCookie.Of) {
1022:                        InstanceCookie.Of of = (InstanceCookie.Of) cookie;
1023:                        return of.instanceOf(type);
1024:                    }
1025:                    // delegate
1026:                    try {
1027:                        Class<?> clazz = cookie.instanceClass();
1028:                        return type.isAssignableFrom(clazz);
1029:                    } catch (IOException ex) {
1030:                        return false;
1031:                    } catch (ClassNotFoundException ex) {
1032:                        return false;
1033:                    }
1034:                }
1035:
1036:                /** Returns the root class of all objects.
1037:                 * Supposed to be overriden in subclasses.
1038:                 *
1039:                 * @return Object.class
1040:                 * @exception IOException an I/O error occured
1041:                 * @exception ClassNotFoundException the class has not been found
1042:                 */
1043:                public Class instanceClass() throws java.io.IOException,
1044:                        ClassNotFoundException {
1045:                    return cookie.instanceClass();
1046:                }
1047:
1048:                /**
1049:                 * @return an object to work with
1050:                 * @exception IOException an I/O error occured
1051:                 * @exception ClassNotFoundException the class has not been found
1052:                 */
1053:                public Object instanceCreate() throws java.io.IOException,
1054:                        ClassNotFoundException {
1055:                    return instanceForCookie(source, cookie);
1056:                }
1057:
1058:                /** Called when a task finishes running.
1059:                 * @param task the finished task
1060:                 */
1061:                public void taskFinished(Task task) {
1062:                    checkRecreate();
1063:                }
1064:
1065:                /** Waits till the instance is ready.
1066:                 */
1067:                public Task getTask() {
1068:                    if (cookie instanceof  Task) {
1069:                        // for example FolderInstance ;-) attach itself for changes
1070:                        // in the cookie
1071:                        return (Task) cookie;
1072:                    } else {
1073:                        return null;
1074:                    }
1075:                }
1076:            } // end of HoldInstance
1077:
1078:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.