/****************************************************************************** * Copyright (c) 2010-2013, Linagora * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Linagora - initial API and implementation *******************************************************************************/ package com.ebmwebsourcing.petals.services.eip.designer; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.Status; import org.eclipse.draw2d.geometry.Point; import com.ebmwebsourcing.petals.services.eip.PetalsEipPlugin; import com.ebmwebsourcing.petals.services.eip.designer.model.AbstractNode; import com.ebmwebsourcing.petals.services.eip.designer.model.EIPtype; import com.ebmwebsourcing.petals.services.eip.designer.model.EipChain; import com.ebmwebsourcing.petals.services.eip.designer.model.EipConnection; import com.ebmwebsourcing.petals.services.eip.designer.model.EipNode; import com.ebmwebsourcing.petals.services.eip.designer.model.EipProperty; import com.ebmwebsourcing.petals.services.eip.designer.model.Endpoint; /** * A class in charge of serializing and de-serializing EIP chains. * @author Vincent Zurczak - EBM WebSourcing */ public final class EipDesignerSerializer { /** * The unique instance of this class. */ public static final EipDesignerSerializer INSTANCE = new EipDesignerSerializer(); public static final String SERIAL_ID = "serial.id"; public static final String CURRENT_SERIAL_ID = "1.0"; public static final String CHAIN_TITLE = "chain.title"; private static final String CHAIN_DESC = "chain.description"; private static final String CHAIN_VERSION = "chain.version"; private static final String CONNECTIONS = "chain.connections"; private static final String EIPS = "chain.eips"; private static final String ENDPOINTS = "chain.endpoints"; private static final String CONN_PREFIX = "c."; private static final String CONN_TARGET = ".target"; private static final String CONN_CONDITION_NAME = ".condition.name"; private static final String CONN_CONDITION_VALUE = ".condition.value"; private static final String CONN_CONSUMED_OPERATION = ".consume.operation"; private static final String CONN_CONSUMED_MEP = ".consume.mep"; private static final String CONN_CONSUME_ITF = ".consume.itf"; private static final String CONN_CONSUME_SRV = ".consume.srv"; private static final String CONN_CONSUME_EDPT = ".consume.edpt"; private static final String SRV_NAME = "service.name"; private static final String SRV_NS = "service.namespace"; private static final String ITF_NAME = "interface.name"; private static final String ITF_NS = "interface.namespace"; private static final String EDPT_NAME = "endpoint.name"; private static final String WSDL_URI = "wsdl.location"; private static final String EIP_TYPE = "pattern"; private static final String OUTGOING_CONNECTIONS = "outgoing.connections"; private static final String LOCATION_X = "location.x"; private static final String LOCATION_Y = "location.y"; /** * Constructor. */ private EipDesignerSerializer() { // nothing } /** * Writes an EIP chain in an output stream. * @param stream an output stream to write in (closed after having been written) * @param eipChain the EIP chain to save (not null) * @throws IOException if something went wrong */ public void write( OutputStream stream, EipChain eipChain ) throws IOException { // 1. Build a properties object Properties properties = new Properties(); properties.setProperty( SERIAL_ID, CURRENT_SERIAL_ID ); // General properties if( eipChain.getTitle() != null ) properties.setProperty( CHAIN_TITLE, eipChain.getTitle()); if( eipChain.getDescription() != null ) properties.setProperty( CHAIN_DESC, eipChain.getDescription()); if( eipChain.getVersion() != null ) properties.setProperty( CHAIN_VERSION, eipChain.getVersion()); // Connections StringBuilder sb = new StringBuilder(); for( Iterator<EipConnection> it = eipChain.getConnections().iterator(); it.hasNext(); ) { EipConnection conn = it.next(); // ID sb.append( conn.getId()); if( it.hasNext()) sb.append( ", " ); // Properties of the connection // The only required is the target (helps to set the incoming connection). // Outgoing connections of EIPs will be used to define sources. properties.setProperty( CONN_PREFIX + conn.getId() + CONN_TARGET, String.valueOf( conn.getTarget().getId())); properties.setProperty( CONN_PREFIX + conn.getId() + CONN_CONSUME_EDPT, String.valueOf( conn.isConsumeEdpt())); properties.setProperty( CONN_PREFIX + conn.getId() + CONN_CONSUME_ITF, String.valueOf( conn.isConsumeItf())); properties.setProperty( CONN_PREFIX + conn.getId() + CONN_CONSUME_SRV, String.valueOf( conn.isConsumeSrv())); properties.setProperty( CONN_PREFIX + conn.getId() + CONN_CONSUMED_MEP, String.valueOf( conn.getConsumeMep())); properties.setProperty( CONN_PREFIX + conn.getId() + CONN_CONSUMED_OPERATION, String.valueOf( conn.getConsumeOperation())); if( conn.shouldHaveCondition()) { if( conn.getConditionExpression() != null ) { properties.setProperty( CONN_PREFIX + conn.getId() + CONN_CONDITION_VALUE, conn.getConditionExpression()); } if( conn.getConditionName() != null ) { properties.setProperty( CONN_PREFIX + conn.getId() + CONN_CONDITION_NAME, conn.getConditionName()); } } } properties.setProperty( CONNECTIONS, sb.toString()); // End-points sb = new StringBuilder(); for( Iterator<Endpoint> it = eipChain.getEndpoints().iterator(); it.hasNext(); ) { // List all the end-points Endpoint edpt = it.next(); sb.append( edpt.getId()); if( it.hasNext()) sb.append( ", " ); // Store the properties of every end-point String key = edpt.getId() + "."; if( edpt.getServiceName() != null ) properties.setProperty( key + SRV_NAME, edpt.getServiceName()); if( edpt.getServiceNamespace() != null ) properties.setProperty( key + SRV_NS, edpt.getServiceNamespace()); if( edpt.getInterfaceName() != null ) properties.setProperty( key + ITF_NAME, edpt.getInterfaceName()); if( edpt.getInterfaceNamespace() != null ) properties.setProperty( key + ITF_NS, edpt.getInterfaceNamespace()); if( edpt.getEndpointName() != null ) properties.setProperty( key + EDPT_NAME, edpt.getEndpointName()); // Store the location properties.setProperty( key + LOCATION_X, String.valueOf( edpt.getLocation().x )); properties.setProperty( key + LOCATION_Y, String.valueOf( edpt.getLocation().y )); } properties.setProperty( ENDPOINTS, sb.toString()); // EIPs sb = new StringBuilder(); for( Iterator<EipNode> it = eipChain.getEipNodes().iterator(); it.hasNext(); ) { // List all the end-points EipNode eip = it.next(); sb.append( eip.getId()); if( it.hasNext()) sb.append( ", " ); // Store the properties of every EIP String key = eip.getId() + "."; if( eip.getServiceName() != null ) properties.setProperty( key + SRV_NAME, eip.getServiceName()); if( eip.getServiceNamespace() != null ) properties.setProperty( key + SRV_NS, eip.getServiceNamespace()); if( eip.getInterfaceName() != null ) properties.setProperty( key + ITF_NAME, eip.getInterfaceName()); if( eip.getInterfaceNamespace() != null ) properties.setProperty( key + ITF_NS, eip.getInterfaceNamespace()); if( eip.getEndpointName() != null ) properties.setProperty( key + EDPT_NAME, eip.getEndpointName()); if( eip.getWsdlUri() != null ) properties.setProperty( key + WSDL_URI, eip.getWsdlUri().toString()); // Store the specific properties properties.setProperty( key + EIP_TYPE, eip.getEipType().toString()); for( EipProperty property : eip.getSupportedProperties()) { String value = eip.getProperties().get( property ); if( value != null ) properties.setProperty( key + property, value ); } // Store the outgoing connections StringBuilder sbConn = new StringBuilder(); for( Iterator<EipConnection> itConn = eip.getOutgoingConnections().iterator(); itConn.hasNext(); ) { sbConn.append( itConn.next().getId()); if( itConn.hasNext()) sbConn.append( ", " ); } properties.setProperty( key + OUTGOING_CONNECTIONS, sbConn.toString()); // Store the location properties.setProperty( key + LOCATION_X, String.valueOf( eip.getLocation().x )); properties.setProperty( key + LOCATION_Y, String.valueOf( eip.getLocation().y )); } properties.setProperty( EIPS, sb.toString()); // 2. Serialize the properties try { properties.store( stream, "EIP Diagram - Created by Petals Studio" ); } finally { if( stream != null ) stream.close(); } } /** * Writes an EIP chain in a file. * @param outputFile the output file (may not exist, overwritten otherwise) * @param eipChain the EIP chain to save (not null) * @throws IOException if something went wrong */ public void write( File outputFile, EipChain eipChain ) throws IOException { if( ! outputFile.exists() && ! outputFile.createNewFile()) throw new IOException( outputFile.getAbsolutePath() + " could not be created." ); FileOutputStream fos = new FileOutputStream( outputFile ); write( fos, eipChain ); } /** * Reads an EIP file and builds an EIP chain from its content. * @param stream the input stream to read (closed after having been read) * @param inputName the name of the stream to display if an error must be logged * @return an EIP chain * @throws IOException if something went wrong */ public EipChain read( InputStream stream, String inputName ) throws IOException { // 1. Load the properties file Properties properties = new Properties(); try { properties.load( stream ); } finally { if( stream != null ) stream.close(); } // 2. Create a new EIP chain from these properties String title = properties.getProperty( CHAIN_TITLE ); String description = properties.getProperty( CHAIN_DESC ); String version = properties.getProperty( CHAIN_VERSION ); EipChain chain = new EipChain(); chain.setTitle( title ); chain.setDescription( description ); chain.setVersion( version ); Map<Integer,AbstractNode> idToNode = new HashMap<Integer,AbstractNode> (); List<IStatus> readingWarnings = new ArrayList<IStatus> (); int maxNodeId = 0, maxConnId = 0; // Read end-points String value = properties.getProperty( ENDPOINTS ); if( value != null ) { for( String part : value.split( "," )) { part = part.trim(); if( part.length() == 0 ) continue; // Create the end-point int id = Integer.valueOf( part ); if( id > maxNodeId ) maxNodeId = id; Endpoint edpt = new Endpoint( id ); chain.simplyAddEndpoint( edpt ); edpt.setEipChain( chain ); idToNode.put( id, edpt ); // Read and set its properties edpt.setServiceName( properties.getProperty( id + "." + SRV_NAME )); edpt.setServiceNamespace( properties.getProperty( id + "." + SRV_NS )); edpt.setInterfaceName( properties.getProperty( id + "." + ITF_NAME )); edpt.setInterfaceNamespace( properties.getProperty( id + "." + ITF_NS )); edpt.setEndpointName( properties.getProperty( id + "." + EDPT_NAME )); // Get the location String loc = properties.getProperty( id + "." + LOCATION_X, null ); if( loc != null ) { int x = Integer.valueOf( loc ); loc = properties.getProperty( id + "." + LOCATION_Y, null ); if( loc != null ) { int y = Integer.valueOf( loc ); edpt.setLocation( new Point( x, y )); } } } } // Read EIPs value = properties.getProperty( EIPS ); Map<EipNode,String> eipToOutgoingConnections = new HashMap<EipNode,String> (); if( value != null ) { for( String part : value.split( "," )) { part = part.trim(); if( part.length() == 0 ) continue; // Create the end-point int id = Integer.valueOf( part ); if( id > maxNodeId ) maxNodeId = id; String eipType = properties.getProperty( id + "." + EIP_TYPE ); if( eipType == null ) { String msg = "The pattern could not be found for the EIP with ID " + id + "."; readingWarnings.add( new Status( IStatus.WARNING, PetalsEipPlugin.PLUGIN_ID, msg )); continue; } EipNode eip = new EipNode( id, EIPtype.valueOf( eipType )); chain.simplyAddEipNode( eip ); eip.setEipChain( chain ); idToNode.put( id, eip ); String outgoingConnections = properties.getProperty( id + "." + OUTGOING_CONNECTIONS ); if( outgoingConnections == null ) outgoingConnections = ""; eipToOutgoingConnections.put( eip, outgoingConnections ); // Read and set its properties eip.setServiceName( properties.getProperty( id + "." + SRV_NAME )); eip.setServiceNamespace( properties.getProperty( id + "." + SRV_NS )); eip.setInterfaceName( properties.getProperty( id + "." + ITF_NAME )); eip.setInterfaceNamespace( properties.getProperty( id + "." + ITF_NS )); eip.setEndpointName( properties.getProperty( id + "." + EDPT_NAME )); eip.setWsdlUri( properties.getProperty( id + "." + WSDL_URI )); // Get the specific properties for( EipProperty property : eip.getSupportedProperties()) { value = properties.getProperty( id + "." + property.toString()); if( value != null ) eip.setEipProperty( property, value ); } // Get the location String loc = properties.getProperty( id + "." + LOCATION_X, null ); if( loc != null ) { int x = Integer.valueOf( loc ); loc = properties.getProperty( id + "." + LOCATION_Y, null ); if( loc != null ) { int y = Integer.valueOf( loc ); eip.setLocation( new Point( x, y )); } } } } // Read connections Map<Integer,EipConnection> idToConnection = new HashMap<Integer,EipConnection> (); value = properties.getProperty( CONNECTIONS ); if( value != null ) { for( String part : value.split( "," )) { part = part.trim(); if( part.length() == 0 ) continue; int id = Integer.valueOf( part ); if( id > maxConnId ) maxConnId = id; String targetIdAsString = properties.getProperty( CONN_PREFIX + id + CONN_TARGET ); int targetId = targetIdAsString == null ? -1 : Integer.parseInt( targetIdAsString ); AbstractNode target = idToNode.get( targetId ); if( target == null ) { String msg = "No node could be resolved for the connection's target " + targetId + "."; readingWarnings.add( new Status( IStatus.WARNING, PetalsEipPlugin.PLUGIN_ID, msg )); continue; } EipConnection conn = new EipConnection( id, null, target ); conn.connect(); idToConnection.put( id, conn ); conn.setConditionExpression( properties.getProperty( CONN_PREFIX + id + CONN_CONDITION_VALUE )); conn.setConditionName( properties.getProperty( CONN_PREFIX + id + CONN_CONDITION_NAME )); String val = properties.getProperty( CONN_PREFIX + id + CONN_CONSUMED_MEP ); conn.setConsumeMep( "null".equals( val ) ? null : val ); val = properties.getProperty( CONN_PREFIX + id + CONN_CONSUMED_OPERATION ); conn.setConsumeOperation( "null".equals( val ) ? null : val ); Boolean b = Boolean.valueOf( properties.getProperty( CONN_PREFIX + id + CONN_CONSUME_EDPT )); conn.setConsumeEdpt( b ); b = Boolean.valueOf( properties.getProperty( CONN_PREFIX + id + CONN_CONSUME_ITF )); conn.setConsumeItf( b ); b = Boolean.valueOf( properties.getProperty( CONN_PREFIX + id + CONN_CONSUME_SRV )); conn.setConsumeSrv( b ); } } // Handle the outgoing connections of the EIPs for( Map.Entry<EipNode,String> entry : eipToOutgoingConnections.entrySet()) { for( String part : entry.getValue().split( "," )) { part = part.trim(); if( part.length() == 0 ) continue; int id = Integer.parseInt( part ); EipConnection conn = idToConnection.get( id ); if( conn == null ) { String msg = "No outgoing connection with the ID " + id + " could be resolved for the EIP " + entry.getKey().getId() + "."; readingWarnings.add( new Status( IStatus.WARNING, PetalsEipPlugin.PLUGIN_ID, msg )); continue; } conn.setSource( entry.getKey()); entry.getKey().addOutgoingConnection( conn ); } } // Update counters for new object creations chain.setNextNodeId( maxNodeId + 1 ); chain.setNextConnectionId( maxConnId + 1 ); // Log errors if( ! readingWarnings.isEmpty()) { IStatus[] children = new IStatus[ readingWarnings.size()]; MultiStatus status = new MultiStatus( PetalsEipPlugin.PLUGIN_ID, 0, readingWarnings.toArray( children ), "Errors where found while parsing " + inputName + ".", null ); PetalsEipPlugin.getDefault().getLog().log( status ); } return chain; } /** * Reads an EIP file and builds an EIP chain from its content. * @param inputFile the input file (must exist) * @return an EIP chain * @throws IOException if something went wrong */ public EipChain read( File inputFile ) throws IOException { if( ! inputFile.exists()) throw new IOException( inputFile.getAbsolutePath() + " could not be read (does not exist)." ); FileInputStream fis = new FileInputStream( inputFile ); return read( fis, inputFile.getAbsolutePath()); } }