openmeetings-db中Java源码初步分析

2021SC@SDUSC

目录

文件结构

源码分析尝试

IWebSession.java

IApplication.java

db/util目录

RoomMessage.java

TextRoomMessage.java

总结


之前的文章已经说明,针对openmeetings-db模块,我们首先着重分析的源码是src/main/java目录下的文件,并且针对pom.xml进行了详细解析,因此本文开始就对该目录下的java代码进行探究。

文件结构

打开src/main/java/org/apache/openmeetings目录,展现的内容如下:

有IApplication.java和IWebSession.java两个java文件,还有db文件夹。根据字面意义,这两个java文件描述的功能应该分别是应用和网络会话,db文件夹包含了openmeetings-db模块的大部分核心代码。 

继续打开db目录,如下:

 可以看到db目录下包含了5个文件夹。同样,根据字面意思,dao指的是数据访问对象(Data Access Object),dto指的是数据传输对象(Data Transfer Object),entity指的是实体,manager指的是管理者,util指的是工具。

打开dao目录,如下:

 包含了两个java文件和若干文件夹。再依次打开dto、entity、manager、util目录,如下:

dto:

entity:

manager:

util:

可以看出,dao、dto、entity具有相似的目录结构,manager和util则具有较为区别的结构。 

源码分析尝试

说明了源码的具体结构之后,就可以正式开始对源码的分析了。

IWebSession.java

本着由易到难的原则,首先来分析src/main/java/org/apache/openmeetings目录下的IWebSession.java文件。

打开IDEA,其源码如下:

package org.apache.openmeetings;

import java.util.Locale;

public interface IWebSession {
	long getOmLanguage();
	void setLanguage(long languageId);
	Locale getLocale();
}

整个java文件的代码量比较小, 只声明了IWebSession接口。在接口中,提供了三个方法,等待实现这个接口的类去实现,分别是long getOmLanguage()、void setLanguage(long languageId)、Locale getLocale()。

三两个方法都比较容易理解,前两个分别是获取某个语言信息和根据语言的id设置语言,第三个方法则是获取类型为Locale的数据。这个类型在前面已经import了,因此进入查看Locale类的源码:

Locale类的源码量过大,因此只展示这一小部分。Locale类内部有静态Locale类型数据,如ENGLISH、FRENCH、GERMAN等,初步判断,Locale类与语言或者语言代表的地域有关。

进一步查阅资料得知,Locale类的作用是转换和划分地区的国际化类。Locale表示地区,每一个Locale对象都代表了一个特定的地理、政治和文化地区,在操作Date、Calendar等表示日期/时间的对象时经常会用到,因为在不同的区域里时间的表示方式不同。 (此处参考自文章https://m.jb51.net/article/85858.htm)对于Locale对象,提供了多种方法。例如,String getCountry()可以获得国家或地区的代码,String getLanguage()可以获得国家的语言等等。

弄清楚Locale的含义后,就可以解释在IWebSession.java中使用到它的理由。即,它可以确定用户所在的国家或地区及其信息。

IApplication.java

使用IDEA打开同样位于src/main/java/org/apache/openmeetings目录下的IApplication.java文件,其源码如下:

package org.apache.openmeetings;

import java.util.Locale;
import java.util.function.Supplier;

import javax.servlet.ServletContext;

import org.apache.openmeetings.db.dao.basic.ConfigurationDao;
import org.apache.openmeetings.db.entity.room.Invitation;
import org.apache.openmeetings.util.ws.IClusterWsMessage;
import org.apache.wicket.request.IExceptionMapper;
import org.apache.wicket.request.IRequestMapper;
import org.apache.wicket.request.mapper.parameter.PageParameters;

public interface IApplication {
	<T> T getOmBean(Class<T> clazz);
	<T> T _getOmBean(Class<T> clazz);
	ServletContext getServletContext();
	IRequestMapper getRootRequestMapper();
	Supplier<IExceptionMapper> getExceptionMapperProvider();
	String getOmString(String key);
	String getOmString(String key, long languageId);
	String getOmString(String key, final Locale loc, String... params);
	String getOmContactsLink();
	String getOmInvitationLink(Invitation i);
	String urlForActivatePage(PageParameters pp);
	void setXFrameOptions(String xFrameOptions);
	void setContentSecurityPolicy(String contentSecurityPolicy);

	String getServerId();

	//JPA
	void updateJpaAddresses(ConfigurationDao dao);

	//WS
	void publishWsTopic(IClusterWsMessage msg);
}

与IWebSession一样,它声明了一个接口。但显然,它import了db/dao目录和db/entity目录下的类。如果不阐明它们的作用,也无法说明IApplication接口的作用。因此此处不得不暂停,先完成分析dao目录和entity目录下的源码,最后回过头来看IApplication.java。但经过观察又发现,db/util目录下的类作为工具常被引用,因此似乎先分析db/util是个更好的选择。

db/util目录

前文提到,util应该是作为工具存在的,其结构如下:

在db/util目录下,存在许多“Helper”、“Util”等java文件。打开ws文件夹,可以看到:

ws文件夹下存在两个java文件,分别是RoomMessage.java和TextRoomMessage.java,现在从它们两个入手开始展开分析。

RoomMessage.java

顾名思义,RoomMessage.java的字面意义是房间信息。我想,在类里面保存的应该正式房间的主要信息。其源码如下:

package org.apache.openmeetings.db.util.ws;

import static org.apache.openmeetings.db.dao.room.SipDao.SIP_FIRST_NAME;
import static org.apache.openmeetings.util.OmFileHelper.SIP_USER_ID;

import java.util.Date;
import java.util.UUID;

import org.apache.openmeetings.db.entity.basic.IClient;
import org.apache.openmeetings.db.entity.user.User;
import org.apache.wicket.protocol.ws.api.message.IWebSocketPushMessage;

public class RoomMessage implements IWebSocketPushMessage {
	private static final long serialVersionUID = 1L;
	public enum Type {
		roomEnter
		, roomExit
		, roomClosed
		, pollCreated
		, pollUpdated
		, recordingStarted
		, recordingStoped
		, sharingStarted
		, sharingStoped
		, rightUpdated
		, activityRemove
		, requestRightModerator
		, requestRightPresenter
		, requestRightWb
		, requestRightShare
		, requestRightRemote
		, requestRightA
		, requestRightAv
		, requestRightExclusive
		, haveQuestion
		, kick
		, newStream
		, closeStream
		, mute
		, exclusive
		, quickPollUpdated
	}
	private final Date timestamp;
	private final String uid;
	private final Long roomId;
	private final Long userId;
	private final String name;
	private final Type type;

	public RoomMessage(Long roomId, IClient c, Type type) {
		this(roomId, c.getUserId(), c.getFirstname(), c.getLastname(), type);
	}

	public RoomMessage(Long roomId, User u, Type type) {
		this(roomId, u.getId(), u.getFirstname(), u.getLastname(), type);
	}

	private RoomMessage(Long roomId, Long userId, String firstName, String lastName, Type type) {
		this.timestamp = new Date();
		this.roomId = roomId;
		if (SIP_USER_ID.equals(userId)) {
			this.name = SIP_FIRST_NAME;
		} else {
			name = String.format("%s %s", firstName, lastName);
		}
		this.userId = userId;
		this.type = type;
		this.uid = UUID.randomUUID().toString();
	}

	public Date getTimestamp() {
		return timestamp;
	}

	public Long getRoomId() {
		return roomId;
	}

	public Long getUserId() {
		return userId;
	}

	public String getName() {
		return name;
	}

	public Type getType() {
		return type;
	}

	public String getUid() {
		return uid;
	}
}

前面import的类中也包含了dao目录和entity目录下的类,先不去处理它们,观察RoomMessage类的结构。

首先,RoomMessage类实现了IWebSocketPushMessage接口,所以先查看这个接口的信息:

package org.apache.wicket.protocol.ws.api.message;

public interface IWebSocketPushMessage extends IWebSocketMessage {
}

IWebSocketPushMessage接口继承自IWebSocketMessage接口,再如此查看它的信息,发现IWebSocketMessage接口继承自IClusterable接口,IClusterable接口继承自Serializable接口。在继承的过程中,每个接口没有提供方法,可以粗略认为IWebSocketPushMessage继承自Serializable接口。也就是说,RoomMessage实现了Serializable接口。

Serializable接口的源码如下:

package java.io;


public interface Serializable {
}

查阅资料(参考自Java Serializable 接口 - 费强胜 - 博客园) 得知,Serializable是java.io包中定义的、用于实现java类的序列化操作而提供的语义级别的接口。Serializable序列化接口没有任何方法或者字段,只是用于标识可序列化的语义。实现了Serializable接口的类可以被ObjectOutputStream转换为字节流,同时也可以通过ObjectInputStream再将其解析为对象。例如,我们可以将序列化对象写入文件后,再次从文件中读取它并反序列化成对象。简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。

既然RoomMessage类实现了Serializable接口,那么它的状态自然可以被保存到内存某处,然后在适当时机重新获取。

接下来看到,RoomMessage类包含的第一个字段是private static final long serialVersionUID = 1L。private意味着它是私有数据,static意味着它是静态数据,final意味着它是不可再次被修改的,类型为long。serialVersionUID的意思应该是序列版本号,它应该是作为一个固定的版本号存在,具体应用还需要在实例中体现。

然后,是一个枚举enum类型,其组成如下:

public enum Type {
		roomEnter
		, roomExit
		, roomClosed
		, pollCreated
		, pollUpdated
		, recordingStarted
		, recordingStoped
		, sharingStarted
		, sharingStoped
		, rightUpdated
		, activityRemove
		, requestRightModerator
		, requestRightPresenter
		, requestRightWb
		, requestRightShare
		, requestRightRemote
		, requestRightA
		, requestRightAv
		, requestRightExclusive
		, haveQuestion
		, kick
		, newStream
		, closeStream
		, mute
		, exclusive
		, quickPollUpdated
	}

根据枚举的定义,它表示的是一组常量。个人理解,它起到了类似class的作用,可以声明一个类型(在这里就声明了Type类型),声明的类型可以去定义对象执行某些操作。因此,在这里的Type,表示的是房间的某种状态或类型,这可以根据它包含的常量名称(如roomEnter等)确认。

再往下,就是一些私有的final变量,但尚未赋值,包含timestamp(时间戳)、uid(识别码)、roomId、userId、name,以及Type类型的type:

    private final Date timestamp;
	private final String uid;
	private final Long roomId;
	private final Long userId;
	private final String name;
	private final Type type;

这些字段应该是在房间创建时根据构造器确定的,且确定后便不能更改,因此这里还没有赋值。

然后便出现了RoomMessage类的几种构造器了:

	public RoomMessage(Long roomId, IClient c, Type type) {
		this(roomId, c.getUserId(), c.getFirstname(), c.getLastname(), type);
	}

	public RoomMessage(Long roomId, User u, Type type) {
		this(roomId, u.getId(), u.getFirstname(), u.getLastname(), type);
	}

	private RoomMessage(Long roomId, Long userId, String firstName, String lastName, Type type) {
		this.timestamp = new Date();
		this.roomId = roomId;
		if (SIP_USER_ID.equals(userId)) {
			this.name = SIP_FIRST_NAME;
		} else {
			name = String.format("%s %s", firstName, lastName);
		}
		this.userId = userId;
		this.type = type;
		this.uid = UUID.randomUUID().toString();
	}

共有三个构造器,前两个是public的,供其他代码调用,而第三个是private的,在前两个构造器中调用。

首先看第三个构造器。传入的参数比较多,包括了roomId、userId、firstName、lastName、type,分别给对应字段赋值,timestamp赋值为实时生成的Date对象,uid由UUID类调用randomUUID方法随机生成。其中,在给name赋值时,对SIP_USER_ID与传入的userId进行了比对,但此时还不清楚SIP_USER_ID的具体作用,所以暂时留个坑以后来填。


这里需要插一些关于UUID的内容,参考自百度百科。

UUID是通用唯一识别码,其目的是让分布式系统中的所有元素,都能有唯一的辨识信息,而不需要通过中央控制端来做辨识信息的指定。如此一来,每个人都可以创建不与他人冲突的UUID。UUID类中的randomUUID方法,可以随机获取一个UUID,重复的概率极小。

所以,在RoomMessage中加入uid字段的目的是,使每个房间都由唯一的UUID来标识。


前两个构造器的参数有些差别,除了传入roomId和type外,第一个构造器传入的是IClient对象,第二个传入的是User对象,并通过它们获取用户的name。同样,它们是来自entity目录下的类,也暂时留个坑。

余下的部分就是普通的get方法了,没有什么好说的。至此,RoomMessage类的源码分析完毕。

TextRoomMessage.java

由于代码量不多,先贴上源码:

package org.apache.openmeetings.db.util.ws;

import org.apache.openmeetings.db.entity.basic.IClient;
import org.apache.openmeetings.db.entity.user.User;

public class TextRoomMessage extends RoomMessage {
	private static final long serialVersionUID = 1L;
	private final String text;

	public TextRoomMessage(Long roomId, IClient client, Type type, String text) {
		super(roomId, client, type);
		this.text = text;
	}

	public TextRoomMessage(Long roomId, User u, Type type, String text) {
		super(roomId, u, type);
		this.text = text;
	}

	public String getText() {
		return text;
	}
}

可以清晰地看出,TextRoomMessage类是RoomMessage类的子类!!!这意味着,它只是对RoomMessage进行了一定程度上的扩展。果然,它只是增加了一个text字段,其余与RoomMessage相同。对于增加这个text的作用,初步猜测是对房间进行某些文字描述。

至此,TextRoomMessage.java分析完毕。

总结

本文对openmeetings-db模块中src/main/java/org/apache/openmeetings目录下的java文件做了结构梳理,并以IWebSession.java为开端,展开对源码的分析,已经完成了IWebSession.java以及util/ws目录下文件的分析。接下来,将尽量迅速地完成util目录的分析,然后选择其他目录继续依次探究源码。

在功能上,视频会议具有如下特点 1、该方基于P2P技术,服务器压力小、流畅。用户之间可以互相获取数据,减轻对服务器的压力。(这个没查到资料,有待确认) 2、视频和音频即时交流,可以看到与会人员的视频图像,听到实时声音。 3、IM文字聊天功能,支持文字和表情的即时文字聊天功能。 4、白板功能,与会人员可以进行画图、写字、贴图等操作,实现同一个白板的共享。同时也支持导入ppt和word等文件,更方便您的演示。同时可以开启多个白板,使用Tab方式切换。 5、桌面共享,与会人员可以看到共享者的电脑的当前画面(可以指定任意大区域被对方看到,比如只允许对方看到右下角的一部分等),便于高级功能的演示。 6、强大的文件导入功能,支持.ppt/.doc/.txt/.rtf等文件的导入,支持.gif/.jpg/.png/.bmp等多种格式图片的导入。导入后的文件可以直接在白板上看到。 7、支持多对多模式(会议模式,多个人有视频摄像头),也支持1对多模式(1个老师,对多个学生的讲课) 8、权限控制,可以进行权限控制,控制与会者的范围,召开私有会议(只有授权者可见的会议)等。 9、多国语言支持,支持英文、简体文、繁体文等多国语言界面。 10、投票交流支持,支持投票系统。 11、录像功能,可以将会议过程录制下来。 12、可提供全部源代码、易用的安装包、文档和技术支持。 13、可提供二次开发SDK包,方便客户的二次开发,标准DLL和COM接口,可以在任意语言调用。 14、高效的压缩技术:带宽占用极低,视频+远程桌面和白板等,只需要10几k的带宽,几乎只要能上网就能使用点量视频会议系统。 视频会议系统,提供系统内的全部源码,方便由开发人员进行二次开发和改动。 100M 局域网内可以支持上万人同时观看。单台4G的双核服务器最高可支持1万人同时在线; 普通3M ADSL可同时支持12-18路左右视频 ,语音大概90-150之间。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值