Configuring OSGI Services on a per use basis - java

I want to create a paging service that will return pages based on a SQL like query. Here is the simple interface:
public interface IPage {
public boolean hasNext();
public Object[] next();
}
When I call this service I want to be able to initialize it with a query String and a page size int.
How do I go about getting a reference to the service that has been initialized with the arguments specified above? I would prefer to use declarative services but it seems to me I would have to use ServiceTracker if I wanted to pass in arguments.
Thanks for your help.

Instead exposing IPage as a service, you might expose an IPageFactory as a service instead. The factory would then take a query and a page size, and return an initialised IPage instance.

Related

Ways to pass additional data to Custom RevisionEntity in Hibernate Envers?

It's RESTful web app. I am using Hibernate Envers to store historical data. Along with revision number and timestamp, I also need to store other details (for example: IP address and authenticated user). Envers provides multiple ways to have a custom revision entity which is awesome. I am facing problem in setting the custom data on the revision entity.
#RevisionEntity( MyCustomRevisionListener.class )
public class MyCustomRevisionEntity extends DefaultRevisionEntity {
private String userName;
private String ip;
//Accessors
}
public class MyCustomRevisionListener implements RevisionListener {
public void newRevision( Object revisionEntity ) {
MyCustomRevisionEntity customRevisionEntity = ( MyCustomRevisionEntity ) revisionEntity;
//Here I need userName and Ip address passed as arguments somehow, so that I can set them on the revision entity.
}
}
Since newRevision() method does not allow any additional arguments, I can not pass my custom data (like username and ip) to it. How can I do that?
Envers also provides another approach as:
An alternative method to using the org.hibernate.envers.RevisionListener is to instead call the getCurrentRevision( Class revisionEntityClass, boolean persist ) method of the org.hibernate.envers.AuditReader interface to obtain the current revision, and fill it with desired information.
So using the above approach, I'll have to do something like this:
Change my current dao method like:
public void persist(SomeEntity entity) {
...
entityManager.persist(entity);
...
}
to
public void persist(SomeEntity entity, String userName, String ip) {
...
//Do the intended work
entityManager.persist(entity);
//Do the additional work
AuditReader reader = AuditReaderFactory.get(entityManager)
MyCustomRevisionEntity revision = reader.getCurrentRevision(MyCustomRevisionEntity, false);
revision.setUserName(userName);
revision.setIp(ip);
}
I don't feel very comfortable with this approach as keeping audit data seems a cross cutting concern to me. And I obtain the userName and Ip and other data through HTTP request object. So all that data will need to flow down right from entry point of application (controller) to the lowest layer (dao layer).
Is there any other way in which I can achieve this? I am using Spring.
I am imagining something like Spring keeping information about the 'stack' to which a particular method invocation belongs. So that when newRevision() in invoked, I know which particular invocation at the entry point lead to this invocation. And also, I can somehow obtain the arguments passed to first method of the call stack.
One good way to do this would be to leverage a ThreadLocal variable.
As an example, Spring Security has a filter that initializes a thread local variable stored in SecurityContextHolder and then you can access this data from that specific thread simply by doing something like:
SecurityContext ctx = SecurityContextHolder.getSecurityContext();
Authorization authorization = ctx.getAuthorization();
So imagine an additional interceptor that your web framework calls that either adds additional information to the spring security context, perhaps in a custom user details object if using spring security or create your own holder & context object to hold the information the listener needs.
Then it becomes a simple:
public class MyRevisionEntityListener implements RevisionListener {
#Override
public void newRevision(Object revisionEntity) {
// If you use spring security, you could use SpringSecurityContextHolder.
final UserContext userContext = UserContextHolder.getUserContext();
MyRevisionEntity mre = MyRevisionEntity.class.cast( revisionEntity );
mre.setIpAddress( userContext.getIpAddress() );
mre.setUserName( userContext.getUserName() );
}
}
This feels like the cleanest approach to me.
It is worth noting that the other API getCurrentRevision(Session,boolean) was deprecated as of Hibernate 5.2 and is scheduled for removal in 6.0. While an alternative means may be introduced, the intended way to perform this type of logic is using a RevisionListener.

Is there clean way to pass context data to #Asynchronous ejb call?

In wildfly I execute stateless ejb method asynchronously (it is mapped with #Asynchronous annotation). In the calling method I have some context information in thread local. What is the best way to pass this data to async method? I don't want to add additional parameter to async method signature.
Essentially you have only 2 options:
Passing value as a parameter
Storing that value in some global place. Like static variable.
The first option is much cleaner and easier. Don't use the second one :)
With a bit of ugly plumbing it can be resolved as follows (wildfly 8.x.x):
if (SecurityContextAssociation.getSecurityContext()==null)
SecurityContextAssociation.setSecurityContext(new JBossSecurityContext("background-job"));
SecurityContext current = SecurityContextAssociation.getSecurityContext();
final Object cred = current.getUtil().getCredential();
final Subject s = current.getUtil().getSubject();
final Principal up = current.getUtil().getUserPrincipal();
boolean needToUpdatePrincipal=true;
if (up instanceof TenantPrincipal) {
if (t.getTenantName().equals(((TenantPrincipal) up).getAdditonalField())) {
needToUpdatePrincipal=false;
}
}
if (needToUpdatePrincipal) {
TenantPrincipal tp=new TenantPrincipal(up.getName());
tp.setAdditionalField(t.getTenantName());
current.getUtil().createSubjectInfo(
, cred, (Subject) s);
}
Basically you need to create your own Principal class and set context data in the additional field of its instance.

Best factory pattern for delivering app data object based on application type in http header

I have a business with multiple applications using my webservice resource. I have a web service resource that looks in a http header for the application ID. This tell the server which application is requesting data. My goal is to deliver to my web application developers a method they can call to retrieve all the application specific settings via the application ID.
Given an applicationID i can specify device type, properties file for that app, and whether GCM,APNS or Microsoft Push Notification, etc. So each applicationID has distinct properties basically.
I want the developer to be able to call for this object like this (or similar):
ApplicationData appData = ApplicationDataFactory.getCurrentApplicationData();
and the factory would look something like this:
class ApplicationDataFactory
{
public static ApplicationData getCurrentApplicationData()
{
//notice how im not passing in criteria here, im getting it from the request so call doens't have to know
String criteria = Request.getHTTPHeaderInfo("applicationID");
if ( criteria.equals("Android") )
return new Android();
else if ( criteria.equals("Android-germany") )
return new Android_germany();
else if ( criteria.equals("ios_germany") )
return new ios_germany();
else if ( criteria.equals("ios"))
return new ios();
else if ( criteria.equals("windows") )
return new windows();
return null;//or throw exception
}
}
so Android, ios, and windows objects all extend off ApplicationData class clearly.
So for example the Android.java object would look like this:
class Android extends ApplicationData{
#override
public String getType(){
return "Android"
}
#override
public Properties getProperties{
return system.getProperties("android.properties");
}
}
and the Android-germany and ios-germany will have common data since there both from germany.
First, i dont like that im specifying the criteria inside the factory and also can anyone help me
with a good design pattern i can use to achieve this ? Remember, in the end i want to be able to have the developer call only ApplicationDataFactory.getCurrentApplicationData(); (or something similar) and the correct application info will be sent referenced. I dont have to use a factory here either its just the first thing i thought of.
So your problem is with the fact that the logic for the criteria is within the factory method. Meanwhile, you don't want the user to provide the criteria as an parameter to the factor method.
First of all, I don't like the idea of having a static Request class. A request should be an object that contains information about the current request. I have a suspicion that your code may be prone to race conditions, once you have many concurrent requests (how do you know which request is which?). So as a starting point, I would refactor the Request class so that you work with instances of Request.
I think, the clearest approach would be that you pass in applicationID as a parameter. This makes testability trivial and the code becomes very obvious, too. You take an input and produce the output based on the input. You could pass the Request instead of the applicationID and let the factory handle the retrieval of the applicationID from the request (as you are doing now).
If you think the Request -> applicationID logic should not be part of the factory, you can create another class, such as ApplicationIDResolver which translates a Request to an applicationID. From then on ApplicationDataFactory would be used through an instance and the ApplicationIDResolver would be a constructor parameter. (I think, this is an overkill.). Another option is to add a getApplicationID() method to the Request class.
If you use a dependency injection framework, it may take care of object life cycles/scopes automatically for you, so the ApplicationData could be a request-scoped object and you could tell your dependency injection framework to instantiate ApplicationData objects based on requests and inject them into the classes where they get used.
Better to use for this purposes enum which implements ApplicationData interface and define each entry. You can resolve proper by valueOf() from enum.

DI with configuration

I newbie in java i don't know of all possibilites. I want to know can i implement something like this:
class DIConfig {
// create at start of application (integration with javaee container)
// load configurable files and stores all configuration
}
class Foo {
// use DIConfig to inject value stored in DIConfig to String url
#Config("general.url")
String url;
public void bar() {
// same thing with local variable
#Config("export.maxRows")
int maxRows;
}
}
It's available? How can i do it?
My trouble - i don't understand how to using annotation execute some code and stores result in annotaed variable.
Seems it not possible.
All DI frameworks use something like binder - i've many classes that using configuration property and create all of this classes via binder or something like this - impossible. I search mechanism that don't use any binders. Somethinh like interceptors (AOP) but initialize variable instead wrap method invoke.

How instantiate several OSGi services?

In the context of an Eclipse RCP application I decided to use OSGi services to provide "Interfaces" out of a plugin (i.e a bundle).
In one of my plugin I have the following Parser interface:
public interface Parser {
public void start(File file);
public boolean hasNext();
public Object next();
}
Consumer plugins will use this interface to parse files. Because several parsing can be done in the same time and because an implementation of this interface will need several "state" private field each consumer of this service must use a dedicated service instance.
In this case, the default solution provided by manu OSGi tutorials consisting in registering ONE service instance in the start method of the parser bundle doesn't work. What is the best solution to handle such a solution ?
I can create a ParserFactory service with one unique method:
public Parser create(File file);
??
Any comment is welcome,
As you're suggesting, I would change your service interface to be a provider of Parsers.
And your Parser is just an Iterator, so maybe something like
public interface ParserFactory<T> {
/** Iterating on the returned object
* provides Ts parsed from the InputStream.
*
* #param input must be closed by the returned object
* when done iterating.
*/
Iterable<T> createParser(InputStream input);
}
Using an InputStream or Reader also makes it more flexible that requiring a File.
Have a look at the OSGi ServiceFactory; this allows you to instantiate services for different requesting bundles. You can read more about it in section 5.6 of the core specification.

Categories

Resources