HadoopIntellijPlugin插件HDFS文件系统对象的设计与实现

  本节,简单介绍HDFS文件系统浏览器的文件系统对象。文件系统对象和HDFS文件系统对象一致,分为目录和文件,文件不再进行具体的区分文件类型。文件系统对象在UI上表现为文件系统树上的节点。FileSystemObject整个设计的类图如下:

文件系统对象的接口定义 FileSystemObject

  文件系统对象在UI上表现为树节点,因此该接口需要继承自定义的树节点接口FileSystemBrowserTreeNode接口。FileSystemObject接口定义了文件系统对象的相关属性和方法,包括显示的名称、图标、对象类型(目录还是文件)、关联的连接处理对象、父对象等等。直接贴代码了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
/**
* 定义文件系统对象接口
* Created by fangyuzhong on 17-7-15.
*/
public interface FileSystemObject extends FileSystemBrowserTreeNode,DynamicContentElement,
Referenceable, PresentableConnectionProvider
{
/**
* 获取文件系统对象类型
*
* @return
*/
FileSystemObjectType getObjectType();
/**
* 获取文件系统对象的名称
*
* @return
*/
@NotNull
String getName();
/**
* 文件系统对象是否加载过
*
* @return
*/
int getOverload();

/**
* 获取文件系统对象的类型名称
*
* @return
*/
String getTypeName();

/**
* 获取文件系统对象的图标
*
* @return
*/
@Nullable
Icon getIcon();
/**
* 获取文件系统对象的连接处理对象
*
* @return
*/
@NotNull
ConnectionHandler getConnectionHandler();
/**
* 获取文件系统对象的父对象
*
* @return
*/
FileSystemObject getParentObject();
/**
* 获取文件系统对象的集合
*
* @return
*/
@NotNull
FileSystemObjectBundle getObjectBundle();
/*
* 获取导航默认对象
*
* @return
*/
@Nullable
FileSystemObject getDefaultNavigationObject();
/**
* 获取未能进行释放的文件系统对象
*
* @return
*/
@Nullable
FileSystemObject getUndisposedElement();
/**
* 获取文件系统对象的属性
*
* @return
*/
FileSystemObjectProperties getProperties();
/**
* 获取文件系统对象可呈现的属性集合
*
* @return
*/
List<PresentableProperty> getPresentableProperties();
/**
* 获取文件系统对象的引用
*
* @return
*/
FileSystemObjectRef getRef();
/**
* 对象是否已验证
*
* @return
*/
boolean isValid();
/**
* 获取文件系统对象的父对象
*
* @return
*/
@NotNull
FileSystemBrowserTreeNode getParent();
}

HDFS根目录对象FileSystemObjectBundle接口定义

  我们把HDFS根目录”/“ 下的对象(目录也好文件也好)单独拿出来,定义成FileSystemObjectBundle,这样设计是为后面读取HDFS对象方便绑定到UI上进行显示,他也是TreeNode,因此也继承了FileSystemBrowserTreeNode,他只是个标志,并拥有 获取根节点对象的数据连接处理对象。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 定义文件系统对象的集合,这里特指HDFS中的根目录对象"/"
* Created by fangyuzhong on 17-7-15.
*/
public interface FileSystemObjectBundle
extends FileSystemBrowserTreeNode, Disposable
{
/**
* 获取文件系统连接对象
* @return
*/
ConnectionHandler getConnectionHandler();
}

文件系统对象的抽象实现 FileSystemObjectImpl

抽象实现类中,有两个构造函数:

1、该构造函数以文件系统对象的父对象、HDFS的FIleStatus和对象的名称为参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* 初始化文件系统对象
* @param parentObject 父对象
* @param HDFSFileStatus HDFS的文件状态对象
* @param name 对象的名称
*/
protected FileSystemObjectImpl(FileSystemObject parentObject,
org.apache.hadoop.fs.FileStatus HDFSFileStatus, String name)
{
this.connectionHandlerRef = ConnectionHandlerRef.from(parentObject.getConnectionHandler());
this.parentObjectRef = FileSystemObjectRef.from(parentObject);
this.name = name;
init(HDFSFileStatus,null);
}

2、该构造函数以文件系统对象连接处理对象、HDFS的FIleStatus和对象的名称为参数,当读取HDFS的根目录“/”对象的时候,调用该构造函数,除此之外,调用构造函数1

1
2
3
4
5
6
7
8
9
10
11
12
13
/**
* 初始化文件系统对象
* @param connectionHandler 文件对象的连接处理类
* @param HDFSFileStatus HDFS的文件状态对象
* @param name 对象的名称
*/
protected FileSystemObjectImpl(ConnectionHandler connectionHandler,
org.apache.hadoop.fs.FileStatus HDFSFileStatus, String name)
{
this.connectionHandlerRef = ConnectionHandlerRef.from(connectionHandler);
this.name = name;
init(HDFSFileStatus,connectionHandler);
}

方法 init(org.apache.hadoop.fs.FileStatus HDFSFileStatus,ConnectionHandler connectionHandler),构建对象的引用,并且读取对象的相关信息,目录或文件的创建者、文件目录大小、文件目录路径等等。

1
2
3
4
5
6
7
8
9
10
11
/**
* 初始化,获取HDFS系统的对象
* @param HDFSFileStatus
* @param connectionHandler
*/
private void init(org.apache.hadoop.fs.FileStatus HDFSFileStatus,ConnectionHandler connectionHandler)
{
FileSystemObjectType fileSystemObjectType = HDFSFileStatus.isDirectory()? FileSystemObjectType.DIRECTORY: FileSystemObjectType.FILE;
this.objectRef = new FileSystemObjectRef(this, fileSystemObjectType,connectionHandler);
fileSystemInform = HDFSUtil.getFileSystemInformation(HDFSFileStatus);
}

内部构建子对象

  获取该对象的全部子对象,使用多线程的方式,获取其子对象,调用抽象方法(该抽象方法在具体的对象实现类中去重写) :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public abstract List<FileSystemBrowserTreeNode> buildAllPossibleTreeChildren();
public List<? extends FileSystemBrowserTreeNode> getChildren()
{
if (this.visibleTreeChildren == null)
{
synchronized (this)
{
if (this.visibleTreeChildren == null)
{
this.visibleTreeChildren = new ArrayList();
this.visibleTreeChildren.add(new LoadInProgressTreeNode(this));
ConnectionHandler connectionHandler = getConnectionHandler();
String connectionString = connectionHandler == null ? "" : " (" + connectionHandler.getName() + ")";
new BackgroundTask(getProject(), "Loading data " + connectionString, true)
{
public void execute(@NotNull ProgressIndicator progressIndicator)
{
buildTreeChildren(false);
}
}.start();
}
}
}
return this.visibleTreeChildren;
}

  内部构建子对象:首先获取全部可能的对象,然后遍历对象,进行对象的初始化,判断是否是加载数据节点,是的话,删除该节点,并设置该对象的子对象加载完毕标志,最后,触发通知,TreeNode已经修改,需要重新加载该对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
private void buildTreeChildren(boolean isreBuild)
{
FailsafeUtil.check(this);
List<FileSystemBrowserTreeNode> allPossibleTreeChildren = getAllPossibleTreeChildren(isreBuild);
List<FileSystemBrowserTreeNode> newTreeChildren = allPossibleTreeChildren;
if (allPossibleTreeChildren.size() > 0)
{
newTreeChildren = new ArrayList(newTreeChildren);
for (FileSystemBrowserTreeNode treeNode : newTreeChildren)
{
FileSystemObject objectList = (FileSystemObject) treeNode;
objectList.initTreeElement();
FailsafeUtil.check(this);
}
if ((this.visibleTreeChildren.size() == 1) && ((this.visibleTreeChildren.get(0) instanceof LoadInProgressTreeNode)))
{
this.visibleTreeChildren.get(0).dispose();
}
}
this.visibleTreeChildren = newTreeChildren;
this.treeChildrenLoaded = true;
//通知TreeNode修改,需要重新加载
Project project = FailsafeUtil.get(getProject());
( EventUtil.notify(project, BrowserTreeEventListener.TOPIC)).nodeChanged(this, TreeEventType.STRUCTURE_CHANGED);
FileSystemBrowserManager.scrollToSelectedElement(getConnectionHandler());
}

HDFS的目录和文件对象的实现 HadoopDirectoryObject 、HadoopFileObject

HDFS目录对象的实现HadoopDirectoryObject。

  继承抽象类FileSystemObjectImpl和,重写对象类型、HDFS目录所在的路径、获取目录对象的子对象。代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/**
* 定义HDFS目录对象
* Created by fangyuzhong on 17-7-17.
*/
public class HadoopDirectoryObject extends FileSystemObjectImpl
{
private List<FileSystemBrowserTreeNode> fileSystemBrowserTreeNodeLists =null;
private org.apache.hadoop.fs.FileStatus fileStatus=null;
/**
* 初始化 HDFS目录对象
* @param parentObject 父对象
* @param resultSet HDFS的FileStatus
* @param name 对象的名称
*/
public HadoopDirectoryObject(FileSystemObject parentObject,
org.apache.hadoop.fs.FileStatus resultSet, String name)
{
super(parentObject,resultSet,name);
fileStatus = resultSet;
}
/**
* 初始化HDFS目录对象
* @param connectionHandler 对象的连接
* @param resultSet HDFS的FileStatus
* @param name 对象的名称
*/
public HadoopDirectoryObject(ConnectionHandler connectionHandler,
org.apache.hadoop.fs.FileStatus resultSet, String name)
{
super(connectionHandler,resultSet,name);
fileStatus = resultSet;
fileSystemBrowserTreeNodeLists = new ArrayList();
}
/**
* 获取对象的类型 这里是目录
* @return
*/
public FileSystemObjectType getObjectType()
{
return FileSystemObjectType.DIRECTORY;
}

/**
* 获取目录对象的HDFS路径
* @return
*/
public String getLocationString()
{
return fileStatus.getPath().toString();
}
/**
* 重写,构建目录的下面的子对象
* @return
*/
public List<FileSystemBrowserTreeNode> buildAllPossibleTreeChildren()
{
ConnectionHandler connectionHandler = getConnectionHandler();
FileSystem fileSystem = connectionHandler.getMainFileSystem();
try
{
String path = fileStatus.getPath().toString();
FileStatus[] fileStatuses = fileSystem.listStatus(new Path(fileStatus.getPath().toString()));
FileSystemBrowserTreeNode[] fileSystemBrowserTreeNodes = new FileSystemBrowserTreeNode[fileStatuses.length];
for (int i = 0; i < fileStatuses.length; i++)
{
FileStatus f = fileStatuses[i];
if (f.isDirectory())
{
FileSystemObject dirdbObject = new HadoopDirectoryObject(this, f,f.getPath().getName());
fileSystemBrowserTreeNodes[i] = dirdbObject;
} else
{
FileSystemObject filedbObject = new HadoopFileObject(this, f,f.getPath().getName());
fileSystemBrowserTreeNodes[i] = filedbObject;
}
}
fileSystemBrowserTreeNodeLists = FileSystemBrowserUtils.createList(fileSystemBrowserTreeNodes);
}
catch (Exception ex)
{

}
return fileSystemBrowserTreeNodeLists;
}
}

HDFS的文件对象的实现HadoopFileObject。

  和目录实现一样,唯一区别是 对象类型是文件类型并且文件是没有子对象的,但也要重写:
public List buildAllPossibleTreeChildren()
并且不能返回NULL。 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* 定义HDFS文件对象
* Created by fangyuzhong on 17-7-17.
*/
public class HadoopFileObject extends FileSystemObjectImpl
{
private List<FileSystemBrowserTreeNode> fileSystemBrowserTreeNodes =null;
private FileStatus fileStatus;
/**
* 初始化HDFS文件对象
* @param parentObject 父对象
* @param resultSet HDFS的FIleStatus
* @param name 文件名称
*/
public HadoopFileObject(FileSystemObject parentObject,
org.apache.hadoop.fs.FileStatus resultSet, String name)
{
super(parentObject, resultSet,name);
fileSystemBrowserTreeNodes = new ArrayList();
fileStatus = resultSet;
}
/**
* 初始化HDFS的文件对象
* @param connectionHandler 连接处理对象
* @param resultSet HDFS的FIleStatus
* @param name 文件名称
*/
public HadoopFileObject(ConnectionHandler connectionHandler,
org.apache.hadoop.fs.FileStatus resultSet, String name)
{
super(connectionHandler, resultSet,name);
fileSystemBrowserTreeNodes = new ArrayList();
fileStatus = resultSet;
}
/**
* 获取HDFS文件所在的路径
* @return
*/
public String getLocationString()
{
return fileStatus.getPath().toString();
}
/**
* 获取对象类型,这里是文件
* @return
*/
public FileSystemObjectType getObjectType()
{
return FileSystemObjectType.FILE;
}
/**
* 文件没有子对象,但不能给NULL
* @return
*/
public List<FileSystemBrowserTreeNode> buildAllPossibleTreeChildren()
{
return fileSystemBrowserTreeNodes;
}
}

HDFS的根目录对象的实现FileSystemObjectBundleImpl。

  该类继承树节点的抽象类FileSystemBrowserTreeNodeBase和FileSystemObjectBundle接口。该类,重点关注,怎么读取HDFS的根目录“/”对象,获取其数据进行绑定的。该类只有一个构造函数,在构造函数中通过 loadData()开始HDFS根目录的数据加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* 初始化
* @param connectionHandler 连接处理接口
* @param treeParent 父节点
*/
public FileSystemObjectBundleImpl(ConnectionHandler connectionHandler, FileSystemBrowserTreeNode treeParent)
{
this.connectionHandler = connectionHandler;
this.treeParent = treeParent;
loadData();
}
/**
* 重新加载数据
*/
public void loadData()
{
//获取根节点下的所有文件和目录 创建 节点
fileSystem = connectionHandler.getMainFileSystem();
if(connectionHandler.getConnectionStatus().isConnected())
{
try
{
if( this.allPossibleTreeChildren!=null)
{
this.allPossibleTreeChildren.clear();
}
FileStatus[] fileStatuses = fileSystem.listStatus(new Path("/"));
FileSystemBrowserTreeNode[] fileSystemBrowserTreeNodes = new FileSystemBrowserTreeNode[fileStatuses.length];
for (int i = 0; i < fileStatuses.length; i++)
{
FileStatus f = fileStatuses[i];
if (f.isDirectory())
{
//如果是目录,实例化目录对象
FileSystemObject dirdbObject = new HadoopDirectoryObject(connectionHandler, f, f.getPath().getName());
fileSystemBrowserTreeNodes[i] = dirdbObject;
} else
{
//如果是文件,实例化文件对象
FileSystemObject filedbObject = new HadoopFileObject(connectionHandler, f, f.getPath().getName());
fileSystemBrowserTreeNodes[i] = filedbObject;
}
}
this.allPossibleTreeChildren = FileSystemBrowserUtils.createList(fileSystemBrowserTreeNodes);
}
catch (Exception ex)
{
}
}
else
{
if( this.allPossibleTreeChildren!=null)
{
this.allPossibleTreeChildren.clear();
}
}
}