Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
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 @@ -20,15 +20,13 @@

import java.util.NoSuchElementException;

import org.jspecify.annotations.Nullable;

import org.apache.causeway.applib.annotation.CollectionLayout;
import org.apache.causeway.applib.annotation.PropertyLayout;
import org.apache.causeway.applib.exceptions.UnrecoverableException;
import org.apache.causeway.applib.graph.tree.TreeNode;
import org.apache.causeway.applib.services.bookmark.Bookmark;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

/**
* Collects together methods for instantiating domain objects, also injecting
Expand Down Expand Up @@ -109,7 +107,7 @@ public interface FactoryService {
* @param <T>
* @param mixinClass
* @param mixedIn
* @throws IllegalArgumentException if mixinClass is not a mixin type
* @throws IllegalArgumentException if mixinClass is not a mixin type or if mixinClass is not already part of the metamodel
* @apiNote forces the mixinClass to be added to the meta-model if not already
*/
<T> T mixin(@NonNull Class<T> mixinClass, @NonNull Object mixedIn);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,10 @@
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

import org.apache.causeway.commons.internal.base._Casts;
import org.apache.causeway.commons.internal.exceptions._Exceptions;
import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

/**
* <h1>- internal use only -</h1>
Expand All @@ -66,6 +65,7 @@ public class _Multimaps {
* @param <V>
*/
public static interface ListMultimap<K, V> extends Map<K, List<V>> {

/**
* Adds {@code value} to the List stored under {@code key}.
* (If no such List exists, a new List is created.)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

@RequiredArgsConstructor(staticName = "named")
Expand Down Expand Up @@ -168,7 +169,6 @@ public Duration getExecutionTime() {
// -- EXECUTION LOGGING

private void onFinished(final _ConcurrentContext context) {

for(var task: tasks) {
if(task.getFailedWith()!=null) {
log.error("----------------------------------------");
Expand All @@ -178,9 +178,8 @@ private void onFinished(final _ConcurrentContext context) {
}
}

if(!context.enableExecutionLogging()) {
return;
}
if(!context.enableExecutionLogging())
return;

log.info("TaskList '%s' running %d/%d tasks %s, took %.3f milliseconds "
.formatted(getName(),
Expand All @@ -191,6 +190,15 @@ private void onFinished(final _ConcurrentContext context) {

}

@SneakyThrows
public void rethrow() {
for(var task: tasks) {
if(task.getFailedWith()!=null) {
throw task.getFailedWith();
}
}
}

// -- SHORTCUTS

public _ConcurrentTaskList addRunnable(final String name, final Runnable runnable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,18 @@
*/
package org.apache.causeway.commons.internal.debug;

import java.util.LongSummaryStatistics;
import java.util.Map;
import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import java.util.stream.Collectors;

import org.apache.causeway.commons.internal.base._NullSafe;
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.commons.internal.context._Context;
import org.apache.causeway.commons.internal.debug.xray.XrayUi;
import org.jspecify.annotations.NonNull;

import lombok.experimental.UtilityClass;

Expand All @@ -46,7 +53,8 @@
@UtilityClass
public class _Debug {

public void onCondition(
@Deprecated(forRemoval = false) // do not remove, see java-doc
public void onCondition(
final boolean condition,
final Runnable runnable) {

Expand All @@ -55,24 +63,121 @@ public void onCondition(
}
}

public void onClassSimpleNameMatch(
@Deprecated(forRemoval = false) // do not remove, see java-doc
public void onClassSimpleNameMatch(
final Class<?> correspondingClass,
final String classSimpleName,
final Runnable runnable) {
onCondition(correspondingClass.getSimpleName().equals(classSimpleName), runnable);
}

public void dump(final Object x) {
@Deprecated(forRemoval = false) // do not remove, see java-doc
public void dump(final Object x) {
dump(x, 0);
}

/**
* General purpose log entry.
*/
public void log(final String format, final Object...args) {
@Deprecated(forRemoval = false) // do not remove, see java-doc
public void log(final String format, final Object...args) {
_XrayEvent.record(1, _IconResource.LOG, format, args);
}

public record Profiler(
Map<String, Measurement> measurements) {

public record Measurement(
String name,
LongSummaryStatistics stats) {
Measurement(final String name) {
this(name, new LongSummaryStatistics());
}
void collect(final Runnable runnable) {
var t0 = System.nanoTime();
runnable.run();
stats.accept(System.nanoTime() - t0);
}
<T> T collect(final Supplier<T> callable) {
var t0 = System.nanoTime();
var t = callable.get();
stats.accept(System.nanoTime() - t0);
return t;
}
@Override
public final String toString() {
return "Profiling %s: %.3f ms, avg %.3f ms (count=%d)"
.formatted(name,
(stats.getSum())/1000_000.,
stats.getAverage()/1000_000.,
stats.getCount());
}
}

public static Profiler getInstance() {
return _Context.computeIfAbsent(Profiler.class, (@NonNull Supplier<Profiler>) Profiler::new);
}

public Profiler() {
this(new ConcurrentHashMap<>());
}

public void measure(final String name, final Runnable runnable) {
measurements.computeIfAbsent(name, Measurement::new)
.collect(runnable);
}

public <T> T measure(final String name, final Supplier<T> callable) {
return measurements.computeIfAbsent(name, Measurement::new)
.collect(callable);
}

@Override
public final String toString() {
return new TreeMap<>(measurements).values().stream()
.map(Measurement::toString)
.collect(Collectors.joining("\n"));
}
}

@Deprecated(forRemoval = false) // do not remove, see java-doc
public String measureTimeResolutionNanos() {
final int iterations = 1_000_000; // Run many samples
long zeroChangeCount = 0;
long totalSteps = 0;

var sb = new StringBuilder();

sb.append("Sampling " + iterations + " consecutive calls to System.nanoTime()...");

final LongSummaryStatistics stats = new LongSummaryStatistics();

for (int i = 0; i < iterations; i++) {
long delta = System.nanoTime() - System.nanoTime();
if (delta == 0) {
zeroChangeCount++;
} else {
stats.accept(-delta);
}
}

double percentageSame = (double) zeroChangeCount / iterations * 100;

sb.append("\n--- Results ---");
sb.append("\nTotal Iterations: " + iterations);
sb.append("\nTimes resolution didn't change: " + zeroChangeCount);
sb.append("\nPercentage of identical consecutive readings: " + String.format("%.2f", percentageSame) + "%");
sb.append("\nTotal unique 'ticks' detected: " + totalSteps);

sb.append("\n\n--- Delta Statistics (Time between calls) ---");
sb.append("\nTotal valid deltas recorded: " + stats.getCount());
sb.append("\nMinimum delta detected: " + stats.getMin() + " ns");
sb.append("\nMaximum delta detected: " + stats.getMax() + " ns");
sb.append("\nAverage delta: %.2f ns\n".formatted(stats.getAverage()));

return sb.toString();
}

// -- HELPER

private void dump(Object x, final int indent) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,13 @@

import java.io.Serializable;

import org.jspecify.annotations.NonNull;

import org.apache.causeway.applib.id.LogicalType;
import org.apache.causeway.applib.services.metamodel.BeanSort;
import org.apache.causeway.applib.services.registry.ServiceRegistry;
import org.apache.causeway.commons.internal.base._Strings;

import org.jspecify.annotations.NonNull;

public record CausewayBeanMetaData(
@NonNull LogicalType logicalType,
@NonNull BeanSort beanSort,
Expand Down Expand Up @@ -86,6 +87,23 @@ public String getBeanName() {
return logicalType.logicalName();
}

public boolean isInjectable(final ServiceRegistry serviceRegistry) {
// optimization
final boolean isDefinitelyNotInjectible = switch (managedBy()) {
case NONE, CAUSEWAY, PERSISTENCE -> true;
case UNSPECIFIED, SPRING -> beanSort.isAbstract()
|| beanSort.isValue()
|| beanSort.isEntity()
|| beanSort.isViewModel()
|| beanSort.isMixin();
};
return !isDefinitelyNotInjectible
&& (beanSort.isManagedBeanAny()
|| serviceRegistry
.lookupRegisteredBeanById(logicalType())
.isPresent());
}

// -- FACTORIES

public static CausewayBeanMetaData vetoed(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,13 @@
import java.util.Optional;
import java.util.stream.Stream;

import org.jspecify.annotations.Nullable;

import org.apache.causeway.applib.annotation.HomePage;
import org.apache.causeway.applib.annotation.Programmatic;
import org.apache.causeway.commons.collections.Can;
import org.apache.causeway.commons.internal.reflection._ClassCache;
import org.apache.causeway.core.config.beans.CausewayBeanMetaData.PersistenceStack;

import org.jspecify.annotations.NonNull;
import org.jspecify.annotations.Nullable;

/**
* Holds discovered domain types grouped by bean-sort.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,11 @@
*/
package org.apache.causeway.core.config.environment;

import jakarta.annotation.PreDestroy;
import jakarta.annotation.Priority;
import jakarta.inject.Named;

import org.apache.causeway.commons.internal.base._StableValue;
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.commons.internal.context._Context;
import org.apache.causeway.commons.internal.ioc.SpringContextHolder;
import org.apache.causeway.core.config.CausewayModuleCoreConfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.event.ApplicationFailedEvent;
Expand All @@ -31,12 +32,9 @@
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Service;

import org.apache.causeway.commons.internal.base._StableValue;
import org.apache.causeway.commons.internal.base._Strings;
import org.apache.causeway.commons.internal.context._Context;
import org.apache.causeway.commons.internal.ioc.SpringContextHolder;
import org.apache.causeway.core.config.CausewayModuleCoreConfig;

import jakarta.annotation.PreDestroy;
import jakarta.annotation.Priority;
import jakarta.inject.Named;
import lombok.Getter;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
Expand All @@ -63,10 +61,10 @@ public class CausewaySystemEnvironment {
private final DeploymentType deploymentType;

@Autowired
public CausewaySystemEnvironment(ApplicationContext springContext) {
public CausewaySystemEnvironment(final ApplicationContext springContext) {
this.springContextHolder = new SpringContextHolder(springContext);
this.deploymentType = deploymentTypeFromEnvironment();
log.info("init for %s (hashCode = {})", deploymentType, this.hashCode());
log.info("init for {} (hashCode = {})", deploymentType, this.hashCode());
}

//JUnit
Expand Down Expand Up @@ -184,7 +182,7 @@ private static boolean isNotSet(final String value) {
return "false".equalsIgnoreCase(value);
}

private _StableValue<Boolean> _isIntegrationTesting = new _StableValue<Boolean>();
private final _StableValue<Boolean> _isIntegrationTesting = new _StableValue<Boolean>();
/**
* Whether we find Spring's ContextCache on the class path.
*/
Expand Down
Loading