Fix header generation for clients

This commit is contained in:
jamesagnew 2016-02-28 15:44:10 -05:00
parent 1da5855c9c
commit 524b16b1e8
9 changed files with 150 additions and 41 deletions

View File

@ -45,6 +45,9 @@ import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.util.FhirTerser;
/**
* Base class for a REST client factory implementation
*/
public abstract class RestfulClientFactory implements IRestfulClientFactory {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestfulClientFactory.class);
@ -268,6 +271,7 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
theBindings, theMethodToLambda, this);
}
@SuppressWarnings("unchecked")
@Override
public void validateServerBase(String theServerBase, IHttpClient theHttpClient, BaseClient theClient) {
GenericClient client = new GenericClient(myContext, theHttpClient, theServerBase, this);

View File

@ -83,7 +83,10 @@ public interface IQuery<T> extends IClientExecutable<IQuery<T>, T>, IBaseQuery<I
/**
* Forces the query to perform the search using the given method (allowable methods are described in the
* <a href="http://www.hl7.org/implement/standards/fhir/http.html#search">FHIR Specification Section 2.1.11</a>)
* <a href="http://www.hl7.org/fhir/search.html">FHIR Search Specification</a>)
* <p>
* This can be used to force the use of an HTTP POST instead of an HTTP GET
* </p>
*
* @see SearchStyleEnum
* @since 0.6

View File

@ -193,13 +193,13 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
encoding = MethodUtil.detectEncoding(myContents);
}
if (encoding == null) {
encoding = EncodingEnum.XML;
}
if (myParams != null) {
return httpClient.createParamRequest(getContext(), myParams, encoding);
} else {
if (encoding == null) {
encoding = EncodingEnum.XML;
}
String contents = parseContents(thePrettyPrint, encoding);
String contentType = getContentType(encoding);
return httpClient.createByteRequest(getContext(), contents, contentType, encoding);

View File

@ -72,7 +72,7 @@ public class JaxRsRestfulClientFactory extends RestfulClientFactory {
@Override
public void setProxy(String theHost, Integer thePort) {
throw new UnsupportedOperationException("Proxies are not supported yet");
throw new UnsupportedOperationException("Proxies are not supported yet in JAX-RS client");
}
/**

View File

@ -2,6 +2,7 @@ package ca.uhn.fhir.rest.client;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.either;
import static org.hamcrest.Matchers.emptyString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
@ -16,6 +17,7 @@ import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
@ -68,6 +70,7 @@ import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.client.exceptions.InvalidResponseException;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.method.SearchStyleEnum;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.EncodingEnum;
@ -610,8 +613,7 @@ public class GenericClientDstu2Test {
.since(new InstantDt("2001-01-02T11:22:33Z"))
.execute();
//@formatter:on
assertThat(capt.getAllValues().get(idx).getURI().toString(), either(equalTo("http://example.com/fhir/Patient/123/_history?_since=2001-01-02T11:22:33Z&_count=123"))
.or(equalTo("http://example.com/fhir/Patient/123/_history?_count=123&_since=2001-01-02T11:22:33Z")));
assertThat(capt.getAllValues().get(idx).getURI().toString(), either(equalTo("http://example.com/fhir/Patient/123/_history?_since=2001-01-02T11:22:33Z&_count=123")).or(equalTo("http://example.com/fhir/Patient/123/_history?_count=123&_since=2001-01-02T11:22:33Z")));
assertEquals(1, response.getEntry().size());
idx++;
@ -664,8 +666,7 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/Patient/123/$meta-add", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"meta\"/><valueMeta><profile value=\"urn:profile:in\"/></valueMeta></parameter></Parameters>",
extractBody(capt, idx));
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"meta\"/><valueMeta><profile value=\"urn:profile:in\"/></valueMeta></parameter></Parameters>", extractBody(capt, idx));
idx++;
}
@ -926,7 +927,8 @@ public class GenericClientDstu2Test {
Parameters outParams = client.operation().onInstance(new IdDt("Patient", "18066")).named("$everything").withParameters(inParams).execute();
/*
* Note that the $everything operation returns a Bundle instead of a Parameters resource. The client operation methods return a Parameters instance however, so HAPI creates a Parameters object
* Note that the $everything operation returns a Bundle instead of a Parameters resource. The client operation
* methods return a Parameters instance however, so HAPI creates a Parameters object
* with a single parameter containing the value.
*/
ca.uhn.fhir.model.dstu2.resource.Bundle responseBundle = (ca.uhn.fhir.model.dstu2.resource.Bundle) outParams.getParameter().get(0).getResource();
@ -1018,9 +1020,7 @@ public class GenericClientDstu2Test {
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"name1\"/><valueString value=\"value1\"/></parameter><parameter><name value=\"name2\"/><valueString value=\"value1\"/></parameter></Parameters>",
(extractBody(capt, idx)));
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"name1\"/><valueString value=\"value1\"/></parameter><parameter><name value=\"name2\"/><valueString value=\"value1\"/></parameter></Parameters>", (extractBody(capt, idx)));
idx++;
/*
@ -1041,8 +1041,7 @@ public class GenericClientDstu2Test {
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"name1\"/><valueIdentifier><system value=\"system1\"/><value value=\"value1\"/></valueIdentifier></parameter><parameter><name value=\"name2\"/><valueString value=\"value1\"/></parameter></Parameters>",
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"name1\"/><valueIdentifier><system value=\"system1\"/><value value=\"value1\"/></valueIdentifier></parameter><parameter><name value=\"name2\"/><valueString value=\"value1\"/></parameter></Parameters>",
(extractBody(capt, idx)));
idx++;
@ -1549,8 +1548,7 @@ public class GenericClientDstu2Test {
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(),
either(equalTo("http://example.com/fhir/Patient/123?_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient/123?_elements=identifier%2Cname")));
assertThat(capt.getValue().getURI().toString(), either(equalTo("http://example.com/fhir/Patient/123?_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient/123?_elements=identifier%2Cname")));
assertEquals(Patient.class, response.getClass());
}
@ -1762,12 +1760,93 @@ public class GenericClientDstu2Test {
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(),
either(equalTo("http://example.com/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient?name=james&_elements=identifier%2Cname")));
assertThat(capt.getValue().getURI().toString(), either(equalTo("http://example.com/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient?name=james&_elements=identifier%2Cname")));
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testSearchByPost() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.elementsSubset("name", "identifier")
.usingStyle(SearchStyleEnum.POST)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/_search?_elements=identifier%2Cname", capt.getValue().getURI().toString());
// assertThat(capt.getValue().getURI().toString(),
// either(equalTo("http://example.com/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient?name=james&_elements=identifier%2Cname")));
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
ourLog.info(Arrays.asList(capt.getValue().getAllHeaders()).toString());
ourLog.info(capt.getValue().toString());
HttpEntityEnclosingRequestBase v = (HttpEntityEnclosingRequestBase) capt.getValue();
String req = IOUtils.toString(v.getEntity().getContent(), "UTF-8");
assertEquals("name=james", req);
assertEquals("application/x-www-form-urlencoded;charset=utf-8", v.getEntity().getContentType().getValue().replace(" ", "").toLowerCase());
assertEquals(Constants.HEADER_ACCEPT_VALUE_XML_OR_JSON, capt.getValue().getFirstHeader("accept").getValue());
assertThat(capt.getValue().getFirstHeader("user-agent").getValue(), not(emptyString()));
}
@Test
public void testSearchByPostUseJson() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.elementsSubset("name", "identifier")
.usingStyle(SearchStyleEnum.POST)
.encodedJson()
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), containsString("http://example.com/fhir/Patient/_search?"));
assertThat(capt.getValue().getURI().toString(), containsString("_elements=identifier%2Cname"));
assertThat(capt.getValue().getURI().toString(), containsString("_format=json"));
// assertThat(capt.getValue().getURI().toString(),
// either(equalTo("http://example.com/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient?name=james&_elements=identifier%2Cname")));
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
ourLog.info(Arrays.asList(capt.getValue().getAllHeaders()).toString());
ourLog.info(capt.getValue().toString());
HttpEntityEnclosingRequestBase v = (HttpEntityEnclosingRequestBase) capt.getValue();
String req = IOUtils.toString(v.getEntity().getContent(), "UTF-8");
assertEquals("name=james", req);
assertEquals("application/x-www-form-urlencoded;charset=utf-8", v.getEntity().getContentType().getValue().replace(" ", "").toLowerCase());
assertEquals(Constants.CT_FHIR_JSON, capt.getValue().getFirstHeader("accept").getValue());
}
@Test
public void testSearchWithLastUpdated() throws Exception {
String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
@ -2207,9 +2286,7 @@ public class GenericClientDstu2Test {
response = client.validate().resource(p).execute();
assertEquals("http://example.com/fhir/Patient/$validate", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>",
extractBody(capt, idx));
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", extractBody(capt, idx));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;
@ -2217,9 +2294,7 @@ public class GenericClientDstu2Test {
response = client.validate().resource(ourCtx.newXmlParser().encodeResourceToString(p)).execute();
assertEquals("http://example.com/fhir/Patient/$validate?_format=xml", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>",
extractBody(capt, idx));
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", extractBody(capt, idx));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;
@ -2273,9 +2348,7 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/Patient/$validate", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>",
extractBody(capt, idx));
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", extractBody(capt, idx));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;

34
pom.xml
View File

@ -13,7 +13,7 @@
<packaging>pom</packaging>
<version>1.5-SNAPSHOT</version>
<name>HAPI-FHIR</name>
<url>http://jamesagnew.github.io/hapi-fhir/</url>
<url>https://github.com/jamesagnew/hapi-fhir</url>
<organization>
<name>University Health Network</name>
@ -240,20 +240,19 @@
<!-- Dependency Versions -->
<derby_version>10.12.1.1</derby_version>
<jersey_version>2.22.1</jersey_version>
<jersey_version>2.22.2</jersey_version>
<jetty_version>9.3.7.v20160115 </jetty_version>
<!-- Note on Hibernate versions: Hibernate 4.3+ uses JPA 2.1, which is too new for a number of platforms including JBoss EAP 6.x and Glassfish 3.0. Upgrade this version with caution! Also note that if
you change this, you may get a failure in hibernate4-maven-plugin. See the note in hapi-fhir-jpaserver-base/pom.xml's configuration for that plugin... -->
<hibernate_version>5.1.0.Final</hibernate_version>
<hibernate_validator_version>5.2.3.Final</hibernate_validator_version>
<hibernate_validator_version>5.2.4.Final</hibernate_validator_version>
<maven_assembly_plugin_version>2.5.3</maven_assembly_plugin_version>
<maven_license_plugin_version>1.8</maven_license_plugin_version>
<maven_site_plugin_version>3.4</maven_site_plugin_version>
<maven_source_plugin_version>2.4</maven_source_plugin_version>
<mitreid-connect-version>1.1.8</mitreid-connect-version>
<phloc_schematron_version>2.7.1</phloc_schematron_version>
<phloc_commons_version>4.4.4</phloc_commons_version>
<spring_version>4.2.4.RELEASE</spring_version>
<spring_version>4.2.5.RELEASE</spring_version>
<thymeleaf-version>2.1.4.RELEASE</thymeleaf-version>
<ebay_cors_filter_version>1.0.1</ebay_cors_filter_version>
<xmlunit_version>1.6</xmlunit_version>
@ -274,7 +273,7 @@
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.1.3</version>
<version>1.1.5</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
@ -744,7 +743,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<version>3.0</version>
<dependencies>
<dependency>
<groupId>org.codehaus.plexus</groupId>
@ -819,7 +818,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-site-plugin</artifactId>
<version>3.4</version>
<version>3.5</version>
<configuration>
<skip>false</skip>
<skipDeploy>true</skipDeploy>
@ -1299,6 +1298,25 @@
</execution>
</executions>
</plugin>
<!--
<plugin>
<groupId>com.github.github</groupId>
<artifactId>site-maven-plugin</artifactId>
<version>0.12</version>
<configuration>
<message>Building site for ${project.version}</message>
<server>github</server>
</configuration>
<executions>
<execution>
<goals>
<goal>site</goal>
</goals>
<phase>site-deploy</phase>
</execution>
</executions>
</plugin>
-->
</plugins>
</build>

View File

@ -13,6 +13,7 @@
<![CDATA[
<ul>
<li>Hibernate (JPA, Web Tester): 5.0.7 -&gt; 5.1.0</li>
<li>Spring (JPA, Web Tester): 4.2.4 -&gt; 4.2.5</li>
<li>SLF4j (All): 1.7.14 -&gt; 1.7.16</li>
</ul>
]]>
@ -305,7 +306,7 @@
<li>Logback (Core): 1.1.2 -&gt; 1.1.3</li>
<li>SLF4j (Core): 1.7.102 -&gt; 1.7.12</li>
<li>Springframework (JPA, Web Tester): 4.1.5 -&gt; 4.2.2</li>
<li>Hibernate (JPA, Web Tester): 4.2.17 -&gt; 5.0.3</li>
<li>Hibernate (JPA, Web Tester): 4.2.17 -&gt; 5."</li>
<li>Hibernate Validator (JPA, Web Tester): 5.2.1 -&gt; 5.2.2</li>
<li>Derby (JPA, CLI, Public Server): 10.11.1.1 -&gt; 10.12.1.1 </li>
<li>Jetty (JPA, CLI, Public Server): 9.2.6.v20141205 -&gt; 9.3.4.v20151007 </li>
@ -1879,8 +1880,12 @@
<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-04-12" description="This release corrects lots of bugs and introduces the fluent client mode">
</release>
</release>
<release version="0.3" date="2014-05-12" description="This release corrects lots of bugs and introduces the fluent client mode">
</release>
<release version="0.2" date="2014-04-23">
</release>
<release version="0.1" date="2014-04-15">
</release>
</body>
</document>

View File

@ -149,6 +149,10 @@
<item name="FindBugs" href="findbugs.html" />
<item name="Checkstyle" href="checkstyle.html" />
</menu>
<menu name="Contribute" inherit="bottom">
<item name="Guide to Hacking HAPI" href="./hacking_hapi_fhir.html"/>
</menu>
</body>
@ -193,7 +197,7 @@
<topNav>Documentation|Get Help|Test Server</topNav>
<bottomNav maxSpan="9" >
<column>HAPI FHIR|Test Server</column>
<column>Using HAPI</column>
<column>Using HAPI|Contribute</column>
<column>JavaDocs|JXR</column>
<column>Get Help|Maven Reports</column>
</bottomNav>

View File

@ -106,12 +106,14 @@
skip this section.
</p>
<p>
<b>Maven Import</b><br/>
Import the HAPI projects as Maven Modules by selecing
<code>File -&gt; Import...</code> from the File menu. Then select
<code>Existing Module Projects</code> as shown below.
</p>
<img src="./images/hacking_import.png"/><br/><br/>
<p>
<b>Select the Projects</b><br/>
Next, browse to the directory where you checked out the HAPI FHIR sources.
You might want to select only the projects you are interested in editing,
in order to keep Eclipse's memory use down. You can always come back and