/* ==================================================================
* Created [2009-4-27 下午11:32:55] by Jon.King
* ==================================================================
* TSS
* ==================================================================
* mailTo:jinpujun@hotmail.com
* Copyright (c) Jon.King, 2009-2012
* ==================================================================
*/
package com.jinhe.tss.portal.engine;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringTokenizer;
import org.dom4j.Document;
import org.dom4j.Element;
import com.jinhe.tss.core.exception.BusinessException;
import com.jinhe.tss.core.util.XMLDocUtil;
import com.jinhe.tss.portal.engine.model.DecoratorNode;
import com.jinhe.tss.portal.engine.model.LayoutNode;
import com.jinhe.tss.portal.engine.model.Node;
import com.jinhe.tss.portal.engine.model.PageNode;
import com.jinhe.tss.portal.engine.model.PortalNode;
import com.jinhe.tss.portal.engine.model.PortletInstanceNode;
import com.jinhe.tss.portal.engine.model.PortletNode;
import com.jinhe.tss.portal.engine.model.SectionNode;
import com.jinhe.tss.portal.engine.model.SubNode;
import com.jinhe.tss.portal.engine.model.Supplementable;
import com.jinhe.tss.portal.entity.Decorator;
import com.jinhe.tss.portal.entity.Layout;
import com.jinhe.tss.portal.entity.PortalStructure;
import com.jinhe.tss.portal.entity.Portlet;
/**
* <p> PortalGenerator.java </p>
* <p>
* 门户生成器,负责组装门户结构
* </p>
*/
public class PortalGenerator {
private Map<Long, Decorator> decoratorsMap = new HashMap<Long, Decorator>(); // 修饰器池
private Map<Long, Layout> layoutsMap = new HashMap<Long, Layout>(); // 布局器池
private Map<Long, Portlet> portletsMap = new HashMap<Long, Portlet>(); // portlet池
private PortalGenerator() { }
/**
* 组装门户结构
* @param root
* 门户结构根节点
* @param list
* 门户结构列表
* @param elements
* 修饰器,布局器,portlet等列表(new Object[]{decorators, layouts, portlets})
* @return
* Node树根节点,PortalNode
*/
public static PortalNode genPortalNode(PortalStructure root, List<PortalStructure> list, Object[] elements){
if( !root.getType().equals(PortalStructure.TYPE_PORTAL) ) {
throw new BusinessException("主装门户时根节点必须是portal根节点, 【" + root.getName() + "】不是根节点!");
}
PortalGenerator generator = new PortalGenerator();
generator.compose(root, list);
// 初始化元素池,包括修饰器,布局器,portlet.
List<?> decoratorsList = (List<?>) elements[0];
List<?> layoutsList = (List<?>) elements[1];
List<?> portletsList = (List<?>) elements[2];
for( Object temp : decoratorsList ){
Decorator element = (Decorator) temp;
generator.decoratorsMap.put( element.getId(), element);
}
for( Object temp : layoutsList ){
Layout element = (Layout) temp;
generator.layoutsMap.put( element.getId(), element);
}
for( Object temp : portletsList ){
Portlet element = (Portlet) temp;
generator.portletsMap.put( element.getId(), element);
}
return (PortalNode) generator.ps2Node(root, null);
}
/**
* 将一个门户结构节点下所有的子节点递归放入到各自的父节点下
* <br>
* |-门户_1 <br>
* ........|- 页面_1 <br>
* ................|- portlet应用_1_1 <br>
* ................|- 版面_1_1 <br>
* ..........................|- 版面_1_1_2 <br>
* ......................................|- portlet应用_1_1_2_1 <br>
* ..........................|- portlet应用_1_1_2 <br>
* ........|- 页面_2 <br>
* ........|- 页面_3 <br>
*
* @param list
*/
private void compose(PortalStructure root, List<PortalStructure> list){
Map<Long, PortalStructure> map = new HashMap<Long, PortalStructure>();
map.put(root.getId(), root);
for ( PortalStructure entity : list ) {
map.put(entity.getId(), entity);
}
for ( PortalStructure entity : list ) {
PortalStructure parent = map.get(entity.getParentId());
if(parent == null) {
throw new BusinessException("门户节点【" + entity.getName() + "】找不到父节点,数据有误,组成门户树失败!");
}
if (root.getType().equals(parent.getType())) {
root.addChild(entity);
} else {
parent.addChild(entity);
}
}
}
/**
* 根据门户结构的type值转换为相应的Node节点对象
* @param ps
* @param parent
* @return
*/
private Node ps2Node(PortalStructure ps, Node parent){
Node newNode = null;
switch(ps.getType()) {
case PortalStructure.TYPE_PORTAL:
newNode = genPortalNode(ps);
break;
case PortalStructure.TYPE_PAGE:
newNode = genPageNode(ps, parent);
break;
case PortalStructure.TYPE_SECTION:
newNode = genSectionNode(ps, parent);
break;
case PortalStructure.TYPE_PORTLET_INSTANCE:
newNode = genPortletInstanceNode(ps, parent);
break;
default:
throw new BusinessException("门户节点【" + ps.getName() + "】 的类型有误,不存在该类型(type=" + ps.getType() + ")的门户结构!");
}
newNode.getPortal().getNodesMap().put(ps.getId(), newNode);
return newNode;
}
/**
* 生成门户根节点
* @param ps
* @return
*/
private Node genPortalNode(PortalStructure ps) {
PortalNode portalNode = new PortalNode(ps);
parseSupplement(portalNode, ps.getSupplement());
for(PortalStructure child : ps.getChildren() ){
portalNode.addChild(ps2Node(child, portalNode));
}
return portalNode;
}
/**
* 生成页面节点。
* 页面节点上还外挂一个修饰器节点和一个布局器节点
* @param ps
* @param portalNode
* @return
*/
private Node genPageNode(PortalStructure ps, Node portalNode) {
PageNode pageNode = new PageNode(ps, portalNode);
parseSupplement(pageNode, ps.getSupplement());
String parametersOnPs = ps.getParameters(); // 获取门户结构上定义的元素参数列表
pageNode.setDecoratorNode(new DecoratorNode(decoratorsMap.get(ps.getDecoratorId()), pageNode, parametersOnPs));
pageNode.setLayoutNode(new LayoutNode(layoutsMap.get(ps.getDefinerId()), pageNode, parametersOnPs));
for(PortalStructure child : ps.getChildren() ){
pageNode.addChild(ps2Node(child, pageNode));
}
return pageNode;
}
/**
* 生成版面节点。
* 版面节点上还外挂一个修饰器节点和一个布局器节点。
* @param ps
* @param parentNode
* 可能是pageNode 也可能是SectionNode
* @return
*/
private Node genSectionNode(PortalStructure ps, Node parentNode) {
SectionNode sectionNode = new SectionNode(ps);
repairSupNode(sectionNode, parentNode);
String parametersOnPs = ps.getParameters(); // 获取门户结构上定义的元素参数列表
sectionNode.setDecoratorNode(new DecoratorNode(decoratorsMap.get(ps.getDecoratorId()), sectionNode, parametersOnPs));
sectionNode.setLayoutNode(new LayoutNode(layoutsMap.get(ps.getDefinerId()), sectionNode, parametersOnPs));
for(PortalStructure child : ps.getChildren() ){
sectionNode.addChild(ps2Node(child, sectionNode));
}
return sectionNode;
}
/**
* 生成portlet实例节点。
* portlet节点上还外挂一个修饰器节点和一个portlet节点
* @param ps
* @param parentNode
* @return
*/
private Node genPortletInstanceNode(PortalStructure ps, Node parentNode) {
PortletInstanceNode node = new PortletInstanceNode(ps);
repairSupNode(node, parentNode);
String parametersOnPs = ps.getParameters(); // 获取门户结构上定义的元素参数列表
node.setDecoratorNode(new DecoratorNode(decoratorsMap.get(ps.getDecoratorId()), node, parametersOnPs));
node.setPortletNode(new PortletNode(portletsMap.get(ps.getDefinerId()), node, parametersOnPs));
return node;
}
/**
* 设置子节点(SectionNode或PortletInstanceNode)的上层节点,<br>
* 包括page,portal,parent节点.<br>
* 如果父节点是PageNode,则当前节点的PageNode就是父节点,<br>
* PortalNode就是父节点(PageNode)的父节点(PageNode.parent)<br>
* 如果父节点是SectionNode, 则继续往上找父节点的父节点,直到找到PageNode,再做上一如果的操作.
*
* @param node
* 被操作节点(SectionNode 或 PortletInstanceNode)
* @param parentNode
* 父节点 (PageNode 或 SectionNode)
*/
private void repairSupNode(SubNode node, Node parentNode){
node.setParent(parentNode);
PageNode pageNode = null;
if(parentNode instanceof PageNode){
pageNode = (PageNode) parentNode;
}
if(parentNode instanceof SectionNode){
Node parent = parentNode.getParent();
while(pageNode == null){
if(parent instanceof PageNode){
pageNode = (PageNode) parent;
break;
}
parent = parent.getParent();
}
}
node.setPage(pageNode);
node.setPortal((PortalNode) pageNode.getParent());
}
/**
* 解析js、css信息。门户或页面上拥有这些信息。
* @param supplement
* @return
*/
private void parseSupplement(Supplementable node, String supplement){
Document doc = XMLDocUtil.dataXml2Doc(supplement);
String scriptCode = ((Element)doc.selectSingleNode("//script/code")).getText();
String styleCode = ((Element)doc.selectSingleNode("//style/code")).getText();
String scriptFiles = ((Element)doc.selectSingleNode("//script/file")).getText(); //格式:1.js,2js,3js
String styleFiles = ((Element)doc.selectSingleNode("//style/file")).getText(); //格式:1.css,2css,3css
List<String> scriptList = new ArrayList<String>();
List<String> styleList = new ArrayList<String>();
StringTokenizer stk = new StringTokenizer(scriptFiles.replaceAll(",", "\n"));
while(stk.hasMoreTokens()){
scriptList.add(stk.nextToken());
}
stk = new StringTokenizer(styleFiles.replaceAll(",", "\n"));
while(stk.hasMoreTokens()){
styleList.add(stk.nextToken());
}
node.setScriptCode(scriptCode);
node.setStyleCode(styleCode);
node.getScriptFiles().addAll(scriptList);
node.getStyleFiles().addAll(styleList);
}
}