001/*-
002 * #%L
003 * HAPI FHIR Subscription Server
004 * %%
005 * Copyright (C) 2014 - 2024 Smile CDR, Inc.
006 * %%
007 * Licensed under the Apache License, Version 2.0 (the "License");
008 * you may not use this file except in compliance with the License.
009 * You may obtain a copy of the License at
010 *
011 *      http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 * #L%
019 */
020package ca.uhn.fhir.jpa.subscription.match.matcher.subscriber;
021
022import ca.uhn.fhir.jpa.searchparam.extractor.StringTrimmingTrimmerMatcher;
023import ca.uhn.fhir.rest.api.Constants;
024import com.google.common.collect.Sets;
025import jakarta.annotation.Nullable;
026import org.apache.commons.lang3.builder.ToStringBuilder;
027import org.apache.commons.lang3.builder.ToStringStyle;
028import org.apache.commons.text.StringTokenizer;
029
030import java.util.Collections;
031import java.util.List;
032import java.util.Set;
033
034import static org.apache.commons.lang3.StringUtils.isBlank;
035import static org.apache.commons.lang3.StringUtils.isNotBlank;
036import static org.apache.commons.lang3.StringUtils.trim;
037
038public enum SubscriptionCriteriaParser {
039        ;
040
041        public enum TypeEnum {
042
043                /**
044                 * Normal search URL expression
045                 */
046                SEARCH_EXPRESSION,
047
048                /**
049                 * Collection of resource types
050                 */
051                MULTITYPE_EXPRESSION,
052
053                /**
054                 * All types
055                 */
056                STARTYPE_EXPRESSION
057        }
058
059        public static class SubscriptionCriteria {
060
061                private final TypeEnum myType;
062                private final String myCriteria;
063                private final Set<String> myApplicableResourceTypes;
064
065                private SubscriptionCriteria(TypeEnum theType, String theCriteria, Set<String> theApplicableResourceTypes) {
066                        myType = theType;
067                        myCriteria = theCriteria;
068                        myApplicableResourceTypes = theApplicableResourceTypes;
069                }
070
071                @Override
072                public String toString() {
073                        ToStringBuilder retVal = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
074                        retVal.append("type", myType);
075                        if (isNotBlank(myCriteria)) {
076                                retVal.append("criteria", myCriteria);
077                        }
078                        if (myApplicableResourceTypes != null) {
079                                retVal.append("applicableResourceTypes", myApplicableResourceTypes);
080                        }
081                        return retVal.toString();
082                }
083
084                public TypeEnum getType() {
085                        return myType;
086                }
087
088                public String getCriteria() {
089                        return myCriteria;
090                }
091
092                public Set<String> getApplicableResourceTypes() {
093                        return myApplicableResourceTypes;
094                }
095        }
096
097        @Nullable
098        public static SubscriptionCriteria parse(String theCriteria) {
099                String criteria = trim(theCriteria);
100                if (isBlank(criteria)) {
101                        return null;
102                }
103
104                if (criteria.startsWith(Constants.SUBSCRIPTION_MULTITYPE_PREFIX)) {
105                        if (criteria.endsWith(Constants.SUBSCRIPTION_MULTITYPE_SUFFIX)) {
106                                String multitypeExpression = criteria.substring(1, criteria.length() - 1);
107                                StringTokenizer tok = new StringTokenizer(multitypeExpression, ",");
108                                tok.setTrimmerMatcher(new StringTrimmingTrimmerMatcher());
109                                List<String> types = tok.getTokenList();
110                                if (types.isEmpty()) {
111                                        return null;
112                                }
113                                if (types.contains(Constants.SUBSCRIPTION_MULTITYPE_STAR)) {
114                                        return new SubscriptionCriteria(TypeEnum.STARTYPE_EXPRESSION, null, null);
115                                }
116                                Set<String> typesSet = Sets.newHashSet(types);
117                                return new SubscriptionCriteria(TypeEnum.MULTITYPE_EXPRESSION, null, typesSet);
118                        }
119                }
120
121                if (Character.isLetter(criteria.charAt(0))) {
122                        String criteriaType = criteria;
123                        int questionMarkIdx = criteriaType.indexOf('?');
124                        if (questionMarkIdx > 0) {
125                                criteriaType = criteriaType.substring(0, questionMarkIdx);
126                        }
127                        Set<String> types = Collections.singleton(criteriaType);
128                        return new SubscriptionCriteria(TypeEnum.SEARCH_EXPRESSION, criteria, types);
129                }
130
131                return null;
132        }
133}