KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > spi > project > support > LookupProviderSupport


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 package org.netbeans.spi.project.support;
20
21 import java.lang.ref.Reference JavaDoc;
22 import java.lang.ref.WeakReference JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Arrays JavaDoc;
25 import java.util.Collection JavaDoc;
26 import java.util.Collections JavaDoc;
27 import java.util.List JavaDoc;
28 import javax.swing.event.ChangeEvent JavaDoc;
29 import javax.swing.event.ChangeListener JavaDoc;
30 import org.netbeans.api.project.SourceGroup;
31 import org.netbeans.api.project.Sources;
32 import org.netbeans.spi.project.LookupMerger;
33 import org.netbeans.spi.project.LookupProvider;
34 import org.openide.ErrorManager;
35 import org.openide.filesystems.FileObject;
36 import org.openide.filesystems.Repository;
37 import org.openide.loaders.DataFolder;
38 import org.openide.loaders.FolderLookup;
39 import org.openide.util.Lookup;
40 import org.openide.util.LookupEvent;
41 import org.openide.util.LookupListener;
42 import org.openide.util.WeakListeners;
43 import org.openide.util.lookup.Lookups;
44 import org.openide.util.lookup.ProxyLookup;
45
46 /**
47  * Factory for lookup capable of merging content from registered
48  * {@link org.netbeans.spi.project.LookupProvider} instances.
49  * @author mkleint
50  * @since org.netbeans.modules.projectapi 1.12
51  */

52 public final class LookupProviderSupport {
53     
54     /** Creates a new instance of LookupProviderSupport */
55     private LookupProviderSupport() {
56     }
57     
58     /**
59      * Creates a project lookup instance that combines the content from multiple sources.
60      * A convenience factory method for implementors of Project
61      *
62      * @param baseLookup initial, base content of the project lookup created by the project owner
63      * @param folderPath the path in the System Filesystem that is used as root for lookup composition.
64      * The content of the folder is assumed to be {@link org.netbeans.spi.project.LookupProvider} instances
65      * @return a lookup to be used in project
66      */

67     public static Lookup createCompositeLookup(Lookup baseLookup, String JavaDoc folderPath) {
68         return new DelegatingLookupImpl(baseLookup, folderPath);
69     }
70     
71     /**
72      * Factory method for creating {@link org.netbeans.spi.project.LookupMerger} instance that merges
73      * {@link org.netbeans.api.project.Sources} instances in the project lookup.
74      * Allows to compose the {@link org.netbeans.api.project.Sources}
75      * content from multiple sources.
76      * @return instance to include in project lookup
77      */

78     public static LookupMerger createSourcesMerger() {
79         return new SourcesMerger();
80     }
81     
82     //TODO maybe have just one single instance for a given path?
83
private static Lookup createLookup(String JavaDoc folderPath) {
84         FileObject root = Repository.getDefault().getDefaultFileSystem().findResource(folderPath);
85         if (root != null) {
86             DataFolder folder = DataFolder.findFolder(root);
87             return new FolderLookup(folder).getLookup();
88         } else { // #87544
89
return Lookup.EMPTY;
90         }
91     }
92     
93     static class DelegatingLookupImpl extends ProxyLookup implements LookupListener {
94         private Lookup baseLookup;
95         private Lookup.Result<LookupProvider> providerResult;
96         private LookupListener providerListener;
97         private List JavaDoc<LookupProvider> old = Collections.emptyList();
98         private List JavaDoc<Lookup> currentLookups;
99         
100         private Lookup.Result<LookupMerger> mergers;
101         private Reference JavaDoc<LookupListener> listenerRef;
102         //#68623: the proxy lookup fires changes only if someone listens on a particular template:
103
private List JavaDoc<Lookup.Result<?>> results = new ArrayList JavaDoc<Lookup.Result<?>>();
104         
105         public DelegatingLookupImpl(Lookup base, String JavaDoc path) {
106             this(base, createLookup(path));
107         }
108         
109         public DelegatingLookupImpl(Lookup base, Lookup providerLookup) {
110             super();
111             assert base != null;
112             baseLookup = base;
113             providerResult = providerLookup.lookup(new Lookup.Template<LookupProvider>(LookupProvider.class));
114             doDelegate(providerResult.allInstances());
115             providerListener = new LookupListener() {
116                 public void resultChanged(LookupEvent ev) {
117                     doDelegate(providerResult.allInstances());
118                 }
119             };
120             providerResult.addLookupListener(providerListener);
121         }
122         
123         
124         public void resultChanged(LookupEvent ev) {
125             doDelegate(providerResult.allInstances());
126         }
127         
128         
129         private synchronized void doDelegate(Collection JavaDoc<? extends LookupProvider> providers) {
130             //unregister listeners from the old results:
131
for (Lookup.Result<?> r : results) {
132                 r.removeLookupListener(this);
133             }
134             
135             List JavaDoc<Lookup> newLookups = new ArrayList JavaDoc<Lookup>();
136             for (LookupProvider elem : providers) {
137                 if (old.contains(elem)) {
138                     int index = old.indexOf(elem);
139                     newLookups.add(currentLookups.get(index));
140                 } else {
141                     Lookup newone = elem.createAdditionalLookup(baseLookup);
142                     assert newone != null;
143                     newLookups.add(newone);
144                 }
145             }
146             old = new ArrayList JavaDoc<LookupProvider>(providers);
147             currentLookups = newLookups;
148             newLookups.add(baseLookup);
149             Lookup lkp = new ProxyLookup(newLookups.toArray(new Lookup[newLookups.size()]));
150             
151             //merge:
152
List JavaDoc<Class JavaDoc<?>> filteredClasses = new ArrayList JavaDoc<Class JavaDoc<?>>();
153             List JavaDoc<Object JavaDoc> mergedInstances = new ArrayList JavaDoc<Object JavaDoc>();
154             LookupListener l = listenerRef != null ? listenerRef.get() : null;
155             if (l != null) {
156                 mergers.removeLookupListener(l);
157             }
158             mergers = lkp.lookupResult(LookupMerger.class);
159             l = WeakListeners.create(LookupListener.class, this, mergers);
160             listenerRef = new WeakReference JavaDoc<LookupListener>(l);
161             mergers.addLookupListener(l);
162             for (LookupMerger lm : mergers.allInstances()) {
163                 Class JavaDoc<?> c = lm.getMergeableClass();
164                 if (filteredClasses.contains(c)) {
165                     ErrorManager.getDefault().log(ErrorManager.WARNING,
166                             "Two LookupMerger registered for class " + c +
167                             ". Only first one will be used"); // NOI18N
168
continue;
169                 }
170                 filteredClasses.add(c);
171                 mergedInstances.add(lm.merge(lkp));
172                 
173                 Lookup.Result<?> result = lkp.lookupResult(c);
174                 
175                 result.addLookupListener(this);
176                 results.add(result);
177             }
178             lkp = Lookups.exclude(lkp, filteredClasses.toArray(new Class JavaDoc<?>[filteredClasses.size()]));
179             Lookup fixed = Lookups.fixed(mergedInstances.toArray(new Object JavaDoc[mergedInstances.size()]));
180             setLookups(fixed, lkp);
181         }
182     }
183     
184     
185     private static class SourcesMerger implements LookupMerger<Sources> {
186         private SourcesImpl merger;
187         
188         public Class JavaDoc<Sources> getMergeableClass() {
189             return Sources.class;
190         }
191
192         public Sources merge(Lookup lookup) {
193             if (merger == null) {
194                 merger = new SourcesImpl();
195             }
196             merger.setLookup(lookup);
197             return merger;
198         }
199     }
200     
201     private static class SourcesImpl implements Sources, ChangeListener JavaDoc, LookupListener {
202         private List JavaDoc<ChangeListener JavaDoc> listeners = new ArrayList JavaDoc<ChangeListener JavaDoc>();
203         private Lookup.Result<Sources> delegates;
204         private Collection JavaDoc<Sources> currentDelegates = new ArrayList JavaDoc<Sources>();
205         
206         public SourcesImpl() {
207         }
208
209         private void setLookup(Lookup lookup) {
210             if (currentDelegates.size() > 0) {
211                 for (Sources old : currentDelegates) {
212                     old.removeChangeListener(this);
213                 }
214                 currentDelegates.clear();
215             }
216             if (delegates != null) {
217                 delegates.removeLookupListener(this);
218             }
219             Lookup.Result<Sources> srcs = lookup.lookupResult(Sources.class);
220             for (Sources ns : srcs.allInstances()) {
221                 ns.addChangeListener(this);
222                 currentDelegates.add(ns);
223             }
224             srcs.addLookupListener(this);
225             delegates = srcs;
226             fireChange();
227         }
228
229         public SourceGroup[] getSourceGroups(String JavaDoc type) {
230             assert delegates != null;
231             Collection JavaDoc<SourceGroup> result = new ArrayList JavaDoc<SourceGroup>();
232             for (Sources ns : delegates.allInstances()) {
233                 SourceGroup[] grps = ns.getSourceGroups(type);
234                 if (grps != null) {
235                     result.addAll(Arrays.asList(grps));
236                 }
237             }
238             return result.toArray(new SourceGroup[result.size()]);
239         }
240
241         public synchronized void addChangeListener(ChangeListener JavaDoc listener) {
242             listeners.add(listener);
243         }
244
245         public synchronized void removeChangeListener(ChangeListener JavaDoc listener) {
246             listeners.remove(listener);
247         }
248
249         public void stateChanged(ChangeEvent JavaDoc e) {
250             fireChange();
251         }
252
253         private void fireChange() {
254             ArrayList JavaDoc<ChangeListener JavaDoc> list = new ArrayList JavaDoc<ChangeListener JavaDoc>();
255             synchronized (this) {
256                 list.addAll(listeners);
257             }
258             for (ChangeListener JavaDoc listener : list) {
259                 listener.stateChanged(new ChangeEvent JavaDoc(this));
260             }
261         }
262
263         public void resultChanged(LookupEvent ev) {
264             if (currentDelegates.size() > 0) {
265                 for (Sources old : currentDelegates) {
266                     old.removeChangeListener(this);
267                 }
268                 currentDelegates.clear();
269             }
270             for (Sources ns : delegates.allInstances()) {
271                 ns.addChangeListener(this);
272                 currentDelegates.add(ns);
273             }
274             fireChange();
275         }
276     }
277     
278 }
279
Popular Tags