diff -r 8c0b6bccfe47 -r 0989ad8c0860 src/share/jaxws_classes/com/sun/xml/internal/ws/assembler/MetroConfigLoader.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/share/jaxws_classes/com/sun/xml/internal/ws/assembler/MetroConfigLoader.java Tue Apr 09 14:51:13 2013 +0100 @@ -0,0 +1,333 @@ +/* + * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package com.sun.xml.internal.ws.assembler; + +import com.sun.istack.internal.NotNull; +import com.sun.istack.internal.logging.Logger; +import com.sun.xml.internal.ws.api.ResourceLoader; +import com.sun.xml.internal.ws.api.server.Container; +import com.sun.xml.internal.ws.resources.TubelineassemblyMessages; +import com.sun.xml.internal.ws.runtime.config.MetroConfig; +import com.sun.xml.internal.ws.runtime.config.TubeFactoryList; +import com.sun.xml.internal.ws.runtime.config.TubelineDefinition; +import com.sun.xml.internal.ws.runtime.config.TubelineMapping; +import com.sun.xml.internal.ws.util.xml.XmlUtil; + +import javax.xml.bind.JAXBContext; +import javax.xml.bind.JAXBElement; +import javax.xml.bind.Unmarshaller; +import javax.xml.stream.XMLInputFactory; +import javax.xml.ws.WebServiceException; +import java.lang.reflect.Method; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.logging.Level; + +/** + * This class is responsible for locating and loading Metro configuration files + * (both application jaxws-tubes.xml and default jaxws-tubes-default.xml). + *

+ * Once the configuration is loaded the class is able to resolve which tubeline + * configuration belongs to each endpoint or endpoint client. This information is + * then used in {@link TubelineAssemblyController} to construct the list of + * {@link TubeCreator} objects that are used in the actual tubeline construction. + * + * @author Marek Potociar + */ +// TODO Move the logic of this class directly into MetroConfig class. +class MetroConfigLoader { + + private static final Logger LOGGER = Logger.getLogger(MetroConfigLoader.class); + + private MetroConfigName defaultTubesConfigNames; + + private static interface TubeFactoryListResolver { + + TubeFactoryList getFactories(TubelineDefinition td); + } + + private static final TubeFactoryListResolver ENDPOINT_SIDE_RESOLVER = new TubeFactoryListResolver() { + + public TubeFactoryList getFactories(TubelineDefinition td) { + return (td != null) ? td.getEndpointSide() : null; + } + }; + private static final TubeFactoryListResolver CLIENT_SIDE_RESOLVER = new TubeFactoryListResolver() { + + public TubeFactoryList getFactories(TubelineDefinition td) { + return (td != null) ? td.getClientSide() : null; + } + }; + // + private MetroConfig defaultConfig; + private URL defaultConfigUrl; + private MetroConfig appConfig; + private URL appConfigUrl; + + MetroConfigLoader(Container container, MetroConfigName defaultTubesConfigNames) { + this.defaultTubesConfigNames = defaultTubesConfigNames; + ResourceLoader spiResourceLoader = null; + if (container != null) { + spiResourceLoader = container.getSPI(ResourceLoader.class); + } + // if spi resource can't load resource, default (MetroConfigUrlLoader) is used; + // it searches the classpath, so it would be most probably used + // when using jaxws- or metro-defaults from jaxws libraries + init(container, spiResourceLoader, new MetroConfigUrlLoader(container)); + } + + private void init(Container container, ResourceLoader... loaders) { + + String appFileName = null; + String defaultFileName = null; + if (container != null) { + MetroConfigName mcn = container.getSPI(MetroConfigName.class); + if (mcn != null) { + appFileName = mcn.getAppFileName(); + defaultFileName = mcn.getDefaultFileName(); + } + } + if (appFileName == null) { + appFileName = defaultTubesConfigNames.getAppFileName(); + } + + if (defaultFileName == null) { + defaultFileName = defaultTubesConfigNames.getDefaultFileName(); + } + this.defaultConfigUrl = locateResource(defaultFileName, loaders); + if (defaultConfigUrl == null) { + throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0001_DEFAULT_CFG_FILE_NOT_FOUND(defaultFileName))); + } + + LOGGER.config(TubelineassemblyMessages.MASM_0002_DEFAULT_CFG_FILE_LOCATED(defaultFileName, defaultConfigUrl)); + this.defaultConfig = MetroConfigLoader.loadMetroConfig(defaultConfigUrl); + if (defaultConfig == null) { + throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0003_DEFAULT_CFG_FILE_NOT_LOADED(defaultFileName))); + } + if (defaultConfig.getTubelines() == null) { + throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0004_NO_TUBELINES_SECTION_IN_DEFAULT_CFG_FILE(defaultFileName))); + } + if (defaultConfig.getTubelines().getDefault() == null) { + throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0005_NO_DEFAULT_TUBELINE_IN_DEFAULT_CFG_FILE(defaultFileName))); + } + + this.appConfigUrl = locateResource(appFileName, loaders); + if (appConfigUrl != null) { + LOGGER.config(TubelineassemblyMessages.MASM_0006_APP_CFG_FILE_LOCATED(appConfigUrl)); + this.appConfig = MetroConfigLoader.loadMetroConfig(appConfigUrl); + } else { + LOGGER.config(TubelineassemblyMessages.MASM_0007_APP_CFG_FILE_NOT_FOUND()); + this.appConfig = null; + } + } + + TubeFactoryList getEndpointSideTubeFactories(URI endpointReference) { + return getTubeFactories(endpointReference, ENDPOINT_SIDE_RESOLVER); + } + + TubeFactoryList getClientSideTubeFactories(URI endpointReference) { + return getTubeFactories(endpointReference, CLIENT_SIDE_RESOLVER); + } + + private TubeFactoryList getTubeFactories(URI endpointReference, TubeFactoryListResolver resolver) { + if (appConfig != null && appConfig.getTubelines() != null) { + for (TubelineMapping mapping : appConfig.getTubelines().getTubelineMappings()) { + if (mapping.getEndpointRef().equals(endpointReference.toString())) { + TubeFactoryList list = resolver.getFactories(getTubeline(appConfig, resolveReference(mapping.getTubelineRef()))); + if (list != null) { + return list; + } else { + break; + } + } + } + + if (appConfig.getTubelines().getDefault() != null) { + TubeFactoryList list = resolver.getFactories(getTubeline(appConfig, resolveReference(appConfig.getTubelines().getDefault()))); + if (list != null) { + return list; + } + } + } + + for (TubelineMapping mapping : defaultConfig.getTubelines().getTubelineMappings()) { + if (mapping.getEndpointRef().equals(endpointReference.toString())) { + TubeFactoryList list = resolver.getFactories(getTubeline(defaultConfig, resolveReference(mapping.getTubelineRef()))); + if (list != null) { + return list; + } else { + break; + } + } + } + + return resolver.getFactories(getTubeline(defaultConfig, resolveReference(defaultConfig.getTubelines().getDefault()))); + } + + TubelineDefinition getTubeline(MetroConfig config, URI tubelineDefinitionUri) { + if (config != null && config.getTubelines() != null) { + for (TubelineDefinition td : config.getTubelines().getTubelineDefinitions()) { + if (td.getName().equals(tubelineDefinitionUri.getFragment())) { + return td; + } + } + } + + return null; + } + + private static URI resolveReference(String reference) { + try { + return new URI(reference); + } catch (URISyntaxException ex) { + throw LOGGER.logSevereException(new WebServiceException(TubelineassemblyMessages.MASM_0008_INVALID_URI_REFERENCE(reference), ex)); + } + } + + + private static URL locateResource(String resource, ResourceLoader loader) { + if (loader == null) return null; + + try { + return loader.getResource(resource); + } catch (MalformedURLException ex) { + LOGGER.severe(TubelineassemblyMessages.MASM_0009_CANNOT_FORM_VALID_URL(resource), ex); + } + return null; + } + + private static URL locateResource(String resource, ResourceLoader[] loaders) { + + for (ResourceLoader loader : loaders) { + URL url = locateResource(resource, loader); + if (url != null) { + return url; + } + } + return null; + } + + private static MetroConfig loadMetroConfig(@NotNull URL resourceUrl) { + MetroConfig result = null; + try { + JAXBContext jaxbContext = JAXBContext.newInstance(MetroConfig.class.getPackage().getName()); + Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); + XMLInputFactory factory = XmlUtil.newXMLInputFactory(true); + final JAXBElement configElement = unmarshaller.unmarshal(factory.createXMLStreamReader(resourceUrl.openStream()), MetroConfig.class); + result = configElement.getValue(); + } catch (Exception e) { + LOGGER.warning(TubelineassemblyMessages.MASM_0010_ERROR_READING_CFG_FILE_FROM_LOCATION(resourceUrl.toString()), e); + } + return result; + } + + private static class MetroConfigUrlLoader extends ResourceLoader { + + Container container; // TODO remove the field together with the code path using it (see below) + ResourceLoader parentLoader; + + MetroConfigUrlLoader(ResourceLoader parentLoader) { + this.parentLoader = parentLoader; + } + + MetroConfigUrlLoader(Container container) { + this((container != null) ? container.getSPI(ResourceLoader.class) : null); + this.container = container; + } + + @Override + public URL getResource(String resource) throws MalformedURLException { + LOGGER.entering(resource); + URL resourceUrl = null; + try { + if (parentLoader != null) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine(TubelineassemblyMessages.MASM_0011_LOADING_RESOURCE(resource, parentLoader)); + } + + resourceUrl = parentLoader.getResource(resource); + } + + if (resourceUrl == null) { + resourceUrl = loadViaClassLoaders("com/sun/xml/internal/ws/assembler/" + resource); + } + + if (resourceUrl == null && container != null) { + // TODO: we should remove this code path, the config file should be loaded using ResourceLoader only + resourceUrl = loadFromServletContext(resource); + } + + return resourceUrl; + } finally { + LOGGER.exiting(resourceUrl); + } + } + + private static URL loadViaClassLoaders(final String resource) { + URL resourceUrl = tryLoadFromClassLoader(resource, Thread.currentThread().getContextClassLoader()); + if (resourceUrl == null) { + resourceUrl = tryLoadFromClassLoader(resource, MetroConfigLoader.class.getClassLoader()); + if (resourceUrl == null) { + return ClassLoader.getSystemResource(resource); + } + } + + return resourceUrl; + } + + private static URL tryLoadFromClassLoader(final String resource, final ClassLoader loader) { + return (loader != null) ? loader.getResource(resource) : null; + } + + private URL loadFromServletContext(String resource) throws RuntimeException { + Object context = null; + try { + final Class contextClass = Class.forName("javax.servlet.ServletContext"); + context = container.getSPI(contextClass); + if (context != null) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine(TubelineassemblyMessages.MASM_0012_LOADING_VIA_SERVLET_CONTEXT(resource, context)); + } + try { + final Method method = context.getClass().getMethod("getResource", String.class); + final Object result = method.invoke(context, "/WEB-INF/" + resource); + return URL.class.cast(result); + } catch (Exception e) { + throw LOGGER.logSevereException(new RuntimeException(TubelineassemblyMessages.MASM_0013_ERROR_INVOKING_SERVLET_CONTEXT_METHOD("getResource()")), e); + } + } + } catch (ClassNotFoundException e) { + if (LOGGER.isLoggable(Level.FINE)) { + LOGGER.fine(TubelineassemblyMessages.MASM_0014_UNABLE_TO_LOAD_CLASS("javax.servlet.ServletContext")); + } + } + return null; + } + } + +}