Eclipse 3.X的selection机制

1. 要想搞清楚Eclipse的selection机制,首先要对Eclipse的WorkBench和它的结构有一个清晰的认识。

下面是我画的一张图,原图在这里: http://www.eclipse.org/articles/Article-UI-
Workbench/workbench.html

一般来说WorkBench有一个WorkBenchWindow,一个WorkBenchWindow有一个WorkBenchPage,一个WorkBenchPage有一个

EditManager,ViewFactory和多个Perspective,ViewFactory是通过引用计数来管理ViewReference的,只有引用计数为0时,对应的View才会被dispose掉。

2. 什么是part

WorkBenchPage中的所有Editor和View是part. 见下图:

ViewReference和EditorReference都继承自WorkbenchPartReference,WorkbenchPartReference有对应的WorkbenchPart和PartPane;

因为Eclipse是lazy初始化的,所有有时WorkbenchPartReference中的WorkbenchPart是空;

PartPane是用来管理给part绘制界面组件的;

PartPane通过给control添加SWT.Activate事件来更新page的active part;

org.eclipse.ui.internal.PartPane的handleEvent方法:

public void handleEvent(Event event) {
    if (event.type == SWT.Activate) {
        if (inLayout) {
            requestActivation();
        }
    }
}

处理Activate事件时,导致setActivePart被调用,来更新activeProvider和它们的listener;

org.eclipse.ui.internal.AbstractSelectionService的setActivePart方法:

/**
 * Sets the current-active part (or null if none)
 * 
 * @since 3.1 
 *
 * @param newPart the new active part (or null if none)
 */
public void setActivePart(IWorkbenchPart newPart) {
    // Optimize.
    if (newPart == activePart) {
        return;
    }

    ISelectionProvider selectionProvider = null;

    if (newPart != null) {
        selectionProvider = newPart.getSite().getSelectionProvider();

        if (selectionProvider == null) {
            newPart = null;
        }
    }

    if (newPart == activePart) {
        return;
    }

    if (activePart != null) {
        if (activeProvider != null) { **//清除旧的SP中的listener**
            activeProvider.removeSelectionChangedListener(selListener);
            if (activeProvider instanceof IPostSelectionProvider) {
                ((IPostSelectionProvider) activeProvider)
                        .removePostSelectionChangedListener(postSelListener);
            } else {
                activeProvider
                        .removeSelectionChangedListener(postSelListener);
            }
            activeProvider = null;
        }
        activePart = null;
    }

    activePart = newPart;

    if (newPart != null) {
        activeProvider = selectionProvider;
        // Fire an event if there's an active provider
        activeProvider.addSelectionChangedListener(selListener); **//将listener加入新的SP**
        ISelection sel = activeProvider.getSelection();
        fireSelection(newPart, sel);
        if (activeProvider instanceof IPostSelectionProvider) {
            ((IPostSelectionProvider) activeProvider)
                    .addPostSelectionChangedListener(postSelListener);
        } else { **//这里的逻辑是不是有问题,如果对应的SP不是IPostSelectionProvider类型,将postSelListener加入SP** ?
            activeProvider.addSelectionChangedListener(postSelListener);
        }
        firePostSelection(newPart, sel);
    } else {
        fireSelection(null, null);
        firePostSelection(null, null);
    }
}

selListener和postSelListener的定义如下:

/**

  • The JFace selection listener to hook on the active part’s selection provider.
    */
    private ISelectionChangedListener selListener = new
    ISelectionChangedListener() {
    public void selectionChanged(SelectionChangedEvent event) {
    fireSelection(activePart, event.getSelection());
    }
    };

/**

  • The JFace post selection listener to hook on the active part’s selection provider.
    */
    private ISelectionChangedListener postSelListener = new
    ISelectionChangedListener() {
    public void selectionChanged(SelectionChangedEvent event) {
    firePostSelection(activePart, event.getSelection());
    }
    };

3. WorkBenchWindow和WorkBenchPage的关系,见下图:

上面已经说过,一个WorkBenchWindow一般有一个WorkBenchPage。

从上图可以看出:

WorkBenchWindow通过busyOpenPage来创建WorkBenchPage;

WorkBenchWindow和WorkBenchPage有自己的SelectionService,但是它们都是继承自org.eclipse.ui.internal.AbstractSelectionService的;

WorkBenchWindow的WWinPartService通过给WorkBenchPage的ParService添加或者删除WWinListener,来和响应Part相关的事件;

WorkBenchWindow的SelectionService叫做WindowSelectionService;

WorkBenchPage的SelectionService叫做PageSelectionService;

SlectionService有多应全局的ListenerList(listeners)和每个part的ListenerList(PagePartSelectionTracker)

4. selection是如何工作的,加下图:

简单的说,当你在且画Editor或者Viewer的时候,WorkbenchPage会通过setActivePart方法,将selListener和postSelListener从老的SP中移除;

然后加入到新的SP中去,然后当SP中有selection改变的时候,SP会通知所有的listener。

5. WorkbenchWindow和WorkbenchPage的SelectionService不一样,那么如何给它们追加listener呢?

getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(l);
给Window的SelectionService追加listener
getSite().getPage().addSelectionListener(l); 给Page的SelectionService追加listener

6. PropertyView是如何响应Selection改变的

org.eclipse.ui.views.properties.PropertySheet通过

public void init(IViewSite site) throws PartInitException {
       site.getPage().addPostSelectionListener(this);
       super.init(site);
}

将机制注册到Page的selection完成队列中,如果有selection改变完成的话,Page会通知PropertySheet来更新自己的。

Note:

1. 加下图,分别是Window和Page的SelectionService中listener个数,可以看到它们两个的个数分别是70和1,

Windows:

Page:

2. 每个Part都要对应的PartSite

3. 每个Part都有可能对应一个SelectionTracker

4. 在PartPane中来处理SWT.Activate事件,来更新Page中的SP

5. 有两个SelectionService,一个是Page的,一个是Window的

6. 不要混淆Page和Window的SelectionService

7. setSelectionProvider只能在 createPartControl()
被调用,之后的调用不会生效;因为没有时机给page去更新SP

8. 如果你的Part有不同的SP,你可能需要在自己写的SP中进行以下trick的处理,可以参见这里:

www.eclipse.org/articles/Article-
WorkbenchSelections/SelectionProviderIntermediate.java

参考:

http://www.eclipse.org/articles/Article-WorkbenchSelections/article.html
http://www.eclipse.org/articles/Article-UI-Workbench/workbench.html


http://wiki.eclipse.org/FAQ_Pages,_parts,_sites,_windows:_What_is_all_this_stuff%3F

Eclipse JDT的Index机制

1. Index是什么?

JDT的Index目的是为了快速的查找变量,方法,构造函数,引用等位置的机制。

如下图,当我们在JDT中使用我框起来的功能时,都是Index机制在为我们服务。

2. Index保存在哪里?

Index的保存路径一般在: .metadata/.plugins/org.eclipse.jdt.core

以下是我的机器上的输出:

/home/test/runtime-EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core
[test@ht191w org.eclipse.jdt.core]$ ls -alh
total 11M
drwxrwxr-x 2 test users 4.0K Nov 15 17:16 .
drwxrwxr-x 20 test users 4.0K Nov 15 12:48 ..
-rw-rw-r– 1 test users 169K Nov 15 17:16 1189544457.index
-rw-rw-r– 1 test users 270K Nov 15 17:16 1266648557.index
-rw-rw-r– 1 test users 9.4M Nov 15 17:16 1346760340.index
-rw-rw-r– 1 test users 91K Nov 15 17:16 1481681510.index
-rw-rw-r– 1 test users 25 Nov 15 17:01 1501317170.index
-rw-rw-r– 1 test users 174K Nov 15 17:16 1580850431.index
-rw-rw-r– 1 test users 387 Nov 15 17:16 2266944301.index
-rw-rw-r– 1 test users 38K Nov 15 17:16 2268464613.index
-rw-rw-r– 1 test users 90K Nov 15 17:16 3421611052.index
-rw-rw-r– 1 test users 53K Nov 15 17:16 4283481814.index
-rw-rw-r– 1 test users 4.2K Nov 15 17:16 680003802.index
-rw-rw-r– 1 test users 22K Nov 15 17:16 690271857.index
-rw-rw-r– 1 test users 870 Nov 15 18:19 externalLibsTimeStamps
-rw-rw-r– 1 test users 4 Nov 15 18:19 invalidArchivesCache
-rw-rw-r– 1 test users 4 Nov 15 10:36 javaLikeNames.txt
-rw-rw-r– 1 test users 782 Nov 15 18:19 nonChainingJarsCache
-rw-rw-r– 1 test users 304 Nov 15 17:16 savedIndexNames.txt
-rw-rw-r– 1 test users 21K Nov 15 18:19 variablesAndContainers.dat

3. Index机制的基本描述

3.1 Index机制的参与类

org.eclipse.jdt.internal.core.search.indexing.IndexManager
用来管理Index,创建,删除,重建,查找等操作

org.eclipse.jdt.internal.core.index.Index 用来操作Index,它包含了

org.eclipse.jdt.internal.core.index.MemoryIndex
和org.eclipse.jdt.internal.core.index.DiskIndex

org.eclipse.jdt.internal.core.search.indexing.IndexRequest
用来给IndexManager发送请求来建立Index

下面是它的子类:

org.eclipse.jdt.internal.core.search.processing.IJob是IndexManager处理请求的所有基类:

org.eclipse.jdt.internal.core.search.PatternSearchJob用来处理所有查找的对象,它的一个注意成员就是SearchPattern,以下是它们继承等级:

3.2 IndexManager的创建

当jdt.core plugins启动时,
org.eclipse.jdt.core.JavaCore将创建IndexManager类,来处理对Index的各种请求

如下图高亮的就是Java Indexing线程:

3.3 Index的建立和使用

通过org.eclipse.jdt.internal.core.search.indexing.IndexManager的

public synchronized IndexLocation computeIndexLocation(IPath containerPath) {
    IndexLocation indexLocation = (IndexLocation) this.indexLocations.get(containerPath);
    if (indexLocation == null) {
        String pathString = containerPath.toOSString();
        CRC32 checksumCalculator = new CRC32();
        checksumCalculator.update(pathString.getBytes());
        String fileName = Long.toString(checksumCalculator.getValue()) + ".index"; //$NON-NLS-1$
        if (VERBOSE)
            Util.verbose("-> index name for " + pathString + " is " + fileName); //$NON-NLS-1$ //$NON-NLS-2$
        // to share the indexLocation between the indexLocations and indexStates tables, get the key from the indexStates table
        indexLocation = (IndexLocation) getIndexStates().getKey(new FileIndexLocation(new File(getSavedIndexesDirectory(), fileName)));
        this.indexLocations.put(containerPath, indexLocation);
    }
    return indexLocation;
}

来计算index文件的名字
然后检查对应的index文件是否存在,如果存在,则直接使用,如果不存在的话,通过

private void rebuildIndex(IndexLocation indexLocation, IPath containerPath) {
    Object target = JavaModel.getTarget(containerPath, true);
    if (target == null) return;

    if (VERBOSE)
        Util.verbose("-> request to rebuild index: "+indexLocation+" path: "+containerPath); //$NON-NLS-1$ //$NON-NLS-2$

    updateIndexState(indexLocation, REBUILDING_STATE);
    IndexRequest request = null;
    if (target instanceof IProject) {
        IProject p = (IProject) target;
        if (JavaProject.hasJavaNature(p))
            request = new IndexAllProject(p, this);
    } else if (target instanceof IFolder) {
        request = new IndexBinaryFolder((IFolder) target, this);
    } else if (target instanceof IFile) {
        request = new AddJarFileToIndex((IFile) target, null, this);
    } else if (target instanceof File) {
        request = new AddJarFileToIndex(containerPath, null, this);
    }
    if (request != null)
        request(request);
}

发送IndexRequest来重建index。 不管是Java工程还是Jar文件,最终都分为两类,一类是source文件,一类是class文件,如下图:

IndexManager来处理收到的IndexRequest来生成Index。

比如下面的堆栈,是处理jar文件并生成Index的调用:

以下是其中一次调用所传递的参数:

_category [t, y, p, e, D, e, c, l]
key [a, c, c, e, s, s, i, b, i, l, i, t, y, /, c, o, m, ., s, u, n, ., a, c,
c, e, s, s, i, b, i, l, i, t, y, ., i, n, t, e, r, n, a, l, ., r, e, s, o, u,
r, c, e, s, /, /, 1,
documentName com/sun/accessibility/internal/resources/accessibility.class _

生成的Index最后会保存道磁盘上,便于以后使用,不需要再次创建,Index文件的header当前是INDEX VERSION 1.126。

以下是DiskIndex中重要的两个变量的Variable截图:

如果我们收到org.eclipse.jdt.core.search.SearchRequestor,我们只需要根据对应的catogory读取文件中对应的位置(根据categoryOffsets和categoryEnds),

然后就可以快速的查找到对应请求的关系,比如变量a的调用的地方,方法b的声明的地方,方法c的父类声明在哪里等。

下面是IndexManager对一个Java工程进行完Index后,所有的Index:

file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/690271857.index - >
Index for
/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/localedata.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/680003802.index ->
Index for /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/dnsns.jar
file:/home/test/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/3421611052.index ->
Index for
/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/sunpkcs11.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/1580850431.index ->
Index for /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/charsets.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/1346760340.index ->
Index for /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/rt.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/2268464613.index ->
Index for /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/jce.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/4283481814.index ->
Index for
/usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/sunjce_provider.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/1481681510.index ->
Index for /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/jsse.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/1266648557.index ->
Index for /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/rhino.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/1189544457.index ->
Index for /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/ext/gnome-
java-bridge.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/1501317170.index ->
Index for /usr/lib/jvm/java-1.6.0-openjdk-1.6.0.0.x86_64/jre/lib/resources.jar
file:/home/jialiang/runtime-
EclipseApplication/.metadata/.plugins/org.eclipse.jdt.core/2266944301.index ->
Index for /dd

Index的使用都是通过调用IndexManager的performConcurrentJob来完成的,以下是它的调用堆栈:

metasploit社区版的最新版本根本就用不了

1. 以下四个服务是metasploit安装完成后安装的服务,但是我在第一次安装完成后,根本就在浏览器中打不开,

只能手动重新启动以下服务,才能连上

C:/metasploit/postgresql/bin/pg_ctl.exe runservice -N “metasploitPostgreSQL”
-D “C:/metasploit/postgresql/data”

C:\metasploit\ruby\bin\ruby.exe -C “C:\metasploit\apps\pro\engine”
prosvc_service.rb -E production
C:\metasploit\ruby\bin\ruby.exe -C “C:\metasploit\apps\pro\ui” thin_service.rb

C:\metasploit\ruby\bin\ruby.exe -C “C:\metasploit\apps\pro\ui”
worker_service.rb

2. 使用社区版的license只能扫描,其它的功能根本不能用。。。

Eclipse 是如何启动的

我测试的Eclipse版本是4.2,低版本的没有测试过。

1.
rt.equinox.framework/features/org.eclipse.equinox.executable.feature/library/eclipseMain.c

会编译成Linux下的eclipse可执行文件或者Windows下的eclipse.exe,它只是来完成对eclipse.ini的解析,

同时来决定通过什么方式来启动eclipse(JNI或者直接调用java来启动)。
2. eclipseMain.c通过
findSymbol方法来调用rt.equinox.framework/features/org.eclipse.equinox.executable.feature/library/eclipse.c的run方法。

在run方法中已经解析了所以的参数和知道通过那种方式来启动eclipse了,然后分两种情况:

直接通过java来启动:

javaResults = launchJavaVM(vmCommand);

通过JNI来启动(JNI_CreateJavaVM in jni.h to start JVM and run Main.run(String[]) ):
javaResults = startJavaVM(jniLib, vmCommandArgs, progCommandArgs, jarFile);

例一:如下的命令是通过eclipse可执行文件来启动eclipse的具体参数:

/usr/bin/java -Dosgi.requiredJavaVersion=1.6 -XX:MaxPermSize=256m -Xms40m
-Xmx512m -jar /home/test/eclipse-standard-kepler-R-linux-
gtk-x86_64//plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar -os
linux -ws gtk -arch x86_64 -showsplash /home/test/eclipse-standard-kepler-R-
linux-gtk-x86_64//plugins/org.eclipse.platform_4.3.0.v20130605-2000/splash.bmp
-launcher /home/test/eclipse-standard-kepler-R-linux-gtk-x86_64/eclipse -name
Eclipse --launcher.library /home/test/eclipse-standard-kepler-R-linux-
gtk-x86_64//plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.200.v20130521-0416/eclipse_1506.so
-startup /home/test/eclipse-standard-kepler-R-linux-
gtk-x86_64//plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar

--launcher.appendVmargs -exitdata 6fa800c -product
org.eclipse.epp.package.standard.product -vm /usr/bin/java -vmargs
-Dosgi.requiredJavaVersion=1.6 -XX:MaxPermSize=256m -Xms40m -Xmx512m -jar
/home/test/eclipse-standard-kepler-R-linux-
gtk-x86_64//plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar

在Linux下的so文件是: --launcher.library /home/test/eclipse-standard-kepler-R-
linux-
gtk-x86_64//plugins/org.eclipse.equinox.launcher.gtk.linux.x86_64_1.1.200.v20130521-0416/eclipse_1506.so

启动文件是: -startup /home/test/eclipse-standard-kepler-R-linux-
gtk-x86_64//plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar

通过这种方法来启动的eclipse有两个进程,一个eclipse的可执行文件进程,另外一个是java进程

例二:直接通过java -jar来启动

java -jar /home/test/eclipse-standard-kepler-R-linux-
gtk-x86_64//plugins/org.eclipse.equinox.launcher_1.3.0.v20130327-1440.jar也可以启动,

但是这种方法启动的eclipse只有java一个进程。

http://wiki.eclipse.org/Equinox_Launcher
http://wiki.eclipse.org/Equinox_Launcher_Plan

互联网怎么赚钱 by taosay --集结贴

互联网怎么赚钱(一) 内容提要:广告,Yahoo!

http://taosay.net/index.php/2013/06/13/%E4%BA%92%E8%81%94%E7%BD%91%E6%80%8E%E4%B9%88%E8%B5%9A%E9%92%B1%EF%BC%88%E4%B8%80%EF%BC%89/

互联网怎么赚钱(二) 内容提要:流量,Baidu,360,腾讯,瑞星,金山

http://taosay.net/index.php/2013/06/14/%E4%BA%92%E8%81%94%E7%BD%91%E6%80%8E%E4%B9%88%E8%B5%9A%E9%92%B1%EF%BC%88%E4%BA%8C%EF%BC%89/

互联网怎么赚钱(三) 内容提要:电商,京东,淘宝,第三方支付行业,抽税,阿里金融

http://taosay.net/index.php/2013/06/16/%E4%BA%92%E8%81%94%E7%BD%91%E6%80%8E%E4%B9%88%E8%B5%9A%E9%92%B1%EF%BC%88%E4%B8%89%EF%BC%89/

互联网怎么赚钱(四) 内容提要:Freemium(免费增值),Evernote,腾讯,游戏,特权,博彩,se情 ,付费的强需求,加速用户付费的频率

http://taosay.net/index.php/2013/06/17/%E4%BA%92%E8%81%94%E7%BD%91%E6%80%8E%E4%B9%88%E8%B5%9A%E9%92%B1%EF%BC%88%E5%9B%9B%EF%BC%89/

互联网怎么赚钱(五) 内容提要:开源软件,开源软件基金会,赞助,主要赞助者来自于商业公司,Redhat,吉列剃须刀

http://taosay.net/index.php/2013/06/18/%E4%BA%92%E8%81%94%E7%BD%91%E6%80%8E%E4%B9%88%E8%B5%9A%E9%92%B1%EF%BC%88%E4%BA%94%EF%BC%89/

互联网怎么赚钱(六) 内容提要:众筹模式,广告、会员制、加工后卖

http://taosay.net/index.php/2013/06/20/%E4%BA%92%E8%81%94%E7%BD%91%E6%80%8E%E4%B9%88%E8%B5%9A%E9%92%B1%EF%BC%88%E5%85%AD%EF%BC%89/

在windows下如何安装lxml的python包

通过pip安装:

1. install easy_install

download file from http://python-distribute.org/distribute_setup.py
python.exe distribute_setup.py
2. install pip
download file from https://raw.github.com/pypa/pip/master/contrib/get-pip.py
python.exe get-pip.py
after install pip, the path is C:\Python27\Scripts\pip.exe
3. install lxml

pip.exe install lxml

自己下载exe安装:

https://pypi.python.org/pypi/lxml/2.3 下载exe文件,安装就可以了

快递公司送货员送到货时,打电话通知客户来取的改进

当快递公司送货员送到货时,每次都要打电话通知客户来取包裹。

这是一个体力活,几乎每个包裹都要打电话通知,有时还会拨错电话。

改进:

为什么不把打电话的这一个动作,集成到一个系统里面,到时候送货员只要通过一个手机的APP

发送对应的指令,然后系统会给相应的用户拨打语音电话,进行提醒。如果拨打不成功,然后反馈给

送货员,这时他就知道对应的客户没在,然后就不用等客户了。

同时这对快递公司也有好处,一方面可以和通信公司合作,减少通信成本,同时也免去了快递员的通信费。

你觉得呢?