org.switchyard.internal.transform.BaseTransformerRegistry Maven / Gradle / Ivy
/*
* Copyright 2013 Red Hat Inc. and/or its affiliates and other contributors.
*
* 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.switchyard.internal.transform;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EventObject;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.xml.namespace.QName;
import org.jboss.logging.Logger;
import org.switchyard.common.xml.QNameUtil;
import org.switchyard.event.EventPublisher;
import org.switchyard.event.TransformerAddedEvent;
import org.switchyard.event.TransformerRemovedEvent;
import org.switchyard.transform.TransformResolver;
import org.switchyard.transform.TransformSequence;
import org.switchyard.runtime.RuntimeMessages;
import org.switchyard.transform.Transformer;
import org.switchyard.transform.TransformerRegistry;
/**
* Maintains a local collection of transformation instances and provides
* facilities to add, query, and remove transforms.
*/
public class BaseTransformerRegistry implements TransformerRegistry {
private static Logger _log = Logger.getLogger(BaseTransformerRegistry.class);
/**
* Default hash code.
*/
private static final int DEFAULT_HASHCODE = 32;
private final ConcurrentHashMap> _transformers =
new ConcurrentHashMap>();
private final ConcurrentHashMap> _fallbackTransformers =
new ConcurrentHashMap>();
private EventPublisher _eventPublisher;
private TransformResolver _transformResolver = new BaseTransformResolver(this);
/**
* Constructor.
*/
public BaseTransformerRegistry() {
}
/**
* Create a new TransformRegistry instance and add the list of transformers
* to the registry.
* @param transformers set of transformers to add to registry
*/
public BaseTransformerRegistry(Set> transformers) {
for (Transformer,?> t : transformers) {
addTransformer(t);
}
}
@Override
public BaseTransformerRegistry addTransformer(Transformer, ?> transformer) {
_fallbackTransformers.clear();
_transformers.put(new NameKey(transformer.getFrom(),
transformer.getTo()), transformer);
publishEvent(new TransformerAddedEvent(transformer));
return this;
}
@Override
public TransformerRegistry addTransformer(Transformer, ?> transformer, QName from, QName to) {
_fallbackTransformers.clear();
_transformers.put(new NameKey(from, to), transformer);
publishEvent(new TransformerAddedEvent(transformer));
return null;
}
/**
* Sets the EventPublisher instance to be used for transformer events.
* @param eventPublisher event publisher
*/
public void setEventPublisher(EventPublisher eventPublisher) {
_eventPublisher = eventPublisher;
}
@Override
public Transformer, ?> getTransformer(QName from, QName to) {
NameKey nameKey = new NameKey(from, to);
Transformer,?> transformer = _transformers.get(nameKey);
if (transformer == null) {
transformer = _fallbackTransformers.get(nameKey);
if (transformer == null && QNameUtil.isJavaMessageType(from)) {
transformer = getJavaFallbackTransformer(from, to);
if (transformer != null && _log.isDebugEnabled()) {
_log.debug("Selecting fallback transformer: from '" + transformer.getFrom() + "' to '" + transformer.getTo() + "'. Type: " + transformer.getClass().getName());
} else if (_log.isDebugEnabled()) {
_log.debug("No compatible transformer registered: from '" + from + "' to '" + to + "'");
}
}
} else if (_log.isDebugEnabled()) {
_log.debug("Selecting transformer: from '" + transformer.getFrom() + "' to '" + transformer.getTo() + "'. Type: " + transformer.getClass().getName());
}
return transformer == NULL_TRANSFORMER ? null : transformer;
}
@Override
public TransformSequence getTransformSequence(QName from, QName to) {
return _transformResolver.resolveSequence(from, to);
}
@Override
public boolean hasTransformer(QName from, QName to) {
NameKey nameKey = new NameKey(from, to);
return _transformers.containsKey(nameKey);
}
private Transformer, ?> getJavaFallbackTransformer(QName from, QName to) {
Class> javaType = QNameUtil.toJavaMessageType(from);
if (javaType == null) {
return null;
}
Set>> entrySet = _transformers.entrySet();
List fallbackTransforms = new ArrayList();
for (Map.Entry> entry : entrySet) {
NameKey nameKey = entry.getKey();
// "to" must be an exact match...
if (nameKey.getTo().equals(to)) {
if (QNameUtil.isJavaMessageType(nameKey.getFrom())) {
Class> candidateType = QNameUtil.toJavaMessageType(nameKey.getFrom());
if (candidateType != null && candidateType.isAssignableFrom(javaType)) {
fallbackTransforms.add(new JavaSourceFallbackTransformer(candidateType, entry.getValue()));
}
}
}
}
if (fallbackTransforms.size() == 0) {
addFallbackTransformer(NULL_TRANSFORMER, from, to);
return NULL_TRANSFORMER;
}
if (fallbackTransforms.size() == 1) {
Transformer, ?> fallbackTransformer = fallbackTransforms.get(0).getTransformer();
addFallbackTransformer(fallbackTransformer, from, to);
return fallbackTransformer;
}
JavaSourceFallbackTransformerComparator comparator = new JavaSourceFallbackTransformerComparator();
Collections.sort(fallbackTransforms, comparator);
if (_log.isDebugEnabled()) {
StringBuilder messageBuilder = new StringBuilder();
messageBuilder.append(RuntimeMessages.MESSAGES.multipleFallbackRegistry());
for (JavaSourceFallbackTransformer t : fallbackTransforms) {
messageBuilder.append("\n\t- from '" + t.getTransformer().getFrom() + "' to '" + t.getTransformer().getTo() + "'");
}
_log.debug(messageBuilder.toString());
}
// Closest super-type will be first in the list..
Transformer, ?> fallbackTransformer = fallbackTransforms.get(0).getTransformer();
addFallbackTransformer(fallbackTransformer, from, to);
return fallbackTransformer;
}
private void addFallbackTransformer(Transformer, ?> fallbackTransformer, QName from, QName to) {
// Fallback transformers are cached so as to save on lookup times...
_fallbackTransformers.put(new NameKey(from, to), fallbackTransformer);
}
@Override
public boolean removeTransformer(Transformer, ?> transformer) {
_fallbackTransformers.clear();
boolean removed = _transformers.remove(
new NameKey(transformer.getFrom(), transformer.getTo())) != null;
if (removed) {
publishEvent(new TransformerRemovedEvent(transformer));
}
return removed;
}
@Override
public List> getRegisteredTransformers() {
return new ArrayList>(_transformers.values());
}
@Override
public List> getTransformersFrom(QName type) {
List> transforms = new LinkedList>();
for (NameKey key : _transformers.keySet()) {
if (key.getFrom() != null && key.getFrom().equals(type)) {
transforms.add(_transformers.get(key));
}
}
return transforms;
}
@Override
public List> getTransformersTo(QName type) {
List> transforms = new LinkedList>();
for (NameKey key : _transformers.keySet()) {
if (key.getTo() != null && key.getTo().equals(type)) {
transforms.add(_transformers.get(key));
}
}
return transforms;
}
@Override
public void setTransfomResolver(TransformResolver resolver) {
this._transformResolver = resolver;
}
// Convenience method to guard against cases when an event publisher has
// not been set.
private void publishEvent(EventObject event) {
if (_eventPublisher != null) {
_eventPublisher.publish(event);
}
}
private class NameKey extends Key {
NameKey(QName from, QName to) {
super(from, to);
}
}
private class Key {
private final F _from;
private final T _to;
Key(F from, T to) {
_from = from;
_to = to;
}
public F getFrom() {
return _from;
}
public T getTo() {
return _to;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || !Key.class.isAssignableFrom(obj.getClass())) {
return false;
}
return isEqual(_from, ((Key,?>) obj).getFrom())
&& isEqual(_to, ((Key,?>) obj).getTo());
}
@Override
public int hashCode() {
return (_from != null ? _from.hashCode() : (DEFAULT_HASHCODE - 1))
+ (_to != null ? _to.hashCode() : DEFAULT_HASHCODE);
}
@Override
public String toString() {
return _from + "::" + _to;
}
// handy method for comparing field refs for equality
private boolean isEqual(Object a, Object b) {
return a == null ? b == null : a.equals(b);
}
}
/**
* Holder type for Fallback Transformer.
*/
public static class JavaSourceFallbackTransformer {
private Class> _javaType;
private Transformer, ?> _transformer;
/**
* Constructor.
* @param javaType Java type.
* @param transformer Transformer instance.
*/
public JavaSourceFallbackTransformer(Class> javaType, Transformer, ?> transformer) {
this._javaType = javaType;
this._transformer = transformer;
}
/**
* Get the Java type.
* @return The Java type.
*/
public Class> getJavaType() {
return _javaType;
}
/**
* Get the Transformer.
* @return The Transformer.
*/
public Transformer, ?> getTransformer() {
return _transformer;
}
}
/**
* Fallback Transformer Sorter.
* @param JavaSourceFallbackTransformer.
*/
@SuppressWarnings("serial")
public static class JavaSourceFallbackTransformerComparator implements Comparator, Serializable {
@Override
public int compare(T t1, T t2) {
if (t1.getJavaType() == t2.getJavaType()) {
return 0;
} else if (t1.getJavaType().isAssignableFrom(t2.getJavaType())) {
return 1;
} else if (t2.getJavaType().isAssignableFrom(t1.getJavaType())) {
return -1;
} else {
// Unrelated types. This means there are branches in the inheritance options,
// which means there are multiple possibilities, therefore it's not uniquely resolvable.
// Marking as equal for now...
return 0;
}
}
}
/**
* NULL_TRANSFORMER is a default validator used to prevent searching for
* fallback validators multiple times. Searching for fallback validators is
* expensive because of Class.forName() usage.
*/
private static final Transformer NULL_TRANSFORMER = new Transformer() {
@Override
public Object transform(Object from) {
return null;
}
@Override
public Transformer setFrom(QName fromType) {
return null;
}
@Override
public QName getFrom() {
return null;
}
@Override
public Transformer setTo(QName toType) {
return null;
}
@Override
public QName getTo() {
return null;
}
@Override
public Class getFromType() {
return null;
}
@Override
public Class getToType() {
return null;
}
};
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy