Skip to content

Commit

Permalink
#3611 - Upgrade to Spring 6, Boot 3, Wicket 10, etc.
Browse files Browse the repository at this point in the history
- Introduce ReificationType to circumvent new DB mapping for enums when using MariaDB
- Adjust entity beans accordingly to always use the custom enum types instead of `@Enumerated(EnumType.STRING)`
- SuccessfulLoginListener should only listen on `AuthenticationSuccessEvent` to avoid Spring detecting a circular dependency with SecurityAutoConfiguration
- Remove `@Transactional` annotations on some methods that already have a `@TransactionalEventListener` because Spring chokes on that now
- Added `proxyBeanMethods = false` on `BeanDefinitionRegistryPostProcessor` to avoid Spring complaining
  • Loading branch information
reckart committed Feb 25, 2024
1 parent 222cb0f commit 1426d30
Show file tree
Hide file tree
Showing 11 changed files with 100 additions and 37 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.event.TransactionalEventListener;
import org.springframework.util.ConcurrentReferenceHashMap;

Expand Down Expand Up @@ -1064,7 +1063,6 @@ private void logExclusiveAccessHolders()
}

@TransactionalEventListener(fallbackExecution = true)
@Transactional
public void beforeLayerConfigurationChanged(LayerConfigurationChangedEvent aEvent)
{
// Tell the known CAS holders for the given project that their type system is outdated
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
import de.tudarmstadt.ukp.inception.support.SettingsUtil;

@ConditionalOnWebApplication
@Configuration
@Configuration(proxyBeanMethods = false)
public class ExternalEditorLoader
implements BeanDefinitionRegistryPostProcessor, WebMvcConfigurer
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
import de.tudarmstadt.ukp.inception.support.SettingsUtil;

@ConditionalOnProperty(prefix = "format.custom-xml", name = "enabled", havingValue = "true", matchIfMissing = false)
@Configuration
@Configuration(proxyBeanMethods = false)
public class CustomXmlFormatLoader
implements BeanDefinitionRegistryPostProcessor
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@
import de.tudarmstadt.ukp.inception.kb.IriConstants;
import de.tudarmstadt.ukp.inception.kb.RepositoryType;
import de.tudarmstadt.ukp.inception.kb.reification.Reification;
import de.tudarmstadt.ukp.inception.kb.reification.ReificationType;
import de.tudarmstadt.ukp.inception.kb.yaml.KnowledgeBaseMapping;
import de.tudarmstadt.ukp.inception.kb.yaml.KnowledgeBaseProfile;
import jakarta.persistence.CollectionTable;
import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.Id;
Expand Down Expand Up @@ -176,7 +176,7 @@ public class KnowledgeBase
private boolean enabled = true;

@Column(nullable = false)
@Enumerated(EnumType.STRING)
@Type(ReificationType.class)
private Reification reification = NONE;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,42 @@
*/
package de.tudarmstadt.ukp.inception.kb.reification;

import de.tudarmstadt.ukp.inception.support.db.PersistentEnum;

public enum Reification
implements PersistentEnum
{
NONE(false), WIKIDATA(true);
NONE("NONE", false), WIKIDATA("WIKIDATA", true);

private final boolean supportsQualifier;

Reification(boolean supportsQualifier)
private final String id;

Reification(String aId, boolean supportsQualifier)
{
this.id = aId;
this.supportsQualifier = supportsQualifier;
}

public boolean supportsQualifier()
{
return supportsQualifier;
}

@Override
public String getId()
{
return id;
}

public String getName()
{
return getId();
}

@Override
public String toString()
{
return getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* Licensed to the Technische Universität Darmstadt under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The Technische Universität Darmstadt
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.
*
* 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 de.tudarmstadt.ukp.inception.kb.reification;

import de.tudarmstadt.ukp.inception.support.db.PersistentEnumUserType;

/**
* Implementation of {@link PersistentEnumUserType}
*
*/
public class ReificationType
extends PersistentEnumUserType<Reification>
{
private static final long serialVersionUID = -5458676818846846515L;

@Override
public Class<Reification> returnedClass()
{
return Reification.class;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,17 @@

import org.hibernate.annotations.OnDelete;
import org.hibernate.annotations.OnDeleteAction;
import org.hibernate.annotations.Type;

import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationDocumentState;
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationDocumentStateType;
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationFeature;
import de.tudarmstadt.ukp.clarin.webanno.model.AnnotationLayer;
import de.tudarmstadt.ukp.clarin.webanno.model.Project;
import jakarta.persistence.CollectionTable;
import jakarta.persistence.Column;
import jakarta.persistence.ElementCollection;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.FetchType;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
Expand Down Expand Up @@ -93,7 +93,7 @@ public class Recommender
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "recommender_ignored_document_states")
@Column(name = "name", nullable = false)
@Enumerated(EnumType.STRING)
@Type(AnnotationDocumentStateType.class)
private Set<AnnotationDocumentState> statesIgnoredForTraining;

@Lob
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ public void init()
@Async
public void onApplicationEvent(ApplicationEvent aEvent)
{
String topic = EVENT_TOPICS.get(aEvent.getClass());
var topic = EVENT_TOPICS.get(aEvent.getClass());
if (topic == null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
import static java.util.concurrent.TimeUnit.SECONDS;
import static java.util.stream.Collectors.toList;
import static java.util.stream.Collectors.toUnmodifiableSet;
import static org.springframework.transaction.annotation.Propagation.REQUIRES_NEW;

import java.io.FileNotFoundException;
import java.io.IOException;
Expand Down Expand Up @@ -403,7 +404,6 @@ public void beforeDocumentRemove(BeforeDocumentRemovedEvent aEvent) throws IOExc
}

@TransactionalEventListener(fallbackExecution = true)
@Transactional
public void afterDocumentCreate(AfterDocumentCreatedEvent aEvent)
{
log.trace("Starting afterDocumentCreate");
Expand All @@ -413,7 +413,6 @@ public void afterDocumentCreate(AfterDocumentCreatedEvent aEvent)
}

@TransactionalEventListener(fallbackExecution = true)
@Transactional
public void afterAnnotationUpdate(AfterCasWrittenEvent aEvent)
{
log.trace("Starting afterAnnotationUpdate");
Expand All @@ -423,12 +422,12 @@ public void afterAnnotationUpdate(AfterCasWrittenEvent aEvent)
}

@TransactionalEventListener(fallbackExecution = true)
@Transactional
@Transactional(propagation = REQUIRES_NEW)
public void beforeLayerConfigurationChanged(LayerConfigurationChangedEvent aEvent)
{
log.trace("Starting beforeLayerConfigurationChanged");

Project project = aEvent.getProject();
var project = aEvent.getProject();

try (PooledIndex pooledIndex = acquireIndex(project.getId())) {
pooledIndex.forceRecycle();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,30 +19,32 @@

import java.util.Date;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.stereotype.Component;

import de.tudarmstadt.ukp.clarin.webanno.security.model.User;
import de.tudarmstadt.ukp.clarin.webanno.security.config.SecurityAutoConfiguration;

@Component(SuccessfulLoginListener.SERVICE_NAME)
/**
* <p>
* This class is exposed as a Spring Component via
* {@link SecurityAutoConfiguration#successfulLoginListener}.
* </p>
*/
public class SuccessfulLoginListener
implements ApplicationListener<ApplicationEvent>
implements ApplicationListener<AuthenticationSuccessEvent>
{
public static final String SERVICE_NAME = "successfulLoginListener";
private final UserDao userRepository;

private @Autowired UserDao userRepository;
public SuccessfulLoginListener(UserDao aUserRepository)
{
userRepository = aUserRepository;
}

@Override
public void onApplicationEvent(ApplicationEvent aEvent)
public void onApplicationEvent(AuthenticationSuccessEvent aEvent)
{
if (aEvent instanceof AuthenticationSuccessEvent) {
AuthenticationSuccessEvent event = (AuthenticationSuccessEvent) aEvent;
User user = userRepository.get(event.getAuthentication().getName());
user.setLastLogin(new Date(event.getTimestamp()));
userRepository.update(user);
}
var user = userRepository.get(aEvent.getAuthentication().getName());
user.setLastLogin(new Date(aEvent.getTimestamp()));
userRepository.update(user);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
Expand All @@ -45,6 +44,7 @@
import de.tudarmstadt.ukp.clarin.webanno.security.PermissionExtension;
import de.tudarmstadt.ukp.clarin.webanno.security.PermissionExtensionPoint;
import de.tudarmstadt.ukp.clarin.webanno.security.PermissionExtensionPointImpl;
import de.tudarmstadt.ukp.clarin.webanno.security.SuccessfulLoginListener;
import de.tudarmstadt.ukp.clarin.webanno.security.UserAccess;
import de.tudarmstadt.ukp.clarin.webanno.security.UserAccessImpl;
import de.tudarmstadt.ukp.clarin.webanno.security.UserDao;
Expand Down Expand Up @@ -87,11 +87,10 @@ public PasswordEncoder passwordEncoder()
{
// Set up a DelegatingPasswordEncoder which decodes legacy passwords using the
// StandardPasswordEncoder but encodes passwords using the modern BCryptPasswordEncoder
String encoderForEncoding = "bcrypt";
Map<String, PasswordEncoder> encoders = new HashMap<>();
var encoderForEncoding = "bcrypt";
var encoders = new HashMap<String, PasswordEncoder>();
encoders.put(encoderForEncoding, new BCryptPasswordEncoder());
DelegatingPasswordEncoder delegatingEncoder = new DelegatingPasswordEncoder(
encoderForEncoding, encoders);
var delegatingEncoder = new DelegatingPasswordEncoder(encoderForEncoding, encoders);
// Decode legacy passwords without encoder ID using the StandardPasswordEncoder
delegatingEncoder.setDefaultPasswordEncoderForMatches(new StandardPasswordEncoder());
return delegatingEncoder;
Expand All @@ -115,7 +114,7 @@ public ExtensiblePermissionEvaluator extensiblePermissionEvaluator(
public MethodSecurityExpressionHandler defaultMethodSecurityExpressionHandler(
ApplicationContext aContext, ExtensiblePermissionEvaluator aEvaluator)
{
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
var expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setApplicationContext(aContext);
expressionHandler.setPermissionEvaluator(aEvaluator);
return expressionHandler;
Expand Down Expand Up @@ -144,4 +143,10 @@ public UserAccess userAccess(UserDao aUserService)
{
return new UserAccessImpl(aUserService);
}

@Bean
public SuccessfulLoginListener successfulLoginListener(UserDao aUserRepository)
{
return new SuccessfulLoginListener(aUserRepository);
}
}

0 comments on commit 1426d30

Please sign in to comment.