blob: 5a4628e9e0354b6b2613b456779d37ef62ea77a4 [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.qpid.server.model;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.Principal;
import java.security.cert.Certificate;
import java.security.cert.CertificateEncodingException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.qpid.server.model.preferences.GenericPrincipal;
import org.apache.qpid.server.security.QpidPrincipal;
import org.apache.qpid.server.util.ServerScopedRuntimeException;
public class ConfiguredObjectCustomSerialization
{
private static final Set<String> OBJECT_METHOD_NAMES = Collections.synchronizedSet(new HashSet<String>());
static
{
for(Method method : Object.class.getMethods())
{
OBJECT_METHOD_NAMES.add(method.getName());
}
}
public interface Converter<T>
{
Class<T> getConversionClass();
Object convert(T value);
}
private static final Map<Class<?>, Converter<?>> REGISTERED_CONVERTERS = new ConcurrentHashMap<>();
private static final Map<Class<?>, Converter<?>> REGISTERED_PERSISTENCE_CONVERTERS = new ConcurrentHashMap<>();
private abstract static class AbstractConverter<T> implements Converter<T>
{
private final Class<T> _conversionClass;
public AbstractConverter(Class<T> conversionClass)
{
this(conversionClass, true, true);
}
public AbstractConverter(Class<T> conversionClass, boolean nonPersistenceConverter, boolean persistenceConverted)
{
if(nonPersistenceConverter)
{
REGISTERED_CONVERTERS.put(conversionClass, this);
}
if(persistenceConverted)
{
REGISTERED_PERSISTENCE_CONVERTERS.put(conversionClass, this);
}
_conversionClass = conversionClass;
}
@Override
public final Class<T> getConversionClass()
{
return _conversionClass;
}
}
public static Collection<Converter<?>> getConverters(final boolean forPersistence)
{
return forPersistence ? REGISTERED_PERSISTENCE_CONVERTERS.values() : REGISTERED_CONVERTERS.values();
}
@SuppressWarnings("unused")
private static final Converter<Principal> PRINCIPAL_CONVERTER =
new AbstractConverter<Principal>(Principal.class)
{
@Override
public Object convert(final Principal value)
{
if (value instanceof QpidPrincipal)
{
return new GenericPrincipal((QpidPrincipal) value).toExternalForm();
}
else if (value instanceof GenericPrincipal)
{
return ((GenericPrincipal) value).toExternalForm();
}
else
{
return value.getName();
}
}
};
@SuppressWarnings("unused")
private static final Converter<Certificate> CERTIFICATE_CONVERTER =
new AbstractConverter<Certificate>(Certificate.class)
{
@Override
public Object convert(final Certificate value)
{
try
{
return value.getEncoded();
}
catch (CertificateEncodingException e)
{
throw new IllegalArgumentException(e);
}
}
};
@SuppressWarnings("unused")
private static final Converter<ConfiguredObject> CONFIGURED_OBJECT_CONVERTER =
new AbstractConverter<ConfiguredObject>(ConfiguredObject.class)
{
@Override
public Object convert(final ConfiguredObject value)
{
return value.getId().toString();
}
};
@SuppressWarnings("unused")
private static final Converter<ManagedAttributeValue> MANAGED_ATTRIBUTE_VALUE_CONVERTER =
new ManagedAttributeValueAbstractConverter(true);
@SuppressWarnings("unused")
private static final Converter<ManagedAttributeValue> MANAGED_ATTRIBUTE_VALUE_PERSISTENCE_CONVERTER =
new ManagedAttributeValueAbstractConverter(false);
private static class ManagedAttributeValueAbstractConverter extends AbstractConverter<ManagedAttributeValue>
{
private final boolean _includeDerivedAttributes;
public ManagedAttributeValueAbstractConverter(final boolean includeDerivedAttributes)
{
super(ManagedAttributeValue.class, includeDerivedAttributes, !includeDerivedAttributes);
_includeDerivedAttributes = includeDerivedAttributes;
}
@Override
public Object convert(final ManagedAttributeValue value)
{
Map<String, Object> valueAsMap = new LinkedHashMap<>();
for (Method method : value.getClass().getMethods())
{
final String methodName = method.getName();
if (method.getParameterTypes().length == 0
&& !OBJECT_METHOD_NAMES.contains(methodName)
&& (methodName.startsWith("is")
|| methodName.startsWith("has")
|| methodName.startsWith("get")))
{
if(_includeDerivedAttributes || !isDerivedMethod(method))
{
String propertyName =
methodName.startsWith("is") ? methodName.substring(2) : methodName.substring(3);
propertyName = Character.toLowerCase(propertyName.charAt(0)) + propertyName.substring(1);
try
{
final Object attrValue = method.invoke(value);
if (attrValue != null)
{
valueAsMap.put(propertyName, attrValue);
}
}
catch (IllegalAccessException | InvocationTargetException e)
{
throw new ServerScopedRuntimeException(e);
}
}
}
}
return valueAsMap;
}
private boolean isDerivedMethod(final Method method)
{
final boolean annotationPresent = method.isAnnotationPresent(ManagedAttributeValueTypeDerivedMethod.class);
if(!annotationPresent)
{
final Class<?> clazz = method.getDeclaringClass();
final String methodName = method.getName();
if (isDerivedMethod(clazz, methodName))
{
return true;
}
}
return annotationPresent;
}
private boolean isDerivedMethod(final Class<?> clazz, final String methodName)
{
for(Method method : clazz.getDeclaredMethods())
{
if(method.getName().equals(methodName)
&& method.getParameterTypes().length==0)
{
if(method.isAnnotationPresent(ManagedAttributeValueTypeDerivedMethod.class))
{
return true;
}
else
{
break;
}
}
}
for(Class<?> iface : clazz.getInterfaces())
{
if(ManagedAttributeValue.class.isAssignableFrom(iface))
{
if(isDerivedMethod(iface, methodName))
{
return true;
}
}
}
if(clazz.getSuperclass() != null && ManagedAttributeValue.class.isAssignableFrom(clazz.getSuperclass()))
{
if(isDerivedMethod(clazz.getSuperclass(), methodName))
{
return true;
}
}
return false;
}
}
}