/******************************************************************************
* Copyright (c) 2006, 2010 VMware Inc., Oracle Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html and the Apache License v2.0
* is available at http://www.opensource.org/licenses/apache2.0.php.
* You may elect to redistribute this code under either of these licenses.
*
* Contributors:
* VMware Inc.
* Oracle Inc.
*****************************************************************************/
package org.eclipse.gemini.blueprint.config.internal.util;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import org.eclipse.gemini.blueprint.config.internal.adapter.ToStringClassAdapter;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.ManagedSet;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
/**
* Parsing utility class.
*
* @author Andy Piper
* @author Costin Leau
*/
public abstract class ParserUtils {
private static final AttributeCallback STANDARD_ATTRS_CALLBACK = new StandardAttributeCallback();
private static final AttributeCallback BLUEPRINT_ATTRS_CALLBACK = new BlueprintAttributeCallback();
private static final AttributeCallback PROPERTY_REF_ATTRS_CALLBACK = new PropertyRefAttributeCallback();
private static final AttributeCallback PROPERTY_CONV_ATTRS_CALLBACK = new ConventionsCallback();
public static final String REFERENCE_LISTENER_REF_ATTR =
"org.eclipse.gemini.blueprint.config.internal.reference.listener.ref.attr";
/**
* Generic attribute callback. Will parse the given callback array, w/o any standard callback.
*
* @param element XML element
* @param builder current bean definition builder
* @param callbacks array of callbacks (can be null/empty)
*/
public static void parseAttributes(Element element, BeanDefinitionBuilder builder, AttributeCallback[] callbacks) {
NamedNodeMap attributes = element.getAttributes();
for (int x = 0; x < attributes.getLength(); x++) {
Attr attr = (Attr) attributes.item(x);
boolean shouldContinue = true;
if (!ObjectUtils.isEmpty(callbacks))
for (int i = 0; i < callbacks.length && shouldContinue; i++) {
AttributeCallback callback = callbacks[i];
shouldContinue = callback.process(element, attr, builder);
}
}
}
/**
* Dedicated parsing method that uses the following stack:
*
* <ol> <li>user given {@link AttributeCallback}s</li> <li>{@link StandardAttributeCallback}</li> <li>
* {@link PropertyRefAttributeCallback}</li> <li>{@link ConventionCallback}</li> </ol> </pre>
*
* @param element XML element
* @param builder current bean definition builder
* @param callbacks array of callbacks (can be null/empty)
*/
public static void parseCustomAttributes(Element element, BeanDefinitionBuilder builder,
AttributeCallback[] callbacks) {
List list = new ArrayList(8);
if (!ObjectUtils.isEmpty(callbacks))
CollectionUtils.mergeArrayIntoCollection(callbacks, list);
// add standard callback
list.add(STANDARD_ATTRS_CALLBACK);
list.add(BLUEPRINT_ATTRS_CALLBACK);
list.add(PROPERTY_REF_ATTRS_CALLBACK);
list.add(PROPERTY_CONV_ATTRS_CALLBACK);
AttributeCallback[] cbacks = (AttributeCallback[]) list.toArray(new AttributeCallback[list.size()]);
parseAttributes(element, builder, cbacks);
}
/**
* Derivative for
* {@link #parseCustomAttributes(Element, BeanDefinitionBuilder, org.eclipse.gemini.blueprint.internal.config.ParserUtils.AttributeCallback[])}
* accepting only one {@link AttributeCallback}.
*
* @param element XML element
* @param builder current bean definition builder
* @param callback attribute callback, can be null
*/
public static void parseCustomAttributes(Element element, BeanDefinitionBuilder builder, AttributeCallback callback) {
AttributeCallback[] callbacks =
(callback == null ? new AttributeCallback[0] : new AttributeCallback[] { callback });
parseCustomAttributes(element, builder, callbacks);
}
public static AttributeCallback[] mergeCallbacks(AttributeCallback[] callbacksA, AttributeCallback[] callbacksB) {
if (ObjectUtils.isEmpty(callbacksA))
if (ObjectUtils.isEmpty(callbacksB))
return new AttributeCallback[0];
else
return callbacksB;
if (ObjectUtils.isEmpty(callbacksB))
return callbacksA;
AttributeCallback[] newCallbacks = new AttributeCallback[callbacksA.length + callbacksB.length];
System.arraycopy(callbacksA, 0, newCallbacks, 0, callbacksA.length);
System.arraycopy(callbacksB, 0, newCallbacks, callbacksA.length, callbacksB.length);
return newCallbacks;
}
/**
* Utility method used for maintaining backwards compatibility by converting Class objects to String (using their
* class names). Used by importer and exporter parsing to set the 'interfaces' property.
*
* @param parsedClasses collection of parsed classes
* @return a collection of converted (if necessary) metadata
*/
public static Set<?> convertClassesToStrings(Set<?> parsedClasses) {
Set<Object> interfaces = new ManagedSet<Object>(parsedClasses.size());
for (Object clazz : parsedClasses) {
if (clazz instanceof TypedStringValue || clazz instanceof String) {
interfaces.add(clazz);
} else {
// add adapter definition for bean references (which can be classes)
interfaces.add(BeanDefinitionBuilder.genericBeanDefinition(ToStringClassAdapter.class)
.addConstructorArgValue(clazz).getBeanDefinition());
}
}
return interfaces;
}
}