001/*-
002 * #%L
003 * Smile CDR - CDR
004 * %%
005 * Copyright (C) 2016 - 2026 Smile CDR, Inc.
006 * %%
007 * All rights reserved.
008 * #L%
009 */
010package ca.cdr.api.security.permission;
011
012import jakarta.annotation.Nonnull;
013import jakarta.annotation.Nullable;
014
015import java.util.Optional;
016
017import static org.apache.commons.lang3.StringUtils.isNotBlank;
018
019/**
020 * An operation name with an optional instance filter.
021 * e.g. $meta-add or $meta-add?category=vital-signs
022 */
023public final class OperationOnAnyInstance extends PermissionArgumentValue
024                implements PermissionArgumentFormat.IOperationRestriction, PermissionArgumentFormat.IOptionalFilterRestriction {
025        // final for optimizer
026
027        private final String myOperationName;
028
029        @Nullable
030        private final String myFilter;
031
032        OperationOnAnyInstance(String theOperationName, @Nullable String theFilter) {
033                myOperationName = theOperationName;
034                myFilter = theFilter;
035        }
036
037        @Override
038        public String getOperationName() {
039                return myOperationName;
040        }
041
042        @Nonnull
043        @Override
044        String getStringValue() {
045                StringBuilder sb = new StringBuilder();
046                sb.append(myOperationName);
047                if (myFilter != null) {
048                        sb.append("?").append(myFilter);
049                }
050                return sb.toString();
051        }
052
053        @Override
054        public Optional<String> getFilter() {
055                return Optional.ofNullable(myFilter);
056        }
057
058        static final class Format implements PermissionArgumentFormat<OperationOnAnyInstance> {
059
060                @Override
061                public Class<OperationOnAnyInstance> getType() {
062                        return OperationOnAnyInstance.class;
063                }
064
065                @Override
066                public @Nonnull Optional<OperationOnAnyInstance> parse(
067                                String theArgumentString, @Nonnull IdBuilder theIdBuilder) {
068                        // e.g. $meta-add or $meta-add?category=vital-signs
069                        if (isNotBlank(theArgumentString)) {
070                                String operationName;
071                                String filter;
072                                int splitIdx = theArgumentString.indexOf('?');
073                                if (splitIdx == 0) {
074                                        // invalid - filter only (i.e. ?category=vital-signs)
075                                        return Optional.empty();
076                                } else if (splitIdx == -1) {
077                                        // valid - no filter (i.e. $meta-add)
078                                        operationName = theArgumentString;
079                                        filter = null;
080                                } else {
081                                        // valid - has filter (i.e. $meta-add?category=vital-signs)
082                                        operationName = theArgumentString.substring(0, splitIdx);
083                                        filter = theArgumentString.substring(splitIdx + 1);
084                                }
085
086                                return Optional.of(new OperationOnAnyInstance(operationName, filter));
087                        }
088
089                        return Optional.empty();
090                }
091
092                @Override
093                public @Nonnull String format(@Nonnull OperationOnAnyInstance theArgument) {
094                        return theArgument.getStringValue();
095                }
096        }
097}