Skip to content
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
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ plugins {
}

group = 'com.flexcodelabs'
version = '0.0.34'
version = '0.0.35'
description = 'Flextuma App'

java {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@
public class RequestLoggingFilter extends OncePerRequestFilter {

private static final Logger log = LoggerFactory.getLogger("FLEXTUMA");
private static final String USERNAME_KEY = "username";
private static final String USERNAME = "username";
private static final String SYSTEM = "SYSTEM";

@Override
protected boolean shouldNotFilterErrorDispatch() {
Expand Down Expand Up @@ -84,7 +85,7 @@ private void logRequest(HttpServletRequest request, HttpServletResponse response
String coloredMethod = logColor + request.getMethod() + reset;
String coloredUri = logColor + fullUri + reset;

org.slf4j.MDC.put(USERNAME_KEY, username);
org.slf4j.MDC.put(USERNAME, username);
try {
if (isError) {
log.error("{} {} {} {} {}ms - Status: {}", statusLog, userInfo, coloredMethod, coloredUri, duration,
Expand All @@ -94,25 +95,73 @@ private void logRequest(HttpServletRequest request, HttpServletResponse response
status);
}
} finally {
org.slf4j.MDC.remove(USERNAME_KEY);
org.slf4j.MDC.remove(USERNAME);
}
}

private String getUsername(HttpServletRequest request) {
String username = getCapturedUsername(request);
if (username != null) {
return username;
}

username = getPrincipalUsername(request);
if (username != null) {
return username;
}

username = getAuthenticationUsername();
if (username != null) {
return username;
}

username = getSessionUsername(request);
if (username != null) {
return username;
}

username = getLoginUsername(request);
if (username != null) {
return username;
}

log.debug("Returning SYSTEM as fallback");
return SYSTEM;
}

private String getCapturedUsername(HttpServletRequest request) {
Object capturedUsername = request.getAttribute(AuthenticatedUserCaptureFilter.REQUEST_USERNAME_ATTRIBUTE);
if (capturedUsername instanceof String username
&& !username.trim().isEmpty()
&& !"SYSTEM".equalsIgnoreCase(username)) {
&& !SYSTEM.equalsIgnoreCase(username)) {
return username;
}
return null;
}

private String getPrincipalUsername(HttpServletRequest request) {
Principal principal = request.getUserPrincipal();
if (principal != null && principal.getName() != null && !principal.getName().trim().isEmpty()) {
return principal.getName();
}
return null;
}

private String getAuthenticationUsername() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
logAuthenticationDetails(auth);

if (auth != null && auth.isAuthenticated() && !"anonymousUser".equals(auth.getPrincipal())) {
String username = auth.getName();
if (username != null && !username.trim().isEmpty() && !SYSTEM.equalsIgnoreCase(username)) {
log.debug("Returning username: {}", username);
return username;
}
}
return null;
}

private void logAuthenticationDetails(Authentication auth) {
log.debug("Authentication found: {}", auth != null);
if (auth != null) {
log.debug("Auth class: {}", auth.getClass().getSimpleName());
Expand All @@ -124,15 +173,9 @@ private String getUsername(HttpServletRequest request) {
} else {
log.debug("Authentication is null");
}
}

if (auth != null && auth.isAuthenticated() && !"anonymousUser".equals(auth.getPrincipal())) {
String username = auth.getName();
if (username != null && !username.trim().isEmpty() && !"SYSTEM".equalsIgnoreCase(username)) {
log.debug("Returning username: {}", username);
return username;
}
}

private String getSessionUsername(HttpServletRequest request) {
HttpSession session = request.getSession(false);
if (session != null) {
Object contextAttr = session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY);
Expand All @@ -142,21 +185,22 @@ private String getUsername(HttpServletRequest request) {
&& !"anonymousUser".equals(sessionAuth.getPrincipal())) {
String sessionUsername = sessionAuth.getName();
if (sessionUsername != null && !sessionUsername.trim().isEmpty()
&& !"SYSTEM".equalsIgnoreCase(sessionUsername)) {
&& !SYSTEM.equalsIgnoreCase(sessionUsername)) {
return sessionUsername;
}
}
}
}
return null;
}

private String getLoginUsername(HttpServletRequest request) {
if (request != null && request.getRequestURI().contains("/login")) {
String loginUsername = request.getParameter(USERNAME_KEY);
String loginUsername = request.getParameter(USERNAME);
if (loginUsername != null && !loginUsername.trim().isEmpty()) {
return loginUsername;
}
}

log.debug("Returning SYSTEM as fallback");
return "SYSTEM";
return null;
}
}
118 changes: 16 additions & 102 deletions src/main/java/com/flexcodelabs/flextuma/core/services/BaseService.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@
import jakarta.persistence.criteria.*;
import jakarta.persistence.metamodel.Attribute;
import jakarta.persistence.metamodel.EntityType;
import jakarta.persistence.metamodel.ManagedType;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
Expand Down Expand Up @@ -54,12 +50,18 @@ public void setEventPublisher(ApplicationEventPublisher eventPublisher) {
}

private CurrentUserResolver currentUserResolver;
private EntityResponseInitializer entityResponseInitializer;

@org.springframework.beans.factory.annotation.Autowired
public void setCurrentUserResolver(CurrentUserResolver currentUserResolver) {
this.currentUserResolver = currentUserResolver;
}

@Autowired
public void setEntityResponseInitializer(EntityResponseInitializer entityResponseInitializer) {
this.entityResponseInitializer = entityResponseInitializer;
}

protected abstract JpaRepository<T, UUID> getRepository();

protected abstract String getReadPermission();
Expand Down Expand Up @@ -182,7 +184,7 @@ private Specification<T> buildTenantSpec() {
}

private Pagination<T> buildPaginatedResponse(Page<T> resultPage, Pageable pageable) {
resultPage.getContent().forEach(entity -> initializeAssociationsForResponse(entity, 1));
resultPage.getContent().forEach(this::initializeAssociationsForResponse);
return Pagination.<T>builder()
.page(pageable.getPageNumber() + 1)
.total(resultPage.getTotalElements())
Expand All @@ -196,7 +198,7 @@ public List<T> findAll() {
checkPermission(getReadPermission());
Specification<T> spec = buildTenantSpec();
List<T> results = getRepositoryAsExecutor().findAll(spec);
results.forEach(entity -> initializeAssociationsForResponse(entity, 1));
results.forEach(this::initializeAssociationsForResponse);
return results;
}

Expand All @@ -223,15 +225,15 @@ private List<T> doFindAll(String fields, List<String> filter, String rootJoin) {
spec = spec.and(buildFetchSpec(fields));
}
List<T> results = getRepositoryAsExecutor().findAll(spec);
results.forEach(entity -> initializeAssociationsForResponse(entity, 1));
results.forEach(this::initializeAssociationsForResponse);
return results;
}

@Transactional(readOnly = true)
public Optional<T> findById(UUID id) {
checkPermission(getReadPermission());
Optional<T> result = getRepository().findById(id);
result.ifPresent(entity -> initializeAssociationsForResponse(entity, 1));
result.ifPresent(this::initializeAssociationsForResponse);
return result;
}

Expand All @@ -244,7 +246,7 @@ public Optional<T> findById(UUID id, String fields) {
spec = spec.and(buildFetchSpec(fields));
}
Optional<T> result = getRepositoryAsExecutor().findOne(spec);
result.ifPresent(entity -> initializeAssociationsForResponse(entity, 1));
result.ifPresent(this::initializeAssociationsForResponse);
return result;
}

Expand All @@ -253,7 +255,7 @@ public T save(T entity) {
checkPermission(getAddPermission());
onPreSave(entity);
T saved = getRepository().save(entity);
initializeAssociationsForResponse(saved, 1);
initializeAssociationsForResponse(saved);
onPostSave(saved);
eventPublisher.publishEvent(new EntityEvent<>(this, saved, EntityEvent.EntityEventType.CREATED));
return saved;
Expand All @@ -269,7 +271,7 @@ public T update(UUID id, T entity) {
String[] excludedFields = getNullPropertyNames(entity);
org.springframework.beans.BeanUtils.copyProperties(entity, existing, excludedFields);
T saved = getRepository().save(existing);
initializeAssociationsForResponse(saved, 1);
initializeAssociationsForResponse(saved);
eventPublisher.publishEvent(new EntityEvent<>(this, saved, EntityEvent.EntityEventType.UPDATED));
return saved;
}
Expand Down Expand Up @@ -445,97 +447,9 @@ protected void onPreSave(T entity) {
protected void onPostSave(T entity) {
}

protected void initializeAssociationsForResponse(Object entity, int depth) {
if (!shouldProcessEntity(entity, depth)) {
return;
}

Hibernate.initialize(entity);
ManagedType<?> managedType = resolveManagedType(Hibernate.getClass(entity));
if (managedType == null) {
return;
}

processAssociations(entity, managedType, depth);
}

private boolean shouldProcessEntity(Object entity, int depth) {
return entity != null && depth >= 0;
}

private void processAssociations(Object entity, ManagedType<?> managedType, int depth) {
BeanWrapper wrapper = new BeanWrapperImpl(entity);
for (Attribute<?, ?> attribute : managedType.getAttributes()) {
if (!isProcessableAssociation(attribute, wrapper)) {
continue;
}

Object value = wrapper.getPropertyValue(attribute.getName());
if (value != null) {
Hibernate.initialize(value);
processAssociationValue(value, depth);
}
}
}

private boolean isProcessableAssociation(Attribute<?, ?> attribute, BeanWrapper wrapper) {
return attribute.isAssociation() && wrapper.isReadableProperty(attribute.getName());
}

private void processAssociationValue(Object value, int depth) {
if (depth == 0) {
return;
}

if (value instanceof Collection<?> collection) {
processCollectionAssociations(collection, depth);
} else {
initializeSingularAssociations(value, depth - 1);
}
}

private void processCollectionAssociations(Collection<?> collection, int depth) {
for (Object item : collection) {
initializeSingularAssociations(item, depth - 1);
}
}

private void initializeSingularAssociations(Object entity, int depth) {
if (entity == null || depth < 0) {
return;
}

Hibernate.initialize(entity);
ManagedType<?> managedType = resolveManagedType(Hibernate.getClass(entity));
if (managedType == null) {
return;
}

BeanWrapper wrapper = new BeanWrapperImpl(entity);
for (Attribute<?, ?> attribute : managedType.getAttributes()) {
if (!attribute.isAssociation() || attribute.isCollection()
|| !wrapper.isReadableProperty(attribute.getName())) {
continue;
}

Object value = wrapper.getPropertyValue(attribute.getName());
if (value != null) {
Hibernate.initialize(value);
if (depth > 0) {
initializeSingularAssociations(value, depth - 1);
}
}
}
}

private ManagedType<?> resolveManagedType(Class<?> javaType) {
try {
if (entityManager == null || entityManager.getMetamodel() == null) {
return null;
}
return entityManager.getMetamodel().managedType(javaType);
} catch (IllegalArgumentException ex) {
return null;
protected void initializeAssociationsForResponse(Object entity) {
if (entityResponseInitializer != null) {
entityResponseInitializer.initialize(entity);
}
}

Expand Down
Loading