| /* |
| * Copyright (c) 2007-2011, Rickard Öberg. All Rights Reserved. |
| * Copyright (c) 2014, Paul Merlin. All Rights Reserved. |
| * |
| * Licensed 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.qi4j.runtime.bootstrap; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.AccessibleObject; |
| import java.lang.reflect.Member; |
| import org.qi4j.api.association.Association; |
| import org.qi4j.api.association.GenericAssociationInfo; |
| import org.qi4j.api.association.ManyAssociation; |
| import org.qi4j.api.association.NamedAssociation; |
| import org.qi4j.api.common.InvalidApplicationException; |
| import org.qi4j.api.common.MetaInfo; |
| import org.qi4j.api.common.Optional; |
| import org.qi4j.api.common.QualifiedName; |
| import org.qi4j.api.common.UseDefaults; |
| import org.qi4j.api.constraint.Constraint; |
| import org.qi4j.api.property.GenericPropertyInfo; |
| import org.qi4j.api.property.Property; |
| import org.qi4j.api.util.Annotations; |
| import org.qi4j.api.util.Classes; |
| import org.qi4j.api.value.ValueComposite; |
| import org.qi4j.bootstrap.StateDeclarations; |
| import org.qi4j.bootstrap.ValueAssembly; |
| import org.qi4j.runtime.association.AssociationModel; |
| import org.qi4j.runtime.association.AssociationsModel; |
| import org.qi4j.runtime.association.ManyAssociationModel; |
| import org.qi4j.runtime.association.ManyAssociationsModel; |
| import org.qi4j.runtime.association.NamedAssociationModel; |
| import org.qi4j.runtime.association.NamedAssociationsModel; |
| import org.qi4j.runtime.composite.StateModel; |
| import org.qi4j.runtime.composite.ValueConstraintsInstance; |
| import org.qi4j.runtime.composite.ValueConstraintsModel; |
| import org.qi4j.runtime.property.PropertyModel; |
| import org.qi4j.runtime.value.ValueModel; |
| import org.qi4j.runtime.value.ValueStateModel; |
| |
| import static org.qi4j.api.util.Annotations.isType; |
| import static org.qi4j.api.util.Classes.typeOf; |
| import static org.qi4j.functional.Iterables.filter; |
| import static org.qi4j.functional.Iterables.first; |
| |
| /** |
| * Declaration of a ValueComposite. |
| */ |
| public final class ValueAssemblyImpl |
| extends CompositeAssemblyImpl |
| implements ValueAssembly |
| { |
| private AssociationsModel associationsModel; |
| private ManyAssociationsModel manyAssociationsModel; |
| private NamedAssociationsModel namedAssociationsModel; |
| |
| public ValueAssemblyImpl( Class<?> compositeType ) |
| { |
| super( compositeType ); |
| // The composite must always implement ValueComposite, as a marker interface |
| if( !ValueComposite.class.isAssignableFrom( compositeType ) ) |
| { |
| types.add( ValueComposite.class ); |
| } |
| } |
| |
| @Override |
| protected StateModel createStateModel() |
| { |
| return new ValueStateModel( propertiesModel, associationsModel, manyAssociationsModel, namedAssociationsModel ); |
| } |
| |
| ValueModel newValueModel( |
| StateDeclarations stateDeclarations, |
| AssemblyHelper helper |
| ) |
| { |
| try |
| { |
| associationsModel = new AssociationsModel(); |
| manyAssociationsModel = new ManyAssociationsModel(); |
| namedAssociationsModel = new NamedAssociationsModel(); |
| buildComposite( helper, stateDeclarations ); |
| |
| ValueModel valueModel = new ValueModel( |
| types, visibility, metaInfo, mixinsModel, (ValueStateModel) stateModel, compositeMethodsModel ); |
| |
| return valueModel; |
| } |
| catch( Exception e ) |
| { |
| throw new InvalidApplicationException( "Could not register " + types, e ); |
| } |
| } |
| |
| @Override |
| protected void addStateFor( AccessibleObject accessor, |
| Iterable<Class<? extends Constraint<?, ?>>> constraintClasses |
| ) |
| { |
| String stateName = QualifiedName.fromAccessor( accessor ).name(); |
| |
| if( registeredStateNames.contains( stateName ) ) |
| { |
| return; // Skip already registered names |
| } |
| |
| Class<?> accessorType = Classes.RAW_CLASS.map( typeOf( accessor ) ); |
| if( Property.class.isAssignableFrom( accessorType ) ) |
| { |
| propertiesModel.addProperty( newPropertyModel( accessor, constraintClasses ) ); |
| registeredStateNames.add( stateName ); |
| } |
| else if( Association.class.isAssignableFrom( accessorType ) ) |
| { |
| associationsModel.addAssociation( newAssociationModel( accessor, constraintClasses ) ); |
| registeredStateNames.add( stateName ); |
| } |
| else if( ManyAssociation.class.isAssignableFrom( accessorType ) ) |
| { |
| manyAssociationsModel.addManyAssociation( newManyAssociationModel( accessor, constraintClasses ) ); |
| registeredStateNames.add( stateName ); |
| } |
| else if( NamedAssociation.class.isAssignableFrom( accessorType ) ) |
| { |
| namedAssociationsModel.addNamedAssociation( newNamedAssociationModel( accessor, constraintClasses ) ); |
| registeredStateNames.add( stateName ); |
| } |
| } |
| |
| @Override |
| protected PropertyModel newPropertyModel( AccessibleObject accessor, |
| Iterable<Class<? extends Constraint<?, ?>>> constraintClasses |
| ) |
| { |
| Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); |
| boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null; |
| ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations, GenericPropertyInfo.propertyTypeOf( accessor ), ( (Member) accessor ) |
| .getName(), optional, constraintClasses, accessor ); |
| ValueConstraintsInstance valueConstraintsInstance = null; |
| if( valueConstraintsModel.isConstrained() ) |
| { |
| valueConstraintsInstance = valueConstraintsModel.newInstance(); |
| } |
| MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); |
| boolean useDefaults = metaInfo.get( UseDefaults.class ) != null || stateDeclarations.useDefaults( accessor ); |
| Object initialValue = stateDeclarations.initialValueOf( accessor ); |
| return new PropertyModel( accessor, true, useDefaults, valueConstraintsInstance, metaInfo, initialValue ); |
| } |
| |
| public AssociationModel newAssociationModel( AccessibleObject accessor, |
| Iterable<Class<? extends Constraint<?, ?>>> constraintClasses |
| ) |
| { |
| Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); |
| boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null; |
| |
| // Constraints for Association references |
| ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations, GenericAssociationInfo |
| .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); |
| ValueConstraintsInstance valueConstraintsInstance = null; |
| if( valueConstraintsModel.isConstrained() ) |
| { |
| valueConstraintsInstance = valueConstraintsModel.newInstance(); |
| } |
| |
| // Constraints for the Association itself |
| valueConstraintsModel = constraintsFor( annotations, Association.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); |
| ValueConstraintsInstance associationValueConstraintsInstance = null; |
| if( valueConstraintsModel.isConstrained() ) |
| { |
| associationValueConstraintsInstance = valueConstraintsModel.newInstance(); |
| } |
| |
| MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); |
| AssociationModel associationModel = new AssociationModel( accessor, valueConstraintsInstance, associationValueConstraintsInstance, metaInfo ); |
| return associationModel; |
| } |
| |
| public ManyAssociationModel newManyAssociationModel( AccessibleObject accessor, |
| Iterable<Class<? extends Constraint<?, ?>>> constraintClasses |
| ) |
| { |
| Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); |
| boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null; |
| |
| // Constraints for entities in ManyAssociation |
| ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations, GenericAssociationInfo |
| .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); |
| ValueConstraintsInstance valueConstraintsInstance = null; |
| if( valueConstraintsModel.isConstrained() ) |
| { |
| valueConstraintsInstance = valueConstraintsModel.newInstance(); |
| } |
| |
| // Constraints for the ManyAssociation itself |
| valueConstraintsModel = constraintsFor( annotations, ManyAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); |
| ValueConstraintsInstance manyValueConstraintsInstance = null; |
| if( valueConstraintsModel.isConstrained() ) |
| { |
| manyValueConstraintsInstance = valueConstraintsModel.newInstance(); |
| } |
| MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); |
| ManyAssociationModel associationModel = new ManyAssociationModel( accessor, valueConstraintsInstance, manyValueConstraintsInstance, metaInfo ); |
| return associationModel; |
| } |
| |
| public NamedAssociationModel newNamedAssociationModel( AccessibleObject accessor, |
| Iterable<Class<? extends Constraint<?, ?>>> constraintClasses |
| ) |
| { |
| Iterable<Annotation> annotations = Annotations.findAccessorAndTypeAnnotationsIn( accessor ); |
| boolean optional = first( filter( isType( Optional.class ), annotations ) ) != null; |
| |
| // Constraints for entities in NamedAssociation |
| ValueConstraintsModel valueConstraintsModel = constraintsFor( annotations, GenericAssociationInfo |
| .associationTypeOf( accessor ), ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); |
| ValueConstraintsInstance valueConstraintsInstance = null; |
| if( valueConstraintsModel.isConstrained() ) |
| { |
| valueConstraintsInstance = valueConstraintsModel.newInstance(); |
| } |
| |
| // Constraints for the NamedAssociation itself |
| valueConstraintsModel = constraintsFor( annotations, NamedAssociation.class, ( (Member) accessor ).getName(), optional, constraintClasses, accessor ); |
| ValueConstraintsInstance namedValueConstraintsInstance = null; |
| if( valueConstraintsModel.isConstrained() ) |
| { |
| namedValueConstraintsInstance = valueConstraintsModel.newInstance(); |
| } |
| MetaInfo metaInfo = stateDeclarations.metaInfoFor( accessor ); |
| NamedAssociationModel associationModel = new NamedAssociationModel( accessor, valueConstraintsInstance, namedValueConstraintsInstance, metaInfo ); |
| return associationModel; |
| } |
| } |