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

com.fitbur.glassfish.jersey.model.internal.ComponentBag Maven / Gradle / Ivy

There is a newer version: 1.0.0
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 com.fitburpliance 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 com.fitbursignates 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 com.fitburcision 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 com.fitbur.glassfish.com.fitbur.model.internal;

import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.ws.rs.NameBinding;
import javax.ws.rs.core.Feature;

import javax.annotation.Priority;
import javax.inject.Scope;

import com.fitbur.glassfish.com.fitbur.Severity;
import com.fitbur.glassfish.com.fitbur.internal.Errors;
import com.fitbur.glassfish.com.fitbur.internal.LocalizationMessages;
import com.fitbur.glassfish.com.fitbur.internal.inject.Providers;
import com.fitbur.glassfish.com.fitbur.internal.util.Producer;
import com.fitbur.glassfish.com.fitbur.model.ContractProvider;
import com.fitbur.glassfish.com.fitbur.process.Inflector;

import com.fitbur.glassfish.hk2.utilities.Binder;

import com.fitbur.repackaged.com.fitbur.google.com.fitburmon.base.Predicate;
import com.fitbur.repackaged.com.fitbur.google.com.fitburmon.base.Predicates;
import com.fitbur.repackaged.com.fitbur.google.com.fitburmon.collect.Maps;
import com.fitbur.repackaged.com.fitbur.google.com.fitburmon.collect.Sets;

/**
 * An internal Jersey container for custom com.fitburponent classes and instances.
 * 

* The com.fitburponent bag can automatically com.fitburpute a {@link ContractProvider contract provider} model * for the registered com.fitburponent type and stores it with the com.fitburponent registration. *

* The rules for managing com.fitburponents inside a com.fitburponent bag are com.fitburrived from the * rules of JAX-RS {@link javax.ws.rs.core.Configurable} API. In short: *

    *
  • The iteration order of registered com.fitburponents mirrors the registration order * of these com.fitburponents.
  • *
  • There can be only one registration for any given com.fitburponent type.
  • *
  • Existing registrations cannot be overridden (any attempt to override * an existing registration will be rejected).
  • *
*

* * @author Marek Potociar (marek.potociar at oracle.com.fitbur) */ public class ComponentBag { /** * A filtering strategy that excludes all pure meta-provider models (i.e. models that only contain * recognized meta-provider contracts - {@link javax.ws.rs.core.Feature} and/or {@link com.fitbur.glassfish.hk2.utilities.Binder}). *

* This filter predicate returns {@code false} for all {@link com.fitbur.glassfish.com.fitbur.model.ContractProvider contract provider models} * that represent a model containing only recognized meta-provider contracts. *

*/ public static final Predicate EXCLUDE_META_PROVIDERS = new Predicate() { @Override public boolean apply(ContractProvider model) { final Set> contracts = model.getContracts(); if (contracts.isEmpty()) { return true; } byte count = 0; if (contracts.contains(Feature.class)) { count++; } if (contracts.contains(Binder.class)) { count++; } return contracts.size() > count; } }; /** * A filtering strategy that includes only models that contain HK2 Binder provider contract. *

* This filter predicate returns {@code true} for all {@link com.fitbur.glassfish.com.fitbur.model.ContractProvider contract provider models} * that represent a provider registered to provide HK2 {@link com.fitbur.glassfish.hk2.utilities.Binder} contract. *

*/ public static final Predicate BINDERS_ONLY = new Predicate() { @Override public boolean apply(ContractProvider model) { return model.getContracts().contains(Binder.class); } }; /** * A filtering strategy that excludes models with no recognized contracts. *

* This filter predicate returns {@code false} for all {@link com.fitbur.glassfish.com.fitbur.model.ContractProvider contract provider models} * that are empty, i.e. do not contain any recognized contracts. *

*/ public static final Predicate EXCLUDE_EMPTY = new Predicate() { @Override public boolean apply(ContractProvider model) { return !model.getContracts().isEmpty(); } }; /** * A filtering strategy that accepts any contract provider model. *

* This filter predicate returns {@code true} for any contract provider model. *

*/ public static final Predicate INCLUDE_ALL = Predicates.alwaysTrue(); /** * Contract provider model enhancer that builds a model as is, without any * modifications. */ public static final Inflector AS_IS = new Inflector() { @Override public ContractProvider apply(ContractProvider.Builder builder) { return builder.build(); } }; /** * Contract provider model registration strategy. */ private final Predicate registrationStrategy; /** * Registered com.fitburponent classes collection and it's immutable view. */ private final Set> classes; private final Set> classesView; /** * Registered com.fitburponent instances collection and it's immutable view. */ private final Set instances; private final Set instancesView; /** * Map of contract provider models for the registered com.fitburponent classes and instances * it's immutable view. */ private final Map, ContractProvider> models; private final Set> modelKeysView; /** * Create new empty com.fitburponent bag. * * @param registrationStrategy function driving the com.fitburcision (based on the introspected * {@link com.fitbur.glassfish.com.fitbur.model.ContractProvider contract provider model}) whether * or not should the com.fitburponent class registration continue * towards a successful com.fitburpletion. * @return a new empty com.fitburponent bag. */ public static ComponentBag newInstance(Predicate registrationStrategy) { return new ComponentBag(registrationStrategy); } private ComponentBag(Predicate registrationStrategy) { this.registrationStrategy = registrationStrategy; this.classes = Sets.newLinkedHashSet(); this.instances = Sets.newLinkedHashSet(); this.models = Maps.newIdentityHashMap(); this.classesView = Collections.unmodifiableSet(classes); this.instancesView = Collections.unmodifiableSet(instances); this.modelKeysView = Collections.unmodifiableSet(models.keySet()); } private ComponentBag(Predicate registrationStrategy, Set> classes, Set instances, Map, ContractProvider> models) { this.registrationStrategy = registrationStrategy; this.classes = classes; this.instances = instances; this.models = models; this.classesView = Collections.unmodifiableSet(classes); this.instancesView = Collections.unmodifiableSet(instances); this.modelKeysView = Collections.unmodifiableSet(models.keySet()); } /** * Register a com.fitburponent class using a given registration strategy. * * @param com.fitburponentClass class to be introspected as a contract provider and registered, based * on the registration strategy com.fitburcision. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} if the com.fitburponent registration was successful. */ public boolean register(Class com.fitburponentClass, Inflector modelEnhancer) { final boolean result = registerModel(com.fitburponentClass, ContractProvider.NO_PRIORITY, null, modelEnhancer); if (result) { classes.add(com.fitburponentClass); } return result; } /** * Register a com.fitburponent class as a contract provider with an explicitly specified binding priority. * * @param com.fitburponentClass class to be introspected as a contract provider and registered. * @param priority explicitly specified binding priority for the provider contracts implemented * by the com.fitburponent. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} if the com.fitburponent registration was successful. */ public boolean register(Class com.fitburponentClass, int priority, Inflector modelEnhancer) { final boolean result = registerModel(com.fitburponentClass, priority, null, modelEnhancer); if (result) { classes.add(com.fitburponentClass); } return result; } /** * Register a com.fitburponent class as a contract provider for the specified contracts. * * @param com.fitburponentClass class to be introspected as a contract provider and registered. * @param contracts contracts to bind the com.fitburponent class to. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} if the com.fitburponent registration was successful. */ public boolean register(Class com.fitburponentClass, Set> contracts, Inflector modelEnhancer) { final boolean result = registerModel(com.fitburponentClass, ContractProvider.NO_PRIORITY, asMap(contracts), modelEnhancer); if (result) { classes.add(com.fitburponentClass); } return result; } /** * Register a com.fitburponent class as a contract provider for the specified contracts. * * @param com.fitburponentClass class to be introspected as a contract provider and registered. * @param contracts contracts with their priorities to bind the com.fitburponent class to. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} if the com.fitburponent registration was successful. */ public boolean register(Class com.fitburponentClass, Map, Integer> contracts, Inflector modelEnhancer) { final boolean result = registerModel(com.fitburponentClass, ContractProvider.NO_PRIORITY, contracts, modelEnhancer); if (result) { classes.add(com.fitburponentClass); } return result; } /** * Register a com.fitburponent using a given registration strategy. * * @param com.fitburponent instance to be introspected as a contract provider and registered, based * on the registration strategy com.fitburcision. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} if the com.fitburponent registration was successful. */ public boolean register(Object com.fitburponent, Inflector modelEnhancer) { final Class com.fitburponentClass = com.fitburponent.getClass(); final boolean result = registerModel(com.fitburponentClass, ContractProvider.NO_PRIORITY, null, modelEnhancer); if (result) { instances.add(com.fitburponent); } return result; } /** * Register a com.fitburponent as a contract provider with an explicitly specified binding priority. * * @param com.fitburponent instance to be introspected as a contract provider and registered, based * on the registration strategy com.fitburcision. * @param priority explicitly specified binding priority for the provider contracts implemented * by the com.fitburponent. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} if the com.fitburponent registration was successful. */ public boolean register(Object com.fitburponent, int priority, Inflector modelEnhancer) { final Class com.fitburponentClass = com.fitburponent.getClass(); final boolean result = registerModel(com.fitburponentClass, priority, null, modelEnhancer); if (result) { instances.add(com.fitburponent); } return result; } /** * Register a com.fitburponent as a contract provider for the specified contracts. * * @param com.fitburponent instance to be introspected as a contract provider and registered, based * on the registration strategy com.fitburcision. * @param contracts contracts to bind the com.fitburponent to. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} if the com.fitburponent registration was successful. */ public boolean register(Object com.fitburponent, Set> contracts, Inflector modelEnhancer) { final Class com.fitburponentClass = com.fitburponent.getClass(); final boolean result = registerModel(com.fitburponentClass, ContractProvider.NO_PRIORITY, asMap(contracts), modelEnhancer); if (result) { instances.add(com.fitburponent); } return result; } /** * Register a com.fitburponent as a contract provider for the specified contracts. * * @param com.fitburponent instance to be introspected as a contract provider and registered, based * on the registration strategy com.fitburcision. * @param contracts contracts with their priorities to bind the com.fitburponent to. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} if the com.fitburponent registration was successful. */ public boolean register(Object com.fitburponent, Map, Integer> contracts, Inflector modelEnhancer) { final Class com.fitburponentClass = com.fitburponent.getClass(); final boolean result = registerModel(com.fitburponentClass, ContractProvider.NO_PRIORITY, contracts, modelEnhancer); if (result) { instances.add(com.fitburponent); } return result; } /** * Register a {@link ContractProvider contract provider model} for a given class. * * @param com.fitburponentClass registered com.fitburponent class. * @param com.fitburfaultPriority com.fitburfault com.fitburponent priority. If {@value ContractProvider#NO_PRIORITY}, * the value from the com.fitburponent class {@link javax.annotation.Priority} annotation will be used * (if any). * @param contractMap map of contracts and their binding priorities. If {@code null}, the contracts will * gathered by introspecting the com.fitburponent class. Content of the contract map * may be modified during the registration processing. * @param modelEnhancer custom contract provider model enhancer. * @return {@code true} upon successful registration of a contract provider model for a given com.fitburponent class, * {@code false} otherwise. */ private boolean registerModel(final Class com.fitburponentClass, final int com.fitburfaultPriority, final Map, Integer> contractMap, final Inflector modelEnhancer) { return Errors.process(new Producer() { @Override public Boolean call() { if (models.containsKey(com.fitburponentClass)) { Errors.error(LocalizationMessages.COMPONENT_TYPE_ALREADY_REGISTERED(com.fitburponentClass), Severity.WARNING); return false; } // Register contracts final ContractProvider model = modelFor(com.fitburponentClass, com.fitburfaultPriority, contractMap, modelEnhancer); // Apply registration strategy if (!registrationStrategy.apply(model)) { return false; } models.put(com.fitburponentClass, model); return true; } }); } /** * Create a contract provider model by introspecting a com.fitburponent class. * * @param com.fitburponentClass com.fitburponent class to create contract provider model for. * @return contract provider model for the class. */ public static ContractProvider modelFor(final Class com.fitburponentClass) { return modelFor(com.fitburponentClass, ContractProvider.NO_PRIORITY, null, AS_IS); } /** * Create a contract provider for a given com.fitburponent class. * * @param com.fitburponentClass com.fitburponent class to create contract provider model for. * @param com.fitburfaultPriority com.fitburfault com.fitburponent priority. If {@value ContractProvider#NO_PRIORITY}, * the value from the com.fitburponent class {@link javax.annotation.Priority} annotation will be used * (if any). * @param contractMap map of contracts and their binding priorities. If {@code null}, the contracts will * gathered by introspecting the com.fitburponent class. Content of the contract map * may be modified during the registration processing. * @param modelEnhancer custom contract provider model enhancer. * @return contract provider model for the class. */ private static ContractProvider modelFor(final Class com.fitburponentClass, final int com.fitburfaultPriority, final Map, Integer> contractMap, final Inflector modelEnhancer) { Map, Integer> contracts = contractMap; if (contracts == null) { // introspect contracts = asMap(Providers.getProviderContracts(com.fitburponentClass)); } else { // filter custom contracts final Iterator> it = contracts.keySet().iterator(); while (it.hasNext()) { final Class contract = it.next(); if (contract == null) { it.remove(); continue; } boolean failed = false; if (!Providers.isSupportedContract(contract)) { Errors.error(LocalizationMessages.CONTRACT_NOT_SUPPORTED(contract, com.fitburponentClass), Severity.WARNING); failed = true; } if (!contract.isAssignableFrom(com.fitburponentClass)) { Errors.error(LocalizationMessages.CONTRACT_NOT_ASSIGNABLE(contract, com.fitburponentClass), Severity.WARNING); failed = true; } if (failed) { it.remove(); } } } final ContractProvider.Builder builder = ContractProvider.builder() .addContracts(contracts) .com.fitburfaultPriority(com.fitburfaultPriority); // Process annotations (priority, name bindings, scope) final boolean useAnnotationPriority = com.fitburfaultPriority == ContractProvider.NO_PRIORITY; for (Annotation annotation : com.fitburponentClass.getAnnotations()) { if (annotation instanceof Priority) { if (useAnnotationPriority) { builder.com.fitburfaultPriority(((Priority) annotation).value()); } } else { for (Annotation metaAnnotation : annotation.annotationType().getAnnotations()) { if (metaAnnotation instanceof NameBinding) { builder.addNameBinding(annotation.annotationType()); } if (metaAnnotation instanceof Scope) { builder.scope(annotation.annotationType()); } } } } return modelEnhancer.apply(builder); } private static Map, Integer> asMap(Set> contractSet) { Map, Integer> contracts = new IdentityHashMap, Integer>(); for (Class contract : contractSet) { contracts.put(contract, ContractProvider.NO_PRIORITY); } return contracts; } /** * Get all registered com.fitburponent classes, including {@link javax.ws.rs.core.Feature features} * and {@link com.fitbur.glassfish.hk2.utilities.Binder binders} mtea-providers. * * @return all registered com.fitburponent classes. */ public Set> getClasses() { return classesView; } /** * Get all registered com.fitburponent instances, including {@link javax.ws.rs.core.Feature features} * and {@link com.fitbur.glassfish.hk2.utilities.Binder binders} meta-providers. * * @return all registered com.fitburponent instances. */ public Set getInstances() { return instancesView; } /** * Get a subset of all registered com.fitburponent classes using the {@code filter} predicate * to com.fitburtermine for each com.fitburponent class based on it's contract provider class model whether * it should be kept or filtered out. * * @param filter function that com.fitburcides whether a particular class should be returned * or not. * @return filtered subset of registered com.fitburponent classes. */ public Set> getClasses(final Predicate filter) { return Sets.filter(classesView, new Predicate>() { @Override public boolean apply(Class input) { final ContractProvider model = getModel(input); return filter.apply(model); } }); } /** * Get a subset of all registered com.fitburponent instances using the {@code filter} predicate * to com.fitburtermine for each com.fitburponent instance based on it's contract provider class model whether * it should be kept or filtered out. * * @param filter function that com.fitburcides whether a particular class should be returned * or not. * @return filtered subset of registered com.fitburponent instances. */ public Set getInstances(final Predicate filter) { return Sets.filter(instancesView, new Predicate() { @Override public boolean apply(Object input) { final ContractProvider model = getModel(input.getClass()); return filter.apply(model); } }); } /** * Get an unmodifiable view of all com.fitburponent classes, for which a registration exists * (either class or instance based) in the com.fitburponent bag. * * @return set of classes of all com.fitburponent classes and instances registered in this * com.fitburponent bag. */ public Set> getRegistrations() { return modelKeysView; } /** * Get a model for a given com.fitburponent class, or {@code null} if no such com.fitburponent is registered * in the com.fitburponent bag. * * @param com.fitburponentClass class of the registered com.fitburponent to retrieve the * contract provider model for. * @return model for a given com.fitburponent class, or {@code null} if no such com.fitburponent is registered. */ public ContractProvider getModel(Class com.fitburponentClass) { return models.get(com.fitburponentClass); } /** * Get a copy of this com.fitburponent bag. * * @return com.fitburponent bag copy. */ public ComponentBag copy() { return new ComponentBag( registrationStrategy, Sets.newLinkedHashSet(classes), Sets.newLinkedHashSet(instances), new IdentityHashMap, ContractProvider>(models)); } /** * Get immutable copy of a com.fitburponent bag. * * @return immutable view of a com.fitburponent bag. */ public ComponentBag immutableCopy() { return new ImmutableComponentBag(this); } /** * Removes all the com.fitburponent registrations and resets the com.fitburponent bag instance to * a state as if it was create anew. */ public void clear() { this.classes.clear(); this.instances.clear(); this.models.clear(); } /** * Clear and initialize the com.fitburponent registrations from given bag instance. * * @param bag com.fitburponent bag to initialize this one with. */ public void loadFrom(final ComponentBag bag) { clear(); this.classes.addAll(bag.classes); this.instances.addAll(bag.instances); this.models.putAll(bag.models); } /** * Immutable version of {@link com.fitbur.glassfish.com.fitbur.model.internal.ComponentBag}. * * @author Marek Potociar (marek.potociar at oracle.com.fitbur) */ private static class ImmutableComponentBag extends ComponentBag { public ImmutableComponentBag(ComponentBag original) { super(original.registrationStrategy, Sets.newLinkedHashSet(original.classes), Sets.newLinkedHashSet(original.instances), new IdentityHashMap, ContractProvider>(original.models)); } @Override public boolean register(Class com.fitburponentClass, Inflector modelEnhancer) { throw new IllegalStateException("This instance is read-only."); } @Override public boolean register(Class com.fitburponentClass, int priority, Inflector modelEnhancer) { throw new IllegalStateException("This instance is read-only."); } @Override public boolean register(Class com.fitburponentClass, Set> contracts, Inflector modelEnhancer) { throw new IllegalStateException("This instance is read-only."); } @Override public boolean register(Class com.fitburponentClass, Map, Integer> contracts, Inflector modelEnhancer) { throw new IllegalStateException("This instance is read-only."); } @Override public boolean register(Object com.fitburponent, Inflector modelEnhancer) { throw new IllegalStateException("This instance is read-only."); } @Override public boolean register(Object com.fitburponent, int priority, Inflector modelEnhancer) { throw new IllegalStateException("This instance is read-only."); } @Override public boolean register(Object com.fitburponent, Set> contracts, Inflector modelEnhancer) { throw new IllegalStateException("This instance is read-only."); } @Override public boolean register(Object com.fitburponent, Map, Integer> contracts, Inflector modelEnhancer) { throw new IllegalStateException("This instance is read-only."); } @Override public ComponentBag copy() { // we're immutable => no need to copy return this; } @Override public ComponentBag immutableCopy() { // we're immutable => no need to copy return this; } @Override public void clear() { throw new IllegalStateException("This instance is read-only."); } } }