2021SC@SDUSC
上篇文章分析了main下的:ConnectionProperties类、NullStringer类、OMContextListener类、OmException类、Version类。接下来将继续分析main下的类,还剩下OmFileHelper类、OpenmeetingsVariables类、StoredFile类、XmlExport类,则openmeetings-util包分析完毕。
OmFileHelper类
public class OmFileHelper {
private static File omHome = null;
private static final String UPLOAD_DIR = "upload";
private static final String PUBLIC_DIR = "public";
private static final String CLIPARTS_DIR = "cliparts";
private static final String WEB_INF_DIR = "WEB-INF";
private static final String GROUP_LOGO_DIR = "grouplogo";
private static final String STREAMS_DIR = "streams";
private static final String EMOTIONS_DIR = "emoticons";
private static final String LANGUAGES_DIR = "languages";
private static final String CONF_DIR = "conf";
private static final String IMAGES_DIR = "images";
private static final String WML_DIR = "stored";
public static final String FILE_NAME_FMT = "%s.%s";
public static final String BACKUP_DIR = "backup";
public static final String IMPORT_DIR = "import";
public static final String PROFILES_DIR = "profiles";
public static final String SCREENSHARING_DIR = "screensharing";
public static final String CSS_DIR = "css";
public static final String CUSTOM_CSS = "custom.css";
public static final String FILES_DIR = "files";
public static final String HIBERNATE = "hibernate";
public static final String PERSISTENCE_NAME = "classes/META-INF/persistence.xml";
public static final String DB_PERSISTENCE_NAME = "classes/META-INF/%s_persistence.xml";
public static final String PROFILES_PREFIX = "profile_";
public static final String LANG_FILE_NAME = "languages.xml";
public static final String LIBRARY_FILE_NAME = "library.xml";
public static final String PROFILE_IMG_NAME = "profile.png";
public static final String PROFILE_FILE_NAME = "profile";
public static final String RECORDING_FILE_NAME = "flvRecording_";
public static final String THUMB_IMG_PREFIX = "_thumb_";
public static final String DOC_PAGE_PREFIX = "page";
public static final String TEST_SETUP_PREFIX = "TEST_SETUP_";
public static final String DASHBOARD_FILE = "dashboard.xml";
public static final String EXTENSION_WML = "wml";
public static final String EXTENSION_FLV = "flv";
public static final String EXTENSION_MP4 = "mp4";
public static final String EXTENSION_JPG = "jpg";
public static final String EXTENSION_PNG = "png";
public static final String EXTENSION_PDF = "pdf";
public static final String WB_VIDEO_FILE_PREFIX = "UPLOADFLV_";
public static final String MP4_MIME_TYPE = "video/" + EXTENSION_MP4;
public static final String JPG_MIME_TYPE = "image/jpeg";
public static final String PNG_MIME_TYPE = "image/png";
public static final String BCKP_ROOM_FILES = "roomFiles";
public static final String BCKP_RECORD_FILES = "recordingFiles";
//Sip related stuff
public static final Long SIP_USER_ID = -1L;
public static final String SIP_PICTURE_URI = "phone.png";
private OmFileHelper() {}
private static File getDir(File parent, String name) {
File f = new File(parent, name);
if (!f.exists()) {
f.mkdirs();
}
return f;
}
public static File getUserProfilePicture(Long userId, String uri) {
return getUserProfilePicture(userId, uri, getDefaultProfilePicture());
}
public static File getUserProfilePicture(Long userId, String uri, File def) {
File img = null;
if (SIP_USER_ID.equals(userId)) {
img = new File(getImagesDir(), SIP_PICTURE_URI);
} else if (userId != null) {
img = new File(getUploadProfilesUserDir(userId), uri == null ? "" : uri);
}
if (img == null || !img.exists() || img.isDirectory()) {
img = def;
}
return img;
}
public static File appendSuffix(File original, String suffix) {
File parent = original.getParentFile();
String name = original.getName();
String ext = "";
int idx = name.lastIndexOf('.');
if (idx > -1) {
name = name.substring(0, idx);
ext = name.substring(idx);
}
return new File(parent, name + suffix + ext);
}
public static File getNewFile(File dir, String name, String ext) throws IOException {
File f = new File(dir, getName(name, ext));
int recursiveNumber = 0;
while (f.exists()) {
f = new File(dir, name + "_" + (recursiveNumber++) + ext);
}
f.createNewFile();
return f;
}
public static File getNewDir(File dir, String name) throws IOException {
File f = new File(dir, name);
String baseName = f.getCanonicalPath();
int recursiveNumber = 0;
while (f.exists()) {
f = new File(baseName + "_" + (recursiveNumber++));
}
f.mkdir();
return f;
}
public static String getHumanSize(File dir) {
return getHumanSize(getSize(dir));
}
public static String getHumanSize(long size) {
if (size <= 0) {
return "0";
}
final String[] units = new String[] { "B", "KB", "MB", "GB", "TB" };
int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
return new DecimalFormat("#,##0.#").format(size / Math.pow(1024, digitGroups)) + " " + units[digitGroups];
}
public static long getSize(File dir) {
long size = 0;
if (dir.isFile()) {
size = dir.length();
} else {
for (File file : dir.listFiles()) {
if (file.isFile()) {
size += file.length();
} else {
size += getSize(file);
}
}
}
return size;
}
public static String getFileName(String name) {
int dotidx = name.lastIndexOf('.');
return dotidx < 0 ? "" : name.substring(0, dotidx);
}
public static String getFileExt(String name) {
int dotidx = name.lastIndexOf('.');
return dotidx < 0 ? "" : name.substring(dotidx + 1).toLowerCase(Locale.ROOT);
}
}
该类是一个文件工具类,这个类的变量需要指向openmeetings webapp目录,该类定义的静态不变字符串常量用来指向openmeetings-web文件下src/main/webapp文件下的各个子目录。每个字符串变量均用来代表一个文件目录或者一个文件。
该类下面的get方法均利用getDir()方法根据上面定义的对应的变量来获取文件目录或文件并返回该File对象,便没有展示在代码中,如:
public static File getUploadFilesDir() {
return getDir(getUploadDir(), FILES_DIR);
}
public static File getUploadProfilesDir() {
return getDir(getUploadDir(), PROFILES_DIR);
}
File appendSuffix()方法:为文件添加后缀,并返回。
File getNewFile()根据传入的参数:目录,文件名,文件后缀名(可没有该参数)来递归的创建一个新的文件或者目录并返回。
该类即是一个文件操作类,指向webapp下的目录并进行获取、创建操作,利用该类辅助其他文件类动态的对webapp下的文件进行操作和修改。
OpenmeetingsVariables类
public class OpenmeetingsVariables {
public static final String ATTR_CLASS = "class";
public static final String ATTR_TITLE = "title";
public static final String PARAM_USER_ID = "userId";
public static final String PARAM_STATUS = "status";
public static final String PARAM_SRC = "src";
public static final String PARAM__SRC = "_src";
public static final String CONFIG_CRYPT = "crypt.class.name";
public static final String CONFIG_DASHBOARD_SHOW_CHAT = "dashboard.show.chat";
public static final String CONFIG_DASHBOARD_SHOW_MYROOMS = "dashboard.show.myrooms";
public static final String CONFIG_DASHBOARD_SHOW_RSS = "dashboard.show.rssfeed";
public static final String CONFIG_DASHBOARD_RSS_FEED1 = "dashboard.rss.feed1";
public static final String CONFIG_DASHBOARD_RSS_FEED2 = "dashboard.rss.feed2";
public static final String CONFIG_DEFAULT_LANG = "default.lang.id";
public static final String CONFIG_DEFAULT_LANDING_ZONE = "default.landing.zone";
public static final String CONFIG_DEFAULT_LDAP_ID = "default.ldap.id";
public static final String CONFIG_DEFAULT_GROUP_ID = "default.group.id";
public static final String CONFIG_DEFAULT_TIMEZONE = "default.timezone";
public static final String CONFIG_REGISTER_FRONTEND = "allow.frontend.register";
public static final String CONFIG_REGISTER_SOAP = "allow.soap.register";
public static final String CONFIG_REGISTER_OAUTH = "allow.oauth.register";
public static final String CONFIG_MAX_UPLOAD_SIZE = "max.upload.size";
public static final String CONFIG_SIP_ENABLED = "sip.enable";
public static final String CONFIG_SIP_ROOM_PREFIX = "sip.room.prefix";
public static final String CONFIG_SIP_EXTEN_CONTEXT = "sip.exten.context";
public static final String CONFIG_LOGIN_MIN_LENGTH = "user.login.minimum.length";
public static final String CONFIG_PASS_MIN_LENGTH = "user.pass.minimum.length";
public static final String CONFIG_IGNORE_BAD_SSL = "oauth2.ignore.bad.ssl";
public static final String CONFIG_REDIRECT_URL_FOR_EXTERNAL = "redirect.url.for.external.users";
public static final String CONFIG_APPOINTMENT_REMINDER_MINUTES = "number.minutes.reminder.send";
public static final String CONFIG_APPLICATION_NAME = "application.name";
public static final String CONFIG_APPLICATION_BASE_URL = "application.base.url";
public static final String CONFIG_SCREENSHARING_QUALITY = "screensharing.default.quality";
public static final String CONFIG_SCREENSHARING_FPS = "screensharing.default.fps";
public static final String CONFIG_SCREENSHARING_FPS_SHOW = "screensharing.fps.show";
public static final String CONFIG_SCREENSHARING_ALLOW_REMOTE = "screensharing.allow.remote";
public static final String CONFIG_GOOGLE_ANALYTICS_CODE = "google.analytics.code";
public static final String CONFIG_SMTP_SERVER = "mail.smtp.server";
public static final String CONFIG_SMTP_PORT = "mail.smtp.port";
public static final String CONFIG_SMTP_USER = "mail.smtp.user";
public static final String CONFIG_SMTP_PASS = "mail.smtp.pass";
public static final String CONFIG_SMTP_SYSTEM_EMAIL = "mail.smtp.system.email";
public static final String CONFIG_SMTP_TLS = "mail.smtp.starttls.enable";
public static final String CONFIG_SMTP_TIMEOUT_CON = "mail.smtp.connection.timeout";
public static final String CONFIG_SMTP_TIMEOUT = "mail.smtp.timeout";
public static final String CONFIG_PATH_IMAGEMAGIC = "path.imagemagick";
public static final String CONFIG_PATH_SOX = "path.sox";
public static final String CONFIG_PATH_FFMPEG = "path.ffmpeg";
public static final String CONFIG_PATH_OFFICE = "path.office";
public static final String CONFIG_DOCUMENT_DPI = "document.dpi";
public static final String CONFIG_DOCUMENT_QUALITY = "document.quality";
public static final String CONFIG_FLASH_SECURE = "flash.secure";
public static final String CONFIG_FLASH_SECURE_PROXY = "flash.secure.proxy";
public static final String CONFIG_FLASH_VIDEO_CODEC = "flash.video.codec";
public static final String CONFIG_FLASH_VIDEO_FPS = "flash.video.fps";
public static final String CONFIG_FLASH_VIDEO_BANDWIDTH = "flash.video.bandwidth";
public static final String CONFIG_FLASH_CAM_QUALITY = "flash.cam.quality";
public static final String CONFIG_FLASH_MIC_RATE = "flash.mic.rate";
public static final String CONFIG_FLASH_ECHO_PATH = "flash.echoPath";
public static final String CONFIG_HEADER_XFRAME = "header.x.frame.options";
public static final String CONFIG_EXT_PROCESS_TTL = "external.process.ttl";
public static final String CONFIG_HEADER_CSP = "header.content.security.policy";
public static final String CONFIG_EMAIL_AT_REGISTER = "send.email.at.register";
public static final String CONFIG_EMAIL_VERIFICATION = "send.email.with.verfication";
public static final String CONFIG_CALENDAR_ROOM_CAPACITY = "calendar.conference.rooms.default.size";
public static final String CONFIG_REPLY_TO_ORGANIZER = "inviter.email.as.replyto";
public static final String CONFIG_KEYCODE_ARRANGE = "video.arrange.keycode";
public static final String CONFIG_KEYCODE_EXCLUSIVE = "exclusive.audio.keycode";
public static final String CONFIG_KEYCODE_MUTE = "mute.keycode";
public static final String CONFIG_MYROOMS_ENABLED = "personal.rooms.enabled";
public static final String CONFIG_REMINDER_MESSAGE = "reminder.message";
public static final String CONFIG_MP4_AUDIO_RATE = "mp4.audio.rate";
public static final String CONFIG_MP4_AUDIO_BITRATE = "mp4.audio.bitrate";
public static final String CONFIG_MP4_VIDEO_PRESET = "mp4.video.preset";
public static final String CONFIG_REST_ALLOW_ORIGIN = "rest.allow.origin";
public static final String CONFIG_FNAME_MIN_LENGTH = "user.fname.minimum.length";
public static final String CONFIG_LNAME_MIN_LENGTH = "user.lname.minimum.length";
public static final String CONFIG_CHAT_SEND_ON_ENTER = "chat.send.on.enter";
public static final String CONFIG_DISPLAY_NAME_EDITABLE = "display.name.editable";
public static final String HEADER_XFRAME_SAMEORIGIN = "SAMEORIGIN";
public static final String HEADER_CSP_SELF = "default-src 'self'; style-src 'self' 'unsafe-inline'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; img-src 'self' data:;";
public static final int RECENT_ROOMS_COUNT = 5;
public static final int USER_LOGIN_MINIMUM_LENGTH = 4;
public static final int USER_PASSWORD_MINIMUM_LENGTH = 8;
public static final String DEFAULT_APP_NAME = "OpenMeetings";
public static final String DEFAULT_CONTEXT_NAME = "openmeetings";
public static final long DEFAULT_MAX_UPLOAD_SIZE = 100 * 1024 * 1024L; // 100MB
public static final String FLASH_SECURE = "secure";
public static final String FLASH_NATIVE_SSL = "native";
public static final String FLASH_PORT = "rtmpPort";
public static final String FLASH_SSL_PORT = "rtmpsPort";
public static final String FLASH_VIDEO_CODEC = "videoCodec";
public static final String FLASH_FPS = "fps";
public static final String FLASH_BANDWIDTH = "bandwidth";
public static final String FLASH_QUALITY = "quality";
public static final String FLASH_ECHO_PATH = "echoPath";
public static final String FLASH_MIC_RATE = "micRate";
public static final int DEFAULT_MINUTES_REMINDER_SEND = 15;
public static final String DEFAULT_BASE_URL = "http://localhost:5080/openmeetings/";
public static final String DEFAULT_SIP_CONTEXT = "rooms";
private static String webAppRootKey = null;
private static String cryptClassName = null;
private static String wicketApplicationName = null;
private static String applicationName = null;
private static int extProcessTtl = 20;
private static int minLoginLength = USER_LOGIN_MINIMUM_LENGTH;
private static int minPasswdLength = USER_PASSWORD_MINIMUM_LENGTH;
private static JSONObject roomSettings = new JSONObject();
private static boolean initComplete = false;
private static long maxUploadSize = DEFAULT_MAX_UPLOAD_SIZE;
private static String baseUrl = DEFAULT_BASE_URL;
private static boolean sipEnabled = false;
private static String gaCode = null;
private static Long defaultLang = 1L;
private static Long defaultGroup = 1L;
private static int audioRate = 22050;
private static String audioBitrate = "32k";
private static String videoPreset = "medium";
private static String defaultTimezone = "Europe/Berlin";
private static String restAllowOrigin = null;
private static String sipContext = DEFAULT_SIP_CONTEXT;
private static int minFnameLength = USER_LOGIN_MINIMUM_LENGTH;
private static int minLnameLength = USER_LOGIN_MINIMUM_LENGTH;
private static boolean chatSendOnEnter = false;
private static boolean allowRegisterFrontend = false;
private static boolean allowRegisterSoap = false;
private static boolean allowRegisterOauth = false;
private static boolean sendVerificationEmail = false;
private static boolean sendRegisterEmail = false;
private static boolean displayNameEditable = false;
}
该类OpenmeetingsVariables定义了一系列openmeetings所需要的基本常变量,并为这些变量设置了get和set方法。如定义了屏幕共享默认的fps,SMTP的server,port,user,默认的app名字为OpenMeetings等等。大部分定义为public static可以直接供其它类来使用,private设置get和set方法来封装使用。
StoredFile类
public class StoredFile {
private static final Logger log = Red5LoggerFactory.getLogger(StoredFile.class, getWebAppRootKey());
private static final String MIME_AUDIO = "audio";
private static final String MIME_VIDEO = "video";
private static final String MIME_IMAGE = "image";
private static final String MIME_TEXT = "text";
private static final String MIME_APP = "application";
private static final Set<MediaType> CONVERT_TYPES = new HashSet<>(Arrays.asList(
application("x-tika-msoffice"), application("x-tika-ooxml"), application("msword")
, application("vnd.wordperfect"), application("rtf")));
private static final MediaType MIME_PNG = MediaType.parse(PNG_MIME_TYPE);
private static final Set<MediaType> PDF_TYPES = new HashSet<>(Arrays.asList(application("pdf"), application("postscript")));
private static final Set<MediaType> CHART_TYPES = new HashSet<>();
private static final Set<MediaType> AS_IS_TYPES = new HashSet<>(Arrays.asList(MIME_PNG));
private static final String ACCEPT_STRING;
private static TikaConfig tika;
static {
Set<MediaType> types = new LinkedHashSet<>();
types.addAll(CONVERT_TYPES);
types.addAll(PDF_TYPES);
//TODO Charts need to added
StringBuilder sb = new StringBuilder("audio/*,video/*,image/*,text/*");
sb.append(",application/vnd.oasis.opendocument.*");
sb.append(",application/vnd.sun.xml.*");
sb.append(",application/vnd.stardivision.*");
sb.append(",application/x-star*");
for (MediaType mt : types) {
sb.append(',').append(mt.toString());
}
ACCEPT_STRING = sb.toString();
try {
tika = new TikaConfig();
} catch (IOException | TikaException e) {
log.error("Unexpected exception while initializing TIKA", e);
throw new RuntimeException(e);
}
}
private String name;
private String ext;
private MediaType mime;
public StoredFile(String fullname, InputStream is) {
this(fullname, null, is);
}
public StoredFile(String name, String ext, InputStream is) {
init(name, ext, is);
}
public StoredFile(String fullname, File f) throws IOException {
this(fullname, null, f);
}
public StoredFile(String name, String ext, File f) throws IOException {
try (InputStream fis = new FileInputStream(f)) {
init(name, ext, fis);
}
}
private void init(String _name, String _ext, InputStream is) {
if (Strings.isEmpty(_ext)) {
int idx = _name.lastIndexOf('.');
name = idx < 0 ? _name : _name.substring(0, idx);
ext = getFileExt(_name);
} else {
name = _name;
ext = _ext.toLowerCase(Locale.ROOT);
}
Metadata md = new Metadata();
md.add(RESOURCE_NAME_KEY, String.format(FILE_NAME_FMT, name, ext));
try {
mime = tika.getDetector().detect(is == null ? null : TikaInputStream.get(is), md);
} catch (Throwable e) {
mime = null;
log.error("Unexpected exception while detecting mime type", e);
}
}
public static String getAcceptAttr() {
return ACCEPT_STRING;
}
public boolean isOffice() {
if (mime == null) {
return false;
}
return MIME_TEXT.equals(mime.getType())
|| (MIME_APP.equals(mime.getType()) &&
(mime.getSubtype().startsWith("vnd.oasis.opendocument")
|| mime.getSubtype().startsWith("vnd.sun.xml")
|| mime.getSubtype().startsWith("vnd.stardivision")
|| mime.getSubtype().startsWith("x-star")
|| mime.getSubtype().startsWith("vnd.ms-")
|| mime.getSubtype().startsWith("vnd.openxmlformats-officedocument")
))
|| CONVERT_TYPES.contains(mime);
}
}
该类StoredFile存储文件,定义了Logger日志类对象log来设置和打印日志,定义了openmeetings的文件类型“audio”、“video”、“image”、“text”、“application”、“pdf”等等,为白板演示操作做准备,初始化TIKA配置,获取和存储初始化,利用InputStream输入流将上传的文件存储至缓冲区域,检测时出现异常则用log报error错误打印出来“Unexpected exception while detecting mime type”。
XmlExport类
public class XmlExport {
public static final String FILE_COMMENT = ""
+ "\n"
+ " Licensed to the Apache Software Foundation (ASF) under one\n"
+ " or more contributor license agreements. See the NOTICE file\n"
+ " distributed with this work for additional information\n"
+ " regarding copyright ownership. The ASF licenses this file\n"
+ " to you under the Apache License, Version 2.0 (the\n"
+ " \"License\"); you may not use this file except in compliance\n"
+ " with the License. You may obtain a copy of the License at\n"
+ "\n"
+ " http://www.apache.org/licenses/LICENSE-2.0\n"
+ "\n"
+ " Unless required by applicable law or agreed to in writing,\n"
+ " software distributed under the License is distributed on an\n"
+ " \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n"
+ " KIND, either express or implied. See the License for the\n"
+ " specific language governing permissions and limitations\n"
+ " under the License.\n"
+ "\n"
+ "\n"
+ "###############################################\n"
+ "This File is auto-generated by the LanguageEditor\n"
+ "to add new Languages or modify/customize it use the LanguageEditor\n"
+ "see https://openmeetings.apache.org/LanguageEditor.html for Details\n"
+ "###############################################\n";
private XmlExport() {}
public static Document createDocument() {
Document document = DocumentHelper.createDocument();
document.setXMLEncoding(UTF_8.name());
document.addComment(XmlExport.FILE_COMMENT);
return document;
}
public static Element createRoot(Document document) {
document.addDocType("properties", null, "http://java.sun.com/dtd/properties.dtd");
return document.addElement("properties");
}
public static Element createRoot(Document document, String root) {
return document.addElement(root);
}
public static void toXml(Writer out, Document doc) throws Exception {
OutputFormat outformat = OutputFormat.createPrettyPrint();
outformat.setIndentSize(1);
outformat.setIndent("\t");
outformat.setEncoding(UTF_8.name());
XMLWriter writer = new XMLWriter(out, outformat);
writer.write(doc);
writer.flush();
out.flush();
out.close();
}
public static void toXml(File f, Document doc) throws Exception {
toXml(new FileOutputStream(f), doc);
}
public static void toXml(OutputStream out, Document doc) throws Exception {
toXml(new OutputStreamWriter(out, "UTF8"), doc);
}
}
该类XmlExport主要是用来将该类下定义的常量FILE_COMMENT字符串输出到每个文件的文件开始,如下图这样,为每一个文件设置版权信息和使用许可。
有关版权所有权的更多信息,请参阅随本作品发布的NOTICE文件。ASF在Apache许可证2.0版(“许可证”)下许可这个文件给你,除非符合许可证,否则你不能使用这个文件。
总结
openmeetings-util下所有类已经分析完毕。该util文件下面的类为openmeetings的工具类,提供了许多种如日期工具类CalendarHelper.java、进程工具栏ProcessHelper.java、om文件工具类OmFileHelper.java等等封装供其他文件使用。截至到该篇文章,我所负责的openmeetings-screenshare文件和openmeetings-util文件已全部分析完毕。分配的任务已完成。希望还有机会继续分析和使用openmeetings这个web应用。