引入:

比起创建Resource,发布过程要困难很多,我上周在support team时候曾经设想不通过调试器,光走读代码来明白其中的奥秘,后来因为堆栈太深而放弃了,现在有了调试器,终于把这些细节弄明白了,果然非常复杂。

细节分析:

在发布Resource时,它的入口是CmsPublishProject类的actionPublish()方法,发布过程复杂到变态,全包装在performDialogOperation()方法中:

/*** @seeorg.opencms.workplace.CmsMultiDialog#performDialogOperation()*/protected boolean performDialogOperation() throws CmsException {CmsPublishList publishList =getSettings().getPublishList();if (publishList == null){thrownew CmsException(Messages.get().container(org.opencms.db.Messages.ERR_GET_PUBLISH_LIST_PROJECT_1,getProjectname()));}OpenCms.getPublishManager().publishProject(getCms(),new CmsHtmlReport(getLocale(),getCms().getRequestContext().getSiteRoot()),publishList);// wait 2 seconds, may be it finishes fastOpenCms.getPublishManager().waitWhileRunning(1500);returntrue;
}

宏观上看,它先获得workplace中所有资源的发布列表,因为本例中只有一个资源,所以调试的列表如下:

[
publish of project:ae97ff1d-7824-11e4-8c0e-28e347ffa92b
publish history ID:f5d6e16a-787e-11e4-8289-28e347ffa92b
resources: [[org.opencms.file.CmsResource, path:/sites/default/charles_study/publish_test1, structure idea051006-787e-11e4-8289-28e347ffa92b, resource id:ea051007-787e-11e4-8289-28e347ffa92b, type id: 1, folder: false, flags: 0,project: ae97ff1d-7824-11e4-8c0e-28e347ffa92b, state: 2, date created: Sun Nov30 18:52:01 CST 2014, user created: c300ba5c-01e8-3727-b305-5dcc9ccae1ee, datelastmodified: Sun Nov 30 18:52:09 CST 2014, user lastmodified:c300ba5c-01e8-3727-b305-5dcc9ccae1ee, date released: Thu Jan 01 08:00:00 CST1970, date expired: Sun Aug 17 15:12:55 CST 292278994, date content: Sun Nov 3018:52:01 CST 2014, size: 0, sibling count: 1, version: 1]]
folders: []
deletedFolders: []
]

其次,它通过CmsPublishManager的publishProject()方法来做对于待发布列表的资源的发布工作。

CmsPublishManager会调用CmsSecurityManager的publishProject()方法,最终调用CmsDriverManager的publishObject()方法来做发布的全部工作。这就是我们要讨论的重点。

重点探讨1: 从CmsDriverManager的publishObject()方法来研究发布过程。

发布过程代码很多也很深,从宏观上看,它做了这么几件事情:

a. 检查父目录,这主要用于是否存在该资产的父目录还没被发布的情况。

b.发起一个CmsEvent类的发布前事件(beforePublishEvent),该事件中除包含上面的发布资源列表(publishList)外还包含projectId,dbContext和一个空的发布报告对象(CmsHtmlReport,用于存储发布失败的错误),该事件中的数据如下:

{publishList=
[
publish of project: ae97ff1d-7824-11e4-8c0e-28e347ffa92b
publish history ID: c0488fed-7882-11e4-8289-28e347ffa92b
resources:[[org.opencms.file.CmsResource,
path:/sites/default/charles_study/publish_test4, structure
idbb3dab29-7882-11e4-8289-28e347ffa92b, resource
id:bb3dab2a-7882-11e4-8289-28e347ffa92b, type id: 1, folder: false,
flags: 0,project: ae97ff1d-7824-11e4-8c0e-28e347ffa92b, state: 2, date
created: Sun Nov30 19:19:21 CST 2014, user created:
c300ba5c-01e8-3727-b305-5dcc9ccae1ee, datelastmodified: Sun Nov 30
19:19:24 CST 2014, user
lastmodified:c300ba5c-01e8-3727-b305-5dcc9ccae1ee, date released: Thu
Jan 01 08:00:00 CST1970, date expired: Sun Aug 17 15:12:55 CST
292278994, date content: Sun Nov 3019:19:21 CST 2014, size: 0, sibling
count: 1, version: 1]]
folders: []
deletedFolders: []
]
,dbContext=org.opencms.db.CmsDbContext@14b787a,report=org.opencms.report.CmsHtmlReport@1d2b627,projectId=ae97ff1d-7824-11e4-8c0e-28e347ffa92b}

然后用CmsEventManager的fireCmsEvent(beforePublishEvent)方法来执行这次发布事件。

因为一个资源的发布会影响到opencms的其他组件的更新,所以这里使用“Observer”设计模式,它吧多个cms的其他组件加到CmsEventManager的监听器列表中,监听器有几百个,我就不一一列出了。

c.用发布锁CmsLock锁住所有发布列表中的资源。

d.调用CmsPublishEngine的enqueuePublishJob()方法来记录下发布的计划任务,并产生具体的发布报告。具体来说:

它创建一个具体的CmsPublishJobInfoBean对象,它其中包含了发布所需的全部细节:

[org.opencms.publish.CmsPublishJobInfoBean, history id:c0488fed-7882-11e4-8289-28e347ffa92b, project idae97ff1d-7824-11e4-8c0e-28e347ffa92b, project name: Offline, user id:c300ba5c-01e8-3727-b305-5dcc9ccae1ee, locale: en, flags: 0, size: 1, enqueue time:0, start time: 0, finish time: 0]
  1. 调用CmsPublishQueue的add方法吧这个发布作业对象添加进去,它在其中会调用CmsDriverManager的createPublishJob()方法来创建具体的发布作业,最后会调用CmsProjectDriver类的createPublishJob()方法来做具体的数据库层面的操作。

其最后执行的SQL语句是:

    INSERT INTO CMS_PUBLISH_JOBS(HISTORY_ID,PROJECT_ID,PROJECT_NAME,USER_ID,PUBLISH_LOCALE,PUBLISH_FLAGS,RESOURCE_COUNT,ENQUEUE_TIME,START_TIME,FINISH_TIME,PUBLISH_LIST) VALUES ('6709c8a5-7887-11e4-8289-28e347ffa92b','ae97ff1d-7824-11e4-8c0e-28e347ffa92b','Offline','c300ba5c-01e8-3727-b305-5dcc9ccae1ee','en',0,1,1417348377907,0,0,x'ACED00057372001D6F72672E6F70656E636D732E64622E436D735075626C6973684C697374DC35DFB34A32E7310C0000787077486709C8A5788711E4828928E347FFA92BAE97FF1D782411E48C0E28E347FFA92B0000000000000001FFFFFFFF000000016244C681788711E4828928E347FFA92B000000000000000078')

所以从这里看出,它会更新CMS_PUBLISH_JOBS表,把发布的若干信息,比如发布历史ID,项目ID,名称,用户ID,发布国际化标示,入发布队列时间,发布开始时间,结束时间,以及发布的列表都插入数据库。

3.调用CmsPublishListenerCollection的fireEnqueued()方法来把这次发布事件通知所有的监听组件,如果发布过程失败,则从CmsPublishJob的publishReport中可以拿到发布错误信息。

e.调用checkCurrentPublishJobThread()方法来做具体的站点发布。因为这里是多线程操作而不是同步走下去的,所以开始几次调试每次都找不到执行点,后来研究了下,发现具体的站点发布代码放在CmsPublishThread的run()中,它最终会调用CmsProjectDriver类的publishProject()方法来执行具体的发布。

它首先调用CmsHistoryDriver的writeProject()方法把指定的Project写入CMS_HISTORY_PROJECTS和CMS_HISTORY_PROJECTRESOURCES表:

// write an entry in the publish project log
m_driverManager.getHistoryDriver(dbc).writeProject(dbc, publishTag, System.currentTimeMillis());

写入CMS_HISTORY_PROJECTS表的SQL语句如下:

NSERT INTO CMS_HISTORY_PROJECTS(PUBLISH_TAG,PROJECT_ID,PROJECT_NAME,PROJECT_PUBLISHDATE,PROJECT_PUBLISHED_BY,USER_ID,GROUP_ID,MANAGERGROUP_ID,PROJECT_DESCRIPTION,DATE_CREATED,PROJECT_TYPE,PROJECT_OU)VALUES(62,'ae97ff1d-7824-11e4-8c0e-28e347ffa92b','Offline',1417354083096,'c300ba5c-01e8-3727-b305-5dcc9ccae1ee','c300ba5c-01e8-3727-b305-5dcc9ccae1ee','6dfffebb-0985-3cbd-8d53-a5df8681a9f3','4d9b473f-3b73-34f7-b80c-15f068c3b2be','TheOffline Project',1417305967147,0,'/')

写入CMS_HISTORY_PROJECTRESOURCES表的SQL语句如下:

INSERT INTO CMS_HISTORY_PROJECTRESOURCES (PUBLISH_TAG,PROJECT_ID,RESOURCE_PATH)VALUES (62,'ae97ff1d-7824-11e4-8c0e-28e347ffa92b','/')

2.它会执行具体的内容变更,它会遍历发布列表publishList, 然后对其中的目录和文件分别发布,其中目录在先。对于目录的发布,它是调用以下代码来实现:

projectDriver.publishFolder(dbc,report,++publishedFolderCount,foldersSize,onlineProject,new CmsFolder(currentFolder),publishList.getPublishHistoryId(),
publishTag);

而对于文件的发布,它是调用以下代码来实现:

projectDriver.publishFile(dbc,report,++publishedFileCount,filesSize,onlineProject,currentResource,publishedContentIds,publishList.getPublishHistoryId(),
publishTag);

重点探讨2:发布文件的过程(其实发布目录差不多一样,只不过因为我用文件做例子,所以只能调试出文件的发布细节了)

总的来说,CmsProjectDriver类的publishFile()方法会调用CmsProjectDriver类的publishNewFile()方法,进而调用CmsProjectDriver类的publishFileContent()方法来执行具体发布的,具体步骤如下:

a. 从CMS_OFFLINE_CONTENTS表中获取给定ResourceID的内容。

byte[] offlineContent= m_driverManager.getVfsDriver(dbc).readContent(dbc,projectIdForReading,offlineResource.getResourceId());

它执行的SQL语句是:

SELECT CMS_OFFLINE_CONTENTS.FILE_CONTENT FROMCMS_OFFLINE_CONTENTS WHERECMS_OFFLINE_CONTENTS.RESOURCE_ID='d46e46f4-7893-11e4-8289-28e347ffa92b'

b.从上步骤的Resource构建offlineFile, 并且克隆到newFile中。

// create the file onlinenewFile = (CmsFile)offlineFile.clone();
newFile.setState(CmsResource.STATE_UNCHANGED);

c.创建cms的online resources和online structure 。通过以下代码:

// update the online/offlinestructure and resource records of the file
m_driverManager.getVfsDriver(dbc).publishResource(dbc, onlineProject, newFile, offlineFile)
其中更新CMS_ONLINE_RESOURCES的SQL语句如下:

    INSERT INTO CMS_ONLINE_RESOURCES(RESOURCE_ID,RESOURCE_TYPE,RESOURCE_FLAGS,DATE_CREATED,USER_CREATED,DATE_LASTMODIFIED,USER_LASTMODIFIED,RESOURCE_STATE,RESOURCE_SIZE,DATE_CONTENT,PROJECT_LASTMODIFIED,SIBLING_COUNT,RESOURCE_VERSION)VALUES('d46e46f4-7893-11e4-8289-28e347ffa92b',1,0,1417353704758,'c300ba5c-01e8-3727-b305-5dcc9ccae1ee',1417353704758,'c300ba5c-01e8-3727-b305-5dcc9ccae1ee',0,0,1417353704758,'ae97ff1d-7824-11e4-8c0e-28e347ffa92b',1,1)

更新CMS_ONLINE_STRUCTURE的SQL语句如下:

INSERT INTO CMS_ONLINE_STRUCTURE(STRUCTURE_ID,RESOURCE_ID,RESOURCE_PATH,STRUCTURE_STATE,DATE_RELEASED,DATE_EXPIRED,PARENT_ID,STRUCTURE_VERSION)VALUES ('d46e46f3-7893-11e4-8289-28e347ffa92b','d46e46f4-7893-11e4-8289-28e347ffa92b','/sites/default/charles_study/publish-test-11',0,0,9223372036854775807,'4bf8b750-785d-11e4-8289-28e347ffa92b',0)

d.接着上一步,更新cms的online resources和online structure的版本号。通过以下代码:

// update version numbersm_driverManager.getVfsDriver(dbc).publishVersions(dbc, offlineResource, !alreadyPublished);

其中更新CMS_ONLINE_RESOURCES的版本号的SQL语句如下:

UPDATE CMS_ONLINE_RESOURCES SET RESOURCE_VERSION = 1WHERE CMS_ONLINE_RESOURCES.RESOURCE_ID ='d46e46f4-7893-11e4-8289-28e347ffa92b'

更新CMS_ONLINE_STRUCTURE的SQL语句 如下:

UPDATE CMS_ONLINE_STRUCTURE SET STRUCTURE_VERSION = 0 WHERECMS_ONLINE_STRUCTURE.STRUCTURE_ID = 'd46e46f3-7893-11e4-8289-28e347ffa92b'

e.创建online文件的内容。通过以下代码:

// create/update the contentm_driverManager.getVfsDriver(dbc).createOnlineContent(dbc,offlineFile.getResourceId(),offlineFile.getContents(),publishTag,true,needToUpdateContent);

它执行的SQL语句如下:

INSERT INTO CMS_CONTENTS(RESOURCE_ID,FILE_CONTENT,PUBLISH_TAG_FROM,PUBLISH_TAG_TO,ONLINE_FLAG) VALUES('d46e46f4-7893-11e4-8289-28e347ffa92b',x'',62,62,1)

f.创建online文件的properties信息。通过以下代码:

m_driverManager.getVfsDriver(dbc).writePropertyObjects(dbc, onlineProject, newFile, offlineProperties);
它会把去写CMS_ONLINE_PROPERTIES文件,因为我的发布的文件没有配置properties,所以调试器跳过了这一段。

g.写入新的online访问控制列表。通过以下代码:

m_driverManager.getUserDriver(dbc).publishAccessControlEntries(dbc,dbc.currentProject(),onlineProject,offlineResource.getResourceId(),newFile.getResourceId());

它最终会去写CMS_ONLINE_ACCESSCONTROL。

最终,发布过程成功,前端会有一个模态对话框总结下这次发布:

wKioL1R7MsuzvdQlAACaoSaMPRs080.jpg

总结:

(1)发布过程宏观上分为发布作业的记录和实际站点发布工作。

(2)发布过程是以事件驱动的,其发布涉及到的信息资源记录在beforePublishEvent中。

(3)发布作业会维护一个作业队列,然后把发布事件添加到发布队列中。发布作业的执行会更新CMS_PUBLISH_JOBS表。

(4)发布作业的结果会通知所有监听器,这些监听器是opencms的自带组件。

(5)对于实际站点发布的工作,是另开了线程来完成的,其线程使用的执行体是CmsPublishThread类。

(6)发布线程会把当前Project信息写入CMS_HISTORY_PROJECTS和CMS_HISTORY_PROJECTRESOURCES表。

(7)具体目录和文件的发布工作,是通过发布线程遍历待发布列表来依次执行的,先执行目录发布工作,再执行文件发布工作。但两者类似。

(8)执行文件的发布会从CMS_OFFLINE_CONTENTS表中获取给定ResourceID的内容,构建offlineFile,并克隆到newFile中,然后依次创建CMS_ONLINE_RESOURCES,CMS_ONLINE_STRUCTURE文件,并更新其版本号。再在以下表(CMS_CONTENTS,CMS_ONLINE_PROPERTIES,CMS_ONLINE_ACCESSCONTROL)中分别创建新条目。

欢迎工作一到五年的Java工程师朋友们加入Java架构开发: 957734884,群内提供免费的Java架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm性能调优、Spring源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代!

opencms 发布过程深入研究相关推荐

  1. 我如何在JavaScript中建立良好的发布过程

    by Dafna Rosenblum 达夫娜·罗森布拉姆(Dafna Rosenblum) 我如何在JavaScript中建立良好的发布过程 (How I established a good rel ...

  2. 白宫计划2019年春季发布新版人工智能研究战略

    来源:人工智能和大数据 近日,据白宫科技政策办公室人工智能助理主任Lynne Parker表示,特朗普政府计划更新由奥巴马政府首次发布的人工智能研究与发展战略. 2016年美国国家人工智能研究与发展战 ...

  3. SQL Server 2012 复制(发布订阅的研究)

    原文:SQL Server 2012 复制(发布订阅的研究) 已实现发布订阅功能,可以实现局域网内双击备份. 一.注意事项: a) 使用[事务复制]功能 b) 必须是相同的SqlServer 帐号和密 ...

  4. typescript 博客_如何使用Typescript自动化博客发布过程

    typescript 博客 Since I'm trying to build a writing habit, well, I'm writing more and more. Even thoug ...

  5. 改进的有效边表算法_优硕微展 | 张和慧:基于邻域保持嵌入算法的间歇过程故障检测研究...

    基于邻域保持嵌入算法的 间歇过程故障检测研究 The Research on batch process fault detection based on Neighborhood Preservin ...

  6. 发布过程5分钟内load飙升问题排查

    这几天新项目每次发布,都发现load在jetty重启过程中突然load会从0.1突然升高到15以上,3分钟后慢慢降到正常非常,cpu使用率也升高了一些,但是jvm内存线程,gc都比较正常,所以怀疑应用 ...

  7. 金蝶 EAS WebService 发布过程

    金蝶 EAS WebService 发布过程 1. 打开BOS开发工具–>右上角切换:金蝶BOS设计开发工具 (1)左边目录右键新建 功能,点开 功能 方法列表点击 增加 方法: (2)右键 功 ...

  8. 目前超级计算机国内外发展状况,浅谈超级计算机发展的过程及研究现状

    浅谈超级计算机发展的过程及研究现状 来源:用户上传 作者: 中图分类号:TP393.01 文献标识码:A 当前,多核技术的不断发展和日渐成熟,使得处理器的性能得到巨大提升.但是对于存储设备来说,无论是 ...

  9. Unity 语音识别 详情版 和 发布过程中遇到的问题

    最近公司打算弄一个新的项目即unity的语音识别,上网搜索后发现讯飞sdk是现目前大多数常用的语音识别,而且识别效果佳 目前网上已有了讯飞+sdk的教程,所以要先谢谢两位大神: 海涛高软:博客地址ht ...

  10. asp.nett网站发布过程

    Asp.net网站发布过程如下: 第一.用VS2005开发的WEB程序也就是网站只要在VS2005里面运行正常就就可以发布到互联网上去了,没有必要将网站发布在本地的IIS中测试,因为只要在VS2005 ...

最新文章

  1. 车联网空间巨大 解决网络安全问题乃当务之急
  2. LeetCode Course Schedule(有向图中是否存在环)
  3. 201671010103 2016-2017-2 《Java程序设计》第十二周学习心得
  4. 1.2.4 Selecting a defualt database
  5. 评论:索尼爱立信能否重振雄风?
  6. PHP与JSP的比较
  7. 测试唯一ID支持多大的并发量
  8. http awstats安装
  9. 研究了一下WORD的斜体,角度约20度
  10. android+解锁工具,安卓手机解锁助手 (A Unlock Tool)
  11. 小学计算机课动画制作的评课稿,小学信息技术评课稿
  12. 深度学习----Tensorflow再命名实体上常用的函数
  13. Word TOC域的使用说明
  14. linux摄像头V4L2 subdev,V4L2 subdev
  15. SpringMVC 学谈 (第三章)
  16. 指数基金投资指南读书笔记
  17. python3使用staf问题_转载—越来越强大的SAFS/STAF/STAX自动化测试框架
  18. 第一、二章大数据与Hadoop的概述
  19. 棋盘覆盖问题——详解(C++)
  20. SSL/TLS Suffers ‘Bar Mitzvah Attack’漏洞检测方法及修复建议

热门文章

  1. ffplay 加载 srt、ass字幕、调整对比度、亮度和饱和度、倍数播放
  2. Android WebView性能分析与优化
  3. three.js 加载fbx文件并解析
  4. linux mysql导出表中的数据_MySQL导出指定表中的数据
  5. Linux如何快速生成大文件
  6. [Chrome插件] SelectJd(京东自营筛选器) v1.0.0 发布
  7. visio一分二连接线_Visio-换线流程(初稿)
  8. Visio 直角连接线增加直角拐弯的方法, 取消自动附着,取消自动捕捉
  9. 【yolov3详解】一文让你读懂yolov3目标检测原理
  10. cr2格式是什么意思?cr2格式用什么软件打开?cr2格式怎么转换成jpg