Author: desruisseaux
Date: Wed Jan 9 07:56:50 2013
New Revision: 1430722
URL: http://svn.apache.org/viewvc?rev=1430722&view=rev
Log:
Ported the XML.(un)marshall methods, after the addition of a hook for
recreating the pool if the classpath changes.
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
(with props)
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SystemListener.java
(with props)
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/XML.java
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java?rev=1430722&view=auto
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
(added)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
Wed Jan 9 07:56:50 2013
@@ -0,0 +1,80 @@
+/*
+ * 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.ArrayList;
+import java.util.Collection;
+import java.util.ServiceLoader;
+
+
+/**
+ * Declares the classes of objects to be marshalled using a default {@code
MarshallerPool}.
+ * This class is not strictly necessary for marshalling a SIS object using
JAXB, but makes
+ * the job easier by allowing {@code MarshallerPool} to configure the JAXB
context automatically.
+ * To allow such automatic configuration, modules must declare instances of
this interface in the
+ * following file:
+ *
+ * {@preformat text
+ * META-INF/services/org.org.apache.sis.internal.jaxb.TypeRegistration
+ * }
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3 (derived from geotk-3.00)
+ * @version 0.3
+ * @module
+ *
+ * @see org.apache.sis.xml.MarshallerPool
+ */
+public abstract class TypeRegistration {
+ /**
+ * For subclasses constructors.
+ */
+ protected TypeRegistration() {
+ }
+
+ /**
+ * Adds to the given collection every types that should be given to
+ * the initial JAXB context.
+ *
+ * @param addTo The collection in which to add new types.
+ */
+ public abstract void getTypes(final Collection<Class<?>> addTo);
+
+ /**
+ * Returns the root classes of SIS objects to be marshalled by default.
+ * Those classes can be given as the last argument to the {@code
MarshallerPool}
+ * constructors, in order to bound a default set of classes with {@code
JAXBContext}.
+ *
+ * <p>The list of classes is determined dynamically from the SIS modules
found on
+ * the classpath.</p>
+ *
+ * @return The default set of classes to be bound to the {@code
JAXBContext}.
+ */
+ public static Class<?>[] defaultClassesToBeBound() {
+ /*
+ * Implementation note: do not keep the ServiceLoader in static field
because:
+ *
+ * 1) It would cache the RegsterableTypes instances, which are not
needed after this method call.
+ * 2) The ClassLoader between different invocations may be different
in an OSGi context.
+ */
+ final ArrayList<Class<?>> types = new ArrayList<>();
+ for (final TypeRegistration t :
ServiceLoader.load(TypeRegistration.class)) {
+ t.getTypes(types);
+ }
+ return types.toArray(new Class<?>[types.size()]);
+ }
+}
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/jaxb/TypeRegistration.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Added:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SystemListener.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SystemListener.java?rev=1430722&view=auto
==============================================================================
---
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SystemListener.java
(added)
+++
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SystemListener.java
Wed Jan 9 07:56:50 2013
@@ -0,0 +1,105 @@
+/*
+ * 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.util;
+
+import java.util.EventListener;
+import org.apache.sis.util.Arrays;
+
+import static java.util.Arrays.copyOf;
+
+
+/**
+ * Listeners for changes in the Apache SIS system. This listener is used only
for rare events,
+ * like OSGi module loaded or unloaded. We use this class instead of OSGi
listeners in order
+ * to keep the SIS library OSGi-independent.
+ *
+ * @author Martin Desruisseaux (Geomatys)
+ * @since 0.3
+ * @version 0.3
+ * @module
+ */
+public abstract class SystemListener implements EventListener {
+ /**
+ * The listeners, or {@code null} if none.
+ */
+ private static SystemListener[] listeners;
+
+ /**
+ * Adds the given listener to the list of listeners to notify when a
change occurs.
+ * This method doesn't check if the given listener is already present in
the array,
+ * unless assertions are enabled.
+ *
+ * @param listener The listener to add. Can not be {@code null}.
+ */
+ public static synchronized void add(final SystemListener listener) {
+ assert (listener != null) && !Arrays.contains(listeners, listener);
+ SystemListener[] list = listeners;
+ if (list == null) {
+ list = new SystemListener[1];
+ } else {
+ list = copyOf(list, list.length + 1);
+ }
+ list[list.length - 1] = listener;
+ listeners = list;
+ }
+
+ /**
+ * Removes all occurrences (not just the first one) of the given listener.
+ * Only one occurrence should exist, but this method check all of them as
+ * a paranoiac check.`
+ *
+ * @param listener The listener to remove.
+ */
+ public static synchronized void remove(final SystemListener listener) {
+ SystemListener[] list = listeners;
+ if (list != null) {
+ for (int i=list.length; --i>=0;) {
+ if (list[i] == listener) {
+ list = Arrays.remove(list, i, 1);
+ }
+ }
+ listeners = list;
+ }
+ }
+
+ /**
+ * For sub-classes constructors.
+ */
+ protected SystemListener() {
+ }
+
+ /**
+ * Invoked when the classpath is likely to have changed.
+ * Any classes using {@link java.util.ServiceLoader} are advised to clear
their cache.
+ */
+ protected abstract void classpathChanged();
+
+ /**
+ * Notifies all registered listeners that the classpath may have changed.
+ */
+ public static void fireClasspathChanged() {
+ final SystemListener[] list;
+ synchronized (SystemListener.class) {
+ list = listeners;
+ }
+ if (list != null) {
+ for (int i=0; i<list.length; i++) {
+ list[i].classpathChanged();
+ }
+ }
+ }
+}
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SystemListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/internal/util/SystemListener.java
------------------------------------------------------------------------------
svn:mime-type = text/plain
Modified:
sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/XML.java
URL:
http://svn.apache.org/viewvc/sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/XML.java?rev=1430722&r1=1430721&r2=1430722&view=diff
==============================================================================
--- sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/XML.java
(original)
+++ sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis/xml/XML.java Wed
Jan 9 07:56:50 2013
@@ -17,9 +17,17 @@
package org.apache.sis.xml;
import java.util.Locale;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.io.StringWriter;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.JAXBException;
import org.apache.sis.util.Static;
+import org.apache.sis.internal.util.SystemListener;
+import org.apache.sis.internal.jaxb.TypeRegistration;
/**
@@ -227,8 +235,144 @@ public final class XML extends Static {
public static final String STRING_SUBSTITUTES =
"org.apache.sis.xml.stringSubstitutes";
/**
+ * The pool of marshallers and unmarshallers used by this class.
+ * The field name uses the uppercase convention because this field is
almost constant:
+ * this field is initially null, then created by {@link #getPool()} when
first needed.
+ * Once created the field value usually doesn't change. However the field
may be reset
+ * to {@code null} in an OSGi context when modules are loaded or unloaded,
because the
+ * set of classes returned by {@link
TypeRegistration#defaultClassesToBeBound()} may
+ * have changed.
+ *
+ * @see #getPool()
+ */
+ private static volatile MarshallerPool POOL;
+
+ /**
+ * Registers a listener for classpath changes. In such case, a new pool
will need to
+ * be created because the {@code JAXBContext} may be different.
+ */
+ static {
+ SystemListener.add(new SystemListener() {
+ @Override protected void classpathChanged() {
+ POOL = null;
+ }
+ });
+ }
+
+ /**
* Do not allow instantiation on this class.
*/
private XML() {
}
+
+ /**
+ * Returns the default (un)marshaller pool used by all methods in this
class.
+ *
+ * {@note Current implementation uses the double-check idiom. This is
usually a deprecated
+ * practice (the recommended alterative is to use static class
initialization), but in this
+ * particular case the field may be reset to <code>null</code> if OSGi
modules are loaded
+ * or unloaded, so static class initialization would be a little bit too
rigid.}
+ */
+ private static MarshallerPool getPool() throws JAXBException {
+ MarshallerPool pool = POOL;
+ if (pool == null) {
+ synchronized (XML.class) {
+ pool = POOL; // Double-check idiom: see javadoc.
+ if (pool == null) {
+ POOL = pool = new
MarshallerPool(TypeRegistration.defaultClassesToBeBound());
+ }
+ }
+ }
+ return pool;
+ }
+
+ /**
+ * Marshall the given object into a string.
+ *
+ * @param object The root of content tree to be marshalled.
+ * @return The XML representation of the given object.
+ * @throws JAXBException If an error occurred during the marshalling.
+ */
+ public static String marshal(final Object object) throws JAXBException {
+ final StringWriter output = new StringWriter();
+ final MarshallerPool pool = getPool();
+ final Marshaller marshaller = pool.acquireMarshaller();
+ marshaller.marshal(object, output);
+ pool.release(marshaller);
+ return output.toString();
+ }
+
+ /**
+ * Marshall the given object into a stream.
+ *
+ * @param object The root of content tree to be marshalled.
+ * @param output The stream where to write.
+ * @throws JAXBException If an error occurred during the marshalling.
+ */
+ public static void marshal(final Object object, final OutputStream output)
throws JAXBException {
+ final MarshallerPool pool = getPool();
+ final Marshaller marshaller = pool.acquireMarshaller();
+ marshaller.marshal(object, output);
+ pool.release(marshaller);
+ }
+
+ /**
+ * Marshall the given object into a file.
+ *
+ * @param object The root of content tree to be marshalled.
+ * @param output The file to be written.
+ * @throws JAXBException If an error occurred during the marshalling.
+ */
+ public static void marshal(final Object object, final File output) throws
JAXBException {
+ final MarshallerPool pool = getPool();
+ final Marshaller marshaller = pool.acquireMarshaller();
+ marshaller.marshal(object, output);
+ pool.release(marshaller);
+ }
+
+ /**
+ * Unmarshall an object from the given string.
+ *
+ * @param input The XML representation of an object.
+ * @return The object unmarshalled from the given input.
+ * @throws JAXBException If an error occurred during the unmarshalling.
+ */
+ public static Object unmarshal(final String input) throws JAXBException {
+ final StringReader in = new StringReader(input);
+ final MarshallerPool pool = getPool();
+ final Unmarshaller unmarshaller = pool.acquireUnmarshaller();
+ final Object object = unmarshaller.unmarshal(in);
+ pool.release(unmarshaller);
+ return object;
+ }
+
+ /**
+ * Unmarshall an object from the given stream.
+ *
+ * @param input The stream from which to read a XML representation.
+ * @return The object unmarshalled from the given input.
+ * @throws JAXBException If an error occurred during the unmarshalling.
+ */
+ public static Object unmarshal(final InputStream input) throws
JAXBException {
+ final MarshallerPool pool = getPool();
+ final Unmarshaller unmarshaller = pool.acquireUnmarshaller();
+ final Object object = unmarshaller.unmarshal(input);
+ pool.release(unmarshaller);
+ return object;
+ }
+
+ /**
+ * Unmarshall an object from the given file.
+ *
+ * @param input The file from which to read a XML representation.
+ * @return The object unmarshalled from the given input.
+ * @throws JAXBException If an error occurred during the unmarshalling.
+ */
+ public static Object unmarshal(final File input) throws JAXBException {
+ final MarshallerPool pool = getPool();
+ final Unmarshaller unmarshaller = pool.acquireUnmarshaller();
+ final Object object = unmarshaller.unmarshal(input);
+ pool.release(unmarshaller);
+ return object;
+ }
}