jaxbutils.java

来自「开源的axis2框架的源码。用于开发WEBSERVER」· Java 代码 · 共 893 行 · 第 1/3 页

JAVA
893
字号
/*
 * 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.axis2.jaxws.message.databinding;

import org.apache.axis2.java.security.AccessController;
import org.apache.axis2.jaxws.ExceptionFactory;
import org.apache.axis2.jaxws.i18n.Messages;
import org.apache.axis2.jaxws.message.factory.ClassFinderFactory;
import org.apache.axis2.jaxws.registry.FactoryRegistry;
import org.apache.axis2.jaxws.utility.ClassUtils;
import org.apache.axis2.jaxws.utility.JavaUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.JAXBIntrospector;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.ws.Holder;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLDecoder;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;


/**
 * JAXB Utilites to pool JAXBContext and related objects. Currently the JAXBContext is pooled by
 * Class name.  We may change this to create and pool by package name.
 */
public class JAXBUtils {

    private static final Log log = LogFactory.getLog(JAXBUtils.class);

    // Create a concurrent map to get the JAXBObject: keys are ClassLoader and Set<String>.
    private static Map<ClassLoader, Map<String, JAXBContextValue>> jaxbMap =
            new ConcurrentHashMap<ClassLoader, Map<String, JAXBContextValue>>();

    private static Map<JAXBContext, Unmarshaller> umap =
            new ConcurrentHashMap<JAXBContext, Unmarshaller>();

    private static Map<JAXBContext, Marshaller> mmap =
            new ConcurrentHashMap<JAXBContext, Marshaller>();

    private static Map<JAXBContext, JAXBIntrospector> imap =
            new ConcurrentHashMap<JAXBContext, JAXBIntrospector>();

    // From Lizet Ernand:
    // If you really care about the performance, 
    // and/or your application is going to read a lot of small documents, 
    // then creating Unmarshaller could be relatively an expensive operation. 
    // In that case, consider pooling Unmarshaller objects.
    // Different threads may reuse one Unmarshaller instance, 
    // as long as you don't use one instance from two threads at the same time. 

    private static boolean ENABLE_ADV_POOLING = false;

    // The maps are freed up when a LOAD FACTOR is hit
    private static int MAX_LOAD_FACTOR = 32;

    // Construction Type
    public enum CONSTRUCTION_TYPE {
        BY_CLASS_ARRAY, BY_CONTEXT_PATH, UNKNOWN}

    ;

    /**
     * Get a JAXBContext for the class
     *
     * @param contextPackage Set<Package>
     * @return JAXBContext
     * @throws JAXBException
     * @deprecated
     */
    public static JAXBContext getJAXBContext(TreeSet<String> contextPackages) throws JAXBException {
        return getJAXBContext(contextPackages, new Holder<CONSTRUCTION_TYPE>(),
                              contextPackages.toString());
    }

    /**
     * Get a JAXBContext for the class
     *
     * @param contextPackage  Set<Package>
     * @param contructionType (output value that indicates how the context was constructed)
     * @return JAXBContext
     * @throws JAXBException
     */
    public static JAXBContext getJAXBContext(TreeSet<String> contextPackages,
                                             Holder<CONSTRUCTION_TYPE> constructionType, String key)
            throws JAXBException {
        // JAXBContexts for the same class can be reused and are supposed to be thread-safe
        if (log.isDebugEnabled()) {
            log.debug("Following packages are in this batch of getJAXBContext() :");
            for (String pkg : contextPackages) {
                log.debug(pkg);
            }
        }
        // The JAXBContexts are keyed by ClassLoader and the set of Strings
        ClassLoader cl = getContextClassLoader();

        // Get the innerMap 
        Map<String, JAXBContextValue> innerMap = jaxbMap.get(cl);
        if (innerMap == null) {
            adjustPoolSize(jaxbMap);
            innerMap = new ConcurrentHashMap<String, JAXBContextValue>();
            jaxbMap.put(cl, innerMap);
        }

        if (contextPackages == null) {
            contextPackages = new TreeSet<String>();
        }

        JAXBContextValue contextValue = innerMap.get(key);
        if (contextValue == null) {
            adjustPoolSize(innerMap);

            // A pooled context was not found, so create one and put it in the map.
            synchronized(contextPackages) {
               // synchronized on contextPackages because this method may prune the contextPackages
               contextValue = createJAXBContextValue(contextPackages, cl);
            }
            // Put the new context in the map keyed by both the original and current list of packages
            innerMap.put(key, contextValue);
            innerMap.put(contextPackages.toString(), contextValue);
            if (log.isDebugEnabled()) {
                log.debug("JAXBContext [created] for " + contextPackages.toString());
            }

        } else {
            if (log.isDebugEnabled()) {
                log.debug("JAXBContext [from pool] for " + contextPackages.toString());
            }
        }
        constructionType.value = contextValue.constructionType;
        return contextValue.jaxbContext;
    }

    /**
     * Create a JAXBContext using the contextPackages
     *
     * @param contextPackages Set<String>
     * @param cl              ClassLoader
     * @return JAXBContextValue (JAXBContext + constructionType)
     * @throws JAXBException
     */
    private static JAXBContextValue createJAXBContextValue(TreeSet<String> contextPackages,
                                                           ClassLoader cl) throws JAXBException {

        JAXBContextValue contextValue = null;
        if (log.isDebugEnabled()) {
            log.debug("Following packages are in this batch of getJAXBContext() :");
            for (String pkg : contextPackages) {
                log.debug(pkg);
            }
        }
        // The contextPackages is a set of package names that are constructed using PackageSetBuilder.
        // PackageSetBuilder gets the packages names from various sources.
        //   a) It walks the various annotations on the WebService collecting package names.
        //   b) It walks the wsdl/schemas and builds package names for each target namespace.
        //
        // The combination of these two sources should produce all of the package names.
        // -------------
        // Note that (b) is necessary for the following case:
        // An operation has a parameter named BASE.
        // Object DERIVED is an extension of BASE and is defined in a different package/schema.
        // In this case, there will not be any annotations on the WebService that reference DERIVED.
        // The only way to find the package for DERIVED is to walk the schemas.
        // -------------

        Iterator<String> it = contextPackages.iterator();
        while (it.hasNext()) {
            String p = it.next();
            // Don't consider java and javax packages
            // REVIEW: We might have to refine this
            if (p.startsWith("java.") ||
                    p.startsWith("javax.")) {
                it.remove();
            }
        }

        // There are two ways to construct the context.
        // 1) USE A CONTEXTPATH, which is a string containing
        //    all of the packages separated by colons.
        // 2) USE A CLASS[], which is an array of all of the classes
        //    involved in the marshal/unmarshal.
        //   
        // There are pros/cons with both approaches.
        // USE A CONTEXTPATH: 
        //    Pros: preferred way of doing this.  
        //          performant
        //          most dynamic
        //    Cons: Each package in context path must have an ObjectFactory
        //        
        //
        // USE CLASS[]:
        //    Pros: Doesn't require ObjectFactory in each package
        //    Cons: Hard to set up, must account for JAX-WS classes, etc.
        //          Does not work if arrays of classes are needed
        //          slower
        //
        //  The following code attempts to build a context path.  It then
        //  choose one of the two constructions above (prefer USE A CONTEXT_PATH)
        //

        // The packages are examined to see if they have ObjectFactory/package-info classes.
        // Invalid packages are removed from the list
        it = contextPackages.iterator();
        boolean contextConstruction = true;
        boolean isJAXBFound = false;
        while (it.hasNext()) {
            String p = it.next();
            // See if this package has an ObjectFactory or package-info
            if (checkPackage(p, cl)) {
                // Flow to here indicates package can be used for CONTEXT construction
                isJAXBFound = true;
                if (log.isDebugEnabled()) {
                    log.debug("Package " + p + " contains an ObjectFactory or package-info class.");
                }
            } else {
                // Flow to here indicates that the package is not valid for context construction.
                // Perhaps the package is invalid.
                if (log.isDebugEnabled()) {
                    log.debug("Package " + p +
                            " does not contain an ObjectFactory or package-info class.  Searching for JAXB classes");
                }
                List<Class> classes = null;
                classes = getAllClassesFromPackage(p, cl);
                if (classes == null || classes.size() == 0) {
                    if (log.isDebugEnabled()) {
                        log.debug("Package " + p +
                                " does not have any JAXB classes.  It is removed from the JAXB context path.");
                    }
                    it.remove();
                } else {
                    // Classes are found in the package.  We cannot use the CONTEXT construction
                    contextConstruction = false;
                    if (log.isDebugEnabled()) {
                        log.debug("Package " + p +
                                " does not contain ObjectFactory, but it does contain other JAXB classes.");
                    }
                }
            }
        }

        if (!isJAXBFound) {
            if (log.isDebugEnabled()) {
                log.debug("Both ObjectFactory & package-info not found in package hierachy");
            }
        }

        // The code above may have removed some packages from the list. 
        // Retry our lookup with the updated list
        Map<String, JAXBContextValue> innerMap = jaxbMap.get(cl);
        if (innerMap != null) {
            contextValue = innerMap.get(contextPackages.toString());
            if (contextValue != null) {
                if (log.isDebugEnabled()) {
                    log.debug("Successfully found JAXBContext with updated context list:" +
                            contextValue.jaxbContext.toString());
                }
                return contextValue;
            }
        }

        // CONTEXT construction
        if (contextConstruction) {
            JAXBContext context = createJAXBContextUsingContextPath(contextPackages, cl);
            if (context != null) {
                contextValue = new JAXBContextValue(context, CONSTRUCTION_TYPE.BY_CONTEXT_PATH);
            }
        }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?