/*******************************************************************************
* Copyright 2017 Capital One Services, LLC and Bitwise, Inc.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/
package hydrograph.ui.graph.command;
import hydrograph.ui.common.component.config.PortSpecification;
import hydrograph.ui.common.component.config.Property;
import hydrograph.ui.common.datastructures.tooltip.PropertyToolTipInformation;
import hydrograph.ui.common.util.ComponentCacheUtil;
import hydrograph.ui.common.util.Constants;
import hydrograph.ui.common.util.XMLConfigUtil;
import hydrograph.ui.graph.figure.ELTFigureConstants;
import hydrograph.ui.graph.model.Component;
import hydrograph.ui.graph.model.Container;
import hydrograph.ui.graph.model.PortAlignmentEnum;
import hydrograph.ui.graph.model.processor.DynamicClassProcessor;
import hydrograph.ui.graph.schema.propagation.SchemaData;
import hydrograph.ui.logging.factory.LogFactory;
import hydrograph.ui.validators.impl.IValidator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.eclipse.draw2d.geometry.Rectangle;
import org.eclipse.gef.commands.Command;
import org.slf4j.Logger;
/**
* The Class ComponentCreateCommand.
* @author Bitwise
*/
public class ComponentCreateCommand extends Command {
private static final Logger logger = LogFactory.INSTANCE.getLogger(ComponentCreateCommand.class);
private SchemaData schemaData;
/** The new Component. */
private final Component component;
/** Graph to add to. */
private final Container parent;
/** The bounds of the new Component. */
private final Rectangle bounds;
/**
* Create a command that will add a new Component in Graph.
*
* @param component the new Component that is to be added
* @param parent the Graph that will hold the new element
* @param bounds the bounds of the new component; the size can be (-1, -1) if not known
* @throws IllegalArgumentException if any parameter is null, or the request does not provide a
* new Component instance
*/
public ComponentCreateCommand(Component component, Container parent, Rectangle bounds) {
String componentName = DynamicClassProcessor.INSTANCE.getClazzName(component.getClass());
hydrograph.ui.common.component.config.Component components = XMLConfigUtil.INSTANCE.getComponent(componentName);
schemaData = new SchemaData();
//attach tooltip information to component
Map<String,PropertyToolTipInformation> tooltipInformation = new LinkedHashMap<>();
for(Property property : components.getProperty()){
tooltipInformation.put(property.getName(),new PropertyToolTipInformation(property.getName(), property.getShowAsTooltip().value(), property.getTooltipDataType().value()));
}
component.setTooltipInformation(tooltipInformation);
int totalPortsOnLeftSide=0, totalPortsOnRightSide=0, totalPortsOnBottomSide=0;
List<PortSpecification> portSpecification = XMLConfigUtil.INSTANCE.getComponent(componentName).getPort().getPortSpecification();
for(PortSpecification p:portSpecification)
{
if(PortAlignmentEnum.LEFT.value().equals(p.getPortAlignment().value())){
totalPortsOnLeftSide=p.getNumberOfPorts();
}else if(PortAlignmentEnum.RIGHT.value().equals(p.getPortAlignment().value())){
totalPortsOnRightSide=p.getNumberOfPorts();
}else if(PortAlignmentEnum.BOTTOM.value().equals(p.getPortAlignment().value())){
totalPortsOnBottomSide=p.getNumberOfPorts();
}
}
int heightFactor=totalPortsOnLeftSide > totalPortsOnRightSide ? totalPortsOnLeftSide : totalPortsOnRightSide;
int height = (heightFactor+1)*27;
int widthFactor = totalPortsOnBottomSide;
int width = 100;
if(widthFactor > 1)
width =(widthFactor+1)*33;
setupComponent(component);
Dimension newSize = new Dimension(width, height + ELTFigureConstants.componentOneLineLabelMargin);
if(newSize.height<75)
newSize.height=75;
this.component = component;
this.parent = parent;
Point p = new Point(bounds.x, bounds.y);
this.bounds = new Rectangle(p, newSize);
setLabel("Component creation");
}
@Override
public void execute() {
component.setLocation(bounds.getLocation());
Dimension size = bounds.getSize();
if (size.width > 0 && size.height > 0)
component.setSize(size);
redo();
}
/**
* Can execute if all the necessary information has been provided.
*
*/
@Override
public boolean canExecute() {
return component != null && parent != null && bounds != null;
}
/**
* Add component to container
*/
@Override
public void redo() {
parent.addChild(component);
}
/**
* Undo add action
*/
@Override
public void undo() {
parent.removeChild(component);
}
private void setupComponent(Component component) {
String componentName = DynamicClassProcessor.INSTANCE.getClazzName(component.getClass());
hydrograph.ui.common.component.config.Component componentConfig = XMLConfigUtil.INSTANCE.getComponent(componentName);
component.setProperties(prepareComponentProperties(componentName, component.getProperties()));
component.setType(componentConfig.getNameInPalette());
component.setCategory(componentConfig.getCategory().value());
component.setPrefix(componentConfig.getDefaultNamePrefix());
}
private Map<String, Object> prepareComponentProperties(String componentName, Map<String, Object> existingProperties) {
boolean componentHasRequiredValues = Boolean.TRUE;
Map<String, Object> properties = ComponentCacheUtil.INSTANCE.getProperties(componentName);
properties.put(Constants.PARAM_NAME, componentName);
hydrograph.ui.common.component.config.Component component = XMLConfigUtil.INSTANCE.getComponent(componentName);
for (Property configProperty : component.getProperty()) {
Object propertyValue = properties.get(configProperty.getName());
List<String> validators = ComponentCacheUtil.INSTANCE.getValidatorsForProperty(componentName, configProperty.getName());
IValidator validator = null;
for (String validatorName : validators) {
try {
validator = (IValidator) Class.forName(Constants.VALIDATOR_PACKAGE_PREFIX + validatorName).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
logger.error("Failed to create validator", e);
throw new RuntimeException("Failed to create validator", e);
}
boolean status = validator.validate(propertyValue, configProperty.getName(),schemaData.getInputSchema(this.component),false);
//NOTE : here if any of the property is not valid then whole component is not valid
if(status == false){
componentHasRequiredValues = Boolean.FALSE;
}
}
}
if(!componentHasRequiredValues){
properties.put(Component.Props.VALIDITY_STATUS.getValue(), Component.ValidityStatus.WARN.name());
}
properties.putAll(existingProperties);
return properties;
}
}