/**
* Copyright 2011-2017 Asakusa Framework Team.
*
* 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 com.asakusafw.vocabulary.flow.graph;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Represents a node in flow graph.
* Application developers should not use this class directly.
* @since 0.1.0
* @version 0.9.1
*/
public final class FlowElement implements FlowElementAttributeProvider {
private final Object identity;
private final FlowElementDescription description;
private final List<FlowElementInput> inputPorts;
private final List<FlowElementOutput> outputPorts;
private final Map<Class<? extends FlowElementAttribute>, FlowElementAttribute> attributeOverride;
/**
* Creates a new instance.
* @param description definition description
* @throws IllegalArgumentException if some parameters were {@code null}
*/
public FlowElement(FlowElementDescription description) {
this(new Object(), description, Collections.emptyList());
}
/**
* Creates a new instance.
* @param description definition description
* @param attributeOverride extra attributes for this element
* @throws IllegalArgumentException if some parameters were {@code null}
*/
public FlowElement(
FlowElementDescription description,
Collection<? extends FlowElementAttribute> attributeOverride) {
this(new Object(), description, attributeOverride);
}
private FlowElement(
Object identity,
FlowElementDescription description,
Collection<? extends FlowElementAttribute> attributeOverride) {
assert identity != null;
assert description != null;
assert attributeOverride != null;
this.identity = identity;
this.description = description;
this.inputPorts = new ArrayList<>();
for (FlowElementPortDescription port : description.getInputPorts()) {
if (port.getDirection() != PortDirection.INPUT) {
throw new IllegalArgumentException(MessageFormat.format(
"{0} must be an INPUT port", //$NON-NLS-1$
port));
}
inputPorts.add(new FlowElementInput(port, this));
}
this.outputPorts = new ArrayList<>();
for (FlowElementPortDescription port : description.getOutputPorts()) {
if (port.getDirection() != PortDirection.OUTPUT) {
throw new IllegalArgumentException(MessageFormat.format(
"{0} must be an OUTPUT port", //$NON-NLS-1$
port));
}
outputPorts.add(new FlowElementOutput(port, this));
}
this.attributeOverride = new HashMap<>();
for (FlowElementAttribute attribute : attributeOverride) {
this.attributeOverride.put(attribute.getDeclaringClass(), attribute);
}
}
/**
* Creates a new copy without any connections.
* This copy only has same {@link #getIdentity() identity}.
* @return the created copy
*/
public FlowElement copy() {
return new FlowElement(identity, description, getAttributeOverride());
}
/**
* Returns the original identity.
* @return the identity
* @since 0.4.0
*/
public Object getIdentity() {
return identity;
}
/**
* Returns the description of this element.
* @return the description
*/
public FlowElementDescription getDescription() {
return description;
}
/**
* Returns input ports of this element.
* @return input ports
*/
public List<FlowElementInput> getInputPorts() {
return inputPorts;
}
/**
* Returns input ports of this element.
* @return output ports
*/
public List<FlowElementOutput> getOutputPorts() {
return outputPorts;
}
/**
* Returns whether this element has the specified attribute or not.
* @param attribute the target attribute
* @return {@code true} if this element has the specified attribute, otherwise {@code false}
* @throws IllegalArgumentException if the parameter is {@code null}
*/
public boolean hasAttribute(FlowElementAttribute attribute) {
if (attribute == null) {
throw new IllegalArgumentException("attribute must not be null"); //$NON-NLS-1$
}
FlowElementAttribute own = getAttribute(attribute.getDeclaringClass());
if (own == null) {
return false;
}
return own.equals(attribute);
}
@Override
public Set<? extends Class<? extends FlowElementAttribute>> getAttributeTypes() {
Set<Class<? extends FlowElementAttribute>> results = new HashSet<>();
results.addAll(attributeOverride.keySet());
results.addAll(getDescription().getAttributeTypes());
return results;
}
@Override
public <T extends FlowElementAttribute> T getAttribute(Class<T> attributeClass) {
if (attributeClass == null) {
throw new IllegalArgumentException("attributeClass must not be null"); //$NON-NLS-1$
}
FlowElementAttribute override = attributeOverride.get(attributeClass);
if (override != null) {
return attributeClass.cast(override);
}
return getDescription().getAttribute(attributeClass);
}
/**
* Overwrites the attribute into this element.
* This does not change the attribute of the description.
* @param attribute the attribute to be overwritten
*/
public void override(FlowElementAttribute attribute) {
if (attribute == null) {
throw new IllegalArgumentException("attribute must not be null"); //$NON-NLS-1$
}
attributeOverride.put(attribute.getDeclaringClass(), attribute);
}
/**
* Returns the overwritten attributes.
* @return the overwritten attributes
*/
public Collection<FlowElementAttribute> getAttributeOverride() {
return new ArrayList<>(attributeOverride.values());
}
@Override
public String toString() {
return MessageFormat.format(
"{0}({1}#{2})", //$NON-NLS-1$
getDescription().getName(),
getDescription().getKind().name().toLowerCase(),
String.valueOf(hashCode()));
}
}