/*******************************************************************************
* 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.
*******************************************************************************/
/********************************************************************************
* 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.model;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
import org.apache.commons.lang.StringUtils;
import org.eclipse.draw2d.geometry.Dimension;
import org.eclipse.draw2d.geometry.Point;
import org.slf4j.Logger;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
import hydrograph.ui.common.cloneableinterface.IDataStructure;
import hydrograph.ui.common.component.config.PortInfo;
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.datastructure.property.JoinConfigProperty;
import hydrograph.ui.graph.model.components.InputSubjobComponent;
import hydrograph.ui.graph.model.components.OutputSubjobComponent;
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;
/**
* The Class Component.
* <p>
* This is a base class in model tier for all types of Hydrograph components.
*
* @author Bitwise
*/
public abstract class Component extends Model {
/** The Constant logger. */
private static final Logger logger = LogFactory.INSTANCE.getLogger(Component.class);
/** The Constant serialVersionUID. */
private static final long serialVersionUID = 2587870876576884352L;
/** The Unique component name. */
private final String UniqueComponentName = "Component" + Math.random() * 10000;
/**
* The Enum Props.
*
* @author Bitwise
*/
public static enum Props {
/** The name prop. */
NAME_PROP("name"),
/** The id prop. */
ID_PROP("id"),
/** The location prop. */
LOCATION_PROP("Location"),
/** The size prop. */
SIZE_PROP("Size"),
/** The inputs. */
INPUTS("inputs"),
/** The outputs. */
OUTPUTS("outputs"),
/** The validity status. */
VALIDITY_STATUS("validityStatus"),
/** The execution status. */
EXECUTION_STATUS("executionStatus");
/** The value. */
private String value;
/**
* Instantiates a new props.
*
* @param value the value
*/
private Props(String value) {
this.value = value;
}
/**
* Gets the value.
*
* @return the value
*/
public String getValue() {
return this.value;
}
/**
* Checks if given value is equal to this component's property value. *
* @param property
* the property
* @return true, if successful
*/
public boolean equalsTo(String property) {
return this.value.equals(property);
}
}
/**
* The Enum ValidityStatus.
*
* @author Bitwise
*/
public static enum ValidityStatus {
/** The warn. */
WARN,
/** The error. */
ERROR,
/** The valid. */
VALID;
}
/** The location. */
private final Point location;
/** The size. */
private final Dimension size;
/** The properties. */
private Map<String, Object> properties;
/** The parent. */
private Container parent;
/** The validity status. */
private String validityStatus;
/** The cloned hash map. */
private Map<String, Object> clonedHashMap;
/** The cloned array list. */
private ArrayList<JoinConfigProperty> clonedArrayList;
/** The input links hash. */
private final Hashtable<String, ArrayList<Link>> inputLinksHash;
/** The output links hash. */
private final Hashtable<String, ArrayList<Link>> outputLinksHash;
/** The input links. */
private ArrayList<Link> inputLinks = new ArrayList<Link>();
/** The output links. */
private ArrayList<Link> outputLinks = new ArrayList<Link>();
/** The inputport terminals. */
private List<String> inputportTerminals;
/** The output port terminals. */
private List<String> outputPortTerminals;
/** The new instance. */
private boolean newInstance;
/** The type. */
private String type;
/** The prefix. */
private String prefix;
/** The category. */
private String category;
/** The ports. */
private Map<String, Port> ports;
/** The component name. */
private String componentName;
/** The component id. */
private String componentId;
/** The port details. */
private List<PortDetails> portDetails;
/** The left port count. */
private int leftPortCount;
/** The right port count. */
private int rightPortCount;
/** The bottom port count. */
private int bottomPortCount;
/** The change in ports cnt dynamically. */
private boolean changeInPortsCntDynamically;
/** The change out ports cnt dynamically. */
private boolean changeOutPortsCntDynamically;
/** The change unused ports cnt dynamically. */
private boolean changeUnusedPortsCntDynamically;
/** The component label. */
private ComponentLabel componentLabel;
/** The component label margin. */
private int componentLabelMargin;
/** The watcher terminals. */
private Map<String, Long> watcherTerminals;
/** The latest changes in schema. */
@XStreamOmitField
private boolean latestChangesInSchema=false;
/** The tooltip information. */
@XStreamOmitField
private Map<String, PropertyToolTipInformation> tooltipInformation;
/** The tool tip error messages. */
// @XStreamOmitField
private Map<String, String> toolTipErrorMessages; // <propertyName,ErrorMessage>
/** The component edit part. */
@XStreamOmitField
private Object componentEditPart;
/** The status. */
@XStreamOmitField
private ComponentExecutionStatus status;
/* Default prefix is used for creating unique component id */
@XStreamOmitField
private String defaultPrefix;
private boolean isContinuousSchemaPropogationAllow;
/**
* Instantiates a new component.
*/
public Component() {
location = new Point(0, 0);
size = new Dimension(100, 80);
properties = new LinkedHashMap<>();
leftPortCount = 0;
rightPortCount = 0;
bottomPortCount = 0;
inputLinksHash = new Hashtable<String, ArrayList<Link>>();
inputLinks = new ArrayList<Link>();
outputLinksHash = new Hashtable<String, ArrayList<Link>>();
outputLinks = new ArrayList<Link>();
inputportTerminals = new ArrayList<String>();
outputPortTerminals = new ArrayList<String>();
watcherTerminals = new HashMap();
newInstance = true;
validityStatus = ValidityStatus.WARN.name();
componentName = DynamicClassProcessor.INSTANCE.getClazzName(this
.getClass());
componentLabel = new ComponentLabel(componentName);
componentLabelMargin = 16;
prefix = XMLConfigUtil.INSTANCE.getComponent(componentName)
.getDefaultNamePrefix();
defaultPrefix=XMLConfigUtil.INSTANCE.getComponent(componentName)
.getDefaultNamePrefix();
initPortSettings();
toolTipErrorMessages = new LinkedHashMap<>();
status = ComponentExecutionStatus.BLANK;
}
/**
* Returns tooltip error message.
*
* @return {@link Map}
*/
public Map<String, String> getToolTipErrorMessages() {
return toolTipErrorMessages;
}
/**
*
* Set Tooltip error message .
*
* @param toolTipErrorMessages the tool tip error messages
*/
public void setToolTipErrorMessages(Map<String, String> toolTipErrorMessages) {
this.toolTipErrorMessages = toolTipErrorMessages;
}
/**
* Inits the port settings.
*/
private void initPortSettings() {
List<PortSpecification> portSpecification = XMLConfigUtil.INSTANCE.getComponent(componentName)
.getPort().getPortSpecification();
portDetails = new ArrayList<PortDetails>();
ports = new HashMap<String, Port>();
PortTypeEnum pEnum = null;
PortAlignmentEnum pAlignEnum = null;
for (PortSpecification p : portSpecification) {
pAlignEnum = PortAlignmentEnum.fromValue(p.getPortAlignment().value());
setPortCount(pAlignEnum, p.getNumberOfPorts(), p.isChangePortCountDynamically());
for(PortInfo portInfo :p.getPort()){
String portTerminal = portInfo.getPortTerminal();
pEnum = PortTypeEnum.fromValue(portInfo.getTypeOfPort().value());
Port port = new Port(portInfo.getLabelOfPort(),
portTerminal, this, getNumberOfPortsForAlignment(pAlignEnum), pEnum
, portInfo.getSequenceOfPort(), p.isAllowMultipleLinks(), p.isLinkMandatory(), pAlignEnum);
logger.trace("Adding portTerminal {}", portTerminal);
ports.put(portTerminal, port);
}
PortDetails pd = new PortDetails(ports, pAlignEnum, p.getNumberOfPorts(), p.isChangePortCountDynamically(), p.isAllowMultipleLinks(), p.isLinkMandatory());
portDetails.add(pd);
}
}
/**
* Gets the number of ports for alignment.
*
* @param pAlignEnum the align enum
* @return the number of ports for alignment
*/
private int getNumberOfPortsForAlignment(PortAlignmentEnum pAlignEnum) {
if(pAlignEnum.equals(PortAlignmentEnum.LEFT)){
return leftPortCount;
}else if(pAlignEnum.equals(PortAlignmentEnum.RIGHT)){
return rightPortCount;
}else if(pAlignEnum.equals(PortAlignmentEnum.BOTTOM)){
return bottomPortCount;
}
return 0;
}
/**
* Sets the port count.
*
* @param pAlign the align
* @param portCount the port count
* @param changePortCount the change port count
*/
private void setPortCount(PortAlignmentEnum pAlign, int portCount, boolean changePortCount) {
if(pAlign.equals(PortAlignmentEnum.LEFT)){
leftPortCount = leftPortCount + portCount;
properties.put("inPortCount", String.valueOf(portCount));
changeInPortsCntDynamically=changePortCount;
} else if (pAlign.equals(PortAlignmentEnum.RIGHT)) {
rightPortCount = rightPortCount + portCount;
properties.put("outPortCount", String.valueOf(portCount));
changeOutPortsCntDynamically=changePortCount;
} else if (pAlign.equals(PortAlignmentEnum.BOTTOM)) {
bottomPortCount = bottomPortCount + portCount;
properties.put("unusedPortCount", String.valueOf(portCount));
changeUnusedPortsCntDynamically=changePortCount;
}
}
/**
* Returns list of input ports of this component.
*
* @return
*/
public List<String> getInputportTerminals() {
return inputportTerminals;
}
/**
* Set input ports for this component.
*
* @param portTerminals
*/
public void setInputportTerminals(List<String> portTerminals){
this.inputportTerminals=portTerminals;
}
/**
*
* Returns list of output ports for this component.
*
* @return
*/
public List<String> getOutputPortTerminals() {
return outputPortTerminals;
}
/**
*
* Set output ports for this component.
*
* @param portTerminals
*/
public void setOutputPortTerminals(List<String> portTerminals) {
this.outputPortTerminals=portTerminals;
}
/**
* Set true when number of input port count changed dynamically.
*
* @param changeInPortsCntDynamically the new change in ports cnt dynamically
*/
public void setChangeInPortsCntDynamically(boolean changeInPortsCntDynamically) {
this.changeInPortsCntDynamically = changeInPortsCntDynamically;
}
/**
* Set true when number of output port count changed dynamically.
*
* @param changeOutPortsCntDynamically the new change out ports cnt dynamically
*/
public void setChangeOutPortsCntDynamically(boolean changeOutPortsCntDynamically) {
this.changeOutPortsCntDynamically = changeOutPortsCntDynamically;
}
/**
* Set true when number of unused port count changed.
*
* @param changeUnusedPortsCntDynamically the new change unused ports cnt dynamically
*/
public void setChangeUnusedPortsCntDynamically(
boolean changeUnusedPortsCntDynamically) {
this.changeUnusedPortsCntDynamically = changeUnusedPortsCntDynamically;
}
/**
*
* Get input port count
*
* @return - number of input ports
*/
public int getInPortCount() {
return leftPortCount;
}
/**
* set number of input ports.
*
* @param inPortCount the new in port count
*/
public void setInPortCount(int inPortCount) {
this.leftPortCount = inPortCount;
this.properties.put("inPortCount", String.valueOf(inPortCount));
}
/**
* Get number of output port.
*
* @return the out port count
*/
public int getOutPortCount() {
return rightPortCount;
}
/**
* Set number of output port.
*
* @param outPortCount the new out port count
*/
public void setOutPortCount(int outPortCount) {
this.rightPortCount = outPortCount;
this.properties.put("outPortCount", String.valueOf(outPortCount));
}
/**
* Get number of unused port.
*
* @return the unused port count
*/
public int getUnusedPortCount() {
return bottomPortCount;
}
/**
* set number of unused port.
*
* @param unusedPortCount the new unused port count
*/
public void setUnusedPortCount(int unusedPortCount) {
this.bottomPortCount = unusedPortCount;
this.properties.put("unusedPortCount", String.valueOf(unusedPortCount));
}
/**
* Get port specification list.
*
* @return - list of {@link PortDetails}
*/
public List<PortDetails> getPortDetails() {
return portDetails;
}
/**
* Get port details based on its alignment.
*
* @return - list of {@link PortDetails}
*/
public PortDetails getPortDetails(PortAlignmentEnum alignmentEnum) {
for(PortDetails portDetails :this.portDetails){
if(alignmentEnum.equals(portDetails.getPortAlignment())){
return portDetails;
}
}
return null;
}
/**
* Set ports.
*
* @param ports the ports
*/
public void setPorts(Map<String, Port> ports) {
this.ports = ports;
}
/**
* returns true when there is change in count of input port.
*
* @return boolean
*/
public boolean isChangeInPortsCntDynamically() {
return changeInPortsCntDynamically;
}
/**
* returns true when there is change in count of output port.
*
* @return boolean
*/
public boolean isChangeOutPortsCntDynamically() {
return changeOutPortsCntDynamically;
}
/**
* returns true when there is change in count of unused port.
*
* @return boolean
*/
public boolean isChangeUnusedPortsCntDynamically() {
return changeUnusedPortsCntDynamically;
}
/**
* Add input ports.
*
* @param key the key
* @return true, if is allow multiple links for port
*/
private boolean isAllowMultipleLinksForPort(String key){
for(PortDetails portDetailsInfo :this.portDetails){
if(portDetailsInfo.getPorts().containsKey(key))
return (portDetailsInfo.getPorts().get(key).isAllowMultipleLinks());
}
return false;
}
/**
* Checks if is link mandatory for port.
*
* @param key the key
* @return true, if is link mandatory for port
*/
private boolean isLinkMandatoryForPort(String key){
for(PortDetails portDetailsInfo :this.portDetails){
if(portDetailsInfo.getPorts().containsKey(key))
return (portDetailsInfo.getPorts().get(key).isLinkMandatory());
}
return false;
}
/**
* Checks if there are latest changes in schema.
*
* @return true, if is latest changes in schema
*/
public boolean isLatestChangesInSchema() {
return latestChangesInSchema;
}
/**
* Sets the latest changes in schema.
*
* @param latestChangesInSchema
* the new latest changes in schema
*/
public void setLatestChangesInSchema(boolean latestChangesInSchema) {
this.latestChangesInSchema = latestChangesInSchema;
}
/**
* Increment left side ports i.e. input ports.
*
* @param newPortCount
* the new port count
* @param oldPortCount
* the old port count
*/
public void incrementLeftSidePorts(int newPortCount, int oldPortCount) {
for (int i = oldPortCount; i < newPortCount; i++) {
Port inPort = new Port(Constants.INPUT_SOCKET_TYPE + i, Constants.INPUT_SOCKET_TYPE + i, this,
newPortCount, PortTypeEnum.IN, i, isAllowMultipleLinksForPort("in0"), isLinkMandatoryForPort("in0"),
PortAlignmentEnum.LEFT);
ports.put(Constants.INPUT_SOCKET_TYPE + i, inPort);
firePropertyChange("Component:add", null, inPort);
for(PortDetails p:portDetails){
if(PortAlignmentEnum.LEFT.equals(p.getPortAlignment())){
p.setPorts(ports);
}
}
}
}
/**
* Add output ports.
*
* @param newPortCount the new port count
* @param oldPortCount the old port count
*/
public void incrementRightSidePorts(int newPortCount, int oldPortCount) {
for (int i = oldPortCount; i < newPortCount; i++) {
Port outputPort = new Port(Constants.OUTPUT_SOCKET_TYPE + i, Constants.OUTPUT_SOCKET_TYPE + i, this,
newPortCount, PortTypeEnum.OUT, i, isAllowMultipleLinksForPort("out0"), isLinkMandatoryForPort("out0"),
PortAlignmentEnum.RIGHT);
ports.put(Constants.OUTPUT_SOCKET_TYPE + i, outputPort);
firePropertyChange("Component:add", null, outputPort);
for(PortDetails p:portDetails){
if(PortAlignmentEnum.RIGHT.equals(p.getPortAlignment())){
p.setPorts(ports);
}
}
}
}
/**
* Add unused ports.
*
* @param newPortCount the new port count
* @param oldPortCount the old port count
*/
public void incrementBottomSidePorts(int newPortCount, int oldPortCount) {
for (int i = oldPortCount; i < newPortCount; i++) {
Port unusedPort = new Port("un" + i, Constants.UNUSED_SOCKET_TYPE + i,
this, newPortCount, PortTypeEnum.UNUSED, i, isAllowMultipleLinksForPort("unused0"), isLinkMandatoryForPort("unused0"),
PortAlignmentEnum.BOTTOM);
ports.put(Constants.UNUSED_SOCKET_TYPE + i, unusedPort);
firePropertyChange("Component:add", null, unusedPort);
for(PortDetails p:portDetails){
if(PortAlignmentEnum.BOTTOM.equals(p.getPortAlignment())){
p.setPorts(ports);
}
}
}
}
/**
* Change input port count.
*
* @param newPortCount the new port count
*/
public void changeInPortCount(int newPortCount) {
List<String> portTerminals = new ArrayList<>();
portTerminals.addAll(ports.keySet());
for (String key : portTerminals) {
if (key.contains("in")) {
ports.get(key).setNumberOfPortsOfThisType(newPortCount);
}
}
setInPortCount(newPortCount);
}
/**
* Change unused port count.
*
* @param newPortCount the new port count
*/
public void changeUnusedPortCount(int newPortCount) {
List<String> portTerminals = new ArrayList<>();
portTerminals.addAll(ports.keySet());
for (String key : portTerminals) {
if (key.contains("un")) {
ports.get(key).setNumberOfPortsOfThisType(newPortCount);
}
}
setUnusedPortCount(newPortCount);
}
/**
* Change output port count.
*
* @param newPortCount the new port count
*/
public void changeOutPortCount(int newPortCount) {
List<String> portTerminals = new ArrayList<>();
portTerminals.addAll(ports.keySet());
for (String key : portTerminals) {
if (key.contains("out")) {
ports.get(key).setNumberOfPortsOfThisType(newPortCount);
}
}
setOutPortCount(newPortCount);
}
/**
* Get ports.
*
* @return the ports
*/
public Map<String, Port> getPorts() {
return ports;
}
/**
* Gets the port.
*
* @param terminal
* the terminal
* @return the port
*/
public Port getPort(String terminal) {
return ports.get(terminal);
}
/**
* Get list of component children.
*
* @return list of {@link Model}
*/
public List<Model> getChildren() {
List<Model> children = new ArrayList<Model>(ports.values());
children.add(componentLabel);
return children;
}
/**
* Update connection property.
*
* @param prop the prop
* @param newValue the new value
*/
private void updateConnectionProperty(String prop, Object newValue) {
firePropertyChange(prop, null, newValue);
}
/**
* Connect input to given link.
*
* @param {@link Link}
*/
public void connectInput(Link link) {
inputLinks.add(link);
inputLinksHash.put(link.getTargetTerminal(), inputLinks);
updateConnectionProperty(Props.INPUTS.getValue(), link);
}
/**
* Connect output to given link.
*
* @param {{@link Link}
*
*/
public void connectOutput(Link link) {
if (outputLinksHash.get(link.getSourceTerminal()) != null){
link.setLinkNumber(getNewLinkNumber(link));
}else{
link.setLinkNumber(0);
}
outputLinks.add(link);
outputLinksHash.put(link.getSourceTerminal(), outputLinks);
updateConnectionProperty(Props.OUTPUTS.getValue(), link);
}
private int getNewLinkNumber(Link newlink){
List<Integer> existingOutputLinkNumbers = getExistingOutputLinkNumbers(newlink);
Integer newLinkNumber = getNewLinkNumberFromExistingLinkNumberRange(existingOutputLinkNumbers);
if(newLinkNumber==null){
newLinkNumber = existingOutputLinkNumbers.size();
}
return newLinkNumber;
}
private Integer getNewLinkNumberFromExistingLinkNumberRange(
List<Integer> existingOutputLinkNumbers) {
int index=0;
Integer newLinkNumber=null;
for(;index<existingOutputLinkNumbers.size();index++){
if(!existingOutputLinkNumbers.contains(index)){
newLinkNumber = index;
break;
}
}
return newLinkNumber;
}
private List<Integer> getExistingOutputLinkNumbers(Link newlink) {
List<Integer> existingOutputLinkNumbers = new ArrayList<>();
for(Link link: outputLinksHash.get(newlink.getSourceTerminal())){
existingOutputLinkNumbers.add(link.getLinkNumber());
}
return existingOutputLinkNumbers;
}
/**
* Disconnect input from given link.
*
* @param link
* the link
*/
public void disconnectInput(Link link) {
inputLinks.remove(link);
inputLinksHash.remove(link.getTargetTerminal());
updateConnectionProperty(Props.INPUTS.getValue(), link);
}
/**
* Disconnect output from given link.
*
* @param link
* the link
*/
public void disconnectOutput(Link link) {
outputLinks.remove(link);
updateConnectionProperty(Props.OUTPUTS.getValue(), link);
}
/**
* Get source connections.
*
* @return the source connections
*/
public List<Link> getSourceConnections() {
return outputLinks;
}
/**
* Set source connections.
*
* @param links the new source connections
*/
public void setSourceConnections(List<Link> links) {
outputLinks=(ArrayList<Link>) links;
}
/**
* Gets the target connections.
* @return the target connections
*/
public List<Link> getTargetConnections() {
return inputLinks;
}
/**
* Engage input port.
*
* @param terminal
* the terminal
*/
public void engageInputPort(String terminal) {
inputportTerminals.add(terminal);
}
/**
* Free up given input port.
*
* @param terminal
* the terminal
*/
public void freeInputPort(String terminal) {
inputportTerminals.remove(terminal);
}
/**
* Checks if input port is engaged (connected ).
*
* @param terminal
* the terminal
* @return true, if is input port engaged
*/
public boolean isInputPortEngaged(String terminal) {
return inputportTerminals.contains(terminal);
}
/**
* Engage output port.
*
* @param terminal
* the terminal
*/
public void engageOutputPort(String terminal) {
outputPortTerminals.add(terminal);
}
/**
* Free up given output port.
*
* @param terminal
* the terminal
*/
public void freeOutputPort(String terminal) {
outputPortTerminals.remove(terminal);
}
/**
* Checks if output port is engaged ( Connected ).
*
* @param terminal
* the terminal
* @return true, if is output port engaged
*/
public boolean isOutputPortEngaged(String terminal) {
return outputPortTerminals.contains(terminal);
}
/**
* Sets the properties.
*
* @param properties
* the properties
*/
public void setProperties(Map<String, Object> properties) {
this.properties = properties;
}
/**
* Return the property value for the given propertyId, or null.
*
* @param propertyId the property id
* @return the property value
*/
public Object getPropertyValue(Object propertyId) {
if (properties.containsKey(propertyId)) {
return properties.get(propertyId);
}
throw new PropertyNotAvailableException();
}
/**
* Set the property value for the given property id.
*
* @param propertyId the property id
* @param value the value
*/
public void setPropertyValue(Object propertyId, Object value) {
properties.put((String) propertyId, value);
// tooltipInformation.get(propertyId).setPropertyValue(value);
}
/**
* Gets the component name.
* @return the component name
*/
public String getComponentName() {
return componentName;
}
/**
* Gets the component label.
* @return the component label
*/
public ComponentLabel getComponentLabel() {
return componentLabel;
}
/**
* Sets the component label.
*
* @param componentLabel
* the new component label
*/
public void setComponentLabel(ComponentLabel componentLabel) {
this.componentLabel = componentLabel;
}
/**
* Sets the component id.
*
* @param String
* the new component id
*/
public void setComponentId(String id) {
this.componentId = id;
}
/**
* Gets the component id.
* @return the component id
*/
public String getComponentId() {
return componentId;
}
/**
* Set the Location of this shape.
*
* @param newLocation
* a non-null Point instance
* @throws IllegalArgumentException
* if the parameter is null
*/
public void setLocation(Point newLocation) {
resetLocation(newLocation);
location.setLocation(newLocation);
firePropertyChange(Props.LOCATION_PROP.getValue(), null, location);
}
/**
* reset if x or y coordinates of components are negative
*
* @param newLocation
*/
private void resetLocation(Point newLocation) {
if (newLocation.x < 0) {
newLocation.x = 0;
}
if (newLocation.y < 0) {
newLocation.y = 0;
}
}
/**
* Return the Location of this shape.
*
* @return a non-null location instance
*/
public Point getLocation() {
return location.getCopy();
}
/**
* Set the Size of this shape. Will not modify the size if newSize is null.
*
* @param newSize
* a non-null Dimension instance or null
*/
public void setSize(Dimension newSize) {
if(newSize.height<80)
newSize.height=80;
if (newSize != null) {
size.setSize(newSize);
firePropertyChange(Props.SIZE_PROP.getValue(), null, size);
}
}
/**
* Return the Size of this shape.
*
* @return a non-null Dimension instance
*/
public Dimension getSize() {
return size.getCopy();
}
/**
* get component label margin.
*
* @return the component label margin
*/
public int getComponentLabelMargin() {
return componentLabelMargin;
}
/**
* Set component label margin.
*
* @param componentLabelMargin the new component label margin
*/
public void setComponentLabelMargin(int componentLabelMargin) {
this.componentLabelMargin = componentLabelMargin;
firePropertyChange("componentLabelMargin", null, componentLabelMargin);
}
/**
* Get parent of the component.
*
* @return {@link Container}
*/
public Container getParent() {
return parent;
}
/**
* Set component parent.
*
* @param parent the new parent
*/
public void setParent(Container parent) {
this.parent = parent;
}
/**
* Returns component properties.
*
* @return the properties
*/
public LinkedHashMap<String, Object> getProperties() {
return (LinkedHashMap<String, Object>) properties;
}
/**
* PropertyNotAvailableException exception.
*
* @author Bitwise
*/
private class PropertyNotAvailableException extends RuntimeException {
/** The Constant serialVersionUID. */
private static final long serialVersionUID = -7978238880803956846L;
}
/**
* Checks if it's a new instance.
*
* @return true, if is new instance
*/
public boolean isNewInstance() {
return newInstance;
}
/**
* Sets the new instance.
*
* @param newInstance the new new instance
*/
public void setNewInstance(boolean newInstance) {
this.newInstance = newInstance;
}
/**
* Returns component type.
*
* @return - component type
*/
public String getType() {
return type;
}
/**
* Set Component type.
*
* @param type the new type
*/
public void setType(String type) {
this.type = type;
}
/**
* Get Component prefix i.e. base name
*
* @return the prefix
*/
public String getPrefix() {
return prefix;
}
/**
* Set Component prefix i.e. base name
*
* @param prefix the new prefix
*/
public void setPrefix(String prefix) {
this.prefix = prefix;
}
/**
* Get Component category .
*
* @return the category
*/
public String getCategory() {
return category;
}
/**
* Set component category.
*
* @param category the new category
*/
public void setCategory(String category) {
this.category = category;
}
/**
* returns component validation status.
*
* @return the validity status
*/
public String getValidityStatus() {
return validityStatus;
}
/**
* Set component validation status.
*
* @param validityStatus the new validity status
*/
public void setValidityStatus(String validityStatus) {
this.validityStatus = validityStatus;
}
/**
* Gets the converter.
*
* @return the converter
*/
// For Target XML
public abstract String getConverter();
/* (non-Javadoc)
* @see java.lang.Object#clone()
*/
@SuppressWarnings("unchecked")
@Override
public Component clone() throws CloneNotSupportedException {
Component component = null;
clonedHashMap = new LinkedHashMap<String, Object>();
try {
component = this.getClass().newInstance();
for (Map.Entry<String, Object> entry : getProperties().entrySet()) {
if (entry.getValue() instanceof String)
{
clonedHashMap.put(entry.getKey(), entry.getValue());
}
else {
if(entry.getValue() instanceof ArrayList)
{
clonedArrayList = new ArrayList<>();
List orignalList = (ArrayList) entry.getValue();
if (!orignalList.isEmpty() && String.class.isAssignableFrom(orignalList.get(0).getClass())) {
clonedArrayList.addAll(orignalList);
} else {
ArrayList<JoinConfigProperty> joinConfigList= (ArrayList<JoinConfigProperty>) orignalList ;
for(int i=0;i<joinConfigList.size();i++)
{
clonedArrayList.add(joinConfigList.get(i).clone());
} }
clonedHashMap.put(entry.getKey(), clonedArrayList);
}
else if (entry.getValue() instanceof LinkedHashMap)
clonedHashMap.put(entry.getKey(),new LinkedHashMap<>((LinkedHashMap<String, String>) entry.getValue()));
else if (entry.getValue() instanceof HashMap)
clonedHashMap.put(entry.getKey(),new HashMap<>((HashMap<String, String>) entry.getValue()));
else if (entry.getValue() instanceof LinkedHashSet)
clonedHashMap.put(entry.getKey(),new LinkedHashSet<>((LinkedHashSet<String>) entry.getValue()));
else if (entry.getValue() instanceof HashSet)
clonedHashMap.put(entry.getKey(),new HashSet<>((HashSet<String>) entry.getValue()));
else if (entry.getValue() instanceof TreeMap)
clonedHashMap.put(entry.getKey(), new TreeMap<>((TreeMap<String,String>) entry.getValue()));
else if (entry.getValue() instanceof InputSubjobComponent) {
clonedHashMap.put(entry.getKey(), null);
}
else if (entry.getValue() instanceof OutputSubjobComponent) {
clonedHashMap.put(entry.getKey(), null);
}
else if (entry.getValue() !=null && isWrapperType(entry.getValue().getClass())){
clonedHashMap.put(entry.getKey(), entry.getValue());
}
else if(entry.getValue()!=null)
{
IDataStructure c=(IDataStructure) entry.getValue();
clonedHashMap.put(entry.getKey(), c.clone());
}
}
}
} catch ( IllegalAccessException | InstantiationException e) {
logger.debug("Unable to clone Component ", e);
}
if(component!=null){
component.setType(getType());
component.setCategory(getCategory());
component.setParent(getParent());
component.setProperties(clonedHashMap);
component.setSize(getSize());
component.setLocation(getLocation());
component.setComponentLabel(new ComponentLabel((String) clonedHashMap.get(Constants.NAME)));
component.setComponentId(this.getComponentId());
HashMap<String, Port> clonedPorts=new HashMap<String, Port>();
for (Map.Entry<String, Port> entry : ports.entrySet()) {
Port p = entry.getValue();
Port clonedPort = p.clone();
clonedPort.setParent(component);
clonedPorts.put(entry.getKey(), clonedPort);
}
component.setPorts(clonedPorts);
component.setInputportTerminals(new ArrayList<String> ());
component.setOutputPortTerminals(new ArrayList<String> ());
component.setValidityStatus(validityStatus);
component.setChangeInPortsCntDynamically(changeInPortsCntDynamically);
component.setChangeOutPortsCntDynamically(changeOutPortsCntDynamically);
component.setChangeUnusedPortsCntDynamically(changeUnusedPortsCntDynamically);
component.setInPortCount(leftPortCount);
component.setOutPortCount(rightPortCount);
component.setUnusedPortCount(bottomPortCount);
}
return component;
}
/**
* Set tooltip information.
*
* @param tooltipInformation the tooltip information
*/
public void setTooltipInformation(
Map<String, PropertyToolTipInformation> tooltipInformation) {
this.tooltipInformation = tooltipInformation;
}
/**
* get tooltip information.
*
* @return the tooltip information
*/
public Map<String, PropertyToolTipInformation> getTooltipInformation() {
return tooltipInformation;
}
/**
* Update tooltip information.
*/
public void updateTooltipInformation() {
for (String propertyName : properties.keySet()) {
if (tooltipInformation != null) {
if (tooltipInformation.get(propertyName) != null) {
tooltipInformation.get(propertyName).setPropertyValue(
properties.get(propertyName));
if (toolTipErrorMessages != null)
tooltipInformation.get(propertyName).setErrorMessage(
toolTipErrorMessages.get(propertyName));
}
}
}
}
/**
* Set component label.
*
* @param label the new component label
*/
public void setComponentLabel(String label) {
setPropertyValue(Component.Props.NAME_PROP.getValue(), label);
componentLabel.setLabelContents(label);
}
/**
* Get component Description.
*
* @return the component description
*/
public String getComponentDescription() {
return XMLConfigUtil.INSTANCE.getComponent(componentName)
.getDescription();
}
/**
* unused port settings.
*
* @param newPortCount the new port count
*/
public void unusedPortSettings(int newPortCount) {
changeUnusedPortCount(newPortCount);
for (int i = 0; i < (newPortCount - 2); i++) {
Port unusedPort = new Port("un" + (i + 2),
Constants.UNUSED_SOCKET_TYPE + (i + 2), this, newPortCount, PortTypeEnum.UNUSED, (i + 2), isAllowMultipleLinksForPort("unused0"),
isLinkMandatoryForPort("unused0"), PortAlignmentEnum.BOTTOM);
ports.put(Constants.UNUSED_SOCKET_TYPE + (i + 2), unusedPort);
firePropertyChange("Component:add", null, unusedPort);
}
}
/**
* Complete input port settings.
*
* @param newPortCount
* the new port count
*/
public void completeInputPortSettings(int newPortCount) {
changeInPortCount(newPortCount);
for (int i = 0; i < (newPortCount); i++) {
Port inPort = new Port(Constants.INPUT_SOCKET_TYPE + (i), Constants.INPUT_SOCKET_TYPE
+ (i), this, newPortCount, PortTypeEnum.IN, (i), isAllowMultipleLinksForPort("in0"),
isLinkMandatoryForPort("in0"), PortAlignmentEnum.LEFT);
ports.put(Constants.INPUT_SOCKET_TYPE + (i), inPort);
firePropertyChange("Component:add", null, inPort);
}
}
/**
* Complete output port settings.
*
* @param newPortCount
* the new port count
*/
public void completeOutputPortSettings(int newPortCount) {
changeOutPortCount(newPortCount);
for (int i = 0; i < (newPortCount); i++) {
Port outPort = new Port(Constants.OUTPUT_SOCKET_TYPE + (i), Constants.OUTPUT_SOCKET_TYPE
+ (i), this, newPortCount, PortTypeEnum.OUT, (i), isAllowMultipleLinksForPort("out0"),
isLinkMandatoryForPort("out0"), PortAlignmentEnum.RIGHT);
ports.put(Constants.OUTPUT_SOCKET_TYPE + (i), outPort);
firePropertyChange("Component:add", null, outPort);
}
}
/**
* Decrements port.
*
* @param portsToBeRemoved the ports to be removed
*/
public void decrementPorts(List<String> portsToBeRemoved) {
deleteInputLinks(portsToBeRemoved);
deleteOutputLinks(portsToBeRemoved);
removePorts(portsToBeRemoved);
}
/**
* Delete input links.
*
* @param portsToBeRemoved the ports to be removed
*/
private void deleteInputLinks(List<String> portsToBeRemoved) {
if (inputLinks.size() > 0) {
Link[] inLinks = new Link[inputLinks.size()];
inputLinks.toArray(inLinks);
for (String portRemove : portsToBeRemoved) {
for (Link l : inLinks) {
if (l.getTargetTerminal().equals(portRemove)) {
l.detachSource();
l.detachTarget();
l.getSource().freeOutputPort(l.getSourceTerminal());
l.getTarget().freeInputPort(l.getTargetTerminal());
l.setTarget(null);
l.setSource(null);
}
}
}
}
}
/**
* Delete output links.
*
* @param portsToBeRemoved the ports to be removed
*/
private void deleteOutputLinks(List<String> portsToBeRemoved) {
if (outputLinks.size() > 0) {
Link[] outLinks = new Link[outputLinks.size()];
outputLinks.toArray(outLinks);
for (String portRemove : portsToBeRemoved) {
for (Link l : outLinks) {
if (l.getSourceTerminal().equals(portRemove)) {
l.detachSource();
l.detachTarget();
l.getSource().freeOutputPort(l.getSourceTerminal());
l.getTarget().freeInputPort(l.getTargetTerminal());
l.setTarget(null);
l.setSource(null);
}
}
}
}
}
/**
* Remove ports.
*
* @param portsToBeRemoved the ports to be removed
*/
private void removePorts(List<String> portsToBeRemoved) {
for (String portRemove : portsToBeRemoved) {
ports.remove(portRemove);
}
}
/**
* Get watcher terminals.
*
* @return the watcher terminals
*/
public Map<String, Long> getWatcherTerminals() {
return watcherTerminals;
}
/**
* Set watcher terminals.
*
* @param watcherTerminals the watcher terminals
*/
public void setWatcherTerminals(Map<String, Long> watcherTerminals) {
this.watcherTerminals = watcherTerminals;
}
/**
* Add watcher terminal.
*
* @param port the port
* @param limit the limit
*/
public void addWatcherTerminal(String port, Long limit) {
watcherTerminals.put(port, limit);
}
/**
* Remove watcher terminal.
*
* @param port the port
*/
public void removeWatcherTerminal(String port) {
watcherTerminals.remove(port);
}
/**
* Clear watchers.
*/
public void clearWatchers() {
watcherTerminals.clear();
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((UniqueComponentName == null) ? 0 : UniqueComponentName.hashCode());
return result;
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Component other = (Component) obj;
if (UniqueComponentName == null) {
if (other.UniqueComponentName != null)
return false;
} else if (!UniqueComponentName.equals(other.UniqueComponentName))
return false;
return true;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Component [UniqueComponentName=" + UniqueComponentName + ", type=" + type + ", prefix=" + prefix
+ ", category=" + category + ", inPortCount=" + leftPortCount + ", outPortCount=" + rightPortCount
+ ", unusedPortCount=" + bottomPortCount + ", componentLabel=" + componentLabel + "]";
}
/**
* Gets the component edit part.
*
* @return the component edit part
*/
public Object getComponentEditPart() {
return componentEditPart;
}
/**
* Sets the component edit part.
*
* @param componentEditPart
* the new component edit part
*/
public void setComponentEditPart(Object componentEditPart) {
this.componentEditPart = componentEditPart;
}
/**
* Update status.
*
* @param currentStatus
* the current status
*/
public void updateStatus(String currentStatus) {
status = ComponentExecutionStatus.fromValue(currentStatus);
firePropertyChange(Props.EXECUTION_STATUS.getValue(), null, currentStatus);
}
/**
* Gets the status.
*
* @return the status
*/
public ComponentExecutionStatus getStatus() {
return status;
}
public boolean isContinuousSchemaPropogationAllow() {
return isContinuousSchemaPropogationAllow;
}
public void setContinuousSchemaPropogationAllow(boolean isContinuousSchemaPropogationAllow) {
this.isContinuousSchemaPropogationAllow = isContinuousSchemaPropogationAllow;
}
/**
* Sets the status.
*
* @param status
* the new status
*/
public void setStatus(ComponentExecutionStatus status) {
this.status = status;
}
/**
* Validates all the properties of component and updates its validity status accordingly.
*
* @return properties
*/
public Map<String, Object> validateComponentProperties(boolean isJobImported) {
boolean componentHasRequiredValues = Boolean.TRUE;
hydrograph.ui.common.component.config.Component component = XMLConfigUtil.INSTANCE.getComponent(this.getComponentName());
Map<String, Object> properties=this.properties;
for (Property configProperty : component.getProperty()) {
Object propertyValue = properties.get(configProperty.getName());
List<String> validators = ComponentCacheUtil.INSTANCE.getValidatorsForProperty(this.getComponentName(), 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(),new SchemaData().getInputSchema(this),
isJobImported);
//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.get(Component.Props.VALIDITY_STATUS.getValue()) == null)
properties.put(Component.Props.VALIDITY_STATUS.getValue(), Component.ValidityStatus.WARN.name());
else if (!componentHasRequiredValues
&& StringUtils.equals((String) properties.get(Component.Props.VALIDITY_STATUS.getValue()),
Component.ValidityStatus.WARN.name()))
properties.put(Component.Props.VALIDITY_STATUS.getValue(), Component.ValidityStatus.WARN.name());
else if (!componentHasRequiredValues
&& StringUtils.equals((String) properties.get(Component.Props.VALIDITY_STATUS.getValue()),
Component.ValidityStatus.ERROR.name()))
properties.put(Component.Props.VALIDITY_STATUS.getValue(), Component.ValidityStatus.ERROR.name());
else if (!componentHasRequiredValues
&& StringUtils.equals((String) properties.get(Component.Props.VALIDITY_STATUS.getValue()),
Component.ValidityStatus.VALID.name()))
properties.put(Component.Props.VALIDITY_STATUS.getValue(), Component.ValidityStatus.ERROR.name());
else if (componentHasRequiredValues)
properties.put(Component.Props.VALIDITY_STATUS.getValue(), Component.ValidityStatus.VALID.name());
return properties;
}
/**
* Checks if given class is of wrapper type.
*
* @param clazz
* the clazz
* @return true, if it's a wrapper type
*/
public static boolean isWrapperType(Class<?> clazz) {
if (clazz == Boolean.class || clazz == Character.class || clazz == Byte.class || clazz == Short.class
|| clazz == Integer.class || clazz == Long.class || clazz == Float.class || clazz == Double.class) {
return true;
}
return false;
}
public String getDefaultPrefix() {
return defaultPrefix;
}
public ArrayList<Link> getInputLinks() {
return inputLinks;
}
}