UserGroupInformation类定义了一个与文件系统相关的用户和组信息抽象的内容,Hadoop框架实现了一个基于Unix系统的用户和组信息的实现类UnixUserGroupInformation,该类继承自UserGroupInformation抽象类。
从UserGroupInformation抽象类与其子类UnixUserGroupInformation的属性字段可以看出,抽象类所定义的功能信息重心在,描述一个登录以后获得的UserGroupInformation实例,而UnixUserGroupInformation类主要是侧重于登录前的信息的处理。首先看一下UnixUserGroupInformation类中定义的属性:
- public static final String DEFAULT_USERNAME = "DrWho";
- public static final String DEFAULT_GROUP = "Tardis";
- final static private HashMap<String, UnixUserGroupInformation> user2UGIMap = new HashMap<String, UnixUserGroupInformation>();
-
- private String userName;
- private String[] groupNames;
-
- final private static String UGI_TECHNOLOGY = "STRING_UGI";
前面两个是默认的Unix用户名DEFAULT_USERNAME和组名DEFAULT_GROUP,另外其中用户名userName和组名groupNames是根据UnixUserGroupInformation类构造方法设置的,这样保证了即使无法得到用户和组的信息,也能够使用默认的值去填充,比较适合用于测试,快速定位到用户名和组名的设置处。
第二个属性user2UGIMap是一个<用户名, 用户和组信息实例>的Map,用来快速获取到用户和组的信息。
最后一个UGI_TECHNOLOGY定义读获取用户和组信息的方式,显然该类中默认使用从文本中读取字符串的方式来构造。
对于UnixUserGroupInformation类实例的构造,该类给出了四个方法:
- public UnixUserGroupInformation() {
- }
-
- public UnixUserGroupInformation(String userName, String[] groupNames) {
- setUserGroupNames(userName, groupNames);
- }
-
-
-
-
- public UnixUserGroupInformation(String[] ugi) {
- if (ugi==null || ugi.length < 2) {
- throw new IllegalArgumentException( "Parameter does contain at least "+ "one user name and one group name");
- }
-
- public static UnixUserGroupInformation createImmutable(String[] ugi) {
- return new UnixUserGroupInformation(ugi) {
- public void readFields(DataInput in) throws IOException {
- throw new UnsupportedOperationException();
- }
- };
- }
- String[] groupNames = new String[ugi.length-1];
- System.arraycopy(ugi, 1, groupNames, 0, groupNames.length);
- setUserGroupNames(ugi[0], groupNames);
- }
该类实现了其抽象基类定义的两个抽象方法,用来获取用户名和组名,如下所示:
- public String[] getGroupNames() {
- return groupNames;
- }
-
- public String getUserName() {
- return userName;
- }
UserGroupInformation抽象类实现了org.apache.hadoop.io.Writable接口,并没有在其中实现序列化操作的两个方法,所以在其子类UnixUserGroupInformationg给出了实现,如下:
-
-
-
- public void readFields(DataInput in) throws IOException {
-
- String ugiType = Text.readString(in);
- if (!UGI_TECHNOLOGY.equals(ugiType)) {
- throw new IOException("Expect UGI prefix: " + UGI_TECHNOLOGY + ", but receive a prefix: " + ugiType);
- }
-
-
- userName = Text.readString(in);
- int numOfGroups = WritableUtils.readVInt(in);
- groupNames = new String[numOfGroups];
- for (int i = 0; i < numOfGroups; i++) {
- groupNames[i] = Text.readString(in);
- }
- }
-
-
-
-
- public void write(DataOutput out) throws IOException {
-
- Text.writeString(out, UGI_TECHNOLOGY);
-
- Text.writeString(out, userName);
- WritableUtils.writeVInt(out, groupNames.length);
- for (String groupName : groupNames) {
- Text.writeString(out, groupName);
- }
- }
下面两个方法,将用户和组的信息以字符串的形式存到Hadoop的配置类Configuration实例中,也能从一个给定的Configuration类实例中读取出来:
- public static void saveToConf(Configuration conf, String attr, UnixUserGroupInformation ugi ) {
- conf.set(attr, ugi.toString());
- }
-
- public static UnixUserGroupInformation readFromConf(Configuration conf, String attr) throws LoginException {
- String[] ugi = conf.getStrings(attr);
- if(ugi == null) {
- return null;
- }
- UnixUserGroupInformation currentUGI = null;
- if (ugi.length>0 ){
- currentUGI = user2UGIMap.get(ugi[0]);
- }
- if (currentUGI == null) {
- try {
- currentUGI = new UnixUserGroupInformation(ugi);
- user2UGIMap.put(currentUGI.getUserName(), currentUGI);
- } catch (IllegalArgumentException e) {
- throw new LoginException("Login failed: "+e.getMessage());
- }
- }
- return currentUGI;
- }
与执行Unix系统的Shell命令相关的三个方法,介绍如下:
-
-
-
- static String getUnixUserName() throws IOException {
- String[] result = executeShellCommand(new String[]{Shell.USER_NAME_COMMAND});
- if (result.length!=1) {
- throw new IOException("Expect one token as the result of " +
- Shell.USER_NAME_COMMAND + ": " + toString(result));
- }
- return result[0];
- }
-
-
-
-
- private static String[] getUnixGroups() throws IOException {
- return executeShellCommand(Shell.getGROUPS_COMMAND());
- }
-
-
- private static String[] executeShellCommand(String[] command) throws IOException {
- String groups = Shell.execCommand(command);
- StringTokenizer tokenizer = new StringTokenizer(groups);
- int numOfTokens = tokenizer.countTokens();
- String[] tokens = new String[numOfTokens];
- for (int i=0; tokenizer.hasMoreTokens(); i++) {
- tokens[i] = tokenizer.nextToken();
- }
- return tokens;
- }
上面三个方法能够模拟执行Unix系统的Shell命令,与Hadoop框架中实现的工具类org.apache.hadoop.util.Shell类密切相关,执行Unix系统的Shell命令的实现有一点点复杂,可以参考其工具类实现。
上面分析与登录系统之前用户和组信息的获取实现。当一个用户具备了充分的信息,可以登录文件系统进行特定的操作。下面就分析执行登录的过程了,有三个实现方法,基本原理都是一致的,下面给出这三个方法的声明及其说明:
-
-
-
- public static UnixUserGroupInformation login() throws LoginException;
-
-
-
-
-
-
- public static UnixUserGroupInformation login(Configuration conf, boolean save) throws LoginException;
-
-
-
-
- public static UnixUserGroupInformation login(Configuration conf) throws LoginException;
最后,该类还有一个用于比较两个UGI是否相同的方法public boolean equals(Object other)。
总结一下,UnixUserGroupInformation类主要对登录前的用户名和组名信息进行格式化,使用两种方式来获取:
1、通过从Hadoop的配置类实例中获取到用户名和组名;
2、模拟执行Unix系统Shell命令获取到 用户名和组名。