001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.isis.core.progmodel.facets.object.membergroups; 021 022import java.util.List; 023import java.util.Properties; 024 025import org.apache.isis.applib.annotation.MemberGroupLayout; 026import org.apache.isis.applib.annotation.MemberGroupLayout.ColumnSpans; 027import org.apache.isis.applib.annotation.MemberGroups; 028import org.apache.isis.applib.annotation.Where; 029import org.apache.isis.applib.filter.Filters; 030import org.apache.isis.core.commons.config.IsisConfiguration; 031import org.apache.isis.core.metamodel.facetapi.FacetHolder; 032import org.apache.isis.core.metamodel.facetapi.FacetUtil; 033import org.apache.isis.core.metamodel.facetapi.FeatureType; 034import org.apache.isis.core.metamodel.facetapi.MetaModelValidatorRefiner; 035import org.apache.isis.core.metamodel.facets.Annotations; 036import org.apache.isis.core.metamodel.facets.FacetFactoryAbstract; 037import org.apache.isis.core.metamodel.facets.object.membergroups.MemberGroupLayoutFacet; 038import org.apache.isis.core.metamodel.spec.ObjectSpecification; 039import org.apache.isis.core.metamodel.spec.feature.Contributed; 040import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation; 041import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorComposite; 042import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting; 043import org.apache.isis.core.metamodel.specloader.validator.MetaModelValidatorVisiting.Visitor; 044import org.apache.isis.core.metamodel.specloader.validator.ValidationFailures; 045 046public class MemberGroupLayoutFacetFactory extends FacetFactoryAbstract implements MetaModelValidatorRefiner { 047 048 public MemberGroupLayoutFacetFactory() { 049 super(FeatureType.OBJECTS_ONLY); 050 } 051 052 @Override 053 public void process(final ProcessClassContext processClassContext) { 054 FacetUtil.addFacet(create(processClassContext)); 055 } 056 057 private MemberGroupLayoutFacet create(final ProcessClassContext processClassContext) { 058 final FacetHolder holder = processClassContext.getFacetHolder(); 059 060 final Class<?> cls = processClassContext.getCls(); 061 062 final Properties properties = processClassContext.metadataProperties("memberGroupLayout"); 063 if(properties != null) { 064 return new MemberGroupLayoutFacetProperties(properties, holder); 065 } 066 067 final MemberGroupLayout mglAnnot = Annotations.getAnnotation(cls, MemberGroupLayout.class); 068 if (mglAnnot != null) { 069 return new MemberGroupLayoutFacetAnnotation(mglAnnot, holder); 070 } 071 final MemberGroups mgAnnot = Annotations.getAnnotation(cls, MemberGroups.class); 072 if (mgAnnot != null) { 073 return new MemberGroupsFacetAnnotation(mgAnnot, processClassContext.getFacetHolder()); 074 } 075 return new MemberGroupLayoutFacetFallback(holder); 076 } 077 078 @Override 079 public void refineMetaModelValidator(MetaModelValidatorComposite metaModelValidator, IsisConfiguration configuration) { 080 metaModelValidator.add(new MetaModelValidatorVisiting(newValidatorVisitor())); 081 } 082 083 private Visitor newValidatorVisitor() { 084 return new MetaModelValidatorVisiting.Visitor() { 085 086 @Override 087 public boolean visit(ObjectSpecification objectSpec, ValidationFailures validationFailures) { 088 MemberGroupLayoutFacet facet = objectSpec.getFacet(MemberGroupLayoutFacet.class); 089 ColumnSpans columnSpans = facet.getColumnSpans(); 090 final List<String> middle = facet.getMiddle(); 091 final List<String> right = facet.getRight(); 092 final int numCollections = numCollectionsOf(objectSpec); 093 094 if(columnSpans.getMiddle() == 0 && !middle.isEmpty()) { 095 validationFailures.add("%s MemberGroupLayout: middle (property) column is 0 for ColumnSpans (%s), but groups have been listed (%s). NB: ColumnSpans may have been defaulted if could not be parsed.", objectSpec.getIdentifier().getClassName(), columnSpans.name(), middle); 096 } 097 if(columnSpans.getMiddle() > 0 && middle.isEmpty()) { 098 // ignore; may want a gap, or there may just not be any properties to put in this column. 099 // validationFailures.add("%s MemberGroupLayout: middle (property) column is non-zero for ColumnSpans (%s), but no groups have been listed", objectSpec.getIdentifier().getClassName(), columnSpans.name()); 100 } 101 102 if(columnSpans.getRight() == 0 && !right.isEmpty()) { 103 validationFailures.add("%s MemberGroupLayout: right (property) column is 0 for ColumnSpans (%s), but groups have been listed (%s). NB: ColumnSpans may have been defaulted if could not be parsed.", objectSpec.getIdentifier().getClassName(), columnSpans.name(), right); 104 } 105 if(columnSpans.getRight() > 0 && right.isEmpty()) { 106 // ignore; may want a gap, or there may just not be any properties to put in this column. 107 // validationFailures.add("%s MemberGroupLayout: right (property) column is non-zero for ColumnSpans (%s), but no groups have been listed", objectSpec.getIdentifier().getClassName(), columnSpans.name()); 108 } 109 110 if(columnSpans.getCollections() == 0 && numCollections>0) { 111 validationFailures.add("%s MemberGroupLayout: collections column is 0 for ColumnSpans (%s), but there are (up to) %d visible collections", objectSpec.getIdentifier().getClassName(), columnSpans.name(), numCollections); 112 } 113 return true; 114 } 115 116 @SuppressWarnings("unchecked") 117 private int numCollectionsOf(ObjectSpecification objectSpec) { 118 List<ObjectAssociation> objectCollections = objectSpec.getAssociations( 119 Contributed.EXCLUDED, Filters.and(ObjectAssociation.Filters.staticallyVisible(Where.OBJECT_FORMS), ObjectAssociation.Filters.COLLECTIONS)); 120 return objectCollections.size(); 121 } 122 }; 123 } 124 125}