Source Code Cross Referenced for SharedClassObject.java in  » IDE-Netbeans » openide » org » openide » util » 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.util 
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.util;
0043:
0044:        import java.beans.PropertyChangeListener;
0045:        import java.beans.PropertyChangeSupport;
0046:        import java.io.Externalizable;
0047:        import java.io.IOException;
0048:        import java.io.ObjectInput;
0049:        import java.io.ObjectInputStream;
0050:        import java.io.ObjectOutput;
0051:        import java.io.ObjectOutputStream;
0052:        import java.io.ObjectStreamException;
0053:        import java.io.Serializable;
0054:        import java.lang.ref.WeakReference;
0055:        import java.lang.reflect.Method;
0056:        import java.security.AccessController;
0057:        import java.security.PrivilegedActionException;
0058:        import java.security.PrivilegedExceptionAction;
0059:        import java.util.HashMap;
0060:        import java.util.HashSet;
0061:        import java.util.Map;
0062:        import java.util.Set;
0063:        import java.util.WeakHashMap;
0064:        import java.util.logging.Level;
0065:        import java.util.logging.Logger;
0066:
0067:        /** Shared object that allows different instances of the same class
0068:         * to share common data.
0069:         * <p>The data are shared only between instances of the same class (not subclasses).
0070:         * Thus, such "variables" have neither instance nor static behavior.
0071:         *
0072:         * @author Ian Formanek, Jaroslav Tulach
0073:         */
0074:        public abstract class SharedClassObject extends Object implements 
0075:                Externalizable {
0076:            /** serialVersionUID */
0077:            private static final long serialVersionUID = 4527891234589143259L;
0078:
0079:            /** property change support (PropertyChangeSupport) */
0080:            private static final Object PROP_SUPPORT = new Object();
0081:
0082:            /** Map (Class, DataEntry) that maps Classes to maps of any objects */
0083:            private static final Map<Class, DataEntry> values = new WeakHashMap<Class, DataEntry>(
0084:                    37);
0085:
0086:            /** A set of all classes for which we are currently inside createInstancePrivileged.
0087:             * If a SCO constructor is called when an instance of that class already exists, normally
0088:             * this will print a warning. However it is common to create an instance inside a static
0089:             * block; in this case the constructor is actually called twice. Only the first instance
0090:             * is ever returned, but this set ensures that no warning is printed during creation of the
0091:             * second instance (because it is nobody's fault and it will be handled OK).
0092:             * Map from class name to nesting count.
0093:             */
0094:            private static final Map<String, Integer> instancesBeingCreated = new HashMap<String, Integer>(
0095:                    7);
0096:
0097:            /** Set of classes to not warn about any more.
0098:             * Names only.
0099:             */
0100:            private static final Set<String> alreadyWarnedAboutDupes = new HashSet<String>();
0101:            private static final Logger err = Logger
0102:                    .getLogger("org.openide.util.SharedClassObject"); // NOI18N
0103:
0104:            /** data entry for this class */
0105:            private final DataEntry dataEntry;
0106:
0107:            /** Lock for the object */
0108:            private Object lock;
0109:
0110:            /** hard reference to primary instance of this class
0111:             * This is here not to allow the finalization till at least
0112:             * one object exists
0113:             */
0114:            private final SharedClassObject first;
0115:
0116:            /** Stack trace indicating where the first instance was created.
0117:             * This is only set on the first instance; and only with the error manager on.
0118:             */
0119:            private Throwable firstTrace = null;
0120:
0121:            /** Set by {@link SystemOption}s through the special property, see {@link #putProperty}.
0122:             * SystemOption needs special handling, e.g. it needs to be deserialized by the lookup
0123:             * after its first instance is created in {@link #findObject} method, only
0124:             * SystemOption can be reset.
0125:             */
0126:            private boolean systemOption = false;
0127:
0128:            /** If set, this means we have a system option waiting to be loaded from lookup.
0129:             * If anyone changes a property on it before this happens, the exception is filled in,
0130:             * so we know when it is loaded that something went wrong.
0131:             */
0132:            private boolean waitingOnSystemOption = false;
0133:            private IllegalStateException prematureSystemOptionMutation = null;
0134:            private boolean inReadExternal = false;
0135:
0136:            /** Check that addNotify, removeNotify, initialize call super sometime. */
0137:            private boolean addNotifySuper;
0138:
0139:            /** Check that addNotify, removeNotify, initialize call super sometime. */
0140:            private boolean removeNotifySuper;
0141:
0142:            /** Check that addNotify, removeNotify, initialize call super sometime. */
0143:            private boolean initializeSuper;
0144:
0145:            /** Create a shared object.
0146:             * Typically shared-class constructors should not take parameters, since there
0147:             * will conventionally be no instance variables.
0148:             * @see #initialize
0149:             */
0150:            protected SharedClassObject() {
0151:                synchronized (getLock()) {
0152:                    DataEntry de = values.get(getClass());
0153:
0154:                    //System.err.println("SCO create: " + this + " de=" + de);
0155:                    if (de == null) {
0156:                        de = new DataEntry();
0157:                        values.put(getClass(), de);
0158:                    }
0159:
0160:                    dataEntry = de;
0161:                    de.increase();
0162:
0163:                    // finds reference for the first object of the class
0164:                    first = de.first(this );
0165:                }
0166:
0167:                if (first != null) {
0168:                    if (first == this ) {
0169:                        // Could be a performance hit, so only do this when developing.
0170:                        if (err.isLoggable(Level.FINE)) {
0171:                            Throwable t = new Throwable(
0172:                                    "First instance created here"); // NOI18N
0173:                            t.fillInStackTrace();
0174:                            first.firstTrace = t;
0175:                        }
0176:                    } else {
0177:                        String clazz = getClass().getName();
0178:                        boolean creating;
0179:
0180:                        synchronized (instancesBeingCreated) {
0181:                            creating = instancesBeingCreated.containsKey(clazz);
0182:                        }
0183:
0184:                        if (creating) {
0185:                            //System.err.println ("Nesting: " + getClass ().getName () + " " + instancesBeingCreated.get (clazz));
0186:                        } else {
0187:                            if (!alreadyWarnedAboutDupes.contains(clazz)) {
0188:                                alreadyWarnedAboutDupes.add(clazz);
0189:
0190:                                Exception e = new IllegalStateException(
0191:                                        "Warning: multiple instances of shared class "
0192:                                                + clazz + " created."); // NOI18N
0193:
0194:                                if (first.firstTrace != null) {
0195:                                    err.log(Level.WARNING, "First stack trace",
0196:                                            first.firstTrace);
0197:                                } else {
0198:                                    err
0199:                                            .warning("(Run with -J-Dorg.openide.util.SharedClassObject.level=0 for more details.)"); // NOI18N
0200:                                }
0201:
0202:                                err.log(Level.WARNING, null, e);
0203:                            }
0204:                        }
0205:                    }
0206:                }
0207:            }
0208:
0209:            /* Calls a referenceLost to decrease the counter on the shared data.
0210:             * This method is final so no descendant can override it, but
0211:             * it calls the method unreferenced() that can be overriden to perform any
0212:             * additional tasks on finalizing.
0213:             */
0214:            protected final void finalize() throws Throwable {
0215:                referenceLost();
0216:            }
0217:
0218:            /** Indicate whether the shared data of the last existing instance of this class
0219:             * should be cleared when that instance is finalized.
0220:             *
0221:             * Subclasses may perform additional tasks
0222:             * on finalization if desired. This method should be overridden
0223:             * in lieu of {@link #finalize}.
0224:             * <p>The default implementation returns <code>true</code>.
0225:             * Classes which have precious shared data may want to return <code>false</code>, so that
0226:             * all instances may be finalized, after which new instances will pick up the same shared variables
0227:             * without requiring a recalculation.
0228:             *
0229:             * @return <code>true</code> if all shared data should be cleared,
0230:             *   <code>false</code> if it should stay in memory
0231:             */
0232:            protected boolean clearSharedData() {
0233:                return true;
0234:            }
0235:
0236:            /** Test whether the classes of the compared objects are the same.
0237:             * @param obj the object to compare to
0238:             * @return <code>true</code> if the classes are equal
0239:             */
0240:            public final boolean equals(Object obj) {
0241:                return ((obj instanceof  SharedClassObject) && (getClass()
0242:                        .equals(obj.getClass())));
0243:            }
0244:
0245:            /** Get a hashcode of the shared class.
0246:             * @return the hash code
0247:             */
0248:            public final int hashCode() {
0249:                return getClass().hashCode();
0250:            }
0251:
0252:            /** Obtain lock for synchronization on manipulation with this
0253:             * class.
0254:             * Can be used by subclasses when performing nonatomic writes, e.g.
0255:             * @return an arbitrary synchronizable lock object
0256:             */
0257:            protected final Object getLock() {
0258:                if (lock == null) {
0259:                    lock = getClass().getName().intern();
0260:                }
0261:
0262:                return lock;
0263:            }
0264:
0265:            /** Should be called from within a finalize method to manage references
0266:             * to the shared data (when the last reference is lost, the object is
0267:             * removed)
0268:             */
0269:            private void referenceLost() {
0270:                //System.err.println ("SharedClassObject.referenceLost:");
0271:                //System.err.println ("\tLock: " + getLock());
0272:                //System.err.println ("\tDataEntry: " + dataEntry);
0273:                //System.err.println ("\tValues: " + values.containsKey(getClass()));
0274:                synchronized (getLock()) {
0275:                    if ((dataEntry == null) || (dataEntry.decrease() == 0)) {
0276:                        if (clearSharedData()) {
0277:                            // clears the data
0278:                            values.remove(getClass());
0279:                        }
0280:                    }
0281:                }
0282:
0283:                //System.err.println("\tValues after: " + values.containsKey(getClass()));
0284:            }
0285:
0286:            /** Set a shared variable.
0287:             * Automatically {@link #getLock locks}.
0288:             * @param key name of the property
0289:             * @param value value for that property (may be null)
0290:             * @return the previous value assigned to the property, or <code>null</code> if none
0291:             */
0292:            protected final Object putProperty(Object key, Object value) {
0293:                if (key == null) {
0294:                    throw new NullPointerException(
0295:                            "Tried to pass null key (value=" + value
0296:                                    + ") to putProperty"); // NOI18N
0297:                }
0298:
0299:                synchronized (getLock()) {
0300:                    if (waitingOnSystemOption && (key != PROP_SUPPORT)
0301:                            && (prematureSystemOptionMutation == null)
0302:                            && !dataEntry.isInInitialize() && !inReadExternal) {
0303:                        // See below in findObject. Note that if we are still in initialize(),
0304:                        // it is harmless to set default values of properties, and from readExternal()
0305:                        // it is expected.
0306:                        prematureSystemOptionMutation = new IllegalStateException(
0307:                                "...setting property here..."); // NOI18N
0308:                    }
0309:
0310:                    return dataEntry.getMap(this ).put(key, value);
0311:
0312:                    //return dataEntry.getMap().put (key, value);
0313:                }
0314:            }
0315:
0316:            /** Set a shared variable available only for string names.
0317:             * Automatically {@link #getLock locks}.
0318:             * <p><strong>Important:</strong> remember that <code>SharedClassObject</code>s
0319:             * are like singleton beans; when you use <code>putProperty</code> with a value
0320:             * of <code>true</code>, or call {@link #firePropertyChange}, you must consider that
0321:             * the property name should match the JavaBeans name for a natural (introspected) property
0322:             * for the bean, if such a property uses this key. For example, if you have a method
0323:             * <code>getFoo</code> which uses {@link #getProperty} and a method <code>setFoo</code>
0324:             * which uses <code>putProperty(..., true)</code>, then the key used <em>must</em>
0325:             * be named <code>foo</code> (assuming you did not override this name in a BeanInfo).
0326:             * Otherwise various listeners may not be prepared for the property change and may just
0327:             * ignore it. For example, the property sheet for a <a href="@org-openide-nodes@/org/openide/nodes/BeanNode.html">BeanNode</a> based on a
0328:             * <code>SharedClassObject</code> which stores its properties using a misnamed key
0329:             * will probably not refresh correctly.
0330:             * @param key name of the property
0331:             * @param value value for that property (may be null)
0332:             * @param notify should all listeners be notified about property change?
0333:             * @return the previous value assigned to the property, or <code>null</code> if none
0334:             */
0335:            protected final Object putProperty(String key, Object value,
0336:                    boolean notify) {
0337:                Object previous = putProperty(key, value);
0338:
0339:                if (notify) {
0340:                    firePropertyChange(key, previous, value);
0341:                }
0342:
0343:                return previous;
0344:            }
0345:
0346:            /** Get a shared variable.
0347:             * Automatically {@link #getLock locks}.
0348:             * @param key name of the property
0349:             * @return value of the property, or <code>null</code> if none
0350:             */
0351:            protected final Object getProperty(Object key) {
0352:                synchronized (getLock()) {
0353:                    //System.err.println("SCO: " + this + " get: " + key + " de=" + dataEntry);
0354:                    if ("org.openide.util.SharedClassObject.initialize"
0355:                            .equals(key)) { // NOI18N
0356:
0357:                        return dataEntry.isInInitialize() ? Boolean.TRUE : null;
0358:                    }
0359:
0360:                    return dataEntry.get(this , key);
0361:                }
0362:            }
0363:
0364:            /** Initialize shared state.
0365:             * Should use {@link #putProperty} to set up variables.
0366:             * Subclasses should always call the super method.
0367:             * <p>This method need <em>not</em> be called explicitly; it will be called once
0368:             * the first time a given shared class is used (not for each instance!).
0369:             */
0370:            protected void initialize() {
0371:                initializeSuper = true;
0372:            }
0373:
0374:            /** Adds the specified property change listener to receive property
0375:             * change events from this object.
0376:             * @param         l the property change listener
0377:             */
0378:            public final void addPropertyChangeListener(PropertyChangeListener l) {
0379:                boolean noListener;
0380:
0381:                synchronized (getLock()) {
0382:                    //      System.out.println ("added listener: " + l + " to: " + getClass ()); // NOI18N
0383:                    PropertyChangeSupport supp = (PropertyChangeSupport) getProperty(PROP_SUPPORT);
0384:
0385:                    if (supp == null) {
0386:                        //        System.out.println ("Creating support"); // NOI18N
0387:                        putProperty(PROP_SUPPORT,
0388:                                supp = new PropertyChangeSupport(this ));
0389:                    }
0390:
0391:                    noListener = !supp.hasListeners(null);
0392:                    supp.addPropertyChangeListener(l);
0393:                }
0394:
0395:                if (noListener) {
0396:                    addNotifySuper = false;
0397:                    addNotify();
0398:
0399:                    if (!addNotifySuper) {
0400:                        // [PENDING] theoretical race condition for this warning if listeners are added
0401:                        // and removed very quickly from two threads, I guess, and addNotify() impl is slow
0402:                        String msg = "You must call super.addNotify() from "
0403:                                + getClass().getName() + ".addNotify()"; // NOI18N
0404:                        err.warning(msg);
0405:                    }
0406:                }
0407:            }
0408:
0409:            /**
0410:             * Removes the specified property change listener so that it
0411:             * no longer receives property change events from this object.
0412:             * @param         l     the property change listener
0413:             */
0414:            public final void removePropertyChangeListener(
0415:                    PropertyChangeListener l) {
0416:                boolean callRemoved;
0417:
0418:                synchronized (getLock()) {
0419:                    PropertyChangeSupport supp = (PropertyChangeSupport) getProperty(PROP_SUPPORT);
0420:
0421:                    if (supp == null) {
0422:                        return;
0423:                    }
0424:
0425:                    boolean hasListener = supp.hasListeners(null);
0426:                    supp.removePropertyChangeListener(l);
0427:                    callRemoved = hasListener && !supp.hasListeners(null);
0428:                }
0429:
0430:                if (callRemoved) {
0431:                    putProperty(PROP_SUPPORT, null); // clean the PCS, see #25417
0432:                    removeNotifySuper = false;
0433:                    removeNotify();
0434:
0435:                    if (!removeNotifySuper) {
0436:                        String msg = "You must call super.removeNotify() from "
0437:                                + getClass().getName() + ".removeNotify()"; // NOI18N
0438:                        err.warning(msg);
0439:                    }
0440:                }
0441:            }
0442:
0443:            /** Notify subclasses that the first listener has been added to this object.
0444:             * Subclasses should always call the super method.
0445:             * The default implementation does nothing.
0446:             */
0447:            protected void addNotify() {
0448:                addNotifySuper = true;
0449:            }
0450:
0451:            /** Notify subclasses that the last listener has been removed from this object.
0452:             * Subclasses should always call the super method.
0453:             * The default implementation does nothing.
0454:             */
0455:            protected void removeNotify() {
0456:                removeNotifySuper = true;
0457:            }
0458:
0459:            /** Fire a property change event to all listeners.
0460:             * @param name the name of the property
0461:             * @param oldValue the old value
0462:             * @param newValue the new value
0463:             */
0464:
0465:            // not final - SystemOption overrides it, e.g.
0466:            protected void firePropertyChange(String name, Object oldValue,
0467:                    Object newValue) {
0468:                PropertyChangeSupport supp = (PropertyChangeSupport) getProperty(PROP_SUPPORT);
0469:
0470:                if (supp != null) {
0471:                    supp.firePropertyChange(name, oldValue, newValue);
0472:                }
0473:            }
0474:
0475:            /** Writes nothing to the stream.
0476:             * @param oo ignored
0477:             */
0478:            public void writeExternal(ObjectOutput oo) throws IOException {
0479:            }
0480:
0481:            /** Reads nothing from the stream.
0482:             * @param oi ignored
0483:             */
0484:            public void readExternal(ObjectInput oi) throws IOException,
0485:                    ClassNotFoundException {
0486:            }
0487:
0488:            /** This method provides correct handling of serialization and deserialization.
0489:             * When serialized the method writeExternal is used to store the state.
0490:             * When deserialized first an instance is located by a call to findObject (clazz, true)
0491:             * and then a method readExternal is called to read its state from stream.
0492:             * <P>
0493:             * This allows to have only one instance of the class in the system and work
0494:             * only with it.
0495:             *
0496:             * @return write replace object that handles the described serialization/deserialization process
0497:             */
0498:            protected Object writeReplace() {
0499:                return new WriteReplace(this );
0500:            }
0501:
0502:            /** Obtain an instance of the desired class, if there is one.
0503:             * @param clazz the shared class to look for
0504:             * @return the instance, or <code>null</code> if such does not exists
0505:             */
0506:            public static <T extends SharedClassObject> T findObject(
0507:                    Class<T> clazz) {
0508:                return findObject(clazz, false);
0509:            }
0510:
0511:            /** Find an existing object, possibly creating a new one as needed.
0512:             * To create a new instance the class must be public and have a public
0513:             * default constructor.
0514:             *
0515:             * @param clazz the class of the object to find (must extend <code>SharedClassObject</code>)
0516:             * @param create <code>true</code> if the object should be created if it does not yet exist
0517:             * @return an instance, or <code>null</code> if there was none and <code>create</code> was <code>false</code>
0518:             * @exception IllegalArgumentException if a new instance could not be created for some reason
0519:             */
0520:            public static <T extends SharedClassObject> T findObject(
0521:                    Class<T> clazz, boolean create) {
0522:                // synchronizing on the same object as returned from getLock()
0523:                synchronized (clazz.getName().intern()) {
0524:                    DataEntry de = values.get(clazz);
0525:
0526:                    // either null or the object
0527:                    SharedClassObject obj = (de == null) ? null : de.get();
0528:                    boolean created = false;
0529:
0530:                    if ((obj == null) && create) {
0531:                        // try to create new instance
0532:                        SetAccessibleAction action = new SetAccessibleAction(
0533:                                clazz);
0534:
0535:                        try {
0536:                            obj = AccessController.doPrivileged(action);
0537:                        } catch (PrivilegedActionException e) {
0538:                            Exception ex = e.getException();
0539:                            IllegalArgumentException newEx = new IllegalArgumentException(
0540:                                    ex.toString());
0541:                            newEx.initCause(ex);
0542:                            throw newEx;
0543:                        }
0544:
0545:                        created = true;
0546:                    }
0547:
0548:                    de = values.get(clazz);
0549:
0550:                    if (de != null) {
0551:                        SharedClassObject obj2 = de.get();
0552:
0553:                        if ((obj != null) && (obj != obj2)) {
0554:                            // Tricked! The static initializer for the class called findObject on itself.
0555:                            // So we created two instances of it.
0556:                            // Returning only the first (that created by the static initializer, rather
0557:                            // than by us explicitly), to avoid duplication.
0558:                            //System.err.println ("Nesting #2: " + clazz.getName ());
0559:                            if ((obj2 == null) && create) {
0560:                                throw new IllegalStateException(
0561:                                        "Inconsistent state: " + clazz); // NOI18N
0562:                            }
0563:
0564:                            return clazz.cast(obj2);
0565:                        }
0566:                    }
0567:
0568:                    if (created) {
0569:                        // This hack was created due to the remove of SystemOptions deserialization
0570:                        // from project open operation, all SystemOptions are deserialized at this place
0571:                        // the first time anybody asks for the option.
0572:                        // It's crutial to do this just for SystemOptions and not for any other SharedClassObject,
0573:                        // otherwise it can cause deadlocks.
0574:                        // Lookup in the active session is used to find serialized state of the option,
0575:                        // if such state exists it is deserialized before the object is returned from lookup.
0576:                        if (obj.isSystemOption()) {
0577:                            // Lookup will find serialized version of searched object and deserialize it
0578:                            final Lookup.Result<T> r = Lookup.getDefault()
0579:                                    .lookup(new Lookup.Template<T>(clazz));
0580:
0581:                            if (r.allInstances().isEmpty()) {
0582:                                // #17711: folder lookup not yet initialized. Try to load the option later.
0583:                                // In the meantime the default state of the option will be available.
0584:                                // If any attempt is made to change the option, _and_ it is later loaded,
0585:                                // then we print a stack trace of the mutation for debugging (since the mutations
0586:                                // would get clobbered by loading the settings from layer or whatever).
0587:                                obj.waitingOnSystemOption = true;
0588:
0589:                                final SharedClassObject _obj = obj;
0590:                                final IllegalStateException start = new IllegalStateException(
0591:                                        "Making a SystemOption here that is not in lookup..."); // NOI18N
0592:
0593:                                class SOLoader implements  LookupListener {
0594:                                    public void resultChanged(LookupEvent ev) {
0595:                                        if (!r.allInstances().isEmpty()) {
0596:                                            // Got it.
0597:                                            r
0598:                                                    .removeLookupListener(SOLoader.this );
0599:
0600:                                            synchronized (_obj.getLock()) {
0601:                                                _obj.waitingOnSystemOption = false;
0602:
0603:                                                if (_obj.prematureSystemOptionMutation != null) {
0604:                                                    warn(start);
0605:                                                    warn(_obj.prematureSystemOptionMutation);
0606:                                                    warn(new IllegalStateException(
0607:                                                            "...and maybe getting clobbered here, see #17711.")); // NOI18N
0608:                                                    _obj.prematureSystemOptionMutation = null;
0609:                                                }
0610:                                            }
0611:                                        }
0612:                                    }
0613:                                }
0614:                                r.addLookupListener(new SOLoader());
0615:                            }
0616:                        }
0617:                    }
0618:
0619:                    if ((obj == null) && create) {
0620:                        throw new IllegalStateException("Inconsistent state: "
0621:                                + clazz); // NOI18N
0622:                    }
0623:
0624:                    return clazz.cast(obj);
0625:                }
0626:            }
0627:
0628:            /** checks whether we are instance of system option.
0629:             */
0630:            private boolean isSystemOption() {
0631:                Class c = this .getClass();
0632:
0633:                while (c != SharedClassObject.class) {
0634:                    if ("org.openide.options.SystemOption".equals(c.getName())) {
0635:                        return true; // NOI18N
0636:                    }
0637:
0638:                    c = c.getSuperclass();
0639:                }
0640:
0641:                return false;
0642:            }
0643:
0644:            // See above:
0645:            private static void warn(Throwable t) {
0646:                err.log(Level.WARNING, null, t);
0647:            }
0648:
0649:            static SharedClassObject createInstancePrivileged(
0650:                    Class<? extends SharedClassObject> clazz) throws Exception {
0651:                java.lang.reflect.Constructor<? extends SharedClassObject> c = clazz
0652:                        .getDeclaredConstructor(new Class[0]);
0653:                c.setAccessible(true);
0654:
0655:                String name = clazz.getName();
0656:                assert instancesBeingCreated != null;
0657:
0658:                synchronized (instancesBeingCreated) {
0659:                    Integer i = instancesBeingCreated.get(name);
0660:                    instancesBeingCreated.put(name,
0661:                            (i == null) ? new Integer(1) : new Integer(i
0662:                                    .intValue() + 1));
0663:                }
0664:
0665:                try {
0666:                    return c.newInstance(new Object[0]);
0667:                } finally {
0668:                    synchronized (instancesBeingCreated) {
0669:                        Integer i = instancesBeingCreated.get(name);
0670:
0671:                        if (i.intValue() == 1) {
0672:                            instancesBeingCreated.remove(name);
0673:                        } else {
0674:                            instancesBeingCreated.put(name, new Integer(i
0675:                                    .intValue() - 1));
0676:                        }
0677:                    }
0678:
0679:                    c.setAccessible(false);
0680:                }
0681:            }
0682:
0683:            /** Is called by the infrastructure in cases when a clean instance is requested.
0684:             * As instances of <code>SharedClassObject</code> are singletons, there is
0685:             * no way how to create new instance that would not contain the same data
0686:             * as previously existing one. This method allows all subclasses that care
0687:             * about the ability to refresh the settings (like <code>SystemOption</code>s)
0688:             * to be notified about the cleaning request and clean their settings themselves.
0689:             * <p>
0690:             * Default implementation does nothing.
0691:             *
0692:             * @since made protected in version 4.46
0693:             */
0694:            protected void reset() {
0695:            }
0696:
0697:            /** Class that is used as default write replace.
0698:             */
0699:            static final class WriteReplace extends Object implements 
0700:                    Serializable {
0701:                /** serialVersionUID */
0702:                static final long serialVersionUID = 1327893248974327640L;
0703:
0704:                /** the class  */
0705:                private Class<? extends SharedClassObject> clazz;
0706:
0707:                /** class name, in case clazz could not be reloaded */
0708:                private String name;
0709:
0710:                /** shared instance */
0711:                private transient SharedClassObject object;
0712:
0713:                /** Constructor.
0714:                 * @param the instance
0715:                 */
0716:                public WriteReplace(SharedClassObject object) {
0717:                    this .object = object;
0718:                    this .clazz = object.getClass();
0719:                    this .name = clazz.getName();
0720:                }
0721:
0722:                /** Write object.
0723:                 */
0724:                private void writeObject(ObjectOutputStream oos)
0725:                        throws IOException {
0726:                    oos.defaultWriteObject();
0727:
0728:                    object.writeExternal(oos);
0729:                }
0730:
0731:                /** Read object.
0732:                 */
0733:                private void readObject(ObjectInputStream ois)
0734:                        throws IOException, ClassNotFoundException {
0735:                    ois.defaultReadObject();
0736:
0737:                    if (clazz == null) {
0738:                        // Means that the class is no longer available in the restoring classloader.
0739:                        // Normal enough if the module has been uninstalled etc. #15654
0740:                        if (name != null) {
0741:                            throw new ClassNotFoundException(name);
0742:                        } else {
0743:                            // Compatibility with older WR's.
0744:                            throw new ClassNotFoundException();
0745:                        }
0746:                    }
0747:
0748:                    object = findObject(clazz, true);
0749:                    object.inReadExternal = true;
0750:
0751:                    try {
0752:                        object.readExternal(ois);
0753:                    } finally {
0754:                        object.inReadExternal = false;
0755:                    }
0756:                }
0757:
0758:                /** Read resolve to the read object.
0759:                 * We give chance to actual instance to do its own resolution as well. It
0760:                 * is necessary for achieving back compatability of certain types of settings etc.
0761:                 */
0762:                private Object readResolve() throws ObjectStreamException {
0763:                    SharedClassObject resolved = object;
0764:
0765:                    Method resolveMethod = findReadResolveMethod(object
0766:                            .getClass());
0767:
0768:                    if (resolveMethod != null) {
0769:                        // invoke resolve method and accept its result
0770:                        try {
0771:                            // make readResolve accessible (it can have any access modifier)
0772:                            resolveMethod.setAccessible(true);
0773:
0774:                            return resolveMethod.invoke(object);
0775:                        } catch (Exception ex) {
0776:                            // checked or runtime does not matter - we must survive
0777:                            String banner = "Skipping " + object.getClass()
0778:                                    + " resolution:"; //NOI18N
0779:                            err.log(Level.WARNING, banner, ex);
0780:                        } finally {
0781:                            resolveMethod.setAccessible(false);
0782:                        }
0783:                    }
0784:
0785:                    return resolved;
0786:                }
0787:
0788:                /** Tries to find readResolve method in given class. Finds
0789:                 * both public and non-public occurences of the method and
0790:                 * searches also in superclasses */
0791:                private static Method findReadResolveMethod(Class clazz) {
0792:                    Method result = null;
0793:
0794:                    //  try ANY-MODIFIER occurences; search also in superclasses
0795:                    for (Class<?> i = clazz; i != null; i = i.getSuperclass()) {
0796:                        try {
0797:                            result = accept(i.getDeclaredMethod("readResolve")); // NOI18N
0798:
0799:                            // get out of cycle if method found
0800:                            if (result != null) {
0801:                                break;
0802:                            }
0803:                        } catch (NoSuchMethodException exc) {
0804:                            // readResolve does not exist in current class
0805:                        }
0806:                    }
0807:
0808:                    return result;
0809:                }
0810:
0811:                /*
0812:                 * @return passed method if method matches exactly readResolve declaration as defined in
0813:                 *         Serializetion specification otherwise null
0814:                 */
0815:                private static Method accept(Method candidate) {
0816:                    if (candidate != null) {
0817:                        // check exceptions clause
0818:                        Class[] result = candidate.getExceptionTypes();
0819:
0820:                        if ((result.length == 1)
0821:                                && ObjectStreamException.class
0822:                                        .equals(result[0])) {
0823:                            // returned value type
0824:                            if (Object.class.equals(candidate.getReturnType())) {
0825:                                return candidate;
0826:                            }
0827:                        }
0828:                    }
0829:
0830:                    return null;
0831:                }
0832:            }
0833:
0834:            /** The inner class that encapsulates the shared data together with
0835:             * a reference counter
0836:             */
0837:            static final class DataEntry extends Object {
0838:                /** The data */
0839:                private HashMap<Object, Object> map;
0840:
0841:                /** The reference counter */
0842:                private int count = 0;
0843:
0844:                /** weak reference to an object of this class */
0845:                private WeakReference<SharedClassObject> ref = new WeakReference<SharedClassObject>(
0846:                        null);
0847:
0848:                /** inited? */
0849:                private boolean initialized = false;
0850:                private boolean initializeInProgress = false;
0851:
0852:                /** #7479: if initialize() threw unchecked exception, keep it here */
0853:                private Throwable invalid = null;
0854:
0855:                public String toString() { // for debugging
0856:
0857:                    return "SCO.DataEntry[ref=" + ref.get() + ",count=" + count
0858:                            + ",initialized=" + initialized + ",invalid="
0859:                            + invalid + ",map=" + map + "]"; // NOI18N
0860:                }
0861:
0862:                /** initialize() is in progress? */
0863:                boolean isInInitialize() {
0864:                    return initializeInProgress;
0865:                }
0866:
0867:                /** Returns the data
0868:                 * @param obj the requestor object
0869:                 * @return the data
0870:                 */
0871:                Map<Object, Object> getMap(SharedClassObject obj) {
0872:                    ensureValid(obj);
0873:
0874:                    if (map == null) {
0875:                        // to signal invalid state
0876:                        map = new HashMap<Object, Object>();
0877:                    }
0878:
0879:                    if (!initialized) {
0880:                        initialized = true;
0881:
0882:                        // no data for this class yet
0883:                        tryToInitialize(obj);
0884:                    }
0885:
0886:                    return map;
0887:                }
0888:
0889:                /** Returns a value for given key
0890:                 * @param obj the requestor object
0891:                 * @return the data
0892:                 */
0893:                Object get(SharedClassObject obj, Object key) {
0894:                    ensureValid(obj);
0895:
0896:                    Object ret;
0897:
0898:                    if (map == null) {
0899:                        // to signal invalid state
0900:                        map = new HashMap<Object, Object>();
0901:                        ret = null;
0902:                    } else {
0903:                        ret = map.get(key);
0904:                    }
0905:
0906:                    if ((ret == null) && !initialized) {
0907:                        if (key == PROP_SUPPORT) {
0908:                            return null;
0909:                        }
0910:
0911:                        initialized = true;
0912:
0913:                        // no data for this class yet
0914:                        tryToInitialize(obj);
0915:                        ret = map.get(key);
0916:                    }
0917:
0918:                    return ret;
0919:                }
0920:
0921:                /** Returns the data
0922:                 * @return the data
0923:                 */
0924:                Map getMap() {
0925:                    ensureValid(get());
0926:
0927:                    if (map == null) {
0928:                        // to signal invalid state
0929:                        map = new HashMap<Object, Object>();
0930:                    }
0931:
0932:                    return map;
0933:                }
0934:
0935:                private void ensureValid(SharedClassObject obj)
0936:                        throws IllegalStateException {
0937:                    if (invalid != null) {
0938:                        String msg;
0939:
0940:                        if (obj != null) {
0941:                            msg = obj.toString();
0942:                        } else {
0943:                            msg = "<unknown object>"; // NOI18N
0944:                        }
0945:
0946:                        throw (IllegalStateException) new IllegalStateException(
0947:                                msg).initCause(invalid);
0948:                    }
0949:                    // else fine
0950:                }
0951:
0952:                private void tryToInitialize(SharedClassObject obj)
0953:                        throws IllegalStateException {
0954:                    initializeInProgress = true;
0955:                    obj.initializeSuper = false;
0956:
0957:                    try {
0958:                        obj.initialize();
0959:                    } catch (Exception e) {
0960:                        invalid = e;
0961:                        throw (IllegalStateException) new IllegalStateException(
0962:                                invalid.toString() + " from " + obj)
0963:                                .initCause(invalid); // NOI18N
0964:                    } catch (LinkageError e) {
0965:                        invalid = e;
0966:                        throw (IllegalStateException) new IllegalStateException(
0967:                                invalid.toString() + " from " + obj)
0968:                                .initCause(invalid); // NOI18N
0969:                    } finally {
0970:                        initializeInProgress = false;
0971:                    }
0972:
0973:                    if (!obj.initializeSuper) {
0974:                        String msg = "You must call super.initialize() from "
0975:                                + obj.getClass().getName() + ".initialize()"; // NOI18N
0976:                        err.warning(msg);
0977:                    }
0978:                }
0979:
0980:                /** Increases the counter (thread safe)
0981:                 * @return new counter value
0982:                 */
0983:                int increase() {
0984:                    return ++count;
0985:                }
0986:
0987:                /** Dereases the counter (thread safe)
0988:                 * @return new counter value
0989:                 */
0990:                int decrease() {
0991:                    return --count;
0992:                }
0993:
0994:                /** Request for first object. If there is none, use the requestor
0995:                 * @param obj requestor
0996:                 * @return the an object of this type
0997:                 */
0998:                SharedClassObject first(SharedClassObject obj) {
0999:                    SharedClassObject s = ref.get();
1000:
1001:                    if (s == null) {
1002:                        ref = new WeakReference<SharedClassObject>(obj);
1003:
1004:                        return obj;
1005:                    } else {
1006:                        return s;
1007:                    }
1008:                }
1009:
1010:                /** @return shared object or null
1011:                 */
1012:                public SharedClassObject get() {
1013:                    return ref.get();
1014:                }
1015:
1016:                /** Reset map of values. */
1017:                public void reset(SharedClassObject obj) {
1018:                    SharedClassObject s = get();
1019:
1020:                    if ((s != null) && (s != obj)) {
1021:                        return;
1022:                    }
1023:
1024:                    invalid = null;
1025:                    getMap().clear();
1026:
1027:                    initialized = true;
1028:                    tryToInitialize(obj);
1029:                }
1030:            }
1031:
1032:            static final class SetAccessibleAction implements 
1033:                    PrivilegedExceptionAction<SharedClassObject> {
1034:                Class<? extends SharedClassObject> klass;
1035:
1036:                SetAccessibleAction(Class<? extends SharedClassObject> klass) {
1037:                    this .klass = klass;
1038:                }
1039:
1040:                public SharedClassObject run() throws Exception {
1041:                    return createInstancePrivileged(klass);
1042:                }
1043:            }
1044:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.