All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.glassfish.jersey.server.internal.inject.WebTargetValueFactoryProvider Maven / Gradle / Ivy

There is a newer version: 2.22.2
Show newest version
/*
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
 *
 * Copyright (c) 2012-2014 Oracle and/or its affiliates. All rights reserved.
 *
 * The contents of this file are subject to the terms of either the GNU
 * General Public License Version 2 only ("GPL") or the Common Development
 * and Distribution License("CDDL") (collectively, the "License").  You
 * may not use this file except in compliance with the License.  You can
 * obtain a copy of the License at
 * http://glassfish.java.net/public/CDDL+GPL_1_1.html
 * or packager/legal/LICENSE.txt.  See the License for the specific
 * language governing permissions and limitations under the License.
 *
 * When distributing the software, include this License Header Notice in each
 * file and include the License file at packager/legal/LICENSE.txt.
 *
 * GPL Classpath Exception:
 * Oracle designates this particular file as subject to the "Classpath"
 * exception as provided by Oracle in the GPL Version 2 section of the License
 * file that accompanied this code.
 *
 * Modifications:
 * If applicable, add the following below the License Header, with the fields
 * enclosed by brackets [] replaced by your own identifying information:
 * "Portions Copyright [year] [name of copyright owner]"
 *
 * Contributor(s):
 * If you wish your version of this file to be governed by only the CDDL or
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
 * elects to include this software in this distribution under the [CDDL or GPL
 * Version 2] license."  If you don't indicate a single choice of license, a
 * recipient has the option to distribute your version of this file under
 * either the CDDL, the GPL Version 2 or to extend the choice of license to
 * its licensees as provided above.  However, if you add GPL Version 2 code
 * and therefore, elected the GPL Version 2 license, then the option applies
 * only if the new code is made subject to such option by the copyright
 * holder.
 */
package org.glassfish.jersey.server.internal.inject;

import java.lang.annotation.Annotation;
import java.security.AccessController;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.ws.rs.ProcessingException;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.ClientBuilder;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Configurable;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Context;

import javax.inject.Inject;

import org.glassfish.jersey.client.ClientConfig;
import org.glassfish.jersey.internal.Errors;
import org.glassfish.jersey.internal.inject.Injections;
import org.glassfish.jersey.internal.util.Producer;
import org.glassfish.jersey.internal.util.PropertiesHelper;
import org.glassfish.jersey.internal.util.ReflectionHelper;
import org.glassfish.jersey.internal.util.collection.Value;
import org.glassfish.jersey.internal.util.collection.Values;
import org.glassfish.jersey.server.ClientBinding;
import org.glassfish.jersey.server.ExtendedUriInfo;
import org.glassfish.jersey.server.Uri;
import org.glassfish.jersey.server.internal.LocalizationMessages;
import org.glassfish.jersey.server.model.Parameter;
import org.glassfish.jersey.uri.internal.JerseyUriBuilder;

import org.glassfish.hk2.api.ServiceLocator;

import jersey.repackaged.com.google.common.base.Function;
import jersey.repackaged.com.google.common.base.Predicate;
import jersey.repackaged.com.google.common.collect.Collections2;
import jersey.repackaged.com.google.common.collect.Maps;

/**
 * Value factory provider supporting the {@link Uri} injection annotation.
 *
 * @author Pavel Bucek (pavel.bucek at oracle.com)
 */
final class WebTargetValueFactoryProvider extends AbstractValueFactoryProvider {
    private final Configuration serverConfig;
    private final ConcurrentMap> managedClients;

    private static class ManagedClient {
        private final Client instance;
        private final String customBaseUri;

        private ManagedClient(Client instance, String customBaseUri) {
            this.instance = instance;
            this.customBaseUri = customBaseUri;
        }
    }

    private static class BindingModel {
        public static final BindingModel EMPTY = new BindingModel(null);

        /**
         * Create a client binding model from a {@link ClientBinding client binding} annotation.
         *
         * @param binding client binding annotation.
         * @return binding model representing a single client binding annotation.
         */
        public static BindingModel create(Annotation binding) {
            if (binding == null || binding.annotationType().getAnnotation(ClientBinding.class) == null) {
                return EMPTY;
            } else {
                return new BindingModel(binding);
            }
        }

        /**
         * Create a client binding model from a set of {@link ClientBinding client binding}
         * annotation candidates.
         * 

* A {@code ClientBinding} marker meta-annotation is used to select the set of binding * annotations. Only those annotations that are annotated with the binding marker * meta-annotation are considered as binding annotations. All other annotations are filtered * out and ignored. *

* * @param bindingCandidates candidate binding annotations. * @return composite binding representing the union of the individual binding annotations * found among the binding candidates. */ public static BindingModel create(final Collection bindingCandidates) { final Collection filtered = Collections2.filter(bindingCandidates, new Predicate() { @Override public boolean apply(Annotation input) { return input != null && input.annotationType().getAnnotation(ClientBinding.class) != null; } }); if (filtered.isEmpty()) { return EMPTY; } else if (filtered.size() > 1) { throw new ProcessingException("Too many client binding annotations."); } else { return new BindingModel(filtered.iterator().next()); } } private final Annotation annotation; private final Class configClass; private final boolean inheritProviders; private final String baseUri; private BindingModel(Annotation annotation) { if (annotation == null) { this.annotation = null; this.configClass = ClientConfig.class; this.inheritProviders = true; this.baseUri = ""; } else { this.annotation = annotation; final ClientBinding cba = annotation.annotationType().getAnnotation(ClientBinding.class); this.configClass = cba.configClass(); this.inheritProviders = cba.inheritServerProviders(); this.baseUri = cba.baseUri(); } } /** * Get the client binding annotation this model represents. * * @return client binding annotation. */ public Annotation getAnnotation() { return annotation; } /** * Get the configuration class to be used. * * @return client configuration class to be used. */ public Class getConfigClass() { return configClass; } /** * Check if the server-side providers should be inherited. * * @return {@code true} if server-side providers should be inherited, {@code false} otherwise. */ public boolean inheritProviders() { return inheritProviders; } /** * Get the client base URI. * * @return client base URI. */ public String baseUri() { return baseUri; } @Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } BindingModel that = (BindingModel) o; return annotation != null ? annotation.equals(that.annotation) : that.annotation == null; } @Override public int hashCode() { return annotation != null ? annotation.hashCode() : 0; } @Override public String toString() { return "BindingModel{" + "binding=" + annotation + ", configClass=" + configClass + ", inheritProviders=" + inheritProviders + ", baseUri=" + baseUri + '}'; } } /** * {@link Uri} injection resolver. */ static final class InjectionResolver extends ParamInjectionResolver { /** * Create new injection resolver. */ public InjectionResolver() { super(WebTargetValueFactoryProvider.class); } } private static final class WebTargetValueFactory extends AbstractContainerRequestValueFactory { private final String uri; private final Value client; WebTargetValueFactory(String uri, Value client) { this.uri = uri; this.client = client; } @Override public WebTarget provide() { // no need for try-catch - unlike for @*Param annotations, any issues with @Uri would usually be caused // by incorrect server code, so the default runtime exception mapping to 500 is appropriate final ExtendedUriInfo uriInfo = getContainerRequest().getUriInfo(); final Map pathParamValues = Maps.transformValues(uriInfo.getPathParameters(), new Function, Object>() { @Override public Object apply(List input) { return input.isEmpty() ? null : input.get(0); } }); JerseyUriBuilder uriBuilder = new JerseyUriBuilder().uri(this.uri).resolveTemplates(pathParamValues); final ManagedClient managedClient = client.get(); if (!uriBuilder.isAbsolute()) { final String customBaseUri = managedClient.customBaseUri; final String rootUri = customBaseUri.isEmpty() ? uriInfo.getBaseUri().toString() : customBaseUri; uriBuilder = new JerseyUriBuilder().uri(rootUri).path(uriBuilder.toTemplate()); } return managedClient.instance.target(uriBuilder); } } /** * Initialize the provider. * * @param locator service locator to be used for injecting into the values factory. * @param serverConfig server-side configuration. */ @Inject public WebTargetValueFactoryProvider(final ServiceLocator locator, @Context final Configuration serverConfig) { super(null, locator, Parameter.Source.URI); this.serverConfig = serverConfig; this.managedClients = new ConcurrentHashMap>(); // init default client this.managedClients.put(BindingModel.EMPTY, Values.lazy(new Value() { @Override public ManagedClient get() { final Client client; if (serverConfig == null) { client = ClientBuilder.newClient(); } else { ClientConfig clientConfig = new ClientConfig(); copyProviders(serverConfig, clientConfig); client = ClientBuilder.newClient(clientConfig); } return new ManagedClient(client, ""); } })); } private void copyProviders(Configuration source, Configurable target) { for (Class c : source.getClasses()) { target.register(c, source.getContracts(c)); } for (Object o : source.getInstances()) { Class c = o.getClass(); target.register(c, source.getContracts(c)); } } @Override protected AbstractContainerRequestValueFactory createValueFactory(final Parameter parameter) { return Errors.processWithException(new Producer>() { @Override public AbstractContainerRequestValueFactory call() { String targetUriTemplate = parameter.getSourceName(); if (targetUriTemplate == null || targetUriTemplate.length() == 0) { // Invalid URI parameter name Errors.warning(this, LocalizationMessages.INJECTED_WEBTARGET_URI_INVALID(targetUriTemplate)); return null; } final Class rawParameterType = parameter.getRawType(); if (rawParameterType == WebTarget.class) { final BindingModel binding = BindingModel.create(Arrays.asList(parameter.getAnnotations())); Value client = managedClients.get(binding); if (client == null) { client = Values.lazy(new Value() { @Override public ManagedClient get() { final String prefix = binding.getAnnotation().annotationType().getName() + "."; final String baseUriProperty = prefix + "baseUri"; final Object bu = serverConfig.getProperty(baseUriProperty); final String customBaseUri = (bu != null) ? bu.toString() : binding.baseUri(); final String configClassProperty = prefix + "configClass"; final ClientConfig cfg = resolveConfig(configClassProperty, binding); final String inheritProvidersProperty = prefix + "inheritServerProviders"; if (PropertiesHelper.isProperty(serverConfig.getProperty(inheritProvidersProperty)) || binding.inheritProviders()) { copyProviders(serverConfig, cfg); } final String propertyPrefix = prefix + "property."; Collection clientProperties = Collections2.filter(serverConfig.getPropertyNames(), new Predicate() { @Override public boolean apply(String property) { return property.startsWith(propertyPrefix); } }); for (String property : clientProperties) { cfg.property(property.substring(propertyPrefix.length()), serverConfig.getProperty(property)); } return new ManagedClient(ClientBuilder.newClient(cfg), customBaseUri); } }); final Value previous = managedClients.putIfAbsent(binding, client); if (previous != null) { client = previous; } } return new WebTargetValueFactory(targetUriTemplate, client); } else { Errors.warning(this, LocalizationMessages.UNSUPPORTED_URI_INJECTION_TYPE(rawParameterType)); return null; } } }); } private ClientConfig resolveConfig(final String configClassProperty, final BindingModel binding) { Class configClass = binding.getConfigClass(); final Object _cc = serverConfig.getProperty(configClassProperty); if (_cc != null) { Class cc; if (_cc instanceof String) { cc = AccessController.doPrivileged(ReflectionHelper.classForNamePA((String) _cc)); } else if (_cc instanceof Class) { cc = (Class) _cc; } else { cc = null; // will cause a warning } if (cc != null && Configuration.class.isAssignableFrom(cc)) { configClass = cc.asSubclass(Configuration.class); } else { Errors.warning(this, LocalizationMessages.ILLEGAL_CLIENT_CONFIG_CLASS_PROPERTY_VALUE( configClassProperty, _cc, configClass.getName() )); } } final Configuration cfg = Injections.getOrCreate(getLocator(), configClass); return (cfg instanceof ClientConfig) ? (ClientConfig) cfg : new ClientConfig().loadFrom(cfg); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy