首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

Workspace Resource框架课题(2)workspace 框架API

2013-04-22 
Workspace Resource框架专题(2)workspace 框架API2? 工作空间API  本节将重点介绍工作空间API和编程模式的

Workspace Resource框架专题(2)workspace 框架API
2? 工作空间API
  本节将重点介绍工作空间API和编程模式的关键部分。在您对资源进行操作时,这部分内容会非常有用。
  工作空间API的全面描述位于org.eclipse.core.resources包的Javadoc中,您可以在Eclipse帮助系统中的Platform Plug-in Developer Guide一节中找到。
2.1? 工作空间和工作空间根目录
  当启动Eclipse时,您访问的是单个工作空间。为了在插件代码中访问工作空间,需要获取当前工作空间的引用。为此,可以通过访问org.eclipse.core.resources插件的插件类,来获取如下的工作空间。
  IWorkspace myWorkspace =
   org.eclipse.core.resources.ResourcesPlugin.getWorkspace();
  一旦获得了工作空间的引用,您就可以添加资源更改侦听器,添加保存参与者以及导航至IWorkspaceRoot。
  myWorkspace.getRoot();
  下面列出了IWorkspace API中的一些值得注意的方法:
●?????? getDescription返回工作空间的描述。这些描述可以用来获取或者更改与工作空间相关的设置,例如工作空间中的项目按照何种顺序构建,资源发生更改时构建过程是否自动执行。其中许多设置与Preferences对话框的Workbench页面中的选项相对应。
●?????? validateName(name,type)返回一个IStatus对象,该方法将验证传入的名称对于指定的资源类别是否合法。
●?????? addResourceChangeListener(…)用于向工作空间添加通用或者特定变化事件的侦听器。
●?????? addSaveParticipant(…)注册一个保存参与者类,该类负责对由传入参数中所指定的插件的工作空间保存事件进行处理。
  名称验证过程由validateName方法提供,它执行必要的测试以验证名称对于指定的资源类型是否合法。只有当资源真正被创建时,才会进行名称的验证过程,而创建一个资源句柄时,并不会进行名称验证。如果您想在实际创建资源之前,验证名称是否合法,请使用validateName方法。
  通常您可以简单地获取工作空间引用,然后使用getRoot方法得到工作空间根目录;从根目录开始,您可以移动到资源模型的其他区域,例如查找特定的项目、添加/修改资源以及在资源树中查找与工具相关的内容。
  工作空间根目录是项目的容器,因此,也是所有资源的容器。工作空间根目录实现了IContainer接口。项目和文件夹也实现了该接口。尽管如此,工作空间根目录只能包含项目。而项目和文件夹可以包含文件夹和文件。工作空间根目录并没有在Navigator视图中显示出来,但您可以通过项目获取其父结点(getParent),得到工作空间根目录。显然,对于getParent方法,工作空间根目录将返回null。
  您可能会指出默认的工作空间目录名应该是workspaceroot。虽然存在一个与工作空间对应的接口(IWorkspace),但是这个接口并没有扩展IResource接口。不要被IWorkspace和IWorkspaceRoot两个接口在结构上的差别和它们所扮演的角色弄糊涂。只需记住一切资源都存在于工作空间中,而您的代码应该总是借助于工作空间API来创建、访问和修改资源。如果您直接向文件系统写文件,然后再通过工作空间刷新来保持工作空间与文件系统的同步,这样会大大削弱了工作空间API的能力。不仅如此,在未同步期间,任何资源变化侦听器或者构建器将无法收到通知,直到文件系统与工作空间同步为止,而且您将无法选择在资源更改的同时,把变化记录在本地的历史记录中。当工作空间文件发生更改时,内置于工作空间API的本地历史记录必须进行相应的更新;而直接对文件系统进行的修改不会被本地历史记录所捕获。
  注意:
  在胖客户端平台应用程序中,工作空间目录仍然存在。在不考虑-data调用选项所指定的工作空间目录名称的情况下,工作空间目录扮演两种角色。一种是作为.metadata目录的父目录,另一种是作为项目的默认位置。只有当配置中包含了org.eclipse.core.resources插件,并且由Workbench正确地启动,工作空间才可以包含项目。这一步对于基于org.eclipse.ui.ide.workbench应用程序的IDE配置来说是自动完成的。
2.2? 资源容器
  一旦获得工作空间根目录,就可以很容易地访问工作空间内的其他资源。每种资源类型均提供了各种访问资源的方法,包括操纵资源树、获取资源的句柄(无论资源是否存在),以及查找特定的资源实例。
  对于那些包含子资源的资源来说,IContainer接口是一个通用的编程接口。这里的容器包括工作空间根目录、项目和文件夹。表1-1列出了资源模型接口及其方法。这些方法可以用来导航资源,一直到资源树中某个文件的内容。
表1-1? 资源模型导航


图1-4? 项目描述:对性质、构建器和项目引用进行管理
  项目描述的用途在于记录项目的重要信息。在Eclipse中,与项目描述有关的API由IProjectDescription接口定义,而项目描述本身在工作空间中则是一个文件。对于每个项目,都存在一个项目描述文件.project,它由资源插件负责管理。下面的例子展示了一个插件开发项目的.project文件的内容。
  <?xm1 version="1.0" encoding="UTF-8"?>
  <projectDescription>
  <name>com.ibm.too1.resources</name>
  <comment> </comment>
  <projects> </projects>
  <bui1dSpec>
  <bui1dCommand>
  <name>org.eclipse.jdt.core.javabui1der</name>
  <arguments> </arguments>
  </bui1dCommand>
  <bui1dCommand>
  <name>org.ec1ipse.pde.ManifestBuilder</name>
  <arguments> </arguments>
  </bui1dCommand>
  <buildCommand>
  <name>org.ec1ipse.pde.SchemaBui1der</name>
  <arguments> </arguments>
  </bui1dCommand>
  </bui1dSpec>
  <natures>
  <nature>org.eclipse.pde.PluginNature</nature>
  <nature>org.ec1ipse.jdt.core.javanature</nature>
  </natures>
  </projectDescription>
  将关于项目的信息保存为项目文件夹下的一个文件,我们可以把它存储在一个资源库中。但如果该类信息作为资源属性存储,它将保存在当前工作空间的.metadata文件夹中,从而无法保存在资源库中。如果您的工具要求关于项目的信息在团队成员内部共享,应该考虑将它保存为一个文件,并存储在资源库中,或者使用用户设置API。
  您可以在项目描述中添加性质和构建器,使之与项目关联起来。使用下面的方法,可以获得项目的性质列表。
  String[] natures = project.getDescription().getNatureIds();
  每个项目都需要定义它的构建命令,而且每个命令都知道构建器的名称。您可以获取所有的构建命令(description.getBuildSpec),然后可以从每个命令中获取构建器的名称(command.getBuilderName)。
  注意:
  尽管项目的构建器和性质存储在一个文件中,但您最好不要直接编辑该文件,修改这些信息。因为,直接向该文件添加一个性质,并不会触发Eclipse对该性质进行配置。所以,性质和构建器只能作为工具功能的一部分进行添加或删除。
  您可以通过两种方式引用其他项目:使用用户界面中的项目属性页,或者使用IProjectDescription API。使用用户界面,您可以创建简单的项目引用,而IProjectDescription API则不仅允许创建同样简单的项目引用,而且可以存储一个动态计算的项目引用集。
  只有简单的项目引用才会保存在.project文件中。下面是一个存储了项目引用的.project文件,这里只显示项目引用部分的内容。
  <projects>
  <project>com.ibm.tool.core</project>
  <project>com.ibm.tool.common</project>
  </projects>
  从项目出发,通过使用如下的API调用,您既可以获得它所引用的项目,也可以获得引用了它的项目。
  project.getReferencedProjects();
  project.getReferencingProjects();
  引用当前项目的项目不会存储在.project文件中,但是可以通过访问工作空间资源模型来确定哪些项目引用了当前项目。
  IProjectDescription API也支持创建和访问动态引用的项目集。这些项目是在运行时定义的,这些定义并没有保存在.project文件中,而是保存在工作空间的元数据中。不同于简单的项目引用,动态引用不显示在用户界面中,惟一的相关记录保存在工作空间的元数据中。既然这些引用对于用户是不可见的,而且无法直接修改,您就可以把动态项目引用称为“粘滞引用”。由于这些引用不会发送到资源库中,所以当项目检出时,它们也需要重新计算。
  下面的代码片段展示了如何利用IProjectDescription接口定义和获取一个动态引用的项目集。
  // Calculate project array and define as dynamic
  // project references.
  IProject[] projects =
   CalculateToolSpecificProjectSet();
  Project.getDescription().setDynamicReferences (projects);
  您可以根据需要来使用这些不同的项目引用方法。诸如JDT和PDE这样的工具,均根据各自的意图使用了这些方法。虽然它们所创建的项目引用作为工作空间的一部分进行管理和/或保存在.project文件中,但在Eclipse平台的其他地方,并不会使用这些项目引用。
2.6? 资源
  IResource接口是资源模型的顶层接口。除工作空间之外的所有核心资源对象均实现了IResource接口。工作空间并不属于该扩展层次中,但是它却包含在资源模型的逻辑表示中(如图1-1所示)。IResource接口提供对于所有资源均可用的基本功能。使用该层的API,您可以完成如下一些操作:
●?????? 复制、移动或者删除资源(copy、move或delete)。
●?????? 确定资源在工作空间中的位置(getParent、getProject或getFullPath)。
●?????? 判断资源是否存在于工作空间中(exists或isAccessible)。
●?????? 读取资源相关的属性,例如派生属性、只读属性或诸如同步之类的状态属性(表明该资源以及给定深度的后代资源是否与文件系统同步)。
  注意:
  与创建资源有关的API是与资源类型相关的;这些功能并没有作为通用的IResource API的一部分。
  也可以从文件系统中刷新资源。这种刷新方法已经在本章前述部分的“资源模型与文件系统的交互”一节中介绍过了。而这里的IResource.refreshLocal方法可以传递一个深度参数,以指明刷新的对象仅仅是该资源,还是该资源及其成员,或者是该资源及其所有后代资源。在创建资源之前,执行一次刷新操作,可以使您的程序更为简洁,但将刷新强加于用户并不一定合适。因为他们可能在项目中保存文件和文件夹,而这些文件和文件夹不一定包含在工作空间中。外部启动的编辑器也可以在项目资源树中创建临时文件。如果您的程序突然将这些资源加入到工作空间中,可能会造成用户管理工作空间内容的混乱。
  有些资源可以标识为派生资源。派生资源是由工具而非用户创建的,它们可以在工具对另一个资源进行处理的过程中被重新创建。对于派生资源,工具可以选择实现特殊的处理过程,例如不将该资源发送到资源档案库中,或者在清除操作中删除所有的派生资源。比如,Java的.class文件是在Java源文件编译的过程中产生的,所以可以标记为派生资源。
  如果资源被标记为只读的话,则表示不允许通过工作空间API更改这些资源(但标记为只读的文件夹仍可以向其中添加文件)。编辑器应该不允许修改标记为只读的文件,或者至少当您试图修改只读文件时,应该弹出警告。这时,系统会抛出一个异常。如果文件系统中资源的只读属性被修改了,那么isReadOnly方法会立即返回新的属性,而无需等待工作空间刷新。

2.7? 路径
  在工作空间API中,路径通常作为方法的参数和返回值使用。路径指的是由标准的分隔符(/)分隔开的一个字符串,该字符串可以以分隔符开头和/或分隔符结尾。驱动器标识符前缀是可有可无的,例如D:或Cork/Data:都是合法的。路径值可以是相对路径,或者是指向资源的绝对位置的引用。
  表1-2对不同类型的路径值进行了比较,这里以一个名为a.proj的项目为例,列举了您可以从像aFold这样的文件夹中获取的路径值。
表1-2? 路径值
路 径 类 型方    法值相对于工作空间位置IResource.getFullPath()/a.proj/aFold相对于项目IResource.getProjectRelativePath()aFold文件系统中的物理位置IResource.getLocation()e:/eclipse/workspace/a.proj/aFold文件系统中的原始物理位置IResource.getRawLocation()e:/eclipse/workspace/a.proj/aFold
  注意:
  getLocation与getRawLocation方法的差别是非常微妙的。如Javadoc中所描述的那样:
  如果资源是一个已存在的项目,返回的路径将等于项目描述中的位置路径。如果资源是在一个已经打开的项目中的链接资源,返回的路径将等于链接资源创建时的位置路径。其他情况下,getRawLocation与getLocation方法的返回值相同。
  惟一值得注意的不同之处是,对于默认位置下(在工作空间目录中)的项目,getRawLocation方法将返回null。
  在获取引用或创建资源句柄时,您可以使用路径来定义资源的位置,例如使用getFile(IPath path)或getFolder(IPath path)方法;在复制或移动资源时,您可以将路径作为参数传递;当您查询变量的值,比如资源、工作空间根目录和平台的位置时,路径可以作为返回值。
  尽管工作空间API包括IPath接口,但您应该使用Path类的构造方法创建一个新的路径。
  IPath myPath = new Path("my/Path/");
  IPath myPatLocation = new Path("D:", "my/Path/");
  Path类的构造函数可以接收一个String类型的路径值作为参数,也可以接收两个String类型的值,第一个表示驱动器,第二个表示路径。如果该String类型的路径值的每段(通过分隔符隔开)是有效的,则该路径是有效的。而对于路径中的每段字符,如果它是非空的而且不包含冒号(:),并且不以空格开头或结尾,则该段字符是有效的。如果路径值中包括一个反斜杠(\),它将会被自动转换为正斜杠(/)。
  IPath接口所提供的方法,允许您对路径值进行操作。您可以查阅相关的Javadoc或源代码以获取可用方法的更多详细信息。
2.8? 文件夹和文件
  创建文件夹和创建文件使用的是相同的编程模式:首先,获取资源的句柄,然后判断该资源是否存在,如果不存在,则可以创建该资源。通常,您可以从文件夹或项目中获得一个文件夹或文件的句柄。如果请求的是一个已经存在资源,那么您已经获得一个可以直接使用的资源。如果请求的资源并不存在,那么需要创建该资源。但有一个前提必须满足:该资源的父资源必须是可访问的。
下面的代码根据名称获取项目的一个文件夹,如果该文件夹不存在,则试图创建该文件夹。
  private void createFolderInProject(
  IProject project, String folderName) {
  IFolder newFolder = project.getFolder(folderName);
  if (!newFolder.exists()) {
  try {
   newFolder.create(true, true,?null);
  } catch (CoreException e) {
   // Deal with exception.
  }
  }
  }
  在获取句柄、创建文件夹的过程中,文件系统有可能已经具有一个同名的文件夹,或者所给的文件夹名不合法。
  当文件系统中包含未被工作空间所感知的资源时,您所设计的创建策略,需要捕获或避免创建错误。对于这一点,Workbench New Folder向导使用了一种混和策略:在处理创建请求之前,先检查文件夹名是否合法,如果文件夹已经存在于文件系统中,则创建失败。
  文件的创建及其内容的设定可以通过工作空间API来实现。IFile API支持使用输入流来获取、设定和添加文件的内容,相应的方法如下所示:
●?????? getContents方法:获取文件内容的输入流。
●?????? setContents方法:通过传入一个输入流参数,或者IFileState参数来设定文件的内容。
●?????? appendContents方法:向当前文件的内容追加一个输入流。
  下面的代码展示了如何在传入参数所指定的文件夹下创建一个文件。如果文件已经存在,它的内容将被替换。其中的getInitialContents方法用来提供新文件的内容或者替换现有文件的内容。
  private void createFi1eInFo1der2(IFo1der folder) {
  IFile newFile = folder.getFi1e("new_Fi1e.txt");
  try {
  if (newFile.exists())
  newFile.setContents(
  getInitialContents(),
  true, false, null);
  else {
  java.io.Fi1e systemFile =
   newFile.getLocation().toFile();
  if (systemFile.exists() {
  // Skip create -- in file system.
  // Could refreshLocal on parent at this point.
  } else {
   newFile.create(getInitialContents(), false, null);
  }
 }
 } catch (CoreException ce) {
 // Failed.
 }
 }
 // Return input stream used to create initial file contents.
 private InputStream getInitialContents() {
 StringBuffer sb = new StringBuffer();
 sb.append("My New File Contents");
 return new ByteArrayInputStream(sb.toString().getBytes());
  }
  这段代码所使用的保证文件可以被创建的方法,已经超出了工作空间API的能力。它通过检查文件系统来判断文件是否已经存在。如果文件已经存在于文件系统中,但不在工作空间中,则跳过该文件的创建和内容设定过程。
2.9? 链接资源
  资源不一定总是物理存在于项目的文件系统树中。在项目的根目录下,您可以创建链接资源。链接资源指的是一个指向文件夹或文件的引用,而这些文件夹或文件并不物理存在于项目中。链接资源既可以通过New Folder或New File向导创建,也可以利用工作空间API创建。
下面的程序将会在项目中创建一个链接文件夹和一个链接文件。
  IPath path = new Path("E:/SharedResources/This");
  IFolder folder?=?project.getFo1der("aFo1der");
  if (!folder.exists())
  try {
   folder.createLink(path,IResource.NONE,nul1);
  } catch (CoreException e) {
   e.printStackTrace();
  }
  path = new Path("E:/SharedResources/That.txt");
  IFile file = project.getFi1e("aFi1e.txt");
  if (!file.exists())
  try {
   fi1e.createLink(path,IResource.ALLOW_MISSING_LOCAL,nul1);
  } catch (CoreException e) {
   e.printStackTrace();
  }
  createLink方法包含一个ALLOW_MISSING_LOCAL参数,该参数表明当欲链接的目标文件不存在时,仍允许创建该链接文件。这一选项同样适用于文件夹。
  如果您正在操作链接资源,也许需要考虑一些特殊的处理选项。如果请求一个复制或移动操作,您可以使用IResource.SHALLOW参数指明,复制的是链接,而非所链接的资源。同样,您也可以通过isLinked方法询问资源是否是一个链接资源。
  如果一个文件夹或文件在工作空间中被其他资源链接,您可以通过IWorkspaceRoot来查找这些链接的位置。您只需要将一个绝对路径(e:\folderName或e:\folder\fileName.txt)作为findContainersForLocation方法或findFilesForLocation方法的IPath参数传入。将一个文件夹的IPath参数传入findContainersForLocation方法中,可以返回一个容器数组,其中每个容器中均链接了该文件夹。而将一个文件的IPath参数传入findContainersForLocation方法中,也可以返回一个容器数组,其中每个容器中均链接了该文件。这些方法对于非链接的资源也有效,但是返回的结果意义不大;这与getParent方法的情形是一样的。
2.10? 访问资源树中的资源
  当您需要查找一个项目、文件夹甚至整个工作空间中的所有资源时,您可以使用工作空间API中的IResourceVisitor或IResourceProxyVisitor接口。通过这些接口,您可以对资源树上的某个节点进行操作,而且可以访问该节点的所有子节点。
  为了操作资源树中给定节点的所有元素,您可以定义一个实现IResourceVisitor或IResourceProxyVisitor接口的类。这两个接口均只定义了一个方法,即visit方法。在您处理资源树中每个元素以及子元素时,需要调用该visit方法。
  这两个接口之间的差别并不复杂:IResourceVisitor只需给定一个要处理的IResource资源实例,而IResourceProxyVisitor则要给定一个真实的IResourceProxy实例。该IResourceProxy实例允许您对诸如名称、类型之类的属性进行检查,但其开销要远小于创建一个真实的IResource实例。这样,可以大大减少处理资源树的开销。IResourceProxy的属性可以帮助您决定是继续访问下一个代理对象,还是需要一个真实的IResource实例。如果需要真实的资源,只需调用IResourceProxy.requestResource方法即可。
  您可以向IResource.accept方法传入感兴趣的资源节点的IResourceVisitor或IResourceProxyVisitor实例,来处理资源树。accept方法存在多种签名,除了访问者参数,其他参数可以用来指导如何处理访问者。
  下面的程序展示了IResourceVisitor接口的一种简单实现。IResourceProxyVisitor接口的实现几乎完全一样,惟一的区别在于传入给visit方法的参数类型不同。
  private void visitResourceTree(IResource resource) {
  IResourceVisitor visitor = new IResourceVisitor() {
  public boolean visit(IResource res) {
  // Process the resource.
  // ...?Your logic here ...
   // By returning true, you are saying you want
   // to process the children.
  return true;
  };
  };
  try {
   resource.accept(visitor);
  } catch (CoreException e) {
   // Problem during visit processing.
  }
  }
  当您希望处理工作空间中的所有或者部分内容时,您可以实现IResourceVisitor或IResourceProxyVisitor接口。访问者的基本功能就是允许您沿着工作空间资源树“行走”。它所返回的boolean值将指导访问者架构继续访问当前资源的子节点。
  注意:
  工作空间API还包含一个IResourceDeltaVisitor接口。该接口支持处理作为IResourceDelta的一部分所提供的资源树。
--------------------
说明:
参考资料来源--《Eclipse 权威开发指南(第2版)》
这是一本译著,原名《The Java Developer’s Guide to Eclipse》 2nd Edition, 这本还是比较全面和深入的讲解了Eclipse开发中的各个部分的感念和原理的,不适合入门,做过一段时间的开发后阅读比较好。

热点排行