001/* 002 * Portions of this software was developed by employees of the National Institute 003 * of Standards and Technology (NIST), an agency of the Federal Government and is 004 * being made available as a public service. Pursuant to title 17 United States 005 * Code Section 105, works of NIST employees are not subject to copyright 006 * protection in the United States. This software may be subject to foreign 007 * copyright. Permission in the United States and in foreign countries, to the 008 * extent that NIST may hold copyright, to use, copy, modify, create derivative 009 * works, and distribute this software and its documentation without fee is hereby 010 * granted on a non-exclusive basis, provided that this notice and disclaimer 011 * of warranty appears in all copies. 012 * 013 * THE SOFTWARE IS PROVIDED 'AS IS' WITHOUT ANY WARRANTY OF ANY KIND, EITHER 014 * EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, ANY WARRANTY 015 * THAT THE SOFTWARE WILL CONFORM TO SPECIFICATIONS, ANY IMPLIED WARRANTIES OF 016 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND FREEDOM FROM 017 * INFRINGEMENT, AND ANY WARRANTY THAT THE DOCUMENTATION WILL CONFORM TO THE 018 * SOFTWARE, OR ANY WARRANTY THAT THE SOFTWARE WILL BE ERROR FREE. IN NO EVENT 019 * SHALL NIST BE LIABLE FOR ANY DAMAGES, INCLUDING, BUT NOT LIMITED TO, DIRECT, 020 * INDIRECT, SPECIAL OR CONSEQUENTIAL DAMAGES, ARISING OUT OF, RESULTING FROM, 021 * OR IN ANY WAY CONNECTED WITH THIS SOFTWARE, WHETHER OR NOT BASED UPON WARRANTY, 022 * CONTRACT, TORT, OR OTHERWISE, WHETHER OR NOT INJURY WAS SUSTAINED BY PERSONS OR 023 * PROPERTY OR OTHERWISE, AND WHETHER OR NOT LOSS WAS SUSTAINED FROM, OR AROSE OUT 024 * OF THE RESULTS OF, OR USE OF, THE SOFTWARE OR SERVICES PROVIDED HEREUNDER. 025 */ 026 027package gov.nist.secauto.metaschema.core.metapath.function.library; 028 029import gov.nist.secauto.metaschema.core.metapath.DynamicContext; 030import gov.nist.secauto.metaschema.core.metapath.DynamicMetapathException; 031import gov.nist.secauto.metaschema.core.metapath.ISequence; 032import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; 033import gov.nist.secauto.metaschema.core.metapath.MetapathException; 034import gov.nist.secauto.metaschema.core.metapath.MetapathExpression; 035import gov.nist.secauto.metaschema.core.metapath.function.FunctionUtils; 036import gov.nist.secauto.metaschema.core.metapath.function.IArgument; 037import gov.nist.secauto.metaschema.core.metapath.function.IFunction; 038import gov.nist.secauto.metaschema.core.metapath.item.IItem; 039import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; 040import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; 041import gov.nist.secauto.metaschema.core.util.ObjectUtils; 042 043import java.util.List; 044import java.util.stream.Stream; 045 046import edu.umd.cs.findbugs.annotations.NonNull; 047 048public final class MpRecurseDepth { 049 // private static final Logger logger = LogManager.getLogger(FnDoc.class); 050 051 @NonNull 052 static final IFunction SIGNATURE_ONE_ARG = IFunction.builder() 053 .name("recurse-depth") 054 .namespace(MetapathConstants.NS_METAPATH) 055 .deterministic() 056 .contextDependent() 057 .focusDependent() 058 .argument(IArgument.newBuilder() 059 .name("recursePath") 060 .type(IStringItem.class) 061 .one() 062 .build()) 063 .returnType(INodeItem.class) 064 .returnZeroOrMore() 065 .functionHandler(MpRecurseDepth::executeOneArg) 066 .build(); 067 068 @NonNull 069 static final IFunction SIGNATURE_TWO_ARG = IFunction.builder() 070 .name("recurse-depth") 071 .namespace(MetapathConstants.NS_METAPATH) 072 .deterministic() 073 .contextDependent() 074 .focusIndependent() 075 .argument(IArgument.newBuilder() 076 .name("context") 077 .type(INodeItem.class) 078 .zeroOrMore() 079 .build()) 080 .argument(IArgument.newBuilder() 081 .name("recursePath") 082 .type(IStringItem.class) 083 .one() 084 .build()) 085 .returnType(INodeItem.class) 086 .returnZeroOrMore() 087 .functionHandler(MpRecurseDepth::executeTwoArg) 088 .build(); 089 090 private MpRecurseDepth() { 091 // disable construction 092 } 093 094 @SuppressWarnings("unused") 095 @NonNull 096 private static ISequence<INodeItem> executeOneArg( 097 @NonNull IFunction function, 098 @NonNull List<ISequence<?>> arguments, 099 @NonNull DynamicContext dynamicContext, 100 IItem focus) { 101 102 ISequence<INodeItem> initalContext = ISequence.of(FunctionUtils.requireType(INodeItem.class, focus)); 103 104 ISequence<? extends IStringItem> arg = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); 105 IStringItem recursionPath = FunctionUtils.requireFirstItem(arg, true); 106 107 return recurseDepth(initalContext, recursionPath, dynamicContext); 108 } 109 110 @SuppressWarnings("unused") 111 @NonNull 112 private static ISequence<INodeItem> executeTwoArg( 113 @NonNull IFunction function, 114 @NonNull List<ISequence<?>> arguments, 115 @NonNull DynamicContext dynamicContext, 116 IItem focus) { 117 118 ISequence<INodeItem> initalContext = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(0))); 119 120 ISequence<? extends IStringItem> arg = FunctionUtils.asType(ObjectUtils.requireNonNull(arguments.get(1))); 121 IStringItem recursionPath = FunctionUtils.requireFirstItem(arg, true); 122 123 return recurseDepth(initalContext, recursionPath, dynamicContext); 124 } 125 126 @NonNull 127 private static ISequence<INodeItem> recurseDepth( 128 @NonNull ISequence<INodeItem> initialContext, 129 @NonNull IStringItem recursionPath, 130 @NonNull DynamicContext dynamicContext) { 131 132 MetapathExpression recursionMetapath; 133 try { 134 recursionMetapath = MetapathExpression.compile(recursionPath.asString()); 135 } catch (MetapathException ex) { 136 throw new DynamicMetapathException(DynamicMetapathException.INVALID_PATH_GRAMMAR, ex.getMessage(), ex); 137 } 138 139 return recurseDepth(initialContext, recursionMetapath, dynamicContext); 140 } 141 142 @NonNull 143 public static ISequence<INodeItem> recurseDepth( 144 @NonNull ISequence<INodeItem> initialContext, 145 @NonNull MetapathExpression recursionMetapath, 146 @NonNull DynamicContext dynamicContext) { 147 148 return ISequence.of(ObjectUtils.notNull(initialContext.asStream() 149 .flatMap(item -> { 150 @NonNull ISequence<INodeItem> metapathResult 151 = recursionMetapath.evaluate(item, dynamicContext); 152 ISequence<INodeItem> result = recurseDepth(metapathResult, recursionMetapath, dynamicContext); 153 return ObjectUtils.notNull(Stream.concat(result.asStream(), Stream.of(item))); 154 }))); 155 } 156}