您的位置:首页 > Web前端

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="/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 创建文件夹