use of io.quarkus.deployment.Feature in project quarkus by quarkusio.
the class RestClientReactiveProcessor method registerProvidersFromAnnotations.
/**
* Creates an implementation of `AnnotationRegisteredProviders` class with a constructor that:
* <ul>
* <li>puts all the providers registered by the @RegisterProvider annotation in a
* map using the {@link AnnotationRegisteredProviders#addProviders(String, Map)} method</li>
* <li>registers all the provider implementations annotated with @Provider using
* {@link AnnotationRegisteredProviders#addGlobalProvider(Class, int)}</li>
* </ul>
*
* @param indexBuildItem index
* @param generatedBeans build producer for generated beans
*/
@BuildStep
void registerProvidersFromAnnotations(CombinedIndexBuildItem indexBuildItem, BuildProducer<GeneratedBeanBuildItem> generatedBeans, BuildProducer<GeneratedClassBuildItem> generatedClasses, BuildProducer<UnremovableBeanBuildItem> unremovableBeans, BuildProducer<ReflectiveClassBuildItem> reflectiveClasses, RestClientReactiveConfig clientConfig) {
String annotationRegisteredProvidersImpl = AnnotationRegisteredProviders.class.getName() + "Implementation";
IndexView index = indexBuildItem.getIndex();
Map<String, List<AnnotationInstance>> annotationsByClassName = new HashMap<>();
for (AnnotationInstance annotation : index.getAnnotations(REGISTER_PROVIDER)) {
String targetClass = annotation.target().asClass().name().toString();
annotationsByClassName.computeIfAbsent(targetClass, key -> new ArrayList<>()).add(annotation);
}
for (AnnotationInstance annotation : index.getAnnotations(REGISTER_PROVIDERS)) {
String targetClass = annotation.target().asClass().name().toString();
annotationsByClassName.computeIfAbsent(targetClass, key -> new ArrayList<>()).addAll(asList(annotation.value().asNestedArray()));
}
try (ClassCreator classCreator = ClassCreator.builder().className(annotationRegisteredProvidersImpl).classOutput(new GeneratedBeanGizmoAdaptor(generatedBeans)).superClass(AnnotationRegisteredProviders.class).build()) {
classCreator.addAnnotation(Singleton.class.getName());
MethodCreator constructor = classCreator.getMethodCreator(MethodDescriptor.ofConstructor(annotationRegisteredProvidersImpl));
constructor.invokeSpecialMethod(MethodDescriptor.ofConstructor(AnnotationRegisteredProviders.class), constructor.getThis());
if (clientConfig.providerAutodiscovery) {
for (AnnotationInstance instance : index.getAnnotations(ResteasyReactiveDotNames.PROVIDER)) {
ClassInfo providerClass = instance.target().asClass();
// ignore providers annotated with `@ConstrainedTo(SERVER)`
AnnotationInstance constrainedToInstance = providerClass.classAnnotation(ResteasyReactiveDotNames.CONSTRAINED_TO);
if (constrainedToInstance != null) {
if (RuntimeType.valueOf(constrainedToInstance.value().asEnum()) == RuntimeType.SERVER) {
continue;
}
}
if (providerClass.interfaceNames().contains(ResteasyReactiveDotNames.FEATURE)) {
// features should not be automatically registered for the client, see javadoc for Feature
continue;
}
int priority = getAnnotatedPriority(index, providerClass.name().toString(), Priorities.USER);
constructor.invokeVirtualMethod(MethodDescriptor.ofMethod(AnnotationRegisteredProviders.class, "addGlobalProvider", void.class, Class.class, int.class), constructor.getThis(), constructor.loadClassFromTCCL(providerClass.name().toString()), constructor.load(priority));
}
}
Map<String, ClientExceptionMapperHandler.Result> ifaceToGeneratedMapper = new HashMap<>();
ClientExceptionMapperHandler clientExceptionMapperHandler = new ClientExceptionMapperHandler(new GeneratedClassGizmoAdaptor(generatedClasses, true));
for (AnnotationInstance instance : index.getAnnotations(CLIENT_EXCEPTION_MAPPER)) {
ClientExceptionMapperHandler.Result result = clientExceptionMapperHandler.generateResponseExceptionMapper(instance);
if (ifaceToGeneratedMapper.containsKey(result.interfaceName)) {
throw new IllegalStateException("Only a single instance of '" + CLIENT_EXCEPTION_MAPPER + "' is allowed per REST Client interface. Offending class is '" + result.interfaceName + "'");
}
ifaceToGeneratedMapper.put(result.interfaceName, result);
reflectiveClasses.produce(new ReflectiveClassBuildItem(true, false, false, false, result.generatedClassName));
}
for (Map.Entry<String, List<AnnotationInstance>> annotationsForClass : annotationsByClassName.entrySet()) {
ResultHandle map = constructor.newInstance(MethodDescriptor.ofConstructor(HashMap.class));
for (AnnotationInstance value : annotationsForClass.getValue()) {
String className = value.value().asString();
AnnotationValue priorityAnnotationValue = value.value("priority");
int priority;
if (priorityAnnotationValue == null) {
priority = getAnnotatedPriority(index, className, Priorities.USER);
} else {
priority = priorityAnnotationValue.asInt();
}
constructor.invokeInterfaceMethod(MAP_PUT, map, constructor.loadClassFromTCCL(className), constructor.load(priority));
}
String ifaceName = annotationsForClass.getKey();
if (ifaceToGeneratedMapper.containsKey(ifaceName)) {
// remove the interface from the generated mapper since it's going to be handled now
// the remaining entries will be handled later
ClientExceptionMapperHandler.Result result = ifaceToGeneratedMapper.remove(ifaceName);
constructor.invokeInterfaceMethod(MAP_PUT, map, constructor.loadClass(result.generatedClassName), constructor.load(result.priority));
}
constructor.invokeVirtualMethod(MethodDescriptor.ofMethod(AnnotationRegisteredProviders.class, "addProviders", void.class, String.class, Map.class), constructor.getThis(), constructor.load(ifaceName), map);
}
// add the remaining generated mappers
for (Map.Entry<String, ClientExceptionMapperHandler.Result> entry : ifaceToGeneratedMapper.entrySet()) {
ResultHandle map = constructor.newInstance(MethodDescriptor.ofConstructor(HashMap.class));
constructor.invokeInterfaceMethod(MAP_PUT, map, constructor.loadClass(entry.getValue().generatedClassName), constructor.load(entry.getValue().priority));
constructor.invokeVirtualMethod(MethodDescriptor.ofMethod(AnnotationRegisteredProviders.class, "addProviders", void.class, String.class, Map.class), constructor.getThis(), constructor.load(entry.getKey()), map);
}
constructor.returnValue(null);
}
unremovableBeans.produce(UnremovableBeanBuildItem.beanClassNames(annotationRegisteredProvidersImpl));
}
use of io.quarkus.deployment.Feature in project quarkus by quarkusio.
the class InfinispanClientProcessor method setup.
@BuildStep
InfinispanPropertiesBuildItem setup(ApplicationArchivesBuildItem applicationArchivesBuildItem, BuildProducer<ReflectiveClassBuildItem> reflectiveClass, BuildProducer<HotDeploymentWatchedFileBuildItem> hotDeployment, BuildProducer<SystemPropertyBuildItem> systemProperties, BuildProducer<FeatureBuildItem> feature, BuildProducer<AdditionalBeanBuildItem> additionalBeans, BuildProducer<ExtensionSslNativeSupportBuildItem> sslNativeSupport, BuildProducer<NativeImageSecurityProviderBuildItem> nativeImageSecurityProviders, BuildProducer<NativeImageConfigBuildItem> nativeImageConfig, CombinedIndexBuildItem applicationIndexBuildItem) throws ClassNotFoundException, IOException {
feature.produce(new FeatureBuildItem(Feature.INFINISPAN_CLIENT));
additionalBeans.produce(AdditionalBeanBuildItem.unremovableOf(InfinispanClientProducer.class));
systemProperties.produce(new SystemPropertyBuildItem("io.netty.noUnsafe", "true"));
hotDeployment.produce(new HotDeploymentWatchedFileBuildItem(META_INF + File.separator + HOTROD_CLIENT_PROPERTIES));
// Enable SSL support by default
sslNativeSupport.produce(new ExtensionSslNativeSupportBuildItem(Feature.INFINISPAN_CLIENT));
nativeImageSecurityProviders.produce(new NativeImageSecurityProviderBuildItem(SASL_SECURITY_PROVIDER));
InputStream stream = Thread.currentThread().getContextClassLoader().getResourceAsStream(META_INF + "/" + HOTROD_CLIENT_PROPERTIES);
Properties properties;
if (stream == null) {
properties = new Properties();
if (log.isTraceEnabled()) {
log.trace("There was no hotrod-client.properties file found - using defaults");
}
} else {
try {
properties = loadFromStream(stream);
if (log.isDebugEnabled()) {
log.debugf("Found HotRod properties of %s", properties);
}
} finally {
Util.close(stream);
}
// We use caffeine for bounded near cache - so register that reflection if we have a bounded near cache
if (properties.containsKey(ConfigurationProperties.NEAR_CACHE_MAX_ENTRIES)) {
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, "com.github.benmanes.caffeine.cache.SSMS"));
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, "com.github.benmanes.caffeine.cache.PSMS"));
}
}
InfinispanClientProducer.replaceProperties(properties);
IndexView index = applicationIndexBuildItem.getIndex();
// This is always non null
Object marshaller = properties.get(ConfigurationProperties.MARSHALLER);
if (marshaller instanceof ProtoStreamMarshaller) {
for (ApplicationArchive applicationArchive : applicationArchivesBuildItem.getAllApplicationArchives()) {
// If we have properties file we may have to care about
Path metaPath = applicationArchive.getChildPath(META_INF);
if (metaPath != null) {
try (Stream<Path> dirElements = Files.list(metaPath)) {
Iterator<Path> protoFiles = dirElements.filter(Files::isRegularFile).filter(p -> p.toString().endsWith(PROTO_EXTENSION)).iterator();
// We monitor the entire meta inf directory if properties are available
if (protoFiles.hasNext()) {
// Quarkus doesn't currently support hot deployment watching directories
// hotDeployment.produce(new HotDeploymentConfigFileBuildItem(META_INF));
}
while (protoFiles.hasNext()) {
Path path = protoFiles.next();
if (log.isDebugEnabled()) {
log.debug(" " + path.toAbsolutePath());
}
byte[] bytes = Files.readAllBytes(path);
// This uses the default file encoding - should we enforce UTF-8?
properties.put(InfinispanClientProducer.PROTOBUF_FILE_PREFIX + path.getFileName().toString(), new String(bytes, StandardCharsets.UTF_8));
}
}
}
}
InfinispanClientProducer.handleProtoStreamRequirements(properties);
Collection<ClassInfo> initializerClasses = index.getAllKnownImplementors(DotName.createSimple(SerializationContextInitializer.class.getName()));
initializerClasses.addAll(index.getAllKnownImplementors(DotName.createSimple(GeneratedSchema.class.getName())));
Set<SerializationContextInitializer> initializers = new HashSet<>(initializerClasses.size());
for (ClassInfo ci : initializerClasses) {
Class<?> initializerClass = Thread.currentThread().getContextClassLoader().loadClass(ci.toString());
try {
SerializationContextInitializer sci = (SerializationContextInitializer) initializerClass.getDeclaredConstructor().newInstance();
initializers.add(sci);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
// This shouldn't ever be possible as annotation processor should generate empty constructor
throw new RuntimeException(e);
}
}
if (!initializers.isEmpty()) {
properties.put(InfinispanClientProducer.PROTOBUF_INITIALIZERS, initializers);
}
}
// Add any user project listeners to allow reflection in native code
Collection<AnnotationInstance> listenerInstances = index.getAnnotations(DotName.createSimple(ClientListener.class.getName()));
for (AnnotationInstance instance : listenerInstances) {
AnnotationTarget target = instance.target();
if (target.kind() == AnnotationTarget.Kind.CLASS) {
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, target.asClass().name().toString()));
}
}
// This is required for netty to work properly
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, "io.netty.channel.socket.nio.NioSocketChannel"));
// We use reflection to have continuous queries work
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, "org.infinispan.client.hotrod.event.impl.ContinuousQueryImpl$ClientEntryListener"));
// We use reflection to allow for near cache invalidations
reflectiveClass.produce(new ReflectiveClassBuildItem(true, false, "org.infinispan.client.hotrod.near.NearCacheService$InvalidatedNearCacheListener"));
// This is required when a cache is clustered to tell us topology
reflectiveClass.produce(new ReflectiveClassBuildItem(false, false, "org.infinispan.client.hotrod.impl.consistenthash.SegmentConsistentHash"));
return new InfinispanPropertiesBuildItem(properties);
}
Aggregations