blob: 166c601a9c67cd17624ec81d0b9be7fabb2a37f3 [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.polygene.runtime.association;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.Objects;
import org.apache.polygene.api.association.AbstractAssociation;
import org.apache.polygene.api.association.AssociationDescriptor;
import org.apache.polygene.api.association.GenericAssociationInfo;
import org.apache.polygene.api.common.MetaInfo;
import org.apache.polygene.api.common.QualifiedName;
import org.apache.polygene.api.constraint.ConstraintViolationException;
import org.apache.polygene.api.entity.Aggregated;
import org.apache.polygene.api.entity.Queryable;
import org.apache.polygene.api.property.Immutable;
import org.apache.polygene.api.util.Classes;
import org.apache.polygene.api.util.Visitable;
import org.apache.polygene.api.util.Visitor;
import org.apache.polygene.bootstrap.BindingException;
import org.apache.polygene.runtime.composite.ValueConstraintsInstance;
import org.apache.polygene.runtime.model.Binder;
import org.apache.polygene.runtime.model.Resolution;
public class AbstractAssociationModel<AT>
implements AbstractAssociation, AssociationDescriptor, AssociationInfo, Binder, Visitable<AT>
{
private final MetaInfo metaInfo;
private final AccessibleObject accessor;
private final QualifiedName qualifiedName;
private final ValueConstraintsInstance constraints;
private final ValueConstraintsInstance associationConstraints;
private final boolean queryable;
private final boolean immutable;
private final boolean aggregated;
private Type type;
private AssociationInfo builderInfo;
public AbstractAssociationModel( AccessibleObject accessor,
ValueConstraintsInstance valueConstraintsInstance,
ValueConstraintsInstance associationConstraintsInstance,
MetaInfo metaInfo )
{
Objects.requireNonNull( accessor );
Objects.requireNonNull( metaInfo );
this.metaInfo = metaInfo;
this.constraints = valueConstraintsInstance;
this.associationConstraints = associationConstraintsInstance;
this.accessor = accessor;
this.type = GenericAssociationInfo.associationTypeOf( accessor );
this.qualifiedName = QualifiedName.fromAccessor( accessor );
this.immutable = metaInfo.get( Immutable.class ) != null;
this.aggregated = metaInfo.get( Aggregated.class ) != null;
Queryable queryable = accessor.getAnnotation( Queryable.class );
this.queryable = queryable == null || queryable.value();
}
@Override
public <T> T metaInfo( Class<T> infoType )
{
return metaInfo.get( infoType );
}
@Override
public QualifiedName qualifiedName()
{
return qualifiedName;
}
@Override
public Type type()
{
return type;
}
@Override
public boolean isImmutable()
{
return immutable;
}
@Override
public boolean isAggregated()
{
return aggregated;
}
@Override
public AccessibleObject accessor()
{
return accessor;
}
@Override
public boolean queryable()
{
return queryable;
}
@Override
public void checkConstraints( Object value )
throws ConstraintViolationException
{
constraints.checkConstraints( value, accessor );
}
public void checkAssociationConstraints( AbstractAssociation association )
throws ConstraintViolationException
{
associationConstraints.checkConstraints( association, accessor );
}
public AssociationInfo builderInfo()
{
return builderInfo;
}
@Override
public void bind( Resolution resolution )
throws BindingException
{
builderInfo = new AssociationInfo()
{
@Override
public boolean isImmutable()
{
return false;
}
@Override
public QualifiedName qualifiedName()
{
return qualifiedName;
}
@Override
public Type type()
{
return type;
}
@Override
public void checkConstraints( Object value )
throws ConstraintViolationException
{
AbstractAssociationModel.this.checkConstraints( value );
}
};
if( type instanceof TypeVariable )
{
Class mainType = resolution.model().types().findFirst().orElse( null );
type = Classes.resolveTypeVariable( (TypeVariable) type, ( (Member) accessor ).getDeclaringClass(), mainType );
}
}
@Override
@SuppressWarnings( "unchecked" )
public <ThrowableType extends Throwable> boolean accept( Visitor<? super AT, ThrowableType> visitor )
throws ThrowableType
{
return visitor.visit( (AT) this );
}
@Override
public boolean equals( Object o )
{
if( this == o )
{
return true;
}
if( o == null || getClass() != o.getClass() )
{
return false;
}
AbstractAssociationModel that = (AbstractAssociationModel) o;
return accessor.equals( that.accessor );
}
@Override
public int hashCode()
{
return accessor.hashCode();
}
@Override
public String toString()
{
if( accessor instanceof Field )
{
return ( (Field) accessor ).toGenericString();
}
else
{
return ( (Method) accessor ).toGenericString();
}
}
}