Skip to content
Closed
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
Expand Up @@ -16,6 +16,7 @@
import com.predic8.membrane.annot.generator.*;
import com.predic8.membrane.annot.generator.kubernetes.*;
import com.predic8.membrane.annot.model.*;
import jakarta.annotation.Resource;

import javax.annotation.processing.*;
import javax.lang.model.*;
Expand Down Expand Up @@ -172,10 +173,11 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
// * in the last round, "roundEnv.processingOver()" is true
try {

String status = "process() a=" + annotations.size() +
" r=" + roundEnv.getRootElements().size() +
" h=" + hashCode() +
(roundEnv.processingOver() ? " processing-over" : " ");
String status = "process() a=%d r=%d h=%d%s".formatted(
annotations.size(),
roundEnv.getRootElements().size(),
hashCode(),
roundEnv.processingOver() ? " processing-over" : " ");
log(status);

read();
Expand All @@ -184,7 +186,10 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment

if (!annotations.isEmpty()) { // a class with one of our annotation needs to be compiled

status = "working with " + getCachedElementsAnnotatedWith(roundEnv, MCMain.class).size() + " and " + getCachedElementsAnnotatedWith(roundEnv, MCElement.class).size();
status = "working with %d and %d and %d".formatted(
getCachedElementsAnnotatedWith(roundEnv, MCMain.class).size(),
getCachedElementsAnnotatedWith(roundEnv, MCElement.class).size(),
getCachedElementsAnnotatedWith(roundEnv, Resource.class).size());
log(status);

Model m = new Model();
Expand Down Expand Up @@ -287,6 +292,10 @@ public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment
}
}

for (Element element : getCachedElementsAnnotatedWith(roundEnv, Resource.class)) {
m.getResources().add((TypeElement) element);
}

process(m);
}

Expand Down Expand Up @@ -524,6 +533,7 @@ public void process(Model m) throws IOException {
new Parsers(processingEnv).writeParserDefinitior(m);
new HelpReference(processingEnv).writeHelp(m);
new NamespaceInfo(processingEnv).writeInfo(m);
new ResourceInfo(processingEnv).write(m);
if (processingEnv.getElementUtils().getTypeElement("org.apache.aries.blueprint.ParserContext") != null) {
new BlueprintParsers(processingEnv).writeParserDefinitior(m);
new BlueprintParsers(processingEnv).writeParsers(m);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,14 @@ public interface BeanRegistry {
void register(String beanName, Object bean);

/**
* Registers a bean of the specified type with the given name if it is not already registered.
* If a bean with the given name is already present, the existing instance is returned.
* Otherwise, the supplier is used to create and register a new instance.
* Registers a bean of the specified type with the given name, if no other bean of the given type is registered.
* The supplier is only called, when the bean creation is requested, but no other bean of the given type has been
* registered.
* @param type the class type of the bean
* @param supplier a supplier that provides a new instance of the bean if not already registered
* @param <T> the generic type of the bean
* @return the existing or newly created and registered bean instance
*/
<T> T registerIfAbsent(Class<T> type, Supplier<T> supplier);
<T> void registerFallbackIfAbsent(Class<T> type, Supplier<T> supplier);

/**
* Release all resources.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.function.*;

import static com.predic8.membrane.annot.yaml.WatchAction.ADDED;
import static java.util.List.of;

/**
* TODO:
Expand All @@ -53,6 +54,8 @@ public class BeanRegistryImplementation implements BeanRegistry, BeanCollector,
// uid -> bean container
private final Map<String, BeanContainer> bcs = new ConcurrentHashMap<>(); // Order is not critical. Order is determined by uidsToActivate

private final List<FallbackBeanDefiner> fallbacks = Collections.synchronizedList(new ArrayList<>());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is s fallback?


@GuardedBy("uidsToActivate")
private final Set<UidAction> uidsToActivate = Collections.synchronizedSet(new LinkedHashSet<>()); // keeps order

Expand All @@ -70,6 +73,25 @@ record UidAction(String uid, WatchAction action) {
record PreDestroyCallback(Object bean, Method method) {
}

record FallbackBeanDefiner(BeanRegistryImplementation registry, Class<?> clazz, Supplier<?> supplier) {

public boolean produces(Class<?> clazz) {
return clazz.isAssignableFrom(this.clazz());
}

public synchronized Object defineIfNecessary() {
if (!registry.hasDefinitionFor(clazz))
return define();
return registry.getBean(clazz).orElseThrow();
}

public synchronized Object define() {
Object bean = supplier.get();
registry.register(null, bean);
return bean;
}
}
Comment thread
rrayst marked this conversation as resolved.

public BeanRegistryImplementation(Grammar grammar) {
this.grammar = grammar;
}
Expand Down Expand Up @@ -154,6 +176,11 @@ public Object resolve(String url) {

@Override
public List<Object> getBeans() {
synchronized (fallbacks) {
for (FallbackBeanDefiner fallbackBeanDefiner : fallbacks) {
fallbackBeanDefiner.defineIfNecessary();
}
}
return bcs.values().stream().filter(bd -> !bd.getDefinition().isComponent())
.map(bc -> bc.getOrCreate(this, grammar))
.filter(Objects::nonNull)
Expand All @@ -165,15 +192,29 @@ public Grammar getGrammar() {
return grammar;
}

protected boolean hasDefinitionFor(Class<?> clazz) {
return bcs.values().stream().anyMatch(bd -> bd.produces(clazz));
}

@Override
public <T> List<T> getBeans(Class<T> clazz) {
return bcs.values().stream()
List<T> result = bcs.values().stream()
.filter(bd -> bd.produces(clazz))
.map(bc -> bc.getOrCreate(this, grammar))
.filter(Objects::nonNull)
.filter(clazz::isInstance)
.map(clazz::cast)
.toList();
if (!result.isEmpty())
return result;

synchronized (fallbacks) {
for (FallbackBeanDefiner fallbackBeanDefiner : fallbacks) {
if (fallbackBeanDefiner.produces(clazz))
return (List<T>) of(fallbackBeanDefiner.defineIfNecessary());
}
}
return Collections.emptyList();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

public <T> Optional<T> getBean(Class<T> clazz) {
Expand All @@ -183,7 +224,15 @@ public <T> Optional<T> getBean(Class<T> clazz) {
log.error(msg);
throw new RuntimeException(msg);
}
return beans.size() == 1 ? Optional.of(beans.getFirst()) : Optional.empty();
if (!beans.isEmpty())
return Optional.of(beans.getFirst());
synchronized (fallbacks) {
for (FallbackBeanDefiner fallbackBeanDefiner : fallbacks) {
if (fallbackBeanDefiner.produces(clazz))
return Optional.of((T) fallbackBeanDefiner.defineIfNecessary());
}
}
return Optional.empty();
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

public <T> Optional<T> getBean(String beanname, Class<T> clazz) {
Expand All @@ -208,16 +257,13 @@ public void register(String beanName, Object bean) {
singletonBeans.put(uuid, bean);
// the return value of 'put' is ignored, since bean registration with
// random keys should not yield duplicates anyway.

if (bean instanceof BeanRegistryAware beanRegistryAware)
beanRegistryAware.setRegistry(this);
}

public <T> T registerIfAbsent(Class<T> type, Supplier<T> supplier) {
synchronized (uniqueClassInitialization) {
return getBean(type).orElseGet(() -> getBean(type).orElseGet(() -> {
T created = supplier.get();
register(null, created);
return created;
}));
}
public <T> void registerFallbackIfAbsent(Class<T> type, Supplier<T> supplier) {
fallbacks.add(new FallbackBeanDefiner(this, type, supplier));
}

private static @NotNull String computeBeanName(String beanName, String uuid) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public void register(String beanName, Object bean) {
}

@Override
public <T> T registerIfAbsent(Class<T> type, Supplier<T> supplier) {
public <T> void registerFallbackIfAbsent(Class<T> type, Supplier<T> supplier) {
throw new UnsupportedOperationException();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/* Copyright 2013 predic8 GmbH, www.predic8.com

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
package com.predic8.membrane.annot.generator;

import com.predic8.membrane.annot.ProcessingException;
import com.predic8.membrane.annot.model.*;
import com.predic8.membrane.annot.model.doc.Doc;
import com.predic8.membrane.annot.model.doc.Doc.Entry;

import javax.annotation.processing.FilerException;
import javax.annotation.processing.ProcessingEnvironment;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.FileObject;
import javax.tools.StandardLocation;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

/**
* Generates a resources.txt resource, which contains the fully qualified class names for all classes annotated with @Resource.
*/
public class ResourceInfo {

private final ProcessingEnvironment processingEnv;

public ResourceInfo(ProcessingEnvironment processingEnv) {
this.processingEnv = processingEnv;
}

public void write(Model m) throws IOException {
try {

for (MainInfo main : m.getMains()) {
List<Element> sources = new ArrayList<>(m.getResources());

FileObject o = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
main.getAnnotation().outputPackage(), "resources.txt", sources.toArray(new Element[0]));
try (BufferedWriter bw = new BufferedWriter(o.openWriter())) {
for (TypeElement resource : m.getResources()) {
bw.write(resource.getQualifiedName() + "\n");
}
}
}
} catch (FilerException e) {
if (e.getMessage().contains("Source file already created"))
return;
throw e;
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@

import com.predic8.membrane.annot.MCMain;

import javax.lang.model.element.TypeElement;

/**
* Keeps track of all information during one (or several incremental) compiler runs.
* <p>
* Collects all {@link MCMain}s found.
*/
public class Model {
private List<MainInfo> mains = new ArrayList<>();
private List<TypeElement> resources = new ArrayList<>();

public List<MainInfo> getMains() {
return mains;
Expand All @@ -33,4 +36,8 @@ public List<MainInfo> getMains() {
public void setMains(List<MainInfo> mains) {
this.mains = mains;
}

public List<TypeElement> getResources() {
return resources;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.predic8.membrane.core.interceptor.Interceptor.Flow;
import com.predic8.membrane.core.model.*;
import com.predic8.membrane.core.proxies.*;
import jakarta.annotation.Resource;
import org.slf4j.*;

import java.text.*;
Expand All @@ -34,6 +35,7 @@
* new exchanges arrive then old exchanges will be dropped (starting from oldest ascending) until the exchange can be
* stored. The LimitedMemoryExchangeStore is the default ExchangeStore Membrane uses.
*/
@Resource(type = ExchangeStore.class)
@MCElement(name="limitedMemoryExchangeStore")
public class LimitedMemoryExchangeStore extends AbstractExchangeStore {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import com.predic8.membrane.core.interceptor.Interceptor.*;
import com.predic8.membrane.core.router.*;
import com.predic8.membrane.core.transport.http.*;
import jakarta.annotation.Resource;
import org.slf4j.*;

import java.util.*;
Expand Down Expand Up @@ -52,6 +53,7 @@
* {@link AbortException} is thrown. The stack is unwound calling
* {@link Interceptor#handleAbort(Exchange)} on each interceptor on it.
*/
@Resource
public class FlowController {

private static final Logger log = LoggerFactory.getLogger(FlowController.class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
package com.predic8.membrane.core.kubernetes.client;

import com.predic8.membrane.core.transport.http.*;
import jakarta.annotation.Resource;

import java.util.*;

Expand All @@ -28,6 +29,7 @@
* Note: "baseUrl" is the KubernetesClient's only supported configuration. (KubernetesClientBuilder supports more, which
* would need to be implemented here.)
*/
@Resource
public class KubernetesClientFactory {
private WeakHashMap<String, KubernetesClient> clients;
private final HttpClientFactory httpClientFactory;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import com.predic8.membrane.core.transport.http.*;
import com.predic8.membrane.core.transport.ssl.*;
import com.predic8.membrane.core.util.*;
import jakarta.annotation.Priority;
import jakarta.annotation.Resource;
import org.jetbrains.annotations.*;
import org.slf4j.*;

Expand All @@ -31,6 +33,7 @@

import static com.predic8.membrane.core.util.URIUtil.*;

@Resource
public class RuleManager {

private static final Logger log = LoggerFactory.getLogger(RuleManager.class.getName());
Expand All @@ -41,6 +44,15 @@ public class RuleManager {
private final List<RuleDefinitionSource> ruleSources = new ArrayList<>();
private final Set<IRuleChangeListener> listeners = new HashSet<>();

@Priority(1)
public RuleManager(Router router) {
this.router = router;
}

public RuleManager() {

}

public enum RuleDefinitionSource {
/**
* rule defined in the spring context that created the router
Expand Down
Loading
Loading