opencms创建资源深度分析

简介:

引入:

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


分析:

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

wKioL1R66MXDg1S8AAC9XpznmZI302.jpg

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


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

1
2
3
4
5
6
7
8
9
10
11
12
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()方法中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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),如下:

wKioL1R66mOiWGc9AAG9dpkJY5c702.jpg

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
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我们称为资源的原型,它创建完只“活”在计算机的内存中,并不做持久化,它的信息如下:

1
[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):

1
[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和其他信息,现在构建的新对象要比原型阶段丰富多了:

1
[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语句是:

1
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)

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

wKiom1R67n7QCLnJAAMDNwGgsa4687.jpg

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

wKiom1R67rDjT76LAAIQzgt1sRs679.jpg

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

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

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

wKiom1R678fxPe5uAAFMFdwWX7Q548.jpg

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

1
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 三张表,这三张表起的作用分别是存储未发布的资源的结构,实际内容,引用关系。





本文转自 charles_wang888 51CTO博客,原文链接:http://blog.51cto.com/supercharles888/1584798,如需转载请自行联系原作者
目录
相关文章
|
4天前
|
存储 前端开发 安全
13:会话跟踪技术Session的深度应用与实践-Java Web
13:会话跟踪技术Session的深度应用与实践-Java Web
34 3
|
6月前
|
存储 Java Spring
Spring框架中的Resource接口是什么,以及它在加载和访问资源时的关键作用
使用 Resource 加载资源 要使用 Resource 接口加载资源,首先需要获取一个 ResourceLoader 实例,通常可以通过依赖注入来获得。接下来,您可以使用 ResourceLoader 来获取 Resource 对象,然后使用它来访问资源的内容。
webpack优化篇(四十三):多进程/多实例构建:资源并行解析可选方案
webpack优化篇(四十三):多进程/多实例构建:资源并行解析可选方案
112 0
webpack优化篇(四十三):多进程/多实例构建:资源并行解析可选方案
|
Android开发
【Android 安装包优化】资源打包配置 ( resources.arsc 资源映射表 | 配置国际化资源 )
【Android 安装包优化】资源打包配置 ( resources.arsc 资源映射表 | 配置国际化资源 )
301 0
【Android 安装包优化】资源打包配置 ( resources.arsc 资源映射表 | 配置国际化资源 )
|
Java 开发者
获取类路径下的资源 | 学习笔记
快速学习获取类路径下的资源。
|
移动开发 小程序 安全
让小程序在自有App中启动的技术来了:mPaaS小程序架构深度解析
mPaaS 小程序框架作为一款 App 通用框架,帮助开发者面向自身的 App 实现小程序投放。不止如此,小程序代码仅需撰写一次,便可多端投放至自有 App、支付宝、钉钉甚至其他小程序开放平台。
2905 0
让小程序在自有App中启动的技术来了:mPaaS小程序架构深度解析
|
SQL 测试技术 数据库
使用VS2010的Database项目模板统一管理数“.NET研究”据库对象
  Visual Studio 2010 有一个数据库项目模板:Visual Studio Database Project(以下简称VSDP),VS 2003/2005/2008也有类似的项目,在VS2010上的得到了很大的加强,现在还具备了智能感知,构建时验证和自动部署功能,VSDP是针对典型的数据库开发任务而设计的,可以对原有数据库反向工程,添加表,存储过程和其他数据库项目,而且有选择性地将修改部署到目标数据库中。
817 0
|
C#
一起谈.NET技术,浅谈C#中的延迟加载(3)——还原模型的业务规则
  上一篇文章讲到把实体类中需要实现延迟加载的属性声明为virtual,然后继承实体类做一个子类,在子类里面实现该属性,配合使用委托来实现比较完美的延迟加载(原本的模型层依旧保持在最底层用于贯穿三层结构,同时又可以实现在实体类的属性里面访问到比他高层的数据访问层)。
932 0
|
C#
浅谈C#中的延迟加载(3)——还原“.NET研究”模型的业务规则
  上一篇文章讲到把实体类中需要实现延迟加载的属性声明为virtual,然后继承实体类做一个子类,在子类里面实现该属性,配合使用委托来实现比较完美的延迟加载(原本的模型层依旧保持在最底层用于贯穿三层结构,同时又可以上海企业网站制作实现在实体类的属性里面访问到比他高层的数据访问层)。
949 0