/**
* Copyright 2007-2010 非也
* All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License v3 as published by the Free Software
* Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with this library; if not, see http://www.gnu.org/licenses/lgpl.html.
*
*/
package org.fireflow.webdesigner.transformer;
import java.awt.Dimension;
import java.io.InputStream;
import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.fireflow.model.ModelElement;
import org.fireflow.model.binding.ServiceBinding;
import org.fireflow.model.io.SerializerException;
import org.fireflow.model.servicedef.ServiceDef;
import org.fireflow.pdl.fpdl.diagram.ActivityShape;
import org.fireflow.pdl.fpdl.diagram.CommentShape;
import org.fireflow.pdl.fpdl.diagram.Diagram;
import org.fireflow.pdl.fpdl.diagram.DiagramElement;
import org.fireflow.pdl.fpdl.diagram.EndNodeShape;
import org.fireflow.pdl.fpdl.diagram.GroupShape;
import org.fireflow.pdl.fpdl.diagram.LaneShape;
import org.fireflow.pdl.fpdl.diagram.NodeShape;
import org.fireflow.pdl.fpdl.diagram.PoolShape;
import org.fireflow.pdl.fpdl.diagram.ProcessNodeShape;
import org.fireflow.pdl.fpdl.diagram.RouterShape;
import org.fireflow.pdl.fpdl.diagram.StartNodeShape;
import org.fireflow.pdl.fpdl.diagram.figure.Figure;
import org.fireflow.pdl.fpdl.diagram.figure.part.Bounds;
import org.fireflow.pdl.fpdl.diagram.figure.part.BoundsImpl;
import org.fireflow.pdl.fpdl.diagram.figure.part.Point;
import org.fireflow.pdl.fpdl.io.FPDLNames;
import org.fireflow.pdl.fpdl.process.Activity;
import org.fireflow.pdl.fpdl.process.EndNode;
import org.fireflow.pdl.fpdl.process.Router;
import org.fireflow.pdl.fpdl.process.StartNode;
import org.fireflow.pdl.fpdl.process.Synchronizer;
import org.fireflow.pdl.fpdl.process.WorkflowProcess;
import org.fireflow.pdl.fpdl.process.features.Feature;
import org.fireflow.pdl.fpdl.process.features.endnode.NormalEndFeature;
import org.fireflow.pdl.fpdl.process.features.endnode.ThrowCompensationFeature;
import org.fireflow.pdl.fpdl.process.features.endnode.ThrowFaultFeature;
import org.fireflow.pdl.fpdl.process.features.endnode.ThrowTerminationFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.AndJoinAndSplitRouterFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.CustomizedRouterFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.DefaultRouterFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.OrJoinOrSplitRouterFeature;
import org.fireflow.pdl.fpdl.process.features.router.impl.XOrJoinXOrSplitRouterFeature;
import org.fireflow.pdl.fpdl.process.features.startnode.CatchCompensationFeature;
import org.fireflow.pdl.fpdl.process.features.startnode.CatchFaultFeature;
import org.fireflow.pdl.fpdl.process.features.startnode.TimerStartFeature;
import org.fireflow.pdl.fpdl.process.features.startnode.WebserviceStartFeature;
import org.w3c.dom.Document;
/**
*
* @author 非也 nychen2000@163.com
* Fire Workflow 官方网站:www.firesoa.com 或者 www.fireflow.org
*
*/
public abstract class AbstractFpdlDiagramSerializer implements
FpdlDiagramSerializer {
private Log log = LogFactory.getLog(AbstractFpdlDiagramSerializer.class);
protected static DocumentBuilderFactory factory = DocumentBuilderFactory
.newInstance();
protected static final int IconTextGap = 5;
protected static final int IMG_RADIUS = 16;
protected static final int SVC_LOGO_RADIUS = 8;
protected static final int DEFAULT_FONT_SIZE = 12;
protected static final int GROUP_TITLE_HEIGHT = 20;
protected static final int POOL_LANE_TITLE_HEIGHT = 32;
protected static final String TYPE = "element_"+FPDLNames.TYPE;
protected static final String ON_CLICK_HANDLER = "on_element_click";
protected static final String DEFAULT_DOT_DASHARRAY = "1 2";
protected static final String DEFAULT_DASH_DASHARRAY = "5 4";
protected static final String DEFAULT_DOTDASH_DASHARRAY = "2 4 5 4";
protected static final String DEFAULT_GROUP_DASHARRAY = "3 2";
protected static final String DEFAULT_ASSOC_DASHARRAY = DEFAULT_DASH_DASHARRAY;
protected static final String DEFAULT_MESSAGEFLOW_DASHARRAY = DEFAULT_DASH_DASHARRAY;
protected static final float PT_2_PX_RATE = 1.8f;
protected static final Map<String,String> SERVICE_LOGO_CACHE = new HashMap<String,String>();
protected WorkflowProcess workflowProcess = null;
protected String subProcessName = null;
protected Document document = null;
protected Diagram diagram = null;
protected int leftTopX = 0;//左上角x
protected int leftTopY = 0;//左上角y
protected int rightDownX = 0;//右下角x
protected int rightDownY = 0;//右下角y
protected String resourcePathPrefix = null;
protected void _refreshDiagramSize(Bounds bounds){
if (bounds.getX()<this.leftTopX){
this.leftTopX = bounds.getX();
}
if (bounds.getY()<this.leftTopY){
this.leftTopY = bounds.getY();
}
int x = bounds.getX()+bounds.getWidth();
int y = bounds.getY()+bounds.getHeight();
if (x>this.rightDownX){
this.rightDownX = x;
}
if (y>this.rightDownY){
this.rightDownY = y;
}
}
protected void _refreshDiagramSize(List<Point> pointList){
if (pointList==null || pointList.size()==0){
for (Point p : pointList){
if (p.getX()<this.leftTopX){
this.leftTopX = p.getX();
}
if (p.getX()>this.rightDownX){
this.rightDownX = p.getX();
}
if (p.getY()<this.leftTopY){
this.leftTopY = p.getY();
}
if (p.getY()>this.rightDownY){
this.rightDownY = p.getY();
}
}
}
}
protected Point _calculateAnchor(NodeShape nodeShape,Bounds nodeBounds,Point refPoint){
Point boundsCenter = new Point();
boundsCenter.setX(nodeBounds.getX()+nodeBounds.getWidth()/2);
boundsCenter.setY(nodeBounds.getY()+nodeBounds.getHeight()/2);
if (nodeShape instanceof StartNodeShape || nodeShape instanceof EndNodeShape){
Point anchor = _calculateStartNodeEndNodeAnchor(nodeBounds,boundsCenter,refPoint);
return anchor;
}
if (nodeShape instanceof ActivityShape
|| nodeShape instanceof CommentShape
|| nodeShape instanceof PoolShape
|| nodeShape instanceof LaneShape){
Point anchor = _calculateChopboxAnchor(nodeBounds,boundsCenter,refPoint);
return anchor;
}
else if (nodeShape instanceof RouterShape){
Point anchor = _calculateRouterAnchor(nodeBounds,boundsCenter,refPoint);
return anchor;
}
//测试用,直接返回bounds的中心
return boundsCenter;
}
protected Point _calculateRouterAnchor(Bounds r,Point center,Point reference){
float centerX = center.getX();
float centerY = center.getY();
if (r.getWidth()<=0 || r.getHeight()<=0
|| (reference.getX() == (int) centerX && reference.getY() == (int) centerY))
return new Point((int) centerX, (int) centerY); // This avoids
// divide-by-zero
//误差忽略
Point ref = new Point();
ref.setX(reference.getX()-center.getX());
ref.setY(reference.getY()-center.getY());
if (Math.abs(ref.getX()) <= 1)//允许有1像素误差
return new Point(reference.getX(), (ref.getY() > 0) ? r.getY()+r.getHeight() : r.getY());
if (Math.abs(ref.getY()) <= 1)//允许有1像素误差
return new Point((ref.getX() > 0) ? r.getX()+r.getWidth() : r.getX(), reference.getY());
float dx = reference.getX() - centerX;
float dy = reference.getY() - centerY;
if (dy==0){
if (dx>0){//right
Point result = new Point();
result.setX(r.getX()+r.getWidth());
result.setY(r.getY()+r.getHeight()/2);
return result;
}
else{//left
Point result = new Point();
result.setX(r.getX());
result.setY(r.getY()+r.getHeight()/2);
return result;
}
}
if (dx==0){
if (dy>0){//bottom
Point result = new Point();
result.setX(r.getX()+r.getWidth()/2);
result.setY(r.getY()+r.getHeight());
return result;
}else {
Point result = new Point();
result.setX(r.getX()+r.getWidth()/2);
result.setY(r.getY());
return result;
}
}
float scale = Math.abs(dx/dy);
float ddy = 0.5f*r.getWidth() / (scale+1);
float ddx = Math.abs(scale*ddy);
if (dx>=0 && dy>=0){
Point result = new Point();
result.setX((int)(centerX+ddx));
result.setY((int)(centerY+ddy));
return result;
}
else if (dx<=0 && dy<=0){
Point result = new Point();
result.setX((int)(centerX-ddx));
result.setY((int)(centerY-ddy));
return result;
}
else if (dx>=0 && dy<=0){
Point result = new Point();
result.setX((int)(centerX+ddx));
result.setY((int)(centerY-ddy));
return result;
}
else {
Point result = new Point();
result.setX((int)(centerX-ddx));
result.setY((int)(centerY+ddy));
return result;
}
}
protected Point _getLabelAbsolutePosition(Point fromAnchor,Point toAnchor,List<Point> linePoints,Point relativePos){
Point result = new Point();
Point centerP = null;
if (linePoints!=null && linePoints.size()>0){
if ((linePoints.size() % 2)==1){
int index = (linePoints.size()-1)/2;
centerP = linePoints.get(index);
}else{
int index = (linePoints.size())/2;
Point p1 = linePoints.get(index-1);
Point p2 = linePoints.get(index);
centerP = new Point();
centerP.setX((p1.getX()+p2.getX())/2);
centerP.setY((p1.getY()+p2.getY())/2);
}
}else{
centerP = new Point();
centerP.setX((fromAnchor.getX()+toAnchor.getX())/2);
centerP.setY((fromAnchor.getY()+toAnchor.getY())/2);
}
result.setX(centerP.getX()+relativePos.getX());
result.setY(centerP.getY()+relativePos.getY());
return result;
}
protected Point _calculateChopboxAnchor(Bounds r,Point center,Point reference){
r.setX(r.getX()-1);
r.setY(r.getY()-1);
r.setWidth(r.getWidth()+1);
r.setHeight(r.getHeight()+1);
float centerX = center.getX();
float centerY = center.getY();
if (r.getWidth() <= 0 || r.getHeight() <= 0
|| (reference.getX() == (int) centerX && reference.getY() == (int) centerY))
return new Point((int) centerX, (int) centerY); // This avoids
//误差忽略
Point ref = new Point();
ref.setX(reference.getX()-center.getX());
ref.setY(reference.getY()-center.getY());
if (Math.abs(ref.getX()) <= 1)//允许有1像素误差
return new Point(reference.getX(), (ref.getY() > 0) ? r.getY()+r.getHeight() : r.getY());
if (Math.abs(ref.getY()) <= 1)//允许有1像素误差
return new Point((ref.getX() > 0) ? r.getX()+r.getWidth() : r.getX(), reference.getY());
// divide-by-zero
float dx = reference.getX() - centerX;
float dy = reference.getY() - centerY;
// r.width, r.height, dx, and dy are guaranteed to be non-zero.
float scale = 0.5f / Math.max(Math.abs(dx) / r.getWidth(), Math.abs(dy)
/ r.getHeight());
dx *= scale;
dy *= scale;
centerX += dx;
centerY += dy;
return new Point(Math.round(centerX), Math.round(centerY));
}
protected Point _calculateStartNodeEndNodeAnchor(Bounds r,Point center,Point reference){
Point ref = new Point();
ref.setX(reference.getX()-center.getX());
ref.setY(reference.getY()-center.getY());
//Point ref = r.getCenter().negate().translate(reference);
if (Math.abs(ref.getX()) <= 1)//允许有1像素误差
return new Point(reference.getX(), (ref.getY() > 0) ? r.getY()+r.getHeight() : r.getY());
if (Math.abs(ref.getY()) <= 1)//允许有1像素误差
return new Point((ref.getX() > 0) ? r.getX()+r.getWidth() : r.getX(), reference.getY());
float dx = (ref.getX() > 0) ? 0.5f : -0.5f;
float dy = (ref.getY() > 0) ? 0.5f : -0.5f;
// ref.x, ref.y, r.width, r.height != 0 => safe to proceed
float k = (float) (ref.getY() * r.getWidth()) / (ref.getX() * r.getHeight());
k = k * k;
int ddx = (int) (r.getWidth() * dx / Math.sqrt(1 + k));
int ddy = (int) (r.getHeight() * dy / Math.sqrt(1 + 1 / k));
Point result = new Point();
result.setX(center.getX()+ddx);
result.setY(center.getY()+ddy);
return result;
}
protected Bounds _getAbsoluteBounds(DiagramElement diagramElm){
//TODO 针对Activity的边事件,需要优化
//TODO 可能需要特殊处理
Bounds result = null;
Bounds original = null;
if (diagramElm instanceof LaneShape){
LaneShape argLane = (LaneShape)diagramElm;
original = new BoundsImpl();
original.setX(0);
original.setY(0);
original.setWidth(0);
original.setHeight(0);
PoolShape poolShape = (PoolShape)diagramElm.getParent();
List<DiagramElement> allLanes = poolShape.getChildren();
for (DiagramElement tmpElm : allLanes){
LaneShape lane = (LaneShape)tmpElm;
Bounds tmpBounds = lane.getFigure().getBounds();
if (argLane.equals(lane)){
original.setWidth(tmpBounds.getWidth()-tmpBounds.getThick()*2);
original.setHeight(tmpBounds.getHeight()-tmpBounds.getThick()*2);
break;
}else{
if (Diagram.VERTICAL.equals(diagram.getDirection())){
original.setX(original.getX()+tmpBounds.getWidth());
}else{
original.setY(original.getY()+tmpBounds.getHeight());
}
}
}
result = original;
}else if (diagramElm instanceof StartNodeShape
|| diagramElm instanceof EndNodeShape
|| diagramElm instanceof RouterShape){
original = diagramElm.getFigure()==null?null:diagramElm.getFigure().getBounds();
if (original==null){
log.warn("NodeShape[id="+diagramElm.getId()+"]的bounds信息为空,无法将bounds坐标转换成绝对值。");
return null;
}
result = original.copy();
}else{
original = diagramElm.getFigure()==null?null:diagramElm.getFigure().getBounds();
if (original==null){
log.warn("NodeShape[id="+diagramElm.getId()+"]的bounds信息为空,无法将bounds坐标转换成绝对值。");
return null;
}
result = original.copy();
result.setX(result.getX()+result.getThick());
result.setY(result.getY()+result.getThick());
result.setWidth(result.getWidth()-result.getThick()*2);
result.setHeight(result.getHeight()-result.getThick()*2);
}
DiagramElement parent = diagramElm.getParent();
if (parent==null){
return result;
}else{
Bounds parentBounds = _getAbsoluteBounds(parent);
if (parentBounds!=null){
if (parent instanceof GroupShape){
result.setX(parentBounds.getX()+result.getX());
result.setY(parentBounds.getY()+result.getY()+(GROUP_TITLE_HEIGHT-parentBounds.getThick()));
}
else if ((parent instanceof LaneShape) || (parent instanceof PoolShape)){
if (Diagram.VERTICAL.equals(diagram.getDirection())){
result.setX(parentBounds.getX()+result.getX());
result.setY(parentBounds.getY()+result.getY()+(POOL_LANE_TITLE_HEIGHT-parentBounds.getThick()));
}else{
result.setX(parentBounds.getX()+result.getX()+(POOL_LANE_TITLE_HEIGHT-parentBounds.getThick()));
result.setY(parentBounds.getY()+result.getY());
}
}
else if (parent instanceof ActivityShape){//边事件
ActivityShape actShape = (ActivityShape)parent;
Bounds actBounds = actShape.getFigure().getBounds();
result.setX((parentBounds.getX()-parentBounds.getThick())+result.getX());
result.setY(parentBounds.getY()+(actBounds.getHeight()-parentBounds.getThick()-IMG_RADIUS)+result.getY());
}
else{
result.setX(parentBounds.getX()+result.getX());
result.setY(parentBounds.getY()+result.getY());
}
}
}
return result;
}
protected String _getSynchronizerNodeImgUri(ProcessNodeShape nodeShape){
ModelElement modelElm = nodeShape.getWorkflowElementRef();
Synchronizer node = (Synchronizer)modelElm;
Feature f = node.getFeature();
String uri = null;
//图形
if (node instanceof StartNode){
if (f==null){
uri="/org/fireflow/webdesigner/resources/images/obj32/empty_start_event.png";
}else if (f instanceof TimerStartFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/timer_start_event.png";
}else if (f instanceof WebserviceStartFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/message_start_event.png";
}
else if ((f instanceof CatchFaultFeature) ){
uri="/org/fireflow/webdesigner/resources/images/obj32/error_start_event.png";
}else if (f instanceof CatchCompensationFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/compensation_start_event.png";
}
else {
uri="/org/fireflow/webdesigner/resources/images/obj32/empty_start_event.png";
}
}else if (node instanceof EndNode){
if (f==null){
uri="/org/fireflow/webdesigner/resources/images/obj32/end_none_event.png";
}
else if (f instanceof NormalEndFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/end_none_event.png";
}
else if (f instanceof ThrowFaultFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/end_error_event.png";
}
else if (f instanceof ThrowCompensationFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/end_compensation_event.png";
}
else if (f instanceof ThrowTerminationFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/end_terminate_event.png";
}else{
uri="/org/fireflow/webdesigner/resources/images/obj32/end_none_event.png";
}
}else if (node instanceof Router){
if (f==null){
uri="/org/fireflow/webdesigner/resources/images/obj32/empty_gateway.png";
}
else if (f instanceof AndJoinAndSplitRouterFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/parallel_gateway.png";
}else if (f instanceof OrJoinOrSplitRouterFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/inclusive_gateway.png";
}else if (f instanceof XOrJoinXOrSplitRouterFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/exclusive_gateway_2.jpg";
}else if (f instanceof CustomizedRouterFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/complex_gateway.png";
}else if (f instanceof DefaultRouterFeature){
uri="/org/fireflow/webdesigner/resources/images/obj32/empty_gateway.png";
}else{
uri="/org/fireflow/webdesigner/resources/images/obj32/empty_gateway.png";
}
}
return uri;
}
/**
* fontSize的单位是pt
* @param text
* @param fontSize
* @return
*/
protected Dimension _calculateFontSize(String text,int fontSize){
if (text==null || text.equals("")){
return new Dimension(0,0);
}else{
int length = text.length();
return new Dimension((int)(fontSize*PT_2_PX_RATE*length),(int)(fontSize*PT_2_PX_RATE));
}
}
/**
* 在待处理的diagram element的外围构造一个<group>节点,当做该图形对象的view port
* @param diagramElm
* @return
*/
protected Bounds _getViewPortBounds(DiagramElement diagramElm){
Figure figure = diagramElm.getFigure();
ModelElement wfElm = diagramElm.getWorkflowElementRef();
int fontSize=DEFAULT_FONT_SIZE;
if (figure.getTitleLabel()!=null){
fontSize = figure.getTitleLabel().getFontSize();
}
if (wfElm instanceof StartNode ||
wfElm instanceof EndNode ||
wfElm instanceof Router){
String displayName = wfElm.getDisplayName();
/*
* 对于这些节点,当displayName为空时,不需要取值name,因为displayname为空时,界面上也显示空,而不是显示name
if(displayName==null || displayName.trim().equals("")){
displayName = nodeWrapper.getName();
}
*/
// 计算bounds
Dimension dimension = null;
dimension = _calculateFontSize(displayName,fontSize);
dimension.width = dimension.width+4;//加上一个余量,以便字体可以显示完全
Bounds bounds = figure.getBounds().copy();
if (dimension.width > 0) {
//高度
bounds.setHeight(bounds.getHeight() + IconTextGap+dimension.height);
if (dimension.width > bounds.getWidth()) {
int oldWidth = bounds.getWidth();
bounds.setWidth(dimension.width);
int newX = bounds.getX()-((dimension.width - oldWidth) / 2);
bounds.setX(newX);
}
}
return bounds;
}
else if (wfElm instanceof Activity){
Activity activity = (Activity)wfElm;
//计算Activity的bounds,宽度暂时限制在Activity本身的宽度之内
Bounds bounds = figure.getBounds().copy();
bounds.setHeight(bounds.getHeight()+IMG_RADIUS+DEFAULT_FONT_SIZE+IconTextGap);
return bounds;
}
else{
Bounds bounds = figure.getBounds().copy();
return bounds;
}
}
protected void _init(WorkflowProcess workflowProcess,
String subProcessName) throws SerializerException {
this.workflowProcess = workflowProcess;
this.subProcessName = subProcessName;
try {
String subProcessId = this.workflowProcess.getId()+WorkflowProcess.ID_SEPARATOR+this.subProcessName;
_checkDiagram(this.workflowProcess, this.subProcessName);
diagram = this.workflowProcess.getDiagramBySubProcessId(subProcessId);
DocumentBuilder docBuilder = factory.newDocumentBuilder();
document = docBuilder.newDocument();
} catch (ParserConfigurationException e) {
throw new SerializerException(e);
}
}
protected String _makePointsSeq(Point fromAnchor,Point toAnchor,List<Point> pointList){
//如果linePoints为空,且fromAnchor与toAnchor的坐标仅相差一个像素的情况下进行在矫正
if (Math.abs(fromAnchor.getX()-toAnchor.getX())<=1){
fromAnchor.setX(toAnchor.getX());
}
if (Math.abs(fromAnchor.getY()-toAnchor.getY())<=1){
fromAnchor.setY(toAnchor.getY());
}
StringBuffer pointSeqBuf = new StringBuffer();
pointSeqBuf.append(fromAnchor.getX()).append(",").append(fromAnchor.getY()).append(" ");
if (pointList!=null && pointList.size()>0){
for (Point p : pointList){
pointSeqBuf.append(p.getX()).append(",").append(p.getY()).append(" ");
}
}
pointSeqBuf.append(toAnchor.getX()).append(",").append(toAnchor.getY());
return pointSeqBuf.toString();
}
/**
* 检查流程定义中是否有diagram信息,如果没有则构造一个缺省的diagram
*
* @param process
* @param subProcessName
*/
protected void _checkDiagram(WorkflowProcess process, String subProcessId) {
// TODO
}
protected String _getActivityImgUri(Activity activity){
ServiceBinding serviceBinding = activity.getServiceBinding();
if (serviceBinding==null)return null;
String serviceId = serviceBinding.getServiceId();
ServiceDef serviceDef = this.workflowProcess.getService(serviceId);
if (serviceDef==null){
return null;
}
String svcClassName = serviceDef.getClass().getName();
String pngUri = SERVICE_LOGO_CACHE.get(svcClassName);
if (pngUri==null){
pngUri = "/"+svcClassName.replaceAll("\\.", "/")+".png";
InputStream inStream = this.getClass().getResourceAsStream(pngUri);
if (inStream!=null){
SERVICE_LOGO_CACHE.put(svcClassName, pngUri);
return pngUri;
}else{
SERVICE_LOGO_CACHE.put(svcClassName, "_LOGO_NOT_FOUND_");
return null;
}
}else if (pngUri.equals("_LOGO_NOT_FOUND_")){
return null;
}else{
return pngUri;
}
}
public void setResourcePathPrefix(String s){
this.resourcePathPrefix = s;
}
public String serializeDiagramToStr(WorkflowProcess workflowProcess,
String subProcessName,String encoding,boolean omitXmlDeclaration) {
try
{
Document doc = this.serializeDiagramToDoc(workflowProcess, subProcessName);
Transformer tf = TransformerFactory.newInstance().newTransformer();
if (omitXmlDeclaration){
tf.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
}
tf.setOutputProperty(OutputKeys.ENCODING, encoding);
tf.setOutputProperty(OutputKeys.INDENT,"yes");
tf.setOutputProperty(
"{http://xml.apache.org/xslt}indent-amount", "2");
StreamResult dest = new StreamResult(new StringWriter());
tf.transform(new DOMSource(doc), dest);
return dest.getWriter().toString();
}
catch (Exception e)
{
//TODO 记录日志
e.printStackTrace();
}
return "";
}
}