2021SC@SDUSC 软件工程应用与实践——OpenMeetings项目分析(三)

2021SC@SDUSC

软件工程应用与实践——OpenMeetings项目分析(三):

概述:上周分析了项目管理工具maven的各种信息,并对其安装使用等过程进行了阐述,同时分析了maven的配置文件pom.xml中各项的含义;这周开始我着手分析我负责的两个文件包,先分析的是WebService目录;

image-20211015190733961

如图,WebService包含了main下的java文件,site下的xml配置文件以及test目录下的测试文件;主要精力应该集中在分析java文件上。

image-20211015194029896

error包的分析

package org.apache.openmeetings.webservice.error;

import javax.xml.ws.WebFault;

import org.apache.openmeetings.db.dto.basic.ServiceResult;

@WebFault	
public class ServiceException extends RuntimeException {
	private static final long serialVersionUID = 1L;
	public static final ServiceException NO_PERMISSION = new ServiceException(ServiceResult.NO_PERMISSION.getMessage());

	public ServiceException(String msg) {
		super(msg);
	}
}

首先分析的是error包下的ServiceException.java;

从名字可看出,是自定义的一个Exception,这个自定义的Exception继承自RuntimeException,表明这是一个运行时的错误 类;同时自定义一个ServiceException的成员变量,调用了openmeetings.db.dto.basic包下的ServiceResult类,表明了一个不被允许的信息;

public static final ServiceResult NO_PERMISSION = new ServiceResult("error.notallowed", Type.ERROR);

后面的构造方法直接通过super使用了父类的构造方法;

类上面的@WebFault是java的注解的一种。

拓展

​ java的注解:通常也叫做元数据,是一种代码级别的说明,可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

刚开始,打开类报错,信息为无法识别@Webfault,分析之后是这个版本的openmeetings项目需要的jdk只能是jdk8,于是在项目设置里将项目的jdk版本切换后,webfault即找到了。

作用:@webfault用来注释特定于服务的异常类,以自定义故障元素的本地名称和名称空间名称以及故障 bean 的名称。

util包的基础分析

首先通过图标可以看出来BaseWebService是一个抽象类,大概率后续多个类 都要继承自它,因此先从它入手。

image-20211015195929952

点击代码左侧的蓝色图标,就是查找其子类,果然,下面的七个类都是继承自BaseWebService;

同时,左边有个小叶子的图标,可以看出用了Spring管理bean,后续再说;

public abstract class BaseWebService {
	private static final Logger log = Red5LoggerFactory.getLogger(BaseWebService.class, getWebAppRootKey());

	static IApplication getApp() {
		return (IApplication)Application.get(getWicketApplicationName());
	}

	static <T> T getBean(Class<T> clazz) {
		T b = null;
		try {
			b = getApp()._getOmBean(clazz);
		} catch (Exception e) {
			throw new ServiceException(e.getMessage());
		}
		if (b == null) {
			throw new ServiceException("");
		}
		return b;
	}

	static SessiondataDao getSessionDao() {
		return getBean(SessiondataDao.class);
	}

	// this one is fail safe
	static Sessiondata check(String sid) {
		try {
			return getSessionDao().check(sid);
		} catch (ServiceException e) {
			log.debug("Exception while checking sid", e);
		}
		return new Sessiondata();
	}

	static Set<Right> getRights(String sid) {
		Sessiondata sd = check(sid);
		return getRights(sd.getUserId());
	}

	static UserDao getUserDao() {
		return getBean(UserDao.class);
	}

	static RoomDao getRoomDao() {
		return getBean(RoomDao.class);
	}

	static FileItemDao getFileDao() {
		return getBean(FileItemDao.class);
	}

	// this one is fail safe
	static Set<Right> getRights(Long id) {
		try {
			return getUserDao().getRights(id);
		} catch (ServiceException e) {
			log.debug("Exception while getting rights", e);
		}
		return new HashSet<>();
	}

	static <T> T performCall(String sid, User.Right level, Function<Sessiondata, T> action) {
		return performCall(sid, sd -> AuthLevelUtil.check(getRights(sd.getUserId()), level), action);
	}

	static <T> T performCall(String sid, Predicate<Sessiondata> allowed, Function<Sessiondata, T> action) {
		try {
			Sessiondata sd = check(sid);
			if (allowed.test(sd)) {
				return action.apply(sd);
			} else {
				throw NO_PERMISSION;
			}
		} catch (ServiceException err) {
			throw err;
		} catch (Exception err) {
			log.error("[performCall]", err);
			throw new ServiceException(err.getMessage());
		}
	}
}

image-20211015201441465

BaseWebService的结构如上图所示;

不加修饰符的方法即为缺省default;

getApp方法用来得到一个IApplication类型得对象,IApplication是openmeetings-db下的一个接口;

getBean方法使用了泛型,避免了直接写死类型得死板,增加了灵活性;

getSessionDao调用getBean方法,传入SessiondataDao(db.dao包下的一个类)的class对象,返回一个SessiondataDao类型对象;

check方法顾名思义,检查一下传入的String类型得id是不是符合要求;

getRights方法同样接受一个sid参数,返回一个Right的集合,Right是db.entity.user下的一个实体类;同时下面有一个重名的方法但是参数不同,此方法内通过getuserid得到了long类型得id后,调用同为成员方法的另一个getRights,返回一个hashset;

getUserDao和getRoomDao、getFileDao方法就是获得呀一个Dao的对象;

performCall方法同样用参数列表区分不同的函数体,且使用了泛型,其中的一个参数Predicate是一个jdk8下的接口, 提供的为逻辑判断操作,即断言:静态方法isEqual:判断是否相等,并返回一个Predicate对象

​ 默认方法and,or,negate:分别代表逻辑判断与、或、非并都返回一个Predicate对象

​ 方法test:按照给定的Predicate条件进行逻辑判断。

​ Function也是一个函数式编程接口;它代表的含义是“函数”,而函数经常是有输入输出的,因此它含有一个apply方法,包含一个输入与一个输出

​ 方法根据参数sid,allowed,以及action判断符合条件后,放行,使用apply方法将参数传递,并返回;

同时我也想学习了一下java8的Function的函数式编程接口,函数式接口亦即接口内只有一个方法;下面贴上一段比较经典的代码:

/**
 * Function测试
 */
public static void functionTest() {
    Function<Integer, Integer> f = s -> s++;
    Function<Integer, Integer> g = s -> s * 2;

    /**
     * 下面表示在执行F时,先执行G,并且执行F时使用G的输出当作输入。
     * 相当于以下代码:
     * Integer a = g.apply(1);
     * System.out.println(f.apply(a));
     */
    System.out.println(f.compose(g).apply(1));

    /**
     * 表示执行F的Apply后使用其返回的值当作输入再执行G的Apply;
     * 相当于以下代码
     * Integer a = f.apply(1);
     * System.out.println(g.apply(a));
     */
    System.out.println(f.andThen(g).apply(1));

    /**
     * identity方法会返回一个不进行任何处理的Function,即输出与输入值相等; 
     */
    System.out.println(Function.identity().apply("a"));
}

至此,util即工具包下的BaseWebservice这个父类分析完成,下面只需要分析其子类,看每个子类根据自身的不同情况进行了怎么样的特化即可;

测试类的简略分析以及junit介绍

public class TestBaseService {
	private static void checkException(Runnable r) {
		try {
			r.run();
			fail("ServiceException expected");
		} catch (ServiceException e) {
			assertTrue("expected", true);
		}
	}

	@Test
	public void testGetBeanExc() {
		checkException(() -> BaseWebService.getBean(UserDao.class));
	}

	@Test
	public void testCheck() {
		Sessiondata sd = BaseWebService.check(null);
		assertNotNull("NOT null Sessiondata should be returned", sd);
		assertNull("UserId should be null", sd.getUserId());
	}

	private static void checkRights(Set<Right> rights) {
		assertNotNull("NOT null Rights should be returned", rights);
		assertTrue("Rights should be empty", rights.isEmpty());
	}

	@Test
	public void testGetRights1() {
		checkRights(BaseWebService.getRights(1L));
	}

	@Test
	public void testGetRights2() {
		checkRights(BaseWebService.getRights(""));
	}

	@Test
	public void testPerformCall() {
		checkException(() -> BaseWebService.performCall("", sd -> true
				, sd -> { throw new RuntimeException("test"); }));
	}
}

image-20211015210442410

可以看到,标记为测试的源文件夹,即test下的java文件夹是绿色的,此文件夹对于项目没有任何影响,对于项目的主要代码是透明的存在;idea在编译项目的时候,会将测试的文件夹下的代码忽略;

可以看到,此类里面的方法全部是test开头的,为了测试以上编写的各个类的功能是否正常,其中,@Test是junit的一个标识,导入junit之后,可以不需要写main方法,直接用@Test进行测试;

拓展

​ JUnit是一个Java语言的单元测试框架。它由Kent Beck和Erich Gamma建立,逐渐成为源于Kent Beck的sUnit的xUnit家族中最为成功的一个。 JUnit有它自己的JUnit扩展生态圈。多数Java的开发环境都已经集成了JUnit作为单元测试的工具。它包括以下特性:

1、用于测试期望结果的断言(Assertion)

2、用于共享共同测试数据的测试工具

3、用于方便的组织和运行测试的测试套件

4、图形和文本的测试运行器

以上,就是本周对于openmeetings的项目源代码的分析,下一周的任务是首先要把util包下的所有子类分析完,再根据情况分析其他文件,分析不是目的,最终还是为了学习,因此在分析代码时遇到的不会的知识是正常的,应该不惧挑战,积极通过网络寻找资源,学习巩固,将知识存储在自己大脑里在以后遇到类似问题就能更快的解决。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

HiddenWorld

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值