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.ISequence; 031import gov.nist.secauto.metaschema.core.metapath.MetapathConstants; 032import gov.nist.secauto.metaschema.core.metapath.function.IArgument; 033import gov.nist.secauto.metaschema.core.metapath.function.IFunction; 034import gov.nist.secauto.metaschema.core.metapath.function.InvalidArgumentFunctionException; 035import gov.nist.secauto.metaschema.core.metapath.item.IItem; 036import gov.nist.secauto.metaschema.core.metapath.item.atomic.IAnyUriItem; 037import gov.nist.secauto.metaschema.core.metapath.item.atomic.IBooleanItem; 038import gov.nist.secauto.metaschema.core.metapath.item.atomic.INumericItem; 039import gov.nist.secauto.metaschema.core.metapath.item.atomic.IStringItem; 040import gov.nist.secauto.metaschema.core.metapath.item.atomic.IUntypedAtomicItem; 041import gov.nist.secauto.metaschema.core.metapath.item.node.INodeItem; 042import gov.nist.secauto.metaschema.core.util.ObjectUtils; 043 044import java.util.List; 045 046import edu.umd.cs.findbugs.annotations.NonNull; 047import edu.umd.cs.findbugs.annotations.Nullable; 048 049public final class FnBoolean { 050 @NonNull 051 static final IFunction SIGNATURE = IFunction.builder() 052 .name("boolean") 053 .namespace(MetapathConstants.NS_XPATH_FUNCTIONS) 054 .deterministic() 055 .contextIndependent() 056 .focusIndependent() 057 .argument(IArgument.newBuilder() 058 .name("arg") 059 .type(IItem.class) 060 .zeroOrMore() 061 .build()) 062 .returnType(IBooleanItem.class) 063 .returnOne() 064 .functionHandler(FnBoolean::execute) 065 .build(); 066 067 private FnBoolean() { 068 // disable construction 069 } 070 071 @SuppressWarnings("unused") 072 @NonNull 073 private static ISequence<IBooleanItem> execute(@NonNull IFunction function, 074 @NonNull List<ISequence<?>> arguments, 075 @NonNull DynamicContext dynamicContext, 076 IItem focus) { 077 078 ISequence<?> items = ObjectUtils.requireNonNull(arguments.iterator().next()); 079 080 IBooleanItem result = fnBoolean(items); 081 return ISequence.of(result); 082 } 083 084 /** 085 * Get the effective boolean value of the provided sequence. 086 * <p> 087 * Based on the XPath 3.1 <a href= 088 * "https://www.w3.org/TR/xpath-functions-31/#func-boolean">fn:boolean</a> 089 * function. 090 * 091 * @param sequence 092 * the sequence to evaluate 093 * @return the effective boolean value of the sequence 094 */ 095 @NonNull 096 public static IBooleanItem fnBoolean(@Nullable ISequence<?> sequence) { 097 IBooleanItem retval; 098 if (sequence == null) { 099 retval = IBooleanItem.FALSE; 100 } else { 101 retval = IBooleanItem.valueOf(fnBooleanAsPrimitive(sequence)); 102 } 103 return retval; 104 } 105 106 /** 107 * A helper method that gets the effective boolean value of the provided 108 * sequence based on <a href="https://www.w3.org/TR/xpath-31/#id-ebv">XPath 109 * 3.1</a>. 110 * 111 * @param sequence 112 * the sequence to evaluate 113 * @return the effective boolean value 114 */ 115 public static boolean fnBooleanAsPrimitive(@NonNull ISequence<?> sequence) { 116 boolean retval = false; 117 if (!sequence.isEmpty()) { 118 List<? extends IItem> items = sequence.asList(); 119 IItem first = ObjectUtils.notNull(items.iterator().next()); 120 if (first instanceof INodeItem) { 121 retval = true; 122 } else if (items.size() == 1) { 123 retval = fnBooleanAsPrimitive(first); 124 } 125 } 126 return retval; 127 } 128 129 /** 130 * A helper method that gets the effective boolean value of the provided item 131 * based on <a href="https://www.w3.org/TR/xpath-31/#id-ebv">XPath 3.1</a>. 132 * 133 * @param item 134 * the item to evaluate 135 * @return the effective boolean value 136 */ 137 public static boolean fnBooleanAsPrimitive(@NonNull IItem item) { 138 boolean retval; 139 if (item instanceof IBooleanItem) { 140 retval = ((IBooleanItem) item).toBoolean(); 141 } else if (item instanceof IStringItem) { 142 String string = ((IStringItem) item).asString(); 143 retval = !string.isBlank(); 144 } else if (item instanceof INumericItem) { 145 retval = ((INumericItem) item).toEffectiveBoolean(); 146 } else if (item instanceof IUntypedAtomicItem) { 147 String string = ((IUntypedAtomicItem) item).asString(); 148 retval = !string.isBlank(); 149 } else if (item instanceof IAnyUriItem) { 150 String string = ((IAnyUriItem) item).asString(); 151 retval = !string.isBlank(); 152 } else { 153 throw new InvalidArgumentFunctionException(InvalidArgumentFunctionException.INVALID_ARGUMENT_TYPE, 154 String.format("Invalid argument type '%s'", item.getClass().getName())); 155 } 156 return retval; 157 } 158}