KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > editor > ext > html > dtd > Registry


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.editor.ext.html.dtd;
21
22 import java.util.*;
23 import java.io.Reader JavaDoc;
24 import java.lang.ref.WeakReference JavaDoc;
25
26 /** This class stores references to DTDReaderProviders. It also acts as a cache
27  * for parsed DTDs and as the only factory for creating DTDs.
28  *
29  * @author Petr Nejedly
30  * @version 1.0
31  */

32 public class Registry {
33
34     /** The map [DTD public identifier -> Weak reference(DTD)]
35      * Works as a DTD cache. */

36     private static Map dtdMap = new HashMap();
37
38     /** List of all registered providers we use for parsing DTDs with */
39     private static List providers = new ArrayList();
40
41     /** The list of all listeners for DTD invalidate events. */
42     private static LinkedList listeners = new LinkedList();
43
44     /** The map [DTDReaderProvider -> Set[String]] representing
45      * the public identifiers of the DTDs parsed by this provider]
46      * Used when the provider is invalidated/removed. */

47     private static Map provider2dtds = new HashMap();
48
49
50     /** Add a DTD.InvalidateListener to the listener list.
51      * The listener will be notified when any DTD is changed.
52      * The listeners are referenced weakly, so they are removed
53      * automatically when they are no longer in use.
54      *
55      * @param listener The DTD.InvalidateListener to be added. */

56     public void addInvalidateListener( InvalidateListener listener ) {
57         synchronized( listeners ) {
58             listeners.add( new WeakReference JavaDoc( listener ) );
59         }
60     }
61
62     /** Remove a DTD.InvalidateListener from teh listener list.
63      * The listeners are referenced weakly, so they are removed
64      * automatically when they are no longer in use.
65      *
66      * @param listener The DTD.InvalidateListener to be removed. */

67     public void removeInvalidateListener( InvalidateListener listener ) {
68         synchronized( listeners ) {
69             // Iterator on LinkedList allows remove()
70
for( Iterator it = listeners.iterator(); it.hasNext(); ) {
71                 WeakReference JavaDoc ref = (WeakReference JavaDoc)it.next();
72                 InvalidateListener obj = (InvalidateListener)ref.get();
73                 // remove required or gc()ed references
74
if( obj == null || obj == listener ) it.remove();
75             }
76         }
77     }
78
79     /**
80      * Report an invalidation event to all registered listeners.
81      *
82      * @param identifiers The set of Strings representing the
83      * public identifiers of invalidated DTDs. */

84     public static void fireInvalidateEvent( Set identifiers ) {
85         // 1. clean up our cache
86
for( Iterator it = identifiers.iterator(); it.hasNext(); ) {
87             dtdMap.remove( it.next() );
88         }
89
90         // 2. gather all valid listeners, throw away those already dead.
91
java.util.List JavaDoc targets = new ArrayList();
92         synchronized( listeners ) {
93             for( Iterator it = listeners.iterator(); it.hasNext(); ) {
94                 WeakReference JavaDoc ref = (WeakReference JavaDoc)it.next();
95                 InvalidateListener obj = (InvalidateListener)ref.get();
96                 if( obj == null ) {
97                     it.remove();
98                 } else {
99                     targets.add( obj );
100                 }
101             }
102         }
103
104         // 3. distribute the event
105
InvalidateEvent evt = new InvalidateEvent( identifiers );
106         for( Iterator it = targets.iterator(); it.hasNext(); ) {
107             InvalidateListener l = (InvalidateListener)it.next();
108             l.dtdInvalidated( evt );
109         }
110     }
111
112
113     /** Add DTDReaderProvider. It can be then used for parsing the DTD.
114      * @param provider The ReaderProvider capable of providing
115      * any number of streams for any public identifier. It shall be able
116      * to provide streams for all public identifiers referenced from its
117      * streams.
118      */

119     public static void registerReaderProvider( ReaderProvider provider ) {
120         providers.add( provider );
121     }
122
123     /** Destroy all DTDs parsed from Readers provided by this provider
124      * and notify all registered users of such DTDs they are invalid now */

125     public static void invalidateReaderProvider( ReaderProvider provider ) {
126         Set identifiers = (Set)provider2dtds.get( provider );
127
128         if( identifiers != null ) {
129             // 2. clean up our cache and notify all registered users
130
// of affected DTDs.
131
fireInvalidateEvent( identifiers );
132
133             // 3. free the provider from the parsed refistry
134
provider2dtds.remove( provider );
135         }
136     }
137
138     /** Remove given ReaderProvider from usage, destroy all DTDs
139      * parsed from Readers provided by this provider and notify all
140      * registered users of such DTDs they are invalid now */

141     public static void unregisterReaderProvider( ReaderProvider provider ) {
142         // remove it from our provider list to not use it any more
143
providers.remove( provider );
144
145         invalidateReaderProvider( provider );
146     }
147
148
149
150     /** The "smart" method for accessing the items in the table, cares
151      * of the weak indirection and cleaning up the gc()ed cells.
152      */

153     private static DTD getWeak( String JavaDoc identifier ) {
154         WeakReference JavaDoc ref = (WeakReference JavaDoc)dtdMap.get( identifier );
155         if( ref == null ) // don't know even the key
156
return null;
157
158         DTD dtd = (DTD)ref.get();
159         if( dtd == null ) // gc()ed in the mean time, clean up the table
160
dtdMap.remove( identifier );
161
162         return dtd;
163     }
164
165     /** The method for storing an item into the map as a weak reference */
166     private static void putWeak( String JavaDoc identifier, DTD dtd ) {
167         dtdMap.put( identifier, new WeakReference JavaDoc( dtd ) );
168     }
169
170
171     private static ReaderProvider getProvider( String JavaDoc identifier, String JavaDoc fileName ) {
172         for( Iterator i = providers.iterator(); i.hasNext(); ) {
173              ReaderProvider prov = (ReaderProvider)i.next();
174              Reader JavaDoc reader = prov.getReaderForIdentifier( identifier, fileName );
175              if( reader != null ) return prov;
176         }
177         return null;
178     }
179
180     private static DTD parseDTD( String JavaDoc identifier, String JavaDoc fileName ) {
181         ReaderProvider prov = getProvider( identifier, fileName );
182         if( prov == null ) return null;
183         try {
184             DTD dtd = new DTDParser().createDTD( prov, identifier, fileName );
185             if( dtd != null ) {
186                 Set dtdSet = (Set)provider2dtds.get( prov );
187                 if( dtdSet == null ) {
188                     dtdSet = new HashSet();
189                     provider2dtds.put( prov, dtdSet );
190                 }
191
192                 dtdSet.add( identifier );
193                 putWeak( identifier, dtd );
194             }
195             return dtd;
196         } catch( DTDParser.WrongDTDException exc ) {
197 //System.err.println("TODO (DTD.java:90): Notify the error during parsing." );
198
return null;
199         }
200     }
201
202     /** Get the DTD identified by its public identifier, exact match
203      * of identifier is required.
204      * @param identifier public identifier of required DTD,
205      * e.g. "-//W3C//DTD HTML 4.01//EN"
206      * @param fileName the name of file for this DTD, is used only as a helper
207      * for lookup, could be <CODE>null</CODE>, or could be e.g. URL to
208      * the DTD on the internet, in which case proper DTDReaderProvider
209      * could try to fetch it from there.
210      * @return implementation of DTD interface for given public identifier,
211      * or null, if no such DTD is cached and could not be created from
212      * registered DTDReaderProviders.
213      */

214     public static DTD getDTD( String JavaDoc identifier, String JavaDoc fileName ) {
215         DTD dtd = getWeak( identifier );
216
217         if( dtd == null ) dtd = parseDTD( identifier, fileName );
218
219         return dtd;
220     }
221 }
222
Popular Tags