001package ca.uhn.fhir.parser.path; 002 003/*- 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2021 Smile CDR, Inc. 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import org.apache.commons.lang3.Validate; 024 025import java.util.ArrayList; 026import java.util.List; 027import java.util.StringTokenizer; 028import java.util.stream.Collectors; 029 030import static org.apache.commons.lang3.StringUtils.isNotBlank; 031 032public class EncodeContextPath { 033 private final List<EncodeContextPathElement> myPath; 034 private final ArrayList<EncodeContextPathElement> myResourcePath = new ArrayList<>(10); 035 036 public EncodeContextPath() { 037 this(new ArrayList<>(10)); 038 } 039 040 public EncodeContextPath(String thePath) { 041 this(); 042 043 StringTokenizer tok = new StringTokenizer(thePath, "."); 044 boolean first = true; 045 while (tok.hasMoreTokens()) { 046 String next = tok.nextToken(); 047 if (first && next.equals("*")) { 048 getPath().add(new EncodeContextPathElement("*", true)); 049 } else if (isNotBlank(next)) { 050 getPath().add(new EncodeContextPathElement(next, Character.isUpperCase(next.charAt(0)))); 051 } 052 first = false; 053 } 054 } 055 056 public EncodeContextPath(List<EncodeContextPathElement> thePath) { 057 myPath = thePath; 058 } 059 060 @Override 061 public String toString() { 062 return myPath.stream().map(t -> t.toString()).collect(Collectors.joining(".")); 063 } 064 065 public List<EncodeContextPathElement> getPath() { 066 return myPath; 067 } 068 069 public EncodeContextPath getCurrentResourcePath() { 070 EncodeContextPath retVal = null; 071 for (int i = myPath.size() - 1; i >= 0; i--) { 072 if (myPath.get(i).isResource()) { 073 retVal = new EncodeContextPath(myPath.subList(i, myPath.size())); 074 break; 075 } 076 } 077 Validate.isTrue(retVal != null); 078 return retVal; 079 } 080 081 /** 082 * Add an element at the end of the path 083 */ 084 public void pushPath(String thePathElement, boolean theResource) { 085 assert isNotBlank(thePathElement); 086 assert !thePathElement.contains("."); 087 assert theResource ^ Character.isLowerCase(thePathElement.charAt(0)); 088 089 EncodeContextPathElement element = new EncodeContextPathElement(thePathElement, theResource); 090 getPath().add(element); 091 if (theResource) { 092 myResourcePath.add(element); 093 } 094 } 095 096 /** 097 * Remove the element at the end of the path 098 */ 099 public void popPath() { 100 EncodeContextPathElement removed = getPath().remove(getPath().size() - 1); 101 if (removed.isResource()) { 102 myResourcePath.remove(myResourcePath.size() - 1); 103 } 104 } 105 106 public ArrayList<EncodeContextPathElement> getResourcePath() { 107 return myResourcePath; 108 } 109 110 public String getLeafElementName() { 111 return getPath().get(getPath().size() - 1).getName(); 112 } 113 114 public String getLeafResourceName() { 115 return myResourcePath.get(myResourcePath.size() - 1).getName(); 116 } 117 118 public String getLeafResourcePathFirstField() { 119 String retVal = null; 120 for (int i = getPath().size() - 1; i >= 0; i--) { 121 if (getPath().get(i).isResource()) { 122 break; 123 } else { 124 retVal = getPath().get(i).getName(); 125 } 126 } 127 return retVal; 128 } 129 130 /** 131 * Tests and returns whether this path starts with {@literal theCurrentResourcePath} 132 * 133 * @param theCurrentResourcePath The path to test 134 * @param theAllowSymmmetrical If <code>true</code>, this method will return true if {@literal theCurrentResourcePath} starts with this path as well as testing whether this path starts with {@literal theCurrentResourcePath} 135 */ 136 public boolean startsWith(EncodeContextPath theCurrentResourcePath, boolean theAllowSymmmetrical) { 137 for (int i = 0; i < getPath().size(); i++) { 138 if (theCurrentResourcePath.getPath().size() == i) { 139 return true; 140 } 141 EncodeContextPathElement expected = getPath().get(i); 142 EncodeContextPathElement actual = theCurrentResourcePath.getPath().get(i); 143 if (!expected.matches(actual)) { 144 return false; 145 } 146 } 147 148 if (theAllowSymmmetrical) { 149 return true; 150 } 151 152 return getPath().size() == theCurrentResourcePath.getPath().size(); 153 } 154 155 public boolean equalsPath(String thePath) { 156 EncodeContextPath parsedPath = new EncodeContextPath(thePath); 157 return getPath().equals(parsedPath.getPath()); 158 } 159 160 161}