Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,7 @@ private String makeJSONCombinedQuery(CombinedQueryDefinitionImpl qdef) {
}

private XMLStreamWriter makeXMLSerializer(OutputStream out) {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
XMLOutputFactory factory = XmlFactories.getOutputFactory();

try {
XMLStreamWriter serializer = factory.createXMLStreamWriter(out, "UTF-8");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1053,8 +1053,7 @@ public PatchHandle build() throws MarkLogicIOException {
} else {
handle.setFormat(Format.XML);
try {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
factory.setProperty("javax.xml.stream.isRepairingNamespaces", true);
XMLOutputFactory factory = XmlFactories.getOutputFactory();

StringWriter writer = new StringWriter();
XMLStreamWriter serializer = factory.createXMLStreamWriter(writer);
Expand Down
3 changes: 1 addition & 2 deletions src/main/java/com/marklogic/client/impl/Utilities.java
Original file line number Diff line number Diff line change
Expand Up @@ -334,8 +334,7 @@ public static boolean writeEvents(List<XMLEvent> events, OutputStream out) {
}

try {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
factory.setProperty("javax.xml.stream.isRepairingNamespaces", true);
XMLOutputFactory factory = XmlFactories.getOutputFactory();

XMLEventWriter eventWriter = factory.createXMLEventWriter(out, "UTF-8");

Expand Down
152 changes: 152 additions & 0 deletions src/main/java/com/marklogic/client/impl/XmlFactories.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright 2012-2016 MarkLogic Corporation
*
* 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.
*/
package com.marklogic.client.impl;

import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLOutputFactory;
import java.lang.ref.SoftReference;

public final class XmlFactories {

private static final CachedInstancePerThreadSupplier<XMLOutputFactory> cachedOutputFactory =
new CachedInstancePerThreadSupplier<XMLOutputFactory>(new Supplier<XMLOutputFactory>() {
@Override
public XMLOutputFactory get() {
return makeNewOutputFactory();
}
});

private XmlFactories() {
// preventing instances of utility class
}

/**
* Returns a new {@link XMLOutputFactory}. This factory will have its
* {@link XMLOutputFactory#IS_REPAIRING_NAMESPACES} property set to {@code true}.
* <p>
* CAUTION: Creating XML factories is potentially a pretty expensive operation. If possible, consider using a shared
* instance ({@link #getOutputFactory()}) to amortize this initialization cost via reuse.
*
* @return a namespace-repairing {@link XMLOutputFactory}
*
* @throws FactoryConfigurationError see {@link XMLOutputFactory#newInstance()}
*
* @see #getOutputFactory()
*/
public static XMLOutputFactory makeNewOutputFactory() {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
return factory;
}

/**
* Returns a shared {@link XMLOutputFactory}. This factory will have its
* {@link XMLOutputFactory#IS_REPAIRING_NAMESPACES} property set to {@code true}.
* <p>
* Creating XML factories is potentially a pretty expensive operation. Using a shared instance helps to amortize
* this initialization cost via reuse.
*
* @return a namespace-repairing {@link XMLOutputFactory}
*
* @throws FactoryConfigurationError see {@link XMLOutputFactory#newInstance()}
*
* @see #makeNewOutputFactory() if you really (really?) need an non-shared instance
*/
public static XMLOutputFactory getOutputFactory() {
return cachedOutputFactory.get();
}

/**
* Represents a supplier of results.
*
* <p>There is no requirement that a new or distinct result be returned each
* time the supplier is invoked.
*
* @param <T> the type of results supplied by this supplier
*/
// TODO replace with java.util.function.Supplier<T> after Java 8 migration
interface Supplier<T> {

/**
* Gets a result.
*
* @return a result
*/
T get();
}

/**
* A supplier that caches results per thread.
* <p>
* The supplier is thread safe.
* <p>
* Upon first invocation from a certain thread it is guaranteed to invoke the {@code supplier}'s {@code get()}
* method to obtain a thread-specific result.
* <p>
* Cached values are wrapped in a {@link java.lang.ref.SoftReference} to allow them to be garbage collected upon low
* memory. This may lead to multiple calls to the {@code delegate}'s {@code get()} method over the lifetime of a
* certain thread if a previous result was cleared due to low memory.
*
* @param <T> the supplier's value type
*/
private static class CachedInstancePerThreadSupplier<T> implements Supplier<T> {

private final ThreadLocal<SoftReference<T>> cachedInstances = new ThreadLocal<SoftReference<T>>();

/**
* The underlying supplier, invoked to originally retrieve the per-thread result
*/
private final Supplier<T> delegate;

CachedInstancePerThreadSupplier(Supplier<T> delegate) {
this.delegate = delegate;

if (null == delegate) {
throw new NullPointerException("Delegate must not be null");
}
}

/**
* Returns the thread-specific instance, possibly creating a new one if there is none exists.
*
* @return a thread specific instance of {@code <T>}. Never {@literal null}.
*/
@Override
public T get() {

SoftReference<T> cachedInstanceReference = cachedInstances.get();

// careful, either the reference itself may be null (upon first access from a thread), or the referred-to
// instance may be null (after a GC run that cleared it out)
T cachedInstance = (null != cachedInstanceReference) ? cachedInstanceReference.get() : null;

if (null == cachedInstance) {
// no instance for the current thread, create a new one ...
cachedInstance = delegate.get();
if (null == cachedInstance) {
throw new NullPointerException("Must not return null from " + delegate.getClass().getName()
+ "::get() (" + delegate + ")");
}

// ... and retain it for later re-use
cachedInstances.set(new SoftReference<T>(cachedInstance));
}

return cachedInstance;
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
import com.marklogic.client.impl.ClientPropertiesImpl;
import com.marklogic.client.impl.DOMWriter;
import com.marklogic.client.impl.ValueConverter;
import com.marklogic.client.impl.XmlFactories;
import com.marklogic.client.io.marker.BufferableHandle;
import com.marklogic.client.io.marker.DocumentMetadataReadHandle;
import com.marklogic.client.io.marker.DocumentMetadataWriteHandle;
Expand Down Expand Up @@ -656,8 +657,7 @@ private void receiveQualityImpl(Document document) {
// TODO: select the metadata sent
private void sendMetadataImpl(OutputStream out) {
try {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
factory.setProperty("javax.xml.stream.isRepairingNamespaces", true);
XMLOutputFactory factory = XmlFactories.getOutputFactory();

valueSerializer = null;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import com.marklogic.client.MarkLogicIOException;
import com.marklogic.client.impl.AbstractQueryDefinition;
import com.marklogic.client.impl.RawQueryDefinitionImpl;
import com.marklogic.client.impl.XmlFactories;
import com.marklogic.client.io.BaseHandle;
import com.marklogic.client.io.Format;
import com.marklogic.client.io.OutputStreamSender;
Expand Down Expand Up @@ -2443,8 +2444,7 @@ private void checkRegion(Region region) {
}

static private XMLStreamWriter makeSerializer(OutputStream out) {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
XMLOutputFactory factory = XmlFactories.getOutputFactory();

try {
XMLStreamWriter serializer = factory.createXMLStreamWriter(out, "UTF-8");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@

import com.marklogic.client.impl.CombinedQueryBuilderImpl;
import com.marklogic.client.impl.CombinedQueryDefinition;
import com.marklogic.client.impl.XmlFactories;
import com.marklogic.client.io.Format;
import com.marklogic.client.io.StringHandle;
import com.marklogic.client.io.marker.QueryOptionsWriteHandle;
Expand Down Expand Up @@ -124,8 +125,7 @@ public void writeOptions(XMLStreamWriter writer) throws XMLStreamException {
}

public XMLStreamWriter makeXMLStreamWriter(OutputStream out) throws XMLStreamException {
XMLOutputFactory factory = XMLOutputFactory.newInstance();
factory.setProperty(XMLOutputFactory.IS_REPAIRING_NAMESPACES, true);
XMLOutputFactory factory = XmlFactories.getOutputFactory();

XMLStreamWriter writer = factory.createXMLStreamWriter(out, "UTF-8");
writer.setDefaultNamespace("http://marklogic.com/appservices/search");
Expand Down