// ============================================================================
//
// Copyright (C) 2006-2012 Talend Inc. - www.talend.com
//
// This source code is available under agreement available at
// %InstallDIR%\features\org.talend.rcp.branding.%PRODUCTNAME%\%PRODUCTNAME%license.txt
//
// You should have received a copy of the agreement
// along with this program; if not, write to Talend SA
// 9 rue Pages 92150 Suresnes, France
//
// ============================================================================
package org.talend.repository.model.migration;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.talend.commons.exception.PersistenceException;
import org.talend.commons.ui.runtime.exception.ExceptionHandler;
import org.talend.core.model.components.ComponentUtilities;
import org.talend.core.model.components.IComponent;
import org.talend.core.model.components.IComponentsFactory;
import org.talend.core.model.migration.AbstractJobMigrationTask;
import org.talend.core.model.process.INodeConnector;
import org.talend.core.model.properties.Item;
import org.talend.core.repository.model.ProxyRepositoryFactory;
import org.talend.designer.core.model.utils.emf.talendfile.ColumnType;
import org.talend.designer.core.model.utils.emf.talendfile.ConnectionType;
import org.talend.designer.core.model.utils.emf.talendfile.ElementParameterType;
import org.talend.designer.core.model.utils.emf.talendfile.MetadataType;
import org.talend.designer.core.model.utils.emf.talendfile.NodeType;
import org.talend.designer.core.model.utils.emf.talendfile.ProcessType;
import org.talend.designer.core.model.utils.emf.talendfile.TalendFileFactory;
import org.talend.repository.i18n.Messages;
import org.talend.repository.model.ComponentsFactoryProvider;
/**
* DOC nrousseau class global comment. Detailled comment
*/
public class ReplaceMultiFlowBytReplicateMigrationTask extends AbstractJobMigrationTask {
private static final int GRID_SIZE = 32;
/*
* (non-Javadoc)
*
* @seeorg.talend.core.model.migration.AbstractJobMigrationTask#executeOnProcess(org.talend.core.model.properties.
* ProcessItem)
*/
@Override
public ExecutionResult execute(Item processItem) {
ProcessType processType = getProcessType(processItem);
if (processType == null) {
return ExecutionResult.NOTHING_TO_DO;
}
IComponentsFactory componentFactory = ComponentsFactoryProvider.getInstance();
boolean modified = false;
try {
List<NodeType> initialNodes = new ArrayList<NodeType>(processType.getNode());
for (NodeType nodeType : initialNodes) {
IComponent component = componentFactory.get(nodeType.getComponentName());
if (component != null) {
if (checkMaxOutputAndUpdate(processItem, processType, component, nodeType)) {
modified = true;
}
} else {
ExceptionHandler.log(Messages.getString("ReplaceMultiFlowBytReplicateMigrationTask.componentNotExist", //$NON-NLS-1$
nodeType.getComponentName(), processItem.getProperty().getLabel()));
}
}
if (modified) {
return ExecutionResult.SUCCESS_WITH_ALERT;
} else {
return ExecutionResult.NOTHING_TO_DO;
}
} catch (PersistenceException e) {
ExceptionHandler.process(e);
return ExecutionResult.FAILURE;
}
}
/**
* DOC nrousseau Comment method "checkMaxOutputAndUpdate".
*
* @param processItem
* @param processType
* @param component
*/
@SuppressWarnings("unchecked")
private boolean checkMaxOutputAndUpdate(Item processItem, ProcessType processType, IComponent component,
NodeType nodeTypeSource) throws PersistenceException {
boolean modified = false;
String nodeSourceUniqueName = ComponentUtilities.getNodeUniqueName(nodeTypeSource);
ProxyRepositoryFactory factory = ProxyRepositoryFactory.getInstance();
List<INodeConnector> nodeConnectors = (List<INodeConnector>) component.createConnectors(null);
for (INodeConnector nodeConnector : nodeConnectors) {
if (nodeConnector.getBaseSchema().equals("FLOW") && nodeConnector.getMaxLinkOutput() == 1) { //$NON-NLS-1$
List<ConnectionType> connections = getConnectionsToMove(processType, nodeConnector, nodeSourceUniqueName);
if (connections != null) {
List<Rectangle> targetPos = getTargetsRectangle(connections);
Rectangle startPos = getNodeRectangle(processType, nodeSourceUniqueName);
Integer tReplicateYPos = 0;
Integer tReplicateXPos = Integer.MAX_VALUE;
for (Rectangle rect : targetPos) {
if (rect.x < tReplicateXPos) {
tReplicateXPos = rect.x;
}
tReplicateYPos += rect.y;
}
tReplicateXPos = (tReplicateXPos + startPos.x) / 2;
tReplicateYPos = tReplicateYPos / targetPos.size();
int tempVar = tReplicateXPos / GRID_SIZE;
tReplicateXPos = tempVar * GRID_SIZE;
tempVar = tReplicateYPos / GRID_SIZE;
tReplicateYPos = tempVar * GRID_SIZE;
Point tReplicatePos = findLocationForNode(processType, new Point(tReplicateXPos, tReplicateYPos));
addtReplicateComponent(processType, tReplicatePos, nodeTypeSource, nodeSourceUniqueName, nodeConnector,
connections);
modified = true;
}
}
}
if (modified) {
factory.save(processItem);
}
return modified;
}
/**
* DOC nrousseau Comment method "addtReplicateComponent".
*
* @param processType
* @param replicatePos
* @param connections
*/
private void addtReplicateComponent(ProcessType processType, Point replicatePos, NodeType nodeTypeSource, String sourceName,
INodeConnector nodeConnector, List<ConnectionType> connections) {
TalendFileFactory fileFact = TalendFileFactory.eINSTANCE;
// create the node
String uniqueName = createNodeType(processType, replicatePos, nodeTypeSource, sourceName, nodeConnector, connections,
fileFact);
// create the connection from source component to tReplicate
createConnectionType(processType, sourceName, nodeConnector, fileFact, uniqueName);
}
/**
* DOC nrousseau Comment method "createConnectionType".
*
* @param processType
* @param sourceName
* @param nodeConnector
* @param fileFact
* @param uniqueName
*/
private void createConnectionType(ProcessType processType, String sourceName, INodeConnector nodeConnector,
TalendFileFactory fileFact, String uniqueName) {
List<String> connectionNames = new ArrayList<String>();
for (Object oConnection : processType.getConnection()) {
ConnectionType connection = (ConnectionType) oConnection;
connectionNames.add(connection.getLabel());
}
String baseName = "row"; //$NON-NLS-1$
int id = 1;
String connectionName = baseName + id;
while (connectionNames.contains(connectionName)) {
id++;
connectionName = baseName + id;
}
ConnectionType connectionType = fileFact.createConnectionType();
connectionType.setConnectorName(nodeConnector.getName());
connectionType.setLabel(connectionName);
connectionType.setLineStyle(nodeConnector.getDefaultConnectionType().getId());
connectionType.setMetaname(sourceName);
connectionType.setSource(sourceName);
connectionType.setTarget(uniqueName);
processType.getConnection().add(connectionType);
}
/**
* DOC nrousseau Comment method "createNodeType".
*
* @param processType
* @param replicatePos
* @param nodeTypeSource
* @param sourceName
* @param nodeConnector
* @param connections
* @param fileFact
* @return
*/
private String createNodeType(ProcessType processType, Point replicatePos, NodeType nodeTypeSource, String sourceName,
INodeConnector nodeConnector, List<ConnectionType> connections, TalendFileFactory fileFact) {
NodeType nodeType = fileFact.createNodeType();
String uniqueName = ComponentUtilities.generateUniqueNodeName("tReplicate", processType); //$NON-NLS-1$
ElementParameterType elemParam = fileFact.createElementParameterType();
elemParam.setField("TEXT"); //$NON-NLS-1$
elemParam.setName("UNIQUE_NAME"); //$NON-NLS-1$
elemParam.setValue(uniqueName);
nodeType.getElementParameter().add(elemParam);
ComponentUtilities.setNodeUniqueName(nodeType, uniqueName);
nodeType.setComponentName("tReplicate"); //$NON-NLS-1$
for (ConnectionType connectionType : connections) {
connectionType.setConnectorName("FLOW"); //$NON-NLS-1$
connectionType.setSource(uniqueName);
connectionType.setMetaname(uniqueName);
}
nodeType.setPosX(replicatePos.x);
nodeType.setPosY(replicatePos.y);
nodeType.setSizeX(GRID_SIZE);
nodeType.setSizeY(GRID_SIZE);
// create the metadata for the new node
if (nodeTypeSource.getMetadata().size() != 0) {
MetadataType metadataTypeSource = null;
for (Object oMetadataType : nodeTypeSource.getMetadata()) {
MetadataType metadataType = (MetadataType) oMetadataType;
if ((metadataType.getConnector() != null && metadataType.getConnector().equals(nodeConnector.getName()))
|| metadataType.getName().equals(sourceName)) {
metadataTypeSource = metadataType;
}
}
if (metadataTypeSource != null) {
MetadataType newMetadataType = fileFact.createMetadataType();
newMetadataType.setComment(metadataTypeSource.getComment());
newMetadataType.setConnector("FLOW"); //$NON-NLS-1$
newMetadataType.setName(uniqueName);
for (Object oColumn : metadataTypeSource.getColumn()) {
ColumnType columnType = (ColumnType) oColumn;
ColumnType newColumnType = fileFact.createColumnType();
newColumnType.setComment(columnType.getComment());
newColumnType.setDefaultValue(columnType.getDefaultValue());
if (columnType.isSetKey()) {
newColumnType.setKey(columnType.isKey());
}
if (columnType.isSetLength()) {
newColumnType.setLength(columnType.getLength());
}
newColumnType.setName(columnType.getName());
if (columnType.isSetNullable()) {
newColumnType.setNullable(columnType.isNullable());
}
newColumnType.setOriginalDbColumnName(columnType.getOriginalDbColumnName());
newColumnType.setPattern(columnType.getPattern());
if (columnType.isSetPrecision()) {
newColumnType.setPrecision(columnType.getPrecision());
}
newColumnType.setSourceType(columnType.getSourceType());
newColumnType.setType(columnType.getType());
newMetadataType.getColumn().add(newColumnType);
}
nodeType.getMetadata().add(newMetadataType);
}
}
processType.getNode().add(nodeType);
return uniqueName;
}
/**
* DOC nrousseau Comment method "findLocationForNode".
*
* @param processType
* @param point
* @return
*/
private Point findLocationForNode(ProcessType processType, Point point) {
Rectangle newRect = new Rectangle(point, new Dimension(GRID_SIZE, GRID_SIZE));
Point newLocation = new Point(point);
for (Object oNodeType : processType.getNode()) {
NodeType node = (NodeType) oNodeType;
String uniqueName = ComponentUtilities.getNodeUniqueName(node);
Rectangle currentRect = getNodeRectangle(processType, uniqueName);
if (currentRect.intersects(newRect)) {
newLocation.x += GRID_SIZE;
newLocation.y += GRID_SIZE;
return findLocationForNode(processType, point);
}
}
return newLocation;
}
/**
* DOC nrousseau Comment method "getNodePosition".
*
* @param nodeUniqueName
* @return
*/
private Rectangle getNodeRectangle(ProcessType processType, String nodeUniqueName) {
NodeType nodeType = ComponentUtilities.getNodeTypeFromUniqueName(processType, nodeUniqueName);
return new Rectangle(nodeType.getPosX(), nodeType.getPosY(), nodeType.getSizeX(), nodeType.getSizeY());
}
/**
* DOC nrousseau Comment method "getTargetsPosition".
*
* @param connections
* @return
*/
private List<Rectangle> getTargetsRectangle(List<ConnectionType> connections) {
List<Rectangle> targetPosList = new ArrayList<Rectangle>();
for (ConnectionType connection : connections) {
targetPosList.add(getNodeRectangle((ProcessType) connection.eContainer(), connection.getTarget()));
}
return targetPosList;
}
/**
* DOC nrousseau Comment method "getConnectionsToMove".
*
* @param processType
* @param nodeUniqueName
* @return
*/
private List<ConnectionType> getConnectionsToMove(ProcessType processType, INodeConnector connector, String nodeUniqueName) {
List<ConnectionType> connToMove = new ArrayList<ConnectionType>();
for (Object oConnection : processType.getConnection()) {
ConnectionType connectionType = (ConnectionType) oConnection;
if (connectionType.getSource().equals(nodeUniqueName)) {
if (connectionType.getConnectorName().equals(connector.getName())) {
connToMove.add(connectionType);
}
}
}
if (connToMove.size() <= 1) {
return null;
}
return connToMove;
}
public Date getOrder() {
GregorianCalendar gc = new GregorianCalendar(2008, 2, 17, 12, 0, 0);
return gc.getTime();
}
}