opencms创建资源深度分析

引入:

在opencms中,有些资源是刚创建的,有些资源是创建并发布的,这些资源创建时候做了哪些工作呢,他们的存储又如何呢,这是这篇文章需要解决的话题。

分析:

以最简单的文本文件为例,当我们在某目录下(比如叫 /charlesstudy)用向导创建某文本文件时,如下:

它发送的请求为 POST http://localhost:8080/opencms/opencms/system/workplace/commons/newresource.jsp

服务器端的响应入口是在CmsNewResource的actionDialog()方法内的case ACTION_SUBMITFORM分支:

public void actionDialog() throwsJspException, ServletException, IOException {
 
        super.actionDialog();
 
        switch (getAction()) {
            caseACTION_SUBMITFORM:
                actionCreateResource();
                if (isResourceCreated()) {
                    actionEditProperties();// redirects only if the edit propertiesoption was checked
                }
                break;
…

在actionCreateResource()方法中:

publicvoidactionCreateResource() throws JspException {
 
        try {
            // calculate the new resource Title property value
            String title = computeNewTitleProperty();
 
            // create the full resource name
            String fullResourceName =computeFullResourceName();
 
            // create the Title and Navigation properties if configured
            I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(getParamNewResourceType());
            List<CmsProperty> properties = createResourceProperties(fullResourceName, resType.getTypeName(), title);
 
            // create the resource            
            getCms().createResource(fullResourceName, resType.getTypeId(), null, properties);
            setParamResource(fullResourceName);
 
            setResourceCreated(true);
        } catch (Throwable e) {
 
            // error creating file, show error dialog
            includeErrorpage(this, e);
        }

我们可以看到,宏观上,它先获取资源标题(title),资源的全路径(fullResourceName),资源类型(plain,其type=1)和配置的额外属性(properties),如下:

然后调用getCms().createResource(fullResourceName,resType.getTypeId(),null,properties)来做创建工作,它会委托A_CmsResourceType类的createResource()来做资源创建,在其中它又会去委托CmsSecurityManager的createResource()方法对需要创建的资源做存在性校验,最终会调用CmsDriverManager的createResource()方法来做实际的资源创建工作,此方法如下:

public CmsResource createResource(
        CmsDbContext dbc,
        String resourcename,
        inttype,
        byte[] content,
        List<CmsProperty> properties) throws CmsException,CmsIllegalArgumentException {
 
        String targetName = resourcename;
 
        if (content == null){
            // name based resource creation MUST have a content
            content = newbyte[0];
        }
        intsize;
 
        if (CmsFolder.isFolderType(type)) {
            // must cut of trailing ‘/‘ for folder creation
            if (CmsResource.isFolder(targetName)) {
                targetName = targetName.substring(0, targetName.length() - 1);
            }
            size = -1;
        } else {
            size = content.length;
        }
 
        // create a new resource
        CmsResource newResource = new CmsResource(CmsUUID.getNullUUID(), // uuids will be "corrected" later
            CmsUUID.getNullUUID(),
            targetName,
            type,
            CmsFolder.isFolderType(type),
            0,
            dbc.currentProject().getUuid(),
            CmsResource.STATE_NEW,
            0,
            dbc.currentUser().getId(),
            0,
            dbc.currentUser().getId(),
            CmsResource.DATE_RELEASED_DEFAULT,
            CmsResource.DATE_EXPIRED_DEFAULT,
            1,
            size,
            0, // version number does not matter since it will be computed later
            0); // content time will be corrected later
 
        return createResource(dbc, targetName, newResource, content, properties, false);
   }

此方法从宏观上分为2部分,一是原型阶段(代码中标记为 //create a new resource的部分),二是实际创建阶段(它会调用重载的createResource()方法来创建真实的资源并写数据库),我们对其做详细分析。

讨论点1:资源创建的原型阶段:

它会仅仅会填入从actionCreateResource中带入的一般信息,比如project UUID,type,path等,然后其他信息全赋空值,这一步创建的Resource我们称为资源的原型,它创建完只“活”在计算机的内存中,并不做持久化,它的信息如下:

[org.opencms.file.CmsResource, path: /sites/default/charles_study/text-text-file-5,structure id 00000000-0000-0000-0000-000000000000, resource id:00000000-0000-0000-0000-000000000000, type id: 1, folder: false, flags: 0,project: ae97ff1d-7824-11e4-8c0e-28e347ffa92b, state: 2, date created: Thu Jan01 08:00:00 CST 1970, user created: c300ba5c-01e8-3727-b305-5dcc9ccae1ee, datelastmodified: Thu Jan 01 08:00:00 CST 1970, 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: Thu Jan 0108:00:00 CST 1970, size: 0, sibling count: 1, version: 0]

讨论点2:资源实际创建阶段:

这段事情很多,因为篇幅关系,我不贴全部代码了,从宏观上它大体做了如下事情:

a. 获取要创建资源的父目录(parentFolder):

[org.opencms.file.CmsFolder, path:/sites/default/charles_study/, structure id 4bf8b750-785d-11e4-8289-28e347ffa92b,resource id: 4bf8b751-785d-11e4-8289-28e347ffa92b, type id: 0, folder: true,flags: 0, project: ae97ff1d-7824-11e4-8c0e-28e347ffa92b, state: 2, datecreated: Sun Nov 30 14:51:23 CST 2014, user created:c300ba5c-01e8-3727-b305-5dcc9ccae1ee, date lastmodified: Sun Nov 30 14:51:35CST 2014, user lastmodified: c300ba5c-01e8-3727-b305-5dcc9ccae1ee, datereleased: Thu Jan 01 08:00:00 CST 1970, date expired: Sun Aug 17 15:12:55 CST292278994, date content: Thu Jan 01 07:59:59 CST 1970, size: -1, sibling count:1, version: 1]

b.判断父目录的锁(lock)。因为父目录如果被其他用户锁住,则我们不可以在这个目录下创建资源。反过来,如果父目录没加锁,或者虽然加了但是锁的owner为当前用户,则可以在其下创建资源。

c.  判断资源的名字是否使用了forbidden字符。

d.  在内存中构建新的resource对象。因为有了structureId,resourceId和其他信息,现在构建的新对象要比原型阶段丰富多了:

[org.opencms.file.CmsResource, path:/sites/default/charles_study/text-text-file-5, structure id5b97ca24-786d-11e4-8289-28e347ffa92b, resource id:5d577b85-786d-11e4-8289-28e347ffa92b, type id: 1, folder: false, flags: 0,project: ae97ff1d-7824-11e4-8c0e-28e347ffa92b, state: 2, date created: Thu Jan01 08:00:00 CST 1970, user created: c300ba5c-01e8-3727-b305-5dcc9ccae1ee, datelastmodified: Thu Jan 01 08:00:00 CST 1970, 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: Thu Jan 0108:00:00 CST 1970, size: 0, sibling count: 1, version: 0]

e.把resource对象写入数据库。写的代码位于CmsVfsDriver的createResource()方法中,从宏观上,它又做了几个步骤:

  1. 据库层面的路径检查
  2. 设置资源的状态和修改日期
  3. 把内存中的resource对象更新到CMS_OFFLINE_STRUCTURE表中。它执行的SQL语句是:
INSERT INTO CMS_OFFLINE_STRUCTURE(STRUCTURE_ID,RESOURCE_ID,RESOURCE_PATH,STRUCTURE_STATE,DATE_RELEASED,DATE_EXPIRED,PARENT_ID,STRUCTURE_VERSION)VALUES (‘273e3066-786e-11e4-8289-28e347ffa92b‘,‘273e3067-786e-11e4-8289-28e347ffa92b‘,‘/sites/default/charles_study/test-text-file-5‘,2,0,9223372036854775807,‘4bf8b750-785d-11e4-8289-28e347ffa92b‘,0)

我们查询数据库可以看到今天做的实验,都是一些未发布的资源:

他们和我们在cms workplace中看到的是精确一致的:

4. 创建文件内容。它是通过CmsVfsDriver()的createContent()方法来实现的,并且对于文件内容<2KB则直接读取,对于>2KB的文件内容通过打开一个输入流来读取,最后把该文件的内容写入CMS_OFFLINE_CONTENTS表中,它执行的SQL语句是:

INSERT INTO CMS_OFFLINE_CONTENTS (RESOURCE_ID,FILE_CONTENT)VALUES (‘273e3067-786e-11e4-8289-28e347ffa92b‘,x‘‘)

写入的文件以BLOB形式存储:

5.  修复所有引用该资源的关系。它通过调用repairBrokenRelations()方法实现,它会更新CMS_OFFLINE_RESOURCE_RELATIONS表。它执行的SQL语句是:

UPDATE CMS_OFFLINE_RESOURCE_RELATIONS LEFT JOINCMS_OFFLINE_STRUCTURE ON CMS_OFFLINE_RESOURCE_RELATIONS.RELATION_TARGET_ID =CMS_OFFLINE_STRUCTURE.STRUCTURE_ID SET RELATION_TARGET_ID =‘273e3066-786e-11e4-8289-28e347ffa92b‘ WHERECMS_OFFLINE_RESOURCE_RELATIONS.RELATION_TARGET_PATH =‘/sites/default/charles_study/test-text-file-5‘ ANDCMS_OFFLINE_STRUCTURE.STRUCTURE_ID IS NULL

f.锁住刚创建的新资源,锁类型为排它锁(CmsLockType.EXCLUSIVE)

总结:

从以上过程可以看出,有以下重要结论:

  1. 资源Resource的创建分两个阶段,其中原型阶段创建的资源对象只存在内存中,而实际创建阶段创建的资源对象既会存在在内存中,又会持久化到数据库中。
  2. 撇开一些不是太关键的环节,比如资源权限校验,资源唯一性校验,锁校验,创建阶段主要会更新CMS_OFFLINE_STRUCTURE,CMS_OFFLINE_CONTENTS,CMS_OFFLINE_RESOURCE_RELATIONS 三张表,这三张表起的作用分别是存储未发布的资源的结构,实际内容,引用关系。
时间: 2024-10-22 13:41:22

opencms创建资源深度分析的相关文章

深度分析Java的枚举类型—-枚举的线程安全性及序列化问题

原文:深度分析Java的枚举类型--枚举的线程安全性及序列化问题 枚举是如何保证线程安全的 要想看源码,首先得有一个类吧,那么枚举类型到底是什么类呢?是enum吗?答案很明显不是,enum就和class一样,只是一个关键字,他并不是一个类,那么枚举是由什么类维护的呢,我们简单的写一个枚举: public enum t { SPRING,SUMMER,AUTUMN,WINTER; } 然后我们使用反编译,看看这段代码到底是怎么实现的,反编译(Java的反编译)后代码内容如下: public fin

OpenCms创建站点过程图解——献给OpenCms的刚開始学习的人们

非常多人都听说了OpenCms,知道了它的强大,索性的下载安装了,最终见到了久违OpenCms,看到了它简洁的界面,欣喜过后却不免一脸茫然,这个东西怎么用,我怎么用它来建站,从哪開始,无从下手,找资料,少之双少,几经周折后,迫于时间等诸多因素,非常多人无奈地选择了放弃…… 希望这篇文章能够对OpenCms的追随者们有所帮助,但这也仅仅是OpenCms的皮毛,把它的强大功能为已所用还须要我们付出很多其它的努力…… 一.切换到“/sites/”下,创建网站目录“testWeb” 输入目录的标题,这个

深度分析LINUX环境下如何配置multi-path

首先介绍一下什么是多路径(multi-path)?先说说多路径功能产生的背景,在多路径功能出现之前,主机上的硬盘是直接挂接到一个总线(PCI)上,路径是一对一的关系,也就是一条路径指向一个硬盘或是存储设备,这样的一对一关系对于操作系统而言,处理相对简单,但是缺少了可靠性.当出现了光纤通道网络(Fibre Channle)也就是通常所说的SAN网络时,或者由iSCSI组成的IPSAN环境时,由于主机和存储之间通过光纤通道交换机或者多块网卡及IP来连接时,构成了多对多关系的IO通道,也就是说一台主机

深度分析如何在Hadoop中控制Map的数量

深度分析如何在Hadoop中控制Map的数量 [email protected] 很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数决定.在默认情况下,最终input 占据了多少block,就应该启动多少个Mapper.如果输入的文件数量巨大,但是每个文件的size都小于HDFS的blockSize,那么会造成 启动的Mapper等于文件的数量(即每个文件都占据了一个block),那么很可能造成启动的Mapper数量超出限制而导致崩溃.这些逻

OpenCms创建网站过程图解——献给OpenCms的初学者们

很多人都听说了OpenCms,知道了它的强大,索性的下载安装了,终于见到了久违OpenCms,看到了它简洁的界面,欣喜过后却不免一脸茫然,这个东西怎么用,我怎么用它来建站,从哪开始,无从下手,找资料,少之双少,几经周折后,迫于时间等诸多因素,很多人无奈地选择了放弃-- 希望这篇文章可以对OpenCms的追随者们有所帮助,但这也只是OpenCms的皮毛,把它的强大功能为已所用还需要我们付出更多的努力-- 一.切换到"/sites/"下,创建站点文件夹"testWeb"

java集合框架(1) hashMap 简单使用以及深度分析(转)

java.util 类 HashMap<K,V>java.lang.Object  java.util.AbstractMap<K,V>      java.util.HashMap<K,V>类型参数:K - 此映射所维护的键的类型V - 所映射值的类型所有已实现的接口: Serializable, Cloneable, Map<K,V> 直接已知子类: LinkedHashMap, PrinterStateReasons -----------------

转:[gevent源码分析] 深度分析gevent运行流程

[gevent源码分析] 深度分析gevent运行流程 http://blog.csdn.net/yueguanghaidao/article/details/24281751 一直对gevent运行流程比较模糊,最近看源码略有所得,不敢独享,故分享之. gevent是一个高性能网络库,底层是libevent,1.0版本之后是libev,核心是greenlet.gevent和eventlet是亲近,唯一不同的是eventlet是自己实现的事件驱动,而gevent是使用libev.两者都有广泛的应

OpenCms创建网站的过程示意图——专用OpenCms人们刚开始学习

很多人听说过OpenCms,我知道它的强大,只需下载并安装,最后,我们看到了久违OpenCms,我们看到了它的简单的界面,喜悦之后,但难免困惑.如何用这个东西,我如何用它来网站,从哪里开始,无从下手.查找信息,少双,几经波折.强制的时间和其他因素,很多人无奈地选择了放弃…… 希望这篇文章能够对OpenCms的追随者们有所帮助,但这也仅仅是OpenCms的皮毛,把它的强大功能为已所用还须要我们付出很多其它的努力…… 一.切换到“/sites/”下,创建网站目录“testWeb” 输入目录的标题.这

深度分析:Android4.3下MMS发送到附件为音频文件(音频为系统内置音频)的彩信给自己,添加音频-发送彩信-接收彩信-下载音频附件-预览-播放(二,发送彩信&lt;1&gt;)

当准备工作(添加附件,输入文本内容)完成之后,我们这里开始进行该流程分析的第二阶段,也就是发送彩信.这里我们从ComposeMessageActivity类的点击发送按钮(mSendButtonMms)的点击事件开始:<TAG 1-1> @Override public void onClick(View v) { if (mShowTwoButtons && (v == mSendButtonSmsViewSec || v == mSendButtonMmsViewSec)