PageRenderTime 55ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/netbeans-platform-7.0.1/openide.util.lookup/src/org/openide/util/lookup/SimpleProxyLookup.java

#
Java | 371 lines | 229 code | 61 blank | 81 comment | 57 complexity | a9a3c4929c646d9f5dde4bb6d62320d1 MD5 | raw file
Possible License(s): MIT, Apache-2.0, LGPL-2.1, GPL-2.0, CPL-1.0, BSD-3-Clause
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
  5. *
  6. * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
  7. * Other names may be trademarks of their respective owners.
  8. *
  9. * The contents of this file are subject to the terms of either the GNU
  10. * General Public License Version 2 only ("GPL") or the Common
  11. * Development and Distribution License("CDDL") (collectively, the
  12. * "License"). You may not use this file except in compliance with the
  13. * License. You can obtain a copy of the License at
  14. * http://www.netbeans.org/cddl-gplv2.html
  15. * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
  16. * specific language governing permissions and limitations under the
  17. * License. When distributing the software, include this License Header
  18. * Notice in each file and include the License file at
  19. * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
  20. * particular file as subject to the "Classpath" exception as provided
  21. * by Oracle in the GPL Version 2 section of the License file that
  22. * accompanied this code. If applicable, add the following below the
  23. * License Header, with the fields enclosed by brackets [] replaced by
  24. * your own identifying information:
  25. * "Portions Copyrighted [year] [name of copyright owner]"
  26. *
  27. * Contributor(s):
  28. *
  29. * The Original Software is NetBeans. The Initial Developer of the Original
  30. * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
  31. * Microsystems, Inc. All Rights Reserved.
  32. *
  33. * If you wish your version of this file to be governed by only the CDDL
  34. * or only the GPL Version 2, indicate your decision by adding
  35. * "[Contributor] elects to include this software in this distribution
  36. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  37. * single choice of license, a recipient has the option to distribute
  38. * your version of this file under either the CDDL, the GPL Version 2 or
  39. * to extend the choice of license to its licensees as provided above.
  40. * However, if you add GPL Version 2 code and therefore, elected the GPL
  41. * Version 2 license, then the option applies only if the new code is
  42. * made subject to such option by the copyright holder.
  43. */
  44. package org.openide.util.lookup;
  45. import java.lang.ref.Reference;
  46. import java.lang.ref.WeakReference;
  47. import org.openide.util.Lookup;
  48. import org.openide.util.LookupEvent;
  49. import org.openide.util.LookupListener;
  50. import java.util.*;
  51. /**
  52. * Simple proxy lookup. Keeps reference to a lookup it delegates to and
  53. * forwards all requests.
  54. *
  55. * @author Jaroslav Tulach
  56. */
  57. final class SimpleProxyLookup extends org.openide.util.Lookup {
  58. /** the provider to check for the status */
  59. private Provider provider;
  60. /** the lookup we currently delegate to */
  61. private Lookup delegate;
  62. /** map of all templates to Reference (results) associated to this lookup */
  63. private WeakHashMap<Template<?>,Reference<ProxyResult<?>>> results;
  64. /**
  65. * @param provider provider to delegate to
  66. */
  67. SimpleProxyLookup(Provider provider) {
  68. this.provider = provider;
  69. }
  70. /** Checks whether we still delegate to the same lookup */
  71. private Lookup checkLookup() {
  72. Lookup l = provider.getLookup();
  73. // iterator over Reference (ProxyResult)
  74. Iterator<Reference<ProxyResult<?>>> toCheck = null;
  75. synchronized (this) {
  76. if (l != delegate) {
  77. this.delegate = l;
  78. if (results != null) {
  79. toCheck = new ArrayList<Reference<ProxyResult<?>>>(results.values()).iterator();
  80. }
  81. }
  82. }
  83. if (toCheck != null) {
  84. // update
  85. ArrayList<Object> evAndListeners = new ArrayList<Object>();
  86. for (Iterator<Reference<ProxyResult<?>>> it = toCheck; it.hasNext(); ) {
  87. java.lang.ref.Reference<ProxyResult<?>> ref = it.next();
  88. if (ref == null) {
  89. continue;
  90. }
  91. ProxyResult<?> p = ref.get();
  92. if (p != null && p.updateLookup(p.delegate, l)) {
  93. p.collectFires(evAndListeners);
  94. }
  95. }
  96. for (Iterator it = evAndListeners.iterator(); it.hasNext(); ) {
  97. LookupEvent ev = (LookupEvent)it.next();
  98. LookupListener ll = (LookupListener)it.next();
  99. ll.resultChanged(ev);
  100. }
  101. }
  102. return delegate;
  103. }
  104. @SuppressWarnings("unchecked")
  105. private static <T> ProxyResult<T> cast(ProxyResult<?> p) {
  106. return (ProxyResult<T>)p;
  107. }
  108. public <T> Result<T> lookup(Template<T> template) {
  109. ProxyResult<T> newP;
  110. synchronized (this) {
  111. if (results == null) {
  112. results = new WeakHashMap<Template<?>,Reference<ProxyResult<?>>>();
  113. } else {
  114. Reference<ProxyResult<?>> ref = results.get(template);
  115. if (ref != null) {
  116. ProxyResult<?> p = ref.get();
  117. if (p != null) {
  118. return cast(p);
  119. }
  120. }
  121. }
  122. newP = new ProxyResult<T>(template);
  123. Reference<ProxyResult<?>> ref = new WeakReference<ProxyResult<?>>(newP);
  124. results.put(template, ref);
  125. }
  126. newP.checkResult();
  127. return newP;
  128. }
  129. public <T> T lookup(Class<T> clazz) {
  130. if (clazz == null) {
  131. checkLookup();
  132. return null;
  133. }
  134. return checkLookup().lookup(clazz);
  135. }
  136. public <T> Item<T> lookupItem(Template<T> template) {
  137. return checkLookup().lookupItem(template);
  138. }
  139. /**
  140. * Result used in SimpleLookup. It holds a reference to the collection
  141. * passed in constructor. As the contents of this lookup result never
  142. * changes the addLookupListener and removeLookupListener are empty.
  143. */
  144. private final class ProxyResult<T> extends WaitableResult<T> implements LookupListener {
  145. /** Template used for this result. It is never null.*/
  146. private Template<T> template;
  147. /** result to delegate to */
  148. private Lookup.Result<T> delegate;
  149. /** listeners set */
  150. private javax.swing.event.EventListenerList listeners;
  151. private LookupListener lastListener;
  152. /** Just remembers the supplied argument in variable template.*/
  153. ProxyResult(Template<T> template) {
  154. this.template = template;
  155. }
  156. /** Checks state of the result
  157. */
  158. private Result<T> checkResult() {
  159. Lookup.Result lkp = delegate;
  160. updateLookup(lkp, checkLookup());
  161. return this.delegate;
  162. }
  163. /** Updates the state of the lookup.
  164. * @return true if the lookup really changed
  165. */
  166. public boolean updateLookup(Lookup.Result prev, Lookup l) {
  167. Collection<? extends Item<T>> oldPairs = null;
  168. if (prev != null) {
  169. oldPairs = prev.allItems();
  170. }
  171. LookupListener prevListener;
  172. Result<T> toAdd;
  173. for (;;) {
  174. synchronized (this) {
  175. if ((delegate != null) && (lastListener != null)) {
  176. prevListener = lastListener;
  177. delegate.removeLookupListener(lastListener);
  178. } else {
  179. prevListener = null;
  180. }
  181. }
  182. // cannot call to foreign code
  183. Lookup.Result<T> res = l.lookup(template);
  184. synchronized (this) {
  185. if (prevListener == lastListener) {
  186. delegate = res;
  187. lastListener = new WeakResult<T>(this, delegate);
  188. toAdd = delegate;
  189. break;
  190. }
  191. }
  192. }
  193. toAdd.addLookupListener(lastListener);
  194. if (oldPairs == null) {
  195. // nobody knows about a change
  196. return false;
  197. }
  198. Collection<? extends Item<T>> newPairs = delegate.allItems();
  199. // See #34961 for explanation.
  200. if (!(oldPairs instanceof List)) {
  201. if (oldPairs == Collections.EMPTY_SET) {
  202. // avoid allocation
  203. oldPairs = Collections.emptyList();
  204. } else {
  205. oldPairs = new ArrayList<Item<T>>(oldPairs);
  206. }
  207. }
  208. if (!(newPairs instanceof List)) {
  209. newPairs = new ArrayList<Item<T>>(newPairs);
  210. }
  211. return !oldPairs.equals(newPairs);
  212. }
  213. public synchronized void addLookupListener(LookupListener l) {
  214. if (listeners == null) {
  215. listeners = new javax.swing.event.EventListenerList();
  216. }
  217. listeners.add(LookupListener.class, l);
  218. }
  219. public synchronized void removeLookupListener(LookupListener l) {
  220. if (listeners != null) {
  221. listeners.remove(LookupListener.class, l);
  222. }
  223. }
  224. public java.util.Collection<? extends T> allInstances() {
  225. return checkResult().allInstances();
  226. }
  227. public Set<Class<? extends T>> allClasses() {
  228. return checkResult().allClasses();
  229. }
  230. public Collection<? extends Item<T>> allItems() {
  231. return checkResult().allItems();
  232. }
  233. protected void beforeLookup(Lookup.Template t) {
  234. Lookup.Result r = checkResult();
  235. if (r instanceof WaitableResult) {
  236. ((WaitableResult) r).beforeLookup(t);
  237. }
  238. }
  239. /** A change in lookup occured.
  240. * @param ev event describing the change
  241. *
  242. */
  243. public void resultChanged(LookupEvent anEvent) {
  244. collectFires(null);
  245. }
  246. protected void collectFires(Collection<Object> evAndListeners) {
  247. javax.swing.event.EventListenerList l = this.listeners;
  248. if (l == null) {
  249. return;
  250. }
  251. Object[] listeners = l.getListenerList();
  252. if (listeners.length == 0) {
  253. return;
  254. }
  255. LookupEvent ev = new LookupEvent(this);
  256. AbstractLookup.notifyListeners(listeners, ev, evAndListeners);
  257. }
  258. }
  259. // end of ProxyResult
  260. private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
  261. private Lookup.Result source;
  262. private Reference<ProxyResult<T>> result;
  263. public WeakResult(ProxyResult<T> r, Lookup.Result<T> s) {
  264. this.result = new WeakReference<ProxyResult<T>>(r);
  265. this.source = s;
  266. }
  267. protected void beforeLookup(Lookup.Template t) {
  268. ProxyResult r = (ProxyResult)result.get();
  269. if (r != null) {
  270. r.beforeLookup(t);
  271. } else {
  272. source.removeLookupListener(this);
  273. }
  274. }
  275. protected void collectFires(Collection<Object> evAndListeners) {
  276. ProxyResult<T> r = result.get();
  277. if (r != null) {
  278. r.collectFires(evAndListeners);
  279. } else {
  280. source.removeLookupListener(this);
  281. }
  282. }
  283. public void addLookupListener(LookupListener l) {
  284. assert false;
  285. }
  286. public void removeLookupListener(LookupListener l) {
  287. assert false;
  288. }
  289. public Collection<T> allInstances() {
  290. assert false;
  291. return null;
  292. }
  293. public void resultChanged(LookupEvent ev) {
  294. ProxyResult r = (ProxyResult)result.get();
  295. if (r != null) {
  296. r.resultChanged(ev);
  297. } else {
  298. source.removeLookupListener(this);
  299. }
  300. }
  301. public Collection<? extends Item<T>> allItems() {
  302. assert false;
  303. return null;
  304. }
  305. public Set<Class<? extends T>> allClasses() {
  306. assert false;
  307. return null;
  308. }
  309. } // end of WeakResult
  310. }