sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1430722 - in /sis/branches/JDK7/sis-utility/src/main/java/org/apache/sis: internal/jaxb/TypeRegistration.java internal/util/SystemListener.java xml/XML.java
Date Wed, 09 Jan 2013 07:56:51 GMT
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;
+    }
 }



Mime
View raw message