/*
* 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.felix.converter.impl;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.osgi.util.converter.ConversionException;
import org.osgi.util.converter.Converter;
import org.osgi.util.converter.ConverterBuilder;
import org.osgi.util.converter.ConverterFunction;
import org.osgi.util.converter.Converting;
import org.osgi.util.converter.TypeReference;
public class AdapterImpl implements InternalConverter {
private final InternalConverter delegate;
private final Map<Type, List<ConverterFunction>> typeRules;
private final List<ConverterFunction> allRules;
private final List<ConverterFunction> errorHandlers;
AdapterImpl(InternalConverter converter, Map<Type, List<ConverterFunction>> rules,
List<ConverterFunction> catchAllRules, List<ConverterFunction> errHandlers) {
delegate = converter;
typeRules = rules;
allRules = catchAllRules;
errorHandlers = errHandlers;
}
@Override
public InternalConverting convert(Object obj) {
InternalConverting converting = delegate.convert(obj);
converting.setConverter(this);
return new ConvertingWrapper(obj, converting);
}
@Override
public ConverterBuilder newConverterBuilder() {
return new ConverterBuilderImpl(this);
}
private class ConvertingWrapper implements InternalConverting {
private final InternalConverting del;
private final Object object;
private volatile Object defaultValue;
private volatile boolean hasDefault;
ConvertingWrapper(Object obj, InternalConverting c) {
object = obj;
del = c;
}
@Override
public Converting copy() {
del.copy();
return this;
}
@Override
public Converting defaultValue(Object defVal) {
del.defaultValue(defVal);
defaultValue = defVal;
hasDefault = true;
return this;
}
@Override
public Converting keysIgnoreCase() {
del.keysIgnoreCase();
return this;
}
@Override
public void setConverter(Converter c) {
del.setConverter(c);
}
@Override
public Converting sourceAs(Class<?> type) {
del.sourceAs(type);
return this;
}
@Override
public Converting sourceAsBean() {
del.sourceAsBean();
return this;
}
@Override
public Converting sourceAsDTO() {
del.sourceAsDTO();
return this;
}
@Override
public Converting targetAs(Class<?> cls) {
del.targetAs(cls);
return this;
}
@Override
public Converting targetAsBean() {
del.targetAsBean();
return this;
}
@Override
public Converting targetAsDTO() {
del.targetAsDTO();
return this;
}
@SuppressWarnings("unchecked")
@Override
public <T> T to(Class<T> cls) {
Type type = cls;
return (T) to(type);
}
@SuppressWarnings("unchecked")
@Override
public <T> T to(TypeReference<T> ref) {
return (T) to(ref.getType());
}
@SuppressWarnings("unchecked")
@Override
public Object to(Type type) {
List<ConverterFunction> tr = typeRules.get(Util.baseType(type));
if (tr == null)
tr = Collections.emptyList();
List<ConverterFunction> converters = new ArrayList<>(tr.size() + allRules.size());
converters.addAll(tr);
converters.addAll(allRules);
try {
if (object != null) {
for (ConverterFunction cf : converters) {
try {
Object res = cf.apply(object, type);
if (res != null) {
return res;
}
} catch (Exception ex) {
if (hasDefault)
return defaultValue;
else
throw new ConversionException("Cannot convert " + object + " to " + type, ex);
}
}
}
return del.to(type);
} catch (Exception ex) {
for (ConverterFunction eh : errorHandlers) {
try {
Object handled = eh.apply(object, type);
if (handled != null)
return handled;
} catch (RuntimeException re) {
throw re;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
// No error handler, throw the original exception
throw ex;
}
}
@Override
public String toString() {
return to(String.class);
}
}
}