Camunda set tenant id when starting a shared process definition - java

Is it possible to set a tenant id when the process definition itself is shared between multiple tenants?
I call this method where I get both id's from the http request which in turn I pass to the embedded process-engine
public void startInstance(String processDefinitionId, String tenantId) {
this.runtimeService.startProcessInstanceById(processDefinitionId);
}
But using this method I am not able to pass a tenant id to the process instance. How do I achieve this?
I found this reading: https://docs.camunda.org/manual/7.5/user-guide/process-engine/multi-tenancy/#instantiate-a-shared-definition but it does not really solve my problem since I get the tenant id from an http-header.

Thanks to the comment of Jan I figured out that one could add the tenant id as a variable to the started instance and retrieve it in the TenantProvider.
The code looks like this
runtimeService.createProcessInstanceById(processDefinitionId).setVariable("tenantId", tenantId).execute();
And on your TenantProvider simply get this variable like so
public class TenantProvider implements TenantIdProvider {
#Override
public String provideTenantIdForProcessInstance(TenantIdProviderProcessInstanceContext ctx) {
return (String) ctx.getVariables().get("tenantId");
}
#Override
public String provideTenantIdForCaseInstance(TenantIdProviderCaseInstanceContext ctx) {
return (String) ctx.getVariables().get("tenantId");
}
#Override
public String provideTenantIdForHistoricDecisionInstance(TenantIdProviderHistoricDecisionInstanceContext ctx) {
return (String) ctx.getExecution().getVariable("tenantId");
}
}
To enable the use of a TenantProvider, start your engine like so
ProcessEngine engine = new StandaloneProcessEngineConfiguration()
.setTenantIdProvider(new TenantProvider())
...
.buildProcessEngine();

Related

How can I make a Java Spring Component class thread safe?

I have a spring class that when you call httpDatastoreFacade.getDatastore() it should give you the REST request thread safe datastore:
#Component
public class HttpDatastoreFacade {
private Boolean useAttribute = Boolean.FALSE;
public String getDatastore() {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextholder.currentRequestAttributes()).getRequest();
String datastore = request.getParameter("datastore");
if(useAttribute) {
datastore = String.valueOf(request.getAttribute("datastore"));
}
return datastore;
}
public void setDatastore(String datastore, Boolean useAttribute) {
HttpServletRequest request = ((ServletRequestAttributes)RequestContextholder.currentRequestAttributes()).getRequest();
request.setAttribute("datastore", datastore);
this.useAttribute = useAttribute;
}
public Boolean getUseAttribute() {
return useAttribute;
}
}
Sometimes in my code I need to change that datastore but then I want to immediately change it back after I call whatever code needs the datastore differently:
#Component
public class someClass() {
#Autowired
private HttpDatastoreFacade datastoreFacade;
#Autowired
private OtherClass otherClass;
public void someMethod() {
String savedDatastore = datastoreFacade.getDatastore();
String savedUseAttribute = datastoreFacade.getUseAttribute;
//setDatastore to new settings
datastoreFacade.setDatastore("newStore", true);
//this is where I call my method's or methods that need this new datastore
otherClass.callSomeMethod();
//set the datastore back to old value
datastoreFacade.setDatastore(savedDatastore , savedUseAttribute );
}
}
My issue is that I'm running into threading problems where useAttribute is true but the datastore isn't set in the request attribute.
I'm looking for a better java pattern where I can lock the HttpDatastoreFacade while I do my otherClass.callSomeMethod() or whatever other calls I need to make until I set the HttpDatastoreFacade back to normal. otherCalss.callSomeMethod may be calling other methods that use HttpDatastoreFacade as well and they may want to set it how they need it. So maybe I need some short of datastore stack that is thread safe?
Seems a bean in #RequestScope could solve your problem.
#Component
#RequestScope
public class X {
//
}
you won't have to think about clearing the request scoped bean as you would the ThreadLocal. It will be collected when the corresponding ServletRequest is cleaned up.
I ended up making useAttribute a ThreadLocal variable which solved my problems.
private ThreadLocal<Boolean> useAttribute = new ThreadLocal<>();

How to call set before configureFieldMetadata in BridgeClass

I have the following BridgeClass and i need that configureFieldMetadata to be executed after the set method.
But by default it's configureFieldMetadata executed first.
Is it possible ?
Thanks in advance!
public class AdditionalAttributesBridge implements
MetadataProvidingFieldBridge{
#Override
public void set(String name, Object value, Document document,
LuceneOptions luceneOptions) {
Set<AdditionalAttribute> attributes = (Set<AdditionalAttribute>)
value;
for (AdditionalAttribute a : attributes) {
//some code
}
}
#Override
public void configureFieldMetadata(String name, FieldMetadataBuilder
builder) {
//ToDo
}
}
configureFieldMetadata is executed on bootstrap, while set is executed at runtime, when indexing.
So no, this is not possible.
You might want to consider why you need set to be called before configureFieldMetadata. I guess you initialize something in the set method based on the parameters, but I don't know what sort of information you would have in set that you could possibly need in configureFieldMetadata... ?

Play Framework 2.7: How to update session within a Action composition in Java

I'm trying to update an app from to Play 2.7. I see that now the access to the session object via Http.Context is deprecated. Instead I have to use the Http.Request object. Additionally before I could just change the Session object right away - now it seems like I have to create a new Session and add to the Result by myself. But how can I achieve this within an Action composition where I don't have access to the Result object?
An Action composition can look like:
public class VerboseAction extends play.mvc.Action.Simple {
public CompletionStage<Result> call(Http.Request req) {
...
return delegate.call(req);
}
}
I can't see how to add something to the Session here!
EDIT:
I couldn't find an easy solution but a workaround with a second action annotation. It's possible to access the Result object via .thenApply and attache the new Session object.
public CompletionStage<Result> call(Http.Request request) {
return delegate.call(request).thenApply(result -> {
Http.Session session = ... change the session
return result.withSession(session);
});
}
Still if someone has a better idea how to change the Session directly in the action composition please feel free to answer.
A session in cleared by withNewSession(). A new session is created when you add something with addingToSession(...), perhaps after a login. Here is my complete working code : I have 2 timestamp : one for the log file and one for an application timeout.
public class ActionCreator implements play.http.ActionCreator {
private final int msTimeout;
#Inject
public ActionCreator(Config config) {
this.msTimeout = config.getInt("application.msTimeout");
}
#Override
public Action<?> createAction(Http.Request request, Method actionMethod) {
return new Action.Simple() {
#Override
public CompletionStage<Result> call(Http.Request req) {
// add timestamp for the elapsed time in log
req.getHeaders().addHeader("x-log-timestamp", "" + System.currentTimeMillis());
// did a session timeout occur
boolean timeout = SessionUtils.isTimeout(req, msTimeout);
// apply current action
return delegate.call(req).thenApply(result -> {
// display some info in log
Utils.logInfo(req);
// return final result
if (timeout) {
return result.withNewSession();
} else if (SessionUtils.isOpen(req)) {
return result.addingToSession(req, "timestamp", "" + System.currentTimeMillis());
} else {
return result;
}
});
}
};
}
}

Dynamic per REST(Jersey) request binding of configurations in Guice

We are using Guice in our project for DI. Currently we have some configurations(properties) that we load a t server startup from a file. These are then bound to all the components & used for all the requests.
But now, we have multiple property files & load them at startup. These configurations can be different per REST(Jersey) request as they depend on the input.
So, we need to bind these configurations dynamically for each request. I looked into Guice API for #RequestScoped, but did not find anything specificallyu helpful.
There are few questions similar to this, but no luck yet. Can you please help me with this.
I'm providing 2 ways of doing this and both are request scoped.
Using HttpServletRequest, for classes where you can Inject request object.
Using ThreadLocal, Generic way. It can be used in any class.
(NOTE: This method wouldn't work if your creating new threads in your code and want to access the value. In which case you'll have to pass the values through Objects to those threads)
I meant something like this:
public class RequestFilter implements ContainerRequestFilter {
#Context
private HttpServletRequest request;
#Override
public void filter(ContainerRequestContext requestContext) throws IOException {
List listOfConfig = //load Config;
request.setAttribute("LOADED_CONFIG",listOfConfig);
// If you want to access this value at some place where Request object cannot be injected (like in service layers, etc.) Then use below ThreadLocals.
ThreadLocalWrapper.getInstance().get().add("adbc"); // In general add your config here, instead of abdc.
}
}
My ThreadLocalWrapper looks like this:
public class ThreadLocalWrapper {
private static ThreadLocal<List<String>> listOfStringLocals; // You can modify this to a list of Object or an Object by itself.
public static synchronized ThreadLocal<List<String>> getInstance() {
if (listOfStringLocals == null) {
listOfStringLocals = new ThreadLocal<List<String>>() {
#Override
protected List<String> initialValue() {
return new ArrayList<String>();
}
};
}
return listOfStringLocals;
}
}
To Access the value:
In Controller - Inject HttpServletRequest Object and do getAttribute() to get the value. Since HttpServletRequest Object is requestScoped, you can set the loaded config. into this and access it in your controller's using request Object again.
In Any other part of the code - If HttpServletRequest is not available then you can always use the ThreadLocal example shown. To access this value.
public class GuiceTransactionImpl implements GuiceTransaction {
private String value = "";
public GuiceTransactionImpl(String text) {
value = text;
}
#Override
public String returnSuccess() {
return value + " Thread Local Value " + ThreadLocalWrapper.getInstance().get();
}
}

Access the HttpRequest with Restfulie?

This seems like a straightforward question, but I can't find it in the Restfulie documentation nor is Google coming up with an example.
I've got a Resource defined, the method is getting invoked, but I need to get to the query parameters on the URL that was used, which presumably means getting to the HttpRequest. Anyone know how you do that with Restfulie?
#Resource
public class Subscribers
{
private final Result result;
public Subscribers(Result result ){
this.result = result;
}
#Get
#Path("/subscribers")
public void get() {
// Need to get at the query parameters here...
result.use( json() ).from( "You got me" ).serialize();
}
}
Try this way
#Get
#Path("/subscribers")
public void get(#QueryParam("name") String name) {
}
your have to append the keys and values to the request URL. also you need to encode the values.
http://mydomain/subscribers?name=abcde

Categories