blob: b5ea456f756ebafc8969cb465c40fad20dc1cc97 [file] [log] [blame]
/*
* Copyright 2018-present Open Networking Foundation
*
* 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 org.onosproject.workflow.api;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import org.onlab.osgi.DefaultServiceDirectory;
import org.onlab.osgi.ServiceNotFoundException;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.util.List;
import java.util.Objects;
import java.util.Set;
/**
* Class for immutable list workflow.
*/
public final class ImmutableListWorkflow extends AbstractWorkflow {
/**
* Init worklet type(class name of init worklet type).
*/
private String initWorkletType;
/**
* List of worklet.
*/
private List<String> workletTypeList;
/**
* Set of workflow attributes.
*/
private Set<WorkflowAttribute> attributes;
/**
* Constructor of ImmutableListWorkflow.
* @param builder builder of ImmutableListWorkflow
*/
private ImmutableListWorkflow(Builder builder) {
super(builder.id);
this.initWorkletType = builder.initWorkletType;
workletTypeList = ImmutableList.copyOf(builder.workletTypeList);
attributes = ImmutableSet.copyOf(builder.attributes);
}
@Override
public Worklet init(WorkflowContext context) throws WorkflowException {
if (Objects.isNull(initWorkletType)) {
return null;
}
return getWorkletInstance(initWorkletType);
}
@Override
public Worklet next(WorkflowContext context) throws WorkflowException {
int cnt = 0;
for (int i = 0; i < workletTypeList.size(); i++) {
if (cnt++ > Worklet.MAX_WORKS) {
throw new WorkflowException("Maximum worklet execution exceeded");
}
String workletType = workletTypeList.get(i);
if (Worklet.Common.COMPLETED.tag().equals(workletType)) {
return Worklet.Common.COMPLETED;
}
if (Worklet.Common.INIT.tag().equals(workletType)) {
continue;
}
Worklet worklet = getWorkletInstance(workletType);
Class workClass = worklet.getClass();
if (BranchWorklet.class.isAssignableFrom(workClass)) {
Class nextClass = ((BranchWorklet) worklet).next(context);
if (nextClass == null) {
throw new WorkflowException("Invalid next Worklet for " + workClass);
}
// TODO : it does not support duplicated use of WorkType. It needs to consider label concept
int nextIdx = getClassIndex(nextClass);
if (nextIdx == -1) {
throw new WorkflowException("Failed to find next " + nextClass + " for " + workClass);
}
i = nextIdx;
continue;
} else {
if (worklet.isNext(context)) {
return worklet;
}
}
}
return Worklet.Common.COMPLETED;
}
@Override
public Worklet getWorkletInstance(String workletType) throws WorkflowException {
WorkflowStore store;
try {
store = DefaultServiceDirectory.getService(WorkflowStore.class);
} catch (ServiceNotFoundException e) {
throw new WorkflowException(e);
}
Class workClass;
try {
workClass = store.getClass(workletType);
} catch (ClassNotFoundException e) {
throw new WorkflowException(e);
}
if (!isAllowed(workClass)) {
throw new WorkflowException("Not allowed class(" + workClass.getSimpleName() + ")");
}
Worklet worklet;
try {
worklet = (Worklet) workClass.newInstance();
} catch (Exception e) {
throw new WorkflowException(e);
}
return worklet;
}
@Override
public Set<WorkflowAttribute> attributes() {
return ImmutableSet.copyOf(attributes);
}
/**
* Gets index of class in worklet type list.
* @param aClass class to get index
* @return index of class in worklet type list
*/
private int getClassIndex(Class aClass) {
for (int i = 0; i < workletTypeList.size(); i++) {
if (Objects.equals(aClass.getName(), workletTypeList.get(i))) {
return i;
}
}
return -1;
}
/**
* Checks whether class is allowed class or not.
* @param clazz class to check
* @return Check result
*/
private boolean isAllowed(Class clazz) {
// non static inner class is not allowed
if (clazz.isMemberClass() && !Modifier.isStatic(clazz.getModifiers())) {
return false;
}
// enum is not allowed
if (clazz.isEnum()) {
return false;
}
// class should be subclass of Work
if (!Worklet.class.isAssignableFrom(clazz)) {
return false;
}
return true;
}
@Override
public int hashCode() {
return Objects.hash(this.toString());
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof EventTask)) {
return false;
}
return Objects.equals(this.id(), ((ImmutableListWorkflow) obj).id())
&& Objects.equals(this.initWorkletType, ((ImmutableListWorkflow) obj).initWorkletType)
&& Objects.equals(this.workletTypeList, ((ImmutableListWorkflow) obj).workletTypeList)
&& Objects.equals(this.attributes, ((ImmutableListWorkflow) obj).attributes);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(getClass())
.add("id", id())
.add("initWorklet", initWorkletType)
.add("workList", workletTypeList)
.add("attributes", attributes)
.toString();
}
/**
* Gets a instance of builder.
* @return instance of builder
*/
public static Builder builder() {
return new Builder();
}
/**
* Builder of ImmutableListWorkflow.
*/
public static class Builder {
private URI id;
private String initWorkletType;
private final List<String> workletTypeList = Lists.newArrayList();
private final Set<WorkflowAttribute> attributes = Sets.newHashSet();
/**
* Sets id of immutable list workflow.
* @param uri id of immutable list workflow
* @return builder
*/
public Builder id(URI uri) {
this.id = uri;
workletTypeList.add(Worklet.Common.INIT.tag());
return this;
}
/**
* Sets init worklet class name of immutable list workflow.
* @param workletClassName class name of worklet
* @return builder
*/
public Builder init(String workletClassName) {
this.initWorkletType = workletClassName;
return this;
}
/**
* Chains worklet class name of immutable list workflow.
* @param workletClassName class name of worklet
* @return builder
*/
public Builder chain(String workletClassName) {
workletTypeList.add(workletClassName);
return this;
}
/**
* Adds workflow attribute.
* @param attribute workflow attribute to be added
* @return builder
*/
public Builder attribute(WorkflowAttribute attribute) {
attributes.add(attribute);
return this;
}
/**
* Builds ImmutableListWorkflow.
* @return instance of ImmutableListWorkflow
*/
public ImmutableListWorkflow build() {
workletTypeList.add(Worklet.Common.COMPLETED.tag());
return new ImmutableListWorkflow(this);
}
}
}