PageRenderTime 48ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/plugins/org.chromium.debug.core/src/org/chromium/debug/core/ChromiumSourceDirector.java

http://chromedevtools.googlecode.com/
Java | 513 lines | 422 code | 61 blank | 30 comment | 64 complexity | e9a78985097ca96c851fcc72618a6b23 MD5 | raw file
Possible License(s): BSD-3-Clause, Apache-2.0
  1. // Copyright (c) 2010 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. package org.chromium.debug.core;
  5. import java.util.ArrayList;
  6. import java.util.Collections;
  7. import java.util.Comparator;
  8. import java.util.Iterator;
  9. import java.util.List;
  10. import org.chromium.debug.core.ScriptNameManipulator.ScriptNamePattern;
  11. import org.chromium.debug.core.model.JavascriptVmEmbedder;
  12. import org.chromium.debug.core.model.LaunchParams;
  13. import org.chromium.debug.core.model.LaunchParams.LookupMode;
  14. import org.chromium.debug.core.model.ResourceManager;
  15. import org.chromium.debug.core.model.StackFrame;
  16. import org.chromium.debug.core.model.VmResource;
  17. import org.chromium.debug.core.model.VmResourceId;
  18. import org.chromium.debug.core.model.VmResourceRef;
  19. import org.chromium.debug.core.util.AccuratenessProperty;
  20. import org.chromium.sdk.Breakpoint;
  21. import org.chromium.sdk.BreakpointTypeExtension;
  22. import org.chromium.sdk.Script;
  23. import org.eclipse.core.resources.IFile;
  24. import org.eclipse.core.resources.IProject;
  25. import org.eclipse.core.runtime.CoreException;
  26. import org.eclipse.core.runtime.IPath;
  27. import org.eclipse.debug.core.ILaunchConfiguration;
  28. import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupDirector;
  29. import org.eclipse.debug.core.sourcelookup.AbstractSourceLookupParticipant;
  30. import org.eclipse.debug.core.sourcelookup.ISourceContainer;
  31. import org.eclipse.debug.core.sourcelookup.ISourceLookupParticipant;
  32. import org.eclipse.osgi.util.NLS;
  33. import org.eclipse.swt.SWT;
  34. import org.eclipse.swt.widgets.Display;
  35. import org.eclipse.swt.widgets.MessageBox;
  36. /**
  37. * A source lookup director implementation that provides a simple participant and
  38. * accepts instance of virtual project once it is created.
  39. */
  40. public class ChromiumSourceDirector extends AbstractSourceLookupDirector {
  41. private volatile ResourceManager resourceManager = null;
  42. private volatile IProject project = null;
  43. private volatile ReverseSourceLookup reverseSourceLookup = null;
  44. private volatile JavascriptVmEmbedder javascriptVmEmbedder = null;
  45. /**
  46. * Contains 'true' if we have already shown the warning about unsupported look-up mode.
  47. * However this should be reset when user switches from one mode to another.
  48. */
  49. private volatile boolean lookupWarningShown = false;
  50. public void initializeParticipants() {
  51. ISourceLookupParticipant participant = new LookupParticipant(this);
  52. addParticipants(new ISourceLookupParticipant[] { participant } );
  53. // Check mode post factum.
  54. checkSupportedLookupMode();
  55. }
  56. public VmResourceRef findVmResourceRef(IFile file) throws CoreException {
  57. return getLookupModeHandler().findVmResourceRef(file);
  58. }
  59. public static LookupMode readLookupMode(ILaunchConfiguration launchConfiguration)
  60. throws CoreException {
  61. String lookupStringValue = launchConfiguration.getAttribute(
  62. LaunchParams.SOURCE_LOOKUP_MODE, (String) null);
  63. LookupMode value;
  64. if (lookupStringValue == null) {
  65. value = LookupMode.DEFAULT_VALUE;
  66. } else {
  67. value = LookupMode.STRING_CONVERTER.decode(lookupStringValue);
  68. }
  69. return value;
  70. }
  71. private LookupModeHandler getLookupModeHandler() {
  72. LookupMode mode;
  73. try {
  74. mode = readLookupMode(getLaunchConfiguration());
  75. } catch (CoreException e) {
  76. ChromiumDebugPlugin.log(e);
  77. mode = LookupMode.DEFAULT_VALUE;
  78. }
  79. return mode.accept(MODE_TO_HANDLER_VISITOR);
  80. }
  81. private final LookupMode.Visitor<LookupModeHandler> MODE_TO_HANDLER_VISITOR =
  82. new LookupMode.Visitor<LookupModeHandler>() {
  83. @Override
  84. public LookupModeHandler visitExactMatch() {
  85. return exactMatchLookupMode;
  86. }
  87. @Override
  88. public LookupModeHandler visitAutoDetect() {
  89. return autoDetectLookupMode;
  90. }
  91. };
  92. @Override
  93. public boolean isFindDuplicates() {
  94. return getLookupModeHandler().forceFindDuplicates() || super.isFindDuplicates();
  95. }
  96. /**
  97. * A single implementation of look participant. This way the participant may decide to become
  98. * exact match/auto-detect after it is created, because javascriptVm instances comes too late
  99. * after everything is created.
  100. */
  101. private static class LookupParticipant extends AbstractSourceLookupParticipant {
  102. private final SuperClassAccess superClassAccess = new SuperClassAccess();
  103. private final ChromiumSourceDirector chromiumSourceDirector;
  104. LookupParticipant(ChromiumSourceDirector chromiumSourceDirector) {
  105. this.chromiumSourceDirector = chromiumSourceDirector;
  106. }
  107. public String getSourceName(Object object) throws CoreException {
  108. return getSourceNameImpl(object);
  109. }
  110. @Override
  111. public Object[] findSourceElements(Object object) throws CoreException {
  112. Delegate delegate = chromiumSourceDirector.getLookupModeHandler().getDelegate();
  113. return delegate.findSourceElements(object, superClassAccess);
  114. }
  115. private Object[] findSourceElementsSuper(Object object) throws CoreException {
  116. return super.findSourceElements(object);
  117. }
  118. static abstract class Delegate {
  119. abstract Object[] findSourceElements(Object object, SuperClassAccess superClass)
  120. throws CoreException;
  121. }
  122. class SuperClassAccess {
  123. Object[] findSourceElements(Object object) throws CoreException {
  124. return findSourceElementsSuper(object);
  125. }
  126. ISourceContainer[] getSourceContainers() {
  127. return LookupParticipant.this.getSourceContainers();
  128. }
  129. ChromiumSourceDirector getChromiumSourceDirector() {
  130. return chromiumSourceDirector;
  131. }
  132. }
  133. }
  134. private static final LookupParticipant.Delegate EXACT_MATCH_DELEGATE =
  135. new LookupParticipant.Delegate() {
  136. @Override
  137. Object[] findSourceElements(Object object, LookupParticipant.SuperClassAccess superClass)
  138. throws CoreException {
  139. Object[] result = superClass.findSourceElements(object);
  140. if (result.length > 0) {
  141. ArrayList<Object> filtered = new ArrayList<Object>(result.length);
  142. for (Object obj : result) {
  143. if (obj instanceof VProjectSourceContainer.LookupResult) {
  144. VProjectSourceContainer.LookupResult vprojectResult =
  145. (VProjectSourceContainer.LookupResult) obj;
  146. expandVProjectResult(vprojectResult, object, filtered);
  147. } else {
  148. filtered.add(obj);
  149. }
  150. }
  151. result = filtered.toArray();
  152. }
  153. return result;
  154. }
  155. };
  156. private static final LookupParticipant.Delegate AUTO_DETECT_DELEGATE =
  157. new LookupParticipant.Delegate() {
  158. @Override
  159. Object[] findSourceElements(Object object, LookupParticipant.SuperClassAccess superClass)
  160. throws CoreException {
  161. ArrayList<Object> result = new ArrayList<Object>();
  162. JavascriptVmEmbedder vmEmbedder =
  163. superClass.getChromiumSourceDirector().javascriptVmEmbedder;
  164. ScriptNameManipulator.FilePath scriptName =
  165. getParsedScriptFileName(object, vmEmbedder.getScriptNameManipulator());
  166. if (scriptName != null) {
  167. for (ISourceContainer container : superClass.getSourceContainers()) {
  168. try {
  169. findSourceElements(container, object, scriptName, result);
  170. } catch (CoreException e) {
  171. ChromiumDebugPlugin.log(e);
  172. continue;
  173. }
  174. // If one container returned one file -- that's a single uncompromised result.
  175. IFile oneFile = getSimpleResult(result);
  176. if (oneFile != null) {
  177. return new Object[] { oneFile };
  178. }
  179. }
  180. }
  181. return result.toArray();
  182. }
  183. private void findSourceElements(ISourceContainer container, Object object,
  184. ScriptNameManipulator.FilePath scriptName, ArrayList<Object> output)
  185. throws CoreException {
  186. Object[] objects = container.findSourceElements(scriptName.getLastComponent());
  187. if (objects.length == 0) {
  188. return;
  189. }
  190. int outputStartPos = output.size();
  191. for (Object obj : objects) {
  192. if (obj instanceof IFile) {
  193. IFile file = (IFile) obj;
  194. if (matchFileAccurateness(file, scriptName)) {
  195. output.add(obj);
  196. }
  197. } else if (obj instanceof VProjectSourceContainer.LookupResult) {
  198. VProjectSourceContainer.LookupResult vprojectResult =
  199. (VProjectSourceContainer.LookupResult) obj;
  200. expandVProjectResult(vprojectResult, object, output);
  201. } else {
  202. output.add(obj);
  203. }
  204. }
  205. int outputEndPos = output.size();
  206. if (outputEndPos - outputStartPos > 1) {
  207. // Put short name last. They cannot be filtered out by our rules, so they may
  208. // be parasite.
  209. Collections.sort(output.subList(outputStartPos, outputEndPos), SHORT_NAME_LAST);
  210. }
  211. }
  212. private IFile getSimpleResult(List<Object> objects) {
  213. if (objects.size() != 1) {
  214. return null;
  215. }
  216. Object oneObject = objects.get(0);
  217. if (oneObject instanceof IFile == false) {
  218. return null;
  219. }
  220. IFile file = (IFile) oneObject;
  221. return file;
  222. }
  223. private boolean matchFileAccurateness(IFile file,
  224. ScriptNameManipulator.FilePath scriptName) throws CoreException {
  225. int accurateness = AccuratenessProperty.read(file);
  226. if (accurateness > AccuratenessProperty.BASE_VALUE) {
  227. IPath path = file.getFullPath();
  228. int pathPos = path.segmentCount() - AccuratenessProperty.BASE_VALUE -1;
  229. Iterator<String> scriptIterator = scriptName.iterator();
  230. while (accurateness > AccuratenessProperty.BASE_VALUE) {
  231. if (pathPos < 0 || !scriptIterator.hasNext()) {
  232. return false;
  233. }
  234. String scriptComponent = scriptIterator.next();
  235. String pathComponent = path.segment(pathPos--);
  236. if (!scriptComponent.equals(pathComponent)) {
  237. return false;
  238. }
  239. accurateness--;
  240. }
  241. }
  242. return true;
  243. }
  244. private ScriptNameManipulator.FilePath getParsedScriptFileName(Object object,
  245. ScriptNameManipulator nameManipulator) throws CoreException {
  246. VmResourceId vmResourceId = getVmResourceId(object);
  247. if (vmResourceId == null) {
  248. return null;
  249. }
  250. final String scriptName = vmResourceId.getName();
  251. if (scriptName == null) {
  252. return UNKNOWN_NAME;
  253. }
  254. return nameManipulator.getFileName(scriptName);
  255. }
  256. };
  257. private static String getSourceNameImpl(Object object) throws CoreException {
  258. VmResourceId vmResourceId = getVmResourceId(object);
  259. if (vmResourceId == null) {
  260. return null;
  261. }
  262. String name = vmResourceId.getName();
  263. if (name == null) {
  264. // Do not return null, this will cancel look-up.
  265. // Return empty string. Virtual project container will pass us some data.
  266. name = ""; //$NON-NLS-1$
  267. }
  268. return name;
  269. }
  270. private static final ScriptNameManipulator.FilePath UNKNOWN_NAME =
  271. new ScriptNameManipulator.FilePath() {
  272. @Override
  273. public String getLastComponent() {
  274. return "<unknonwn source>"; //$NON-NLS-1$
  275. }
  276. @Override
  277. public Iterator<String> iterator() {
  278. return Collections.<String>emptyList().iterator();
  279. }
  280. };
  281. private static final Comparator<Object> SHORT_NAME_LAST = new Comparator<Object>() {
  282. @Override
  283. public int compare(Object o1, Object o2) {
  284. int len1 = getPathLength(o1);
  285. int len2 = getPathLength(o2);
  286. return len2 - len1;
  287. }
  288. private int getPathLength(Object obj) {
  289. if (obj instanceof IFile == false) {
  290. return Integer.MIN_VALUE;
  291. }
  292. IFile file = (IFile) obj;
  293. return file.getFullPath().segmentCount();
  294. }
  295. };
  296. private static VmResourceId getVmResourceId(Object object) throws CoreException {
  297. if (object instanceof Script) {
  298. Script script = (Script) object;
  299. return VmResourceId.forScript(script);
  300. } else if (object instanceof StackFrame) {
  301. StackFrame jsStackFrame = (StackFrame) object;
  302. return jsStackFrame.getVmResourceId();
  303. } else if (object instanceof Breakpoint) {
  304. Breakpoint breakpoint = (Breakpoint) object;
  305. return breakpoint.getTarget().accept(BREAKPOINT_RESOURCE_VISITOR);
  306. } else if (object instanceof VmResourceId) {
  307. VmResourceId resourceId = (VmResourceId) object;
  308. return resourceId;
  309. } else {
  310. return null;
  311. }
  312. }
  313. /**
  314. * Virtual project container cannot properly resolve from a sting name. Instead it returns
  315. * {@link ResourceManager} object that can be processed here, where we have full
  316. * {@link VmResourceId}.
  317. */
  318. private static void expandVProjectResult(VProjectSourceContainer.LookupResult lookupResult,
  319. Object object, ArrayList<Object> output) throws CoreException {
  320. VmResourceId resourceId = getVmResourceId(object);
  321. if (resourceId.getId() != null) {
  322. VmResource vmResource = lookupResult.getVmResource(resourceId);
  323. if (vmResource != null) {
  324. output.add(vmResource.getVProjectFile());
  325. }
  326. }
  327. }
  328. private static final Breakpoint.Target.Visitor<VmResourceId> BREAKPOINT_RESOURCE_VISITOR =
  329. new BreakpointTypeExtension.ScriptRegExpSupport.Visitor<VmResourceId>() {
  330. @Override public VmResourceId visitScriptName(String scriptName) {
  331. return new VmResourceId(scriptName, null);
  332. }
  333. @Override public VmResourceId visitScriptId(Object scriptId) {
  334. return new VmResourceId(null, scriptId);
  335. }
  336. @Override public VmResourceId visitRegExp(String regExp) {
  337. // RegExp cannot be converted into VmResourceId without additional context.
  338. return null;
  339. }
  340. @Override public VmResourceId visitUnknown(Breakpoint.Target target) {
  341. return null;
  342. }
  343. };
  344. public void initializeVProjectContainers(IProject project, ResourceManager resourceManager,
  345. JavascriptVmEmbedder javascriptVmEmbedder) {
  346. this.resourceManager = resourceManager;
  347. this.project = project;
  348. this.javascriptVmEmbedder = javascriptVmEmbedder;
  349. this.reverseSourceLookup = new ReverseSourceLookup(this);
  350. checkSupportedLookupMode();
  351. }
  352. public ReverseSourceLookup getReverseSourceLookup() {
  353. return reverseSourceLookup;
  354. }
  355. public ResourceManager getResourceManager() {
  356. return resourceManager;
  357. }
  358. IProject getProject() {
  359. return project;
  360. }
  361. private void checkSupportedLookupMode() {
  362. LookupModeHandler lookupMode = getLookupModeHandler();
  363. if (javascriptVmEmbedder != null) {
  364. lookupMode.showUnsupportedWarning(javascriptVmEmbedder);
  365. }
  366. }
  367. private static abstract class LookupModeHandler {
  368. abstract LookupParticipant.Delegate getDelegate();
  369. abstract void showUnsupportedWarning(JavascriptVmEmbedder javascriptVmEmbedder);
  370. abstract boolean forceFindDuplicates();
  371. abstract VmResourceRef findVmResourceRef(IFile file) throws CoreException;
  372. }
  373. private final LookupModeHandler exactMatchLookupMode = new LookupModeHandler() {
  374. @Override LookupParticipant.Delegate getDelegate() {
  375. return EXACT_MATCH_DELEGATE;
  376. }
  377. @Override void showUnsupportedWarning(JavascriptVmEmbedder javascriptVmEmbedder) {
  378. // 'Exact match' is chosen. Enable warning again.
  379. lookupWarningShown = false;
  380. }
  381. @Override boolean forceFindDuplicates() {
  382. return false;
  383. }
  384. @Override
  385. VmResourceRef findVmResourceRef(IFile file) throws CoreException {
  386. VmResourceId vmResourceId = reverseSourceLookup.findVmResource(file);
  387. if (vmResourceId == null) {
  388. return null;
  389. }
  390. return VmResourceRef.forVmResourceId(vmResourceId);
  391. }
  392. };
  393. private final LookupModeHandler autoDetectLookupMode = new LookupModeHandler() {
  394. @Override LookupParticipant.Delegate getDelegate() {
  395. return AUTO_DETECT_DELEGATE;
  396. }
  397. @Override
  398. void showUnsupportedWarning(final JavascriptVmEmbedder javascriptVmEmbedder) {
  399. if (lookupWarningShown) {
  400. return;
  401. }
  402. BreakpointTypeExtension breakpointTypeExtension =
  403. javascriptVmEmbedder.getJavascriptVm().getBreakpointTypeExtension();
  404. BreakpointTypeExtension.ScriptRegExpSupport scriptRegExpSupport =
  405. breakpointTypeExtension.getScriptRegExpSupport();
  406. if (scriptRegExpSupport != null) {
  407. return;
  408. }
  409. lookupWarningShown = true;
  410. Display display = Display.getDefault();
  411. display.asyncExec(new Runnable() {
  412. @Override
  413. public void run() {
  414. Display display = Display.getDefault();
  415. MessageBox messageBox = new MessageBox(display.getActiveShell(), SWT.ICON_WARNING);
  416. messageBox.setText(Messages.ChromiumSourceDirector_WARNING_TITLE);
  417. String messagePattern = Messages.ChromiumSourceDirector_WARNING_TEXT_PATTERN;
  418. String message = NLS.bind(messagePattern,
  419. javascriptVmEmbedder.getJavascriptVm().getVersion());
  420. messageBox.setMessage(message);
  421. messageBox.open();
  422. }
  423. });
  424. }
  425. @Override boolean forceFindDuplicates() {
  426. return true;
  427. }
  428. @Override
  429. VmResourceRef findVmResourceRef(IFile file) throws CoreException {
  430. {
  431. // Try inside virtual project.
  432. VmResourceId resourceId = resourceManager.getResourceId(file);
  433. if (resourceId != null) {
  434. return VmResourceRef.forVmResourceId(resourceId);
  435. }
  436. }
  437. IPath path = file.getFullPath();
  438. int accurateness = AccuratenessProperty.read(file);
  439. if (accurateness > path.segmentCount()) {
  440. accurateness = path.segmentCount();
  441. }
  442. int offset = path.segmentCount() - accurateness;
  443. List<String> components = new ArrayList<String>(accurateness);
  444. for (int i = 0; i < accurateness; i++) {
  445. components.add(path.segment(i + offset));
  446. }
  447. ScriptNameManipulator scriptNameManipulator = javascriptVmEmbedder.getScriptNameManipulator();
  448. ScriptNamePattern pattern = scriptNameManipulator.createPattern(components);
  449. return VmResourceRef.forRegExpBased(pattern);
  450. }
  451. };
  452. }