/** * Searches for AttributeSets that contain {@code aggregatingRelationship}, then verifies that the * Subject and Object AttributeSets have the correct type. * * @param aggregatingType the type of AttributeSet that is the aggregator (i.e., the Subject) * @param aggregatedType the type of AttributeSet that is being aggregated (i.e. the Object) * @param aggregatingRelationship the relationship that relates the Subject to the Object * @param attributeMap the AttributeSetManager, used to look up the relationships * @param errors a map containing errors generated when checking aggregations */ @Override protected void checkAggregation( String aggregatingType, String aggregatedType, String aggregatingRelationship, Map<String, AttributeSet> attributeMap, List<String> errors) { for (AttributeSet aggregatingAs : matchAttribute(attributeMap, new AttributeImpl(aggregatingRelationship, null, null))) { // Using the name of the AttributeSet as a proxy for type, check to insure that the // aggregating AttributeSet // has the expected type if (!aggregatingAs.getName().equals(aggregatingType)) { errors.add( String.format( INCORRECT_SUBJECT_TYPE, aggregatingAs.getName(), "unknown", aggregatingRelationship, aggregatedType, aggregatingAs.getName())); } // Retrieve a Map of ResourceIds to types Map<String, Set<String>> typeMap = types(values(aggregatingAs, aggregatingRelationship), attributeMap); checkTypes(null, aggregatingAs, aggregatingRelationship, typeMap, aggregatedType); } }
/** * Searches the {@code AttributeSetManager} for AttributeSets that use the supplied string as an * identifier. * * <p>The supplied String is used to match Attributes that: * * <ol> * <li>have a value equal to the string, <em>AND</em> * <li>have a name that ends with "-ResourceId" (see {@link #IDENTIFIER_ATTR_NAME}) * </ol> * * If the Attribute satisfies these criteria, then the AttributeSet it belongs to is returned in * the results. * * @param attributeMap the AttributeSetManager containing the AttributeSets to search * @param s a String that may be an identifier of a business object * @return AttributeSets that use the supplied string as an identifier */ static Set<AttributeSet> findAttributeSetContainingId( final String s, Map<String, AttributeSet> attributeMap) { Set<AttributeSet> matches = new HashSet<>(); // Match any Attribute Set that has the identifier of the Business Object as an Attribute value for (AttributeSet candidate : attributeMap.values()) { for (Attribute candidateAttr : candidate.getAttributes()) { if (candidateAttr.getValue().equals(s)) { if (candidateAttr.getName().endsWith("ResourceId")) { matches.add(candidate); } } } } return matches; }
/** * Produces a "type map" containing the reported types of each business object id in {@code * resourceIds}. The name of an AttributeSet can be considered a proxy for a business object type. * For example, if the business id 'id:1234' is present in an AttributeSet named 'Ore-Rem-Project' * (<em>and</em> the Attribute with the value 'id:1234' carries "identifier" semantics), then we * can infer that 'id:1234' identifies a Project business object. * * <p><em>If</em> the AttributeSets have been produced properly, we expect exactly one * 'Ore-Rem-Project' AttributeSet to contain the identifer Attribute value 'id:1234'. However, it * is possible that the AttributeSets were not produced correctly. So this method returns a {@code * Map} which allows for multiple types (AttributeSet names) to be returned for a particular * business id. * * @param resourceIds the resource ids to produce the type map for. The supplied ids will be keys * in the returned Map. * @param attributeMap the AttributeSetManager * @return a Map of AttributeSet names keyed by resource id. As noted above, AttributeSet names * can be used as a proxy for business object type. */ static Map<String, Set<String>> types( Collection<String> resourceIds, Map<String, AttributeSet> attributeMap) { Map<String, Set<String>> typeMap = new HashMap<>(); for (final String id : resourceIds) { typeMap.put(id, new HashSet<>()); final Set<AttributeSet> candidates = findAttributeSetContainingId(id, attributeMap); for (AttributeSet candidate : candidates) { typeMap.get(id).add(candidate.getName()); } } return typeMap; }
/** * Insures that the types in the {@code typeMap} match the {@code expectedType}. * * @param aggregatingAsKey the aggregating attribute set key (used for logging errors) * @param aggregatingAs the aggregating attribute set (used for logging errors) * @param aggregatingRelationship the aggregating relationship * @param typeMap a map of String business object identifiers to a Set of types * @param expectedType the expected type */ private void checkTypes( String aggregatingAsKey, AttributeSet aggregatingAs, String aggregatingRelationship, Map<String, Set<String>> typeMap, String expectedType) { for (Map.Entry<String, Set<String>> e : typeMap.entrySet()) { for (String type : e.getValue()) { if (!type.equals(expectedType)) { if (aggregatingAsKey == null || aggregatingAsKey.trim().length() == 0) { aggregatingAsKey = "unknown"; } throw new RuntimeException( String.format( INCORRECT_OBJECT_TYPE, aggregatingAs.getName(), aggregatingAsKey, e.getKey(), aggregatingRelationship, expectedType, e.getValue())); // errors.add(String.format(INCORRECT_OBJECT_TYPE, aggregatingAs.getName(), // aggregatingAsKey, // e.getKey(), aggregatingRelationship, expectedType, e.getValue())); } } } }