blob: e5457ee3a5cd2cfba52384924d732f57ad6562a3 [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.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.UUID;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.store.ConfiguredObjectDependency;
import org.apache.qpid.server.store.ConfiguredObjectIdDependency;
import org.apache.qpid.server.store.ConfiguredObjectNameDependency;
import org.apache.qpid.server.store.ConfiguredObjectRecord;
import org.apache.qpid.server.store.UnresolvedConfiguredObject;
public abstract class AbstractUnresolvedObject<C extends ConfiguredObject<C>> implements UnresolvedConfiguredObject<C>
{
private final Class<C> _clazz;
private final Collection<ConfiguredObjectDependency<?>> _unresolvedObjects = new ArrayList<ConfiguredObjectDependency<?>>();
private final ConfiguredObjectRecord _record;
private final ConfiguredObject<?>[] _parents;
protected AbstractUnresolvedObject(Class<C> clazz,
ConfiguredObjectRecord record,
ConfiguredObject<?>... parents)
{
_clazz = clazz;
_record = record;
_parents = parents;
Collection<ConfiguredObjectAttribute<? super C, ?>> attributes =
parents[0].getModel().getTypeRegistry().getAttributes(clazz);
for(ConfiguredObjectAttribute<? super C, ?> attribute : attributes)
{
if(attribute.isPersisted())
{
final Class<?> attributeType = attribute.getType();
if (ConfiguredObject.class.isAssignableFrom(attributeType))
{
addUnresolvedObject((Class<? extends ConfiguredObject>) attributeType,
attribute.getName(),
attribute.isAutomated() && ((ConfiguredSettableAttribute<? super C,?>)attribute).isMandatory());
}
else if (Collection.class.isAssignableFrom(attributeType))
{
Type returnType = attribute.getGenericType();
Class<? extends ConfiguredObject> attrClass = getMemberType(returnType);
if (attrClass != null)
{
Object attrValue = _record.getAttributes().get(attribute.getName());
if (attrValue != null)
{
if (attrValue instanceof Collection)
{
for (Object val : (Collection) attrValue)
{
addUnresolvedObject(attrClass, attribute.getName(), val);
}
}
else if (attrValue instanceof Object[])
{
for (Object val : (Object[]) attrValue)
{
addUnresolvedObject(attrClass, attribute.getName(), val);
}
}
else
{
addUnresolvedObject(attrClass, attribute.getName(), attrValue);
}
}
}
}
}
}
}
private Class<? extends ConfiguredObject> getMemberType(Type returnType)
{
Class<? extends ConfiguredObject> categoryClass = null;
if (returnType instanceof ParameterizedType)
{
Type type = ((ParameterizedType) returnType).getActualTypeArguments()[0];
if (type instanceof Class && ConfiguredObject.class.isAssignableFrom((Class)type))
{
categoryClass = (Class<? extends ConfiguredObject>) type;
}
else if (type instanceof ParameterizedType)
{
Type rawType = ((ParameterizedType) type).getRawType();
if (rawType instanceof Class && ConfiguredObject.class.isAssignableFrom((Class)rawType))
{
categoryClass = (Class<? extends ConfiguredObject>) rawType;
}
}
else if (type instanceof TypeVariable)
{
Type[] bounds = ((TypeVariable) type).getBounds();
for(Type boundType : bounds)
{
categoryClass = getMemberType(boundType);
if(categoryClass != null)
{
break;
}
}
}
}
return categoryClass;
}
public ConfiguredObjectRecord getRecord()
{
return _record;
}
public ConfiguredObject<?>[] getParents()
{
return _parents;
}
private void addUnresolvedObject(final Class<? extends ConfiguredObject> clazz,
final String attributeName,
boolean mandatory)
{
Object attrValue = _record.getAttributes().get(attributeName);
if(attrValue != null)
{
addUnresolvedObject(clazz, attributeName, attrValue);
}
else if(mandatory)
{
throw new IllegalConfigurationException("Missing attribute " + attributeName + " has no value");
}
}
private void addUnresolvedObject(final Class<? extends ConfiguredObject> clazz,
final String attributeName,
final Object attrValue)
{
if(attrValue instanceof UUID)
{
_unresolvedObjects.add(new IdDependency(clazz, attributeName, (UUID) attrValue));
}
else if(attrValue instanceof String)
{
String interpolatedValue = AbstractConfiguredObject.interpolate(_parents[0], (String) attrValue);
try
{
_unresolvedObjects.add(new IdDependency(clazz, attributeName, UUID.fromString(interpolatedValue)));
}
catch(IllegalArgumentException e)
{
_unresolvedObjects.add(new NameDependency(clazz, attributeName, interpolatedValue));
}
}
else if(!clazz.isInstance(attrValue))
{
throw new IllegalArgumentException("Cannot convert from type " + attrValue.getClass() + " to a configured object dependency");
}
}
protected abstract <X extends ConfiguredObject<X>> void resolved(ConfiguredObjectDependency<X> dependency, X value);
@Override
public Collection<ConfiguredObjectDependency<?>> getUnresolvedDependencies()
{
return _unresolvedObjects;
}
@Override
public String toString()
{
return getClass().getSimpleName() + "{" +
"class=" + _clazz.getSimpleName() +
", unresolvedObjects=" + _unresolvedObjects +
'}';
}
private abstract class Dependency<X extends ConfiguredObject<X>> implements ConfiguredObjectDependency<X>
{
private final Class<X> _clazz;
private final String _attributeName;
public Dependency(final Class<X> clazz,
final String attributeName)
{
_clazz = clazz;
_attributeName = attributeName;
}
@Override
public final Class<X> getCategoryClass()
{
return _clazz;
}
@Override
public final void resolve(final X object)
{
_unresolvedObjects.remove(this);
resolved(this, object);
}
public final String getAttributeName()
{
return _attributeName;
}
}
private class IdDependency<X extends ConfiguredObject<X>> extends Dependency<X> implements ConfiguredObjectIdDependency<X>
{
private final UUID _id;
public IdDependency(final Class<X> clazz,
final String attributeName,
final UUID id)
{
super(clazz, attributeName);
_id = id;
}
@Override
public UUID getId()
{
return _id;
}
@Override
public String toString()
{
return "IdDependency{" + getCategoryClass().getSimpleName() + ", " + _id + " }";
}
}
private class NameDependency<X extends ConfiguredObject<X>> extends Dependency<X> implements ConfiguredObjectNameDependency<X>
{
private final String _name;
public NameDependency(final Class<X> clazz,
final String attributeName,
final String attrValue)
{
super(clazz, attributeName);
_name = attrValue;
}
@Override
public String getName()
{
return _name;
}
@Override
public String toString()
{
return "NameDependency{" + getCategoryClass().getSimpleName() + ", \"" + _name + "\" }";
}
}
}