/**
* Licensed to the Austrian Association for Software Tool Integration (AASTI)
* under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. The AASTI licenses this file to you 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.openengsb.core.common.remote;
import java.util.Iterator;
import java.util.List;
import org.openengsb.core.api.remote.FilterAction;
import org.openengsb.core.api.remote.FilterChainElement;
import org.openengsb.core.api.remote.FilterChainElementFactory;
import org.openengsb.core.api.remote.FilterConfigurationException;
import org.openengsb.core.api.remote.FilterException;
import com.google.common.base.Preconditions;
/**
* This class makes it possible to configure a FilterChain as a bean (e.g. via blueprint).
*/
public class FilterChainFactory<InputType, OutputType> {
private List<Object> filters;
private Class<InputType> inputType;
private Class<OutputType> outputType;
/**
* The filters-list must be set. If the last-element is not set, the last element of the filters-list will be used.
*
* @throws FilterConfigurationException if the filters in the filter-list are not compatible with each other
*/
public FilterChain create() throws FilterConfigurationException {
Preconditions.checkState(filters != null, "list of filters must be set");
Preconditions.checkState(inputType != null, "inputType must be set");
Preconditions.checkState(outputType != null, "outputType must be set");
Preconditions.checkState(filters.size() > 0, "need at least one filter");
validateFiltersList();
Iterator<Object> iterator = filters.iterator();
FilterChainElement firstInstance = getInstanceFromListElement(iterator.next());
if (!firstInstance.getSupportedInputType().isAssignableFrom(inputType)
|| !firstInstance.getSupportedOutputType().isAssignableFrom(outputType)) {
throw new FilterConfigurationException(String.format(
"incompatible Filtertype (%s) should be (%s->%s) - is (%s->%s)",
firstInstance.getClass(), inputType, outputType, firstInstance.getSupportedInputType(),
firstInstance.getSupportedOutputType()));
}
FilterChainElement current = firstInstance;
while (iterator.hasNext()) {
Object next = iterator.next();
FilterChainElement nextFilterElement = getInstanceFromListElement(next);
if (nextFilterElement == null) {
current.setNext((FilterAction) next);
break;
}
current.setNext(nextFilterElement);
current = nextFilterElement;
}
return new FilterChain(firstInstance);
}
private FilterChainElement getInstanceFromListElement(Object next) throws FilterConfigurationException {
if (next instanceof String) {
try {
Class<?> class1 = Class.forName((String) next);
return createFromClass(class1);
} catch (ClassNotFoundException e) {
throw new FilterException(e);
}
}
if (next instanceof Class) {
return createFromClass(next);
}
if (next instanceof FilterChainElementFactory) {
return ((FilterChainElementFactory) next).newInstance();
}
return null;
}
private FilterChainElement createFromClass(Object next) {
try {
return (FilterChainElement) ((Class<?>) next).newInstance();
} catch (InstantiationException e) {
throw new FilterConfigurationException("Exception when instantiating FilterAction", e);
} catch (IllegalAccessException e) {
throw new FilterConfigurationException("Exception when instantiating FilterAction", e);
}
}
public void setFilters(List<Object> filters) {
this.filters = filters;
}
public void setInputType(Class<InputType> inputType) {
this.inputType = inputType;
}
public void setOutputType(Class<OutputType> outputType) {
this.outputType = outputType;
}
private void validateFiltersList() {
Iterator<Object> iterator = filters.iterator();
while (iterator.hasNext()) {
Object element = iterator.next();
if (element instanceof FilterAction && !(element instanceof FilterChainElement)) {
// must be final action
break;
}
validateElement(element);
}
if (iterator.hasNext()) {
throw new FilterConfigurationException("Cannot add more filter-actions after final element");
}
}
private void validateElement(Object object) {
Class<? extends Object> objClass = object.getClass();
if (objClass.equals(String.class)) {
return;
}
if (object instanceof FilterChainElementFactory) {
return;
}
// Allow FilterAction-classes with proper default-constructors
if (Class.class.isAssignableFrom(objClass)) {
Class<?> filterClass = (Class<?>) object;
if (!FilterAction.class.isAssignableFrom(filterClass)) {
throw new FilterConfigurationException(String.format(
"Incompatible type: %s, Class must be derived from one of the following: %s", filterClass,
FilterAction.class.getName()));
}
try {
filterClass.getConstructor();
} catch (NoSuchMethodException e) {
throw new FilterConfigurationException("Filter-class must have a visible default constructor", e);
}
return;
}
throw new FilterConfigurationException(String.format("Element %s is not a valid FilterElement",
object.toString()));
}
public FilterChainFactory() {
}
public FilterChainFactory(Class<InputType> inputType, Class<OutputType> outputType) {
this.inputType = inputType;
this.outputType = outputType;
}
}