001 /*
002 * Java GPX Library (jpx-3.1.0).
003 * Copyright (c) 2016-2023 Franz Wilhelmstötter
004 *
005 * Licensed under the Apache License, Version 2.0 (the "License");
006 * you may not use this file except in compliance with the License.
007 * You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 *
017 * Author:
018 * Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019 * Antoine Vianey (https://github.com/avianey)
020 */
021 package io.jenetics.jpx;
022
023 import java.util.Iterator;
024 import java.util.ServiceLoader;
025
026 import javax.xml.parsers.DocumentBuilderFactory;
027 import javax.xml.stream.XMLInputFactory;
028 import javax.xml.stream.XMLOutputFactory;
029
030 /**
031 * A {@link ServiceLoader} for managing XML factories used by the library.
032 * Custom implementation should be referenced in a
033 * {@code META-INF/services/io.jenetics.jpx.XMLProvider} file.
034 *
035 * @see ServiceLoader
036 *
037 * @version 1.7
038 * @since 1.7
039 */
040 public abstract class XMLProvider {
041
042 private static final Object LOCK = new Object(){};
043
044 private static volatile XMLProvider INSTANCE;
045
046 protected XMLProvider() {
047 }
048
049 /**
050 * Returns {@link XMLInputFactory} to be used for reading files.
051 *
052 * @return the xml input factory
053 */
054 public XMLInputFactory xmlInputFactory() {
055 return XMLInputFactory.newInstance();
056 }
057
058 /**
059 * Returns {@link XMLOutputFactory} to be used for writing files.
060 *
061 * @return the xml output factory
062 */
063 public XMLOutputFactory xmlOutputFactory() {
064 return XMLOutputFactory.newInstance();
065 }
066
067 /**
068 * Returns the {@link DocumentBuilderFactory} used for handling extensions documents
069 *
070 * @return the document builder factory
071 */
072 public DocumentBuilderFactory documentBuilderFactory() {
073 final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
074 factory.setIgnoringElementContentWhitespace(true);
075 factory.setNamespaceAware(true);
076 return factory;
077 }
078
079 /**
080 * Return an instance of the current {@code XMLProvider}.
081 *
082 * @return an instance of the current {@code XMLProvider}
083 */
084 public static XMLProvider provider() {
085 if (INSTANCE == null) {
086 synchronized (LOCK) {
087 if (INSTANCE == null) {
088 loadInstance();
089 }
090 }
091 }
092 return INSTANCE;
093 }
094
095 /**
096 * Clear current spi to allow hot reloading a new one...
097 */
098 protected static void clear() {
099 if (INSTANCE != null) {
100 synchronized (LOCK) {
101 if (INSTANCE != null) {
102 INSTANCE = null;
103 }
104 }
105 }
106 }
107
108 private static void loadInstance() {
109 final ServiceLoader<XMLProvider> loader =
110 ServiceLoader.load(XMLProvider.class);
111
112 final Iterator<XMLProvider> providers = loader.iterator();
113 if (providers.hasNext()) {
114 INSTANCE = providers.next();
115 } else {
116 INSTANCE = new DefaultXMLProvider();
117 }
118 }
119
120 }
121
122 /**
123 * Default implementation of the {@code XMLProvider} class. Doesn't need any
124 * additional implementation.
125 */
126 final class DefaultXMLProvider extends XMLProvider { }
|