1 11 package org.eclipse.jdt.internal.ui.text.java; 12 13 import java.io.IOException ; 14 import java.io.StringReader ; 15 import java.io.StringWriter ; 16 import java.util.ArrayList ; 17 import java.util.Collections ; 18 import java.util.HashMap ; 19 import java.util.HashSet ; 20 import java.util.Iterator ; 21 import java.util.LinkedHashMap ; 22 import java.util.LinkedHashSet ; 23 import java.util.List ; 24 import java.util.Map ; 25 import java.util.Set ; 26 import java.util.Map.Entry; 27 28 import javax.xml.parsers.DocumentBuilder ; 29 import javax.xml.parsers.DocumentBuilderFactory ; 30 import javax.xml.parsers.ParserConfigurationException ; 31 import javax.xml.transform.OutputKeys ; 32 import javax.xml.transform.Transformer ; 33 import javax.xml.transform.TransformerException ; 34 import javax.xml.transform.TransformerFactory ; 35 import javax.xml.transform.dom.DOMSource ; 36 import javax.xml.transform.stream.StreamResult ; 37 38 import org.eclipse.core.runtime.Assert; 39 import org.eclipse.core.runtime.CoreException; 40 import org.eclipse.core.runtime.IProgressMonitor; 41 import org.eclipse.core.runtime.IStatus; 42 import org.eclipse.core.runtime.NullProgressMonitor; 43 import org.eclipse.core.runtime.Preferences; 44 45 46 import org.eclipse.jdt.core.Flags; 47 import org.eclipse.jdt.core.IType; 48 import org.eclipse.jdt.core.ITypeHierarchy; 49 import org.eclipse.jdt.core.JavaModelException; 50 51 import org.eclipse.jdt.internal.ui.JavaPlugin; 52 import org.eclipse.jdt.internal.ui.JavaUIException; 53 import org.eclipse.jdt.internal.ui.JavaUIStatus; 54 55 import org.w3c.dom.Document ; 56 import org.w3c.dom.Element ; 57 import org.w3c.dom.Node ; 58 import org.w3c.dom.NodeList ; 59 import org.xml.sax.InputSource ; 60 import org.xml.sax.SAXException ; 61 62 67 public final class ContentAssistHistory { 68 73 private static final class ReaderWriter { 74 75 private static final String NODE_ROOT= "history"; private static final String NODE_LHS= "lhs"; private static final String NODE_RHS= "rhs"; private static final String ATTRIBUTE_NAME= "name"; private static final String ATTRIBUTE_MAX_LHS= "maxLHS"; private static final String ATTRIBUTE_MAX_RHS= "maxRHS"; 82 public void store(ContentAssistHistory history, StreamResult result) throws CoreException { 83 try { 84 DocumentBuilderFactory factory= DocumentBuilderFactory.newInstance(); 85 DocumentBuilder builder= factory.newDocumentBuilder(); 86 Document document= builder.newDocument(); 87 88 Element rootElement = document.createElement(NODE_ROOT); 89 rootElement.setAttribute(ATTRIBUTE_MAX_LHS, Integer.toString(history.fMaxLHS)); 90 rootElement.setAttribute(ATTRIBUTE_MAX_RHS, Integer.toString(history.fMaxRHS)); 91 document.appendChild(rootElement); 92 93 for (Iterator leftHandSides= history.fLHSCache.keySet().iterator(); leftHandSides.hasNext();) { 94 String lhs= (String ) leftHandSides.next(); 95 Element lhsElement= document.createElement(NODE_LHS); 96 lhsElement.setAttribute(ATTRIBUTE_NAME, lhs); 97 rootElement.appendChild(lhsElement); 98 99 Set rightHandSides= (Set ) history.fLHSCache.get(lhs); 100 for (Iterator rhsIterator= rightHandSides.iterator(); rhsIterator.hasNext();) { 101 String rhs= (String ) rhsIterator.next(); 102 Element rhsElement= document.createElement(NODE_RHS); 103 rhsElement.setAttribute(ATTRIBUTE_NAME, rhs); 104 lhsElement.appendChild(rhsElement); 105 } 106 } 107 108 Transformer transformer=TransformerFactory.newInstance().newTransformer(); 109 transformer.setOutputProperty(OutputKeys.METHOD, "xml"); transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); transformer.setOutputProperty(OutputKeys.INDENT, "no"); DOMSource source = new DOMSource (document); 113 114 transformer.transform(source, result); 115 } catch (TransformerException e) { 116 throw createException(e, JavaTextMessages.ContentAssistHistory_serialize_error); 117 } catch (ParserConfigurationException e) { 118 throw createException(e, JavaTextMessages.ContentAssistHistory_serialize_error); 119 } 120 } 121 122 public ContentAssistHistory load(InputSource source) throws CoreException { 123 Element root; 124 try { 125 DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); 126 root = parser.parse(source).getDocumentElement(); 127 } catch (SAXException e) { 128 throw createException(e, JavaTextMessages.ContentAssistHistory_deserialize_error); 129 } catch (ParserConfigurationException e) { 130 throw createException(e, JavaTextMessages.ContentAssistHistory_deserialize_error); 131 } catch (IOException e) { 132 throw createException(e, JavaTextMessages.ContentAssistHistory_deserialize_error); 133 } 134 135 if (root == null || !root.getNodeName().equalsIgnoreCase(NODE_ROOT)) 136 return null; 137 138 int maxLHS= parseNaturalInt(root.getAttribute(ATTRIBUTE_MAX_LHS), DEFAULT_TRACKED_LHS); 139 int maxRHS= parseNaturalInt(root.getAttribute(ATTRIBUTE_MAX_RHS), DEFAULT_TRACKED_RHS); 140 141 ContentAssistHistory history= new ContentAssistHistory(maxLHS, maxRHS); 142 143 NodeList list= root.getChildNodes(); 144 int length= list.getLength(); 145 for (int i= 0; i < length; ++i) { 146 Node lhsNode= list.item(i); 147 if (lhsNode.getNodeType() == Node.ELEMENT_NODE) { 148 Element lhsElement= (Element ) lhsNode; 149 if (lhsElement.getNodeName().equalsIgnoreCase(NODE_LHS)) { 150 String lhs= lhsElement.getAttribute(ATTRIBUTE_NAME); 151 if (lhs != null) { 152 Set cache= history.getCache(lhs); 153 NodeList children= lhsElement.getChildNodes(); 154 int nRHS= children.getLength(); 155 for (int j= 0; j < nRHS; j++) { 156 Node rhsNode= children.item(j); 157 if (rhsNode.getNodeType() == Node.ELEMENT_NODE) { 158 Element rhsElement= (Element ) rhsNode; 159 if (rhsElement.getNodeName().equalsIgnoreCase(NODE_RHS)) { 160 String rhs= rhsElement.getAttribute(ATTRIBUTE_NAME); 161 if (rhs != null) { 162 cache.add(rhs); 163 } 164 } 165 } 166 } 167 } 168 } 169 } 170 } 171 172 return history; 173 } 174 175 private int parseNaturalInt(String attribute, int defaultValue) { 176 try { 177 int integer= Integer.parseInt(attribute); 178 if (integer > 0) 179 return integer; 180 return defaultValue; 181 } catch (NumberFormatException e) { 182 return defaultValue; 183 } 184 } 185 186 private JavaUIException createException(Exception e, String message) { 187 return new JavaUIException(JavaUIStatus.createError(IStatus.ERROR, message, e)); 188 } 189 } 190 191 198 private static final class MRUMap extends LinkedHashMap { 199 private static final long serialVersionUID= 1L; 200 private final int fMaxSize; 201 202 207 public MRUMap(int maxSize) { 208 Assert.isLegal(maxSize > 0); 209 fMaxSize= maxSize; 210 } 211 212 215 public Object put(Object key, Object value) { 216 Object object= remove(key); 217 super.put(key, value); 218 return object; 219 } 220 221 224 protected boolean removeEldestEntry(Entry eldest) { 225 return size() > fMaxSize; 226 } 227 } 228 229 235 private static final class MRUSet extends LinkedHashSet { 236 private static final long serialVersionUID= 1L; 237 private final int fMaxSize; 238 239 244 public MRUSet(int maxSize) { 245 Assert.isLegal(maxSize > 0); 246 fMaxSize= maxSize; 247 } 248 249 252 public boolean add(Object o) { 253 if (remove(o)) { 254 super.add(o); 255 return false; 256 } 257 258 if (size() >= fMaxSize) 259 remove(this.iterator().next()); 260 261 super.add(o); 262 return true; 263 } 264 } 265 266 271 public static final class RHSHistory { 272 private final LinkedHashMap fHistory; 273 private List fList; 274 275 RHSHistory(LinkedHashMap history) { 276 fHistory= history; 277 } 278 279 286 public float getRank(String type) { 287 if (fHistory == null) 288 return 0.0F; 289 Integer integer= (Integer ) fHistory.get(type); 290 return integer == null ? 0.0F : integer.floatValue() / fHistory.size(); 291 } 292 293 298 public int size() { 299 return fHistory == null ? 0 : fHistory.size(); 300 } 301 302 309 public List getTypes() { 310 if (fHistory == null) 311 return Collections.EMPTY_LIST; 312 if (fList == null) { 313 fList= Collections.unmodifiableList(new ArrayList (fHistory.keySet())); 314 } 315 return fList; 316 } 317 } 318 319 private static final RHSHistory EMPTY_HISTORY= new RHSHistory(null); 320 private static final int DEFAULT_TRACKED_LHS= 100; 321 private static final int DEFAULT_TRACKED_RHS= 10; 322 323 private static final Set UNCACHEABLE; 324 static { 325 Set uncacheable= new HashSet (); 326 uncacheable.add("java.lang.Object"); uncacheable.add("java.lang.Comparable"); uncacheable.add("java.io.Serializable"); uncacheable.add("java.io.Externalizable"); UNCACHEABLE= Collections.unmodifiableSet(uncacheable); 331 } 332 333 private final LinkedHashMap fLHSCache; 334 private final int fMaxLHS; 335 private final int fMaxRHS; 336 337 343 public ContentAssistHistory(int maxLHS, int maxRHS) { 344 Assert.isLegal(maxLHS > 0); 345 Assert.isLegal(maxRHS > 0); 346 fMaxLHS= maxLHS; 347 fMaxRHS= maxRHS; 348 fLHSCache= new MRUMap(fMaxLHS); 349 } 350 351 355 public ContentAssistHistory() { 356 this(DEFAULT_TRACKED_LHS, DEFAULT_TRACKED_RHS); 357 } 358 359 366 public void remember(IType lhs, IType rhs) { 367 Assert.isLegal(lhs != null); 368 Assert.isLegal(rhs != null); 369 370 try { 371 if (!isCacheableRHS(rhs)) 372 return; 373 ITypeHierarchy hierarchy= rhs.newSupertypeHierarchy(getProgressMonitor()); 374 if (hierarchy.contains(lhs)) { 375 IType[] allLHSides= hierarchy.getAllSupertypes(lhs); 377 for (int i= 0; i < allLHSides.length; i++) 378 rememberInternal(allLHSides[i], rhs); 379 rememberInternal(lhs, rhs); 380 } 381 } catch (JavaModelException x) { 382 JavaPlugin.log(x); 383 } 384 } 385 386 394 public RHSHistory getHistory(String lhs) { 395 MRUSet rhsCache= (MRUSet) fLHSCache.get(lhs); 396 if (rhsCache != null) { 397 int count= rhsCache.size(); 398 LinkedHashMap history= new LinkedHashMap ((int) (count / 0.75)); 399 int rank= 1; 400 for (Iterator it= rhsCache.iterator(); it.hasNext(); rank++) { 401 String type= (String ) it.next(); 402 history.put(type, new Integer (rank)); 403 } 404 return new RHSHistory(history); 405 } 406 return EMPTY_HISTORY; 407 } 408 409 415 public Map getEntireHistory() { 416 HashMap map= new HashMap ((int) (fLHSCache.size() / 0.75)); 417 for (Iterator it= fLHSCache.entrySet().iterator(); it.hasNext();) { 418 Entry entry= (Entry) it.next(); 419 String lhs= (String ) entry.getKey(); 420 map.put(lhs, getHistory(lhs)); 421 } 422 return Collections.unmodifiableMap(map); 423 } 424 425 private void rememberInternal(IType lhs, IType rhs) throws JavaModelException { 426 if (isCacheableLHS(lhs)) 427 getCache(lhs.getFullyQualifiedName()).add(rhs.getFullyQualifiedName()); 428 } 429 430 private boolean isCacheableLHS(IType type) throws JavaModelException { 431 return !Flags.isFinal(type.getFlags()) && !UNCACHEABLE.contains(type.getFullyQualifiedName()); 432 } 433 434 private boolean isCacheableRHS(IType type) throws JavaModelException { 435 return !type.isInterface() && !Flags.isAbstract(type.getFlags()); 436 } 437 438 private Set getCache(String lhs) { 439 MRUSet rhsCache= (MRUSet) fLHSCache.get(lhs); 440 if (rhsCache == null) { 441 rhsCache= new MRUSet(fMaxRHS); 442 fLHSCache.put(lhs, rhsCache); 443 } 444 445 return rhsCache; 446 } 447 448 private IProgressMonitor getProgressMonitor() { 449 return new NullProgressMonitor(); 450 } 451 452 461 public static void store(ContentAssistHistory history, Preferences preferences, String key) throws CoreException { 462 StringWriter writer= new StringWriter (); 463 new ReaderWriter().store(history, new StreamResult (writer)); 464 preferences.setValue(key, writer.toString()); 465 } 466 467 478 public static ContentAssistHistory load(Preferences preferences, String key) throws CoreException { 479 String value= preferences.getString(key); 480 if (value != null && value.length() > 0) { 481 return new ReaderWriter().load(new InputSource (new StringReader (value))); 482 } 483 return null; 484 } 485 } 486 | Popular Tags |