My company is currently using an old javaee jar (5.2.0) which doesn't contain the AroundTimeOut class. The jar cannot be changed because it will occur some major impacts. My manager asks me to intercept a timeout method.. Do you know if there is a way to workaround this issue?
This is the method that I use:
#Timeout
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
#Interceptors(CorrelationIdInterceptor.class)
public void handleTimeout(Timer timer) {
And the interceptor:
public class CorrelationIdInterceptor {
private static final String CORRELATION_ID = "CORRELATION_ID";
private static final String GET_CORRELATION_ID = "getCorrelationId";
private static final Logger LOGGER =
Logger.getLogger(CorrelationIdInterceptor.class);
#AroundInvoke
public Object log(final InvocationContext ic) throws Exception {
String webServiceMethodName = ic.getMethod().getName();
if(webServiceMethodName.equalsIgnoreCase("handleTimeout")){
webServiceMethodName="SIBOI"+":"+ webServiceMethodName;
}
Try to add in your ejb-jar.xml
<assembly-descriptor>
<interceptor-binding>
<ejb-name>full.path.to.your.ejb</ejb-name>
<interceptor-class>full.path.to.your.interceptor</interceptor-class>
<method-name>method.in.your.ejb</method-name>
</interceptor-binding>
</assembly-descriptor>
Related
I have some validation code that should run on server startup and make sure various conditions are met so whoever deploys the server don't messes up the DB or start the server with bad security configurations etc. To do that I created a bean
#Component
public class ApplicationStartupConditionsValidationBean {
static class ServerInitializationError extends Error{
public ServerInitializationError(String msg){
super(msg);
}
}
private Environment springEnv;
private String datasourceURL;
private String ddlAuto;
private static final Logger logger = LogManager.getLogger();
#Autowired
public ApplicationStartupConditionsValidationBean(Environment springEnv) throws Exception {
this.springEnv = springEnv;
this.datasourceURL = springEnv.getProperty("spring.datasource.url");
this.ddlAuto = springEnv.getProperty("spring.jpa.hibernate.ddl-auto");
validateStartupConditions();
}
public boolean isDBLocal(){
return datasourceURL.startsWith("jdbc:postgresql://localhost:");
}
private String disallowedParamMsg(String optionName, String optionValue){
return "option " + optionName + "=" + optionValue + " not allowed in production";
}
private void reject(String msg) throws ServerInitializationError{
String rejectionMsg = "startup conditions validation failed with msg: " + msg;
logger.error(rejectionMsg);
throw new ServerInitializationError(rejectionMsg);
}
private void reject(String paramName, String paramValue) throws ServerInitializationError{
reject(disallowedParamMsg(paramName, paramValue));
}
private void validateDatasourceParams(){
if(!isDBLocal() &&
!ddlAuto.equals("validate")){
reject("ddl-auto", ddlAuto);
}
}
public void validateStartupConditions() throws Exception{
logger.info("validating startup conditions");
validateDatasourceParams();
// more validation logic...
logger.info("startup conditions validation succeeded, proceeding with boot");
}
}
The way I would have wanted to use this class is to define what beans this must come before. In the example here I would have wanted to make sure this bean would be created before the DataSource bean is created, so that "ddl-auto=create" doesn't slip in production. I Know about the #DependsOn annotation but I would have wanted to do the reverse, and declare that this bean #HappensBefore a list of other beans. Is there any way to do this?
Thanks!
To run code before "normal" beans get created, you can use a BeanFactoryPostProcessor.
To declaratively add additional dependencies among beans, you could also use a BeanPostProcessor, but that sounds needlessly cumbersome for your use case.
public abstract class MainService<T extends Managed> {
private static final Logger logger = LoggerFactory.getLogger(ContentService.class);
protected final ExecutorService executor;
private final boolean idValidation;
#Autowired
private LockValidator lockValidator;
public MainService() {
this(null, true);
}
public MainService(boolean idValidation) {
this(null, idValidation);
}
public MainService(final ThreadConfig tpConfig) {
this(tpConfig, true);
}
protected MainService(final ThreadConfig tpConfig, final boolean idValidation) {
// Some code
}
The code above works fine. But I have to replace the #Autowired annotation and inject the component via constructor. The problem is when I create this constructor:
public MainService(LockValidation lockValidation) {
this.lockValidation = lockValidation;
}
Instantly, these attributes get errors:
protected final ExecutorService executor;
private final boolean idValidation;
Variable 'executor' might not have been initialized
And of course, I guess that I need to send some parameters into the new constructor. The question is: How Could I refactor this code, using a constructor to inject the component instead of the annotation?
Quick fix:
public MainService(LockValidation lockValidation,ThreadConfig tpConfig,boolean idValidation) {
this(tpConfig,idValidation);
this.lockValidation = lockValidation;
}
You are not following SOLID principles (Dependency Injection) here by initializing executor inside the constructor. Best approach would be to use all argument constructor.
protected MainService(ThreadConfig tpConfig,boolean idValidation,ExecutorService executor,LockValidation lockValidation) {
this.tpConfig=tpConfig;
this.idValidation=idValidation;
this.executor=executor;
this.lockValidation=lockValidation;
/// Some code
}
Finally, I could see that to create a constructor could be a headache because it's probable to make refactors in the constructors. So, I decided to implement an injection via set method like this:
#Autowired
public void setLockValidation(LockValidation lockValidation) {
this.lockValidation = lockValidation;
}
It worked fine
Does this have a proper name?
public class SomethingFactory {
private final String someParameter;
public SomethingFactory(String someParameter) {
this.someParameter = someParameter;
}
public Something create(String anotherParameter) {
return new Something(someParameter, anotherParameter);
}
}
public class Something {
public final String someParameter;
public final String anotherParameter;
public Something(String someParameter, String anotherParameter) {
this.someParameter = someParameter;
this.anotherParameter = anotherParameter;
}
}
What's different from a regular factory is that you have to specify a parameter at runtime to create() whenever you need to create an object.
That way you can make a singleton factory within Spring context for example, configuring first half of parameters there, and then finish with the rest of parameters at runtime when you call create().
Why I need that in the first place if you're curious:
I used to have regular singleton objects in Spring context and it was fine in thread-per-request applications, but now my whole app is non-blocking and I can't use ThreadLocal to keep stuff throughout entire request processing. For example, to keep info on timings with something like Apache StopWatch.
I needed to find a way to implement a "request scope" in a multithreading, non-blocking environment without having to supply the object representing the scope in every method (that would be silly) of my code.
So I thought let's make every (service) class take this scope object in constructor and let's create those classes on every request, but that goes against the singletons. The singletons we're talking are like, UserService that logs a user in, or a CryptoService that generates digital signatures. They're configured once in Spring, injected wheneven needed and everything's ok. But now I need to create those service classes in every method where they're needed, instead of just referencing an injected singleton instance.
So I thought let's call those singletons "templates" and whenever you need an actual instance you call create() supplying the said scope object. That way every class has the scope object, you just have to keep supplying it into other template service constructors. The full thing would look like this:
public class UserService {
private final Scope scope;
private final Template t;
private UserService(Template t, Scope scope) {
this.t = t;
this.scope = scope;
}
public void login(String username) {
scope.timings.probe("before calling database");
t.database.doSomething(username);
scope.timings.probe("after calling database");
}
public static class Template { /* The singleton configured in Spring */
private Database database;
public void setDatabase(Database database) { /* Injected by Spring */
this.database = database;
}
public UserService create(Scope scope) {
return new UserService(this, scope);
}
}
}
public class LoginHttpHandler { /* Also a Spring singleton */
private UserService.Template userServiceT;
public void setUserServiceT(UserService.Template userServiceT) { /* Injected by Spring */
this.userServiceT = userServiceT;
}
public void handle(HttpContext context) { /* Called on every http request */
userServiceT.create(context.scope).login("billgates");
}
}
In Spring you'd just describe a UserService.Template bean with the appropriate dependencies it needs and then inject that bean whenever a UserService is needed.
I just call that a "template". But like always I feel it's already been done. Does it have any name?
That is almost the example given for Guice's AssistedInject:
public class RealPaymentFactory implements PaymentFactory {
private final Provider<CreditService> creditServiceProvider;
private final Provider<AuthService> authServiceProvider;
#Inject
public RealPaymentFactory(Provider<CreditService> creditServiceProvider, Provider<AuthService> authServiceProvider) {
this.creditServiceProvider = creditServiceProvider;
this.authServiceProvider = authServiceProvider;
}
public Payment create(Date startDate, Money amount) {
return new RealPayment(creditServiceProvider.get(), authServiceProvider.get(), startDate, amount);
}
}
public class RealPayment implements Payment {
public RealPayment(
CreditService creditService, // from the Injector
AuthService authService, // from the Injector
Date startDate, // from the instance's creator
Money amount) // from the instance's creator
{
...
}
}
Assisted injection is used to "create classes that need extra arguments at construction time".
Also, this is similar to partial application, so you could have a PartialUserService that creates a UserService.
I am trying to define a custom DeltaSpike ConfigSource. The custom config source will have the highest priority and check the database for the config parameter.
I have a ConfigParameter entity, that simply has a key and a value.
#Entity
#Cacheable
public class ConfigParameter ... {
private String key;
private String value;
}
I have a #Dependent DAO that finds all config parameters.
What I am trying to do now, is define a custom ConfigSource, that is able to get the config parameter from the database. Therefore, I want to inject my DAO in the ConfigSource. So basically something like
#ApplicationScoped
public class DatabaseConfigSource implements ConfigSource {
#Inject
private ConfigParameterDao configParameterDao;
....
}
However, when registering the ConfigSource via META-INF/services/org.apache.deltaspike.core.spi.config.ConfigSource, the class will be instantiated and CDI will not work.
Is there any way to get CDI working in this case?
Thanks in advance, if you need any further information, please let me know.
The main problem is, that the ConfigSource gets instantiated very early on when the BeanManager is not available yet. Even the JNDI lookup does not work at that point in time. Thus, I need to delay the injection/lookup.
What I did now, is add a static boolean to my config source, that I set manually. We have a InitializerService that makes sure that the system is setup properly. At the end of the initialization process, I call allowInitialization() in order to tell the config source, that the bean is injectable now. Next time the ConfigSource is asked, it will be able to inject the bean using BeanProvider.injectFields.
public class DatabaseConfigSource implements ConfigSource {
private static boolean allowInit;
#Inject
private ConfigParameterProvider configParameterProvider;
#Override
public int getOrdinal() {
return 500;
}
#Override
public String getPropertyValue(String key) {
initIfNecessary();
if (configParameterProvider == null) {
return null;
}
return configParameterProvider.getProperty(key);
}
public static void allowInitialization() {
allowInit = true;
}
private void initIfNecessary() {
if (allowInit) {
BeanProvider.injectFields(this);
}
}
}
I have a request-scoped bean that holds all my config variables for type-safe access.
#RequestScoped
public class Configuration {
#Inject
#ConfigProperty(name = "myProperty")
private String myProperty;
#Inject
#ConfigProperty(name = "myProperty2")
private String myProperty2;
....
}
When injecting the Configuration class in a different bean, each ConfigProperty will be resolved. Since my custom DatabaseConfigSource has the highest ordinal (500), it will be used for property resolution first. If the property is not found, it will delegate the resolution to the next ConfigSource.
For each ConfigProperty the getPropertyValue function from the DatabaseConfigSource is called. Since I do not want to retreive the parameters from the database for each config property, I moved the config property resolution to a request-scoped bean.
#RequestScoped
public class ConfigParameterProvider {
#Inject
private ConfigParameterDao configParameterDao;
private Map<String, String> configParameters = new HashMap<>();
#PostConstruct
public void init() {
List<ConfigParameter> configParams = configParameterDao.findAll();
configParameters = configParams.stream()
.collect(toMap(ConfigParameter::getId, ConfigParameter::getValue));
}
public String getProperty(String key) {
return configParameters.get(key);
}
}
I could sure change the request-scoped ConfigParameterProvider to ApplicationScoped. However, we have a multi-tenant setup and the parameters need to be resolved per request.
As you can see, this is a bit hacky, because we need to explicitly tell the ConfigSource, when it is allowed to be instantiated properly (inject the bean).
I would prefer a standarized solution from DeltaSpike for using CDI in a ConfigSource. If you have any idea on how to properly realise this, please let me know.
Even though this post has been answered already I'd like to suggest another possible solution for this problem.
I managed to load properties from my db service by creating an #Signleton #Startup EJB which extends the org.apache.deltaspike.core.impl.config.BaseConfigSource and injects my DAO as delegate which I then registered into the org.apache.deltaspike.core.api.config.ConfigResolver.
#Startup
#Singleton
public class DatabaseConfigSourceBean extends BaseConfigSource {
private static final Logger logger = LoggerFactory.getLogger(DatabaseConfigSourceBean.class);
private #Inject PropertyService delegateService;
#PostConstruct
public void onStartup() {
ConfigResolver.addConfigSources(Collections.singletonList(this));
logger.info("Registered the DatabaseConfigSourceBean in the ConfigSourceProvider ...");
}
#Override
public Map<String, String> getProperties() {
return delegateService.getProperties();
}
#Override
public String getPropertyValue(String key) {
return delegateService.getPropertyValue(key);
}
#Override
public String getConfigName() {
return DatabaseConfigSourceBean.class.getSimpleName();
}
#Override
public boolean isScannable() {
return true;
}
}
I know that creating an EJB for this purpose basically produces a way too big overhead, but I think it's a bit of a cleaner solution instead of handling this problem by some marker booleans with static accessors ...
DS is using the java se spi mechanism for this which is not CD'Injectable'. One solution would be to use the BeanProvider to get hold of your DatabaseConfigSource and delegate operations to it.
I use method level security. In class I annotated some methods, expressions use fields of this class. But I see SpEL exceptions, that I can't reference them.
Here is part of code of this class. In expressions I want to use field repPrefix, but I receive exceptions that it's an unknown variable.
#Component("c2rTableManager")
#Scope("prototype")
public class C2RTableManager implements TableManager {
private final TableManager tableManager;
private final String repPrefix;
#Autowired
private SecurityInfoService securityInfoService;
public C2RTableManager(TableManager tableManager, String repository) {
this.tableManager = tableManager;
this.repPrefix = repository + "__";
}
...some methods
#Override
#PreAuthorize("hasRole('DBA') || hasPermission(repPrefix + #table, 'TABLE', 'DELETE_TABLE')")
public void dropTable(String table) throws InterruptedException, IOException {
tableManager.dropTable(table);
}
...other methods
}
If I write another way, expressions AREN'T EVALUATED at all. Can't understand why.
#Component("c2rTableManager")
#Scope("prototype")
public class C2RTableManager implements TableManager {
private final TableManager tableManager;
private final String repPrefix;
#Autowired
private SecurityInfoService securityInfoService;
public C2RTableManager(TableManager tableManager, String repository) {
this.tableManager = tableManager;
this.repPrefix = repository + "__";
}
...some methods
#Override
public void dropTable(String table) throws InterruptedException, IOException {
dropTable(table, repPrefix);
}
#PreAuthorize("hasRole('DBA') || hasPermission(#repPrefix + #table, 'TABLE', 'DELETE_TABLE')")
public void dropTable(String table, String repPrefix) throws InterruptedException, IOException {
tableManager.dropTable(table);
}
...other methods
}
How can I write expressions for methods of class using values of fields of this class?
I do not have enough reputation for adding a comment.
From the Spring Security docs available at http://docs.spring.io/spring-security/site/docs/3.0.x/reference/el-access.html
Here we're actually using a method argument as part of the expression
to decide whether the current user has the “admin”permission for the
given contact. The built-in hasPermission() expression is linked into
the Spring Security ACL module through the application context, as
we'll see below. You can access any of the method arguments by name as
expression variables, provided your code has debug information
compiled in.
Please stress on the Last sentence. Check the below two points:
Did you Compile the classes with debug flag on?
Did you enable the method level security with this declaration:<global-method-security pre-post-annotations="enabled"/>
I needed to declare bield as public
private final String repPrefix;
And write annotation with link to this
#PreAuthorize("hasRole('DBA') || hasPermission(repPrefix + #table, 'TABLE', 'DELETE_TABLE')")