Merge branch 'master' of github.com:jamesagnew/hapi-fhir

Conflicts:
	examples/pom.xml.orig
	hapi-deployable-pom/pom.xml
	hapi-fhir-base/src/main/java/ca/uhn/fhir/model/base/resource/BaseOperationOutcome.java
	hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/RestfulServer.java
	hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.java
	hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/exceptions/UnprocessableEntityException.java
	hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java
	hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component
	hapi-fhir-structures-dev/.gitignore
	hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/CustomObservation.java
	hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java
	hapi-tinder-plugin/src/main/resources/vm/resource.vm
	hapi-tinder-plugin/src/main/resources/vm/resource_dstu.vm
	pom.xml
	restful-server-example/.settings/org.eclipse.wst.common.component
	restful-server-example/.settings/org.eclipse.wst.common.component.orig
	src/changes/changes.xml
	src/site/resources/svg/restful-server-interceptors.svg
	src/site/site.xml
This commit is contained in:
jamesagnew 2014-11-08 10:58:35 -05:00
commit 66bb291e04
98 changed files with 4895 additions and 516 deletions

52
examples/pom.xml Normal file
View File

@ -0,0 +1,52 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>0.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-base-examples</artifactId>
<packaging>jar</packaging>
<name>HAPI FHIR - Examples (for site)</name>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>0.8-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>0.8-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit_version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,61 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>0.8-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-base-examples</artifactId>
<packaging>jar</packaging>
<name>HAPI FHIR - Examples (for site)</name>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>0.8-SNAPSHOT</version>
<<<<<<< HEAD:hapi-fhir-base/examples/pom.xml
=======
<<<<<<< HEAD
=======
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2:examples/pom.xml.orig
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu</artifactId>
<version>0.8-SNAPSHOT</version>
<<<<<<< HEAD:hapi-fhir-base/examples/pom.xml
=======
>>>>>>> versions
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2:examples/pom.xml.orig
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit_version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -35,12 +35,18 @@ patient.addUndeclaredExtension(ext);
//START SNIPPET: resourceStringExtension
// Continuing the example from above, we will add a name to the patient, and then
// add an extension to part of that name
HumanNameDt name = patient.addName();
name.addFamily().setValue("Shmoe");
// Add a new "given name", which is of type StringDt
StringDt given = name.addGiven();
given.setValue("Joe");
ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#moreext", new StringDt("Hello"));
given.addUndeclaredExtension(ext2);
// Create an extension and add it to the StringDt
ExtensionDt givenExt = new ExtensionDt(false, "http://examples.com#moreext", new StringDt("Hello"));
given.addUndeclaredExtension(givenExt);
//END SNIPPET: resourceStringExtension
String output = new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
@ -64,10 +70,12 @@ List<ExtensionDt> modExts = patient.getUndeclaredModifierExtensions();
public void foo() {
//START SNIPPET: subExtension
Patient patient = new Patient();
// Add an extension (initially with no contents) to the resource
ExtensionDt parent = new ExtensionDt(false, "http://example.com#parent");
patient.addUndeclaredExtension(parent);
// Add two extensions as children to the parent extension
ExtensionDt child1 = new ExtensionDt(false, "http://example.com#childOne", new StringDt("value1"));
parent.addUndeclaredExtension(child1);

View File

@ -0,0 +1,29 @@
package example;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
//START SNIPPET: interceptor
public class RequestCounterInterceptor extends InterceptorAdapter
{
private int myRequestCount;
public int getRequestCount() {
return myRequestCount;
}
/**
* Override the incomingRequestPreProcessed method, which is called
* for each incoming request before any processing is done
*/
@Override
public boolean incomingRequestPreProcessed(HttpServletRequest theRequest, HttpServletResponse theResponse) {
myRequestCount++;
return true;
}
}
//END SNIPPET: interceptor

View File

@ -0,0 +1,42 @@
package example;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
//START SNIPPET: interceptor
public class RequestExceptionInterceptor extends InterceptorAdapter
{
@Override
public boolean handleException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest,
HttpServletResponse theServletResponse) throws ServletException, IOException {
// If the exception is a built-in type, it defines the correct status
// code to return. Otherwise default to 500.
if (theException instanceof BaseServerResponseException) {
theServletResponse.setStatus(((BaseServerResponseException) theException).getStatusCode());
} else {
theServletResponse.setStatus(Constants.STATUS_HTTP_500_INTERNAL_ERROR);
}
// Provide a response ourself
theServletResponse.setContentType("text/plain");
theServletResponse.getWriter().append("Failed to process!");
theServletResponse.getWriter().close();
// Since we handled this response in the interceptor, we must return false
// to stop processing immediately
return false;
}
}
//END SNIPPET: interceptor

View File

@ -3,6 +3,9 @@ package example;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
@ -11,12 +14,13 @@ import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
public class ServerInterceptors {
@SuppressWarnings("unused")
public static void main(String[] args) throws DataFormatException, IOException {
// START SNIPPET: resourceExtension
// Create an example patient

View File

@ -22,6 +22,7 @@
<reportSets>
<reportSet>
<reports>
<report>scm</report>
</reports>
</reportSet>
</reportSets>
@ -39,6 +40,7 @@
<configuration>
<links>
<link>http://docs.oracle.com/javaee/7/api</link>
<link>http://jamesagnew.github.io/hapi-fhir/apidocs</link>
</links>
</configuration>
</reportSet>

View File

@ -0,0 +1,127 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>0.8-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>hapi-deployable-pom</artifactId>
<packaging>pom</packaging>
<name>HAPI FHIR - Deployable Artifact Parent POM</name>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.7</version>
<<<<<<< HEAD
<reportSets>
<reportSet>
<reports>
=======
<inherited>false</inherited>
<reportSets>
<reportSet>
<reports>
<report>scm</report>
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
</reports>
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven_javadoc_plugin_version}</version>
<reportSets>
<reportSet>
<id>default</id>
<reports>
<report>javadoc</report>
</reports>
<configuration>
<links>
<link>http://docs.oracle.com/javaee/7/api</link>
<<<<<<< HEAD
=======
<link>http://jamesagnew.github.io/hapi-fhir/apidocs</link>
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
</links>
</configuration>
</reportSet>
</reportSets>
</plugin>
</plugins>
</reporting>
<profiles>
<profile>
<id>DIST</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<inherited>true</inherited>
<configuration>
<minmemory>128m</minmemory>
<maxmemory>1g</maxmemory>
<linksource>true</linksource>
<verbose>false</verbose>
<debug>false</debug>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven_source_plugin_version}</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>${maven_license_plugin_version}</version>
<executions>
<execution>
<id>first</id>
<goals>
<goal>update-file-header</goal>
</goals>
<phase>process-sources</phase>
<configuration>
<licenseName>apache_v2</licenseName>
<canUpdateDescription>true</canUpdateDescription>
<canUpdateCopyright>true</canUpdateCopyright>
<roots>
<root>src/main/java</root>
</roots>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -1,6 +1,5 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/resources=UTF-8
encoding/<project>=UTF-8

View File

@ -1,3 +0,0 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding/<project>=UTF-8

View File

@ -1,289 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6
org.eclipse.jdt.core.formatter.align_type_members_on_columns=false
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation=0
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression=16
org.eclipse.jdt.core.formatter.alignment_for_assignment=0
org.eclipse.jdt.core.formatter.alignment_for_binary_expression=16
org.eclipse.jdt.core.formatter.alignment_for_compact_if=16
org.eclipse.jdt.core.formatter.alignment_for_conditional_expression=80
org.eclipse.jdt.core.formatter.alignment_for_enum_constants=0
org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer=16
org.eclipse.jdt.core.formatter.alignment_for_method_declaration=0
org.eclipse.jdt.core.formatter.alignment_for_multiple_fields=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_resources_in_try=80
org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation=16
org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration=16
org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch=16
org.eclipse.jdt.core.formatter.blank_lines_after_imports=1
org.eclipse.jdt.core.formatter.blank_lines_after_package=1
org.eclipse.jdt.core.formatter.blank_lines_before_field=0
org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration=0
org.eclipse.jdt.core.formatter.blank_lines_before_imports=1
org.eclipse.jdt.core.formatter.blank_lines_before_member_type=1
org.eclipse.jdt.core.formatter.blank_lines_before_method=1
org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk=1
org.eclipse.jdt.core.formatter.blank_lines_before_package=0
org.eclipse.jdt.core.formatter.blank_lines_between_import_groups=1
org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations=1
org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_array_initializer=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_block_in_case=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_constant=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_lambda_body=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_method_declaration=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_switch=end_of_line
org.eclipse.jdt.core.formatter.brace_position_for_type_declaration=end_of_line
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment=false
org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment=false
org.eclipse.jdt.core.formatter.comment.format_block_comments=true
org.eclipse.jdt.core.formatter.comment.format_header=false
org.eclipse.jdt.core.formatter.comment.format_html=true
org.eclipse.jdt.core.formatter.comment.format_javadoc_comments=true
org.eclipse.jdt.core.formatter.comment.format_line_comments=true
org.eclipse.jdt.core.formatter.comment.format_source_code=true
org.eclipse.jdt.core.formatter.comment.indent_parameter_description=true
org.eclipse.jdt.core.formatter.comment.indent_root_tags=true
org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags=insert
org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter=insert
org.eclipse.jdt.core.formatter.comment.line_length=80
org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries=true
org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries=true
org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments=false
org.eclipse.jdt.core.formatter.compact_else_if=true
org.eclipse.jdt.core.formatter.continuation_indentation=2
org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer=2
org.eclipse.jdt.core.formatter.disabling_tag=@formatter\:off
org.eclipse.jdt.core.formatter.enabling_tag=@formatter\:on
org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line=false
org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header=true
org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header=true
org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_empty_lines=false
org.eclipse.jdt.core.formatter.indent_statements_compare_to_block=true
org.eclipse.jdt.core.formatter.indent_statements_compare_to_body=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases=true
org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch=false
org.eclipse.jdt.core.formatter.indentation.size=3
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type=insert
org.eclipse.jdt.core.formatter.insert_new_line_after_label=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement=do not insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_annotation_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_block=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_method_body=insert
org.eclipse.jdt.core.formatter.insert_new_line_in_empty_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments=insert
org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters=insert
org.eclipse.jdt.core.formatter.insert_space_after_ellipsis=insert
org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources=insert
org.eclipse.jdt.core.formatter.insert_space_after_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter=insert
org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_binary_operator=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_ellipsis=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try=insert
org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return=insert
org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw=insert
org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional=insert
org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources=do not insert
org.eclipse.jdt.core.formatter.insert_space_before_unary_operator=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration=do not insert
org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation=do not insert
org.eclipse.jdt.core.formatter.join_lines_in_comments=true
org.eclipse.jdt.core.formatter.join_wrapped_lines=true
org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line=false
org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line=false
org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line=false
org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line=false
org.eclipse.jdt.core.formatter.lineSplit=160
org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column=false
org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column=false
org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body=0
org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve=1
org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line=true
org.eclipse.jdt.core.formatter.tabulation.char=space
org.eclipse.jdt.core.formatter.tabulation.size=3
org.eclipse.jdt.core.formatter.use_on_off_tags=false
org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations=true
org.eclipse.jdt.core.formatter.wrap_before_binary_operator=true
org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch=true
org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested=true

View File

@ -1,3 +0,0 @@
eclipse.preferences.version=1
formatter_profile=_examples-format
formatter_settings_version=12

View File

@ -15,13 +15,6 @@
<name>HAPI FHIR - Core Library</name>
<distributionManagement>
<site>
<id>git.server</id>
<url>scm:git:git@github.com:jamesagnew/hapi-fhir.git</url>
</site>
</distributionManagement>
<dependencies>
<!-- JSON -->
@ -214,6 +207,8 @@
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>

View File

@ -0,0 +1,70 @@
package ca.uhn.fhir.context;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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%
*/
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.ProvidesResources;
/**
* Scans a class tagged with {@code ProvidesResources} and adds any resources listed to its FhirContext's resource
* definition list. This makes the profile generator find the classes.
*
* @see ca.uhn.fhir.model.api.annotation.ProvidesResources
*/
public class ProvidedResourceScanner {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelScanner.class);
private FhirContext myContext;
/**
* Constructor
* @param theContext - context whose resource definition list is to be updated by the scanner
*/
public ProvidedResourceScanner(FhirContext theContext) {
myContext = theContext;
}
/**
* If {@code theProvider} is tagged with the {@code ProvidesResources} annotation, this method will add every resource listed
* by the {@code resources} method.
* <p/>
* notes:
* <ul>
* <li>if {@code theProvider} isn't annotated with {@code resources} nothing is done; it's expected that most RestfulServers and
* ResourceProviders won't be annotated.</li>
* <li>any object listed in {@code resources} that doesn't implement {@code IResource} will generate a warning in the log.</li>
* </ul>
*
* @param theProvider - Normally, either a {@link ca.uhn.fhir.rest.server.RestfulServer} or a {@link ca.uhn.fhir.rest.server.IResourceProvider}
* that might be annotated with {@link ca.uhn.fhir.model.api.annotation.ProvidesResources}
*/
public void scanForProvidedResources(Object theProvider) {
ProvidesResources annotation = theProvider.getClass().getAnnotation(ProvidesResources.class);
if (annotation == null)
return;
for (Class clazz : annotation.resources()) {
if (IResource.class.isAssignableFrom(clazz)) {
myContext.getResourceDefinition(clazz);
} else {
ourLog.warn(clazz.getSimpleName() + "is not assignable from IResource");
}
}
}
}

View File

@ -23,6 +23,7 @@ package ca.uhn.fhir.model.api;
import java.util.HashMap;
import java.util.Map;
import ca.uhn.fhir.rest.gclient.StringClientParam;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
@ -50,6 +51,17 @@ public abstract class BaseResource extends BaseElement implements IResource {
@SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="string" )
public static final String SP_RES_ID = "_id";
/**
* <b>Fluent Client</b> search parameter constant for <b>_id</b>
* <p>
* Description: <b>the _id of a resource</b><br/>
* Type: <b>string</b><br/>
* Path: <b>Resource._id</b><br/>
* </p>
*/
public static final StringClientParam RES_ID = new StringClientParam(BaseResource.SP_RES_ID);
@Child(name = "contained", order = 2, min = 0, max = 1)
private ContainedDt myContained;

View File

@ -0,0 +1,44 @@
package ca.uhn.fhir.model.api.annotation;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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%
*/
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
* IResourceProvider and RestfulServer subclasses can use this annotation to designate which custom resources they can provide.
* These resources will automatically be added to the resource list used for profile generation.
* <pre>
* Examples:
* {@code
* @literal@ProvidesResources(resource=CustomObservation.class)
* class CustomObservationResourceProvider implements IResourceProvider{...}
*
* @literal@ProvidesResources(resource={CustomPatient.class,CustomObservation.class}){...}
* class FhirServer extends RestfulServer
* }
* </pre>
* Note that you needn't annotate both the IResourceProvider and the RestfulServer for a given resource; either one will suffice.
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface ProvidesResources {
Class[] resources();
}

View File

@ -46,12 +46,11 @@ public abstract class BaseOperationOutcome extends BaseResource implements IReso
public abstract BaseCodingDt getType();
public abstract BaseIssue addLocation( String theString);
public abstract BaseIssue addLocation(String theString);
public abstract BaseIssue setDetails(String theString);
public abstract StringDt getLocationFirstRep();
}

View File

@ -0,0 +1,75 @@
package ca.uhn.fhir.model.base.resource;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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%
*/
import java.util.List;
import ca.uhn.fhir.model.api.BaseIdentifiableElement;
import ca.uhn.fhir.model.api.BaseResource;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.IResourceBlock;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.StringDt;
public abstract class BaseOperationOutcome extends BaseResource implements IResource {
public abstract BaseIssue addIssue();
public abstract List<? extends BaseIssue> getIssue();
public abstract BaseIssue getIssueFirstRep();
public static abstract class BaseIssue extends BaseIdentifiableElement implements IResourceBlock {
<<<<<<< HEAD
public abstract CodeDt getSeverityElement();
=======
public abstract CodeDt getSeverityElement();
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
public abstract StringDt getDetailsElement();
public abstract BaseCodingDt getType();
<<<<<<< HEAD
public abstract BaseIssue addLocation( String theString);
=======
public abstract BaseIssue addLocation(String theString);
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
public abstract BaseIssue setDetails(String theString);
public abstract StringDt getLocationFirstRep();
<<<<<<< HEAD
}
=======
}
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
}

View File

@ -1,4 +1,4 @@
package ca.uhn.fhir.rest.server;
package ca.uhn.fhir.model.base.resource;
/*
* #%L
@ -20,13 +20,9 @@ package ca.uhn.fhir.rest.server;
* #L%
*/
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.model.api.BaseResource;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
public abstract class BaseSecurityEvent extends BaseResource implements IResource {
/**
* @deprecated Use {@link ca.uhn.fhir.rest.server.security.ISecurityManager} instead
*/
public interface ISecurityManager {
public void authenticate(HttpServletRequest request) throws AuthenticationException;
}

View File

@ -207,10 +207,11 @@ public class ParameterUtil {
case ',':
case '|':
b.append('\\');
// fall through
break;
default:
b.append(next);
break;
}
b.append(next);
}
return b.toString();

View File

@ -50,6 +50,7 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.context.ProvidedResourceScanner;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.exception.ExceptionUtils;
@ -91,13 +92,12 @@ public class RestfulServer extends HttpServlet {
private AddProfileTagEnum myAddProfileTag;
private FhirContext myFhirContext;
private String myImplementationDescription;
private List<IServerInterceptor> myInterceptors = new ArrayList<IServerInterceptor>();
private final List<IServerInterceptor> myInterceptors = new ArrayList<IServerInterceptor>();
private ResourceBinding myNullResourceBinding = new ResourceBinding();
private IPagingProvider myPagingProvider;
private Collection<Object> myPlainProviders;
private Map<String, ResourceBinding> myResourceNameToProvider = new HashMap<String, ResourceBinding>();
private Collection<IResourceProvider> myResourceProviders;
private ISecurityManager mySecurityManager;
private IServerAddressStrategy myServerAddressStrategy = new IncomingRequestAddressStrategy();
private BaseMethodBinding<?> myServerConformanceMethod;
private Object myServerConformanceProvider;
@ -122,8 +122,7 @@ public class RestfulServer extends HttpServlet {
/**
* This method is called prior to sending a response to incoming requests. It is used to add custom headers.
* <p>
* Use caution if overriding this method: it is recommended to call <code>super.addHeadersToResponse</code> to avoid
* inadvertantly disabling functionality.
* Use caution if overriding this method: it is recommended to call <code>super.addHeadersToResponse</code> to avoid inadvertantly disabling functionality.
* </p>
*/
public void addHeadersToResponse(HttpServletResponse theHttpResponse) {
@ -132,7 +131,7 @@ public class RestfulServer extends HttpServlet {
private void assertProviderIsValid(Object theNext) throws ConfigurationException {
if (Modifier.isPublic(theNext.getClass().getModifiers()) == false) {
throw new ConfigurationException("Can not use provider '" + theNext.getClass() + "' - Class ust be public");
throw new ConfigurationException("Can not use provider '" + theNext.getClass() + "' - Class must be public");
}
}
@ -235,14 +234,13 @@ public class RestfulServer extends HttpServlet {
Package pack = annotation.annotationType().getPackage();
if (pack.equals(IdParam.class.getPackage())) {
if (!allowableParams.contains(annotation.annotationType())) {
throw new ConfigurationException("Method[" + m.toString() + "] is not allowed to have a parameter annotated with "+ annotation);
throw new ConfigurationException("Method[" + m.toString() + "] is not allowed to have a parameter annotated with " + annotation);
}
}
}
}
}
resourceBinding.addMethod(foundMethodBinding);
ourLog.debug(" * Method: {}#{} is a handler", theProvider.getClass(), m.getName());
}
@ -292,8 +290,8 @@ public class RestfulServer extends HttpServlet {
}
/**
* Gets the {@link FhirContext} associated with this server. For efficient processing, resource providers and plain
* providers should generally use this context if one is needed, as opposed to creating their own.
* Gets the {@link FhirContext} associated with this server. For efficient processing, resource providers and plain providers should generally use this context if one is needed, as opposed to
* creating their own.
*/
public FhirContext getFhirContext() {
return myFhirContext;
@ -335,26 +333,16 @@ public class RestfulServer extends HttpServlet {
}
/**
* Provides the security manager, or <code>null</code> if none
*/
public ISecurityManager getSecurityManager() {
return mySecurityManager;
}
/**
* Get the server address strategy, which is used to determine what base URL to provide clients to refer to this
* server. Defaults to an instance of {@link IncomingRequestAddressStrategy}
* Get the server address strategy, which is used to determine what base URL to provide clients to refer to this server. Defaults to an instance of {@link IncomingRequestAddressStrategy}
*/
public IServerAddressStrategy getServerAddressStrategy() {
return myServerAddressStrategy;
}
/**
* Returns the server conformance provider, which is the provider that is used to generate the server's conformance
* (metadata) statement.
* Returns the server conformance provider, which is the provider that is used to generate the server's conformance (metadata) statement.
* <p>
* By default, the {@link ServerConformanceProvider} is used, but this can be changed, or set to <code>null</code>
* if you do not wish to export a conformance statement.
* By default, the {@link ServerConformanceProvider} is used, but this can be changed, or set to <code>null</code> if you do not wish to export a conformance statement.
* </p>
*/
public Object getServerConformanceProvider() {
@ -362,8 +350,7 @@ public class RestfulServer extends HttpServlet {
}
/**
* Gets the server's name, as exported in conformance profiles exported by the server. This is informational only,
* but can be helpful to set with something appropriate.
* Gets the server's name, as exported in conformance profiles exported by the server. This is informational only, but can be helpful to set with something appropriate.
*
* @see RestfulServer#setServerName(String)
*/
@ -376,8 +363,7 @@ public class RestfulServer extends HttpServlet {
}
/**
* Gets the server's version, as exported in conformance profiles exported by the server. This is informational
* only, but can be helpful to set with something appropriate.
* Gets the server's version, as exported in conformance profiles exported by the server. This is informational only, but can be helpful to set with something appropriate.
*/
public String getServerVersion() {
return myServerVersion;
@ -416,12 +402,14 @@ public class RestfulServer extends HttpServlet {
NarrativeModeEnum narrativeMode = determineNarrativeMode(theRequest);
boolean respondGzip = theRequest.isRespondGzip();
Bundle bundle = createBundleFromBundleProvider(this, theResponse, resultList, responseEncoding, theRequest.getFhirServerBase(), theRequest.getCompleteUrl(), prettyPrint, requestIsBrowser, narrativeMode, start, count, thePagingAction);
Bundle bundle = createBundleFromBundleProvider(this, theResponse, resultList, responseEncoding, theRequest.getFhirServerBase(), theRequest.getCompleteUrl(), prettyPrint, requestIsBrowser,
narrativeMode, start, count, thePagingAction);
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = getInterceptors().get(i);
boolean continueProcessing = next.outgoingResponse(theRequest, bundle, theRequest.getServletRequest(), theRequest.getServletResponse());
if (!continueProcessing) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
}
@ -434,31 +422,29 @@ public class RestfulServer extends HttpServlet {
for (IServerInterceptor next : myInterceptors) {
boolean continueProcessing = next.incomingRequestPreProcessed(theRequest, theResponse);
if (!continueProcessing) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
}
String fhirServerBase = null;
boolean requestIsBrowser = requestIsBrowser(theRequest);
RequestDetails requestDetails=null;
try {
if (null != mySecurityManager) {
mySecurityManager.authenticate(theRequest);
}
String resourceName = null;
String requestFullPath = StringUtils.defaultString(theRequest.getRequestURI());
String servletPath = StringUtils.defaultString(theRequest.getServletPath());
StringBuffer requestUrl = theRequest.getRequestURL();
String servletContextPath = "";
// if (getServletContext().getMajorVersion() >= 3) {
// // getServletContext is only supported in version 3+ of servlet-api
if (getServletContext() != null) {
servletContextPath = StringUtils.defaultString(getServletContext().getContextPath());
}
// }
// if (getServletContext().getMajorVersion() >= 3) {
// // getServletContext is only supported in version 3+ of servlet-api
if (getServletContext() != null) {
servletContextPath = StringUtils.defaultString(getServletContext().getContextPath());
}
// }
if (ourLog.isTraceEnabled()) {
ourLog.trace("Request FullPath: {}", requestFullPath);
ourLog.trace("Servlet Path: {}", servletPath);
@ -608,7 +594,7 @@ public class RestfulServer extends HttpServlet {
throw new InvalidRequestException(b.toString());
}
RequestDetails requestDetails = r;
requestDetails = r;
requestDetails.setResourceOperationType(resourceMethod.getResourceOperationType());
requestDetails.setSystemOperationType(resourceMethod.getSystemOperationType());
requestDetails.setOtherOperationType(resourceMethod.getOtherOperationType());
@ -616,6 +602,7 @@ public class RestfulServer extends HttpServlet {
for (IServerInterceptor next : myInterceptors) {
boolean continueProcessing = next.incomingRequestPostProcessed(requestDetails, theRequest, theResponse);
if (!continueProcessing) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
}
@ -623,6 +610,15 @@ public class RestfulServer extends HttpServlet {
resourceMethod.invokeServer(this, r);
} catch (AuthenticationException e) {
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = getInterceptors().get(i);
if (!next.handleException(requestDetails, e, theRequest, theResponse)) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
}
if (requestIsBrowser) {
// if request is coming from a browser, prompt the user to enter login credentials
theResponse.setHeader("WWW-Authenticate", "BASIC realm=\"FHIR\"");
@ -635,14 +631,30 @@ public class RestfulServer extends HttpServlet {
} catch (Throwable e) {
/*
* We have caught an exception while handling an incoming server request.
* Start by notifying the interceptors..
*/
for (int i = getInterceptors().size() - 1; i >= 0; i--) {
IServerInterceptor next = getInterceptors().get(i);
if (!next.handleException(requestDetails, e, theRequest, theResponse)) {
ourLog.debug("Interceptor {} returned false, not continuing processing");
return;
}
}
BaseOperationOutcome oo = null;
int statusCode = 500;
int statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR;
if (e instanceof BaseServerResponseException) {
oo = ((BaseServerResponseException) e).getOperationOutcome();
statusCode = ((BaseServerResponseException) e).getStatusCode();
}
/*
* Generate an OperationOutcome to return, unless the exception throw by
* the resource provider had one
*/
if (oo == null) {
try {
oo = (BaseOperationOutcome) myFhirContext.getResourceDefinition("OperationOutcome").getImplementingClass().newInstance();
@ -650,7 +662,7 @@ public class RestfulServer extends HttpServlet {
ourLog.error("Failed to instantiate OperationOutcome resource instance", e1);
throw new ServletException("Failed to instantiate OperationOutcome resource instance", e1);
}
BaseIssue issue = oo.addIssue();
issue.getSeverityElement().setValue("error");
if (e instanceof InternalErrorException) {
@ -663,6 +675,23 @@ public class RestfulServer extends HttpServlet {
} else {
ourLog.error("Failure during REST processing", e);
issue.getDetailsElement().setValue(e.toString() + "\n\n" + ExceptionUtils.getStackTrace(e));
statusCode = ((InternalErrorException) e).getStatusCode();
} else if (e instanceof BaseServerResponseException) {
ourLog.warn("Failure during REST processing: {}", e.toString());
BaseServerResponseException baseServerResponseException = (BaseServerResponseException) e;
statusCode = baseServerResponseException.getStatusCode();
issue.getDetailsElement().setValue(e.getMessage());
if (baseServerResponseException.getAdditionalMessages() != null) {
for (String next : baseServerResponseException.getAdditionalMessages()) {
BaseIssue issue2 = oo.addIssue();
issue2.getSeverityElement().setValue("error");
issue2.setDetails(next);
}
}
} else {
ourLog.error("Failure during REST processing: " + e.toString(), e);
issue.getDetailsElement().setValue(e.toString() + "\n\n" + ExceptionUtils.getStackTrace(e));
statusCode = Constants.STATUS_HTTP_500_INTERNAL_ERROR;
}
}
@ -680,9 +709,8 @@ public class RestfulServer extends HttpServlet {
}
/**
* Initializes the server. Note that this method is final to avoid accidentally introducing bugs in implementations,
* but subclasses may put initialization code in {@link #initialize()}, which is called immediately before beginning
* initialization of the restful server's internal init.
* Initializes the server. Note that this method is final to avoid accidentally introducing bugs in implementations, but subclasses may put initialization code in {@link #initialize()}, which is
* called immediately before beginning initialization of the restful server's internal init.
*/
@Override
public final void init() throws ServletException {
@ -690,10 +718,8 @@ public class RestfulServer extends HttpServlet {
try {
ourLog.info("Initializing HAPI FHIR restful server");
mySecurityManager = getSecurityManager();
if (null == mySecurityManager) {
ourLog.trace("No security manager has been provided");
}
ProvidedResourceScanner providedResourceScanner = new ProvidedResourceScanner(getFhirContext());
providedResourceScanner.scanForProvidedResources(this);
Collection<IResourceProvider> resourceProvider = getResourceProviders();
if (resourceProvider != null) {
@ -707,6 +733,7 @@ public class RestfulServer extends HttpServlet {
throw new ServletException("Multiple providers for type: " + resourceType.getCanonicalName());
}
typeToProvider.put(resourceType, nextProvider);
providedResourceScanner.scanForProvidedResources(nextProvider);
}
ourLog.info("Got {} resource providers", typeToProvider.size());
for (IResourceProvider provider : typeToProvider.values()) {
@ -730,14 +757,13 @@ public class RestfulServer extends HttpServlet {
ourLog.error("An error occurred while loading request handlers!", ex);
throw new ServletException("Failed to initialize FHIR Restful server", ex);
}
myStarted = true;
ourLog.info("A FHIR has been lit on this server");
}
/**
* This method may be overridden by subclasses to do perform initialization that needs to be performed prior to the
* server being used.
* This method may be overridden by subclasses to do perform initialization that needs to be performed prior to the server being used.
*/
protected void initialize() throws ServletException {
// nothing by default
@ -758,9 +784,8 @@ public class RestfulServer extends HttpServlet {
}
/**
* Sets the profile tagging behaviour for the server. When set to a value other than {@link AddProfileTagEnum#NEVER}
* (which is the default), the server will automatically add a profile tag based on the class of the resource(s)
* being returned.
* Sets the profile tagging behaviour for the server. When set to a value other than {@link AddProfileTagEnum#NEVER} (which is the default), the server will automatically add a profile tag based
* on the class of the resource(s) being returned.
*
* @param theAddProfileTag
* The behaviour enum (must not be null)
@ -779,7 +804,6 @@ public class RestfulServer extends HttpServlet {
myImplementationDescription = theImplementationDescription;
}
/**
* Sets (or clears) the list of interceptors
*
@ -855,15 +879,7 @@ public class RestfulServer extends HttpServlet {
}
/**
* Sets the security manager, or <code>null</code> if none
*/
public void setSecurityManager(ISecurityManager theSecurityManager) {
mySecurityManager = theSecurityManager;
}
/**
* Provide a server address strategy, which is used to determine what base URL to provide clients to refer to this
* server. Defaults to an instance of {@link IncomingRequestAddressStrategy}
* Provide a server address strategy, which is used to determine what base URL to provide clients to refer to this server. Defaults to an instance of {@link IncomingRequestAddressStrategy}
*/
public void setServerAddressStrategy(IServerAddressStrategy theServerAddressStrategy) {
Validate.notNull(theServerAddressStrategy, "Server address strategy can not be null");
@ -871,17 +887,14 @@ public class RestfulServer extends HttpServlet {
}
/**
* Returns the server conformance provider, which is the provider that is used to generate the server's conformance
* (metadata) statement.
* Returns the server conformance provider, which is the provider that is used to generate the server's conformance (metadata) statement.
* <p>
* By default, the {@link ServerConformanceProvider} is used, but this can be changed, or set to <code>null</code>
* if you do not wish to export a conformance statement.
* By default, the {@link ServerConformanceProvider} is used, but this can be changed, or set to <code>null</code> if you do not wish to export a conformance statement.
* </p>
* Note that this method can only be called before the server is initialized.
*
* @throws IllegalStateException
* Note that this method can only be called prior to {@link #init() initialization} and will throw an
* {@link IllegalStateException} if called after that.
* Note that this method can only be called prior to {@link #init() initialization} and will throw an {@link IllegalStateException} if called after that.
*/
public void setServerConformanceProvider(Object theServerConformanceProvider) {
if (myStarted) {
@ -891,24 +904,22 @@ public class RestfulServer extends HttpServlet {
}
/**
* Sets the server's name, as exported in conformance profiles exported by the server. This is informational only,
* but can be helpful to set with something appropriate.
* Sets the server's name, as exported in conformance profiles exported by the server. This is informational only, but can be helpful to set with something appropriate.
*/
public void setServerName(String theServerName) {
myServerName = theServerName;
}
/**
* Gets the server's version, as exported in conformance profiles exported by the server. This is informational
* only, but can be helpful to set with something appropriate.
* Gets the server's version, as exported in conformance profiles exported by the server. This is informational only, but can be helpful to set with something appropriate.
*/
public void setServerVersion(String theServerVersion) {
myServerVersion = theServerVersion;
}
/**
* If set to <code>true</code> (default is false), the server will use browser friendly content-types (instead of
* standard FHIR ones) when it detects that the request is coming from a browser instead of a FHIR
* If set to <code>true</code> (default is false), the server will use browser friendly content-types (instead of standard FHIR ones) when it detects that the request is coming from a browser
* instead of a FHIR
*/
public void setUseBrowserFriendlyContentTypes(boolean theUseBrowserFriendlyContentTypes) {
myUseBrowserFriendlyContentTypes = theUseBrowserFriendlyContentTypes;
@ -934,8 +945,8 @@ public class RestfulServer extends HttpServlet {
}
}
public static Bundle createBundleFromBundleProvider(RestfulServer theServer, HttpServletResponse theHttpResponse, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, boolean theRequestIsBrowser,
NarrativeModeEnum theNarrativeMode, int theOffset, Integer theLimit, String theSearchId) {
public static Bundle createBundleFromBundleProvider(RestfulServer theServer, HttpServletResponse theHttpResponse, IBundleProvider theResult, EncodingEnum theResponseEncoding,
String theServerBase, String theCompleteUrl, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode, int theOffset, Integer theLimit, String theSearchId) {
theHttpResponse.setStatus(200);
if (theRequestIsBrowser && theServer.isUseBrowserFriendlyContentTypes()) {
@ -957,7 +968,7 @@ public class RestfulServer extends HttpServlet {
numToReturn = theResult.size();
resourceList = theResult.getResources(0, numToReturn);
validateResourceListNotNull(resourceList);
} else {
IPagingProvider pagingProvider = theServer.getPagingProvider();
if (theLimit == null) {
@ -1040,11 +1051,11 @@ public class RestfulServer extends HttpServlet {
Set<String> containedIds = new HashSet<String>();
for (IResource nextContained : next.getContained().getContainedResources()) {
if (nextContained.getId().isEmpty()==false) {
if (nextContained.getId().isEmpty() == false) {
containedIds.add(nextContained.getId().getValue());
}
}
if (theContext.getNarrativeGenerator() != null) {
String title = theContext.getNarrativeGenerator().generateTitle(next);
ourLog.trace("Narrative generator created title: {}", title);
@ -1067,7 +1078,7 @@ public class RestfulServer extends HttpServlet {
// Don't add contained IDs as top level resources
continue;
}
IdDt id = nextRes.getId().toVersionless();
if (id.hasResourceType() == false) {
String resName = theContext.getResourceDefinition(nextRes).getName();
@ -1183,9 +1194,7 @@ public class RestfulServer extends HttpServlet {
}
/**
* Determine whether a response should be given in JSON or XML format based on the
* incoming HttpServletRequest's <code>"_format"</code> parameter and <code>"Accept:"</code>
* HTTP header.
* Determine whether a response should be given in JSON or XML format based on the incoming HttpServletRequest's <code>"_format"</code> parameter and <code>"Accept:"</code> HTTP header.
*/
public static EncodingEnum determineResponseEncoding(HttpServletRequest theReq) {
String[] format = theReq.getParameterValues(Constants.PARAM_FORMAT);
@ -1278,8 +1287,8 @@ public class RestfulServer extends HttpServlet {
return prettyPrint;
}
public static void streamResponseAsBundle(RestfulServer theServer, HttpServletResponse theHttpResponse, Bundle bundle, EncodingEnum theResponseEncoding, String theServerBase, boolean thePrettyPrint, NarrativeModeEnum theNarrativeMode, boolean theRespondGzip)
throws IOException {
public static void streamResponseAsBundle(RestfulServer theServer, HttpServletResponse theHttpResponse, Bundle bundle, EncodingEnum theResponseEncoding, String theServerBase,
boolean thePrettyPrint, NarrativeModeEnum theNarrativeMode, boolean theRespondGzip) throws IOException {
assert !theServerBase.endsWith("/");
Writer writer = getWriter(theHttpResponse, theRespondGzip);
@ -1297,14 +1306,14 @@ public class RestfulServer extends HttpServlet {
}
}
public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode, boolean theRespondGzip,
String theServerBase) throws IOException {
public static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint,
boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode, boolean theRespondGzip, String theServerBase) throws IOException {
int stausCode = 200;
streamResponseAsResource(theServer, theHttpResponse, theResource, theResponseEncoding, thePrettyPrint, theRequestIsBrowser, theNarrativeMode, stausCode, theRespondGzip, theServerBase);
}
private static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint, boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode, int stausCode,
boolean theRespondGzip, String theServerBase) throws IOException {
private static void streamResponseAsResource(RestfulServer theServer, HttpServletResponse theHttpResponse, IResource theResource, EncodingEnum theResponseEncoding, boolean thePrettyPrint,
boolean theRequestIsBrowser, NarrativeModeEnum theNarrativeMode, int stausCode, boolean theRespondGzip, String theServerBase) throws IOException {
theHttpResponse.setStatus(stausCode);
if (theResource.getId() != null && theResource.getId().hasIdPart() && isNotBlank(theServerBase)) {

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,9 @@
package ca.uhn.fhir.rest.server.exceptions;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
@ -27,9 +29,8 @@ import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
*/
/**
* Base class for RESTful client and server exceptions. RESTful client methods will only throw exceptions which are
* subclasses of this exception type, and RESTful server methods should also only call subclasses of this exception
* type.
* Base class for RESTful client and server exceptions. RESTful client methods will only throw exceptions which are subclasses of this exception type, and RESTful server methods should also only call
* subclasses of this exception type.
*/
public abstract class BaseServerResponseException extends RuntimeException {
@ -49,11 +50,12 @@ public abstract class BaseServerResponseException extends RuntimeException {
registerExceptionType(NotImplementedOperationException.STATUS_CODE, NotImplementedOperationException.class);
}
private List<String> myAdditionalMessages = null;
private BaseOperationOutcome myBaseOperationOutcome;
private String myResponseBody;
private String myResponseMimeType;
private int myStatusCode;
/**
* Constructor
*
@ -67,7 +69,24 @@ public abstract class BaseServerResponseException extends RuntimeException {
myStatusCode = theStatusCode;
myBaseOperationOutcome = null;
}
/**
* Constructor
*
* @param theStatusCode
* The HTTP status code corresponding to this problem
* @param theMessage
* The message
*/
public BaseServerResponseException(int theStatusCode, String... theMessages) {
super(theMessages != null && theMessages.length > 0 ? theMessages[0] : null);
myStatusCode = theStatusCode;
myBaseOperationOutcome = null;
if (theMessages != null && theMessages.length > 1) {
myAdditionalMessages = Arrays.asList(Arrays.copyOfRange(theMessages, 1, theMessages.length, String[].class));
}
}
/**
* Constructor
*
@ -151,6 +170,10 @@ public abstract class BaseServerResponseException extends RuntimeException {
myBaseOperationOutcome = theBaseOperationOutcome;
}
public List<String> getAdditionalMessages() {
return myAdditionalMessages;
}
/**
* Returns the {@link BaseOperationOutcome} resource if any which was supplied in the response, or <code>null</code>
*/
@ -159,8 +182,7 @@ public abstract class BaseServerResponseException extends RuntimeException {
}
/**
* In a RESTful client, this method will be populated with the body of the HTTP respone if one was provided by the
* server, or <code>null</code> otherwise.
* In a RESTful client, this method will be populated with the body of the HTTP respone if one was provided by the server, or <code>null</code> otherwise.
* <p>
* In a restful server, this method is currently ignored.
* </p>
@ -170,8 +192,7 @@ public abstract class BaseServerResponseException extends RuntimeException {
}
/**
* In a RESTful client, this method will be populated with the HTTP status code that was returned with the HTTP
* response.
* In a RESTful client, this method will be populated with the HTTP status code that was returned with the HTTP response.
* <p>
* In a restful server, this method is currently ignored.
* </p>
@ -193,6 +214,8 @@ public abstract class BaseServerResponseException extends RuntimeException {
* client implementations you should not call this method.
*
* @param theBaseOperationOutcome The BaseOperationOutcome resource
* Sets the BaseOperationOutcome resource associated with this exception. In server implementations, this is the OperartionOutcome resource to include with the HTTP response. In client
* implementations you should not call this method.
*/
public void setOperationOutcome(BaseOperationOutcome theBaseOperationOutcome) {
myBaseOperationOutcome = theBaseOperationOutcome;

View File

@ -0,0 +1,301 @@
package ca.uhn.fhir.rest.server.exceptions;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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%
*/
/**
* Base class for RESTful client and server exceptions. RESTful client methods will only throw exceptions which are subclasses of this exception type, and RESTful server methods should also only call
* subclasses of this exception type.
*/
public abstract class BaseServerResponseException extends RuntimeException {
private static final Map<Integer, Class<? extends BaseServerResponseException>> ourStatusCodeToExceptionType = new HashMap<Integer, Class<? extends BaseServerResponseException>>();
private static final long serialVersionUID = 1L;
static {
registerExceptionType(AuthenticationException.STATUS_CODE, AuthenticationException.class);
registerExceptionType(InternalErrorException.STATUS_CODE, InternalErrorException.class);
registerExceptionType(InvalidRequestException.STATUS_CODE, InvalidRequestException.class);
registerExceptionType(MethodNotAllowedException.STATUS_CODE, MethodNotAllowedException.class);
registerExceptionType(ResourceNotFoundException.STATUS_CODE, ResourceNotFoundException.class);
registerExceptionType(ResourceVersionNotSpecifiedException.STATUS_CODE, ResourceVersionNotSpecifiedException.class);
registerExceptionType(ResourceVersionConflictException.STATUS_CODE, ResourceVersionConflictException.class);
registerExceptionType(UnprocessableEntityException.STATUS_CODE, UnprocessableEntityException.class);
registerExceptionType(ResourceGoneException.STATUS_CODE, ResourceGoneException.class);
registerExceptionType(NotImplementedOperationException.STATUS_CODE, NotImplementedOperationException.class);
}
<<<<<<< HEAD
=======
private List<String> myAdditionalMessages = null;
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
private BaseOperationOutcome myBaseOperationOutcome;
private String myResponseBody;
private String myResponseMimeType;
private int myStatusCode;
/**
* Constructor
*
* @param theStatusCode
* The HTTP status code corresponding to this problem
* @param theMessage
* The message
*/
public BaseServerResponseException(int theStatusCode, String theMessage) {
super(theMessage);
myStatusCode = theStatusCode;
myBaseOperationOutcome = null;
<<<<<<< HEAD
=======
}
/**
* Constructor
*
* @param theStatusCode
* The HTTP status code corresponding to this problem
* @param theMessage
* The message
*/
public BaseServerResponseException(int theStatusCode, String... theMessages) {
super(theMessages != null && theMessages.length > 0 ? theMessages[0] : null);
myStatusCode = theStatusCode;
myBaseOperationOutcome = null;
if (theMessages != null && theMessages.length > 1) {
myAdditionalMessages = Arrays.asList(Arrays.copyOfRange(theMessages, 1, theMessages.length, String[].class));
}
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
}
/**
* Constructor
*
* @param theStatusCode
* The HTTP status code corresponding to this problem
* @param theMessage
* The message
* @param theBaseOperationOutcome
<<<<<<< HEAD
* An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome
* that was returned from the server (in a client)
=======
* An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome that was returned from the server (in a client)
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
*/
public BaseServerResponseException(int theStatusCode, String theMessage, BaseOperationOutcome theBaseOperationOutcome) {
super(theMessage);
myStatusCode = theStatusCode;
myBaseOperationOutcome = theBaseOperationOutcome;
}
/**
* Constructor
*
* @param theStatusCode
* The HTTP status code corresponding to this problem
* @param theMessage
* The message
* @param theCause
* The cause
*/
public BaseServerResponseException(int theStatusCode, String theMessage, Throwable theCause) {
super(theMessage, theCause);
myStatusCode = theStatusCode;
myBaseOperationOutcome = null;
}
/**
* Constructor
*
* @param theStatusCode
* The HTTP status code corresponding to this problem
* @param theMessage
* The message
* @param theCause
* The underlying cause exception
* @param theBaseOperationOutcome
<<<<<<< HEAD
* An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome
* that was returned from the server (in a client)
=======
* An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome that was returned from the server (in a client)
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
*/
public BaseServerResponseException(int theStatusCode, String theMessage, Throwable theCause, BaseOperationOutcome theBaseOperationOutcome) {
super(theMessage, theCause);
myStatusCode = theStatusCode;
myBaseOperationOutcome = theBaseOperationOutcome;
}
/**
* Constructor
*
* @param theStatusCode
* The HTTP status code corresponding to this problem
* @param theCause
* The underlying cause exception
*/
public BaseServerResponseException(int theStatusCode, Throwable theCause) {
super(theCause.toString(), theCause);
myStatusCode = theStatusCode;
myBaseOperationOutcome = null;
}
/**
* Constructor
*
* @param theStatusCode
* The HTTP status code corresponding to this problem
* @param theCause
* The underlying cause exception
* @param theBaseOperationOutcome
<<<<<<< HEAD
* An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome
* that was returned from the server (in a client)
=======
* An BaseOperationOutcome resource to return to the calling client (in a server) or the BaseOperationOutcome that was returned from the server (in a client)
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
*/
public BaseServerResponseException(int theStatusCode, Throwable theCause, BaseOperationOutcome theBaseOperationOutcome) {
super(theCause.toString(), theCause);
myStatusCode = theStatusCode;
myBaseOperationOutcome = theBaseOperationOutcome;
<<<<<<< HEAD
=======
}
public List<String> getAdditionalMessages() {
return myAdditionalMessages;
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
}
/**
* Returns the {@link BaseOperationOutcome} resource if any which was supplied in the response, or <code>null</code>
*/
public BaseOperationOutcome getOperationOutcome() {
return myBaseOperationOutcome;
}
/**
* In a RESTful client, this method will be populated with the body of the HTTP respone if one was provided by the server, or <code>null</code> otherwise.
* <p>
* In a restful server, this method is currently ignored.
* </p>
*/
public String getResponseBody() {
return myResponseBody;
}
/**
* In a RESTful client, this method will be populated with the HTTP status code that was returned with the HTTP response.
* <p>
* In a restful server, this method is currently ignored.
* </p>
*/
public String getResponseMimeType() {
return myResponseMimeType;
}
/**
* Returns the HTTP status code corresponding to this problem
*/
public int getStatusCode() {
return myStatusCode;
}
/**
<<<<<<< HEAD
* Sets the BaseOperationOutcome resource associated with this exception. In server
* implementations, this is the OperartionOutcome resource to include with the HTTP response. In
* client implementations you should not call this method.
*
* @param theBaseOperationOutcome The BaseOperationOutcome resource
=======
* Sets the BaseOperationOutcome resource associated with this exception. In server implementations, this is the OperartionOutcome resource to include with the HTTP response. In client
* implementations you should not call this method.
*
* @param theBaseOperationOutcome
* The BaseOperationOutcome resource
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
*/
public void setOperationOutcome(BaseOperationOutcome theBaseOperationOutcome) {
myBaseOperationOutcome = theBaseOperationOutcome;
}
/**
* This method is currently only called internally by HAPI, it should not be called by user code.
*/
public void setResponseBody(String theResponseBody) {
myResponseBody = theResponseBody;
}
/**
* This method is currently only called internally by HAPI, it should not be called by user code.
*/
public void setResponseMimeType(String theResponseMimeType) {
myResponseMimeType = theResponseMimeType;
}
/**
* For unit tests only
*/
static boolean isExceptionTypeRegistered(Class<?> theType) {
return ourStatusCodeToExceptionType.values().contains(theType);
}
public static BaseServerResponseException newInstance(int theStatusCode, String theMessage) {
if (ourStatusCodeToExceptionType.containsKey(theStatusCode)) {
try {
return ourStatusCodeToExceptionType.get(theStatusCode).getConstructor(new Class[] { String.class }).newInstance(theMessage);
} catch (InstantiationException e) {
throw new InternalErrorException(e);
} catch (IllegalAccessException e) {
throw new InternalErrorException(e);
} catch (IllegalArgumentException e) {
throw new InternalErrorException(e);
} catch (InvocationTargetException e) {
throw new InternalErrorException(e);
} catch (NoSuchMethodException e) {
throw new InternalErrorException(e);
} catch (SecurityException e) {
throw new InternalErrorException(e);
}
} else {
return new UnclassifiedServerFailureException(theStatusCode, theMessage);
}
}
static void registerExceptionType(int theStatusCode, Class<? extends BaseServerResponseException> theType) {
if (ourStatusCodeToExceptionType.containsKey(theStatusCode)) {
throw new Error("Can not register " + theType + " to status code " + theStatusCode + " because " + ourStatusCodeToExceptionType.get(theStatusCode) + " already registers that code");
}
ourStatusCodeToExceptionType.put(theStatusCode, theType);
}
}

View File

@ -77,7 +77,7 @@ public class UnprocessableEntityException extends BaseServerResponseException {
* Constructor which accepts an array of Strings describing the issue. This strings will be translated into an {@link BaseOperationOutcome} resource which will be supplied in the response.
*/
public UnprocessableEntityException(String... theMessage) {
super(STATUS_CODE, theMessage[0]); // TODO: this used to generate an OperationOutcome - why?
super(STATUS_CODE, theMessage);
}
}

View File

@ -78,22 +78,10 @@ public class UnprocessableEntityException extends BaseServerResponseException {
*/
public UnprocessableEntityException(String... theMessage) {
<<<<<<< HEAD
super(STATUS_CODE, DEFAULT_MESSAGE, toOperationOutcome(theMessage));
}
private static OperationOutcome toOperationOutcome(String... theMessage) {
OperationOutcome OperationOutcome = new OperationOutcome();
if (theMessage != null) {
for (String next : theMessage) {
OperationOutcome.addIssue().setDetails(next);
}
}
return OperationOutcome;
=======
super(STATUS_CODE, theMessage[0]); // TODO: this used to generate an OperationOutcome - why?
>>>>>>> versions
=======
super(STATUS_CODE, theMessage);
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
}
}

View File

@ -64,7 +64,8 @@ public interface IServerInterceptor {
* </p>
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including
* A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest
* The incoming request
* @param theResponse
@ -82,7 +83,8 @@ public interface IServerInterceptor {
* This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including
* A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}.
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest
@ -124,7 +126,8 @@ public interface IServerInterceptor {
* This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including
* A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}.
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest
@ -145,7 +148,8 @@ public interface IServerInterceptor {
* This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including
* A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}.
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest
@ -171,7 +175,9 @@ public interface IServerInterceptor {
* </p>
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including
* Contains either <code>null</code>, or a bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}. This parameter may be
* null if the request processing did not successfully parse the incoming request, but will generally not be null.
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest

View File

@ -0,0 +1,202 @@
package ca.uhn.fhir.rest.server.interceptor;
/*
* #%L
* HAPI FHIR - Core Library
* %%
* Copyright (C) 2014 University Health Network
* %%
* 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
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* 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%
*/
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
/**
* Provides methods to intercept requests and responses. Note that implementations of this interface may wish to use {@link InterceptorAdapter} in order to not need to implement every method.
*/
public interface IServerInterceptor {
/**
* This method is called before any other processing takes place for each incoming request. It may be used to provide alternate handling for some requests, or to screen requests before they are
* handled, etc.
* <p>
* Note that any exceptions thrown by this method will not be trapped by HAPI (they will be passed up to the server)
* </p>
*
* @param theRequest
* The incoming request
* @param theResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
* response normally, you must return <code>false</code>. In this case, no further processing will occur and no further interceptors will be called.
*/
public boolean incomingRequestPreProcessed(HttpServletRequest theRequest, HttpServletResponse theResponse);
/**
* This method is called just before the actual implementing server method is invoked.
* <p>
* Note about exceptions:
* </p>
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest
* The incoming request
* @param theResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
* response normally, you must return <code>false</code>. In this case, no further processing will occur and no further interceptors will be called.
* @throws AuthenticationException
* This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the
* client.
*/
public boolean incomingRequestPostProcessed(RequestDetails theRequestDetails, HttpServletRequest theRequest, HttpServletResponse theResponse) throws AuthenticationException;
/**
* This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}.
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest
* The incoming request
* @param theResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
* response normally, you must return <code>false</code>. In this case, no further processing will occur and no further interceptors will be called.
* @throws AuthenticationException
* This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the
* client.
*/
public boolean outgoingResponse(RequestDetails theRequestDetails, TagList theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
throws AuthenticationException;
/**
* This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest
* The incoming request
* @param theResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
* response normally, you must return <code>false</code>. In this case, no further processing will occur and no further interceptors will be called.
* @throws AuthenticationException
* This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the
* client.
*/
public boolean outgoingResponse(RequestDetails theRequestDetails, Bundle theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
throws AuthenticationException;
/**
* This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}.
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest
* The incoming request
* @param theResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
* response normally, you must return <code>false</code>. In this case, no further processing will occur and no further interceptors will be called.
* @throws AuthenticationException
* This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the
* client.
*/
public boolean outgoingResponse(RequestDetails theRequestDetails, IResource theResponseObject, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse)
throws AuthenticationException;
/**
* This method is called after the server implementation method has been called, but before any attempt to stream the response back to the client
*
* @param theRequestDetails
* A bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}.
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest
* The incoming request
* @param theResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
* response normally, you must return <code>false</code>. In this case, no further processing will occur and no further interceptors will be called.
* @throws AuthenticationException
* This exception may be thrown to indicate that the interceptor has detected an unauthorized access attempt. If thrown, processing will stop and an HTTP 401 will be returned to the
* client.
*/
public boolean outgoingResponse(RequestDetails theRequestDetails, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws AuthenticationException;
/**
* This method is called upon any exception being thrown within the server's request processing code. This includes any exceptions thrown within resource provider methods (e.g. {@link Search} and
* {@link Read} methods) as well as any runtime exceptions thrown by the server itself. This also includes any {@link AuthenticationException}s thrown.
* <p>
* Implementations of this method may choose to ignore/log/count/etc exceptions, and return <code>true</code>. In this case, processing will continue, and the server will automatically generate an
* {@link BaseOperationOutcome OperationOutcome}. Implementations may also choose to provide their own response to the client. In this case, they should return <code>false</code>, to indicate that
* they have handled the request and processing should stop.
* </p>
*
* @param theRequestDetails
<<<<<<< HEAD
* A bean containing details about the request that is about to be processed, including
=======
* Contains either <code>null</code>, or a bean containing details about the request that is about to be processed, including details such as the resource type and logical ID (if any) and other
* FHIR-specific aspects of the request which have been pulled out of the {@link HttpServletRequest servlet request}. This parameter may be
* null if the request processing did not successfully parse the incoming request, but will generally not be null.
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
* @param theResponseObject
* The actual object which is being streamed to the client as a response
* @param theRequest
* The incoming request
* @param theResponse
* The response. Note that interceptors may choose to provide a response (i.e. by calling {@link HttpServletResponse#getWriter()}) but in that case it is important to return
* <code>false</code>
* @return Return <code>true</code> if processing should continue normally. This is generally the right thing to do. If your interceptor is providing a response rather than letting HAPI handle the
* response normally, you must return <code>false</code>. In this case, no further processing will occur and no further interceptors will be called.
* @throws ServletException
* If this exception is thrown, it will be re-thrown up to the container for handling.
* @throws IOException
* If this exception is thrown, it will be re-thrown up to the container for handling.
*/
public boolean handleException(RequestDetails theRequestDetails, Throwable theException, HttpServletRequest theServletRequest, HttpServletResponse theServletResponse) throws ServletException,
IOException;
}

View File

@ -357,6 +357,8 @@ public class XmlUtil {
case '"':
case '&':
hasEscapable = true;
default:
break;
}
}

View File

@ -6,23 +6,20 @@
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/resources"/>
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<dependent-module archiveName="hapi-fhir-jpaserver-base-0.8-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-jpaserver-base/hapi-fhir-jpaserver-base">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="hapi-fhir-base-0.8-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="hapi-fhir-structures-dstu-0.8-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-structures-dstu/hapi-fhir-structures-dstu">
<dependency-type>uses</dependency-type>
</dependent-module>
<<<<<<< HEAD
<dependent-module archiveName="hapi-fhir-jpaserver-base-0.6.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-jpaserver-base/hapi-fhir-jpaserver-base">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="hapi-fhir-base-0.6.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module deploy-path="/" handle="module:/overlay/var/M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-testpage-overlay/0.6/hapi-fhir-testpage-overlay-0.6.war?unpackFolder=target/m2e-wtp/overlays&amp;includes=**/**&amp;excludes=META-INF/MANIFEST.MF">
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-testpage-overlay?includes=**/**&amp;excludes=META-INF/MANIFEST.MF">
=======
<dependent-module archiveName="hapi-fhir-jpaserver-base-0.7-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-jpaserver-base/hapi-fhir-jpaserver-base">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="hapi-fhir-base-0.7-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module deploy-path="/" handle="module:/overlay/var/M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-testpage-overlay/0.7-SNAPSHOT/hapi-fhir-testpage-overlay-0.7-SNAPSHOT.war?unpackFolder=target/m2e-wtp/overlays&amp;includes=**/**&amp;excludes=META-INF/MANIFEST.MF">
>>>>>>> cdd4b137fb40dd72f895c2bcb644d6e668e1015b
<dependent-module deploy-path="/" handle="module:/overlay/var/M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-testpage-overlay/0.8-SNAPSHOT/hapi-fhir-testpage-overlay-0.8-SNAPSHOT.war?unpackFolder=target/m2e-wtp/overlays&amp;includes=**/**&amp;excludes=META-INF/MANIFEST.MF">
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
<dependency-type>consumes</dependency-type>
</dependent-module>
<dependent-module deploy-path="/" handle="module:/overlay/slf/?includes=**/**&amp;excludes=META-INF/MANIFEST.MF">

View File

@ -0,0 +1,7 @@
/target/
<<<<<<< HEAD
/.settings/
.classpath
.project
=======
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2

View File

@ -1,5 +1,4 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/resources=UTF-8
encoding/<project>=UTF-8

View File

@ -0,0 +1,5 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -1,12 +0,0 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -1,4 +0,0 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View File

@ -0,0 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
<wb-module deploy-name="hapi-fhir-structures-dstu"/>
</project-modules>

View File

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<faceted-project>
<installed facet="java" version="1.6"/>
<installed facet="jst.utility" version="1.0"/>
</faceted-project>

View File

@ -0,0 +1,2 @@
disabled=06target
eclipse.preferences.version=1

View File

@ -0,0 +1,34 @@
package ca.uhn.fhir.context;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.primitive.StringDt;
/**
* Created by Bill de Beaubien on 10/31/2014.
*/
@ResourceDef(name="Observation", id="customobservation")
<<<<<<< HEAD
public class CustomObservation extends Observation {
=======
class CustomObservation extends Observation {
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
@Child(name = "valueUnits", order = 3)
@Extension(url = "http://hapi.test.com/profile/customobservation#valueUnits", definedLocally = true, isModifier = false)
@Description(shortDefinition = "Units on an observation whose type is of valueString")
private StringDt myValueUnits;
public StringDt getValueUnits() {
if (myValueUnits == null) {
myValueUnits = new StringDt();
}
return myValueUnits;
}
public void setValueUnits(StringDt theValueUnits) {
myValueUnits = theValueUnits;
}
}

View File

@ -0,0 +1,35 @@
package ca.uhn.fhir.context;
import ca.uhn.fhir.model.api.annotation.ProvidesResources;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu.resource.Patient;
import junit.framework.TestCase;
import org.junit.Test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
public class ProvidedResourceScannerTest extends TestCase {
@Test
public void testScannerShouldAddProvidedResources() {
FhirContext ctx = new FhirContext();
assertNull(ctx.getElementDefinition(CustomPatient.class));
ProvidedResourceScanner scanner = new ProvidedResourceScanner(ctx);
scanner.scanForProvidedResources(new TestResourceProviderB());
assertNotNull(ctx.getElementDefinition(CustomPatient.class));
}
@ProvidesResources(resources=CustomObservation.class)
class TestResourceProviderA {
}
@ProvidesResources(resources={CustomPatient.class,ResourceWithExtensionsA.class})
class TestResourceProviderB {
}
@ResourceDef(name = "Patient", id="CustomPatient")
class CustomPatient extends Patient {
}
}

View File

@ -507,7 +507,7 @@ public class ClientTest {
@Test
public void testHistoryWithParams() throws Exception {
//@formatter:off
final String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\"><title/><id>6c1d93be-027f-468d-9d47-f826cd15cf42</id><link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/><link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults><published>2014-04-13T18:24:50-04:00</published><author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author><entry><title>Patient 222</title><id>222</id><updated>1969-12-31T19:00:20.000-05:00</updated><published>1969-12-31T19:00:10.000-05:00</published><link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history/1\"/><content type=\"text/xml\"><Patient xmlns=\"http://hl7.org/fhir\"><identifier><use value=\"official\"/><system value=\"urn:hapitest:mrns\"/><value value=\"00001\"/></identifier><name><family value=\"OlderFamily\"/><given value=\"PatientOne\"/></name><gender><text value=\"M\"/></gender></Patient></content></entry><entry><title>Patient 222</title><id>222</id><updated>1969-12-31T19:00:30.000-05:00</updated><published>1969-12-31T19:00:10.000-05:00</published><link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history/2\"/><content type=\"text/xml\"><Patient xmlns=\"http://hl7.org/fhir\"><identifier><use value=\"official\"/><system value=\"urn:hapitest:mrns\"/><value value=\"00001\"/></identifier><name><family value=\"NewerFamily\"/><given value=\"PatientOne\"/></name><gender><text value=\"M\"/></gender></Patient></content></entry></feed>";
//@formatter:on
@ -525,17 +525,16 @@ public class ClientTest {
ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo");
client.getHistoryPatientInstance(new IdDt("111"), new InstantDt("2012-01-02T00:01:02"), new IntegerDt(12));
// ensures the local timezone
String expectedDateString = new InstantDt(new InstantDt("2012-01-02T12:01:02").getValue()).getValueAsString();
expectedDateString = expectedDateString.replace(":", "%3A").replace("+", "%2B");
client.getHistoryPatientInstance(new IdDt("111"), new InstantDt("2012-01-02T12:01:02"), new IntegerDt(12));
assertThat(capt.getAllValues().get(0).getURI().toString(), containsString("http://foo/Patient/111/_history?"));
assertThat(capt.getAllValues().get(0).getURI().toString(), containsString("_since=2012-01-02T00%3A01%3A02"));
assertThat(capt.getAllValues().get(0).getURI().toString(), containsString("_since="+expectedDateString.replaceAll("\\..*", "")));
assertThat(capt.getAllValues().get(0).getURI().toString(), containsString("_count=12"));
String expectedDateString = new InstantDt(new InstantDt("2012-01-02T00:01:02").getValue()).getValueAsString(); // ensures
// the
// local
// timezone
expectedDateString = expectedDateString.replace(":", "%3A");
client.getHistoryPatientInstance(new IdDt("111"), new InstantDt("2012-01-02T00:01:02").getValue(), new IntegerDt(12).getValue());
client.getHistoryPatientInstance(new IdDt("111"), new InstantDt("2012-01-02T12:01:02").getValue(), new IntegerDt(12).getValue());
assertThat(capt.getAllValues().get(1).getURI().toString(), containsString("http://foo/Patient/111/_history?"));
assertThat(capt.getAllValues().get(1).getURI().toString(), containsString("_since="+expectedDateString));
assertThat(capt.getAllValues().get(1).getURI().toString(), containsString("_count=12"));

View File

@ -33,6 +33,7 @@ import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.PortUtil;
/**
@ -54,6 +55,21 @@ public class ExceptionTest {
ourExceptionType=null;
}
@Test
public void testThrowUnprocessableEntityWithMultipleMessages() throws Exception {
{
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?throwUnprocessableEntityWithMultipleMessages=aaa");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(422, status.getStatusLine().getStatusCode());
OperationOutcome oo = (OperationOutcome) servlet.getFhirContext().newXmlParser().parseResource(responseContent);
assertThat(oo.getIssueFirstRep().getDetails().getValue(), StringContains.containsString("message1"));
assertEquals(3, oo.getIssue().size());
}
}
@Test
public void testInternalError() throws Exception {
{
@ -162,10 +178,15 @@ public class ExceptionTest {
@Search
public List<Patient> findPatient(@RequiredParam(name = "throwInternalError") StringParam theParam) {
public List<Patient> throwInternalError(@RequiredParam(name = "throwInternalError") StringParam theParam) {
throw new InternalErrorException("Exception Text");
}
@Search
public List<Patient> throwUnprocessableEntityWithMultipleMessages(@RequiredParam(name = "throwUnprocessableEntityWithMultipleMessages") StringParam theParam) {
throw new UnprocessableEntityException("message1", "message2", "message3");
}
@Override
public Class<? extends IResource> getResourceType() {
return Patient.class;

View File

@ -1378,11 +1378,6 @@ public class ResfulServerMethodTest {
return myResourceProviders;
}
@Override
public ISecurityManager getSecurityManager() {
return null;
}
}
}

View File

@ -0,0 +1,94 @@
package ca.uhn.fhir.rest.server;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.ProvidesResources;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import junit.framework.TestCase;
import org.junit.Test;
import javax.servlet.ServletException;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Bill de Beaubien on 11/1/2014.
*/
public class ServerProvidedResourceScannerTest extends TestCase {
@Test
public void testWhenRestfulServerInitialized_annotatedResources_shouldBeAddedToContext() throws ServletException {
// Given
MyServer server = new MyServer();
// When
server.init();
// Then
assertNotNull(server.getFhirContext().getElementDefinition(CustomObservation.class));
assertNotNull(server.getFhirContext().getElementDefinition(CustomPatient.class));
}
@Test
public void testWhenUnannotatedServerInitialized_annotatedResources_shouldNotBeAddedToContext() throws ServletException {
// Given
RestfulServer server = new RestfulServer();
// When
server.init();
// Then
assertNull(server.getFhirContext().getElementDefinition(CustomObservation.class));
assertNull(server.getFhirContext().getElementDefinition(CustomPatient.class));
}
@Test
public void testWhenServletWithAnnotatedProviderInitialized_annotatedResource_shouldBeAddedToContext() throws ServletException {
// Given
MyServerWithProvider server = new MyServerWithProvider();
// When
server.init();
// Then
assertNotNull(server.getFhirContext().getElementDefinition(CustomObservation.class));
}
@ResourceDef(name = "Patient", id="CustomPatient")
class CustomPatient extends Patient {
}
@ResourceDef(name = "Observation", id="CustomObservation")
class CustomObservation extends Observation {
}
@ProvidesResources(resources={CustomPatient.class,CustomObservation.class})
class MyServer extends RestfulServer {
}
class MyServerWithProvider extends RestfulServer {
@Override
protected void initialize() throws ServletException {
List<IResourceProvider> providers = new ArrayList<IResourceProvider>();
providers.add(new MyObservationProvider());
setResourceProviders(providers);
}
}
@ProvidesResources(resources=CustomObservation.class)
public static class MyObservationProvider implements IResourceProvider {
@Override
public Class<? extends IResource> getResourceType() {
return CustomObservation.class;
}
@Read(version = false)
public CustomObservation readObservation(@IdParam IdDt theId) {
return null;
}
}
}

View File

@ -0,0 +1,165 @@
package ca.uhn.fhir.rest.server.interceptor;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hamcrest.core.StringContains;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.slf4j.Logger;
import ca.uhn.fhir.model.dstu.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Read;
import ca.uhn.fhir.rest.annotation.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.util.PortUtil;
public class ExceptionHandlingInterceptorTest {
private static CloseableHttpClient ourClient;
private static int ourPort;
private static Server ourServer;
private static RestfulServer servlet;
private IServerInterceptor myInterceptor;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExceptionHandlingInterceptorTest.class);
@Test
public void testThrowUnprocessableEntityException() throws Exception {
when(myInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.handleException(any(RequestDetails.class), any(Throwable.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=throwUnprocessableEntityException");
HttpResponse status = ourClient.execute(httpGet);
ourLog.info(IOUtils.toString(status.getEntity().getContent()));
assertEquals(422, status.getStatusLine().getStatusCode());
IOUtils.closeQuietly(status.getEntity().getContent());
ArgumentCaptor<Throwable> captor = ArgumentCaptor.forClass(Throwable.class);
verify(myInterceptor, times(1)).handleException(any(RequestDetails.class), captor.capture(), any(HttpServletRequest.class), any(HttpServletResponse.class));
assertEquals(UnprocessableEntityException.class, captor.getValue().getClass());
}
@Test
public void testThrowUnprocessableEntityExceptionAndOverrideResponse() throws Exception {
when(myInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
when(myInterceptor.handleException(any(RequestDetails.class), any(Throwable.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenAnswer(new Answer<Boolean>() {
@Override
public Boolean answer(InvocationOnMock theInvocation) throws Throwable {
HttpServletResponse resp = (HttpServletResponse) theInvocation.getArguments()[3];
resp.setStatus(405);
resp.setContentType("text/plain");
resp.getWriter().write("HELP IM A BUG");
resp.getWriter().close();
return false;
}
});
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=throwUnprocessableEntityException");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(405, status.getStatusLine().getStatusCode());
IOUtils.closeQuietly(status.getEntity().getContent());
assertEquals("HELP IM A BUG", responseContent);
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@Before
public void before() {
myInterceptor = mock(IServerInterceptor.class);
servlet.setInterceptors(Collections.singletonList(myInterceptor));
}
@BeforeClass
public static void beforeClass() throws Exception {
ourPort = PortUtil.findFreePort();
ourServer = new Server(ourPort);
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
servlet = new RestfulServer();
servlet.setResourceProviders(patientProvider);
ServletHolder servletHolder = new ServletHolder(servlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
ourServer.start();
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourClient = builder.build();
}
/**
* Created by dsotnikov on 2/25/2014.
*/
public static class DummyPatientResourceProvider implements IResourceProvider {
/**
* Retrieve the resource by its identifier
*
* @param theId
* The resource identity
* @return The resource
*/
@Search(queryName = "throwUnprocessableEntityException")
public List<Patient> throwUnprocessableEntityException() {
throw new UnprocessableEntityException("Unprocessable!");
}
@Override
public Class<Patient> getResourceType() {
return Patient.class;
}
}
}

View File

@ -221,7 +221,7 @@ public class TinderStructuresMojo extends AbstractMojo {
String dtOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/composite";
ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet("dev", ".");
rp.setBaseResourceNames(Arrays.asList("referralrequest", "patient","practitioner","encounter",
rp.setBaseResourceNames(Arrays.asList("conformance", "referralrequest", "patient","practitioner","encounter",
"organization","location","relatedperson","appointment","slot","order","availability","device", "valueset"));
rp.parse();
rp.bindValueSets(vsp);

View File

@ -0,0 +1,272 @@
package ca.uhn.fhir.tinder;
import java.io.File;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.Component;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;
import ca.uhn.fhir.tinder.parser.DatatypeGeneratorUsingSpreadsheet;
import ca.uhn.fhir.tinder.parser.ProfileParser;
import ca.uhn.fhir.tinder.parser.ResourceGeneratorUsingSpreadsheet;
@Mojo(name = "generate-structures", defaultPhase = LifecyclePhase.GENERATE_SOURCES)
public class TinderStructuresMojo extends AbstractMojo {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TinderStructuresMojo.class);
@Parameter(required = false)
private List<String> baseResourceNames;
@Parameter(required = false, defaultValue = "false")
private boolean buildDatatypes;
@Component
private MavenProject myProject;
@Parameter(alias = "package", required = true)
private String packageName;
@Parameter(alias = "version", required = true, defaultValue="dstu")
private String version = "dstu";
@Parameter(required = false)
private List<ProfileFileDefinition> resourceProfileFiles;
@Parameter(required = false)
private List<ValueSetFileDefinition> resourceValueSetFiles;
@Parameter(required = true, defaultValue = "${project.build.directory}/generated-sources/tinder")
private String targetDirectory;
@Parameter(required = true, defaultValue = "${project.build.directory}/generated-resources/tinder")
private String targetResourceDirectory;
@Parameter(required = true, defaultValue = "${project.build.directory}/..")
private String baseDir;
@Override
public void execute() throws MojoExecutionException, MojoFailureException {
if (StringUtils.isBlank(packageName)) {
throw new MojoFailureException("Package not specified");
}
if (packageName.contains("..") || packageName.endsWith(".")) {
throw new MojoFailureException("Invalid package specified");
}
ourLog.info("Beginning HAPI-FHIR Tinder Code Generation...");
ourLog.info(" * Output Package: " + packageName);
File resDirectoryBase = new File(new File(targetResourceDirectory), packageName.replace('.', File.separatorChar));
resDirectoryBase.mkdirs();
ourLog.info(" * Output Resource Directory: " + resDirectoryBase.getAbsolutePath());
File directoryBase = new File(new File(targetDirectory), packageName.replace('.', File.separatorChar));
directoryBase.mkdirs();
ourLog.info(" * Output Source Directory: " + directoryBase.getAbsolutePath());
ValueSetGenerator vsp = new ValueSetGenerator(version);
vsp.setResourceValueSetFiles(resourceValueSetFiles);
try {
vsp.parse();
} catch (Exception e) {
throw new MojoFailureException("Failed to load valuesets", e);
}
ourLog.info("Loading Datatypes...");
Map<String, String> datatypeLocalImports = new HashMap<String, String>();
DatatypeGeneratorUsingSpreadsheet dtp = new DatatypeGeneratorUsingSpreadsheet(version, baseDir);
if (buildDatatypes) {
try {
dtp.parse();
dtp.markResourcesForImports();
} catch (Exception e) {
throw new MojoFailureException("Failed to load datatypes", e);
}
dtp.bindValueSets(vsp);
datatypeLocalImports = dtp.getLocalImports();
}
ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet(version, baseDir);
if (baseResourceNames != null && baseResourceNames.size() > 0) {
ourLog.info("Loading Resources...");
try {
rp.setBaseResourceNames(baseResourceNames);
rp.parse();
rp.markResourcesForImports();
} catch (Exception e) {
throw new MojoFailureException("Failed to load resources", e);
}
rp.bindValueSets(vsp);
rp.getLocalImports().putAll(datatypeLocalImports);
datatypeLocalImports.putAll(rp.getLocalImports());
ourLog.info("Writing Resources...");
File resSubDirectoryBase = new File(directoryBase, "resource");
rp.combineContentMaps(dtp);
rp.writeAll(resSubDirectoryBase, resDirectoryBase, packageName);
}
ProfileParser pp = new ProfileParser(version, baseDir);
if (resourceProfileFiles != null) {
ourLog.info("Loading profiles...");
for (ProfileFileDefinition next : resourceProfileFiles) {
ourLog.info("Parsing file: {}", next.profileFile);
pp.parseSingleProfile(new File(next.profileFile), next.profileSourceUrl);
}
pp.bindValueSets(vsp);
pp.markResourcesForImports();
pp.getLocalImports().putAll(datatypeLocalImports);
datatypeLocalImports.putAll(pp.getLocalImports());
pp.combineContentMaps(rp);
pp.combineContentMaps(dtp);
pp.writeAll(new File(directoryBase, "resource"), resDirectoryBase, packageName);
}
if (dtp != null) {
ourLog.info("Writing Composite Datatypes...");
dtp.combineContentMaps(pp);
dtp.combineContentMaps(rp);
dtp.writeAll(new File(directoryBase, "composite"), resDirectoryBase, packageName);
}
ourLog.info("Writing ValueSet Enums...");
vsp.writeMarkedValueSets(new File(directoryBase, "valueset"), packageName);
myProject.addCompileSourceRoot(targetDirectory);
}
public List<String> getBaseResourceNames() {
return baseResourceNames;
}
public String getPackageName() {
return packageName;
}
public List<ProfileFileDefinition> getResourceProfileFiles() {
return resourceProfileFiles;
}
public List<ValueSetFileDefinition> getResourceValueSetFiles() {
return resourceValueSetFiles;
}
public String getTargetDirectory() {
return targetDirectory;
}
public boolean isBuildDatatypes() {
return buildDatatypes;
}
public void setBaseResourceNames(List<String> theBaseResourceNames) {
baseResourceNames = theBaseResourceNames;
}
public void setBuildDatatypes(boolean theBuildDatatypes) {
buildDatatypes = theBuildDatatypes;
}
public void setPackageName(String thePackageName) {
packageName = thePackageName;
}
public void setResourceProfileFiles(List<ProfileFileDefinition> theResourceProfileFiles) {
resourceProfileFiles = theResourceProfileFiles;
}
public void setResourceValueSetFiles(List<ValueSetFileDefinition> theResourceValueSetFiles) {
resourceValueSetFiles = theResourceValueSetFiles;
}
public void setTargetDirectory(String theTargetDirectory) {
targetDirectory = theTargetDirectory;
}
public static void main(String[] args) throws Exception {
// ProfileParser pp = new ProfileParser();
// pp.parseSingleProfile(new File("../hapi-tinder-test/src/test/resources/profile/patient.xml"), "http://foo");
ValueSetGenerator vsp = new ValueSetGenerator("dev");
// vsp.setResourceValueSetFiles(theResourceValueSetFiles);Directory("src/main/resources/vs/");
vsp.parse();
DatatypeGeneratorUsingSpreadsheet dtp = new DatatypeGeneratorUsingSpreadsheet("dev", ".");
dtp.parse();
dtp.markResourcesForImports();
dtp.bindValueSets(vsp);
Map<String, String> datatypeLocalImports = dtp.getLocalImports();
String dtOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/composite";
ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet("dev", ".");
<<<<<<< HEAD
rp.setBaseResourceNames(Arrays.asList("referralrequest", "patient","practitioner","encounter",
=======
rp.setBaseResourceNames(Arrays.asList("conformance", "referralrequest", "patient","practitioner","encounter",
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
"organization","location","relatedperson","appointment","slot","order","availability","device", "valueset"));
rp.parse();
rp.bindValueSets(vsp);
rp.markResourcesForImports();
// rp.bindValueSets(vsp);
String rpOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/resource";
String rpSOutputDir = "target/generated-resources/tinder/ca/uhn/fhir/model/dev";
dtp.combineContentMaps(rp);
rp.combineContentMaps(dtp);
rp.getLocalImports().putAll(datatypeLocalImports);
datatypeLocalImports.putAll(rp.getLocalImports());
dtp.writeAll(new File(dtOutputDir), null, "ca.uhn.fhir.model.dev");
rp.writeAll(new File(rpOutputDir), new File(rpSOutputDir), "ca.uhn.fhir.model.dev");
String vsOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/valueset";
vsp.writeMarkedValueSets(new File(vsOutputDir), "ca.uhn.fhir.model.dev");
}
public static class ProfileFileDefinition {
@Parameter(required = true)
private String profileFile;
@Parameter(required = true)
private String profileSourceUrl;
}
public static class ValueSetFileDefinition {
@Parameter(required = true)
private String valueSetFile;
public String getValueSetFile() {
return valueSetFile;
}
public void setValueSetFile(String theValueSetFile) {
valueSetFile = theValueSetFile;
}
}
}

View File

@ -40,7 +40,7 @@ import ${import};
*/
@ResourceDef(name="${elementName}", profile="${profile}", id="${id}")
public class ${className}
extends #{if}( ${className}=="OperationOutcome" || ${className}=="Conformance" ) ca.uhn.fhir.model.base.resource.Base${className} #{else} BaseResource #{end}
extends #{if}( ${className}=="OperationOutcome" || ${className}=="Conformance" || ${className}=="SecurityEvent" ) ca.uhn.fhir.model.base.resource.Base${className} #{else} BaseResource #{end}
implements IResource {
#foreach ( $param in $searchParams )
@ -88,4 +88,4 @@ public class ${className}
#childExtensionTypes( $childExtensionTypes )
}
}

View File

@ -0,0 +1,95 @@
#parse ( "/vm/templates.vm" )
package ${packageBase}.resource;
import java.math.BigDecimal;
import java.net.URI;
import java.util.*;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.annotation.*;
import ca.uhn.fhir.rest.gclient.*;
#foreach ( $import in $imports )
import ${import};
#end
##import ${packageBase}.composite.*;
##import ${packageBase}.valueset.*;
/**
* HAPI/FHIR <b>${elementName}</b> Resource
* (${shortName})
*
* <p>
* <b>Definition:</b>
* ${definition}
* </p>
*
* <p>
* <b>Requirements:</b>
* ${requirements}
* </p>
*
#if (${profile} != "")
* <p>
* <b>Profile Definition:</b>
* <a href="${profile}">${profile}</a>
* </p>
*
#end
*/
@ResourceDef(name="${elementName}", profile="${profile}", id="${id}")
public class ${className}
<<<<<<< HEAD
extends #{if}( ${className}=="OperationOutcome" || ${className}=="Conformance" ) ca.uhn.fhir.model.base.resource.Base${className} #{else} BaseResource #{end}
=======
extends #{if}( ${className}=="OperationOutcome" || ${className}=="Conformance" || ${className}=="SecurityEvent" ) ca.uhn.fhir.model.base.resource.Base${className} #{else} BaseResource #{end}
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
implements IResource {
#foreach ( $param in $searchParams )
/**
* Search parameter constant for <b>${param.name}</b>
* <p>
* Description: <b>${param.description}</b><br/>
* Type: <b>${param.type}</b><br/>
* Path: <b>${param.path}</b><br/>
* </p>
*/
@SearchParamDefinition(name="${param.name}", path="${param.path}", description="${param.description}", type="${param.type}" #{if}($param.compositeOf.empty == false) , compositeOf={ #{foreach}($compositeOf in $param.compositeOf) "${compositeOf}"#{if}($foreach.hasNext), #{end}#{end} } #{end} )
public static final String $param.constantName = "${param.name}";
/**
* <b>Fluent Client</b> search parameter constant for <b>${param.name}</b>
* <p>
* Description: <b>${param.description}</b><br/>
* Type: <b>${param.type}</b><br/>
* Path: <b>${param.path}</b><br/>
* </p>
*/
#if( ${param.typeCapitalized} == 'Composite' )
public static final CompositeClientParam<${param.compositeTypes[0]}ClientParam, ${param.compositeTypes[1]}ClientParam> ${param.fluentConstantName} = new CompositeClientParam<${param.compositeTypes[0]}ClientParam, ${param.compositeTypes[1]}ClientParam>(${param.constantName});
#else
public static final ${param.typeCapitalized}ClientParam ${param.fluentConstantName} = new ${param.typeCapitalized}ClientParam(${param.constantName});
#end
#if( ${param.typeCapitalized} == 'Reference' )
#foreach ( $include in $param.paths )
/**
* Constant for fluent queries to be used to add include statements. Specifies
* the path value of "<b>${include.path}</b>".
*/
public static final Include INCLUDE_${include.includeName} = new Include("${include.path}");
#end
#end
#end
#childExtensionFields( $childExtensionTypes )
#childVars( $children )
#childAccessors( $children )
#childResourceBlocks($resourceBlockChildren)
#childExtensionTypes( $childExtensionTypes )
}

View File

@ -39,7 +39,7 @@ import ${import};
*/
@ResourceDef(name="${elementName}", profile="${profile}", id="${id}")
public class ${className}
extends #{if}( ${className}=="OperationOutcome" || ${className}=="Conformance" ) ca.uhn.fhir.model.base.resource.Base${className} #{else} BaseResource #{end}
extends #{if}( ${className}=="OperationOutcome" || ${className}=="Conformance" || ${className}=="SecurityEvent" ) ca.uhn.fhir.model.base.resource.Base${className} #{else} BaseResource #{end}
implements IResource {
#foreach ( $param in $searchParams )
@ -87,4 +87,4 @@ public class ${className}
#childExtensionTypes( $childExtensionTypes )
}
}

View File

@ -0,0 +1,94 @@
#parse ( "/vm/templates_dstu.vm" )
package ${packageBase}.resource;
import java.util.*;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.api.annotation.*;
import ca.uhn.fhir.rest.gclient.*;
#foreach ( $import in $imports )
import ${import};
#end
##import ${packageBase}.composite.*;
##import ${packageBase}.valueset.*;
/**
* HAPI/FHIR <b>${elementName}</b> Resource
* (${shortName})
*
* <p>
* <b>Definition:</b>
* ${definition}
* </p>
*
* <p>
* <b>Requirements:</b>
* ${requirements}
* </p>
*
#if (${profile} != "")
* <p>
* <b>Profile Definition:</b>
* <a href="${profile}">${profile}</a>
* </p>
*
#end
*/
@ResourceDef(name="${elementName}", profile="${profile}", id="${id}")
public class ${className}
<<<<<<< HEAD
extends #{if}( ${className}=="OperationOutcome" || ${className}=="Conformance" ) ca.uhn.fhir.model.base.resource.Base${className} #{else} BaseResource #{end}
=======
extends #{if}( ${className}=="OperationOutcome" || ${className}=="Conformance" || ${className}=="SecurityEvent" ) ca.uhn.fhir.model.base.resource.Base${className} #{else} BaseResource #{end}
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
implements IResource {
#foreach ( $param in $searchParams )
/**
* Search parameter constant for <b>${param.name}</b>
* <p>
* Description: <b>${param.description}</b><br/>
* Type: <b>${param.type}</b><br/>
* Path: <b>${param.path}</b><br/>
* </p>
*/
@SearchParamDefinition(name="${param.name}", path="${param.path}", description="${param.description}", type="${param.type}" #{if}($param.compositeOf.empty == false) , compositeOf={ #{foreach}($compositeOf in $param.compositeOf) "${compositeOf}"#{if}($foreach.hasNext), #{end}#{end} } #{end} )
public static final String $param.constantName = "${param.name}";
/**
* <b>Fluent Client</b> search parameter constant for <b>${param.name}</b>
* <p>
* Description: <b>${param.description}</b><br/>
* Type: <b>${param.type}</b><br/>
* Path: <b>${param.path}</b><br/>
* </p>
*/
#if( ${param.typeCapitalized} == 'Composite' )
public static final CompositeClientParam<${param.compositeTypes[0]}ClientParam, ${param.compositeTypes[1]}ClientParam> ${param.fluentConstantName} = new CompositeClientParam<${param.compositeTypes[0]}ClientParam, ${param.compositeTypes[1]}ClientParam>(${param.constantName});
#else
public static final ${param.typeCapitalized}ClientParam ${param.fluentConstantName} = new ${param.typeCapitalized}ClientParam(${param.constantName});
#end
#if( ${param.typeCapitalized} == 'Reference' )
#foreach ( $include in $param.paths )
/**
* Constant for fluent queries to be used to add include statements. Specifies
* the path value of "<b>${include.path}</b>".
*/
public static final Include INCLUDE_${include.includeName} = new Include("${include.path}");
#end
#end
#end
#childExtensionFields( $childExtensionTypes )
#childVars( $children )
#childAccessors( $children )
#childResourceBlocks($resourceBlockChildren)
#childExtensionTypes( $childExtensionTypes )
}

1
list_releases.sh Normal file
View File

@ -0,0 +1 @@
curl https://api.github.com/repos/jamesagnew/hapi-fhir/releases

30
pom.xml
View File

@ -28,6 +28,13 @@
<url>https://github.com/jamesagnew/hapi-fhir/issues/</url>
</issueManagement>
<distributionManagement>
<site>
<id>git.server</id>
<url>scm:git:git@github.com:jamesagnew/hapi-fhir.git</url>
</site>
</distributionManagement>
<scm>
<connection>scm:git:git@github.com:jamesagnew/hapi-fhir.git</connection>
<url>scm:git:git@github.com:jamesagnew/hapi-fhir.git</url>
@ -502,12 +509,33 @@
</reportSet>
</reportSets>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<classFilesDirectory>./hapi-fhir-base/target/classes</classFilesDirectory>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>findbugs</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-linkcheck-plugin</artifactId>
<version>1.1</version> </plugin> -->
</plugins>
</reporting>
<profiles>
<profile>
<id>ROOT</id>
<modules>
</modules>
</profile>
<profile>
<id>SIGN_ARTIFACTS</id>
<activation>
@ -540,6 +568,7 @@
<module>hapi-fhir-base</module>
<module>hapi-fhir-structures-dstu</module>
<module>hapi-fhir-structures-dev</module>
<module>examples</module>
</modules>
</profile>
<profile>
@ -551,7 +580,6 @@
<module>hapi-deployable-pom</module>
<module>hapi-fhir-base</module>
<module>hapi-fhir-oauth2</module>
<module>hapi-fhir-base/examples</module>
<module>hapi-fhir-base/testmindeps</module>
<module>hapi-tinder-plugin</module>
<module>hapi-tinder-test</module>

633
pom.xml.orig Normal file
View File

@ -0,0 +1,633 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.sonatype.oss</groupId>
<artifactId>oss-parent</artifactId>
<version>9</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<packaging>pom</packaging>
<version>0.8-SNAPSHOT</version>
<name>HAPI-FHIR</name>
<url>http://hl7api.sourceforge.net/hapi-fhir/</url>
<organization>
<name>University Health Network</name>
<url>http://www.uhn.ca</url>
</organization>
<inceptionYear>2014</inceptionYear>
<issueManagement>
<system>GitHub</system>
<url>https://github.com/jamesagnew/hapi-fhir/issues/</url>
</issueManagement>
<distributionManagement>
<site>
<id>git.server</id>
<url>scm:git:git@github.com:jamesagnew/hapi-fhir.git</url>
</site>
</distributionManagement>
<scm>
<connection>scm:git:git@github.com:jamesagnew/hapi-fhir.git</connection>
<url>scm:git:git@github.com:jamesagnew/hapi-fhir.git</url>
<developerConnection>scm:git:git@github.com:jamesagnew/hapi-fhir.git</developerConnection>
</scm>
<description>
</description>
<dependencies>
</dependencies>
<prerequisites>
<maven>3.0.1</maven>
</prerequisites>
<developers>
<developer>
<id>jamesagnew</id>
<name>James Agnew</name>
<organization>University Health Network</organization>
</developer>
<developer>
<name>Dmitri Sotnikov</name>
<organization>University Health Network</organization>
</developer>
<developer>
<name>Lisa Wong</name>
<organization>University Health Network</organization>
</developer>
<developer>
<name>Josh Mandel</name>
<organization>Boston Children's Hospital</organization>
</developer>
<developer>
<name>Laura MacDougall Sookraj</name>
<organization>University Health Network</organization>
</developer>
<developer>
<name>Neal Acharya</name>
<organization>University Health Network</organization>
</developer>
<developer>
<name>David Hay</name>
<organization>Orion Health</organization>
</developer>
<developer>
<id>suranga</id>
<name>Suranga Nath Kasthurirathne</name>
<organization>OpenMRS / Regenstrief Center for Biomedical Informatics</organization>
</developer>
<developer>
<id>dougmartin</id>
<name>Doug Martin</name>
<organization>Regenstrief Center for Biomedical Informatics</organization>
</developer>
<developer>
<id>akley</id>
<name>Alexander Kley</name>
</developer>
<developer>
<id>preston</id>
<name>Preston Lee</name>
<organization>Arizona State University</organization>
</developer>
<developer>
<id>jathman</id>
<name>Joe Athman</name>
</developer>
<developer>
<id>petromykhailysyn</id>
<name>Petro Mykhailyshyn</name>
</developer>
</developers>
<licenses>
<license>
<name>Apache Software License 2.0</name>
<url>https://www.apache.org/licenses/LICENSE-2.0.txt</url>
</license>
</licenses>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!-- For site-deploy -->
<siteMainDirectory>${user.home}/sites/hapi-fhir</siteMainDirectory>
<scmPubCheckoutDirectory>${user.home}/sites/scm/hapi-fhir</scmPubCheckoutDirectory>
<!-- Plugin Versions -->
<commons_lang_version>3.3.2</commons_lang_version>
<derby_version>10.11.1.1</derby_version>
<guava_version>18.0</guava_version>
<hamcrest_version>1.3</hamcrest_version>
<hibernate_version>4.2.12.Final</hibernate_version>
<hibernate_validator_version>5.1.0.Final</hibernate_validator_version>
<jetty_version>9.2.2.v20140723</jetty_version>
<jscience_version>4.3.1</jscience_version>
<junit_version>4.11</junit_version>
<logback_version>1.1.2</logback_version>
<maven_assembly_plugin_version>2.4.1</maven_assembly_plugin_version>
<maven_javadoc_plugin_version>2.9.1</maven_javadoc_plugin_version>
<maven_license_plugin_version>1.7</maven_license_plugin_version>
<maven_surefire_plugin_version>2.17</maven_surefire_plugin_version>
<maven_site_plugin_version>3.4</maven_site_plugin_version>
<maven_source_plugin_version>2.3</maven_source_plugin_version>
<mitreid-connect-version>1.1.8</mitreid-connect-version>
<mockito_version>1.9.5</mockito_version>
<phloc_schematron_version>2.7.1</phloc_schematron_version>
<phloc_commons_version>4.3.3</phloc_commons_version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<servlet_api_version>3.1.0</servlet_api_version>
<slf4j_version>1.7.7</slf4j_version>
<spring_version>4.1.0.RELEASE</spring_version>
<spring_security_version>3.2.4.RELEASE</spring_security_version>
<thymeleaf-version>2.1.3.RELEASE</thymeleaf-version>
<ebay_cors_filter_version>1.0.1</ebay_cors_filter_version>
<woodstox_version>4.4.0</woodstox_version>
</properties>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven_surefire_plugin_version}</version>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
<runOrder>random</runOrder>
<!--<argLine>-Dfile.encoding=ISO-8859-1</argLine> -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>${maven_site_plugin_version}</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-ssh</artifactId>
<version>1.0</version>
</dependency>
<dependency>
<groupId>org.apache.maven.doxia</groupId>
<artifactId>doxia-module-markdown</artifactId>
<version>1.6</version>
</dependency>
</dependencies>
<configuration>
<skip>true</skip>
<skipDeploy>true</skipDeploy>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven_javadoc_plugin_version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven_source_plugin_version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
<version>${maven_license_plugin_version}</version>
<configuration>
<verbose>true</verbose>
<addSvnKeyWords>false</addSvnKeyWords>
</configuration>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<version>${maven_site_plugin_version}</version>
<configuration>
<skip>false</skip>
<skipDeploy>true</skipDeploy>
</configuration>
<dependencies>
<dependency>
<groupId>org.apache.maven.wagon</groupId>
<artifactId>wagon-scm</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-manager-plexus</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-provider-gitexe</artifactId>
<version>1.9</version>
</dependency>
<dependency>
<groupId>org.apache.maven.scm</groupId>
<artifactId>maven-scm-api</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.7</version>
<inherited>false</inherited>
<executions>
<execution>
<id>copySubProjects</id>
<phase>site</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<copy todir="target/site/apidocs">
<fileset dir="hapi-fhir-base/target/site/apidocs"/>
</copy>
<copy todir="target/site/apidocs-dstu">
<fileset dir="hapi-fhir-structures-dstu/target/site/apidocs"/>
</copy>
<copy todir="target/site/apidocs-dev">
<fileset dir="hapi-fhir-structures-dev/target/site/apidocs"/>
</copy>
</target>
</configuration>
</execution>
<execution>
<id>addSyntaxHighlighter</id>
<phase>site</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<target>
<echo>Adding Syntax Highlighter</echo>
<replace dir="target/site" summary="true">
<include name="*.html"></include>
<replacetoken><![CDATA[</body>]]></replacetoken>
<replacevalue><![CDATA[
<script type="text/javascript">
var elements = document.getElementsByClassName("source");
for (var i=0; i < elements.length; i++) {
var pres = elements[i].getElementsByTagName("pre");
for (var j = 0; j < pres.length; j++) {
var pre = pres[j];
if (pre.innerHTML.match(/\/\*/)) {
pre.className = 'brush: java';
} else if (pre.innerHTML.match(/^\/\//)) {
pre.className = 'brush: java';
} else if (pre.innerHTML.match(/^\{/)) {
pre.className = 'brush: jscript';
} else if (pre.innerHTML.match(/^\#/)) {
pre.className = 'brush: bash';
} else if (pre.innerHTML.match(/\&lt\;\//)) {
pre.className = 'brush: xml';
} else {
pre.className = 'brush: java';
}
}
}
SyntaxHighlighter.all();
</script>
</body>
]]></replacevalue>
</replace>
</target>
</configuration>
</execution>
<execution>
<id>addAnalytics</id>
<phase>post-site</phase>
<configuration>
<target>
<echo>Adding Google analytics in target/site for &lt;body&gt;</echo>
<replace dir="target/site" summary="true">
<include name="**/*.html"></include>
<replacefilter token="#build#" value="${label}" />
<replacefilter token="#version#" value="${project.version}" />
<replacetoken><![CDATA[</body>]]></replacetoken>
<replacevalue><![CDATA[
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-1395874-5', 'auto');
ga('require', 'displayfeatures');
ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview');
</script>
</body >
]]></replacevalue>
</replace>
<echo>Adding Google analytics in target/site for &lt;BODY&gt;</echo>
<replace dir="target/site" summary="true">
<include name="**/*.html"></include>
<replacetoken><![CDATA[</BODY>]]></replacetoken>
<replacevalue><![CDATA[
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-1395874-5', 'auto');
ga('require', 'displayfeatures');
ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview');
</script>
</BODY >
]]></replacevalue>
</replace>
<echo>Adding social plugins for HAPI</echo>
<replace dir="target/site/" summary="true">
<include name="**/*.html"></include>
<replacetoken><![CDATA[SOCIALPLUGINSHEREFHIR]]></replacetoken>
<replacevalue><![CDATA[
<table cellpadding="0" cellspacing="0" border="0"><tr>
<td><div class="g-plusone" data-annotation="inline" data-width="300" data-href="http://hl7api.sourceforge.net/"></div></td>
<td><div class="fb-like" data-href="http://hl7api.sourceforge.net/" data-send="false" data-layout="button_count" data-width="450" data-show-faces="true"></div></td>
</tr></table>
<<<<<<< HEAD
</p><p>
<!-- Place this tag after the last +1 button tag. -->
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
<div id="fb-root"></div>
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
]]></replacevalue>
</replace>
=======
</p><p>
<!-- Place this tag after the last +1 button tag. -->
<script type="text/javascript">
(function() {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/plusone.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
</script>
<div id="fb-root"></div>
<script>(function(d, s, id) {
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) return;
js = d.createElement(s); js.id = id;
js.src = "//connect.facebook.net/en_US/all.js#xfbml=1";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));</script>
]]></replacevalue>
</replace>
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<version>1.12</version>
<inherited>true</inherited>
<configuration>
<signature>
<groupId>org.codehaus.mojo.signature</groupId>
<artifactId>java16</artifactId>
<version>1.01</version>
</signature>
</configuration>
</plugin>
<plugin>
<artifactId>maven-site-plugin</artifactId>
<inherited>false</inherited>
<executions>
<execution>
<id>stage-for-scm-publish</id>
<phase>post-site</phase>
<goals>
<goal>stage</goal>
</goals>
<configuration>
<stagingDirectory>${siteMainDirectory}</stagingDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-publish-plugin</artifactId>
<version>1.1</version>
<inherited>false</inherited>
<configuration>
<checkoutDirectory>${scmPubCheckoutDirectory}</checkoutDirectory>
<content>\${siteMainDirectory}</content>
<tryUpdate>true</tryUpdate>
<scmBranch>gh-pages</scmBranch>
<pubScmUrl>scm:git:git@github.com:jamesagnew/hapi-fhir.git</pubScmUrl>
</configuration>
<executions>
<execution>
<id>scm-publish</id>
<phase>site-deploy</phase>
<goals>
<goal>publish-scm</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-changes-plugin</artifactId>
<version>2.11</version>
<inherited>false</inherited>
<reportSets>
<reportSet>
<reports>
<report>changes-report</report>
</reports>
</reportSet>
</reportSets>
<configuration>
<feedType>atom_1.0</feedType>
<issueLinkTemplatePerSystem>
<default>https://github.com/jamesagnew/hapi-fhir/issues/%ISSUE%</default>
</issueLinkTemplatePerSystem>
<escapeHTML>false</escapeHTML>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${maven_surefire_plugin_version}</version>
<configuration>
<aggregate>true</aggregate>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-project-info-reports-plugin</artifactId>
<version>2.7</version>
<inherited>false</inherited>
<reportSets>
<reportSet>
<reports>
<report>project-team</report>
<report>issue-tracking</report>
<report>license</report>
<report>scm</report>
</reports>
</reportSet>
</reportSets>
</plugin>
<<<<<<< HEAD
=======
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>findbugs-maven-plugin</artifactId>
<version>3.0.0</version>
<configuration>
<classFilesDirectory>./hapi-fhir-base/target/classes</classFilesDirectory>
</configuration>
<reportSets>
<reportSet>
<reports>
<report>findbugs</report>
</reports>
</reportSet>
</reportSets>
</plugin>
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
<!-- <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-linkcheck-plugin</artifactId>
<version>1.1</version> </plugin> -->
</plugins>
</reporting>
<profiles>
<profile>
<id>ROOT</id>
<modules>
</modules>
</profile>
<profile>
<id>SIGN_ARTIFACTS</id>
<activation>
<property>
<name>gpg.passphrase</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>SITE</id>
<modules>
<module>hapi-fhir-base</module>
<module>hapi-fhir-structures-dstu</module>
<module>hapi-fhir-structures-dev</module>
<<<<<<< HEAD
=======
<module>examples</module>
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
</modules>
</profile>
<profile>
<id>ALLMODULES</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<modules>
<module>hapi-deployable-pom</module>
<module>hapi-fhir-base</module>
<module>hapi-fhir-oauth2</module>
<<<<<<< HEAD
<module>hapi-fhir-base/examples</module>
=======
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2
<module>hapi-fhir-base/testmindeps</module>
<module>hapi-tinder-plugin</module>
<module>hapi-tinder-test</module>
<module>hapi-fhir-structures-dstu</module>
<module>hapi-fhir-structures-dev</module>
<module>hapi-fhir-jpaserver-base</module>
<module>hapi-fhir-jpaserver-test</module>
<module>restful-server-example</module>
<module>restful-server-example-test</module>
<module>hapi-fhir-testpage-overlay</module>
<module>hapi-fhir-jpaserver-uhnfhirtest</module>
</modules>
</profile>
</profiles>
</project>

View File

@ -3,17 +3,13 @@
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
<<<<<<< HEAD
<dependent-module deploy-path="/" handle="module:/overlay/var/M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-testpage-overlay/0.7/hapi-fhir-testpage-overlay-0.7.war?unpackFolder=target/m2e-wtp/overlays&amp;includes=**/**&amp;excludes=META-INF/MANIFEST.MF">
=======
<dependent-module archiveName="hapi-fhir-base-0.8-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module archiveName="hapi-fhir-structures-dstu-0.8-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-structures-dstu/hapi-fhir-structures-dstu">
<dependency-type>uses</dependency-type>
</dependent-module>
<dependent-module deploy-path="/" handle="module:/overlay/var/M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-testpage-overlay/0.8-SNAPSHOT/hapi-fhir-testpage-overlay-0.8-SNAPSHOT.war?unpackFolder=target/m2e-wtp/overlays&amp;includes=**/**&amp;excludes=META-INF/MANIFEST.MF">
>>>>>>> ece0e836092fef78edeab7cf2aac4d9be34d864c
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-testpage-overlay?includes=**/**&amp;excludes=META-INF/MANIFEST.MF">
<dependency-type>consumes</dependency-type>
</dependent-module>
<dependent-module deploy-path="/" handle="module:/overlay/slf/?includes=**/**&amp;excludes=META-INF/MANIFEST.MF">

View File

@ -7,11 +7,19 @@
</properties>
<body>
<release version="0.8" date="TBD">
<action type="add" issue="38">
<action>
<![CDATA[<b>API CHANGE:</b>]]> The "FHIR structures" for DSTU1 (the classes which model the
resources and composite datatypes) have been moved out of the core JAR into their
own JAR, in order to allow support for DEV resources, and DSTU2 resources when thast
version is finalized. See
<![CDATA[<a href="./doc_upgrading.html">upgrading</a>]]>
for more information.
</action>
<action type="add" issue="38" dev="wdebeau1">
Profile generation on the server was not working due to IdDt being
incorrectly used. Thanks to Bill de Beaubien for the pull request!
</action>
<action type="add" issue="42">
<action type="add" issue="42" dev="wdebeau1">
Profiles did not generate correctly if a resource definition class had a
defined extension which was of a composite type. Thanks to Bill de Beaubien for the pull request!
</action>
@ -19,6 +27,25 @@
Remove unnessecary IOException from narrative generator API. Thanks to
Petro Mykhailysyn for the pull request!
</action>
<action type="add" issue="48" dev="wdebeau1">
Introduced a new
<![CDATA[<code>@ProvidesResources</code>]]> annotation which can be added to
resource provider and servers to allow them to declare additional resource
classes they are able to serve. This is useful if you have a server which can
serve up multiple classes for the same resource type (e.g. a server that sometimes
returns a default Patient, but sometimes uses a custom subclass).
Thanks to Bill de Beaubien for the pull request!
</action>
<action>
Add a new method <![CDATA[handleException]]> to the server interceptor
framework which allows interceptors to be notified of any exceptions and
runtime errors within server methods. Interceptors may optionally also
override the default error handling behaviour of the RestfulServer.
</action>
<action dev="wdebeau1">
Add constants to BaseResource for the "_id" search parameter which all resources
should support.
</action>
</release>
<release version="0.7" date="2014-Oct-23">
<action type="add" issue="30">

View File

@ -0,0 +1,476 @@
<?xml version="1.0"?>
<document xmlns="http://maven.apache.org/changes/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 ./changes.xsd">
<properties>
<author>James Agnew</author>
<title>HAPI FHIR Changelog</title>
</properties>
<body>
<release version="0.8" date="TBD">
<<<<<<< HEAD:src/changes/changes.xml
<action type="add" issue="38">
Profile generation on the server was not working due to IdDt being
incorrectly used. Thanks to Bill de Beaubien for the pull request!
</action>
<action type="add" issue="42">
=======
<action>
<![CDATA[<b>API CHANGE:</b>]]> The "FHIR structures" for DSTU1 (the classes which model the
resources and composite datatypes) have been moved out of the core JAR into their
own JAR, in order to allow support for DEV resources, and DSTU2 resources when thast
version is finalized. See
<![CDATA[<a href="./doc_upgrading.html">upgrading</a>]]>
for more information.
</action>
<action type="add" issue="38" dev="wdebeau1">
Profile generation on the server was not working due to IdDt being
incorrectly used. Thanks to Bill de Beaubien for the pull request!
</action>
<action type="add" issue="42" dev="wdebeau1">
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2:src/changes/changes.xml
Profiles did not generate correctly if a resource definition class had a
defined extension which was of a composite type. Thanks to Bill de Beaubien for the pull request!
</action>
<action type="add" issue="44" dev="petromykhailysyn">
Remove unnessecary IOException from narrative generator API. Thanks to
Petro Mykhailysyn for the pull request!
</action>
<<<<<<< HEAD:src/changes/changes.xml
=======
<action type="add" issue="48" dev="wdebeau1">
Introduced a new
<![CDATA[<code>@ProvidesResources</code>]]> annotation which can be added to
resource provider and servers to allow them to declare additional resource
classes they are able to serve. This is useful if you have a server which can
serve up multiple classes for the same resource type (e.g. a server that sometimes
returns a default Patient, but sometimes uses a custom subclass).
Thanks to Bill de Beaubien for the pull request!
</action>
<action>
Add a new method <![CDATA[handleException]]> to the server interceptor
framework which allows interceptors to be notified of any exceptions and
runtime errors within server methods. Interceptors may optionally also
override the default error handling behaviour of the RestfulServer.
</action>
<action dev="wdebeau1">
Add constants to BaseResource for the "_id" search parameter which all resources
should support.
</action>
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2:src/changes/changes.xml
</release>
<release version="0.7" date="2014-Oct-23">
<action type="add" issue="30">
<![CDATA[<b>API CHANGE:</b>]]> The TagList class previously implemented ArrayList semantics,
but this has been replaced with LinkedHashMap semantics. This means that the list of
tags will no longer accept duplicate tags, but that tag order will still be
preserved. Thanks to Bill de Beaubien for reporting!
</action>
<action type="fix" issue="33">
Server was incorrectly including contained resources being returned as both contained resources, and as
top-level resources in the returned bundle for search operations.
Thanks to Bill de Beaubien for reporting! This also fixes Issue #20, thanks to
lephty for reporting!
</action>
<action type="add" dev="suranga">
Documentation fixes
</action>
<action type="add" dev="dougmartin">
Add a collection of new methods on the generic client which support the
<![CDATA[
<b><a href="./apidocs/ca/uhn/fhir/rest/client/IGenericClient.html#read(java.lang.Class,%20ca.uhn.fhir.model.primitive.UriDt)">read</a></b>,
<b><a href="./apidocs/ca/uhn/fhir/rest/client/IGenericClient.html#vread(java.lang.Class,%20ca.uhn.fhir.model.primitive.UriDt)">read</a></b>,
and <b><a href="./apidocs/ca/uhn/fhir/rest/client/IGenericClient.html#search(java.lang.Class,%20ca.uhn.fhir.model.primitive.UriDt)">search</a></b>
]]>
operations using an absolute URL. This allows developers to perform these operations using
URLs they obtained from other sources (or external resource references within resources). In
addition, the existing read/vread operations will now access absolute URL references if
they are passed in. Thanks to Doug Martin of the Regenstrief Center for Biomedical Informatics
for contributing this implementation!
</action>
<action type="fix">
Server implementation was not correctly figuring out its own FHIR Base URL when deployed
on Amazon Web Service server. Thanks to Jeffrey Ting and Bill De Beaubien of
Systems Made Simple for their help in figuring out this issue!
</action>
<action type="fix">
XML Parser failed to encode fields with both a resource reference child and
a primitive type child. Thanks to Jeffrey Ting and Bill De Beaubien of
Systems Made Simple for their help in figuring out this issue!
</action>
<action type="fix">
HAPI now runs successfully on Servlet 2.5 containers (such as Tomcat 6). Thanks to
Bernard Gitaadji for reporting and diagnosing the issue!
</action>
<action type="fix">
Summary (in the bundle entry) is now encoded by the XML and JSON parsers if supplied. Thanks to David Hay of
Orion Health for reporting this!
</action>
<action type="fix" issue="24">
Conformance profiles which are automatically generated by the server were missing a few mandatory elements,
which meant that the profile did not correctly validate. Thanks to Bill de Beaubien of Systems Made Simple
for reporting this!
</action>
<action type="fix">
XHTML (in narratives) containing escapable characters (e.g. &lt; or &quot;) will now always have those characters
escaped properly in encoded messages.
</action>
<action type="fix">
Resources containing entities which are not valid in basic XML (e.g. &amp;sect;) will have those
entities converted to their equivalent unicode characters when resources are encoded, since FHIR does
not allow extended entities in resource instances.
</action>
<action type="add">
Add a new client interceptor which adds HTTP Authorization Bearer Tokens (for use with OAUTH2 servers)
to client requests.
</action>
<action type="fix">
Add phloc-commons dependency explicitly, which resolves an issue building HAPI from source on
some platforms. Thanks to Odysseas Pentakalos for the patch!
</action>
<action type="add">
HAPI now logs a single line indicating the StAX implementation being used upon the
first time an XML parser is created.
</action>
<action type="fix">
Update methods on the server did not return a "content-location" header, but
only a "location" header. Both are required according to the FHIR specification.
Thanks to Bill de Beaubien of Systems Made Simple for reporting this!
</action>
<action type="fix" issue="26" dev="akley">
Parser failed to correctly read contained Binary resources. Thanks to Alexander Kley for
the patch!
</action>
<action type="fix" issue="29" dev="akley">
Calling encode multiple times on a resource with contained resources caused the contained
resources to be re-added (and the actual message to grow) with each encode pass. Thanks to
Alexander Kley for the test case!
</action>
<action type="fix">
JSON-encoded contained resources with the incorrect "_id" element (which should be "id", but some
incorrect examples exist on the FHIR specification) now parse correctly. In other words, HAPI
previously only accepted the correct "id" element, but now it also accepts the incorrect
"_id" element just to be more lenient.
</action>
<action type="fix">
Several unit tests failed on Windows (or any platform with non UTF-8 default encoding). This may
have also caused resource validation to fail occasionally on these platforms as well.
Thanks to Bill de Beaubien for reporting!
</action>
<action type="fix">
toString() method on TokenParam was incorrectly showing the system as the value.
Thanks to Bill de Beaubien for reporting!
</action>
<action type="update">
Documentation on contained resources contained a typo and did not actually produce contained resources. Thanks
to David Hay of Orion Health for reporting!
</action>
<action type="add" issue="31" dev="preston">
Add a
<![CDATA[<a href="https://www.vagrantup.com/">Vagrant</a>]]>
based environment (basically a fully built, self contained development environment) for
trying out the HAPI server modules. Thanks to Preston Lee for the pull request, and for
offering to maintain this!
</action>
<action type="add" issue="32" dev="jathman">
Change validation API so that it uses a return type instead of exceptions to communicate
validation failures. Thanks to Joe Athman for the pull request!
</action>
<action type="add" issue="35" dev="petromykhailysyn">
Add a client interceptor which adds an HTTP cookie to each client request. Thanks to
Petro Mykhailysyn for the pull request!
</action>
</release>
<release version="0.6" date="2014-Sep-08" description="This release brings a number of new features and bug fixes!">
<!--
<action type="add">
Allow generic client ... OAUTH
</action>
-->
<action type="add">
Add server interceptor framework, and new interceptor for logging incoming
requests.
</action>
<action type="add">
Add server validation framework for validating resources against the FHIR schemas and schematrons
</action>
<action type="fix">
Tester UI created double _format and _pretty param entries in searches. Thanks to Gered King of University
Health Network for reporting!
</action>
<action type="fix" issue="4">
Create method was incorrectly returning an HTTP 204 on sucessful completion, but
should be returning an HTTP 200 per the FHIR specification. Thanks to wanghaisheng
for reporting!
</action>
<action type="fix">
FHIR Tester UI now correctly sends UTF-8 charset in responses so that message payloads containing
non US-ASCII characters will correctly display in the browser
</action>
<action type="fix">
JSON parser was incorrectly encoding extensions on composite elements outside the element itself
(as is done correctly for non-composite elements) instead of inside of them. Thanks to David Hay of
Orion for reporting this!
</action>
<action type="add">
Contained/included resource instances received by a client are now automatically
added to any ResourceReferenceDt instancea in other resources which reference them.
</action>
<action type="add">
Add documentation on how to use eBay CORS Filter to support Cross Origin Resource
Sharing (CORS) to server. CORS support that was built in to the server itself has
been removed, as it did not work correctly (and was reinventing a wheel that others
have done a great job inventing). Thanks to Peter Bernhardt of Relay Health for all the assistance
in testing this!
</action>
<action type="fix">
IResource interface did not expose the getLanguage/setLanguage methods from BaseResource,
so the resource language was difficult to access.
</action>
<action type="fix">
JSON Parser now gives a more friendly error message if it tries to parse JSON with invalid use
of single quotes
</action>
<action type="add">
Transaction server method is now allowed to return an OperationOutcome in addition to the
incoming resources. The public test server now does this in order to return status information
about the transaction processing.
</action>
<action type="add">
Update method in the server can now flag (via a field on the MethodOutcome object being returned)
that the result was actually a creation, and Create method can indicate that it was actually an
update. This has no effect other than to switch between the HTTP 200 and HTTP 201 status codes on the
response, but this may be useful in some circumstances.
</action>
<action type="fix">
Annotation client search methods with a specific resource type (e.g. List&lt;Patient&gt; search())
won't return any resources that aren't of the correct type that are received in a response
bundle (generally these are referenced resources, so they are populated in the reference fields instead).
Thanks to Tahura Chaudhry of University Health Network for the unit test!
</action>
<action type="add">
Added narrative generator template for OperationOutcome resource
</action>
<action type="fix">
Date/time types did not correctly parse values in the format "yyyymmdd" (although the FHIR-defined format
is "yyyy-mm-dd" anyhow, and this is correctly handled). Thanks to Jeffrey Ting of Systems Made Simple
for reporting!
</action>
<action type="fix">
Server search method for an unnamed query gets called if the client requests a named query
with the same parameter list. Thanks to Neal Acharya of University Health Network for reporting!
</action>
<action type="fix">
Category header (for tags) is correctly read in client for "read" operation
</action>
<action type="add">
Transaction method in server can now have parameter type Bundle instead of
List&lt;IResource&gt;
</action>
<action type="add">
HAPI parsers now use field access to get/set values instead of method accessors and mutators.
This should give a small performance boost.
</action>
<action type="fix">
JSON parser encodes resource references incorrectly, using the name "resource" instead
of the name "reference" for the actual reference. Thanks to
Ricky Nguyen for reporting and tracking down the issue!
</action>
<action type="fix">
Rename NotImpementedException to NotImplementedException (to correct typo)
</action>
<action type="fix">
Server setUseBrowserFriendlyContentType setting also respected for errors (e.g. OperationOutcome with 4xx/5xx status)
</action>
<action type="fix">
Fix performance issue in date/time datatypes where pattern matchers were not static
</action>
<action type="fix">
Server now gives a more helpful error message if a @Read method has a search parameter (which is invalid, but
previously lead to a very unhelpful error message). Thanks to Tahura Chaudhry of UHN for reporting!
</action>
<action type="fix">
Resource of type "List" failed to parse from a bundle correctly. Thanks to David Hay of Orion Health
for reporting!
</action>
<action type="fix">
QuantityParam correctly encodes approximate (~) prefix to values
</action>
<action type="fix" issue="14">
If a server defines a method with parameter "_id", incoming search requests for that method may
get delegated to the wrong method. Thanks to Neal Acharya for reporting!
</action>
<action type="add">
SecurityEvent.Object structural element has been renamed to
SecurityEvent.ObjectElement to avoid conflicting names with the
java Object class. Thanks to Laurie Macdougall-Sookraj of UHN for
reporting!
</action>
<action type="fix">
Text/narrative blocks that were created with a non-empty
namespace prefix (e.g. &lt;xhtml:div xmlns:xhtml="..."&gt;...&lt;/xhtml:div&gt;)
failed to encode correctly (prefix was missing in encoded resource)
</action>
<action type="fix">
Resource references previously encoded their children (display and reference)
in the wrong order so references with both would fail schema validation.
</action>
<action type="add">
SecurityEvent resource's enums now use friendly enum names instead of the unfriendly
numeric code values. Thanks to Laurie MacDougall-Sookraj of UHN for the
suggestion!
</action>
</release>
<release version="0.5" date="2014-Jul-30">
<action type="add">
HAPI has a number of RESTful method parameter types that have similar but not identical
purposes and confusing names. A cleanup has been undertaken to clean this up.
This means that a number of existing classes
have been deprocated in favour of new naming schemes.
<![CDATA[<br/><br/>]]>
All annotation-based clients and all server search method parameters are now named
(type)Param, for example: StringParam, TokenParam, etc.
<![CDATA[<br/><br/>]]>
All generic/fluent client method parameters are now named
(type)ClientParam, for example: StringClientParam, TokenClientParam, etc.
<![CDATA[<br/><br/>]]>
All renamed classes have been retained and deprocated, so this change should not cause any issues
for existing applications but those applications should be refactored to use the
new parameters when possible.
</action>
<action type="add">
Allow server methods to return wildcard generic types (e.g. List&lt;? extends IResource&gt;)
</action>
<action type="add">
Search parameters are not properly escaped and unescaped. E.g. for a token parameter such as
"&amp;identifier=system|codepart1\|codepart2"
</action>
<action type="add">
Add support for OPTIONS verb (which returns the server conformance statement)
</action>
<action type="add">
Add support for CORS headers in server
</action>
<action type="add">
Bump SLF4j dependency to latest version (1.7.7)
</action>
<action type="add">
Add interceptor framework for clients (annotation based and generic), and add interceptors
for configurable logging, capturing requests and responses, and HTTP basic auth.
</action>
<action type="fix">
Transaction client invocations with XML encoding were using the wrong content type ("application/xml+fhir" instead
of the correct "application/atom+xml"). Thanks to David Hay of Orion Health for surfacing this one!
</action>
<action type="add">
Bundle entries now support a link type of "search". Thanks to David Hay for the suggestion!
</action>
<action type="add" issue="1">
If a client receives a non 2xx response (e.g. HTTP 500) and the response body is a text/plain message or
an OperationOutcome resource, include the message in the exception message so that it will be
more conveniently displayed in logs and other places. Thanks to Neal Acharya for the suggestion!
</action>
<action type="add" issue="2">
Read invocations in the client now process the "Content-Location" header and use it to
populate the ID of the returned resource. Thanks to Neal Acharya for the suggestion!
</action>
<action type="fix" issue="3">
Fix issue where vread invocations on server incorrectly get routed to instance history method if one is
defined. Thanks to Neal Acharya from UHN for surfacing this one!
</action>
<action type="add">
Binary reads on a server not include the Content-Disposition header, to prevent HTML in binary
blobs from being used for nefarious purposes. See
<![CDATA[<a href="http://gforge.hl7.org/gf/project/fhir/tracker/?action=TrackerItemEdit&tracker_id=677&tracker_item_id=3298">FHIR Tracker Bug 3298</a>]]>
for more information.
</action>
<action type="add">
Support has been added for using an HTTP proxy for outgoing requests.
</action>
<action type="fix">
Fix: Primitive extensions declared against custom resource types
are encoded even if they have no value. Thanks to David Hay of Orion for
reporting this!
</action>
<action type="fix">
Fix: RESTful server deployed to a location where the URL to access it contained a
space (e.g. a WAR file with a space in the name) failed to work correctly.
Thanks to David Hay of Orion for reporting this!
</action>
</release>
<release version="0.4" date="2014-Jul-13">
<action type="add">
<![CDATA[<b>BREAKING CHANGE:</b>]]>: IdDt has been modified so that it
contains a partial or complete resource identity. Previously it contained
only the simple alphanumeric id of the resource (the part at the end of the "read" URL for
that resource) but it can now contain a complete URL or even a partial URL (e.g. "Patient/123")
and can optionally contain a version (e.g. "Patient/123/_history/456"). New methods have
been added to this datatype which provide just the numeric portion. See the JavaDoc
for more information.
</action>
<action type="add">
<![CDATA[<b>API CHANGE:</b>]]>: Most elements in the HAPI FHIR model contain
a getId() and setId() method. This method is confusing because it is only actually used
for IDREF elements (which are rare) but its name makes it easy to confuse with more
important identifiers. For this reason, these methods have been deprocated and replaced with
get/setElementSpecificId() methods. The old methods will be removed at some point. Resource
types are unchanged and retain their get/setId methods.
</action>
<action type="add">
Allow use of QuantityDt as a service parameter to support the "quantity" type. Previously
QuantityDt did not implement IQueryParameterType so it was not valid, and there was no way to
support quantity search parameters on the server (e.g. Observation.value-quantity)
</action>
<action type="add">
Introduce StringParameter type which can be used as a RESTful operation search parameter
type. StringParameter allows ":exact" matches to be specified in clients, and handled in servers.
</action>
<action type="add">
Parsers (XML/JSON) now support deleted entries in bundles
</action>
<action type="add">
Transaction method now supported in servers
</action>
<action type="add">
Support for Binary resources added (in servers, clients, parsers, etc.)
</action>
<action type="fix">
Support for Query resources fixed (in parser)
</action>
<action type="fix">
Nested contained resources (e.g. encoding a resource with a contained resource that itself contains a resource)
now parse and encode correctly, meaning that all contained resources are placed in the "contained" element
of the root resource, and the parser looks in the root resource for all container levels when stitching
contained resources back together.
</action>
<action type="fix">
Server methods with @Include parameter would sometimes fail when no _include was actually
specified in query strings.
</action>
<action type="fix">
Client requests for IdentifierDt types (such as Patient.identifier) did not create the correct
query string if the system is null.
</action>
<action type="add">
Add support for paging responses from RESTful servers.
</action>
<action type="fix">
Don't fail on narrative blocks in JSON resources with only an XML declaration but no content (these are
produced by the Health Intersections server)
</action>
<action type="fix">
Server now automatically compresses responses if the client indicates support
</action>
<action type="fix">
Server failed to support optional parameters when type is String and :exact qualifier is used
</action>
<action type="fix">
Read method in client correctly populated resource ID in returned object
</action>
<action type="add">
Support added for deleted-entry by/name, by/email, and comment from Tombstones spec
</action>
</release>
<release version="0.3" date="2014-May-12" description="This release corrects lots of bugs and introduces the fluent client mode">
</release>
</body>
</document>

View File

@ -0,0 +1 @@
<mxGraphModel dx="940" dy="431" grid="1" gridSize="10" guides="1" tooltips="1" connect="1" fold="1" page="1" pageScale="1" pageWidth="826" pageHeight="1169" style="default-style2" math="0"><root><mxCell id="0"/><mxCell id="1" parent="0"/><mxCell id="2" value="RESTful&#xa;Server" style="shape=umlLifeline;perimeter=lifelinePerimeter;size=46;strokeColor=#0000FF;strokeWidth=2;fillColor=#99FFFF" parent="1" vertex="1"><mxGeometry x="150" y="20" width="100" height="280" as="geometry"/></mxCell><mxCell id="3" value="Interceptor" style="shape=umlLifeline;perimeter=lifelinePerimeter;size=46;strokeColor=#0000FF;strokeWidth=2;fillColor=#99FFFF" parent="1" vertex="1"><mxGeometry x="280" y="20" width="100" height="280" as="geometry"/></mxCell><mxCell id="4" value="Resource/Plain&#xa;Provider&#xa;Method" style="shape=umlLifeline;perimeter=lifelinePerimeter;size=46;strokeColor=#0000FF;strokeWidth=2;fillColor=#99FFFF" parent="1" vertex="1"><mxGeometry x="400" y="20" width="100" height="280" as="geometry"/></mxCell><mxCell id="7" value="" style="ellipse;shape=startState;fillColor=#000000;strokeColor=#ff0000;" parent="1" vertex="1"><mxGeometry x="70" y="80" width="30" height="30" as="geometry"/></mxCell><mxCell id="8" value="Incoming Request" style="edgeStyle=elbowEdgeStyle;elbow=horizontal;verticalAlign=bottom;endArrow=open;endSize=8;strokeColor=#ff0000;entryX=0.5;entryY=0.3;entryPerimeter=0" parent="1" source="7" edge="1"><mxGeometry x="70" y="80" as="geometry"><mxPoint x="200" y="95" as="targetPoint"/></mxGeometry></mxCell><mxCell id="21" value="Request is handled" style="rounded=1;whiteSpace=wrap" parent="1" vertex="1"><mxGeometry x="390" y="150" width="120" height="30" as="geometry"/></mxCell><mxCell id="22" value="" style="edgeStyle=none;align=left;entryX=0.5;entryY=0.632;entryPerimeter=0;exitX=0.5;exitY=0.632;exitPerimeter=0" parent="1" edge="1"><mxGeometry width="100" height="100" relative="1" as="geometry"><mxPoint x="200" y="140.15999999999997" as="sourcePoint"/><mxPoint x="450" y="140.15999999999997" as="targetPoint"/></mxGeometry></mxCell><mxCell id="24" value="" parent="1" vertex="1"><mxGeometry x="320" y="233" width="20" height="27" as="geometry"/></mxCell><mxCell id="25" value="handleException" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;endArrow=block;exitX=0.5;exitY=0.478;exitPerimeter=0;align=left" parent="1" target="24" edge="1"><mxGeometry x="221.75" y="233.25" as="geometry"><mxPoint x="200" y="233.39999999999998" as="sourcePoint"/></mxGeometry></mxCell><mxCell id="26" value="return true;" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;dashed=1;endArrow=open;endSize=8;" parent="1" source="24" edge="1"><mxGeometry x="221.75" y="233.25" as="geometry"><mxPoint x="200" y="260" as="targetPoint"/></mxGeometry></mxCell><mxCell id="27" value="" style="ellipse;shape=endState;fillColor=#000000;strokeColor=#ff0000;align=left" parent="1" vertex="1"><mxGeometry x="70" y="270" width="30" height="30" as="geometry"/></mxCell><mxCell id="28" value="Response" style="edgeStyle=orthogonalEdgeStyle;endArrow=block;dashed=0;dashPattern=1 4;align=left;entryX=1;entryY=0.5;exitX=0.5;exitY=0.954;exitPerimeter=0;endFill=1;strokeWidth=1;strokeColor=#FF0000" parent="1" target="27" edge="1"><mxGeometry x="0.500299820107935" y="-13" width="100" height="100" relative="1" as="geometry"><mxPoint x="200" y="285.05999999999995" as="sourcePoint"/><mxPoint x="650" y="213" as="targetPoint"/><mxPoint x="-8" y="-12" as="offset"/></mxGeometry></mxCell><mxCell id="29" value="" style="ellipse;shape=cloud;whiteSpace=wrap;html=1;" vertex="1" parent="1"><mxGeometry x="175" y="100" width="50" height="30" as="geometry"/></mxCell><mxCell id="30" value="throw exception" style="edgeStyle=elbowEdgeStyle;elbow=vertical;verticalAlign=bottom;dashed=1;endArrow=open;endSize=8;" edge="1" parent="1"><mxGeometry x="351.75" y="173.25" as="geometry"><mxPoint x="200" y="200" as="targetPoint"/><mxPoint x="450" y="200" as="sourcePoint"/></mxGeometry></mxCell></root></mxGraphModel>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,4 @@
In this directory:
* XCF files are opened in The GIMP
* XML files are opened in draw.io

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -60,7 +60,7 @@
<menu name="Documentation">
<item name="Introduction" href="./doc_intro.html" />
<item name="The Data Model" href="./doc_fhirobjects.html">
<item name="Extensions" href="./doc_extensions.html" />
<item name="Profiles &amp; Extensions" href="./doc_extensions.html" />
<item name="Resource References" href="./doc_resource_references.html" />
<item name="Tags" href="./doc_tags.html" />
<item name="Validation" href="./doc_validation.html" />
@ -85,9 +85,9 @@
</menu>
<menu name="JavaDocs">
<item name="API (Core)" href="./apidocs/index.html" />
<item name="API (DSTU Model)" href="./apidocs-dstu/index.html" />
<item name="API (DEV Model)" href="./apidocs-dev/index.html" />
<item name="Core API" href="./apidocs/index.html" />
<item name="Model API (DSTU1)" href="./apidocs-dstu/index.html" />
<item name="Model API (DEV)" href="./apidocs-dev/index.html" />
<item name="Source Code" href=".https://github.com/jamesagnew/hapi-fhir" />
</menu>

124
src/site/site.xml.orig Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<project xmlns="http://maven.apache.org/DECORATION/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/DECORATION/1.1.0 http://maven.apache.org/xsd/decoration-1.1.0.xsd" name="HAPI">
<bannerLeft>
<name>HAPI</name>
<src>images/hapi_fhir_banner.png</src>
<href>http://jamesagnew.github.io/hapi-fhir/</href>
</bannerLeft>
<bannerRight>
<name>FHIR</name>
<src>images/hapi_fhir_banner_right.png</src>
<href>http://jamesagnew.github.io/hapi-fhir/</href>
</bannerRight>
<poweredBy>
<logo name="Hosted on GitHub" href="https://github.com/jamesagnew/hapi-fhir" img="./images/github-logo-mini.png"/>
<logo name="Built with Maven 3" href="http://maven.apache.org" img="./images/maven-logo-mini.png" />
</poweredBy>
<version position="left" />
<body>
<head>
<!-- Syntax Highlighter -->
<script type="text/javascript" src="syntaxhighlighter/shCore.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushJScript.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushJava.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushBash.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushXml.js"></script>
<link href="syntaxhighlighter/shCore.css" rel="stylesheet" type="text/css" />
<link href="syntaxhighlighter/shThemeDefault.css" rel="stylesheet" type="text/css" />
<!--
HAPI stylesheet comes after because it overwrites the Syntax Highlighter
font size
-->
<link rel="shortcut icon" href="https://github.com/jamesagnew/hapi-fhir/images/favicon.png" />
<link rel="stylesheet" type="text/css" href="hapi.css" />
</head>
<links>
<item name="GitHub Page" href="https://github.com/jamesagnew/hapi-fhir/" />
<item name="hl7.org" href="http://hl7.org/" />
<item name="University Health Network" href="http://www.uhn.ca/" />
</links>
<menu name="Welcome">
<item name="Welcome" href="index.html" />
<item name="Download" href="./download.html" />
<item name="Upgrade Guide" href="./doc_upgrading.html" />
<item name="Changelog" href="./changes-report.html" />
</menu>
<menu name="Test Server">
<item name="Public Test Server" href="http://fhirtest.uhn.ca"/>
<item name="Vagrant (Private) Test Server" href="doc_vagrant.html"/>
</menu>
<menu name="Documentation">
<item name="Introduction" href="./doc_intro.html" />
<item name="The Data Model" href="./doc_fhirobjects.html">
<item name="Profiles &amp; Extensions" href="./doc_extensions.html" />
<item name="Resource References" href="./doc_resource_references.html" />
<item name="Tags" href="./doc_tags.html" />
<item name="Validation" href="./doc_validation.html" />
</item>
<item name="RESTful Client" href="./doc_rest_client.html" >
<item name="Interceptors (client)" href="./doc_rest_client_interceptor.html"/>
</item>
<item name="RESTful Server" href="./doc_rest_server.html" >
<item name="RESTful Operations" href="./doc_rest_operations.html" />
<item name="Narrative Generator" href="./doc_narrative.html" />
<item name="CORS Support" href="./doc_cors.html" />
<item name="Interceptors (server)" href="./doc_rest_server_interceptor.html" />
<item name="Web Testing UI" href="./doc_server_tester.html" />
</item>
<item name="Logging" href="./doc_logging.html" />
<item name="Tinder Plugin" href="./doc_tinder.html" />
</menu>
<menu name="Community">
<item name="Google Group" href="https://groups.google.com/d/forum/hapi-fhir" />
<item name="Issue Tracker" href="https://github.com/jamesagnew/hapi-fhir/issues" />
</menu>
<menu name="JavaDocs">
<<<<<<< HEAD:src/site/site.xml
<item name="API (Core)" href="./apidocs/index.html" />
<item name="API (DSTU Model)" href="./apidocs-dstu/index.html" />
<item name="API (DEV Model)" href="./apidocs-dev/index.html" />
=======
<item name="Core API" href="./apidocs/index.html" />
<item name="Model API (DSTU1)" href="./apidocs-dstu/index.html" />
<item name="Model API (DEV)" href="./apidocs-dev/index.html" />
>>>>>>> d22a35788f57e9f7ce64bc8afc2ee7eaf29d94f2:src/site/site.xml
<item name="Source Code" href=".https://github.com/jamesagnew/hapi-fhir" />
</menu>
<menu name="Reports">
<item name="Developers" href="team-list.html" />
<item name="Unit Test Report" href="surefire-report.html" />
<item name="FindBugs" href="findbugs.html" />
<item name="License" href="license.html" />
<item name="Source Code" href="https://github.com/jamesagnew/hapi-fhir" />
</menu>
</body>
<skin>
<groupId>org.apache.maven.skins</groupId>
<artifactId>maven-fluido-skin</artifactId>
<version>1.3.1</version>
</skin>
<custom>
<fluidoSkin>
<googleSearch />
<!-- <sourceLineNumbersEnabled>true</sourceLineNumbersEnabled> -->
</fluidoSkin>
</custom>
</project>

View File

@ -2,7 +2,7 @@
<document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
<properties>
<title>Extensions - HAPI FHIR</title>
<title>Profiles and Extensions - HAPI FHIR</title>
<author email="jamesagnew@users.sourceforge.net">James Agnew</author>
</properties>
@ -13,19 +13,21 @@
<macro name="toc">
</macro>
<p>
Extensions are a key part of the FHIR specification, providing a standardized
way of placing additional data in a resource.
</p>
</section>
<section name="Undeclared Extensions">
<p>
All HAPI FHIR Resource objects support "undeclared extensions",
which are arbitrary extensions you can add.
Extensions are a key part of the FHIR specification, providing a standardized
way of placing additional data in a resource.
</p>
<p>
The simplest way to interact with extensions (i.e. to add them to resources you are creating, or
to read them from resources you are consuming) is to treat them as "undeclared extensions".
Undeclared extensions can be added to any of the built in FHIR resource types that come with HAPI-FHIR.
</p>
<macro name="snippet">
<param name="id" value="resourceExtension" />
<param name="file" value="examples/src/main/java/example/Extensions.java" />
@ -56,8 +58,8 @@
<subsection name="Retrieving Extension Values">
<p>
HAPI provides a few ways of getting data back out of
an extension value (i.e. from a received resource):
HAPI provides a few ways of accessing extension values in resources
which are receieved from other sources (i.e. downloaded by a client).
</p>
<macro name="snippet">
<param name="id" value="parseExtension" />

View File

@ -69,6 +69,32 @@
of the operation being invoked (resource, bundle, etc.)
</li>
</ul>
<br clear="all"/>
<subsection name="Exception Handling">
<img src="svg/restful-server-interceptors-exception.svg" alt="Interceptors" align="right"/>
<p>
In the event of an exception being thrown within the server, the interceptor
method
<code><a href="./apidocs/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.html#handleException(ca.uhn.fhir.rest.method.RequestDetails,%20java.lang.Throwable,%20javax.servlet.http.HttpServletRequest,%20javax.servlet.http.HttpServletResponse)">handleException</a></code>
will be called. This applies both to HAPI-FHIR defined exceptions thrown within resource provider methods
you have created as well as unexpected exceptions such as NullPointerException thrown
at any point in the handling chain.
</p>
<p>
In general, you will want to return <code>true</code> from the <code>handleException</code>
method, which means that processing continues normally (RestfulServer will return an
HTTP 4xx or 5xx response automatically depending on the specific exception which was thrown).
</p>
<p>
However, you may override the server's built-in exception handling by returning
<code>false</code>. In this case, you must provide your own response by
interacting with the <code>HttpServletResponse</code> object which is
passed in.
</p>
</subsection>
<br clear="all"/>
<subsection name="Registering Interceptors">
@ -129,6 +155,29 @@
</section>
<section name="Creating Interceptors">
<p>
Creating your own interceptors is easy. HAPI-FHIR provides a class called
<code>InterceptorAdapter</code> which you can extend and then override any
methods you wish. The following example shows a simple request counter.
</p>
<macro name="snippet">
<param name="id" value="interceptor" />
<param name="file" value="examples/src/main/java/example/RequestCounterInterceptor.java" />
</macro>
<p>
The following example shows an exception handling interceptor which
overrides the built-in exception handling by providing a custom response.
</p>
<macro name="snippet">
<param name="id" value="interceptor" />
<param name="file" value="examples/src/main/java/example/RequestExceptionInterceptor.java" />
</macro>
</section>
</body>
</document>

View File

@ -26,6 +26,57 @@
</subsection>
</section>
<section name="Upgrading to HAPI FHIR 0.5">
<p>
<b>This section is still incomplete: </b> Note that HAPI 0.8 has not
yet been released. This section provides details about how to use the
latest SNAPSHOT release, but it will continue to be enhanced as we move towards
the final 0.8 release.
</p>
<subsection name="Importing Resources">
<p>
Beginning in HAPI-FHIR 0.8, the main distribution has been split from one
JAR to a set of JAR files. You will need at least two to use HAPI:
</p>
<ul>
<li>
<i>Required:</i> The <code>hapi-fhir-base-[version].jar</code> file containing the core library.
</li>
<li>
<i>Required:</i> The <code>hapi-fhir-structures-dstu-[version].jar</code> file containing the FHIR model classes
for DSTU1 (all contents of this JAR were previously found in hapi-fhir-base).
</li>
<li>
<i>Optional:</i> You may also choose to include the
<code>hapi-fhir-structures-dev-[version].jar</code>. This JAR contains structures for the
latest DEV version of FHIR. You may create a client/server which supports either DSTU1 or DEV
resources, or both depending on your needs. Note that using DEV resources may introduce
incompatibilities with other frameworks however. If you are including this JAR,
<b>you must also include hapi-fhir-structures-dstu-[version].jar</b>.
Hopefully by the time 0.8 is final this requirement will be relaxed, but for now it
is mandatory.
</li>
</ul>
</subsection>
<subsection name="Tinder Plugin">
<p>
If you are using the "Tinder" Maven plugin to generate structure code,
you will need to add a structure dependency to the plugin configuration
itself in your project pom.xml. See the
<a href="./doc_tinder.html">Tinder Page</a> for an example of
how to do this.
</p>
</subsection>
</section>
<section name="Upgrading to HAPI FHIR 0.5">