Source Code Cross Referenced for MultiDataObject.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.PropertyVetoException;
0045:        import java.io.*;
0046:        import java.lang.ref.WeakReference;
0047:        import java.util.*;
0048:        import java.util.logging.*;
0049:        import javax.swing.event.*;
0050:        import org.openide.filesystems.*;
0051:        import org.openide.nodes.*;
0052:        import org.openide.util.*;
0053:
0054:        /** Provides support for handling of data objects with multiple files.
0055:         * One file is represented by one {@link Entry}. Each handler
0056:         * has one {@link #getPrimaryEntry primary} entry and zero or more secondary entries.
0057:         *
0058:         * @author Ales Novak, Jaroslav Tulach, Ian Formanek
0059:         */
0060:        public class MultiDataObject extends DataObject {
0061:            /** generated Serialized Version UID */
0062:            static final long serialVersionUID = -7750146802134210308L;
0063:
0064:            /** Synchronization object used in getCookieSet and setCookieSet methods.
0065:             */
0066:            private static final Object cookieSetLock = new Object();
0067:
0068:            /** Lock used for lazy creation of secondary field (in method getSecondary()) */
0069:            private static final Object secondaryCreationLock = new Object();
0070:
0071:            /** A RequestProceccor used for firing property changes asynchronously */
0072:            private static final RequestProcessor firingProcessor = new RequestProcessor(
0073:                    "MDO PropertyChange processor");
0074:
0075:            /** A RequestProceccor used for waiting for finishing refresh */
0076:            private static final RequestProcessor delayProcessor = new RequestProcessor(
0077:                    "MDO Firing delayer");
0078:            /** a task waiting for the FolderList task to finish scanning of the folder */
0079:            private RequestProcessor.Task delayedPropFilesTask;
0080:            /** lock used in firePropFilesAfterFinishing */
0081:            private static final Object delayedPropFilesLock = new Object();
0082:            /** logging of operations in multidataobject */
0083:            static final Logger ERR = Logger.getLogger(MultiDataObject.class
0084:                    .getName());
0085:
0086:            /** getPrimaryEntry() is intended to have all inetligence for copy/move/... */
0087:            private Entry primary;
0088:
0089:            /** Map of secondary entries and its files. (FileObject, Entry) */
0090:            private HashMap<FileObject, Entry> secondary;
0091:
0092:            /** array of cookies for this object */
0093:            private CookieSet cookieSet;
0094:
0095:            /** flag when to call checkFiles(this) */
0096:            boolean checked = false;
0097:
0098:            /** Create a MultiFileObject.
0099:             * @see DataObject#DataObject(org.openide.filesystems.FileObject,org.openide.loaders.DataLoader)
0100:             * @param fo the primary file object
0101:             * @param loader loader of this data object
0102:             */
0103:            public MultiDataObject(FileObject fo, MultiFileLoader loader)
0104:                    throws DataObjectExistsException {
0105:                super (fo, loader);
0106:                primary = createPrimaryEntry(this , getPrimaryFile());
0107:            }
0108:
0109:            /** This constructor is added for backward compatibility, MultiDataObject should be
0110:             * properly constructed using the MultiFileLoader.
0111:             * @param fo the primary file object
0112:             * @param loader loader of this data object
0113:             * @deprecated do not use this constructor, it is for backward compatibility of 
0114:             * {@link #DataShadow} and {@link #DataFolder} only
0115:             * @since 1.13
0116:             */
0117:            @Deprecated
0118:            MultiDataObject(FileObject fo, DataLoader loader)
0119:                    throws DataObjectExistsException {
0120:                super (fo, loader);
0121:                primary = createPrimaryEntry(this , getPrimaryFile());
0122:            }
0123:
0124:            /** Getter for the multi file loader that created this
0125:             * object.
0126:             *
0127:             * @return the multi loader for the object
0128:             */
0129:            public final MultiFileLoader getMultiFileLoader() {
0130:                DataLoader loader = getLoader();
0131:
0132:                if (!(loader instanceof  MultiFileLoader))
0133:                    return null;
0134:
0135:                return (MultiFileLoader) loader;
0136:            }
0137:
0138:            @Override
0139:            public Set<FileObject> files() {
0140:                // move lazy initialization to FilesSet
0141:                return new FilesSet(this );
0142:            }
0143:
0144:            /* Getter for delete action.
0145:             * @return true if the object can be deleted
0146:             */
0147:            public boolean isDeleteAllowed() {
0148:                return !getPrimaryFile().isReadOnly()
0149:                        && !existReadOnlySecondary();
0150:            }
0151:
0152:            private boolean existReadOnlySecondary() {
0153:                synchronized (synchObjectSecondary()) {
0154:                    for (FileObject f : getSecondary().keySet()) {
0155:                        if (f.isReadOnly()) {
0156:                            return true;
0157:                        }
0158:                    }
0159:                }
0160:                return false;
0161:            }
0162:
0163:            /** Performs checks by calling checkFiles
0164:             * @return getSecondary() method result
0165:             */
0166:            private Map<FileObject, Entry> checkSecondary() {
0167:                // enumeration of all files
0168:                if (!checked) {
0169:                    checkFiles(this );
0170:                    checked = true;
0171:                }
0172:                return getSecondary();
0173:            }
0174:
0175:            /** Lazy getter for secondary property
0176:             * @return secondary object
0177:             */
0178:            /* package-private */Map<FileObject, Entry> getSecondary() {
0179:                synchronized (secondaryCreationLock) {
0180:                    if (secondary == null) {
0181:                        secondary = new HashMap<FileObject, Entry>(4);
0182:                    }
0183:                    if (ERR.isLoggable(Level.FINE)) {
0184:                        ERR.fine("getSecondary for " + this  + " is "
0185:                                + secondary); // NOI18N
0186:                    }
0187:                    return secondary;
0188:                }
0189:            }
0190:
0191:            /* Getter for copy action.
0192:             * @return true if the object can be copied
0193:             */
0194:            public boolean isCopyAllowed() {
0195:                return true;
0196:            }
0197:
0198:            /* Getter for move action.
0199:             * @return true if the object can be moved
0200:             */
0201:            public boolean isMoveAllowed() {
0202:                return !getPrimaryFile().isReadOnly()
0203:                        && !existReadOnlySecondary();
0204:            }
0205:
0206:            /* Getter for rename action.
0207:             * @return true if the object can be renamed
0208:             */
0209:            public boolean isRenameAllowed() {
0210:                return !getPrimaryFile().isReadOnly()
0211:                        && !existReadOnlySecondary();
0212:            }
0213:
0214:            /* Help context for this object.
0215:             * @return help context
0216:             */
0217:            public HelpCtx getHelpCtx() {
0218:                return HelpCtx.DEFAULT_HELP;
0219:            }
0220:
0221:            /** Provide object used for synchronization of methods working with 
0222:             * Secondaries.
0223:             * @return The private field <CODE>secondary</CODE>.
0224:             */
0225:            Object synchObjectSecondary() {
0226:                Object lock = checkSecondary();
0227:                if (lock == null)
0228:                    throw new IllegalStateException(
0229:                            "checkSecondary was null from " + this ); // NOI18N
0230:                return checkSecondary();
0231:            }
0232:
0233:            /** Provides node that should represent this data object.
0234:             *
0235:             * @return the node representation
0236:             * @see DataNode
0237:             */
0238:            protected Node createNodeDelegate() {
0239:                DataNode dataNode = (DataNode) super .createNodeDelegate();
0240:                return dataNode;
0241:            }
0242:
0243:            /** Add a new secondary entry to the list.
0244:             * @param fe the entry to add
0245:             */
0246:            protected final void addSecondaryEntry(Entry fe) {
0247:                synchronized (getSecondary()) {
0248:                    getSecondary().put(fe.getFile(), fe);
0249:                    if (ERR.isLoggable(Level.FINE)) {
0250:                        ERR.fine("addSecondaryEntry: " + fe + " for " + this ); // NOI18N
0251:                    }
0252:                }
0253:
0254:                // Fire PROP_FILES only if we have actually finished making the folder.
0255:                // It is dumb to fire this if we do not yet even know what all of our
0256:                // initial secondary files are going to be.
0257:                FolderList l = getFolderList();
0258:                if (l == null) {
0259:                    firePropertyChangeLater(PROP_FILES, null, null);
0260:                } else { // l != null
0261:                    if (l.isCreated()) {
0262:                        firePropertyChangeLater(PROP_FILES, null, null);
0263:                    } else {
0264:                        firePropFilesAfterFinishing();
0265:                    }
0266:                }
0267:            }
0268:
0269:            /** Finds FolderList object for the primary file's parent folder
0270:             * @return FolderList object or <code>null</code>
0271:             */
0272:            private FolderList getFolderList() {
0273:                FileObject parent = primary.file.getParent();
0274:                if (parent != null) {
0275:                    return FolderList.find(parent, false);
0276:                }
0277:                return null;
0278:            }
0279:
0280:            /** Remove a secondary entry from the list.
0281:             * @param fe the entry to remove
0282:             */
0283:            protected final void removeSecondaryEntry(Entry fe) {
0284:                synchronized (getSecondary()) {
0285:                    getSecondary().remove(fe.getFile());
0286:                    if (ERR.isLoggable(Level.FINE)) {
0287:                        ERR
0288:                                .fine("removeSecondaryEntry: " + fe + " for "
0289:                                        + this ); // NOI18N
0290:                    }
0291:                }
0292:
0293:                firePropertyChangeLater(PROP_FILES, null, null);
0294:                updateFilesInCookieSet();
0295:
0296:                if (fe.isImportant()) {
0297:                    checkConsistency(this );
0298:                }
0299:            }
0300:
0301:            /** All secondary entries are recognized. Called from multi file object.
0302:             * @param recognized object to mark recognized file to
0303:             */
0304:            final void markSecondaryEntriesRecognized(
0305:                    DataLoader.RecognizedFiles recognized) {
0306:                synchronized (getSecondary()) {
0307:                    for (FileObject fo : getSecondary().keySet()) {
0308:                        recognized.markRecognized(fo);
0309:                    }
0310:                }
0311:            }
0312:
0313:            /** Tests whether this file is between entries and if not,
0314:             * creates a secondary entry for it and adds it into set of
0315:             * secondary entries.
0316:             * <P>
0317:             * This method should be used in constructor of MultiDataObject to
0318:             * register all the important files, that could belong to this data object.
0319:             * As example, our XMLDataObject, tries to locate its <CODE>xmlinfo</CODE>
0320:             * file and then do register it
0321:             *
0322:             * @param fo the file to register (can be null, then the action is ignored)
0323:             * @return the entry associated to this file object (returns primary entry if the fo is null)
0324:             */
0325:            protected final Entry registerEntry(FileObject fo) {
0326:                synchronized (getSecondary()) {
0327:                    if (fo == null) {
0328:                        // is it ok, to do this or somebody would like to see different behavour?
0329:                        return primary;
0330:                    }
0331:                    if (fo.equals(getPrimaryFile())) {
0332:                        return primary;
0333:                    }
0334:
0335:                    Entry e = getSecondary().get(fo);
0336:                    if (e != null) {
0337:                        return e;
0338:                    }
0339:
0340:                    // add it into set of entries
0341:                    e = createSecondaryEntry(this , fo);
0342:                    addSecondaryEntry(e);
0343:
0344:                    return e;
0345:                }
0346:            }
0347:
0348:            /** Removes the entry from the set of secondary entries.
0349:             * Called from the notifyFileDeleted
0350:             */
0351:            final void removeFile(FileObject fo) {
0352:                synchronized (getSecondary()) {
0353:                    Entry e = getSecondary().get(fo);
0354:                    if (e != null) {
0355:                        removeSecondaryEntry(e);
0356:                    }
0357:                }
0358:            }
0359:
0360:            /** Get the primary entry.
0361:             * @return the entry
0362:             */
0363:            public final Entry getPrimaryEntry() {
0364:                return primary;
0365:            }
0366:
0367:            /** Get secondary entries.
0368:             * @return immutable set of entries
0369:             */
0370:            public final Set<Entry> secondaryEntries() {
0371:                synchronized (synchObjectSecondary()) {
0372:                    removeAllInvalid();
0373:
0374:                    return new HashSet<Entry>(getSecondary().values());
0375:                }
0376:            }
0377:
0378:            /** For a given file, find the associated secondary entry.
0379:             * @param fo file object
0380:             * @return the entry associated with the file object, or <code>null</code> if there is no
0381:             *    such entry
0382:             */
0383:            public final Entry findSecondaryEntry(FileObject fo) {
0384:                Entry e;
0385:                synchronized (synchObjectSecondary()) {
0386:                    removeAllInvalid();
0387:                    e = getSecondary().get(fo);
0388:                }
0389:                return e;
0390:            }
0391:
0392:            /** Removes all FileObjects that are not isValid from the
0393:             * set of objects.
0394:             */
0395:            private void removeAllInvalid() {
0396:                if (ERR.isLoggable(Level.FINE)) {
0397:                    ERR.fine("removeAllInvalid, started " + this ); // NOI18N
0398:                }
0399:                Iterator it = checkSecondary().entrySet().iterator();
0400:                while (it.hasNext()) {
0401:                    Map.Entry e = (Map.Entry) it.next();
0402:                    FileObject fo = (FileObject) e.getKey();
0403:                    if (!fo.isValid()) {
0404:                        it.remove();
0405:                        if (ERR.isLoggable(Level.FINE)) {
0406:                            ERR.fine("removeAllInvalid, removed: " + fo
0407:                                    + " for " + this ); // NOI18N
0408:                        }
0409:                        firePropertyChangeLater(PROP_FILES, null, null);
0410:                    }
0411:                }
0412:                if (ERR.isLoggable(Level.FINE)) {
0413:                    ERR.fine("removeAllInvalid, finished " + this ); // NOI18N
0414:                }
0415:            }
0416:
0417:            //methods overriding DataObjectHandler's abstract methods
0418:
0419:            /* Obtains lock for primary file by asking getPrimaryEntry() entry.
0420:             *
0421:             * @return the lock for primary file
0422:             * @exception IOException if it is not possible to set the template
0423:             *   state.
0424:             */
0425:            protected FileLock takePrimaryFileLock() throws IOException {
0426:                return getPrimaryEntry().takeLock();
0427:            }
0428:
0429:            // XXX does nothing of the sort --jglick
0430:            /** Check if in specific folder exists fileobject with the same name.
0431:             * If it exists user is asked for confirmation to rewrite, rename or cancel operation.
0432:             * @param folder destination folder
0433:             * @return the suffix which should be added to the name or null if operation is cancelled
0434:             */
0435:            private String existInFolder(FileObject fo, FileObject folder) {
0436:                // merge folders when neccessary
0437:                if (fo.isFolder() && isMergingFolders(fo, folder))
0438:                    return ""; // NOI18N
0439:
0440:                String orig = fo.getName();
0441:                String name = FileUtil.findFreeFileName(folder, orig, fo
0442:                        .getExt());
0443:                if (name.length() <= orig.length()) {
0444:                    return ""; // NOI18N
0445:                } else {
0446:                    return name.substring(orig.length());
0447:                }
0448:            }
0449:
0450:            /** Override to change default handling of name collisions detected during the
0451:             * copy, move operations. Reasonable for MultiDataObjects having folder their
0452:             * primary file (e.g. DataFolder, CompoundDataObject).
0453:             * @return <code>false</code> means, that new folder name should be synthetized when
0454:             * the same folder already exists in the target location of copy, move operation, otherwise
0455:             * existing falder will be used. Default implementation returns <code>false</code>.
0456:             */
0457:            boolean isMergingFolders(FileObject who, FileObject targetFolder) {
0458:                return false;
0459:            }
0460:
0461:            /** Copies primary and secondary files to new folder.
0462:             * May ask for user confirmation before overwriting.
0463:             * @param df the new folder
0464:             * @return data object for the new primary
0465:             * @throws IOException if there was a problem copying
0466:             * @throws UserCancelException if the user cancelled the copy
0467:             */
0468:            protected DataObject handleCopy(DataFolder df) throws IOException {
0469:                FileObject fo;
0470:
0471:                String suffix = existInFolder(getPrimaryEntry().getFile(), df
0472:                        .getPrimaryFile());
0473:                if (suffix == null)
0474:                    throw new org.openide.util.UserCancelException();
0475:
0476:                Iterator it = secondaryEntries().iterator();
0477:                while (it.hasNext()) {
0478:                    ((Entry) it.next()).copy(df.getPrimaryFile(), suffix);
0479:                }
0480:                //#33244 - copy primary file after the secondary ones
0481:                fo = getPrimaryEntry().copy(df.getPrimaryFile(), suffix);
0482:
0483:                boolean fullRescan = getMultiFileLoader() == null
0484:                        || getMultiFileLoader().findPrimaryFile(fo) != fo;
0485:                try {
0486:                    return fullRescan ? DataObject.find(fo)
0487:                            : createMultiObject(fo);
0488:                } catch (DataObjectExistsException ex) {
0489:                    return ex.getDataObject();
0490:                }
0491:            }
0492:
0493:            /* Deletes all secondary entries, removes them from the set of
0494:             * secondary entries and then deletes the getPrimaryEntry() entry.
0495:             */
0496:            protected void handleDelete() throws IOException {
0497:                List<FileObject> toRemove = new ArrayList<FileObject>();
0498:                Iterator<Map.Entry<FileObject, Entry>> it;
0499:                synchronized (synchObjectSecondary()) {
0500:                    removeAllInvalid();
0501:                    it = new ArrayList<Map.Entry<FileObject, Entry>>(
0502:                            getSecondary().entrySet()).iterator();
0503:                }
0504:
0505:                while (it.hasNext()) {
0506:                    Map.Entry<FileObject, Entry> e = it.next();
0507:                    e.getValue().delete();
0508:                    toRemove.add(e.getKey());
0509:                }
0510:
0511:                synchronized (synchObjectSecondary()) {
0512:                    for (FileObject f : toRemove) {
0513:                        getSecondary().remove(f);
0514:                        if (ERR.isLoggable(Level.FINE)) {
0515:                            ERR.fine("  handleDelete, removed entry: " + f);
0516:                        }
0517:                    }
0518:                }
0519:
0520:                getPrimaryEntry().delete();
0521:            }
0522:
0523:            /* Renames all entries and changes their files to new ones.
0524:             */
0525:            protected FileObject handleRename(String name) throws IOException {
0526:                getPrimaryEntry().changeFile(getPrimaryEntry().rename(name));
0527:
0528:                Map<FileObject, Entry> add = null;
0529:
0530:                List<FileObject> toRemove = new ArrayList<FileObject>();
0531:
0532:                Iterator<Map.Entry<FileObject, Entry>> it;
0533:                synchronized (synchObjectSecondary()) {
0534:                    removeAllInvalid();
0535:                    it = new ArrayList<Map.Entry<FileObject, Entry>>(
0536:                            getSecondary().entrySet()).iterator();
0537:                }
0538:
0539:                while (it.hasNext()) {
0540:                    Map.Entry<FileObject, Entry> e = it.next();
0541:                    FileObject fo = e.getValue().rename(name);
0542:                    if (fo == null) {
0543:                        // remove the entry
0544:                        toRemove.add(e.getKey());
0545:                    } else {
0546:                        if (!fo.equals(e.getKey())) {
0547:                            // put the new one into change table
0548:                            if (add == null)
0549:                                add = new HashMap<FileObject, Entry>();
0550:                            Entry entry = e.getValue();
0551:                            entry.changeFile(fo);
0552:                            // using getFile to let the entry correctly annotate
0553:                            // the file by isImportant flag
0554:                            add.put(entry.getFile(), entry);
0555:
0556:                            // changed the file => remove the file
0557:                            toRemove.add(e.getKey());
0558:                        }
0559:                    }
0560:                }
0561:
0562:                // if there has been a change in files, apply it
0563:                if ((add != null) || (!toRemove.isEmpty())) {
0564:                    synchronized (synchObjectSecondary()) {
0565:                        // remove entries
0566:                        if (!toRemove.isEmpty()) {
0567:                            for (FileObject f : toRemove) {
0568:                                getSecondary().remove(f);
0569:                                if (ERR.isLoggable(Level.FINE)) {
0570:                                    ERR.fine("handleRename, removed: " + f
0571:                                            + " for " + this ); // NOI18N
0572:                                }
0573:                            }
0574:                        }
0575:                        // add entries
0576:                        if (add != null) {
0577:                            getSecondary().putAll(add);
0578:                            if (ERR.isLoggable(Level.FINE)) {
0579:                                ERR.fine("handleRename, putAll: " + add
0580:                                        + " for " + this ); // NOI18N
0581:                            }
0582:                        }
0583:                    }
0584:                    firePropertyChangeLater(PROP_FILES, null, null);
0585:                }
0586:
0587:                return getPrimaryEntry().getFile();
0588:            }
0589:
0590:            /** Moves primary and secondary files to a new folder.
0591:             * May ask for user confirmation before overwriting.
0592:             * @param df the new folder
0593:             * @return the moved primary file object
0594:             * @throws IOException if there was a problem moving
0595:             * @throws UserCancelException if the user cancelled the move
0596:             */
0597:            protected FileObject handleMove(DataFolder df) throws IOException {
0598:                String suffix = existInFolder(getPrimaryEntry().getFile(), df
0599:                        .getPrimaryFile());
0600:                if (suffix == null)
0601:                    throw new org.openide.util.UserCancelException();
0602:
0603:                List<Pair> backup = saveEntries();
0604:
0605:                try {
0606:                    HashMap<FileObject, Entry> add = null;
0607:
0608:                    ArrayList<FileObject> toRemove = new ArrayList<FileObject>();
0609:                    Iterator<Map.Entry<FileObject, Entry>> it;
0610:                    int count;
0611:                    synchronized (synchObjectSecondary()) {
0612:                        removeAllInvalid();
0613:                        ArrayList<Map.Entry<FileObject, Entry>> list = new ArrayList<Map.Entry<FileObject, Entry>>(
0614:                                getSecondary().entrySet());
0615:                        count = list.size();
0616:                        it = list.iterator();
0617:                    }
0618:
0619:                    if (ERR.isLoggable(Level.FINE)) {
0620:                        ERR.fine("move " + this  + " to " + df
0621:                                + " number of secondary entries: " + count); // NOI18N
0622:                        ERR.fine("moving primary entry: " + getPrimaryEntry()); // NOI18N
0623:                    }
0624:                    getPrimaryEntry()
0625:                            .changeFile(
0626:                                    getPrimaryEntry().move(df.getPrimaryFile(),
0627:                                            suffix));
0628:                    if (ERR.isLoggable(Level.FINE))
0629:                        ERR.fine("               moved: "
0630:                                + getPrimaryEntry().getFile()); // NOI18N
0631:
0632:                    while (it.hasNext()) {
0633:                        Map.Entry<FileObject, Entry> e = it.next();
0634:                        if (ERR.isLoggable(Level.FINE))
0635:                            ERR.fine("moving entry :" + e); // NOI18N
0636:                        FileObject fo = (e.getValue()).move(
0637:                                df.getPrimaryFile(), suffix);
0638:                        if (ERR.isLoggable(Level.FINE))
0639:                            ERR.fine("  moved to   :" + fo); // NOI18N
0640:                        if (fo == null) {
0641:                            // remove the entry
0642:                            toRemove.add(e.getKey());
0643:                        } else {
0644:                            if (!fo.equals(e.getKey())) {
0645:                                // put the new one into change table
0646:                                if (add == null)
0647:                                    add = new HashMap<FileObject, Entry>();
0648:                                Entry entry = e.getValue();
0649:                                entry.changeFile(fo);
0650:                                // using entry.getFile, so the file has correctly
0651:                                // associated its isImportant flag
0652:                                add.put(entry.getFile(), entry);
0653:
0654:                                // changed the file => remove the file
0655:                                toRemove.add(e.getKey());
0656:                            }
0657:                        }
0658:                    }
0659:
0660:                    // if there has been a change in files, apply it
0661:                    if ((add != null) || (!toRemove.isEmpty())) {
0662:                        synchronized (synchObjectSecondary()) {
0663:                            // remove entries
0664:                            if (!toRemove.isEmpty()) {
0665:                                Object[] objects = toRemove.toArray();
0666:                                for (int i = 0; i < objects.length; i++) {
0667:                                    getSecondary().remove(objects[i]);
0668:                                    if (ERR.isLoggable(Level.FINE)) {
0669:                                        ERR.fine("handleMove, remove: "
0670:                                                + objects[i] + " for " + this ); // NOI18N
0671:                                    }
0672:                                }
0673:                            }
0674:                            // add entries
0675:                            if (add != null) {
0676:                                getSecondary().putAll(add);
0677:                                if (ERR.isLoggable(Level.FINE)) {
0678:                                    ERR.fine("handleMove, putAll: " + add
0679:                                            + " for " + this ); // NOI18N
0680:                                }
0681:                            }
0682:                        }
0683:                        firePropertyChangeLater(PROP_FILES, null, null);
0684:                    }
0685:
0686:                    if (ERR.isLoggable(Level.FINE)) {
0687:                        ERR.fine("successfully moved " + this ); // NOI18N
0688:                    }
0689:                    return getPrimaryEntry().getFile();
0690:                } catch (IOException e) {
0691:                    if (ERR.isLoggable(Level.FINE)) {
0692:                        ERR
0693:                                .fine("exception is here, restoring entries "
0694:                                        + this ); // NOI18N
0695:                        ERR.log(Level.FINE, null, e);
0696:                    }
0697:                    restoreEntries(backup);
0698:                    if (ERR.isLoggable(Level.FINE)) {
0699:                        ERR.fine("entries restored " + this ); // NOI18N
0700:                    }
0701:                    throw e;
0702:                }
0703:            }
0704:
0705:            /* Creates new object from template.
0706:             * @exception IOException
0707:             */
0708:            protected DataObject handleCreateFromTemplate(DataFolder df,
0709:                    String name) throws IOException {
0710:                if (name == null) {
0711:                    name = FileUtil.findFreeFileName(df.getPrimaryFile(),
0712:                            getPrimaryFile().getName(), getPrimaryFile()
0713:                                    .getExt());
0714:                }
0715:
0716:                FileObject primary = null;
0717:                Map<String, Object> params = null;
0718:                for (CreateFromTemplateHandler h : Lookup.getDefault()
0719:                        .lookupAll(CreateFromTemplateHandler.class)) {
0720:                    FileObject current = getPrimaryEntry().getFile();
0721:                    if (h.accept(current)) {
0722:                        if (params == null) {
0723:                            params = DataObject.CreateAction
0724:                                    .findParameters(name);
0725:                        }
0726:                        primary = h.createFromTemplate(current, df
0727:                                .getPrimaryFile(), name,
0728:                                DataObject.CreateAction.enhanceParameters(
0729:                                        params, name, current.getExt()));
0730:                        assert primary != null;
0731:                        break;
0732:                    }
0733:                }
0734:                if (params == null) {
0735:                    // do the regular creation
0736:                    primary = getPrimaryEntry().createFromTemplate(
0737:                            df.getPrimaryFile(), name);
0738:                }
0739:
0740:                Iterator<Entry> it = secondaryEntries().iterator();
0741:                NEXT_ENTRY: while (it.hasNext()) {
0742:                    Entry entry = it.next();
0743:                    for (CreateFromTemplateHandler h : Lookup.getDefault()
0744:                            .lookupAll(CreateFromTemplateHandler.class)) {
0745:                        FileObject current = entry.getFile();
0746:                        if (h.accept(current)) {
0747:                            if (params == null) {
0748:                                params = DataObject.CreateAction
0749:                                        .findParameters(name);
0750:                            }
0751:                            FileObject fo = h.createFromTemplate(current, df
0752:                                    .getPrimaryFile(), name,
0753:                                    DataObject.CreateAction.enhanceParameters(
0754:                                            params, name, current.getExt()));
0755:                            assert fo != null;
0756:                            continue NEXT_ENTRY;
0757:                        }
0758:                    }
0759:                    entry.createFromTemplate(df.getPrimaryFile(), name);
0760:                }
0761:
0762:                try {
0763:                    // #61600: not very object oriented, but covered by DefaultVersusXMLDataObjectTest
0764:                    if (this  instanceof  DefaultDataObject) {
0765:                        return DataObject.find(primary);
0766:                    }
0767:
0768:                    return createMultiObject(primary);
0769:                } catch (DataObjectExistsException ex) {
0770:                    return ex.getDataObject();
0771:                }
0772:            }
0773:
0774:            @Override
0775:            protected DataObject handleCopyRename(DataFolder df, String name,
0776:                    String ext) throws IOException {
0777:                if (getLoader() instanceof  UniFileLoader) {
0778:                    //allow the operation for single file DataObjects
0779:                    FileObject fo = getPrimaryEntry().copyRename(
0780:                            df.getPrimaryFile(), name, ext);
0781:                    return DataObject.find(fo);
0782:                }
0783:
0784:                throw new IOException(
0785:                        "SaveAs operation not supported for this file type.");
0786:            }
0787:
0788:            /** Set the set of cookies.
0789:             * To the provided cookie set a listener is attached,
0790:             * and any change to the set is propagated by
0791:             * firing a change on {@link #PROP_COOKIE}.
0792:             *
0793:             * @param s the cookie set to use
0794:             * @deprecated just use getCookieSet().add(...) instead
0795:             */
0796:            @Deprecated
0797:            protected final void setCookieSet(CookieSet s) {
0798:                setCookieSet(s, true);
0799:            }
0800:
0801:            /** Set the set of cookies.
0802:             *
0803:             * @param s the cookie set to use
0804:             * @param fireChange used when called from getter. In this case event shouldn't
0805:             * be fired.
0806:             */
0807:            private void setCookieSet(CookieSet s, boolean fireChange) {
0808:                synchronized (cookieSetLock) {
0809:                    ChangeListener ch = getChangeListener();
0810:
0811:                    if (cookieSet != null) {
0812:                        cookieSet.removeChangeListener(ch);
0813:                    }
0814:
0815:                    s.addChangeListener(ch);
0816:                    cookieSet = s;
0817:                }
0818:
0819:                if (fireChange) {
0820:                    fireCookieChange();
0821:                }
0822:            }
0823:
0824:            /** Get the set of cookies.
0825:             * If the set had been
0826:             * previously set by {@link #setCookieSet}, that set
0827:             * is returned. Otherwise an empty set is
0828:             * returned.
0829:             *
0830:             * @return the cookie set (never <code>null</code>)
0831:             */
0832:            protected final CookieSet getCookieSet() {
0833:                CookieSet s = cookieSet;
0834:                if (s != null)
0835:                    return s;
0836:                synchronized (cookieSetLock) {
0837:                    if (cookieSet != null)
0838:                        return cookieSet;
0839:
0840:                    // generic cookie set with reference to data object and 
0841:                    // a callback that updates FileObjects in its list.
0842:                    CookieSet g = CookieSet.createGeneric(getChangeListener());
0843:                    g.assign(DataObject.class, this );
0844:                    setCookieSet(g, false);
0845:                    return cookieSet;
0846:                }
0847:            }
0848:
0849:            /** Look for a cookie in the current cookie set matching the requested class.
0850:             *
0851:             * @param type the class to look for
0852:             * @return an instance of that class, or <code>null</code> if this class of cookie
0853:             *    is not supported
0854:             */
0855:            @Override
0856:            public <T extends Node.Cookie> T getCookie(Class<T> type) {
0857:                CookieSet c = cookieSet;
0858:                if (c != null) {
0859:                    T cookie = c.getCookie(type);
0860:                    if (cookie != null)
0861:                        return cookie;
0862:                }
0863:                return super .getCookie(type);
0864:            }
0865:
0866:            /** Fires cookie change.
0867:             */
0868:            final void fireCookieChange() {
0869:                firePropertyChange(PROP_COOKIE, null, null);
0870:            }
0871:
0872:            /** Fires property change but in event thread.
0873:             */
0874:            private void firePropertyChangeLater(final String name,
0875:                    final Object oldV, final Object newV) {
0876:                firingProcessor.post(new Runnable() {
0877:                    public void run() {
0878:                        firePropertyChange(name, oldV, newV);
0879:                        if (PROP_FILES.equals(name)
0880:                                || PROP_PRIMARY_FILE.equals(name)) {
0881:                            updateFilesInCookieSet();
0882:                        }
0883:                    }
0884:                });
0885:            }
0886:
0887:            /**
0888:             * Posts a task to delayProcessor such that task
0889:             *   1. waits for the FolderList to finish
0890:             *   2. calls firePropertyChangeLater with PROP_FILES
0891:             * Second time this method is called (delayedPropFilesTask is not null)
0892:             * the new task is not created - the old one is rescheduled to run again.
0893:             *
0894:             * NOTE: this method should be improved not to fire twice in some cases.
0895:             */
0896:            private void firePropFilesAfterFinishing() {
0897:                synchronized (delayedPropFilesLock) {
0898:                    if (delayedPropFilesTask == null) {
0899:                        delayedPropFilesTask = delayProcessor
0900:                                .post(new Runnable() {
0901:                                    public void run() {
0902:                                        FolderList l = getFolderList();
0903:                                        if (l != null) {
0904:                                            l.waitProcessingFinished();
0905:                                        }
0906:                                        firePropertyChangeLater(PROP_FILES,
0907:                                                null, null);
0908:                                    }
0909:                                });
0910:                    } else {
0911:                        delayedPropFilesTask.schedule(0);
0912:                    }
0913:                }
0914:            }
0915:
0916:            /** sets checked to true */
0917:            final void recognizedByFolder() {
0918:                checked = true;
0919:            }
0920:
0921:            private ChangeAndBefore chLis;
0922:
0923:            final ChangeAndBefore getChangeListener() {
0924:                if (chLis == null) {
0925:                    chLis = new ChangeAndBefore();
0926:                }
0927:                return chLis;
0928:            }
0929:
0930:            // -- Following methods were added in order to wrap calls to MultiFileLoader
0931:            // and check if the loader is really of this type. This hack was added to
0932:            // keep backward compatibility of DataFolder and DataShadow classes, which
0933:            // were originally subclassing DataObject, but was changed to subclass
0934:            // MultiDataObject. Methods can be removed as the deprecated constructor
0935:            // MultiDataObject(FileObject, DataLoader) disappears.
0936:
0937:            private final MultiDataObject.Entry createPrimaryEntry(
0938:                    MultiDataObject obj, FileObject fo) {
0939:                MultiFileLoader loader = getMultiFileLoader();
0940:
0941:                if (loader != null)
0942:                    return loader.createPrimaryEntry(obj, fo);
0943:
0944:                Entry e;
0945:                if (fo.isFolder())
0946:                    e = new FileEntry.Folder(obj, fo);
0947:                else
0948:                    e = new FileEntry(obj, fo);
0949:
0950:                return e;
0951:            }
0952:
0953:            private final MultiDataObject.Entry createSecondaryEntry(
0954:                    MultiDataObject obj, FileObject fo) {
0955:                MultiFileLoader loader = getMultiFileLoader();
0956:
0957:                if (loader != null)
0958:                    return loader.createSecondaryEntryImpl(obj, fo);
0959:
0960:                Entry e;
0961:                if (fo.isFolder())
0962:                    e = new FileEntry.Folder(obj, fo);
0963:                else
0964:                    e = new FileEntry(obj, fo);
0965:
0966:                return e;
0967:            }
0968:
0969:            private final MultiDataObject createMultiObject(FileObject fo)
0970:                    throws DataObjectExistsException, IOException {
0971:                MultiFileLoader loader = getMultiFileLoader();
0972:
0973:                MultiDataObject obj;
0974:
0975:                if (loader != null) {
0976:                    obj = DataObjectPool.createMultiObject(loader, fo);
0977:                } else {
0978:                    obj = (MultiDataObject) getLoader().findDataObject(fo,
0979:                            RECOGNIZER);
0980:                }
0981:                return obj;
0982:            }
0983:
0984:            private final void checkConsistency(MultiDataObject obj) {
0985:                MultiFileLoader loader = getMultiFileLoader();
0986:
0987:                if (loader != null)
0988:                    loader.checkConsistency(obj);
0989:            }
0990:
0991:            private final void checkFiles(MultiDataObject obj) {
0992:                MultiFileLoader loader = getMultiFileLoader();
0993:
0994:                if (loader != null)
0995:                    loader.checkFiles(obj);
0996:            }
0997:
0998:            private static EmptyRecognizer RECOGNIZER = new EmptyRecognizer();
0999:
1000:            private static class EmptyRecognizer implements 
1001:                    DataLoader.RecognizedFiles {
1002:                EmptyRecognizer() {
1003:                }
1004:
1005:                public void markRecognized(FileObject fo) {
1006:                }
1007:            }
1008:
1009:            // End of compatibility hack. --^
1010:
1011:            /** Save pairs Entry <-> Entry.getFile () in the list
1012:             *  @return list of saved pairs
1013:             */
1014:            final List<Pair> saveEntries() {
1015:                synchronized (synchObjectSecondary()) {
1016:                    LinkedList<Pair> ll = new LinkedList<Pair>();
1017:
1018:                    ll.add(new Pair(getPrimaryEntry()));
1019:                    for (MultiDataObject.Entry en : secondaryEntries()) {
1020:                        ll.add(new Pair(en));
1021:                    }
1022:                    return ll;
1023:                }
1024:            }
1025:
1026:            /** Restore entries from the list. If Entry.getFile () has changed from
1027:             * time when backup list was created, original file is restored and
1028:             * Entry is re-assigned to it.
1029:             * @param backup list obtained from {@link #saveEntries ()} function
1030:             */
1031:            final void restoreEntries(List<Pair> backup) {
1032:                for (Pair p : backup) {
1033:                    if (p.entry.getFile().equals(p.file))
1034:                        continue;
1035:                    if (p.file.isValid()) {
1036:                        p.entry.changeFile(p.file);
1037:                    } else {
1038:                        // copy back
1039:                        try {
1040:                            if (p.entry.getFile().isData())
1041:                                p.entry.changeFile(p.entry.getFile().copy(
1042:                                        p.file.getParent(), p.file.getName(),
1043:                                        p.file.getExt()));
1044:                            else {
1045:                                FileObject fo = p.file.getParent()
1046:                                        .createFolder(p.file.getName());
1047:                                FileUtil.copyAttributes(p.entry.getFile(), fo);
1048:                                p.entry.changeFile(fo);
1049:                            }
1050:                        } catch (IOException e) {
1051:                            // should not occure
1052:                        }
1053:                    }
1054:                }
1055:            }
1056:
1057:            final static class Pair {
1058:                MultiDataObject.Entry entry;
1059:                FileObject file;
1060:
1061:                Pair(MultiDataObject.Entry e) {
1062:                    entry = e;
1063:                    file = e.getFile();
1064:                }
1065:            }
1066:
1067:            /** Represents one file in a {@link MultiDataObject group data object}. */
1068:            public abstract class Entry implements  java.io.Serializable {
1069:                /** generated Serialized Version UID */
1070:                static final long serialVersionUID = 6024795908818133571L;
1071:
1072:                /** modified from MultiDataObject operations, that is why it is package
1073:                 * private. Do not assign anything to this object, use changeFile method
1074:                 */
1075:                private FileObject file;
1076:
1077:                /** This factory is used for creating new clones of the holding lock for internal
1078:                 * use of this DataObject. It factory is null it means that the file entry is not
1079:                 */
1080:                private transient WeakReference<FileLock> lock;
1081:
1082:                protected Entry(FileObject file) {
1083:                    this .file = file;
1084:                    if (!isImportant()) {
1085:                        file.setImportant(false);
1086:                    }
1087:                }
1088:
1089:                /** A method to change the entry file to some else.
1090:                 * @param newFile
1091:                 */
1092:                final void changeFile(FileObject newFile) {
1093:                    assert newFile != null : "NPE for " + file;
1094:                    if (newFile.equals(file)) {
1095:                        return;
1096:                    }
1097:                    if (ERR.isLoggable(Level.FINE)) {
1098:                        ERR.fine("changeFile: " + newFile + " for " + this 
1099:                                + " of " + getDataObject()); // NOI18N
1100:                    }
1101:                    newFile.setImportant(isImportant());
1102:                    this .file = newFile;
1103:
1104:                    // release lock for old file
1105:                    FileLock l = lock == null ? null : (FileLock) lock.get();
1106:                    if (l != null && l.isValid()) {
1107:                        if (ERR.isLoggable(Level.FINE)) {
1108:                            ERR.fine("releasing old lock: " + this  + " was: "
1109:                                    + l);
1110:                        }
1111:                        l.releaseLock();
1112:                    }
1113:                    lock = null;
1114:                }
1115:
1116:                /** Get the file this entry works with.
1117:                 */
1118:                public final FileObject getFile() {
1119:                    return file;
1120:                }
1121:
1122:                /** Get the multi data object this entry is assigned to.
1123:                 * @return the data object
1124:                 */
1125:                public final MultiDataObject getDataObject() {
1126:                    return MultiDataObject.this ;
1127:                }
1128:
1129:                /** Method that allows to check whether an entry is important or is not.
1130:                 * Should be overriden by subclasses, the current implementation returns 
1131:                 * true.
1132:                 *
1133:                 * @return true if this entry is important or false if not
1134:                 */
1135:                public boolean isImportant() {
1136:                    return true;
1137:                }
1138:
1139:                /** Called when the entry is to be copied.
1140:                 * Depending on the entry type, it should either copy the underlying <code>FileObject</code>,
1141:                 * or do nothing (if it cannot be copied).
1142:                 * @param f the folder to create this entry in
1143:                 * @param suffix the suffix to add to the name of original file
1144:                 * @return the copied <code>FileObject</code> or <code>null</code> if it cannot be copied
1145:                 * @exception IOException when the operation fails
1146:                 */
1147:                public abstract FileObject copy(FileObject f, String suffix)
1148:                        throws IOException;
1149:
1150:                /** Called when the entry is to be renamed.
1151:                 * Depending on the entry type, it should either rename the underlying <code>FileObject</code>,
1152:                 * or delete it (if it cannot be renamed).
1153:                 * @param name the new name
1154:                 * @return the renamed <code>FileObject</code> or <code>null</code> if it has been deleted
1155:                 * @exception IOException when the operation fails
1156:                 */
1157:                public abstract FileObject rename(String name)
1158:                        throws IOException;
1159:
1160:                /** Called when the entry is to be moved.
1161:                 * Depending on the entry type, it should either move the underlying <code>FileObject</code>,
1162:                 * or delete it (if it cannot be moved).
1163:                 * @param f the folder to move this entry to
1164:                 * @param suffix the suffix to use
1165:                 * @return the moved <code>FileObject</code> or <code>null</code> if it has been deleted
1166:                 * @exception IOException when the operation fails
1167:                 */
1168:                public abstract FileObject move(FileObject f, String suffix)
1169:                        throws IOException;
1170:
1171:                /** Called when the entry is to be deleted.
1172:                 * @exception IOException when the operation fails
1173:                 */
1174:                public abstract void delete() throws IOException;
1175:
1176:                /** Called when the entry is to be created from a template.
1177:                 * Depending on the entry type, it should either copy the underlying <code>FileObject</code>,
1178:                 * or do nothing (if it cannot be copied).
1179:                 * @param f the folder to create this entry in
1180:                 * @param name the new name to use
1181:                 * @return the copied <code>FileObject</code> or <code>null</code> if it cannot be copied
1182:                 * @exception IOException when the operation fails
1183:                 */
1184:                public abstract FileObject createFromTemplate(FileObject f,
1185:                        String name) throws IOException;
1186:
1187:                /** 
1188:                 * Called when the entry is to be copied and renamed.
1189:                 * @param f the folder to create this entry in
1190:                 * @param name new file name
1191:                 * @param ext new file extension
1192:                 * @return the copied and renamed <code>FileObject</code>, never null
1193:                 * @exception IOException when the operation fails
1194:                 * @since 6.3
1195:                 */
1196:                public FileObject copyRename(FileObject f, String name,
1197:                        String ext) throws IOException {
1198:                    throw new IOException("Unsupported operation");
1199:                }
1200:
1201:                /** Try to lock this file entry.
1202:                 * @return the lock if the operation was successful; otherwise <code>null</code>
1203:                 * @throws IOException if the lock could not be taken
1204:                 */
1205:                public FileLock takeLock() throws IOException {
1206:                    FileLock l = lock == null ? null : lock.get();
1207:                    if (l == null || !l.isValid()) {
1208:                        l = getFile().lock();
1209:                        lock = new WeakReference<FileLock>(l);
1210:                    }
1211:                    if (ERR.isLoggable(Level.FINE)) {
1212:                        ERR.fine("takeLock: " + this  + " is: " + l);
1213:                    }
1214:                    return l;
1215:                }
1216:
1217:                /** Tests whether the entry is locked.
1218:                 * @return <code>true</code> if so
1219:                 */
1220:                public boolean isLocked() {
1221:                    FileLock l = lock == null ? null : lock.get();
1222:                    return l != null && l.isValid();
1223:                }
1224:
1225:                public boolean equals(Object o) {
1226:                    if (!(o instanceof  Entry))
1227:                        return false;
1228:                    return getFile().equals(((Entry) o).getFile());
1229:                }
1230:
1231:                public int hashCode() {
1232:                    return getFile().hashCode();
1233:                }
1234:
1235:                /** Make a Serialization replacement.
1236:                 * The entry is identified by the
1237:                 * file object is holds. When serialized, it stores the
1238:                 * file object and the data object. On deserialization
1239:                 * it finds the data object and creates the right entry
1240:                 * for it.
1241:                 */
1242:                protected Object writeReplace() {
1243:                    return new EntryReplace(getFile());
1244:                }
1245:            }
1246:
1247:            void notifyFileDeleted(FileEvent fe) {
1248:                removeFile(fe.getFile());
1249:                if (fe.getFile().equals(getPrimaryFile())) {
1250:                    try {
1251:                        MultiDataObject.this .markInvalid0();
1252:                    } catch (PropertyVetoException ex) {
1253:                        // silently ignore?
1254:                        Logger.getLogger(MultiDataObject.class.getName()).log(
1255:                                Level.WARNING, null, ex);
1256:                    }
1257:                }
1258:            }
1259:
1260:            /** Fired when a file has been added to the same folder
1261:             * @param fe the event describing context where action has taken place
1262:             */
1263:            void notifyFileDataCreated(FileEvent fe) {
1264:                checked = false;
1265:            }
1266:
1267:            final void updateFilesInCookieSet() {
1268:                getCookieSet().assign(FileObject.class,
1269:                        files().toArray(new FileObject[0]));
1270:            }
1271:
1272:            void checkCookieSet(Class<?> c) {
1273:            }
1274:
1275:            /** Change listener and implementation of before.
1276:             */
1277:            private final class ChangeAndBefore implements  ChangeListener,
1278:                    CookieSet.Before {
1279:                public void stateChanged(ChangeEvent ev) {
1280:                    fireCookieChange();
1281:                }
1282:
1283:                public void beforeLookup(Class<?> clazz) {
1284:                    if (clazz.isAssignableFrom(FileObject.class)) {
1285:                        updateFilesInCookieSet();
1286:                    }
1287:                    checkCookieSet(clazz);
1288:                }
1289:            }
1290:
1291:            /** Entry replace.
1292:             */
1293:            private static final class EntryReplace extends Object implements 
1294:                    java.io.Serializable {
1295:                /** generated Serialized Version UID */
1296:                static final long serialVersionUID = -1498798537289529182L;
1297:
1298:                /** file object of the entry */
1299:                private FileObject file;
1300:                /** entry to be used during read */
1301:                private transient Entry entry;
1302:
1303:                public EntryReplace(FileObject fo) {
1304:                    file = fo;
1305:                }
1306:
1307:                private void readObject(ObjectInputStream ois)
1308:                        throws IOException, ClassNotFoundException {
1309:                    ois.defaultReadObject();
1310:                    try {
1311:                        DataObject obj = DataObject.find(file);
1312:                        if (obj instanceof  MultiDataObject) {
1313:                            MultiDataObject m = (MultiDataObject) obj;
1314:
1315:                            if (file.equals(m.getPrimaryFile())) {
1316:                                // primary entry
1317:                                entry = m.getPrimaryEntry();
1318:                            } else {
1319:                                // secondary entry
1320:                                Entry e = (Entry) m.findSecondaryEntry(file);
1321:                                if (e == null) {
1322:                                    throw new InvalidObjectException(obj
1323:                                            .toString());
1324:                                }
1325:                                // remember the entry
1326:                                entry = e;
1327:                            }
1328:                        }
1329:                    } catch (DataObjectNotFoundException ex) {
1330:                        throw new InvalidObjectException(ex.getMessage());
1331:                    }
1332:                }
1333:
1334:                public Object readResolve() {
1335:                    return entry;
1336:                }
1337:            }
1338:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.