/* ==================================================================
* 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.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.tree.DefaultDocument;
import org.dom4j.tree.DefaultElement;
import com.jinhe.tss.core.util.EasyUtils;
import com.jinhe.tss.core.util.XMLDocUtil;
import com.jinhe.tss.portal.dao.IPortalDao;
import com.jinhe.tss.portal.engine.model.AbstractElementNode;
import com.jinhe.tss.portal.engine.model.DecoratorConfigable;
import com.jinhe.tss.portal.engine.model.DecoratorNode;
import com.jinhe.tss.portal.engine.model.LayoutConfigable;
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.entity.Decorator;
import com.jinhe.tss.portal.entity.Layout;
import com.jinhe.tss.portal.entity.Portlet;
import com.jinhe.tss.portal.helper.IElement;
/**
* <p> PersonalManager.java </p>
*
* 门户个性化定制管理器。 PortalNode.clone + 个性化定制信息 ==> 个性化PortalNode ==> 个性化页面
*
* PS: 门户缓存池中:
* 默认portalNode和用户自定义的personalNode不能放在同一个缓存池中,因为他们的reload方法不一样。
*
*/
public class PersonalManager {
public final static String STRUCTURE_NODE_NAME = "structure";
public final static String PAGE_NODE_NAME = "page";
public final static String SECTION_NODE_NAME = "section";
public final static String PORTLETINSTACE_NODE_NAME = "portletInstanse";
public final static String ELEMENT_TYPE_NAME = "class";
public final static String DECORATOR_TYPE = "Decorator";
public final static String LAYOUT_TYPE = "Layout";
public final static String PORTLET_TYPE = "Portlet";
public final static String ID = "id";
public final static String PARAMS_NODE_NAME = "params";
public final static String PARAM_NODE_NAME = "param";
public final static String STRUCTURE_ID = "structureId";
public final static String ELEMENT_ID = "elementId";
private IPortalDao dao;
private PortalNode portal;
private List<Document> personalPageXMLs; //页面个性化定制信息XML列表
public PersonalManager(PortalNode portal, List<Document> personalPageXMLs, IPortalDao dao) {
this.portal = portal;
this.personalPageXMLs = personalPageXMLs;
this.dao = dao;
}
/**
* 解析用户的自定义页面。
* 解析成功后返回用户自定义门户PortalNode节点。
* @return
*/
public PortalNode generatePersonalPortal() {
if (personalPageXMLs != null && personalPageXMLs.size() > 0) {
for ( Document personalPageXML : personalPageXMLs ) {
generatorPersonalPage(personalPageXML);
}
}
return portal;
}
/**
* 解析单个自定义页面。
*
* @param doc
*/
private void generatorPersonalPage(Document doc) {
Element structureNode = (Element) doc.selectSingleNode("//" + STRUCTURE_NODE_NAME);
Element pageElement = (Element) structureNode.element(PAGE_NODE_NAME);
Element paramsNode = (Element) doc.selectSingleNode("//" + PARAMS_NODE_NAME);
Map<String, Map<String, String>> params = parsePersonalParams(paramsNode);
parseStructure(pageElement, params);
}
/**
* 解析每一个门户结构节点。
* 此方法本生递归调用,直至解析完所有的叶子节点。
* @param structure
* @param params
* @return
*/
@SuppressWarnings("unchecked")
private Node parseStructure(Element structure, Map<String, Map<String, String>> params){
Long structureId = Long.valueOf(structure.attributeValue(ID));
SubNode node = (SubNode) portal.getNodesMap().get(structureId);
if(node == null)
return null;
DecoratorConfigable decoratorConfigableNode = (DecoratorConfigable)node;
DecoratorNode decoratorNode = (decoratorConfigableNode).getDecoratorNode();
Object[] objs = repair(structure, params, node, DECORATOR_TYPE, decoratorNode);
if(objs != null) {
DecoratorNode personalDecoratorNode = new DecoratorNode((Decorator)objs[0], node, (Map<String, String>)objs[1]);
decoratorConfigableNode.setDecoratorNode(personalDecoratorNode);
}
if( isLeaf(structure) ){
PortletInstanceNode portletInstanceNode = (PortletInstanceNode) node;
PortletNode portletNode = (portletInstanceNode).getPortletNode();
objs = repair(structure, params, node, PORTLET_TYPE, portletNode);
if(objs != null) {
PortletNode personalPortletNode = new PortletNode((Portlet)objs[0], node, (Map<String, String>)objs[1]);
portletInstanceNode.setPortletNode(personalPortletNode);
}
}
else {
LayoutConfigable layoutConfigableNode = (LayoutConfigable)node;
LayoutNode layoutNode = (layoutConfigableNode).getLayoutNode();
objs = repair(structure, params, node, LAYOUT_TYPE, layoutNode);
if(objs != null) {
LayoutNode personalLayoutNode = new LayoutNode((Layout)objs[0], node, (Map<String, String>)objs[1]);
layoutConfigableNode.setLayoutNode(personalLayoutNode);
}
node.getChildren().clear();
for(Iterator<?> it = structure.elementIterator(); it.hasNext();){
Element sonElement = (Element) it.next();
if("emptyPortlet".equals(sonElement.getName())) continue;
SubNode son = (SubNode) parseStructure(sonElement, params);
son.setParent(node);
node.getChildren().add(son);
}
}
return node;
}
/**
* 修复门户结构节点的元素。
* 如果元素和默认元素的ID相等,则沿用老的元素Node,并将自定义的参数信息(有的话)覆盖到老的Node参数Map中。
* 如果不相等,则创建一个新的元素Node,并将自定义的参数信息(有的话)覆盖到Node参数Map中。
*
* @param structure
* @param params
* @param node
* @param type
* @param elementNode
* @return
*/
private Object[] repair(Element structure, Map<String, Map<String, String>> params,
SubNode node, String type, AbstractElementNode elementNode) {
Long structureId = Long.valueOf(structure.attributeValue(ID));
Long elementId = Long.valueOf(structure.attributeValue(type.toLowerCase() + "Id"));
Map<String, String> personalElementParams = params.get(structureId + "_" + type + "_" + elementId);
if(elementNode.getId().equals(elementId)){
if(personalElementParams != null) {
elementNode.getParameters().putAll(personalElementParams);
}
return null;
}
else {
IElement element = (IElement) dao.getEntity(elementNode.getElement().getClass(), elementId);
return new Object[]{ element, personalElementParams };
}
}
/**
* 判断门户结构是否为叶子节点。如果是portlet实例的话则返回true。
* @param structure
* @return
*/
private boolean isLeaf(Element structure){
return PORTLETINSTACE_NODE_NAME.equals(structure.getName());
}
/**
* 解析各个元素对应的参数。
* @param paramsNode
* @return
*/
private Map<String, Map<String, String>> parsePersonalParams(Element paramsNode){
Map<String, Map<String, String>> paramsMap = new HashMap<String, Map<String, String>>();
for(Iterator<?> it = paramsNode.elementIterator(PARAM_NODE_NAME); it.hasNext();){
Element paramNode = (Element) it.next();
Map<String, String> paramMap = new HashMap<String, String>();
for(Iterator<?> iter = paramNode.elementIterator(); iter.hasNext();){
Element attrNode = (Element) iter.next();
String text = attrNode.getText();
if( !EasyUtils.isNullOrEmpty(text) ) {
paramMap.put(attrNode.getName(), text);
}
}
String structureId = paramNode.attributeValue(STRUCTURE_ID);
String elementId = paramNode.attributeValue(ELEMENT_ID);
String type = paramNode.attributeValue(ELEMENT_TYPE_NAME);
paramsMap.put(structureId + "_" + type + "_" + elementId, paramMap);
}
return paramsMap;
}
/**
* 将门户结构按页面解析成XML格式。
* @return
*/
public String genetateStructureXML(PageNode page) {
Document doc = new DefaultDocument();
doc.addElement("personal");
Element structureElement = new DefaultElement("structure");
Element paramsElement = new DefaultElement("params");
Element pageElement = doGen(page, paramsElement);
structureElement.add(pageElement);
doc.getRootElement().add(structureElement);
doc.getRootElement().add(paramsElement);
return doc.asXML();
}
private Element doGen(SubNode node, Element paramsElement) {
Element element = new DefaultElement("page");
if(node instanceof PortletInstanceNode){
element = new DefaultElement("portletInstanse");
PortletNode portletNode = ((PortletInstanceNode)node).getPortletNode();
element.addAttribute("portletId", portletNode.getId().toString());
paramsElement.add(genParamNode(portletNode, "portlet"));
}
else {
if(node instanceof SectionNode)
element = new DefaultElement("section");
LayoutNode layoutNode = ((LayoutConfigable)node).getLayoutNode();
element.addAttribute("layoutId", layoutNode.getId().toString());
paramsElement.add(genParamNode(layoutNode, "layout"));
}
element.addAttribute("id", node.getId().toString());
DecoratorNode decoratorNode = ((DecoratorConfigable)node).getDecoratorNode();
element.addAttribute("decoratorId", decoratorNode.getId().toString());
paramsElement.add(genParamNode(decoratorNode, "decorator"));
for(Iterator<?> it = node.getChildren().iterator(); it.hasNext();){
SubNode son = (SubNode) it.next();
element.add(doGen(son, paramsElement));
}
return element;
}
private Element genParamNode(AbstractElementNode node, String type) {
Element element = XMLDocUtil.map2DataNode(node.getParameters(), "param");
element.addAttribute("structureId", node.getParent().getId().toString());
element.addAttribute("elementId", node.getId().toString());
element.addAttribute("class", type);
return element;
}
}