Instance variable in Spring Service - java

I have following Spring Service
#Service
class FeatureTogglesImpl implements FeatureToggles {
private final FeatureToggleRepository featureToggleRepository;
private Map<String, Feature> featuresCache;
#Autowired
public FeatureTogglesImpl(final FeatureToggleRepository featureToggleRepository) {
this.featureToggleRepository = featureToggleRepository;
this.featuresCache = loadAllFromRepository();
}
#Override
#Transactional
public void enable(Feature feature) {
Feature cachedFeature = loadFromCache(feature);
cachedFeature.enable();
featureToggleRepository.save(cachedFeature);
onFeatureToggled();
}
#Override
public boolean isEnabled(Feature feature) {
return loadFromCache(feature).isEnabled();
}
private Feature loadFromCache(Feature feature) {
checkNotNull(feature);
return featuresCache.get(feature.getKey());
}
private Map<String, Feature> loadAllFromRepository() {
return Maps.uniqueIndex(featureToggleRepository.findAll(), new Function<Feature, String>() {
#Override
public String apply(Feature feature) {
return feature.getKey();
}
});
}
void onFeatureToggled() {
featuresCache = loadAllFromRepository();
}
}
As you can see,I store loaded features into featuresCache, so that when client calls isEnabled() it is loading according feature from the cache.
There is a managed bean, who manages toggling the feature,
#Component
#ManagedBean
#Scope("view")
public class FeatureTogglesManager {
#Autowired
private FeatureToggles featureToggles;
#Secured({"ROLE_FEATURE_TOGGLES_EDIT"})
public String enable(Feature feature) {
featureToggles.enable(feature);
return null;
}
}
When I call enable() from AdminFeatureTogglesManager , I can see proper feature toggled, and cache pre-populated.
I have another service, which actually uses FeatureToggles.isEnabled() service
#Service
class ProductServieImpl implements ProductService {
#Autowired
private FeatureToggles featureToggles;
#Override
#Transactional
public void loadProducts() {
if (featureToggles.isEnabled(NewProducts.insance())) {
loadNewProducts();
return;
}
loadOldProducts();
}
}
The problem is that featureToggles.isEnabled() from this service always returns old instance from the cache, and when I debug the FeatureTogglesImpl, I do not see my pre-populated cache, although after toggle I could see correct/updated cache.
Isn't FeatureTogglesImpl supposed to be a singletong, so that if I change instance variable, it changes everywhere? Any help is appreciated.

Related

Spring Boot: How to Update Beans?

I have a #Bean which calls an external API at the start of the application. How can I have it such that it makes a new call and updates the bean on a set timer?
#Bean
public Template apiCall()
{
final String uri = "http://...";
return new RestTemplate().getForObject(uri,Template.class);
}
One way is reload the template in some kind of factory bean.
#Component
public class TemplateProvider {
#Value("${template.uri}")
private String uri;
private Template template;
#Autowired
private RestTemplate restTemplate;
#PostConstruct
init () {
loadTemplate();
}
public synchronized void reset() {
loadTemplate();
}
public synchronized Template template() {
return template;
}
private void loadTemplate() {
try {
this.template = restTemplate.getFor...();
}
catch (Exception e) {
//
}
}
}
Then you can call reset() inside a #scheduled method.
The only drawback to this is that callers should not keep reference of Template in their state.. Always access template via the provider to avoid inconsistency problems.
public class Client {
#Autowired
private TemplateProvider templateProvider;
public void method() {
templateProvider.template().method();
}
}

spring #Transactional rolling back halfways

I have a weird issue with #Transactional, the thing is, it's not doing a complete rollback on an error and I don't get why.
This is my service:
#Transactional
public class AService {
#Autowired
private AuditRepository auditRepository;
#Autowired
private RequestStatusRepository requestStatusRepository;
#Autowired
private ApprovementRepository approvementRepository;
public void approve(long approvementId) {
updateStatus();
}
private void updateStatus(long approvementId){
Approvement approvement = approvementRepository.findById(approvementId);
updateApprovement(approvement);
Request request = requestRepository.findById(approvement.getRequest().getId());
updateRequest(request);
}
private void updateApprovement(){
approvementRepository.save(approvement);
}
private void updateRequest(Request request){
requestRepository.save(request);
auditRepository.save(new Audit(request));
}
}
This is the Approvement Repository they are all similar:
#Repository
public class ApprovementRepositoryImpl implements ApprovementRepository {
#Autowired
private JpaApprovementRepository jpaApprovementRepository;
private Mapper mapper = DozerBeanMapperSingletonWrapper.getInstance();
#Override
public Approvement findById(long id) {
return jpaApprovementRepository.findById(id).map(this::to).orElse(null);
}
#Override
public void save(Approvement approvement) {
jpaApprovementRepository.save(from(approvement));
}
public Approvement to(ApprovementEntity from){
return mapper.map(from, Approvement.class);
}
public ApprovementEntity from(Approvement to){
return mapper.map(from, ApprovementEntity.class);
}
}
Ok, the request I'm getting has a very long field and the auditRepository isn't being able to store it, the change in audit never happened, and the change in request gets rolled back, but, the change in approvement it's being commited.
Why is this happening? I've been trying different types of propagations, and moving the #Transactional annotation from the class to the public method without success, any ideas would be great, thanks.

Dagger 2 Null field injection

Hi I've read through other posts but I am not being able to fix it. Basically my issue is that I call .inject and when I want to use the field it's still null.
I have this class:
public class Application extends Game implements IApplication {
#Inject IApplication app;
#Inject IRouter router;
public Application(IPlatformCode platformCode) {
}
#Override
public void create() {
initDagger();
System.out.println(app); //NULL
System.out.println(router); //NULL
router.showPage(Page.MenuPage); //NULL EXCEPTION
}
#Override
public void render() {
Gdx.gl.glClearColor(1, 0.5f, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
super.render();
}
#Override
public void setPage(IPage page) {
setScreen(page);
}
protected void initDagger() {
ApplicationComponent.Initializer.init(this).inject(this);
RouterComponent.Initializer.init().inject(this);
}
}
I won't show the router because I'm doing the same in app.
My Application component looks like this:
#Singleton
#Component ( modules = {ApplicationModule.class })
public interface ApplicationComponent {
void inject(IApplication application);
IApplication getApplication();
static final class Initializer {
private Initializer(){}
public static ApplicationComponent init(IApplication app) {
return DaggerApplicationComponent
.builder()
.applicationModule(new ApplicationModule(app))
.build();
}
}
}
And this is the module:
#Module
public class ApplicationModule {
private IApplication app;
public ApplicationModule(IApplication app) {
this.app = app;
}
#Provides
#Singleton
public IApplication providesApplication(){
return app;
}
}
As far as I read after calling inject(IApplication) the #Inject IApplication should be injected and have a value but right now it's null.
The generated code looks like this:
public final class DaggerApplicationComponent implements ApplicationComponent {
private Provider<IApplication> providesApplicationProvider;
private DaggerApplicationComponent(DaggerApplicationComponent.Builder builder) {
assert builder != null;
this.initialize(builder);
}
public static DaggerApplicationComponent.Builder builder() {
return new DaggerApplicationComponent.Builder();
}
private void initialize(DaggerApplicationComponent.Builder builder) {
this.providesApplicationProvider = DoubleCheck.provider(ApplicationModule_ProvidesApplicationFactory.create(builder.applicationModule));
}
public void inject(IApplication application) {
MembersInjectors.noOp().injectMembers(application);
}
public IApplication getApplication() {
return (IApplication)this.providesApplicationProvider.get();
}
public static final class Builder {
private ApplicationModule applicationModule;
private Builder() {
}
public ApplicationComponent build() {
if(this.applicationModule == null) {
throw new IllegalStateException(ApplicationModule.class.getCanonicalName() + " must be set");
} else {
return new DaggerApplicationComponent(this);
}
}
public DaggerApplicationComponent.Builder applicationModule(ApplicationModule applicationModule) {
this.applicationModule = (ApplicationModule)Preconditions.checkNotNull(applicationModule);
return this;
}
}
}
Thanks in advance.
Your inject method
void inject(IApplication application);
needs to change to
void inject(Application application);
Note the change from IApplication to just Application. You can't use interfaces for inject methods, you need to use a class.
Typically, Dagger 2 component creation is done in a class extending one of Android's Application classes. This is primarily done to ensure that these components (and the dependencies they house) are only instantiated once. (see Dagger docs for more details: https://google.github.io/dagger/users-guide)
While I haven't seen anything that says you can't wire it up differently, I haven't found an example of it, either. I'm wondering if trying to wire the components on-the-fly with the Initializer.init() calls you're making is somehow bypassing Dagger's ability to setup Components for injection correctly. Would it be possible to refactor the instantiation of the Component classes into an Application implementation instead?
The code above looks like it should work (outside of getting a new DaggerApplicationComponent instance with every init() call instead of a Singleton), I can't really explain why it doesn't.

Cache population in Spring controller

I want to call all the request mapping method(which has #Resource injection) before the server starts. How I can do this?
#Controller
public class ServiceController {
#Resource(name="userService")
private IUserService userService;
#RequestMapping("/getAllCountry")
public String getAllCountry() {
return userService.getAllCountry();
}
#RequestMapping("/getAllStates")
public String getAllStates() {
return userService.getStates();
}
#PostConstruct
public void cacheData(){
cache.put("ALL_COUNTRY_DATA", getAllCountry());
cache.put("ALL_STATE_DATA", getAllStates());
}
}
The above code fails and give me IllegalStateException. What is the best way to call the request mapping methods before the server is up and populate the cache.
Try using ApplicationListener in conjunction with ContextRefreshedEvent:
#Controller
public class ServiceController implements ApplicationListener<ContextRefreshedEvent> {
private static final Map<String, String> cache = new HashMap<>();
#Resource(name = "userService")
private IUserService userService;
#RequestMapping("/getAllCountry")
public String getAllCountry() {
return userService.getAllCountry();
}
#RequestMapping("/getAllStates")
public String getAllStates() {
return userService.getStates();
}
public void cacheData() {
cache.put("ALL_COUNTRY_DATA", getAllCountry());
cache.put("ALL_STATE_DATA", getAllStates());
}
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
cacheData();
}
}

How are transactions used when I mix EJBs and CDI beans?

I'm working on a JEE application that only uses EJBs at the moment. The application processes messages and stores some things in the database and/or possibly sends messages to other applications (pretty straightforward I guess).
I have some filtering business logic that determines whether or not the data should be stored in a database. Something like this (simplified):
#MessageDriven(...)
public class MessageListener {
private FilterProvider filter = new FilterProvider();
#EJB private SomeDao dao;
public void handleMessage(SomeMessage message) {
if(filter.allows(message)) {
dao.store(message);
} else {
// Ignore, not relevant
}
}
}
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class SomeDao {
public store(SomeMessage message) {
// Create the right entities and store in the db
}
}
public class FilterProvider {
public boolean allows(SomeMessage message) {
return message.getAllowed() == true;
}
}
Currently I'm investigating if I can use CDI to inject the FilterProvider and I've put together these modifications:
#MessageDriven(...)
public class MessageListener {
#Inject
private FilterProvider filter; // <-- Added annotation here and removed constructor call.
#EJB private SomeDao dao;
public void handleMessage(SomeMessage message) {
if(filter.allows(message)) {
dao.store(message);
} else {
// Ignore, not relevant
}
}
}
#Stateless
#TransactionAttribute(TransactionAttributeType.REQUIRED)
public class SomeDao {
public store(SomeMessage message) {
// Create the right entities and store in the db
}
}
#Default // <-- Added annotation here
public class FilterProvider {
public boolean allows(SomeMessage message) {
return message.getAllowed() == true;
}
}
My first question: What is the impact on the transactions by these changes?
My second question: What kind of risks/pitfalls am I introducing by this type of setup?

Categories

Resources