Author: desruisseaux
Date: Tue Dec 25 17:42:05 2012
New Revision: 1425760
URL: http://svn.apache.org/viewvc?rev=1425760&view=rev
Log:
Initial port of MarshallerPool. Still needs a bit of work before being usable.
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/AdapterReplacement.java
(with props)
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
(with props)
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/AdapterReplacement.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/AdapterReplacement.java?rev=1425760&view=auto
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/AdapterReplacement.java
(added)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/AdapterReplacement.java
Tue Dec 25 17:42:05 2012
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.sis.internal.jaxb;
+
+import java.util.ServiceLoader;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.annotation.adapters.XmlAdapter;
+
+
+/**
+ * An interface for {@link XmlAdapter} to be used in replacement of the
instance created by JAXB.
+ * This interface provides a way to replace <cite>default</cite> adapters by
<cite>configured</cite>
+ * ones. It does not allow the addition of new adapters (i.e. it can not be
used in replacement of
+ * the {@link javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter}
annotation).
+ *
+ * <p>This interface is mostly for handling extensions to metadata profile
provided as extension,
+ * like the {@code FRA} extension for France provided in the {@code
sis-metadata-fra} module.</p>
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.00)
+ * @version 0.3
+ * @module
+ *
+ * @see Marshaller#setAdapter(XmlAdapter)
+ * @see Unmarshaller#setAdapter(XmlAdapter)
+ */
+public interface AdapterReplacement {
+ /**
+ * The system-wide provider of {@code AdapterReplacement} instances.
+ * <strong>Every usage of this service loader must be
synchronized.</strong>
+ * This loader is public for allowing modules to unregister their instance
+ * when the module is unloaded (e.g. from an OSGi container), as below:
+ *
+ * {@preformat java
+ * synchronized (AdapterReplacement.PROVIDER) {
+ * AdapterReplacement.PROVIDER.reload();
+ * }
+ * }
+ */
+ ServiceLoader<AdapterReplacement> PROVIDER =
ServiceLoader.load(AdapterReplacement.class);
+
+ /**
+ * Invoked when a new adapter is created by {@link
org.apache.sis.xml.MarshallerPool}.
+ * Typical implementations will be as below:
+ *
+ * {@preformat java
+ * marshaller.setAdapter(MyParent.class, this);
+ * }
+ *
+ * @param marshaller The marshaller to be configured.
+ * @throws JAXBException If the given marshaller can not be configured.
+ */
+ void register(Marshaller marshaller) throws JAXBException;
+
+ /**
+ * Invoked when a new adapter is created by {@link
org.apache.sis.xml.MarshallerPool}.
+ * Typical implementations will be as below:
+ *
+ * {@preformat java
+ * unmarshaller.setAdapter(MyParent.class, this);
+ * }
+ *
+ * @param unmarshaller The unmarshaller to be configured.
+ * @throws JAXBException If the given unmarshaller can not be configured.
+ */
+ void register(Unmarshaller unmarshaller) throws JAXBException;
+}
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/AdapterReplacement.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/AdapterReplacement.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java?rev=1425760&view=auto
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
(added)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
Tue Dec 25 17:42:05 2012
@@ -0,0 +1,332 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.sis.xml;
+
+import java.util.Map;
+import java.util.Deque;
+import java.util.LinkedList;
+import java.util.Collections;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import net.jcip.annotations.ThreadSafe;
+import org.apache.sis.util.logging.Logging;
+import org.apache.sis.internal.jaxb.AdapterReplacement;
+
+
+/**
+ * Creates and configures {@link Marshaller} or {@link Unmarshaller} objects
for use with SIS.
+ * Users fetch (un)marshallers by calls to the {@link #acquireMarshaller()} or
+ * {@link #acquireUnmarshaller()} methods, and can restitute the
(un)marshaller to the pool
+ * after usage like below:
+ *
+ * {@preformat java
+ * Marshaller marshaller = pool.acquireMarshaller();
+ * marshaller.marchall(...);
+ * pool.release(marshaller);
+ * }
+ *
+ * {@section Configuring (un)marshallers}
+ * The (un)marshallers created by this class can optionally by configured with
the SIS-specific
+ * properties defined in the {@link XML} class, in addition to JAXB standard
properties.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.00)
+ * @version 0.3
+ * @module
+ *
+ * @see XML
+ *
+ * @todo Need a timeout for disposing marshallers that have been unused for a
while.
+ */
+@ThreadSafe
+public class MarshallerPool {
+ /**
+ * Maximal amount of marshallers and unmarshallers to keep.
+ */
+ private static final int CAPACITY = 16;
+
+ /**
+ * The key to be used in the map given to the constructors for specifying
the root namespace.
+ * An example of value for this key is {@code
"http://www.isotc211.org/2005/gmd"}.
+ */
+ public static final String ROOT_NAMESPACE_KEY =
"org.apache.sis.xml.rootNamespace";
+
+ /**
+ * The JAXB context to use for creating marshaller and unmarshaller.
+ */
+ private final JAXBContext context;
+
+ /**
+ * {@code true} if the JAXB implementation is the one bundled in JDK 6,
+ * or {@code false} if this is an external implementation like a JAR put
+ * in the endorsed directory.
+ */
+ private final boolean internal;
+
+ /**
+ * The mapper between namespaces and prefix.
+ */
+ private final Object mapper;
+
+ /**
+ * The pool of marshaller. This pool is initially empty
+ * and will be filled with elements as needed.
+ */
+ private final Deque<Marshaller> marshallers = new LinkedList<>();
+
+ /**
+ * The pool of unmarshaller. This pool is initially empty
+ * and will be filled with elements as needed.
+ */
+ private final Deque<Unmarshaller> unmarshallers = new LinkedList<>();
+
+ /**
+ * Creates a new factory for the given class to be bound, with a default
empty namespace.
+ *
+ * @param classesToBeBound The classes to be bound, for example {@code
DefaultMetadata.class}.
+ * @throws JAXBException If the JAXB context can not be created.
+ */
+ public MarshallerPool(final Class<?>... classesToBeBound) throws
JAXBException {
+ this(Collections.<String,String>emptyMap(), classesToBeBound);
+ }
+
+ /**
+ * Creates a new factory for the given class to be bound. The keys in the
{@code properties} map
+ * shall be one or many of the constants defined in this class like {@link
#ROOT_NAMESPACE_KEY}.
+ *
+ * @param properties The set of properties to be given to the pool.
+ * @param classesToBeBound The classes to be bound, for example {@code
DefaultMetadata.class}.
+ * @throws JAXBException If the JAXB context can not be created.
+ */
+ public MarshallerPool(final Map<String,String> properties, final
Class<?>... classesToBeBound) throws JAXBException {
+ this(properties, JAXBContext.newInstance(classesToBeBound));
+ }
+
+ /**
+ * Creates a new factory for the given packages, with a default empty
namespace.
+ * The separator character for the packages is the colon.
+ *
+ * @param packages The packages in which JAXB will search for
annotated classes to be bound,
+ * for example {@code
"org.apache.sis.metadata.iso:org.apache.sis.metadata.iso.citation"}.
+ * @throws JAXBException If the JAXB context can not be created.
+ */
+ public MarshallerPool(final String packages) throws JAXBException {
+ this(Collections.<String,String>emptyMap(), packages);
+ }
+
+ /**
+ * Creates a new factory for the given packages. The separator character
for the packages is the
+ * colon. The keys in the {@code properties} map shall be one or many of
the constants defined
+ * in this class like {@link #ROOT_NAMESPACE_KEY}.
+ *
+ * @param properties The set of properties to be given to the pool.
+ * @param packages The packages in which JAXB will search for
annotated classes to be bound,
+ * for example {@code
"org.apache.sis.metadata.iso:org.apache.sis.metadata.iso.citation"}.
+ * @throws JAXBException If the JAXB context can not be created.
+ */
+ public MarshallerPool(final Map<String,String> properties, final String
packages) throws JAXBException {
+ this(properties, JAXBContext.newInstance(packages));
+ }
+
+ /**
+ * Creates a new factory for the given packages.
+ *
+ * @param properties The set of properties to be given to the pool.
+ * @param context The JAXB context.
+ * @throws JAXBException If the OGC namespace prefix mapper can not be
created.
+ */
+ @SuppressWarnings({"unchecked", "rawtypes"}) // Generic array creation
+ private MarshallerPool(final Map<String,String> properties, final
JAXBContext context) throws JAXBException {
+ this.context = context;
+ String rootNamespace = properties.get(ROOT_NAMESPACE_KEY);
+ if (rootNamespace == null) {
+ rootNamespace = "";
+ }
+ /*
+ * Detects if we are using the endorsed JAXB implementation (i.e. the
one provided in
+ * separated JAR files). If not, we will assume that we are using the
implementation
+ * bundled in JDK 6. We use the JAXB context package name as a
criterion.
+ *
+ * JAXB endorsed JAR uses "com.sun.xml.bind"
+ * JAXB bundled in JDK uses "com.sun.xml.internal.bind"
+ */
+ internal =
!context.getClass().getName().startsWith("com.sun.xml.bind");
+ String type = "org.apache.sis.xml.OGCNamespacePrefixMapper_Endorsed";
+ if (internal) {
+ type = type.substring(0, type.lastIndexOf('_'));
+ }
+ /*
+ * Instantiates the OGCNamespacePrefixMapper appropriate for the
implementation
+ * we just detected.
+ */
+ try {
+ mapper =
Class.forName(type).getConstructor(String.class).newInstance(rootNamespace);
+ } catch (ReflectiveOperationException | NoClassDefFoundError
exception) {
+ // The NoClassDefFoundError is because of our trick using
"geotk-provided".
+ throw new JAXBException("Unsupported JAXB implementation.",
exception);
+ }
+ }
+
+ /**
+ * Returns the marshaller or unmarshaller to use from the given queue.
+ * If the queue is empty, returns {@code null}.
+ */
+ private static <T> T acquire(final Deque<T> queue) {
+ synchronized (queue) {
+ return queue.pollLast();
+ }
+ }
+
+ /**
+ * Marks the given marshaller or unmarshaller available for further reuse.
+ */
+ private static <T> void release(final Deque<T> queue, final T marshaller) {
+ try {
+ ((Pooled) marshaller).reset();
+ } catch (JAXBException exception) {
+ // Not expected to happen because the we are supposed
+ // to reset the properties to their initial values.
+ Logging.unexpectedException(MarshallerPool.class, "release",
exception);
+ return;
+ }
+ synchronized (queue) {
+ queue.addLast(marshaller);
+ while (queue.size() > CAPACITY) {
+ // Remove the least recently used marshallers.
+ queue.removeFirst();
+ }
+ }
+ }
+
+ /**
+ * Returns a JAXB marshaller from the pool. If there is no marshaller
currently available
+ * in the pool, then this method will {@linkplain #createMarshaller
create} a new one.
+ *
+ * <p>This method shall be used as below:</p>
+ *
+ * {@preformat java
+ * Marshaller marshaller = pool.acquireMarshaller();
+ * marshaller.marchall(...);
+ * pool.release(marshaller);
+ * }
+ *
+ * Note that this is not strictly required to release the marshaller in a
{@code finally}
+ * block. Actually it is safer to let the garbage collector disposes the
marshaller if an
+ * error occurred while marshalling the object.
+ *
+ * @return A marshaller configured for formatting OGC/ISO XML.
+ * @throws JAXBException If an error occurred while creating and
configuring a marshaller.
+ */
+ public Marshaller acquireMarshaller() throws JAXBException {
+ Marshaller marshaller = acquire(marshallers);
+ if (marshaller == null) {
+ marshaller = new PooledMarshaller(createMarshaller(), internal);
+ }
+ return marshaller;
+ }
+
+ /**
+ * Returns a JAXB unmarshaller from the pool. If there is no unmarshaller
currently available
+ * in the pool, then this method will {@linkplain #createUnmarshaller
create} a new one.
+ *
+ * <p>This method shall be used as below:</p>
+ *
+ * {@preformat java
+ * Unmarshaller unmarshaller = pool.acquireUnmarshaller();
+ * Unmarshaller.unmarchall(...);
+ * pool.release(unmarshaller);
+ * }
+ *
+ * Note that this is not strictly required to release the unmarshaller in
a {@code finally}
+ * block. Actually it is safer to let the garbage collector disposes the
unmarshaller if an
+ * error occurred while unmarshalling the object.
+ *
+ * @return A unmarshaller configured for parsing OGC/ISO XML.
+ * @throws JAXBException If an error occurred while creating and
configuring the unmarshaller.
+ */
+ public Unmarshaller acquireUnmarshaller() throws JAXBException {
+ Unmarshaller unmarshaller = acquire(unmarshallers);
+ if (unmarshaller == null) {
+ unmarshaller = new PooledUnmarshaller(createUnmarshaller(),
internal);
+ }
+ return unmarshaller;
+ }
+
+ /**
+ * Declares a marshaller as available for reuse. The caller should not use
+ * anymore the marshaller after this method call.
+ *
+ * @param marshaller The marshaller to return to the pool.
+ */
+ public void release(final Marshaller marshaller) {
+ release(marshallers, marshaller);
+ }
+
+ /**
+ * Declares a unmarshaller as available for reuse. The caller should not
use
+ * anymore the unmarshaller after this method call.
+ *
+ * @param unmarshaller The unmarshaller to return to the pool.
+ */
+ public void release(final Unmarshaller unmarshaller) {
+ release(unmarshallers, unmarshaller);
+ }
+
+ /**
+ * Creates an configure a new JAXB marshaller.
+ * This method is invoked only when no existing marshaller is available in
the pool.
+ * Subclasses can override this method if they need to change the
marshaller configuration.
+ *
+ * @return A new marshaller configured for formatting OGC/ISO XML.
+ * @throws JAXBException If an error occurred while creating and
configuring the marshaller.
+ */
+ protected Marshaller createMarshaller() throws JAXBException {
+ final String mapperKey = internal ?
+ "com.sun.xml.internal.bind.namespacePrefixMapper" :
+ "com.sun.xml.bind.namespacePrefixMapper";
+ final Marshaller marshaller = context.createMarshaller();
+ marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
+ marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
+ marshaller.setProperty(mapperKey, mapper);
+ synchronized (AdapterReplacement.PROVIDER) {
+ for (final AdapterReplacement adapter :
AdapterReplacement.PROVIDER) {
+ adapter.register(marshaller);
+ }
+ }
+ return marshaller;
+ }
+
+ /**
+ * Creates an configure a new JAXB unmarshaller.
+ * This method is invoked only when no existing unmarshaller is available
in the pool.
+ * Subclasses can override this method if they need to change the
unmarshaller configuration.
+ *
+ * @return A new unmarshaller configured for parsing OGC/ISO XML.
+ * @throws JAXBException If an error occurred while creating and
configuring the unmarshaller.
+ */
+ protected Unmarshaller createUnmarshaller() throws JAXBException {
+ final Unmarshaller unmarshaller = context.createUnmarshaller();
+ synchronized (AdapterReplacement.PROVIDER) {
+ for (final AdapterReplacement adapter :
AdapterReplacement.PROVIDER) {
+ adapter.register(unmarshaller);
+ }
+ }
+ return unmarshaller;
+ }
+}
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/MarshallerPool.java
------------------------------------------------------------------------------
svn:mime-type = text/plain