Remove dependencies on StAX on Android
This commit is contained in:
parent
7c1ab11b02
commit
5a5933f232
|
@ -24,6 +24,7 @@ import ca.uhn.fhir.model.api.BasePrimitive;
|
|||
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
|
||||
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.util.XmlDetectionUtil;
|
||||
import ca.uhn.fhir.util.XmlUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -77,7 +78,7 @@ public class XhtmlDt extends BasePrimitive<String> {
|
|||
|
||||
@Override
|
||||
protected String parse(String theValue) {
|
||||
if (XmlUtil.isStaxPresent()) {
|
||||
if (XmlDetectionUtil.isStaxPresent()) {
|
||||
// for validation
|
||||
XmlUtil.parse(theValue);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
|
||||
public class XmlDetectionUtil {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(XmlDetectionUtil.class);
|
||||
private static Boolean ourStaxPresent;
|
||||
|
||||
/**
|
||||
* This method will return <code>true</code> if a StAX XML parsing library is present
|
||||
* on the classpath
|
||||
*/
|
||||
public static boolean isStaxPresent() {
|
||||
Boolean retVal = ourStaxPresent;
|
||||
if (retVal == null) {
|
||||
try {
|
||||
Class.forName("javax.xml.stream.events.XMLEvent");
|
||||
Class<?> xmlUtilClazz = Class.forName("ca.uhn.fhir.util.XmlUtil");
|
||||
xmlUtilClazz.getMethod("createXmlReader", Reader.class).invoke(xmlUtilClazz, new StringReader(""));
|
||||
ourStaxPresent = Boolean.TRUE;
|
||||
retVal = Boolean.TRUE;
|
||||
} catch (Throwable t) {
|
||||
ourLog.info("StAX not detected on classpath, XML processing will be disabled");
|
||||
ourStaxPresent = Boolean.FALSE;
|
||||
retVal = Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -46,15 +46,14 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
* This class contains code adapted from the Apache Axiom project.
|
||||
*/
|
||||
public class XmlUtil {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlUtil.class);
|
||||
private static final Map<String, Integer> VALID_ENTITY_NAMES;
|
||||
private static final ExtendedEntityReplacingXmlResolver XML_RESOLVER = new ExtendedEntityReplacingXmlResolver();
|
||||
private static XMLOutputFactory ourFragmentOutputFactory;
|
||||
private static volatile boolean ourHaveLoggedStaxImplementation;
|
||||
private static volatile XMLInputFactory ourInputFactory;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlUtil.class);
|
||||
private static Throwable ourNextException;
|
||||
private static volatile XMLOutputFactory ourOutputFactory;
|
||||
private static Boolean ourStaxPresent;
|
||||
private static final Map<String, Integer> VALID_ENTITY_NAMES;
|
||||
private static final ExtendedEntityReplacingXmlResolver XML_RESOLVER = new ExtendedEntityReplacingXmlResolver();
|
||||
|
||||
static {
|
||||
HashMap<String, Integer> validEntityNames = new HashMap<String, Integer>(1448);
|
||||
|
@ -1510,74 +1509,6 @@ public class XmlUtil {
|
|||
VALID_ENTITY_NAMES = Collections.unmodifiableMap(validEntityNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an XML string into a set of StAX events
|
||||
*/
|
||||
public static List<XMLEvent> parse(String theValue) {
|
||||
if (isBlank(theValue)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String val = theValue.trim();
|
||||
if (!val.startsWith("<")) {
|
||||
val = XhtmlDt.DIV_OPEN_FIRST + val + "</div>";
|
||||
}
|
||||
boolean hasProcessingInstruction = val.startsWith("<?");
|
||||
if (hasProcessingInstruction && val.endsWith("?>")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
ArrayList<XMLEvent> value = new ArrayList<>();
|
||||
StringReader reader = new StringReader(val);
|
||||
XMLEventReader er = XmlUtil.createXmlReader(reader);
|
||||
boolean first = true;
|
||||
while (er.hasNext()) {
|
||||
XMLEvent next = er.nextEvent();
|
||||
if (first) {
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
if (er.hasNext()) {
|
||||
// don't add the last event
|
||||
value.add(next);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("String does not appear to be valid XML/XHTML (error is \"" + e.getMessage() + "\"): " + theValue, e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a set of StAX events into a String
|
||||
*/
|
||||
public static String encode(List<XMLEvent> theEvents) {
|
||||
try {
|
||||
StringWriter w = new StringWriter();
|
||||
XMLEventWriter ew = XmlUtil.createXmlFragmentWriter(w);
|
||||
|
||||
for (XMLEvent next : theEvents) {
|
||||
if (next.isCharacters()) {
|
||||
ew.add(next);
|
||||
} else {
|
||||
ew.add(next);
|
||||
}
|
||||
}
|
||||
ew.close();
|
||||
return w.toString();
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("Problem with the contained XML events", e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static XMLOutputFactory createOutputFactory() throws FactoryConfigurationError {
|
||||
try {
|
||||
// Detect if we're running with the Android lib, and force repackaged Woodstox to be used
|
||||
|
@ -1638,6 +1569,30 @@ public class XmlUtil {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a set of StAX events into a String
|
||||
*/
|
||||
public static String encode(List<XMLEvent> theEvents) {
|
||||
try {
|
||||
StringWriter w = new StringWriter();
|
||||
XMLEventWriter ew = XmlUtil.createXmlFragmentWriter(w);
|
||||
|
||||
for (XMLEvent next : theEvents) {
|
||||
if (next.isCharacters()) {
|
||||
ew.add(next);
|
||||
} else {
|
||||
ew.add(next);
|
||||
}
|
||||
}
|
||||
ew.close();
|
||||
return w.toString();
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("Problem with the contained XML events", e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static XMLOutputFactory getOrCreateFragmentOutputFactory() throws FactoryConfigurationError {
|
||||
XMLOutputFactory retVal = ourFragmentOutputFactory;
|
||||
if (retVal == null) {
|
||||
|
@ -1723,6 +1678,7 @@ public class XmlUtil {
|
|||
return ourOutputFactory;
|
||||
}
|
||||
|
||||
|
||||
private static void logStaxImplementation(Class<?> theClass) {
|
||||
IDependencyLog logger = DependencyLogFactory.createJarLogger();
|
||||
if (logger != null) {
|
||||
|
@ -1754,6 +1710,49 @@ public class XmlUtil {
|
|||
return outputFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an XML string into a set of StAX events
|
||||
*/
|
||||
public static List<XMLEvent> parse(String theValue) {
|
||||
if (isBlank(theValue)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
String val = theValue.trim();
|
||||
if (!val.startsWith("<")) {
|
||||
val = XhtmlDt.DIV_OPEN_FIRST + val + "</div>";
|
||||
}
|
||||
boolean hasProcessingInstruction = val.startsWith("<?");
|
||||
if (hasProcessingInstruction && val.endsWith("?>")) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
ArrayList<XMLEvent> value = new ArrayList<>();
|
||||
StringReader reader = new StringReader(val);
|
||||
XMLEventReader er = XmlUtil.createXmlReader(reader);
|
||||
boolean first = true;
|
||||
while (er.hasNext()) {
|
||||
XMLEvent next = er.nextEvent();
|
||||
if (first) {
|
||||
first = false;
|
||||
continue;
|
||||
}
|
||||
if (er.hasNext()) {
|
||||
// don't add the last event
|
||||
value.add(next);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("String does not appear to be valid XML/XHTML (error is \"" + e.getMessage() + "\"): " + theValue, e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FOR UNIT TESTS ONLY - Throw this exception for the next operation
|
||||
*/
|
||||
|
@ -1783,26 +1782,6 @@ public class XmlUtil {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method will return <code>true</code> if a StAX XML parsing library is present
|
||||
* on the classpath
|
||||
*/
|
||||
public static boolean isStaxPresent() {
|
||||
Boolean retVal = ourStaxPresent;
|
||||
if (retVal == null) {
|
||||
try {
|
||||
newInputFactory();
|
||||
ourStaxPresent = Boolean.TRUE;
|
||||
retVal = Boolean.TRUE;
|
||||
} catch (ConfigurationException e) {
|
||||
ourLog.info("StAX not detected on classpath, XML processing will be disabled");
|
||||
ourStaxPresent = Boolean.FALSE;
|
||||
retVal = Boolean.FALSE;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static class MyEscaper implements EscapingWriterFactory {
|
||||
|
||||
@Override
|
||||
|
|
|
@ -35,6 +35,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||
import ca.uhn.fhir.util.XmlDetectionUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
@ -110,7 +111,7 @@ public abstract class BaseClient implements IRestfulClient {
|
|||
setKeepResponses(true);
|
||||
}
|
||||
|
||||
if (XmlUtil.isStaxPresent() == false) {
|
||||
if (XmlDetectionUtil.isStaxPresent() == false) {
|
||||
myEncoding = EncodingEnum.JSON;
|
||||
}
|
||||
|
||||
|
|
|
@ -576,11 +576,11 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
} catch (InterruptedException theE) {
|
||||
// ignore
|
||||
}
|
||||
} else {
|
||||
ourLog.info("Proceeding, as we have {} results", mySyncedPids.size());
|
||||
}
|
||||
} while (keepWaiting);
|
||||
|
||||
ourLog.info("Proceeding, as we have {} results", mySyncedPids.size());
|
||||
|
||||
ArrayList<Long> retVal = new ArrayList<>();
|
||||
synchronized (mySyncedPids) {
|
||||
verifySearchHasntFailedOrThrowInternalErrorException(mySearch);
|
||||
|
@ -594,6 +594,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
|||
}
|
||||
}
|
||||
|
||||
ourLog.info("Done syncing results", mySyncedPids.size());
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
|
|
@ -189,6 +189,7 @@ public class EmailSubscriptionDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(subscriptionTemp));
|
||||
|
||||
|
||||
ourClient.update().resource(subscriptionTemp).withId(subscriptionTemp.getIdElement()).execute();
|
||||
waitForQueueToDrain();
|
||||
|
||||
|
|
|
@ -26,7 +26,11 @@
|
|||
<![CDATA[<br/><br/>]]>
|
||||
See the
|
||||
<![CDATA[<a href="http://hapifhir.io/doc_android.html">HAPI FHIR Android Documentation</a>]]>
|
||||
for more information.
|
||||
for more information. As a part of this fix, all dependencies on
|
||||
the StAX API have been removed in environments where StAX is not
|
||||
present (such as Android). The client will now detect this case, and
|
||||
explicitly request JSON payloads from servers, meaning that Android clients
|
||||
no longer need to include two parser stacks
|
||||
</action>
|
||||
<action type="add">
|
||||
A performance to the JPA server has been made which reduces the number
|
||||
|
|
Loading…
Reference in New Issue