Liferay 控制面板创建文件夹流程分析
2012-07-05 18:53
351 查看
总结:
当我们在控制面板中添加Folder时,实际是在数据库的DLFolder表中插入了一行记录:记录信息包含用户输入的信息以及用户所在的id,repositoryId等。最精妙的地方是,它根本不会在服务器节点上创建这个我们给定名字的文件夹。
下面具体分析:
当我们以管理员登录,然后在控制面板中选择"Documents and Media" -> Add->"Folder"时,如下图所示:
这时候,对应的请求动作url为:
从这里可以看出,请求的struts_action为 /document_library/edit_folder
我们到struts-config.xml中寻找匹配:
这里可以看出这个action 会转发到的path是 portlet.document_library.edit_folder:
我们去tiles-def.xml中找到这个path匹配的文件:
所以,最终会转发到edit_folder.jsp:
这个页面本质上是一个表单,最终会提交给自己:
其中,name和description都是从表单页面上提取用户的输入,我们去看下struts中对于这个表单的处理,对应的类是与/document_libraray/edit_folder的请求匹配的类:com.liferay.portlet.documentlibrary.action.EditFolderAction
因为cmd是"add",所以,它会去调用updateFolder(actionRequest)方法:
我们继续跟进,对于updateFolder方法:
它会从actionRequest中提取folderId, repositoryId, parentFolderId, name, description等参数,因为我们的folderId是0,所以执行DLAppServiceUtil.addFolder()方法:
它最终会调用DLAppServiceImpl类的addFolder方法,如下:
实际上它做2步,一是21行通过repositoryId来获取Repository对象,二是23-24行来调用Repository对象上的addFolder来做实际的目录添加动作。我们分别分析:
(1) 根据repositoryId来获取Repository对象:
这个getRepository方法定义在DLAppServiceImpl类中:
它最终会调用RepositoryServiceImpl的getRepositoryImpl(long)方法:
a. 先分析checkRepository方法,跟进可以看到05行它先去检查repositoryId,这是通过执行数据库查询来完成的:
因为我们的repositoryId为19,所以我们来查询下数据库:
对于 Group,可以搜到以下的实例,所以满足group!=null的条件,直接返回。
b.获取Repository对象,这是通过RepositoryLocalServiceImpl类的getRepositoryImpl(long repositoryId)来完成的:
断点调试可以发现从05-06行返回null,然后不进入08-10行,然后进入12行返回的classNameId为12493,然后第15行从PortalUtil.getClassNameId返回的值也是12493, 两者匹配,于是进入第17行,它会用许多填充信息来创建一个LiferayRepository对象:
最终得到的LiferayRepository对象如下:
这就是我们的期望值, 它和repositoryId=19 关联了起来。
(2) 执行repository.addFolder动作
我们回到DLAppServiceImpl的addFolder方法,它最后一行的addFolder事实上最终调用LiferayRepository类的addFolder方法:
我们来调试这段代码:
从调试信息上看,mountPoint的值为false.
然后执行DLFolderServiceImpl的addFolder方法:
它会去委托DLFolderLocalServiceImpl的addFolder方法:
到31行为止,我们创建的DLFolder对象涵盖了所有这些值:
然后第33行要持久化这个我们创建的dLFolder ,它最终是调用DLFolderPersistenceImpl类的updateImpl方法,并且把DLFolder对象作为第一个参数传入:
最终,它调用BatchSessionUtil.update(session, dlFolder, merge)来实际进行更新操作。
我们继续跟进,发现它最终调用BatchSessionImpl的update方法:
实际调用Hibernate框架的session的saveOrUpdate方法对这个folder进行持久化,最终会再数据库中添加一条记录。我们去数据库检查:
果然和我们预计一样。
当我们在控制面板中添加Folder时,实际是在数据库的DLFolder表中插入了一行记录:记录信息包含用户输入的信息以及用户所在的id,repositoryId等。最精妙的地方是,它根本不会在服务器节点上创建这个我们给定名字的文件夹。
下面具体分析:
当我们以管理员登录,然后在控制面板中选择"Documents and Media" -> Add->"Folder"时,如下图所示:
这时候,对应的请求动作url为:
从这里可以看出,请求的struts_action为 /document_library/edit_folder
我们到struts-config.xml中寻找匹配:
<action path="/document_library/edit_folder" type="com.liferay.portlet.documentlibrary.action.EditFolderAction"> <forward name="portlet.document_library.edit_folder" path="portlet.document_library.edit_folder" /> <forward name="portlet.document_library.error" path="portlet.document_library.error" /> </action>
这里可以看出这个action 会转发到的path是 portlet.document_library.edit_folder:
我们去tiles-def.xml中找到这个path匹配的文件:
<definition name="portlet.document_library.edit_folder" extends="portlet.document_library"> <put name="portlet_content" value="/portlet/document_library/edit_folder.jsp" /> </definition>
所以,最终会转发到edit_folder.jsp:
这个页面本质上是一个表单,最终会提交给自己:
其中,name和description都是从表单页面上提取用户的输入,我们去看下struts中对于这个表单的处理,对应的类是与/document_libraray/edit_folder的请求匹配的类:com.liferay.portlet.documentlibrary.action.EditFolderAction
因为cmd是"add",所以,它会去调用updateFolder(actionRequest)方法:
public void processAction( ActionMapping mapping, ActionForm form, PortletConfig portletConfig, ActionRequest actionRequest, ActionResponse actionResponse) throws Exception { String cmd = ParamUtil.getString(actionRequest, Constants.CMD); try { if (cmd.equals(Constants.ADD) || cmd.equals(Constants.UPDATE)) { updateFolder(actionRequest); } ...
我们继续跟进,对于updateFolder方法:
protected void updateFolder(ActionRequest actionRequest) throws Exception { long folderId = ParamUtil.getLong(actionRequest, "folderId"); long repositoryId = ParamUtil.getLong(actionRequest, "repositoryId"); long parentFolderId = ParamUtil.getLong( actionRequest, "parentFolderId"); String name = ParamUtil.getString(actionRequest, "name"); String description = ParamUtil.getString(actionRequest, "description"); ServiceContext serviceContext = ServiceContextFactory.getInstance( DLFolder.class.getName(), actionRequest); if (folderId <= 0) { // Add folder DLAppServiceUtil.addFolder( repositoryId, parentFolderId, name, description, serviceContext); } else { // Update folder DLAppServiceUtil.updateFolder( folderId, name, description, serviceContext); } }
它会从actionRequest中提取folderId, repositoryId, parentFolderId, name, description等参数,因为我们的folderId是0,所以执行DLAppServiceUtil.addFolder()方法:
public static com.liferay.portal.kernel.repository.model.Folder addFolder( long repositoryId, long parentFolderId, java.lang.String name, java.lang.String description, com.liferay.portal.service.ServiceContext serviceContext) throws com.liferay.portal.kernel.exception.PortalException, com.liferay.portal.kernel.exception.SystemException { return getService() .addFolder(repositoryId, parentFolderId, name, description, serviceContext); }
它最终会调用DLAppServiceImpl类的addFolder方法,如下:
/** * Adds a folder. * * @param repositoryId the primary key of the repository * @param parentFolderId the primary key of the folder's parent folder * @param name the folder's name * @param description the folder's description * @param serviceContext the service context to be applied. In a Liferay * repository, it may include boolean mountPoint specifying whether * folder is a facade for mounting a third-party repository * @return the folder * @throws PortalException if the parent folder could not be found or if the * new folder's information was invalid * @throws SystemException if a system exception occurred */ public Folder addFolder( long repositoryId, long parentFolderId, String name, String description, ServiceContext serviceContext) throws PortalException, SystemException { Repository repository = getRepository(repositoryId); return repository.addFolder( parentFolderId, name, description, serviceContext); }
实际上它做2步,一是21行通过repositoryId来获取Repository对象,二是23-24行来调用Repository对象上的addFolder来做实际的目录添加动作。我们分别分析:
(1) 根据repositoryId来获取Repository对象:
这个getRepository方法定义在DLAppServiceImpl类中:
protected Repository getRepository(long repositoryId) throws PortalException, SystemException { return repositoryService.getRepositoryImpl(repositoryId); }
它最终会调用RepositoryServiceImpl的getRepositoryImpl(long)方法:
public com.liferay.portal.kernel.repository.Repository getRepositoryImpl( long repositoryId) throws PortalException, SystemException { checkRepository(repositoryId); return repositoryLocalService.getRepositoryImpl(repositoryId); }
a. 先分析checkRepository方法,跟进可以看到05行它先去检查repositoryId,这是通过执行数据库查询来完成的:
public void checkRepository(long repositoryId) throws PortalException, SystemException { Group group = groupPersistence.fetchByPrimaryKey(repositoryId); if (group != null) { return; } try { Repository repository = repositoryPersistence.findByPrimaryKey( repositoryId); DLFolderPermission.check( getPermissionChecker(), repository.getGroupId(), repository.getDlFolderId(), ActionKeys.VIEW); } catch (NoSuchRepositoryException nsre) { throw new RepositoryException(nsre.getMessage()); } }
因为我们的repositoryId为19,所以我们来查询下数据库:
对于 Group,可以搜到以下的实例,所以满足group!=null的条件,直接返回。
b.获取Repository对象,这是通过RepositoryLocalServiceImpl类的getRepositoryImpl(long repositoryId)来完成的:
public com.liferay.portal.kernel.repository.Repository getRepositoryImpl( long repositoryId) throws PortalException, SystemException { com.liferay.portal.kernel.repository.Repository repositoryImpl = _repositoriesByRepositoryId.get(repositoryId); if (repositoryImpl != null) { return repositoryImpl; } long classNameId = getRepositoryClassNameId(repositoryId); if (classNameId == PortalUtil.getClassNameId(LiferayRepository.class.getName())) { repositoryImpl = new LiferayRepository( repositoryLocalService, repositoryService, dlAppHelperLocalService, dlFileEntryLocalService, dlFileEntryService, dlFileVersionLocalService, dlFileVersionService, dlFolderLocalService, dlFolderService, repositoryId); } else { repositoryImpl = createRepositoryImpl(repositoryId, classNameId); } checkRepository(repositoryId); _repositoriesByRepositoryId.put(repositoryId, repositoryImpl); return repositoryImpl; }
断点调试可以发现从05-06行返回null,然后不进入08-10行,然后进入12行返回的classNameId为12493,然后第15行从PortalUtil.getClassNameId返回的值也是12493, 两者匹配,于是进入第17行,它会用许多填充信息来创建一个LiferayRepository对象:
最终得到的LiferayRepository对象如下:
这就是我们的期望值, 它和repositoryId=19 关联了起来。
(2) 执行repository.addFolder动作
我们回到DLAppServiceImpl的addFolder方法,它最后一行的addFolder事实上最终调用LiferayRepository类的addFolder方法:
public Folder addFolder( long parentFolderId, String title, String description, ServiceContext serviceContext) throws PortalException, SystemException { boolean mountPoint = ParamUtil.getBoolean(serviceContext, "mountPoint"); DLFolder dlFolder = dlFolderService.addFolder( getGroupId(), getRepositoryId(), mountPoint, toFolderId(parentFolderId), title, description, serviceContext); return new LiferayFolder(dlFolder); }
我们来调试这段代码:
从调试信息上看,mountPoint的值为false.
然后执行DLFolderServiceImpl的addFolder方法:
public DLFolder addFolder( long groupId, long repositoryId, boolean mountPoint, long parentFolderId, String name, String description, ServiceContext serviceContext) throws PortalException, SystemException { DLFolderPermission.check( getPermissionChecker(), groupId, parentFolderId, ActionKeys.ADD_FOLDER); return dlFolderLocalService.addFolder( getUserId(), groupId, repositoryId, mountPoint, parentFolderId, name, description, serviceContext); }
它会去委托DLFolderLocalServiceImpl的addFolder方法:
public DLFolder addFolder( long userId, long groupId, long repositoryId, boolean mountPoint, long parentFolderId, String name, String description, ServiceContext serviceContext) throws PortalException, SystemException { // Folder User user = userPersistence.findByPrimaryKey(userId); parentFolderId = getParentFolderId(groupId, parentFolderId); Date now = new Date(); validateFolder(groupId, parentFolderId, name); long folderId = counterLocalService.increment(); DLFolder dlFolder = dlFolderPersistence.create(folderId); dlFolder.setUuid(serviceContext.getUuid()); dlFolder.setGroupId(groupId); dlFolder.setCompanyId(user.getCompanyId()); dlFolder.setUserId(user.getUserId()); dlFolder.setCreateDate(serviceContext.getCreateDate(now)); dlFolder.setModifiedDate(serviceContext.getModifiedDate(now)); dlFolder.setRepositoryId(repositoryId); dlFolder.setMountPoint(mountPoint); dlFolder.setParentFolderId(parentFolderId); dlFolder.setName(name); dlFolder.setDescription(description); dlFolder.setOverrideFileEntryTypes(false); dlFolder.setExpandoBridgeAttributes(serviceContext); dlFolderPersistence.update(dlFolder, false); // Resources if (serviceContext.isAddGroupPermissions() || serviceContext.isAddGuestPermissions()) { addFolderResources( dlFolder, serviceContext.isAddGroupPermissions(), serviceContext.isAddGuestPermissions()); } else { if (serviceContext.isDeriveDefaultPermissions()) { serviceContext.deriveDefaultPermissions( repositoryId, DLFolderConstants.getClassName()); } addFolderResources( dlFolder, serviceContext.getGroupPermissions(), serviceContext.getGuestPermissions()); } // Parent folder if (parentFolderId != DLFolderConstants.DEFAULT_PARENT_FOLDER_ID) { DLFolder parentDLFolder = dlFolderPersistence.findByPrimaryKey( parentFolderId); parentDLFolder.setLastPostDate(now); dlFolderPersistence.update(parentDLFolder, false); } // App helper dlAppHelperLocalService.addFolder( new LiferayFolder(dlFolder), serviceContext); return dlFolder; }
到31行为止,我们创建的DLFolder对象涵盖了所有这些值:
然后第33行要持久化这个我们创建的dLFolder ,它最终是调用DLFolderPersistenceImpl类的updateImpl方法,并且把DLFolder对象作为第一个参数传入:
public DLFolder updateImpl( com.liferay.portlet.documentlibrary.model.DLFolder dlFolder, boolean merge) throws SystemException { dlFolder = toUnwrappedModel(dlFolder); boolean isNew = dlFolder.isNew(); DLFolderModelImpl dlFolderModelImpl = (DLFolderModelImpl)dlFolder; if (Validator.isNull(dlFolder.getUuid())) { String uuid = PortalUUIDUtil.generate(); dlFolder.setUuid(uuid); } Session session = null; try { session = openSession(); BatchSessionUtil.update(session, dlFolder, merge); dlFolder.setNew(false); } ...
最终,它调用BatchSessionUtil.update(session, dlFolder, merge)来实际进行更新操作。
我们继续跟进,发现它最终调用BatchSessionImpl的update方法:
public void update(Session session, BaseModel<?> model, boolean merge) throws ORMException { if (merge || model.isCachedModel()) { session.merge(model); } else { if (model.isNew()) { session.save(model); } .. if (!isEnabled()) { session.flush(); return; } if ((PropsValues.HIBERNATE_JDBC_BATCH_SIZE == 0) || ((_counter.get() % PropsValues.HIBERNATE_JDBC_BATCH_SIZE) == 0)) { session.flush(); } _counter.set(_counter.get() + 1); }
实际调用Hibernate框架的session的saveOrUpdate方法对这个folder进行持久化,最终会再数据库中添加一条记录。我们去数据库检查:
果然和我们预计一样。
相关文章推荐
- Liferay 控制面板在指定文件夹添加Basic Document流程分析
- OGRE根据高度图创建Terrain地形流程分析
- Android5.1 Telecomm层通话去电流程两路进程分析之四通话连接创建成功通知显示InCallUI
- Openstack之Nova创建虚机流程分析
- 在Ceph中创建虚拟机流程改进之分析(转)
- 通过heat创建stack的代码流程分析heat stack-create
- Openstack之Nova创建虚机流程分析(02)
- Liferay 创建新用户页面中随机文本验证分析
- openstack之虚拟机创建流程分析
- 虚拟机创建流程中neutron代码分析(二)
- OGRE根据高度图创建Terrain地形流程分析
- Android系统应用---SystemUI之一:SystemUI概述和创建启动流程分析
- openstack Nova分析之 创建虚拟机流程(4)
- hyperstart 容器创建流程分析
- Windows进程创建的流程分析
- Spark1.3从创建到提交:1)master和worker启动流程源码分析
- 点击internet explorer 显示该文件没有程序与之关联来执行该操作 请在控制面板的文件夹选项中创建关联程解决方案
- Windows进程创建的流程分析
- 该文件没有程序与之关联来执行该操作,请在控制面板的文件夹选项中创建关联 解决代码
- 【OVS2.5.0源码分析】vxlan端口创建流程分析