blob: 2e2b473fdb4045750b8bfba7bc6b526573c9d6c4 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.aries.blueprint.reflect;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.apache.aries.blueprint.PassThroughMetadata;
import org.osgi.service.blueprint.reflect.BeanArgument;
import org.osgi.service.blueprint.reflect.BeanMetadata;
import org.osgi.service.blueprint.reflect.CollectionMetadata;
import org.osgi.service.blueprint.reflect.ComponentMetadata;
import org.osgi.service.blueprint.reflect.IdRefMetadata;
import org.osgi.service.blueprint.reflect.MapMetadata;
import org.osgi.service.blueprint.reflect.Metadata;
import org.osgi.service.blueprint.reflect.NullMetadata;
import org.osgi.service.blueprint.reflect.PropsMetadata;
import org.osgi.service.blueprint.reflect.ReferenceListMetadata;
import org.osgi.service.blueprint.reflect.RefMetadata;
import org.osgi.service.blueprint.reflect.ReferenceMetadata;
import org.osgi.service.blueprint.reflect.ServiceMetadata;
import org.osgi.service.blueprint.reflect.Target;
import org.osgi.service.blueprint.reflect.ValueMetadata;
/**
* A utility class that handles cloning various polymorphic
* bits of metadata into concrete class implementations.
*
* @version $Rev$, $Date$
*/
public class MetadataUtil {
public static final Comparator<BeanArgument> BEAN_COMPARATOR = new BeanArgumentComparator();
static public Metadata cloneMetadata(Metadata source) {
if (source == null) {
return null;
}
else if (source instanceof MapMetadata) {
return new MapMetadataImpl((MapMetadata)source);
}
else if (source instanceof NullMetadata) {
return NullMetadata.NULL;
}
else if (source instanceof PropsMetadata) {
return new PropsMetadataImpl((PropsMetadata)source);
}
else if (source instanceof RefMetadata) {
return new RefMetadataImpl((RefMetadata)source);
}
else if (source instanceof IdRefMetadata) {
return new IdRefMetadataImpl((IdRefMetadata)source);
}
else if (source instanceof ValueMetadata) {
return new ValueMetadataImpl((ValueMetadata)source);
}
else if (source instanceof BeanMetadata) {
return new BeanMetadataImpl((BeanMetadata)source);
}
else if (source instanceof ReferenceListMetadata) {
return new ReferenceListMetadataImpl((ReferenceListMetadata)source);
}
else if (source instanceof ServiceMetadata) {
return new ServiceMetadataImpl((ServiceMetadata)source);
}
else if (source instanceof ReferenceMetadata) {
return new ReferenceMetadataImpl((ReferenceMetadata)source);
}
else if (source instanceof CollectionMetadata) {
return new CollectionMetadataImpl((CollectionMetadata)source);
}
else if (source instanceof PassThroughMetadata) {
return new PassThroughMetadataImpl((PassThroughMetadata)source);
}
throw new RuntimeException("Unknown Metadata type received: " + source.getClass().getName());
}
/**
* Clone a component metadata item, returning a mutable
* instance.
*
* @param source The source metadata item.
*
* @return A mutable instance of this metadata item.
*/
static public ComponentMetadata cloneComponentMetadata(ComponentMetadata source) {
return (ComponentMetadata) cloneMetadata(source);
}
/**
* Clone a target item, returning a mutable
* instance.
*
* @param source The source target item.
*
* @return A mutable instance of this target item.
*/
static public Target cloneTarget(Target source) {
return (Target) cloneMetadata(source);
}
/**
* Create a new metadata instance of the given type
*
* @param type the class of the Metadata object to create
* @param <T>
* @return a new instance
*/
public static <T extends Metadata> T createMetadata(Class<T> type) {
if (MapMetadata.class.isAssignableFrom(type)) {
return type.cast(new MapMetadataImpl());
} else if (NullMetadata.class.isAssignableFrom(type)) {
return type.cast(NullMetadata.NULL);
} else if (PropsMetadata.class.isAssignableFrom(type)) {
return type.cast(new PropsMetadataImpl());
} else if (RefMetadata.class.isAssignableFrom(type)) {
return type.cast(new RefMetadataImpl());
} else if (IdRefMetadata.class.isAssignableFrom(type)) {
return type.cast(new IdRefMetadataImpl());
} else if (ValueMetadata.class.isAssignableFrom(type)) {
return type.cast(new ValueMetadataImpl());
} else if (BeanMetadata.class.isAssignableFrom(type)) {
return type.cast(new BeanMetadataImpl());
} else if (ReferenceListMetadata.class.isAssignableFrom(type)) {
return type.cast(new ReferenceListMetadataImpl());
} else if (ServiceMetadata.class.isAssignableFrom(type)) {
return type.cast(new ServiceMetadataImpl());
} else if (ReferenceMetadata.class.isAssignableFrom(type)) {
return type.cast(new ReferenceMetadataImpl());
} else if (CollectionMetadata.class.isAssignableFrom(type)) {
return type.cast(new CollectionMetadataImpl());
} else if (PassThroughMetadata.class.isAssignableFrom(type)) {
return type.cast(new PassThroughMetadataImpl());
} else {
throw new IllegalArgumentException("Unsupport metadata type: " + (type != null ? type.getName() : null));
}
}
public static List<BeanArgument> validateBeanArguments(List<BeanArgument> arguments) {
if (arguments == null || arguments.isEmpty()) {
return arguments;
}
// check if all or none arguments have index attribute
boolean hasIndexFirst = (arguments.get(0).getIndex() > -1);
for (int i = 1; i < arguments.size(); i++) {
boolean hasIndex = (arguments.get(i).getIndex() > -1);
if ( (hasIndexFirst && !hasIndex) ||
(!hasIndexFirst && hasIndex) ) {
throw new IllegalArgumentException("Index attribute must be specified either on all or none constructor arguments");
}
}
if (hasIndexFirst) {
// sort the arguments
List<BeanArgument> argumentsCopy = new ArrayList<BeanArgument>(arguments);
Collections.sort(argumentsCopy, MetadataUtil.BEAN_COMPARATOR);
arguments = argumentsCopy;
// check if the indexes are sequential
for (int i = 0; i < arguments.size(); i++) {
int index = arguments.get(i).getIndex();
if (index > i) {
throw new IllegalArgumentException("Missing attribute index");
} else if (index < i) {
throw new IllegalArgumentException("Duplicate attribute index");
} // must be the same
}
}
return arguments;
}
public static boolean isPrototypeScope(BeanMetadata metadata) {
return (BeanMetadata.SCOPE_PROTOTYPE.equals(metadata.getScope()) ||
(metadata.getScope() == null && metadata.getId() == null));
}
public static boolean isSingletonScope(BeanMetadata metadata) {
return (BeanMetadata.SCOPE_SINGLETON.equals(metadata.getScope()) ||
(metadata.getScope() == null && metadata.getId() != null));
}
public static boolean isCustomScope(BeanMetadata metadata) {
return (metadata.getScope() != null &&
!BeanMetadata.SCOPE_PROTOTYPE.equals(metadata.getScope()) &&
!BeanMetadata.SCOPE_SINGLETON.equals(metadata.getScope()));
}
private static class BeanArgumentComparator implements Comparator<BeanArgument>, Serializable {
public int compare(BeanArgument object1, BeanArgument object2) {
return object1.getIndex() - object2.getIndex();
}
}
}