blob: d7d1008006cf8e4260ae159185f37ac44f766a77 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2006, 2010 VMware 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.
*****************************************************************************/
package org.eclipse.gemini.blueprint.config.internal;
import java.util.Comparator;
import java.util.Locale;
import org.eclipse.gemini.blueprint.config.internal.util.AttributeCallback;
import org.eclipse.gemini.blueprint.config.internal.util.ParserUtils;
import org.eclipse.gemini.blueprint.service.importer.support.CollectionType;
import org.eclipse.gemini.blueprint.service.importer.support.MemberType;
import org.eclipse.gemini.blueprint.service.importer.support.OsgiServiceCollectionProxyFactoryBean;
import org.eclipse.gemini.blueprint.service.importer.support.internal.util.ServiceReferenceComparator;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.xml.DomUtils;
import org.w3c.dom.Attr;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* <osgi:list>, <osgi:set>, element parser.
*
* @author Costin Leau
*
*/
public abstract class CollectionBeanDefinitionParser extends AbstractReferenceDefinitionParser {
/**
* Greedy proxy attribute callback.
*
* @author Costin Leau
*/
static class CollectionAttributeCallback implements AttributeCallback {
public boolean process(Element parent, Attr attribute, BeanDefinitionBuilder builder) {
String name = attribute.getLocalName();
if (MEMBER_TYPE.equals(name)) {
builder.addPropertyValue(MEMBER_TYPE_PROPERTY, MemberType.valueOf(attribute.getValue().toUpperCase(Locale.ENGLISH)
.replace('-', '_')));
return false;
}
return true;
}
}
private static final String NESTED_COMPARATOR = "comparator";
private static final String INLINE_COMPARATOR_REF = "comparator-ref";
private static final String COLLECTION_TYPE_PROP = "collectionType";
private static final String COMPARATOR_PROPERTY = "comparator";
private static final String SERVICE_ORDER = "service";
private static final String SERVICE_REFERENCE_ORDER = "service-reference";
private static final String MEMBER_TYPE = "member-type";
private static final String MEMBER_TYPE_PROPERTY = "memberType";
private static final Comparator SERVICE_REFERENCE_COMPARATOR = new ServiceReferenceComparator();
private static final String NATURAL = "natural";
private static final String BASIS = "basis";
protected Class getBeanClass(Element element) {
return OsgiServiceCollectionProxyFactoryBean.class;
}
/**
* {@inheritDoc}
*
* Add support for 'greedy-proxying' attribute.
*/
protected void parseAttributes(Element element, BeanDefinitionBuilder builder, AttributeCallback[] callbacks,
OsgiDefaultsDefinition defaults) {
// add timeout callback
CollectionAttributeCallback greedyProxyingCallback = new CollectionAttributeCallback();
super.parseAttributes(element, builder, ParserUtils.mergeCallbacks(callbacks,
new AttributeCallback[] { greedyProxyingCallback }), defaults);
}
protected void parseNestedElements(Element element, ParserContext context, BeanDefinitionBuilder builder) {
super.parseNestedElements(element, context, builder);
parseComparator(element, context, builder);
}
/**
* Parse <comparator> element.
*
* @param element
* @param context
* @param builder
*/
protected void parseComparator(Element element, ParserContext context, BeanDefinitionBuilder builder) {
boolean hasComparatorRef = element.hasAttribute(INLINE_COMPARATOR_REF);
// check nested comparator
Element comparatorElement = DomUtils.getChildElementByTagName(element, NESTED_COMPARATOR);
Object nestedComparator = null;
// comparator definition present
if (comparatorElement != null) {
// check duplicate nested and inline bean definition
if (hasComparatorRef)
context.getReaderContext().error(
"nested comparator declaration is not allowed if " + INLINE_COMPARATOR_REF
+ " attribute has been specified", comparatorElement);
NodeList nl = comparatorElement.getChildNodes();
// take only elements
for (int i = 0; i < nl.getLength(); i++) {
Node nd = nl.item(i);
if (nd instanceof Element) {
Element beanDef = (Element) nd;
String name = beanDef.getLocalName();
// check if we have a 'natural' tag (known comparator
// definitions)
if (NATURAL.equals(name))
nestedComparator = parseNaturalComparator(beanDef);
else
// we have a nested definition
nestedComparator = parsePropertySubElement(context, beanDef, builder.getBeanDefinition());
}
}
// set the reference to the nested comparator reference
if (nestedComparator != null)
builder.addPropertyValue(COMPARATOR_PROPERTY, nestedComparator);
}
// set collection type
// based on the existence of the comparator
// we treat the case where the comparator is natural which means the
// comparator
// instance is null however, we have to force a sorted collection to be
// used
// so that the object natural ordering is used.
if (comparatorElement != null || hasComparatorRef) {
if (CollectionType.LIST.equals(collectionType())) {
builder.addPropertyValue(COLLECTION_TYPE_PROP, CollectionType.SORTED_LIST);
}
if (CollectionType.SET.equals(collectionType())) {
builder.addPropertyValue(COLLECTION_TYPE_PROP, CollectionType.SORTED_SET);
}
} else {
builder.addPropertyValue(COLLECTION_TYPE_PROP, collectionType());
}
}
/**
* Parse &lt;osgi:natural&gt; element.
*
* @param element
* @return
*/
protected Comparator parseNaturalComparator(Element element) {
Comparator comparator = null;
NamedNodeMap attributes = element.getAttributes();
for (int x = 0; x < attributes.getLength(); x++) {
Attr attribute = (Attr) attributes.item(x);
String name = attribute.getLocalName();
String value = attribute.getValue();
if (BASIS.equals(name)) {
if (SERVICE_REFERENCE_ORDER.equals(value))
return SERVICE_REFERENCE_COMPARATOR;
// no comparator means relying on Comparable interface of the
// services
else if (SERVICE_ORDER.equals(value))
return null;
}
}
return comparator;
}
/**
* Hook used for indicating the main collection type (set/list) on which this parser applies.
*
* @return service collection type
*/
protected abstract CollectionType collectionType();
}