View Javadoc
1   package ca.uhn.fhir.model.api;
2   
3   import static org.apache.commons.lang3.StringUtils.isBlank;
4   import static org.apache.commons.lang3.StringUtils.isNotBlank;
5   
6   import java.io.Serializable;
7   
8   import org.apache.commons.lang3.builder.ToStringBuilder;
9   
10  /*
11   * #%L
12   * HAPI FHIR - Core Library
13   * %%
14   * Copyright (C) 2014 - 2018 University Health Network
15   * %%
16   * Licensed under the Apache License, Version 2.0 (the "License");
17   * you may not use this file except in compliance with the License.
18   * You may obtain a copy of the License at
19   * 
20   *      http://www.apache.org/licenses/LICENSE-2.0
21   * 
22   * Unless required by applicable law or agreed to in writing, software
23   * distributed under the License is distributed on an "AS IS" BASIS,
24   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
25   * See the License for the specific language governing permissions and
26   * limitations under the License.
27   * #L%
28   */
29  
30  /**
31   * Represents a FHIR resource path specification, e.g. <code>Patient:name</code>
32   * <p>
33   * Note on equality: This class uses {@link #getValue() value} and the {@link #isRecurse() recurse} properties to test
34   * equality. Prior to HAPI 1.2 (and FHIR DSTU2) the recurse property did not exist, so this may merit consideration when
35   * upgrading servers.
36   * </p>
37   */
38  public class Include implements Serializable {
39  
40  	private static final long serialVersionUID = 1L;
41  	
42  	private final boolean myImmutable;
43  	private boolean myRecurse;
44  	private String myValue;
45  
46  	/**
47  	 * Constructor for <b>non-recursive</b> include
48  	 * 
49  	 * @param theValue
50  	 *           The <code>_include</code> value, e.g. "Patient:name"
51  	 */
52  	public Include(String theValue) {
53  		myValue = theValue;
54  		myImmutable = false;
55  	}
56  
57  	/**
58  	 * Constructor for an include
59  	 * 
60  	 * @param theValue
61  	 *           The <code>_include</code> value, e.g. "Patient:name"
62  	 * @param theRecurse
63  	 *           Should the include recurse
64  	 */
65  	public Include(String theValue, boolean theRecurse) {
66  		myValue = theValue;
67  		myRecurse = theRecurse;
68  		myImmutable = false;
69  	}
70  
71  	/**
72  	 * Constructor for an include
73  	 * 
74  	 * @param theValue
75  	 *           The <code>_include</code> value, e.g. "Patient:name"
76  	 * @param theRecurse
77  	 *           Should the include recurse
78  	 */
79  	public Include(String theValue, boolean theRecurse, boolean theImmutable) {
80  		myValue = theValue;
81  		myRecurse = theRecurse;
82  		myImmutable = theImmutable;
83  	}
84  
85  	/**
86  	 * Creates a copy of this include with non-recurse behaviour
87  	 */
88  	public Include asNonRecursive() {
89  		return new Include(myValue, false);
90  	}
91  
92  	/**
93  	 * Creates a copy of this include with recurse behaviour
94  	 */
95  	public Include asRecursive() {
96  		return new Include(myValue, true);
97  	}
98  
99  	/**
100 	 * See the note on equality on the {@link Include class documentation}
101 	 */
102 	@Override
103 	public boolean equals(Object obj) {
104 		if (this == obj) {
105 			return true;
106 		}
107 		if (obj == null) {
108 			return false;
109 		}
110 		if (getClass() != obj.getClass()) {
111 			return false;
112 		}
113 		Include other = (Include) obj;
114 		if (myRecurse != other.myRecurse) {
115 			return false;
116 		}
117 		if (myValue == null) {
118 			if (other.myValue != null) {
119 				return false;
120 			}
121 		} else if (!myValue.equals(other.myValue)) {
122 			return false;
123 		}
124 		return true;
125 	}
126 
127 	/**
128 	 * Returns the portion of the value before the first colon
129 	 */
130 	public String getParamType() {
131 		int firstColon = myValue.indexOf(':');
132 		if (firstColon == -1 || firstColon == myValue.length() - 1) {
133 			return null;
134 		}
135 		return myValue.substring(0, firstColon);
136 	}
137 
138 	/**
139 	 * Returns the portion of the value after the first colon but before the second colon
140 	 */
141 	public String getParamName() {
142 		int firstColon = myValue.indexOf(':');
143 		if (firstColon == -1 || firstColon == myValue.length() - 1) {
144 			return null;
145 		}
146 		int secondColon = myValue.indexOf(':', firstColon + 1);
147 		if (secondColon != -1) {
148 			return myValue.substring(firstColon + 1, secondColon);
149 		}
150 		return myValue.substring(firstColon + 1);
151 	}
152 
153 	/**
154 	 * Returns the portion of the string after the second colon, or null if there are not two colons in the value.
155 	 */
156 	public String getParamTargetType() {
157 		int firstColon = myValue.indexOf(':');
158 		if (firstColon == -1 || firstColon == myValue.length() - 1) {
159 			return null;
160 		}
161 		int secondColon = myValue.indexOf(':', firstColon + 1);
162 		if (secondColon != -1) {
163 			return myValue.substring(secondColon + 1);
164 		}
165 		return null;
166 
167 	}
168 
169 	public String getValue() {
170 		return myValue;
171 	}
172 
173 	/**
174 	 * See the note on equality on the {@link Include class documentation}
175 	 */
176 	@Override
177 	public int hashCode() {
178 		final int prime = 31;
179 		int result = 1;
180 		result = prime * result + (myRecurse ? 1231 : 1237);
181 		result = prime * result + ((myValue == null) ? 0 : myValue.hashCode());
182 		return result;
183 	}
184 
185 	/**
186 	 * Is this object {@link #toLocked() locked}?
187 	 */
188 	public boolean isLocked() {
189 		return myImmutable;
190 	}
191 
192 	public boolean isRecurse() {
193 		return myRecurse;
194 	}
195 
196 	/**
197 	 * Should this include recurse
198 	 *
199 	 * @return  Returns a reference to <code>this</code> for easy method chaining
200 	 */
201 	public Include setRecurse(boolean theRecurse) {
202 		myRecurse = theRecurse;
203 		return this;
204 	}
205 
206 	public void setValue(String theValue) {
207 		if (myImmutable) {
208 			throw new IllegalStateException("Can not change the value of this include");
209 		}
210 		myValue = theValue;
211 	}
212 
213 	/**
214 	 * Return a new
215 	 */
216 	public Include toLocked() {
217 		Include retVal = new Include(myValue, myRecurse, true);
218 		return retVal;
219 	}
220 
221 	@Override
222 	public String toString() {
223 		ToStringBuilder builder = new ToStringBuilder(this);
224 		builder.append("value", myValue);
225 		builder.append("recurse", myRecurse);
226 		return builder.toString();
227 	}
228 
229 	/**
230 	 * Creates and returns a new copy of this Include with the given type. The following table shows what will be
231 	 * returned:
232 	 * <table>
233 	 * <tr>
234 	 * <th>Initial Contents</th>
235 	 * <th>theResourceType</th>
236 	 * <th>Output</th>
237 	 * </tr>
238 	 * <tr>
239 	 * <td>Patient:careProvider</th>
240 	 * <th>Organization</th>
241 	 * <th>Patient:careProvider:Organization</th>
242 	 * </tr>
243 	 * <tr>
244 	 * <td>Patient:careProvider:Practitioner</th>
245 	 * <th>Organization</th>
246 	 * <th>Patient:careProvider:Organization</th>
247 	 * </tr>
248 	 * <tr>
249 	 * <td>Patient</th>
250 	 * <th>(any)</th>
251 	 * <th>{@link IllegalStateException}</th>
252 	 * </tr>
253 	 * </table>
254 	 * 
255 	 * @param theResourceType
256 	 *           The resource type (e.g. "Organization")
257 	 * @return A new copy of the include. Note that if this include is {@link #toLocked() locked}, the returned include
258 	 *         will be too
259 	 */
260 	public Include withType(String theResourceType) {
261 		StringBuilder b = new StringBuilder();
262 		
263 		String paramType = getParamType();
264 		String paramName = getParamName();
265 		if (isBlank(paramType) || isBlank(paramName)) {
266 			throw new IllegalStateException("This include does not contain a value in the format [ResourceType]:[paramName]");
267 		}
268 		b.append(paramType);
269 		b.append(":");
270 		b.append(paramName);
271 		
272 		if (isNotBlank(theResourceType)) {
273 			b.append(':');
274 			b.append(theResourceType);
275 		}
276 		Include retVal = new Include(b.toString(), myRecurse, myImmutable);
277 		return retVal;
278 	}
279 
280 }