2021SC@SDUSC
上篇文章主要对模块openmeetins-util下src/main中的crypt文件里面的六个类进行了分析,文件的主要功能即实现对字符串的哈希编码形成哈希字符串返回,并用来实现加密功能。接下来将继续分析util文件下的其他类。该篇文章将分析src/main下的mail文件夹下的类。
目录
mail文件夹
首先看mail文件下的类:
总共只有三个类,分别是ByteArrayDataSourse、IcalHandler、MailUtil类来实现创建数据源、对会议日历的处理、以及判断地址是否有效。
ByteArrayDataSourse类
public class ByteArrayDataSource implements DataSource {
private byte[] data; // data
private String type; // content-type
public ByteArrayDataSource(InputStream is, String type) {
this.type = type;
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
int ch;
while ((ch = is.read()) != -1) {
os.write(ch);
}
data = os.toByteArray();
} catch (IOException ioex) {
//no-op
}
}
public ByteArrayDataSource(byte[] data, String type) {
this.data = data;
this.type = type;
}
public ByteArrayDataSource(String data, String type) {
this.data = data.getBytes(UTF_8);
this.type = type;
}
@Override
public InputStream getInputStream() throws IOException {
if (data == null)
throw new IOException("no data");
return new ByteArrayInputStream(data);
}
@Override
public OutputStream getOutputStream() throws IOException {
throw new IOException("cannot do this");
}
@Override
public String getContentType() {
return type;
}
@Override
public String getName() {
return "dummy";
}
}
这个类ByteArrayDataSourse实现了DataSourse接口,并实现了它的方法。
DataSourse这是一个工厂对象,用于提供到此 DataSource 对象所表示的物理数据源的连接。作为 DriverManager 工具的替代项,DataSource 对象是获取连接的首选方法。
实现 DataSource 接口的对象通常在基于 JavaTM Naming and Directory Interface (JNDI) API 的命名服务中注册。
使用Spring Boot时,默认情况下,配置DataSource非常容易。Spring Boot会自动为我们配置好一个DataSource。如果在application.yml中指定了spring.datasource的相关配置,Spring Boot就会使用该配置创建一个DataSource。如果在application.yml中没有指定任何spring.datasource的相关配置,Spring Boot会在classpath中搜索H2、hsqldb等内存数据库的jar包,如果找到了,就会自动配置一个内存数据库的DataSource,所以,我们只要引入jar包即可。
该类里面定义了一个byte类型的数组data,以及String类型的type,分别表示数据和内容类型。首先是第一个方法是其带参数的构造方法,接收的参数为InputStream类对象is和String类型变量type,是从输入流创建数据源。第二个构造方法是接收一个byte数组类型对象data和String类型变量type,是从字节数组创建数据源。第三个构造方法是接收一个String类型变量data和String类型变量type,是从一个字符串创建一个数据源。然后实现了上述接口类DataSource里的四个get方法,不需要分析。
IcalHandler类
public class IcalHandler {
private static final Logger log = Red5LoggerFactory.getLogger(IcalHandler.class, getWebAppRootKey());
static {
System.setProperty("net.fortuna.ical4j.timezone.update.enabled", "false");
System.setProperty("net.fortuna.ical4j.timezone.cache.impl", "net.fortuna.ical4j.util.MapTimeZoneCache");
}
/** ICal instance */
private final Calendar icsCalendar;
/** Creation of a new Event */
public static final Method ICAL_METHOD_REQUEST = Method.REQUEST;
public static final Method ICAL_METHOD_CANCEL = Method.CANCEL;
public static final Method ICAL_METHOD_REFRESH = Method.REFRESH;
public IcalHandler(Method method) {
log.debug("Icalhandler method type : " + method);
icsCalendar = new Calendar();
icsCalendar.getProperties().add(new ProdId("-//Events Calendar//iCal4j 1.0//EN"));
icsCalendar.getProperties().add(Version.VERSION_2_0);
icsCalendar.getProperties().add(CalScale.GREGORIAN);
icsCalendar.getProperties().add(method);
}
// ---------------------------------------------------------------------------------------
public String addNewMeeting(Date startDate, Date endDate, String name,
List<Map<String, String>> attendees, String description,
Map<String, String> organizer, String uid, String javaTzId)
{
TimeZoneRegistry registry = TimeZoneRegistryFactory.getInstance().createRegistry();
TimeZone timeZone = registry.getTimeZone(javaTzId);
if (timeZone == null) {
throw new NoSuchElementException("Unable to get time zone by id provided: " + javaTzId);
}
DateTime start = new DateTime(startDate);
start.setTimeZone(timeZone);
DateTime end = new DateTime(endDate);
end.setTimeZone(timeZone);
VEvent meeting = new VEvent(start, end, name);
meeting.getProperties().add(new Description(description));
meeting.getProperties().add(new Sequence(0));
meeting.getProperties().add(new Location(""));
meeting.getProperties().add(Transp.OPAQUE);
// generate unique identifier (if not submitted)
Uid ui;
if (Strings.isEmpty(uid)) {
ui = new Uid(UUID.randomUUID().toString());
log.debug("Generating Meeting UID : " + ui.getValue());
} else {
ui = new Uid(uid);
log.debug("Using Meeting UID : " + ui.getValue());
}
meeting.getProperties().add(ui);
for (Map<String, String> att : attendees) {
Attendee uno = new Attendee(URI.create(att.get("uri")));
String chair = att.get("chair");
uno.getParameters().add("0".equals(chair) ? Role.REQ_PARTICIPANT : Role.CHAIR);
uno.getParameters().add(new Cn(att.get("cn")));
meeting.getProperties().add(uno);
}
Organizer orger = new Organizer(URI.create(organizer.get("uri")));
orger.getParameters().add(new Cn(organizer.get("cn")));
meeting.getProperties().add(orger);
icsCalendar.getComponents().add(timeZone.getVTimeZone());
icsCalendar.getComponents().add(meeting);
return ui.getValue();
}
public Map<String, String> getAttendeeData(String emailAdress, String displayName, boolean chair) {
Map<String, String> oneRecord = new HashMap<>();
oneRecord.put("uri", "mailto:" + emailAdress);
oneRecord.put("cn", displayName);
oneRecord.put("chair", chair ? "1" : "0");
return oneRecord;
}
public void writeDataToFile(String _filerPath) throws Exception {
String filerPath = _filerPath.endsWith(".ics") ? _filerPath
: String.format("%s.ics", _filerPath);
try (FileOutputStream fout = new FileOutputStream(filerPath)) {
CalendarOutputter outputter = new CalendarOutputter();
outputter.output(icsCalendar, fout);
}
}
public byte[] getIcalAsByteArray() throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
CalendarOutputter outputter = new CalendarOutputter();
outputter.output(icsCalendar, bout);
return bout.toByteArray();
}
public String getICalDataAsString() {
return icsCalendar.toString();
}
}
类IcalHandler首先利用Red5LoggerFactory工厂类创建一个Logger日志类对象log,方便打印日志,利于测试过程中的调试。IcalHandler是对日历和会议进行处理的一个类,Ical是指互联网日历。定义了一个常量Calendar类对象 icsCalendar 实例,创建几个新的事件,包括ICAL_METHOD_REQUEST、ICAL_METHOD_CANCEL、ICAL_METHOD_REFRESH,主要用于在程序运行状态中,动态地获取方法信息。
构造函数接收Method类对象参数,将该参数记录在日志里面,然后初始化icsCalendar对象,调用getProperties()为它设置属性,例如版本信息,id,规模和method。
然后addNewMeeting()方法接收几个参数,startDate和endDate为使用标准时区,name为会议名字,attendees为参与会议的人列表,description为对这个会议的描述,oganizer为会议组织者,uid为会议号(传入的时候可能为空),javaTzId是所有者的java时区ID,返回是是该会议的id号。该方法即是添加一个会议,设置会议的一些属性。
然后getAttendeeData()方法:使用此函数为添加会议生成与会者建立一个有效的记录。接收的参数,emailAdress是参会者的地址,displayName为参会者的名字,chair是当前组织者。返回的为一个记录Map。
然后writeDataToFile()方法:将iCal写入文件,参数_filerPath是“*.ics”文件的路径,该方法会抛出异常以防在写入文件时发生错误。
接下来的getIcalAsByteArray()方法:获取IcalBody作为ByteArray,返回以字节格式显示的ICS日历,该方法会抛出异常以防在写入字节数组时发生错误。
最后的getICalDataAsString():以字符串形式检索数据,返回类变量icsCalendar的字符串形式。
MailUtil类
public class MailUtil {
private MailUtil() {}
public static boolean isValid(String email) {
if (Strings.isEmpty(email)) {
return false;
}
Validatable<String> eml = new Validatable<>(email);
RfcCompliantEmailAddressValidator.getInstance().validate(eml);
return eml.isValid();
}
}
类MailUtil里面只有一个方法即isValid(String email),即判断传入的参数email是否有效。
如果为空则为无效,导入import org.apache.wicket.validation.Validatable;依赖,利用validate()方法进行数据校验。 RfcCompliantEmailAddressValidator是一个测试套件,This test suite comes from Dominic Sayers and is a mix of RFC examples and examples from other validators.
The test suite is currently allowing addresses that are unroutable on the public Internet, such as first.last@example.123. This behavior is disabled by default, but can be switched on; the tests are run in both modes for comparison.(这个测试套件来自Dominic Sayers,它混合了RFC示例和来自其他验证器的示例。测试套件目前允许在公共互联网上不可路由的地址,例如first.last@example.123。这种行为在默认情况下是禁用的,但可以打开;测试在两种模式下运行,以便进行比较。)
总结
本文对src/main/mail文件下的三个类进行了分析。之后将继续对main文件下的类和代码进行分析。下一篇文章将对src/main/process下的类进行分析。