Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable @ConstrainedTo on Features #4055

Merged
merged 3 commits into from
Feb 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -106,23 +106,28 @@ private static final class FeatureRegistration {

private final Class<? extends Feature> featureClass;
private final Feature feature;
private final RuntimeType runtimeType;

private FeatureRegistration(final Class<? extends Feature> featureClass) {
this.featureClass = featureClass;
this.feature = null;
final ConstrainedTo runtimeTypeConstraint = featureClass.getAnnotation(ConstrainedTo.class);
this.runtimeType = runtimeTypeConstraint == null ? null : runtimeTypeConstraint.value();
}

private FeatureRegistration(final Feature feature) {
this.featureClass = feature.getClass();
this.feature = feature;
final ConstrainedTo runtimeTypeConstraint = featureClass.getAnnotation(ConstrainedTo.class);
this.runtimeType = runtimeTypeConstraint == null ? null : runtimeTypeConstraint.value();
}

/**
* Get the registered feature class.
*
* @return registered feature class.
*/
Class<? extends Feature> getFeatureClass() {
private Class<? extends Feature> getFeatureClass() {
return featureClass;
}

Expand All @@ -133,10 +138,21 @@ Class<? extends Feature> getFeatureClass() {
* @return the registered feature instance or {@code null} if this is a
* class based feature registration.
*/
public Feature getFeature() {
private Feature getFeature() {
return feature;
}

/**
* Get the {@code RuntimeType} constraint given by {@code ConstrainedTo} annotated
* the Feature or {@code null} if not annotated.
*
* @return the {@code RuntimeType} constraint given by {@code ConstrainedTo} annotated
* the Feature or {@code null} if not annotated.
*/
private RuntimeType getFeatureRuntimeType() {
return runtimeType;
}

@Override
public boolean equals(final Object obj) {
if (this == obj) {
Expand Down Expand Up @@ -653,6 +669,13 @@ private void configureFeatures(InjectionManager injectionManager,
continue;
}

final RuntimeType runtimeTypeConstraint = registration.getFeatureRuntimeType();
if (runtimeTypeConstraint != null && !type.equals(runtimeTypeConstraint)) {
LOGGER.config(LocalizationMessages.FEATURE_CONSTRAINED_TO_IGNORED(
registration.getFeatureClass(), registration.runtimeType, type));
continue;
}

Feature feature = registration.getFeature();
if (feature == null) {
feature = injectionManager.createAndInitialize(registration.getFeatureClass());
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -70,6 +70,7 @@ errors.and.warnings.detected=Following issues have been detected: {0}
exception.caught.while.loading.spi.providers=Exception caught while loading SPI providers.
exception.mapper.supported.type.unknown=Unable to retrieve the supported exception type for a registered exception mapper service class "{0}".
feature.has.already.been.processed=Feature [{0}] has already been processed.
feature.constrainedTo.ignored=Feature {0} registered in {2} runtime is constrained to {1} runtime and is ignored.
hint.msg=HINT: {0}
hints.detected=The following hints have been detected: {0}
http.header.comments.not.allowed=Comments are not allowed.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2018 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
Expand Down Expand Up @@ -287,7 +287,7 @@ private void copyProviders(Configuration source, Configurable<?> target) {
for (Object o : source.getInstances()) {
Class<?> c = o.getClass();
if (!targetConfig.isRegistered(o)) {
target.register(c, source.getContracts(c));
target.register(o, source.getContracts(c));
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/*
* Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/

package org.glassfish.jersey.tests.e2e.common;

import org.glassfish.jersey.server.ResourceConfig;
import org.glassfish.jersey.server.Uri;
import org.glassfish.jersey.test.JerseyTest;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import javax.ws.rs.ConstrainedTo;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.RuntimeType;
import javax.ws.rs.client.WebTarget;
import javax.ws.rs.core.Application;
import javax.ws.rs.core.Configuration;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Feature;
import javax.ws.rs.core.FeatureContext;
import java.util.concurrent.atomic.AtomicInteger;

public class FeatureConstraintTest extends JerseyTest {

public static AtomicInteger clientEnvironmentHitCount = new AtomicInteger(0);
public static AtomicInteger serverEnvironmentHitCount = new AtomicInteger(0);
public static AtomicInteger clientServerEnvironmentHitCount = new AtomicInteger(0);

@Override
protected Application configure() {
return new ResourceConfig(PropagatedConfigResource.class, ServerConstrainedClassFeature.class,
ClientConstrainedClassFeature.class, ClientServerConstrainedClassFeature.class)
.register(new ServerConstrainedInstanceFeature())
.register(new ClientConstrainedInstanceFeature())
.register(new ClientServerConstrainedInstanceFeature());
}

@ConstrainedTo(RuntimeType.SERVER)
public static class ServerConstrainedClassFeature implements Feature {
protected int increment = 10;
@Override
public boolean configure(FeatureContext context) {
if (context.getConfiguration().getRuntimeType().equals(RuntimeType.CLIENT)) {
clientEnvironmentHitCount.addAndGet(increment);
}
return true;
}
}

@ConstrainedTo(RuntimeType.SERVER)
public static class ServerConstrainedInstanceFeature extends ServerConstrainedClassFeature {
{
increment = 100;
}
};

@ConstrainedTo(RuntimeType.CLIENT)
public static class ClientConstrainedClassFeature implements Feature {
protected int increment = 10;
@Override
public boolean configure(FeatureContext context) {
if (context.getConfiguration().getRuntimeType().equals(RuntimeType.SERVER)) {
serverEnvironmentHitCount.addAndGet(increment);
}
return true;
}
}

@ConstrainedTo(RuntimeType.CLIENT)
public static class ClientConstrainedInstanceFeature extends ClientConstrainedClassFeature {
{
increment = 100;
}
};

public static class ClientServerConstrainedClassFeature implements Feature {
protected int increment = 10;
@Override
public boolean configure(FeatureContext context) {
if (context.getConfiguration().getRuntimeType().equals(RuntimeType.SERVER)) {
clientServerEnvironmentHitCount.addAndGet(increment);
}
if (context.getConfiguration().getRuntimeType().equals(RuntimeType.CLIENT)) {
clientServerEnvironmentHitCount.addAndGet(100 * increment);
}
return true;
}
}

public static class ClientServerConstrainedInstanceFeature extends ClientServerConstrainedClassFeature {
{
increment = 100;
}
};

@Path("/")
public static class PropagatedConfigResource {
@Uri("/isRegistered")
WebTarget target;

@Path("isRegistered")
@GET
public boolean isRegisteredOnServer(@Context Configuration config) {
return config.isRegistered(ServerConstrainedClassFeature.class)
&& config.isRegistered(ServerConstrainedInstanceFeature.class)
&& config.isRegistered(ClientConstrainedClassFeature.class)
&& config.isRegistered(ClientConstrainedInstanceFeature.class)
&& config.isRegistered(ClientServerConstrainedClassFeature.class)
&& config.isRegistered(ClientServerConstrainedInstanceFeature.class);
}

@Path("isInherited")
@GET
public boolean isInheritedInInjectedClientConfig() {
final Configuration config = target.getConfiguration();
return isRegisteredOnServer(config);
}

@Path("featureConfigurationNotInvoked")
@GET
public boolean featureConfigurationNotInvoked() {
return target
.register(ServerConstrainedClassFeature.class)
.register(new ServerConstrainedInstanceFeature())
.register(ClientConstrainedClassFeature.class)
.register(new ClientConstrainedInstanceFeature())
.register(ClientServerConstrainedClassFeature.class)
.register(new ClientServerConstrainedInstanceFeature())
.request().get().readEntity(boolean.class);
}
}

@Test
public void test() {
assertThat("*Constrained*Feature must be registered in a server configuration",
target("isRegistered")
.register(ServerConstrainedClassFeature.class)
.register(new ServerConstrainedInstanceFeature())
.register(ClientConstrainedClassFeature.class)
.register(new ClientConstrainedInstanceFeature())
.register(ClientServerConstrainedClassFeature.class)
.register(new ClientServerConstrainedInstanceFeature())
.request().get().readEntity(boolean.class),
is(true));

assertThat("Server Features should not have been configured on Client", clientEnvironmentHitCount.get(), is(0));
assertThat("Client Features should not have been configured on Server", serverEnvironmentHitCount.get(), is(0));
assertThat("ClientSever Features should have been configured", clientServerEnvironmentHitCount.get(), is(11110));
clientServerEnvironmentHitCount.set(0); //reset configuration invoked on a server, it won't happen again

assertThat("*Constrained*Feature must be in an application classes set",
target("isInherited").request().get().readEntity(boolean.class),
is(true));

assertThat("Server Features should not have been configured on Client", clientEnvironmentHitCount.get(), is(0));
assertThat("Client Features should not have been configured on Server", serverEnvironmentHitCount.get(), is(0));
assertThat("ClientSever Features should not have been configured", clientServerEnvironmentHitCount.get(), is(0));

assertThat("ServerConstrainedFeature must be in an application classes set",
target("featureConfigurationNotInvoked")
.register(ServerConstrainedClassFeature.class)
.register(new ServerConstrainedInstanceFeature())
.register(ClientConstrainedClassFeature.class)
.register(new ClientConstrainedInstanceFeature())
.register(ClientServerConstrainedClassFeature.class)
.register(new ClientServerConstrainedInstanceFeature())
.request().get().readEntity(boolean.class),
is(true));

assertThat("Server Features should not have been configured on Client", clientEnvironmentHitCount.get(), is(0));
assertThat("Client Features should not have been configured on Server", serverEnvironmentHitCount.get(), is(0));
assertThat("ClientSever Features should have been configured", clientServerEnvironmentHitCount.get(), is(22000));
}


}