src/share/jaxws_classes/com/sun/xml/internal/ws/assembler/MetroConfigLoader.java

Fri, 14 Feb 2014 11:13:45 +0100

author
mkos
date
Fri, 14 Feb 2014 11:13:45 +0100
changeset 515
6cd506508147
parent 384
8f2986ff0235
child 637
9c07ef4934dd
permissions
-rw-r--r--

8026188: Enhance envelope factory
Summary: Avoiding caching data initialized via TCCL in static context; fix also reviewed by Alexander Fomin
Reviewed-by: ahgross, mgrebac, skoivu

alanb@368 1 /*
alanb@368 2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
alanb@368 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
alanb@368 4 *
alanb@368 5 * This code is free software; you can redistribute it and/or modify it
alanb@368 6 * under the terms of the GNU General Public License version 2 only, as
alanb@368 7 * published by the Free Software Foundation. Oracle designates this
alanb@368 8 * particular file as subject to the "Classpath" exception as provided
alanb@368 9 * by Oracle in the LICENSE file that accompanied this code.
alanb@368 10 *
alanb@368 11 * This code is distributed in the hope that it will be useful, but WITHOUT
alanb@368 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
alanb@368 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
alanb@368 14 * version 2 for more details (a copy is included in the LICENSE file that
alanb@368 15 * accompanied this code).
alanb@368 16 *
alanb@368 17 * You should have received a copy of the GNU General Public License version
alanb@368 18 * 2 along with this work; if not, write to the Free Software Foundation,
alanb@368 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
alanb@368 20 *
alanb@368 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
alanb@368 22 * or visit www.oracle.com if you need additional information or have any
alanb@368 23 * questions.
alanb@368 24 */
alanb@368 25
alanb@368 26 package com.sun.xml.internal.ws.assembler;
alanb@368 27
alanb@368 28 import com.sun.istack.internal.NotNull;
alanb@368 29 import com.sun.istack.internal.logging.Logger;
alanb@368 30 import com.sun.xml.internal.ws.api.ResourceLoader;
alanb@368 31 import com.sun.xml.internal.ws.api.server.Container;
alanb@368 32 import com.sun.xml.internal.ws.resources.TubelineassemblyMessages;
alanb@368 33 import com.sun.xml.internal.ws.runtime.config.MetroConfig;
alanb@368 34 import com.sun.xml.internal.ws.runtime.config.TubeFactoryList;
alanb@368 35 import com.sun.xml.internal.ws.runtime.config.TubelineDefinition;
alanb@368 36 import com.sun.xml.internal.ws.runtime.config.TubelineMapping;
alanb@368 37 import com.sun.xml.internal.ws.util.xml.XmlUtil;
alanb@368 38
alanb@368 39 import javax.xml.bind.JAXBContext;
alanb@368 40 import javax.xml.bind.JAXBElement;
alanb@368 41 import javax.xml.bind.Unmarshaller;
alanb@368 42 import javax.xml.stream.XMLInputFactory;
alanb@368 43 import javax.xml.ws.WebServiceException;
alanb@368 44 import java.lang.reflect.Method;
mkos@384 45 import java.lang.reflect.ReflectPermission;
alanb@368 46 import java.net.MalformedURLException;
alanb@368 47 import java.net.URI;
alanb@368 48 import java.net.URISyntaxException;
alanb@368 49 import java.net.URL;
mkos@384 50 import java.security.*;
mkos@384 51 import java.util.PropertyPermission;
alanb@368 52 import java.util.logging.Level;
alanb@368 53
alanb@368 54 /**
alanb@368 55 * This class is responsible for locating and loading Metro configuration files
alanb@368 56 * (both application jaxws-tubes.xml and default jaxws-tubes-default.xml).
alanb@368 57 * <p/>
alanb@368 58 * Once the configuration is loaded the class is able to resolve which tubeline
alanb@368 59 * configuration belongs to each endpoint or endpoint client. This information is
alanb@368 60 * then used in {@link TubelineAssemblyController} to construct the list of
alanb@368 61 * {@link TubeCreator} objects that are used in the actual tubeline construction.
alanb@368 62 *
alanb@368 63 * @author Marek Potociar <marek.potociar at sun.com>
alanb@368 64 */
alanb@368 65 // TODO Move the logic of this class directly into MetroConfig class.
alanb@368 66 class MetroConfigLoader {
alanb@368 67
alanb@368 68 private static final Logger LOGGER = Logger.getLogger(MetroConfigLoader.class);
alanb@368 69
alanb@368 70 private MetroConfigName defaultTubesConfigNames;
alanb@368 71
alanb@368 72 private static interface TubeFactoryListResolver {
alanb@368 73
alanb@368 74 TubeFactoryList getFactories(TubelineDefinition td);
alanb@368 75 }
alanb@368 76
alanb@368 77 private static final TubeFactoryListResolver ENDPOINT_SIDE_RESOLVER = new TubeFactoryListResolver() {
alanb@368 78
alanb@368 79 public TubeFactoryList getFactories(TubelineDefinition td) {
alanb@368 80 return (td != null) ? td.getEndpointSide() : null;
alanb@368 81 }
alanb@368 82 };
alanb@368 83 private static final TubeFactoryListResolver CLIENT_SIDE_RESOLVER = new TubeFactoryListResolver() {
alanb@368 84
alanb@368 85 public TubeFactoryList getFactories(TubelineDefinition td) {
alanb@368 86 return (td != null) ? td.getClientSide() : null;
alanb@368 87 }
alanb@368 88 };
alanb@368 89 //
alanb@368 90 private MetroConfig defaultConfig;
alanb@368 91 private URL defaultConfigUrl;
alanb@368 92 private MetroConfig appConfig;
alanb@368 93 private URL appConfigUrl;
alanb@368 94
alanb@368 95 MetroConfigLoader(Container container, MetroConfigName defaultTubesConfigNames) {
alanb@368 96 this.defaultTubesConfigNames = defaultTubesConfigNames;
alanb@368 97 ResourceLoader spiResourceLoader = null;
alanb@368 98 if (container != null) {
alanb@368 99 spiResourceLoader = container.getSPI(ResourceLoader.class);
alanb@368 100 }
alanb@368 101 // if spi resource can't load resource, default (MetroConfigUrlLoader) is used;
alanb@368 102 // it searches the classpath, so it would be most probably used
alanb@368 103 // when using jaxws- or metro-defaults from jaxws libraries
alanb@368 104 init(container, spiResourceLoader, new MetroConfigUrlLoader(container));
alanb@368 105 }
alanb@368 106
alanb@368 107 private void init(Container container, ResourceLoader... loaders) {
alanb@368 108
alanb@368 109 String appFileName = null;
alanb@368 110 String defaultFileName = null;
alanb@368 111 if (container != null) {
alanb@368 112 MetroConfigName mcn = container.getSPI(MetroConfigName.class);
alanb@368 113 if (mcn != null) {
alanb@368 114 appFileName = mcn.getAppFileName();
alanb@368 115 defaultFileName = mcn.getDefaultFileName();
alanb@368 116 }
alanb@368 117 }
alanb@368 118 if (appFileName == null) {
alanb@368 119 appFileName = defaultTubesConfigNames.getAppFileName();
alanb@368 120 }
alanb@368 121
alanb@368 122 if (defaultFileName == null) {
alanb@368 123 defaultFileName = defaultTubesConfigNames.getDefaultFileName();
alanb@368 124 }
alanb@368 125 this.defaultConfigUrl = locateResource(defaultFileName, loaders);
alanb@368 126 if (defaultConfigUrl == null) {
alanb@368 127 throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0001_DEFAULT_CFG_FILE_NOT_FOUND(defaultFileName)));
alanb@368 128 }
alanb@368 129
alanb@368 130 LOGGER.config(TubelineassemblyMessages.MASM_0002_DEFAULT_CFG_FILE_LOCATED(defaultFileName, defaultConfigUrl));
alanb@368 131 this.defaultConfig = MetroConfigLoader.loadMetroConfig(defaultConfigUrl);
alanb@368 132 if (defaultConfig == null) {
alanb@368 133 throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0003_DEFAULT_CFG_FILE_NOT_LOADED(defaultFileName)));
alanb@368 134 }
alanb@368 135 if (defaultConfig.getTubelines() == null) {
alanb@368 136 throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0004_NO_TUBELINES_SECTION_IN_DEFAULT_CFG_FILE(defaultFileName)));
alanb@368 137 }
alanb@368 138 if (defaultConfig.getTubelines().getDefault() == null) {
alanb@368 139 throw LOGGER.logSevereException(new IllegalStateException(TubelineassemblyMessages.MASM_0005_NO_DEFAULT_TUBELINE_IN_DEFAULT_CFG_FILE(defaultFileName)));
alanb@368 140 }
alanb@368 141
alanb@368 142 this.appConfigUrl = locateResource(appFileName, loaders);
alanb@368 143 if (appConfigUrl != null) {
alanb@368 144 LOGGER.config(TubelineassemblyMessages.MASM_0006_APP_CFG_FILE_LOCATED(appConfigUrl));
alanb@368 145 this.appConfig = MetroConfigLoader.loadMetroConfig(appConfigUrl);
alanb@368 146 } else {
alanb@368 147 LOGGER.config(TubelineassemblyMessages.MASM_0007_APP_CFG_FILE_NOT_FOUND());
alanb@368 148 this.appConfig = null;
alanb@368 149 }
alanb@368 150 }
alanb@368 151
alanb@368 152 TubeFactoryList getEndpointSideTubeFactories(URI endpointReference) {
alanb@368 153 return getTubeFactories(endpointReference, ENDPOINT_SIDE_RESOLVER);
alanb@368 154 }
alanb@368 155
alanb@368 156 TubeFactoryList getClientSideTubeFactories(URI endpointReference) {
alanb@368 157 return getTubeFactories(endpointReference, CLIENT_SIDE_RESOLVER);
alanb@368 158 }
alanb@368 159
alanb@368 160 private TubeFactoryList getTubeFactories(URI endpointReference, TubeFactoryListResolver resolver) {
alanb@368 161 if (appConfig != null && appConfig.getTubelines() != null) {
alanb@368 162 for (TubelineMapping mapping : appConfig.getTubelines().getTubelineMappings()) {
alanb@368 163 if (mapping.getEndpointRef().equals(endpointReference.toString())) {
alanb@368 164 TubeFactoryList list = resolver.getFactories(getTubeline(appConfig, resolveReference(mapping.getTubelineRef())));
alanb@368 165 if (list != null) {
alanb@368 166 return list;
alanb@368 167 } else {
alanb@368 168 break;
alanb@368 169 }
alanb@368 170 }
alanb@368 171 }
alanb@368 172
alanb@368 173 if (appConfig.getTubelines().getDefault() != null) {
alanb@368 174 TubeFactoryList list = resolver.getFactories(getTubeline(appConfig, resolveReference(appConfig.getTubelines().getDefault())));
alanb@368 175 if (list != null) {
alanb@368 176 return list;
alanb@368 177 }
alanb@368 178 }
alanb@368 179 }
alanb@368 180
alanb@368 181 for (TubelineMapping mapping : defaultConfig.getTubelines().getTubelineMappings()) {
alanb@368 182 if (mapping.getEndpointRef().equals(endpointReference.toString())) {
alanb@368 183 TubeFactoryList list = resolver.getFactories(getTubeline(defaultConfig, resolveReference(mapping.getTubelineRef())));
alanb@368 184 if (list != null) {
alanb@368 185 return list;
alanb@368 186 } else {
alanb@368 187 break;
alanb@368 188 }
alanb@368 189 }
alanb@368 190 }
alanb@368 191
alanb@368 192 return resolver.getFactories(getTubeline(defaultConfig, resolveReference(defaultConfig.getTubelines().getDefault())));
alanb@368 193 }
alanb@368 194
alanb@368 195 TubelineDefinition getTubeline(MetroConfig config, URI tubelineDefinitionUri) {
alanb@368 196 if (config != null && config.getTubelines() != null) {
alanb@368 197 for (TubelineDefinition td : config.getTubelines().getTubelineDefinitions()) {
alanb@368 198 if (td.getName().equals(tubelineDefinitionUri.getFragment())) {
alanb@368 199 return td;
alanb@368 200 }
alanb@368 201 }
alanb@368 202 }
alanb@368 203
alanb@368 204 return null;
alanb@368 205 }
alanb@368 206
alanb@368 207 private static URI resolveReference(String reference) {
alanb@368 208 try {
alanb@368 209 return new URI(reference);
alanb@368 210 } catch (URISyntaxException ex) {
alanb@368 211 throw LOGGER.logSevereException(new WebServiceException(TubelineassemblyMessages.MASM_0008_INVALID_URI_REFERENCE(reference), ex));
alanb@368 212 }
alanb@368 213 }
alanb@368 214
alanb@368 215
alanb@368 216 private static URL locateResource(String resource, ResourceLoader loader) {
alanb@368 217 if (loader == null) return null;
alanb@368 218
alanb@368 219 try {
alanb@368 220 return loader.getResource(resource);
alanb@368 221 } catch (MalformedURLException ex) {
alanb@368 222 LOGGER.severe(TubelineassemblyMessages.MASM_0009_CANNOT_FORM_VALID_URL(resource), ex);
alanb@368 223 }
alanb@368 224 return null;
alanb@368 225 }
alanb@368 226
alanb@368 227 private static URL locateResource(String resource, ResourceLoader[] loaders) {
alanb@368 228
alanb@368 229 for (ResourceLoader loader : loaders) {
alanb@368 230 URL url = locateResource(resource, loader);
alanb@368 231 if (url != null) {
alanb@368 232 return url;
alanb@368 233 }
alanb@368 234 }
alanb@368 235 return null;
alanb@368 236 }
alanb@368 237
alanb@368 238 private static MetroConfig loadMetroConfig(@NotNull URL resourceUrl) {
alanb@368 239 MetroConfig result = null;
alanb@368 240 try {
mkos@384 241 JAXBContext jaxbContext = createJAXBContext();
alanb@368 242 Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
alanb@368 243 XMLInputFactory factory = XmlUtil.newXMLInputFactory(true);
alanb@368 244 final JAXBElement<MetroConfig> configElement = unmarshaller.unmarshal(factory.createXMLStreamReader(resourceUrl.openStream()), MetroConfig.class);
alanb@368 245 result = configElement.getValue();
alanb@368 246 } catch (Exception e) {
alanb@368 247 LOGGER.warning(TubelineassemblyMessages.MASM_0010_ERROR_READING_CFG_FILE_FROM_LOCATION(resourceUrl.toString()), e);
alanb@368 248 }
alanb@368 249 return result;
alanb@368 250 }
alanb@368 251
mkos@384 252 private static JAXBContext createJAXBContext() throws Exception {
mkos@384 253 if (isJDKInternal()) {
mkos@384 254 // since jdk classes are repackaged, extra privilege is necessary to create JAXBContext
mkos@384 255 return AccessController.doPrivileged(
mkos@384 256 new PrivilegedExceptionAction<JAXBContext>() {
mkos@384 257 @Override
mkos@384 258 public JAXBContext run() throws Exception {
mkos@384 259 return JAXBContext.newInstance(MetroConfig.class.getPackage().getName());
mkos@384 260 }
mkos@384 261 }, createSecurityContext()
mkos@384 262 );
mkos@384 263 } else {
mkos@384 264 // usage from JAX-WS/Metro/Glassfish
mkos@384 265 return JAXBContext.newInstance(MetroConfig.class.getPackage().getName());
mkos@384 266 }
mkos@384 267 }
mkos@384 268
mkos@384 269 private static AccessControlContext createSecurityContext() {
mkos@384 270 PermissionCollection perms = new Permissions();
mkos@384 271 perms.add(new RuntimePermission("accessClassInPackage.com" + ".sun.xml.internal.ws.runtime.config")); // avoid repackaging
mkos@384 272 perms.add(new ReflectPermission("suppressAccessChecks"));
mkos@384 273 return new AccessControlContext(
mkos@384 274 new ProtectionDomain[]{
mkos@384 275 new ProtectionDomain(null, perms),
mkos@384 276 });
mkos@384 277 }
mkos@384 278
mkos@384 279 private static boolean isJDKInternal() {
mkos@384 280 // avoid "string repackaging"
mkos@384 281 return MetroConfigLoader.class.getName().startsWith("com." + "sun.xml.internal.ws");
mkos@384 282 }
mkos@384 283
alanb@368 284 private static class MetroConfigUrlLoader extends ResourceLoader {
alanb@368 285
alanb@368 286 Container container; // TODO remove the field together with the code path using it (see below)
alanb@368 287 ResourceLoader parentLoader;
alanb@368 288
alanb@368 289 MetroConfigUrlLoader(ResourceLoader parentLoader) {
alanb@368 290 this.parentLoader = parentLoader;
alanb@368 291 }
alanb@368 292
alanb@368 293 MetroConfigUrlLoader(Container container) {
alanb@368 294 this((container != null) ? container.getSPI(ResourceLoader.class) : null);
alanb@368 295 this.container = container;
alanb@368 296 }
alanb@368 297
alanb@368 298 @Override
alanb@368 299 public URL getResource(String resource) throws MalformedURLException {
alanb@368 300 LOGGER.entering(resource);
alanb@368 301 URL resourceUrl = null;
alanb@368 302 try {
alanb@368 303 if (parentLoader != null) {
alanb@368 304 if (LOGGER.isLoggable(Level.FINE)) {
alanb@368 305 LOGGER.fine(TubelineassemblyMessages.MASM_0011_LOADING_RESOURCE(resource, parentLoader));
alanb@368 306 }
alanb@368 307
alanb@368 308 resourceUrl = parentLoader.getResource(resource);
alanb@368 309 }
alanb@368 310
alanb@368 311 if (resourceUrl == null) {
alanb@368 312 resourceUrl = loadViaClassLoaders("com/sun/xml/internal/ws/assembler/" + resource);
alanb@368 313 }
alanb@368 314
alanb@368 315 if (resourceUrl == null && container != null) {
alanb@368 316 // TODO: we should remove this code path, the config file should be loaded using ResourceLoader only
alanb@368 317 resourceUrl = loadFromServletContext(resource);
alanb@368 318 }
alanb@368 319
alanb@368 320 return resourceUrl;
alanb@368 321 } finally {
alanb@368 322 LOGGER.exiting(resourceUrl);
alanb@368 323 }
alanb@368 324 }
alanb@368 325
alanb@368 326 private static URL loadViaClassLoaders(final String resource) {
alanb@368 327 URL resourceUrl = tryLoadFromClassLoader(resource, Thread.currentThread().getContextClassLoader());
alanb@368 328 if (resourceUrl == null) {
alanb@368 329 resourceUrl = tryLoadFromClassLoader(resource, MetroConfigLoader.class.getClassLoader());
alanb@368 330 if (resourceUrl == null) {
alanb@368 331 return ClassLoader.getSystemResource(resource);
alanb@368 332 }
alanb@368 333 }
alanb@368 334
alanb@368 335 return resourceUrl;
alanb@368 336 }
alanb@368 337
alanb@368 338 private static URL tryLoadFromClassLoader(final String resource, final ClassLoader loader) {
alanb@368 339 return (loader != null) ? loader.getResource(resource) : null;
alanb@368 340 }
alanb@368 341
alanb@368 342 private URL loadFromServletContext(String resource) throws RuntimeException {
alanb@368 343 Object context = null;
alanb@368 344 try {
alanb@368 345 final Class<?> contextClass = Class.forName("javax.servlet.ServletContext");
alanb@368 346 context = container.getSPI(contextClass);
alanb@368 347 if (context != null) {
alanb@368 348 if (LOGGER.isLoggable(Level.FINE)) {
alanb@368 349 LOGGER.fine(TubelineassemblyMessages.MASM_0012_LOADING_VIA_SERVLET_CONTEXT(resource, context));
alanb@368 350 }
alanb@368 351 try {
alanb@368 352 final Method method = context.getClass().getMethod("getResource", String.class);
alanb@368 353 final Object result = method.invoke(context, "/WEB-INF/" + resource);
alanb@368 354 return URL.class.cast(result);
alanb@368 355 } catch (Exception e) {
alanb@368 356 throw LOGGER.logSevereException(new RuntimeException(TubelineassemblyMessages.MASM_0013_ERROR_INVOKING_SERVLET_CONTEXT_METHOD("getResource()")), e);
alanb@368 357 }
alanb@368 358 }
alanb@368 359 } catch (ClassNotFoundException e) {
alanb@368 360 if (LOGGER.isLoggable(Level.FINE)) {
alanb@368 361 LOGGER.fine(TubelineassemblyMessages.MASM_0014_UNABLE_TO_LOAD_CLASS("javax.servlet.ServletContext"));
alanb@368 362 }
alanb@368 363 }
alanb@368 364 return null;
alanb@368 365 }
alanb@368 366 }
alanb@368 367
alanb@368 368 }

mercurial