2014-02-17 17:58:32 -05:00
package ca.uhn.fhir.context ;
2014-04-24 12:25:47 -04:00
/ *
* # % L
2014-07-21 09:24:38 -04:00
* HAPI FHIR - Core Library
2014-04-24 12:25:47 -04:00
* % %
2021-01-01 15:50:24 -05:00
* Copyright ( C ) 2014 - 2021 Smile CDR , Inc .
2014-04-24 12:25:47 -04:00
* % %
* Licensed under the Apache License , Version 2 . 0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
2019-07-05 11:19:51 -04:00
*
2014-04-24 12:25:47 -04:00
* http : //www.apache.org/licenses/LICENSE-2.0
2019-07-05 11:19:51 -04:00
*
2014-04-24 12:25:47 -04:00
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
* # L %
* /
2020-06-30 17:36:54 -04:00
import ca.uhn.fhir.model.api.annotation.ResourceDef ;
import ca.uhn.fhir.util.UrlUtil ;
import org.hl7.fhir.instance.model.api.IAnyResource ;
import org.hl7.fhir.instance.model.api.IBase ;
import org.hl7.fhir.instance.model.api.IBaseResource ;
import org.hl7.fhir.instance.model.api.IDomainResource ;
2014-05-13 18:59:18 -04:00
import java.util.ArrayList ;
2014-03-10 12:43:49 -04:00
import java.util.Collections ;
import java.util.Comparator ;
2016-03-14 06:31:45 -04:00
import java.util.HashMap ;
2014-05-05 05:57:43 -07:00
import java.util.LinkedHashMap ;
2014-03-10 12:43:49 -04:00
import java.util.List ;
import java.util.Map ;
2014-12-10 17:40:47 -05:00
public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefinition < IBaseResource > {
2014-02-17 17:58:32 -05:00
2016-06-06 11:15:11 -07:00
private Class < ? extends IBaseResource > myBaseType ;
2016-03-14 06:31:45 -04:00
private Map < String , List < RuntimeSearchParam > > myCompartmentNameToSearchParams ;
2016-01-06 08:49:24 -05:00
private FhirContext myContext ;
private String myId ;
2014-05-05 05:57:43 -07:00
private Map < String , RuntimeSearchParam > myNameToSearchParam = new LinkedHashMap < String , RuntimeSearchParam > ( ) ;
2015-02-16 11:33:46 -05:00
private IBaseResource myProfileDef ;
2014-05-05 05:57:43 -07:00
private String myResourceProfile ;
2014-05-13 18:59:18 -04:00
private List < RuntimeSearchParam > mySearchParams ;
2014-12-22 12:03:02 -05:00
private final FhirVersionEnum myStructureVersion ;
2016-06-06 11:15:11 -07:00
private volatile RuntimeResourceDefinition myBaseDefinition ;
2017-05-09 15:08:59 -07:00
2016-06-06 11:15:11 -07:00
public RuntimeResourceDefinition ( FhirContext theContext , String theResourceName , Class < ? extends IBaseResource > theClass , ResourceDef theResourceAnnotation , boolean theStandardType , Map < Class < ? extends IBase > , BaseRuntimeElementDefinition < ? > > theClassToElementDefinitions ) {
super ( theResourceName , theClass , theStandardType , theContext , theClassToElementDefinitions ) ;
2016-03-14 06:31:45 -04:00
myContext = theContext ;
2014-03-10 12:43:49 -04:00
myResourceProfile = theResourceAnnotation . profile ( ) ;
2014-05-28 16:07:53 -04:00
myId = theResourceAnnotation . id ( ) ;
2016-03-14 06:31:45 -04:00
2016-08-14 13:05:16 -04:00
IBaseResource instance ;
2014-12-22 12:03:02 -05:00
try {
2020-12-18 08:49:09 -05:00
instance = theClass . getConstructor ( ) . newInstance ( ) ;
2014-12-22 12:03:02 -05:00
} catch ( Exception e ) {
throw new ConfigurationException ( myContext . getLocalizer ( ) . getMessage ( getClass ( ) , " nonInstantiableType " , theClass . getName ( ) , e . toString ( ) ) , e ) ;
}
2016-08-14 13:05:16 -04:00
myStructureVersion = instance . getStructureFhirVersionEnum ( ) ;
if ( myStructureVersion ! = theContext . getVersion ( ) . getVersion ( ) ) {
throw new ConfigurationException ( myContext . getLocalizer ( ) . getMessage ( getClass ( ) , " typeWrongVersion " , theContext . getVersion ( ) . getVersion ( ) , theClass . getName ( ) , myStructureVersion ) ) ;
}
2016-03-14 06:31:45 -04:00
2014-03-10 12:43:49 -04:00
}
2017-05-09 15:08:59 -07:00
2014-05-05 05:57:43 -07:00
public void addSearchParam ( RuntimeSearchParam theParam ) {
myNameToSearchParam . put ( theParam . getName ( ) , theParam ) ;
2014-02-17 17:58:32 -05:00
}
2014-08-23 16:40:26 -04:00
/ * *
* If this definition refers to a class which extends another resource definition type , this
* method will return the definition of the topmost resource . For example , if this definition
* refers to MyPatient2 , which extends MyPatient , which in turn extends Patient , this method
* will return the resource definition for Patient .
* < p >
* If the definition has no parent , returns < code > this < / code >
* < / p >
* /
public RuntimeResourceDefinition getBaseDefinition ( ) {
2016-06-06 11:15:11 -07:00
validateSealed ( ) ;
if ( myBaseDefinition = = null ) {
myBaseDefinition = myContext . getResourceDefinition ( myBaseType ) ;
}
2014-08-23 16:40:26 -04:00
return myBaseDefinition ;
}
@Override
public ca . uhn . fhir . context . BaseRuntimeElementDefinition . ChildTypeEnum getChildType ( ) {
return ChildTypeEnum . RESOURCE ;
}
2016-01-06 08:49:24 -05:00
public String getId ( ) {
return myId ;
}
/ * *
* Express { @link # getImplementingClass ( ) } as theClass ( to prevent casting warnings )
* /
@SuppressWarnings ( " unchecked " )
public < T > Class < T > getImplementingClass ( Class < T > theClass ) {
if ( ! theClass . isAssignableFrom ( getImplementingClass ( ) ) ) {
throw new ConfigurationException ( " Unable to convert " + getImplementingClass ( ) + " to " + theClass ) ;
}
return ( Class < T > ) getImplementingClass ( ) ;
}
2014-12-12 11:42:14 -05:00
@Deprecated
2014-08-23 16:40:26 -04:00
public String getResourceProfile ( ) {
return myResourceProfile ;
}
2014-12-12 11:42:14 -05:00
public String getResourceProfile ( String theServerBase ) {
2016-06-06 11:15:11 -07:00
validateSealed ( ) ;
2014-12-12 11:42:14 -05:00
String profile ;
if ( ! myResourceProfile . isEmpty ( ) ) {
profile = myResourceProfile ;
} else if ( ! myId . isEmpty ( ) ) {
profile = myId ;
} else {
return " " ;
}
2015-01-24 16:17:20 +01:00
if ( ! UrlUtil . isValid ( profile ) ) {
2016-01-04 17:57:00 -05:00
String resourceName = " /StructureDefinition/ " ;
String profileWithUrl = theServerBase + resourceName + profile ;
2015-01-24 16:17:20 +01:00
if ( UrlUtil . isValid ( profileWithUrl ) ) {
2014-12-12 11:42:14 -05:00
return profileWithUrl ;
}
}
return profile ;
}
2014-08-23 16:40:26 -04:00
public RuntimeSearchParam getSearchParam ( String theName ) {
2016-06-06 11:15:11 -07:00
validateSealed ( ) ;
2014-08-23 16:40:26 -04:00
return myNameToSearchParam . get ( theName ) ;
}
public List < RuntimeSearchParam > getSearchParams ( ) {
2016-06-06 11:15:11 -07:00
validateSealed ( ) ;
2014-08-23 16:40:26 -04:00
return mySearchParams ;
}
2016-03-14 06:31:45 -04:00
/ * *
* Will not return null
* /
public List < RuntimeSearchParam > getSearchParamsForCompartmentName ( String theCompartmentName ) {
2016-06-06 11:15:11 -07:00
validateSealed ( ) ;
2016-03-14 06:31:45 -04:00
List < RuntimeSearchParam > retVal = myCompartmentNameToSearchParams . get ( theCompartmentName ) ;
if ( retVal = = null ) {
return Collections . emptyList ( ) ;
}
return retVal ;
}
2016-01-06 08:49:24 -05:00
public FhirVersionEnum getStructureVersion ( ) {
return myStructureVersion ;
}
public boolean isBundle ( ) {
return " Bundle " . equals ( getName ( ) ) ;
}
2016-06-06 11:15:11 -07:00
@SuppressWarnings ( " unchecked " )
2014-08-23 16:40:26 -04:00
@Override
2015-02-12 17:32:00 -05:00
public void sealAndInitialize ( FhirContext theContext , Map < Class < ? extends IBase > , BaseRuntimeElementDefinition < ? > > theClassToElementDefinitions ) {
super . sealAndInitialize ( theContext , theClassToElementDefinitions ) ;
2014-08-23 16:40:26 -04:00
myNameToSearchParam = Collections . unmodifiableMap ( myNameToSearchParam ) ;
ArrayList < RuntimeSearchParam > searchParams = new ArrayList < RuntimeSearchParam > ( myNameToSearchParam . values ( ) ) ;
Collections . sort ( searchParams , new Comparator < RuntimeSearchParam > ( ) {
@Override
public int compare ( RuntimeSearchParam theArg0 , RuntimeSearchParam theArg1 ) {
return theArg0 . getName ( ) . compareTo ( theArg1 . getName ( ) ) ;
}
} ) ;
mySearchParams = Collections . unmodifiableList ( searchParams ) ;
2016-03-14 06:31:45 -04:00
2018-06-12 21:52:01 +08:00
Map < String , List < RuntimeSearchParam > > compartmentNameToSearchParams = new HashMap < > ( ) ;
2016-03-14 06:31:45 -04:00
for ( RuntimeSearchParam next : searchParams ) {
if ( next . getProvidesMembershipInCompartments ( ) ! = null ) {
for ( String nextCompartment : next . getProvidesMembershipInCompartments ( ) ) {
2021-04-08 05:59:05 -04:00
if ( nextCompartment . startsWith ( " Base FHIR compartment definition for " ) ) {
nextCompartment = nextCompartment . substring ( " Base FHIR compartment definition for " . length ( ) ) ;
}
2016-03-14 06:31:45 -04:00
if ( ! compartmentNameToSearchParams . containsKey ( nextCompartment ) ) {
2018-06-12 21:52:01 +08:00
compartmentNameToSearchParams . put ( nextCompartment , new ArrayList < > ( ) ) ;
}
List < RuntimeSearchParam > searchParamsForCompartment = compartmentNameToSearchParams . get ( nextCompartment ) ;
searchParamsForCompartment . add ( next ) ;
/ *
* If one search parameter marks an SP as making a resource
* a part of a compartment , let ' s also denote all other
* SPs with the same path the same way . This behaviour is
* used by AuthorizationInterceptor
* /
2018-09-29 13:48:35 -04:00
String nextPath = massagePathForCompartmentSimilarity ( next . getPath ( ) ) ;
2018-06-12 21:52:01 +08:00
for ( RuntimeSearchParam nextAlternate : searchParams ) {
2018-09-29 13:48:35 -04:00
String nextAlternatePath = massagePathForCompartmentSimilarity ( nextAlternate . getPath ( ) ) ;
if ( nextAlternatePath . equals ( nextPath ) ) {
2018-06-12 21:52:01 +08:00
if ( ! nextAlternate . getName ( ) . equals ( next . getName ( ) ) ) {
searchParamsForCompartment . add ( nextAlternate ) ;
}
}
2016-03-14 06:31:45 -04:00
}
}
}
}
myCompartmentNameToSearchParams = Collections . unmodifiableMap ( compartmentNameToSearchParams ) ;
2014-08-23 16:40:26 -04:00
Class < ? > target = getImplementingClass ( ) ;
2016-06-06 11:15:11 -07:00
myBaseType = ( Class < ? extends IBaseResource > ) target ;
2014-08-23 16:40:26 -04:00
do {
target = target . getSuperclass ( ) ;
2016-03-28 20:51:27 -04:00
if ( IBaseResource . class . isAssignableFrom ( target ) & & target . getAnnotation ( ResourceDef . class ) ! = null ) {
2016-06-06 11:15:11 -07:00
myBaseType = ( Class < ? extends IBaseResource > ) target ;
2014-08-23 16:40:26 -04:00
}
2016-03-14 06:31:45 -04:00
} while ( target . equals ( Object . class ) = = false ) ;
2017-01-14 07:55:42 -06:00
/ *
* See # 504 :
* Bundle types may not have extensions
* /
if ( hasExtensions ( ) ) {
if ( IAnyResource . class . isAssignableFrom ( getImplementingClass ( ) ) ) {
if ( ! IDomainResource . class . isAssignableFrom ( getImplementingClass ( ) ) ) {
throw new ConfigurationException ( " Class \" " + getImplementingClass ( ) + " \" is invalid. This resource type is not a DomainResource, it must not have extensions " ) ;
}
}
}
2014-08-23 16:40:26 -04:00
}
2018-09-29 13:48:35 -04:00
private String massagePathForCompartmentSimilarity ( String thePath ) {
String path = thePath ;
if ( path . matches ( " .* \\ .where \\ (resolve \\ ( \\ ) is [a-zA-Z]+ \\ ) " ) ) {
path = path . substring ( 0 , path . indexOf ( " .where " ) ) ;
}
return path ;
}
2014-12-16 09:25:12 -05:00
@Deprecated
2015-02-16 11:33:46 -05:00
public synchronized IBaseResource toProfile ( ) {
2016-06-06 11:15:11 -07:00
validateSealed ( ) ;
2014-08-23 16:40:26 -04:00
if ( myProfileDef ! = null ) {
return myProfileDef ;
}
2015-02-16 11:33:46 -05:00
IBaseResource retVal = myContext . getVersion ( ) . generateProfile ( this , null ) ;
2014-08-23 16:40:26 -04:00
myProfileDef = retVal ;
return retVal ;
}
2015-02-16 11:33:46 -05:00
public synchronized IBaseResource toProfile ( String theServerBase ) {
2016-06-06 11:15:11 -07:00
validateSealed ( ) ;
2014-12-16 09:25:12 -05:00
if ( myProfileDef ! = null ) {
return myProfileDef ;
}
2014-03-10 12:43:49 -04:00
2015-02-16 11:33:46 -05:00
IBaseResource retVal = myContext . getVersion ( ) . generateProfile ( this , theServerBase ) ;
2014-12-16 09:25:12 -05:00
myProfileDef = retVal ;
2014-03-10 12:43:49 -04:00
2014-12-16 09:25:12 -05:00
return retVal ;
}
2017-01-13 21:46:16 -06:00
2014-02-17 17:58:32 -05:00
}