PageRenderTime 39ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/projects/netbeans-7.3/xml.schema.model/src/org/netbeans/modules/xml/schema/model/impl/GlobalComponentsIndexSupport.java

https://gitlab.com/essere.lab.public/qualitas.class-corpus
Java | 436 lines | 282 code | 36 blank | 118 comment | 71 complexity | a8d1e6e773767702a7ad4e8af7e81da7 MD5 | raw file
  1. /*
  2. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
  3. *
  4. * Copyright 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. * If you wish your version of this file to be governed by only the CDDL
  28. * or only the GPL Version 2, indicate your decision by adding
  29. * "[Contributor] elects to include this software in this distribution
  30. * under the [CDDL or GPL Version 2] license." If you do not indicate a
  31. * single choice of license, a recipient has the option to distribute
  32. * your version of this file under either the CDDL, the GPL Version 2 or
  33. * to extend the choice of license to its licensees as provided above.
  34. * However, if you add GPL Version 2 code and therefore, elected the GPL
  35. * Version 2 license, then the option applies only if the new code is
  36. * made subject to such option by the copyright holder.
  37. *
  38. * Contributor(s):
  39. *
  40. * Portions Copyrighted 2009 Sun Microsystems, Inc.
  41. */
  42. package org.netbeans.modules.xml.schema.model.impl;
  43. import java.text.DecimalFormat;
  44. import java.util.ArrayList;
  45. import java.util.HashSet;
  46. import java.util.List;
  47. import java.util.Map;
  48. import java.util.TreeMap;
  49. import org.netbeans.modules.xml.schema.model.GlobalAttribute;
  50. import org.netbeans.modules.xml.schema.model.GlobalAttributeGroup;
  51. import org.netbeans.modules.xml.schema.model.GlobalComplexType;
  52. import org.netbeans.modules.xml.schema.model.GlobalElement;
  53. import org.netbeans.modules.xml.schema.model.GlobalGroup;
  54. import org.netbeans.modules.xml.schema.model.GlobalSimpleType;
  55. import org.netbeans.modules.xml.schema.model.GlobalType;
  56. import org.netbeans.modules.xml.schema.model.Schema;
  57. import org.netbeans.modules.xml.schema.model.SchemaComponent;
  58. import org.netbeans.modules.xml.schema.model.visitor.FindGlobalReferenceVisitor;
  59. import org.netbeans.modules.xml.xam.ComponentEvent;
  60. import org.netbeans.modules.xml.xam.ComponentListener;
  61. import org.netbeans.modules.xml.xam.Named;
  62. import org.netbeans.modules.xml.xam.NamedReferenceable;
  63. import org.openide.util.RequestProcessor;
  64. /**
  65. * The Index is constructed lazily. It is initiated by call of the method
  66. * findByNameAndType(...).
  67. *
  68. * The index is build only for global level schema components (children of the schema
  69. * component) and if it's total amount exceeds GLOBAL_COMPONENT_INDEX_CREATE_THRESHOLD.
  70. *
  71. * On the contrary, if the total amount less them GLOBAL_COMPONENT_INDEX_REMOVE_THRESHOLD
  72. * the index is removed automatically.
  73. *
  74. * @author Nikita Krjukov
  75. */
  76. public class GlobalComponentsIndexSupport implements Runnable {
  77. private static HashSet<Class<? extends SchemaComponent>> mIndexedTypes =
  78. new HashSet<Class<? extends SchemaComponent>>();
  79. private static int GLOBAL_COMPONENT_INDEX_CREATE_THRESHOLD = 60;
  80. private static int GLOBAL_COMPONENT_INDEX_REMOVE_THRESHOLD = 50;
  81. private static int INDEX_RECALCULATION_DELAY = 100;
  82. private static RequestProcessor mIndexRecalculationRP;
  83. static {
  84. mIndexedTypes.add(GlobalAttribute.class);
  85. mIndexedTypes.add(GlobalAttributeGroup.class);
  86. mIndexedTypes.add(GlobalGroup.class);
  87. mIndexedTypes.add(GlobalType.class);
  88. mIndexedTypes.add(GlobalSimpleType.class);
  89. mIndexedTypes.add(GlobalComplexType.class);
  90. mIndexedTypes.add(GlobalElement.class);
  91. // 3 Schema models can be processed in parallel.
  92. mIndexRecalculationRP = new RequestProcessor("IndexRecalculator", 3, true);
  93. }
  94. private SchemaModelImpl mSModel;
  95. // Index of global components
  96. // Value can be either global schema component or a list of such components
  97. private TreeMap<String, Object> mGlobalComponentIndex = null;
  98. private ComponentListener mComponentListener = null;
  99. private RequestProcessor.Task mIndexGenerationTask;
  100. private boolean mSupportIndex = false; // indicates if the schema model support the index
  101. private final Object lock = new Object();
  102. public GlobalComponentsIndexSupport(SchemaModelImpl model) {
  103. mSModel = model;
  104. }
  105. public <T extends NamedReferenceable> T findByNameAndType(String localName, Class<T> type) {
  106. synchronized(lock) {
  107. checkGlobalComponentIndexRequired();
  108. //
  109. boolean indexNotAccessible =
  110. !mSupportIndex ||
  111. mGlobalComponentIndex == null ||
  112. !mIndexedTypes.contains(type) ||
  113. mSModel.isIntransaction();
  114. //
  115. // The index is not used if the schema model is in transaction
  116. // because the index can be not synchronized if something is changed
  117. // inside of the transaction. The index can be rebuilt after
  118. // transaction commited.
  119. //
  120. if (!indexNotAccessible) {
  121. T result = null;
  122. Object cached = mGlobalComponentIndex.get(localName);
  123. if (cached != null) {
  124. if (type.isInstance(cached)) {
  125. result = type.cast(cached);
  126. } else if (cached instanceof List) {
  127. // #207608 - may be a single element, whose type is different than searched for.
  128. List compList = List.class.cast(cached);
  129. for (Object sComp : compList) {
  130. if (type.isInstance(sComp)) {
  131. result = type.cast(sComp);
  132. }
  133. }
  134. }
  135. }
  136. //
  137. return result;
  138. }
  139. }
  140. //
  141. // If it didn't managed to use the index then go ordinary way
  142. SchemaImpl schema = mSModel.getSchema();
  143. if (schema == null) {
  144. return null;
  145. }
  146. return new FindGlobalReferenceVisitor<T>().find(type, localName, schema);
  147. }
  148. /**
  149. * Calculates if the index required and set up or remove all infrastructure.
  150. * It has to be called in synchronized context.
  151. */
  152. private void checkGlobalComponentIndexRequired() {
  153. //
  154. SchemaImpl schema = mSModel.getSchema();
  155. if (schema == null) {
  156. return;
  157. }
  158. //
  159. boolean indexAllowed = true;
  160. if (mTestSupport != null) {
  161. indexAllowed = mTestSupport.isIndexAllowed();
  162. }
  163. //
  164. int childrenCount = schema.getChildrenCount();
  165. //
  166. boolean indexCreateRequired =
  167. childrenCount > GLOBAL_COMPONENT_INDEX_CREATE_THRESHOLD;
  168. if (indexCreateRequired && !mSupportIndex && indexAllowed) {
  169. //
  170. if (mTestSupport != null) {
  171. mTestSupport.log("Switch ON components' index for Schema model: " +
  172. mSModel.toString()); // NOI18N
  173. }
  174. //
  175. if (mComponentListener == null) {
  176. mComponentListener = new ComponentListener() {
  177. public void valueChanged(ComponentEvent evt) {
  178. // Ignore this event
  179. }
  180. public void childrenAdded(ComponentEvent evt) {
  181. if (evt.getSource() == mSModel.getSchema()) {
  182. initiateIndexRebuld();
  183. }
  184. }
  185. public void childrenDeleted(ComponentEvent evt) {
  186. if (evt.getSource() == mSModel.getSchema()) {
  187. initiateIndexRebuld();
  188. }
  189. }
  190. };
  191. mSModel.addComponentListener(mComponentListener);
  192. }
  193. //
  194. if (mGlobalComponentIndex == null && mIndexGenerationTask == null) {
  195. //
  196. if (mTestSupport != null) {
  197. mTestSupport.log("initiate new index building for Schema model: " +
  198. mSModel.toString()); // NOI18N
  199. }
  200. //
  201. buildIndex(0);
  202. }
  203. mSupportIndex = true;
  204. //
  205. return;
  206. }
  207. //
  208. boolean indexRemoveRequired =
  209. childrenCount < GLOBAL_COMPONENT_INDEX_REMOVE_THRESHOLD;
  210. if ((!indexAllowed || indexRemoveRequired) && mSupportIndex) {
  211. //
  212. if (mTestSupport != null) {
  213. mTestSupport.log("Switch OFF components' index for Schema model: " +
  214. mSModel.toString()); // NOI18N
  215. }
  216. //
  217. mGlobalComponentIndex = null;
  218. if (mIndexGenerationTask != null) {
  219. mIndexGenerationTask.cancel();
  220. mIndexGenerationTask = null;
  221. }
  222. //
  223. if (mComponentListener != null) {
  224. mSModel.removeComponentListener(mComponentListener);
  225. mComponentListener = null;
  226. }
  227. //
  228. mSupportIndex = false;
  229. }
  230. }
  231. private void initiateIndexRebuld() {
  232. synchronized(lock) {
  233. if (mTestSupport != null) {
  234. mTestSupport.log("initiate index rebuilding for Schema model: " +
  235. mSModel.toString()); // NOI18N
  236. }
  237. //
  238. mGlobalComponentIndex = null; // The old index is absolete
  239. if (mIndexGenerationTask != null) {
  240. mIndexGenerationTask.cancel();
  241. }
  242. //
  243. // A delay is necessary because multiple modification events can come after
  244. // a transactin is commited. The delay helps avoid multiple index's
  245. // rebuilding per single transaction.
  246. buildIndex(INDEX_RECALCULATION_DELAY);
  247. }
  248. }
  249. /**
  250. * Initiates building index in a separate thread
  251. * It has to be executed in synchronized context.
  252. * @param delay
  253. */
  254. private void buildIndex(int delay) {
  255. mIndexGenerationTask = mIndexRecalculationRP.post(
  256. this, delay, Thread.NORM_PRIORITY);
  257. }
  258. /**
  259. * This method is executed by RequestProcessor.
  260. * The only instance of Runnable is enough because the process is stateless.
  261. */
  262. public void run() {
  263. TreeMap<String, Object> newIndex = buildGlobalComponentIndex();
  264. if (!Thread.interrupted()) {
  265. synchronized(lock) {
  266. mGlobalComponentIndex = newIndex;
  267. mIndexGenerationTask = null;
  268. }
  269. }
  270. }
  271. private TreeMap<String, Object> buildGlobalComponentIndex() {
  272. if (Thread.interrupted()) {
  273. return null;
  274. }
  275. //
  276. long before = 0;
  277. if (mTestSupport != null) {
  278. before = System.nanoTime();
  279. mTestSupport.log("buildComponentIndex STARTED for Schema model: " +
  280. mSModel.toString()); // NOI18N
  281. }
  282. //
  283. TreeMap<String, Object> resultIndex = new TreeMap<String, Object>();
  284. //
  285. Schema schema = mSModel.getSchema();
  286. if (schema == null) {
  287. return null;
  288. }
  289. List<SchemaComponent> globalSCompList = schema.getChildren();
  290. //
  291. for (SchemaComponent globalSComp : globalSCompList) {
  292. //
  293. if (Thread.interrupted()) {
  294. return null;
  295. }
  296. //
  297. Class<? extends SchemaComponent> componentType = globalSComp.getComponentType();
  298. if (mIndexedTypes.contains(componentType)) {
  299. assert globalSComp instanceof Named;
  300. String name = Named.class.cast(globalSComp).getName();
  301. if (name == null || name.length() == 0) {
  302. // Skip components without a name attribute or
  303. // with empty attributes' value.
  304. continue;
  305. }
  306. //
  307. Object value = resultIndex.get(name);
  308. if (value == null) {
  309. resultIndex.put(name, globalSComp);
  310. continue;
  311. }
  312. //
  313. if (value instanceof List) {
  314. List valuesList = List.class.cast(value);
  315. valuesList.add(globalSComp);
  316. } else {
  317. List valuesList = new ArrayList();
  318. valuesList.add(value);
  319. valuesList.add(globalSComp);
  320. resultIndex.put(name, valuesList);
  321. }
  322. }
  323. }
  324. //
  325. if (mTestSupport != null) {
  326. long after = System.nanoTime();
  327. float delay = (after - before) / 1000000F;
  328. mTestSupport.log("buildComponentIndex FINISHED for Schema model: " +
  329. mSModel.toString()); // NOI18N
  330. mTestSupport.log("Index contains " + resultIndex.size() + " items. " +
  331. "Building has taken " +
  332. new DecimalFormat("#0.00#").format(delay) + " ms"); // NOI18N
  333. }
  334. //
  335. return resultIndex;
  336. }
  337. // -------------------------------------------------------------------------
  338. // JUnit Test Support
  339. private JUnitTestSupport mTestSupport;
  340. public JUnitTestSupport getJUnitTestSupport() {
  341. if (mTestSupport == null) {
  342. mTestSupport = new JUnitTestSupport(this);
  343. }
  344. return mTestSupport;
  345. }
  346. public static class JUnitTestSupport {
  347. private GlobalComponentsIndexSupport mIndexSupport;
  348. private List<String> mMsgLog;
  349. private boolean mIndexAllowed = true;
  350. public JUnitTestSupport(GlobalComponentsIndexSupport indexSupport) {
  351. mIndexSupport = indexSupport;
  352. mMsgLog = new ArrayList<String>();
  353. }
  354. public void log(String msg) {
  355. mMsgLog.add(msg);
  356. }
  357. public String printLog() {
  358. List<String> logCopy = new ArrayList<String>(mMsgLog);
  359. StringBuilder sb = new StringBuilder();
  360. String newLine = System.getProperty("line.separator");
  361. for (String msg : logCopy) {
  362. sb.append(msg).append(newLine);
  363. }
  364. return sb.toString();
  365. }
  366. public int getIndexSize() {
  367. synchronized (mIndexSupport.lock) {
  368. Map index = mIndexSupport.mGlobalComponentIndex;
  369. if (index != null) {
  370. return index.size();
  371. }
  372. }
  373. return 0;
  374. }
  375. public boolean indexContains(String compName) {
  376. synchronized (mIndexSupport.lock) {
  377. Map index = mIndexSupport.mGlobalComponentIndex;
  378. if (index != null) {
  379. return index.containsKey(compName);
  380. }
  381. }
  382. return false;
  383. }
  384. /**
  385. * @return current index using status.
  386. */
  387. public boolean isSupportIndex() {
  388. synchronized(mIndexSupport.lock) {
  389. mIndexSupport.checkGlobalComponentIndexRequired();
  390. return mIndexSupport.mSupportIndex;
  391. }
  392. }
  393. public void setIndexAllowed(boolean status) {
  394. mIndexAllowed = status;
  395. }
  396. public boolean isIndexAllowed() {
  397. return mIndexAllowed;
  398. }
  399. }
  400. }