/**
* 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.cxf.jaxrs.impl;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.logging.Logger;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Feature;
import org.apache.cxf.common.logging.LogUtils;
import org.apache.cxf.jaxrs.utils.AnnotationUtils;
public class ConfigurationImpl implements Configuration {
private static final Logger LOG = LogUtils.getL7dLogger(ConfigurationImpl.class);
private Map<String, Object> props = new HashMap<>();
private RuntimeType runtimeType;
private Map<Object, Map<Class<?>, Integer>> providers =
new LinkedHashMap<Object, Map<Class<?>, Integer>>();
private Map<Feature, Boolean> features = new LinkedHashMap<Feature, Boolean>();
public ConfigurationImpl(RuntimeType rt) {
this.runtimeType = rt;
}
public ConfigurationImpl(Configuration parent, Class<?>[] defaultContracts) {
if (parent != null) {
this.props.putAll(parent.getProperties());
this.runtimeType = parent.getRuntimeType();
Set<Class<?>> providerClasses = new HashSet<Class<?>>(parent.getClasses());
for (Object o : parent.getInstances()) {
if (!(o instanceof Feature)) {
registerParentProvider(o, parent, defaultContracts);
} else {
Feature f = (Feature)o;
features.put(f, parent.isEnabled(f));
}
providerClasses.remove(o.getClass());
}
for (Class<?> cls : providerClasses) {
registerParentProvider(createProvider(cls), parent, defaultContracts);
}
}
}
private void registerParentProvider(Object o, Configuration parent, Class<?>[] defaultContracts) {
Map<Class<?>, Integer> contracts = parent.getContracts(o.getClass());
if (contracts != null) {
providers.put(o, contracts);
} else {
register(o, AnnotationUtils.getBindingPriority(o.getClass()), defaultContracts);
}
}
@Override
public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
for (Object o : getInstances()) {
classes.add(o.getClass());
}
return classes;
}
@Override
public Map<Class<?>, Integer> getContracts(Class<?> cls) {
for (Object o : getInstances()) {
if (cls.isAssignableFrom(o.getClass())) {
return Collections.unmodifiableMap(providers.get(o));
}
}
return Collections.emptyMap();
}
@Override
public Set<Object> getInstances() {
Set<Object> allInstances = new HashSet<>();
allInstances.addAll(providers.keySet());
allInstances.addAll(features.keySet());
return Collections.unmodifiableSet(allInstances);
}
@Override
public Map<String, Object> getProperties() {
return Collections.unmodifiableMap(props);
}
@Override
public Object getProperty(String name) {
return props.get(name);
}
@Override
public Collection<String> getPropertyNames() {
return Collections.unmodifiableSet(props.keySet());
}
@Override
public RuntimeType getRuntimeType() {
return runtimeType;
}
@Override
public boolean isEnabled(Feature f) {
return features.containsKey(f);
}
@Override
public boolean isEnabled(Class<? extends Feature> f) {
for (Feature feature : features.keySet()) {
if (feature.getClass().isAssignableFrom(f)) {
return true;
}
}
return false;
}
@Override
public boolean isRegistered(Object obj) {
for (Object o : getInstances()) {
if (o.equals(obj)) {
return true;
}
}
return false;
}
@Override
public boolean isRegistered(Class<?> cls) {
for (Object o : getInstances()) {
if (cls == o.getClass()) {
return true;
}
}
return false;
}
public void setProperty(String name, Object value) {
if (name == null) {
props.remove(name);
} else {
props.put(name, value);
}
}
public void setFeature(Feature f, boolean enabled) {
features.put(f, enabled);
}
private void register(Object provider, int bindingPriority, Class<?>... contracts) {
register(provider, initContractsMap(bindingPriority, contracts));
}
public boolean register(Object provider, Map<Class<?>, Integer> contracts) {
if (provider.getClass() == Class.class) {
if (isRegistered((Class<?>)provider)) {
LOG.warning("Provider class " + ((Class<?>)provider).getName() + " has already been registered");
return false;
}
provider = createProvider((Class<?>)provider);
}
if (isRegistered(provider)) {
LOG.warning("Provider " + provider.getClass().getName() + " has already been registered");
return false;
}
Map<Class<?>, Integer> metadata = providers.get(provider);
if (metadata == null) {
metadata = new HashMap<>();
providers.put(provider, metadata);
}
for (Entry<Class<?>, Integer> entry : contracts.entrySet()) {
if (entry.getKey().isAssignableFrom(provider.getClass())) {
metadata.put(entry.getKey(), entry.getValue());
}
}
return true;
}
public static Map<Class<?>, Integer> initContractsMap(int bindingPriority, Class<?>... contracts) {
Map<Class<?>, Integer> metadata = new HashMap<>();
for (Class<?> contract : contracts) {
metadata.put(contract, bindingPriority);
}
return metadata;
}
public static Object createProvider(Class<?> cls) {
try {
return cls.newInstance();
} catch (Throwable ex) {
throw new RuntimeException(ex);
}
}
}