001/* 002 * SPDX-FileCopyrightText: none 003 * SPDX-License-Identifier: CC0-1.0 004 */ 005 006package dev.metaschema.core.model; 007 008import org.apache.logging.log4j.LogManager; 009import org.apache.logging.log4j.Logger; 010 011import java.util.Collection; 012import java.util.LinkedHashSet; 013import java.util.Objects; 014import java.util.Set; 015import java.util.function.Function; 016 017import edu.umd.cs.findbugs.annotations.NonNull; 018import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 019 020/** 021 * Supports walking a portion of a metaschema model collecting a set of 022 * definitions that match the provided filter. For a definition to be collected, 023 * the filter must return {@code true}. 024 */ 025public abstract class DefinitionCollectingModelWalker 026 extends ModelWalker<Void> { 027 private static final Logger LOGGER = LogManager.getLogger(DefinitionCollectingModelWalker.class); 028 029 private final Function<IDefinition, Boolean> filter; 030 @NonNull 031 private final Set<IDefinition> definitions = new LinkedHashSet<>(); 032 033 @Override 034 protected Void getDefaultData() { 035 return null; 036 } 037 038 /** 039 * Construct a new walker using the provided filter. 040 * 041 * @param filter 042 * the filter to match definitions against 043 */ 044 protected DefinitionCollectingModelWalker(Function<IDefinition, Boolean> filter) { 045 Objects.requireNonNull(filter, "filter"); 046 this.filter = filter; 047 } 048 049 /** 050 * Retrieves the filter used for matching. 051 * 052 * @return the filter 053 */ 054 protected Function<IDefinition, Boolean> getFilter() { 055 return filter; 056 } 057 058 /** 059 * Return the collection of definitions matching the configured filter. 060 * 061 * @return the collection of definitions 062 */ 063 @NonNull 064 @SuppressFBWarnings(value = "EI_EXPOSE_REP", justification = "interface doesn't allow modification") 065 public Collection<? extends IDefinition> getDefinitions() { 066 return definitions; 067 } 068 069 @Override 070 protected void visit(IFlagDefinition def, Void data) { 071 if (LOGGER.isTraceEnabled()) { 072 LOGGER.trace("visiting flag definition '{}'", def.toCoordinates()); 073 } 074 if (getFilter().apply(def)) { 075 definitions.add(def); 076 } 077 } 078 079 @Override 080 protected boolean visit(IFieldDefinition def, Void data) { 081 if (LOGGER.isTraceEnabled()) { 082 LOGGER.trace("visiting field definition '{}'", def.toCoordinates()); 083 } 084 boolean retval; 085 if (definitions.contains(def)) { 086 // no need to visit, since this has already been seen 087 retval = false; 088 } else { 089 if (getFilter().apply(def)) { 090 definitions.add(def); 091 } 092 retval = true; 093 } 094 return retval; 095 } 096 097 @Override 098 protected boolean visit(IAssemblyDefinition def, Void data) { 099 if (LOGGER.isTraceEnabled()) { 100 LOGGER.trace("visiting assembly definition '{}'", def.toCoordinates()); 101 } 102 boolean retval; 103 if (definitions.contains(def)) { 104 // no need to visit, since this has already been seen 105 retval = false; 106 } else { 107 if (getFilter().apply(def)) { 108 definitions.add(def); 109 } 110 retval = true; 111 } 112 return retval; 113 } 114}