Camel 3.x and multiple contexts

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Camel 3.x and multiple contexts

scsynergy
Hello everyone,

with version 3 Camel has dropped support for multiple Camel contexts,
which we have been using extensively. Our software may be licensed as
on-premises or as cloud service and offers every customer the option of
using Camel to e. g. import files from email servers (or FTP or REST
etc.) or publish files / data via REST / SQL / SMB etc. to external servers.

With Camel 2.x we created a separate Camel context for each customer to
ensure that:
1. every customer can choose a meaningful route id (e. g.
"text-extraction" or "invoices") without duplicates causing errors
2. customers may only edit their own configuration and start / stop
their own routes / context
3. customers do not have access to other customers' routes (e. g. by
allowing the "vm" component to only address routes within the same context)
3. configuration errors do not cause Camel processing of other customers
to stop working
4. we can just copy a customer's Camel configuration from our cloud
system to an on-premises system or vice versa if the customer wishes to
change his license
5. our support team may quickly and easily help in configuring or
troubleshooting Camel without having to identify which routes belong to
whom first

So, my question is: With Camel 3+ how may we achieve the same separation
of services? Info: We use Wildfly application server as environment for
our code to run (on Linux and Windows).

Best regards
Ronny
--
*sc synergy GmbH*
Hilgestrasse 14 | 55294 Bodenheim | Deutschland
Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
http://www.scsynergy.com | [hidden email]
Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
Geschäftsführer: Christian Reichert
Reply | Threaded
Open this post in threaded view
|

Re: Camel 3.x and multiple contexts

skin27
Hi Ronald,

I can't tell about the separation within Camel. I can however say how I see
how this is done. For example separate the integration from the application
and then start every integration in a separate process or Docker container

Kind regards,

Raymond

Op di 31 mrt. 2020 om 15:04 schreef Ronald Feicht <
[hidden email]>:

> Hello everyone,
>
> with version 3 Camel has dropped support for multiple Camel contexts,
> which we have been using extensively. Our software may be licensed as
> on-premises or as cloud service and offers every customer the option of
> using Camel to e. g. import files from email servers (or FTP or REST
> etc.) or publish files / data via REST / SQL / SMB etc. to external
> servers.
>
> With Camel 2.x we created a separate Camel context for each customer to
> ensure that:
> 1. every customer can choose a meaningful route id (e. g.
> "text-extraction" or "invoices") without duplicates causing errors
> 2. customers may only edit their own configuration and start / stop
> their own routes / context
> 3. customers do not have access to other customers' routes (e. g. by
> allowing the "vm" component to only address routes within the same context)
> 3. configuration errors do not cause Camel processing of other customers
> to stop working
> 4. we can just copy a customer's Camel configuration from our cloud
> system to an on-premises system or vice versa if the customer wishes to
> change his license
> 5. our support team may quickly and easily help in configuring or
> troubleshooting Camel without having to identify which routes belong to
> whom first
>
> So, my question is: With Camel 3+ how may we achieve the same separation
> of services? Info: We use Wildfly application server as environment for
> our code to run (on Linux and Windows).
>
> Best regards
> Ronny
> --
> *sc synergy GmbH*
> Hilgestrasse 14 | 55294 Bodenheim | Deutschland
> Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
> http://www.scsynergy.com | [hidden email]
> Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
> Geschäftsführer: Christian Reichert
>
Reply | Threaded
Open this post in threaded view
|

Re: Camel 3.x and multiple contexts

scsynergy
Hi Raymond,

thank you for your answer. We have dismissed the option you mention
because, although that would separate Camel contexts, it would introduce
a plethora of new problems:
We would need to interact with the operating system (OS) to create,
remove, start, stop, restart and monitor the external processes or
Docker containers. As it is now, if our application is running we can
rest assured every customer's camel context is up and running until the
application shuts down or we delete the customer.
Interacting with the OS would require different code for Linux and
Windows machines, maybe even for different Windows or Linux versions.
Not to mention the security considerations when doing command line calls.

If nobody has a better idea we will just have to stay with Camel 2.x for
as long as possible and then switch to something completely different,
something that has context separation built-in. Has anybody got a
recommendation for a replacement for Camel?

Best regards
Ronny

On 3/31/20 3:57 PM, ski n wrote:

> Hi Ronald,
>
> I can't tell about the separation within Camel. I can however say how I see
> how this is done. For example separate the integration from the application
> and then start every integration in a separate process or Docker container
>
> Kind regards,
>
> Raymond
>
> Op di 31 mrt. 2020 om 15:04 schreef Ronald Feicht <
> [hidden email]>:
>
>> Hello everyone,
>>
>> with version 3 Camel has dropped support for multiple Camel contexts,
>> which we have been using extensively. Our software may be licensed as
>> on-premises or as cloud service and offers every customer the option of
>> using Camel to e. g. import files from email servers (or FTP or REST
>> etc.) or publish files / data via REST / SQL / SMB etc. to external
>> servers.
>>
>> With Camel 2.x we created a separate Camel context for each customer to
>> ensure that:
>> 1. every customer can choose a meaningful route id (e. g.
>> "text-extraction" or "invoices") without duplicates causing errors
>> 2. customers may only edit their own configuration and start / stop
>> their own routes / context
>> 3. customers do not have access to other customers' routes (e. g. by
>> allowing the "vm" component to only address routes within the same context)
>> 3. configuration errors do not cause Camel processing of other customers
>> to stop working
>> 4. we can just copy a customer's Camel configuration from our cloud
>> system to an on-premises system or vice versa if the customer wishes to
>> change his license
>> 5. our support team may quickly and easily help in configuring or
>> troubleshooting Camel without having to identify which routes belong to
>> whom first
>>
>> So, my question is: With Camel 3+ how may we achieve the same separation
>> of services? Info: We use Wildfly application server as environment for
>> our code to run (on Linux and Windows).
>>
>> Best regards
>> Ronny
>> --
>> *sc synergy GmbH*
>> Hilgestrasse 14 | 55294 Bodenheim | Deutschland
>> Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
>> http://www.scsynergy.com | [hidden email]
>> Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
>> Geschäftsführer: Christian Reichert
>>

--
*sc synergy GmbH*
Hilgestrasse 14 | 55294 Bodenheim | Deutschland
Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
http://www.scsynergy.com | [hidden email]
Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
Geschäftsführer: Christian Reichert
Reply | Threaded
Open this post in threaded view
|

Re: Camel 3.x and multiple contexts

Claus Ibsen-2
In reply to this post by scsynergy
Hi

You can run as many camel contexts as you like in a JVM.

For example on WildFly or Karaf you can just deploy multiple XML files
(deployments) each with their own <camelContext>.
In other word manage each customer in their own xml file and have them
separated.

Then each deployment is per customer and they can manage that as now,
eg stop/start routes and whatnot.

It was just that in a single XML file you could have multiple
<camelContext> which is bad design as then they end up in the same
deployment and have shared lifecycle, and also its harder to separate
resources between them as they may end up picking up the same
resources (eg a data source) as some camel components have built in
defaults to lookup default resources and use them and so on.

Its a bad design and practice. And separation is recommended as
individual deployment units in your application server. Then the
application server manages proper lifecycles, separate classloading
and resources etc.

And this is also where the world is going with cloud and containers to
have separate processes.

And also to get better help for your situation then it would help to
show more exactly what you do today, and provide some examples. That
help everybody to better understand.

On Tue, Mar 31, 2020 at 3:04 PM Ronald Feicht
<[hidden email]> wrote:

>
> Hello everyone,
>
> with version 3 Camel has dropped support for multiple Camel contexts,
> which we have been using extensively. Our software may be licensed as
> on-premises or as cloud service and offers every customer the option of
> using Camel to e. g. import files from email servers (or FTP or REST
> etc.) or publish files / data via REST / SQL / SMB etc. to external servers.
>
> With Camel 2.x we created a separate Camel context for each customer to
> ensure that:
> 1. every customer can choose a meaningful route id (e. g.
> "text-extraction" or "invoices") without duplicates causing errors
> 2. customers may only edit their own configuration and start / stop
> their own routes / context
> 3. customers do not have access to other customers' routes (e. g. by
> allowing the "vm" component to only address routes within the same context)
> 3. configuration errors do not cause Camel processing of other customers
> to stop working
> 4. we can just copy a customer's Camel configuration from our cloud
> system to an on-premises system or vice versa if the customer wishes to
> change his license
> 5. our support team may quickly and easily help in configuring or
> troubleshooting Camel without having to identify which routes belong to
> whom first
>
> So, my question is: With Camel 3+ how may we achieve the same separation
> of services? Info: We use Wildfly application server as environment for
> our code to run (on Linux and Windows).
>
> Best regards
> Ronny
> --
> *sc synergy GmbH*
> Hilgestrasse 14 | 55294 Bodenheim | Deutschland
> Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
> http://www.scsynergy.com | [hidden email]
> Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
> Geschäftsführer: Christian Reichert



--
Claus Ibsen
-----------------
http://davsclaus.com @davsclaus
Camel in Action 2: https://www.manning.com/ibsen2
Reply | Threaded
Open this post in threaded view
|

Re: Camel 3.x and multiple contexts

scsynergy
Hi Claus,

I am not sure I understand it fully: We use separate xml files for each
customer which we keep in the database. With these we start a separate
CamelContext instance from within our code (war file). So, even though
we have multiple xml files, all Camel contexts are created and
controlled from one Java class dynamically. Is our way of doing things
different from having multiple Camel contexts in a single xml file?

This is the class in question:

@Startup
@Singleton
public class Bootstrap {

     @Inject
     private BeanManager manager;
     @Inject
     private CollectionDispenser collectionDispenser;
     private Map<String, TenantCamelContext> contexts = new HashMap<>();

     @PostConstruct
     public void init() {
         createCamelContextForEachTenantExceptDefaultTenant();
     }

     /**
      * When a tenant is deleted the corresponding Camel context should be
      * stopped via
      * <pre>
      * {@code
      * tenantContext.cleanup();
      * }</pre>
      */
     public void destroyCamelContextOfDeletedTenant(String tenantId) {
         if (tenantId != null && !tenantId.isEmpty()) {
             TenantCamelContext tenantContext = contexts.get(tenantId);
             if (tenantContext != null) {
                 tenantContext.cleanup();
                 contexts.remove(tenantId);
             }
         }
     }

     /**
      * This method checks whether the context has previously been
created and
      * otherwise creates and starts the tenant's corresponding Camel
context.
      */
     public void createCamelContextForNewTenant(String tenantId) {
         if (tenantId != null && !tenantId.isEmpty() &&
contexts.get(tenantId) == null) {
             TenantCamelContext tenantContext = bootstrap(tenantId);
             if (tenantContext != null) {
                 contexts.put(tenantContext.getName(), tenantContext);
             }
         }
     }

     private void createCamelContextForEachTenantExceptDefaultTenant() {
         try (MongoCursor<Tenant> cursor =
collectionDispenser.getMongoCollection(Tenant.DEFAULTTENANTID, null,
Tenant.class).find().sort(new Document(TenantBasicDBDummy.TENANTID,
1)).iterator()) {
             while (cursor.hasNext()) {
                 Tenant tenant = cursor.next();
                 if (tenant.getTenantId() != null &&
!tenant.getTenantId().isEmpty()) {
                     TenantCamelContext tenantContext =
bootstrap(tenant.getTenantId());
                     if (tenantContext != null) {
                         contexts.put(tenantContext.getName(),
tenantContext);
                     }
                 }
             }
         }
     }

     private TenantCamelContext bootstrap(String camelContextTenantName) {
         Set<Bean<?>> beans = manager.getBeans(TenantCamelContext.class);
         if (beans != null && !beans.isEmpty()) {
             Bean<TenantCamelContext> bean = (Bean<TenantCamelContext>)
manager.resolve(beans);
             CreationalContext<TenantCamelContext> creational =
manager.createCreationalContext(bean);
             AnnotatedType<TenantCamelContext> annotatedType =
manager.createAnnotatedType(TenantCamelContext.class);
             InjectionTargetFactory<TenantCamelContext> factory =
manager.getInjectionTargetFactory(annotatedType);
             InjectionTarget<TenantCamelContext> target =
factory.createInjectionTarget(bean);
             TenantCamelContext camel = target.produce(creational);
             camel.setName(camelContextTenantName);
             target.inject(camel, creational);
             target.postConstruct(camel);
             camel.setApplicationContextClassLoader(new
GroovyClassLoader());
             creational.push(camel);
             return camel;
         }
         return null;
     }

     @PreDestroy
     public void cleanup() {
         for (TenantCamelContext tmp : contexts.values()) {
             FutureTask<Void> task = new FutureTask<>(() -> {
                 tmp.cleanup();
                 return null;
             });
Executors.newSingleThreadScheduledExecutor().execute(task);
         }
     }

     public Map<String, TenantCamelContext> getContexts() {
         return contexts;
     }
}

So, is this way of doing it still supported?

Best regards
Ronny

On 4/1/20 9:42 AM, Claus Ibsen wrote:

> Hi
>
> You can run as many camel contexts as you like in a JVM.
>
> For example on WildFly or Karaf you can just deploy multiple XML files
> (deployments) each with their own <camelContext>.
> In other word manage each customer in their own xml file and have them
> separated.
>
> Then each deployment is per customer and they can manage that as now,
> eg stop/start routes and whatnot.
>
> It was just that in a single XML file you could have multiple
> <camelContext> which is bad design as then they end up in the same
> deployment and have shared lifecycle, and also its harder to separate
> resources between them as they may end up picking up the same
> resources (eg a data source) as some camel components have built in
> defaults to lookup default resources and use them and so on.
>
> Its a bad design and practice. And separation is recommended as
> individual deployment units in your application server. Then the
> application server manages proper lifecycles, separate classloading
> and resources etc.
>
> And this is also where the world is going with cloud and containers to
> have separate processes.
>
> And also to get better help for your situation then it would help to
> show more exactly what you do today, and provide some examples. That
> help everybody to better understand.
>
> On Tue, Mar 31, 2020 at 3:04 PM Ronald Feicht
> <[hidden email]> wrote:
>> Hello everyone,
>>
>> with version 3 Camel has dropped support for multiple Camel contexts,
>> which we have been using extensively. Our software may be licensed as
>> on-premises or as cloud service and offers every customer the option of
>> using Camel to e. g. import files from email servers (or FTP or REST
>> etc.) or publish files / data via REST / SQL / SMB etc. to external servers.
>>
>> With Camel 2.x we created a separate Camel context for each customer to
>> ensure that:
>> 1. every customer can choose a meaningful route id (e. g.
>> "text-extraction" or "invoices") without duplicates causing errors
>> 2. customers may only edit their own configuration and start / stop
>> their own routes / context
>> 3. customers do not have access to other customers' routes (e. g. by
>> allowing the "vm" component to only address routes within the same context)
>> 3. configuration errors do not cause Camel processing of other customers
>> to stop working
>> 4. we can just copy a customer's Camel configuration from our cloud
>> system to an on-premises system or vice versa if the customer wishes to
>> change his license
>> 5. our support team may quickly and easily help in configuring or
>> troubleshooting Camel without having to identify which routes belong to
>> whom first
>>
>> So, my question is: With Camel 3+ how may we achieve the same separation
>> of services? Info: We use Wildfly application server as environment for
>> our code to run (on Linux and Windows).
>>
>> Best regards
>> Ronny
>> --
>> *sc synergy GmbH*
>> Hilgestrasse 14 | 55294 Bodenheim | Deutschland
>> Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
>> http://www.scsynergy.com | [hidden email]
>> Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
>> Geschäftsführer: Christian Reichert
>
>

--
*sc synergy GmbH*
Hilgestrasse 14 | 55294 Bodenheim | Deutschland
Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
http://www.scsynergy.com | [hidden email]
Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
Geschäftsführer: Christian Reichert
Reply | Threaded
Open this post in threaded view
|

Re: Camel 3.x and multiple contexts

Claus Ibsen-2
Hi

What you do is a custom bootstrapping of Camels. You can still do that.
Just mind about the pros/cons of doing this - also for 2.x.

So you can try and test your way with the Camel 3 releases.

On Wed, Apr 1, 2020 at 2:14 PM Ronald Feicht <[hidden email]> wrote:

>
> Hi Claus,
>
> I am not sure I understand it fully: We use separate xml files for each
> customer which we keep in the database. With these we start a separate
> CamelContext instance from within our code (war file). So, even though
> we have multiple xml files, all Camel contexts are created and
> controlled from one Java class dynamically. Is our way of doing things
> different from having multiple Camel contexts in a single xml file?
>
> This is the class in question:
>
> @Startup
> @Singleton
> public class Bootstrap {
>
>      @Inject
>      private BeanManager manager;
>      @Inject
>      private CollectionDispenser collectionDispenser;
>      private Map<String, TenantCamelContext> contexts = new HashMap<>();
>
>      @PostConstruct
>      public void init() {
>          createCamelContextForEachTenantExceptDefaultTenant();
>      }
>
>      /**
>       * When a tenant is deleted the corresponding Camel context should be
>       * stopped via
>       * <pre>
>       * {@code
>       * tenantContext.cleanup();
>       * }</pre>
>       */
>      public void destroyCamelContextOfDeletedTenant(String tenantId) {
>          if (tenantId != null && !tenantId.isEmpty()) {
>              TenantCamelContext tenantContext = contexts.get(tenantId);
>              if (tenantContext != null) {
>                  tenantContext.cleanup();
>                  contexts.remove(tenantId);
>              }
>          }
>      }
>
>      /**
>       * This method checks whether the context has previously been
> created and
>       * otherwise creates and starts the tenant's corresponding Camel
> context.
>       */
>      public void createCamelContextForNewTenant(String tenantId) {
>          if (tenantId != null && !tenantId.isEmpty() &&
> contexts.get(tenantId) == null) {
>              TenantCamelContext tenantContext = bootstrap(tenantId);
>              if (tenantContext != null) {
>                  contexts.put(tenantContext.getName(), tenantContext);
>              }
>          }
>      }
>
>      private void createCamelContextForEachTenantExceptDefaultTenant() {
>          try (MongoCursor<Tenant> cursor =
> collectionDispenser.getMongoCollection(Tenant.DEFAULTTENANTID, null,
> Tenant.class).find().sort(new Document(TenantBasicDBDummy.TENANTID,
> 1)).iterator()) {
>              while (cursor.hasNext()) {
>                  Tenant tenant = cursor.next();
>                  if (tenant.getTenantId() != null &&
> !tenant.getTenantId().isEmpty()) {
>                      TenantCamelContext tenantContext =
> bootstrap(tenant.getTenantId());
>                      if (tenantContext != null) {
>                          contexts.put(tenantContext.getName(),
> tenantContext);
>                      }
>                  }
>              }
>          }
>      }
>
>      private TenantCamelContext bootstrap(String camelContextTenantName) {
>          Set<Bean<?>> beans = manager.getBeans(TenantCamelContext.class);
>          if (beans != null && !beans.isEmpty()) {
>              Bean<TenantCamelContext> bean = (Bean<TenantCamelContext>)
> manager.resolve(beans);
>              CreationalContext<TenantCamelContext> creational =
> manager.createCreationalContext(bean);
>              AnnotatedType<TenantCamelContext> annotatedType =
> manager.createAnnotatedType(TenantCamelContext.class);
>              InjectionTargetFactory<TenantCamelContext> factory =
> manager.getInjectionTargetFactory(annotatedType);
>              InjectionTarget<TenantCamelContext> target =
> factory.createInjectionTarget(bean);
>              TenantCamelContext camel = target.produce(creational);
>              camel.setName(camelContextTenantName);
>              target.inject(camel, creational);
>              target.postConstruct(camel);
>              camel.setApplicationContextClassLoader(new
> GroovyClassLoader());
>              creational.push(camel);
>              return camel;
>          }
>          return null;
>      }
>
>      @PreDestroy
>      public void cleanup() {
>          for (TenantCamelContext tmp : contexts.values()) {
>              FutureTask<Void> task = new FutureTask<>(() -> {
>                  tmp.cleanup();
>                  return null;
>              });
> Executors.newSingleThreadScheduledExecutor().execute(task);
>          }
>      }
>
>      public Map<String, TenantCamelContext> getContexts() {
>          return contexts;
>      }
> }
>
> So, is this way of doing it still supported?
>
> Best regards
> Ronny
>
> On 4/1/20 9:42 AM, Claus Ibsen wrote:
> > Hi
> >
> > You can run as many camel contexts as you like in a JVM.
> >
> > For example on WildFly or Karaf you can just deploy multiple XML files
> > (deployments) each with their own <camelContext>.
> > In other word manage each customer in their own xml file and have them
> > separated.
> >
> > Then each deployment is per customer and they can manage that as now,
> > eg stop/start routes and whatnot.
> >
> > It was just that in a single XML file you could have multiple
> > <camelContext> which is bad design as then they end up in the same
> > deployment and have shared lifecycle, and also its harder to separate
> > resources between them as they may end up picking up the same
> > resources (eg a data source) as some camel components have built in
> > defaults to lookup default resources and use them and so on.
> >
> > Its a bad design and practice. And separation is recommended as
> > individual deployment units in your application server. Then the
> > application server manages proper lifecycles, separate classloading
> > and resources etc.
> >
> > And this is also where the world is going with cloud and containers to
> > have separate processes.
> >
> > And also to get better help for your situation then it would help to
> > show more exactly what you do today, and provide some examples. That
> > help everybody to better understand.
> >
> > On Tue, Mar 31, 2020 at 3:04 PM Ronald Feicht
> > <[hidden email]> wrote:
> >> Hello everyone,
> >>
> >> with version 3 Camel has dropped support for multiple Camel contexts,
> >> which we have been using extensively. Our software may be licensed as
> >> on-premises or as cloud service and offers every customer the option of
> >> using Camel to e. g. import files from email servers (or FTP or REST
> >> etc.) or publish files / data via REST / SQL / SMB etc. to external servers.
> >>
> >> With Camel 2.x we created a separate Camel context for each customer to
> >> ensure that:
> >> 1. every customer can choose a meaningful route id (e. g.
> >> "text-extraction" or "invoices") without duplicates causing errors
> >> 2. customers may only edit their own configuration and start / stop
> >> their own routes / context
> >> 3. customers do not have access to other customers' routes (e. g. by
> >> allowing the "vm" component to only address routes within the same context)
> >> 3. configuration errors do not cause Camel processing of other customers
> >> to stop working
> >> 4. we can just copy a customer's Camel configuration from our cloud
> >> system to an on-premises system or vice versa if the customer wishes to
> >> change his license
> >> 5. our support team may quickly and easily help in configuring or
> >> troubleshooting Camel without having to identify which routes belong to
> >> whom first
> >>
> >> So, my question is: With Camel 3+ how may we achieve the same separation
> >> of services? Info: We use Wildfly application server as environment for
> >> our code to run (on Linux and Windows).
> >>
> >> Best regards
> >> Ronny
> >> --
> >> *sc synergy GmbH*
> >> Hilgestrasse 14 | 55294 Bodenheim | Deutschland
> >> Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
> >> http://www.scsynergy.com | [hidden email]
> >> Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
> >> Geschäftsführer: Christian Reichert
> >
> >
>
> --
> *sc synergy GmbH*
> Hilgestrasse 14 | 55294 Bodenheim | Deutschland
> Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
> http://www.scsynergy.com | [hidden email]
> Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
> Geschäftsführer: Christian Reichert



--
Claus Ibsen
-----------------
http://davsclaus.com @davsclaus
Camel in Action 2: https://www.manning.com/ibsen2
Reply | Threaded
Open this post in threaded view
|

Re: Camel 3.x and multiple contexts

scsynergy
Hi Claus,

thank you for explaining - we greatly appreciate your work.
:-)

Best wishes
Ronny

On 4/2/20 11:24 AM, Claus Ibsen wrote:

> Hi
>
> What you do is a custom bootstrapping of Camels. You can still do that.
> Just mind about the pros/cons of doing this - also for 2.x.
>
> So you can try and test your way with the Camel 3 releases.
>
> On Wed, Apr 1, 2020 at 2:14 PM Ronald Feicht <[hidden email]> wrote:
>> Hi Claus,
>>
>> I am not sure I understand it fully: We use separate xml files for each
>> customer which we keep in the database. With these we start a separate
>> CamelContext instance from within our code (war file). So, even though
>> we have multiple xml files, all Camel contexts are created and
>> controlled from one Java class dynamically. Is our way of doing things
>> different from having multiple Camel contexts in a single xml file?
>>
>> This is the class in question:
>>
>> @Startup
>> @Singleton
>> public class Bootstrap {
>>
>>       @Inject
>>       private BeanManager manager;
>>       @Inject
>>       private CollectionDispenser collectionDispenser;
>>       private Map<String, TenantCamelContext> contexts = new HashMap<>();
>>
>>       @PostConstruct
>>       public void init() {
>>           createCamelContextForEachTenantExceptDefaultTenant();
>>       }
>>
>>       /**
>>        * When a tenant is deleted the corresponding Camel context should be
>>        * stopped via
>>        * <pre>
>>        * {@code
>>        * tenantContext.cleanup();
>>        * }</pre>
>>        */
>>       public void destroyCamelContextOfDeletedTenant(String tenantId) {
>>           if (tenantId != null && !tenantId.isEmpty()) {
>>               TenantCamelContext tenantContext = contexts.get(tenantId);
>>               if (tenantContext != null) {
>>                   tenantContext.cleanup();
>>                   contexts.remove(tenantId);
>>               }
>>           }
>>       }
>>
>>       /**
>>        * This method checks whether the context has previously been
>> created and
>>        * otherwise creates and starts the tenant's corresponding Camel
>> context.
>>        */
>>       public void createCamelContextForNewTenant(String tenantId) {
>>           if (tenantId != null && !tenantId.isEmpty() &&
>> contexts.get(tenantId) == null) {
>>               TenantCamelContext tenantContext = bootstrap(tenantId);
>>               if (tenantContext != null) {
>>                   contexts.put(tenantContext.getName(), tenantContext);
>>               }
>>           }
>>       }
>>
>>       private void createCamelContextForEachTenantExceptDefaultTenant() {
>>           try (MongoCursor<Tenant> cursor =
>> collectionDispenser.getMongoCollection(Tenant.DEFAULTTENANTID, null,
>> Tenant.class).find().sort(new Document(TenantBasicDBDummy.TENANTID,
>> 1)).iterator()) {
>>               while (cursor.hasNext()) {
>>                   Tenant tenant = cursor.next();
>>                   if (tenant.getTenantId() != null &&
>> !tenant.getTenantId().isEmpty()) {
>>                       TenantCamelContext tenantContext =
>> bootstrap(tenant.getTenantId());
>>                       if (tenantContext != null) {
>>                           contexts.put(tenantContext.getName(),
>> tenantContext);
>>                       }
>>                   }
>>               }
>>           }
>>       }
>>
>>       private TenantCamelContext bootstrap(String camelContextTenantName) {
>>           Set<Bean<?>> beans = manager.getBeans(TenantCamelContext.class);
>>           if (beans != null && !beans.isEmpty()) {
>>               Bean<TenantCamelContext> bean = (Bean<TenantCamelContext>)
>> manager.resolve(beans);
>>               CreationalContext<TenantCamelContext> creational =
>> manager.createCreationalContext(bean);
>>               AnnotatedType<TenantCamelContext> annotatedType =
>> manager.createAnnotatedType(TenantCamelContext.class);
>>               InjectionTargetFactory<TenantCamelContext> factory =
>> manager.getInjectionTargetFactory(annotatedType);
>>               InjectionTarget<TenantCamelContext> target =
>> factory.createInjectionTarget(bean);
>>               TenantCamelContext camel = target.produce(creational);
>>               camel.setName(camelContextTenantName);
>>               target.inject(camel, creational);
>>               target.postConstruct(camel);
>>               camel.setApplicationContextClassLoader(new
>> GroovyClassLoader());
>>               creational.push(camel);
>>               return camel;
>>           }
>>           return null;
>>       }
>>
>>       @PreDestroy
>>       public void cleanup() {
>>           for (TenantCamelContext tmp : contexts.values()) {
>>               FutureTask<Void> task = new FutureTask<>(() -> {
>>                   tmp.cleanup();
>>                   return null;
>>               });
>> Executors.newSingleThreadScheduledExecutor().execute(task);
>>           }
>>       }
>>
>>       public Map<String, TenantCamelContext> getContexts() {
>>           return contexts;
>>       }
>> }
>>
>> So, is this way of doing it still supported?
>>
>> Best regards
>> Ronny
>>
>> On 4/1/20 9:42 AM, Claus Ibsen wrote:
>>> Hi
>>>
>>> You can run as many camel contexts as you like in a JVM.
>>>
>>> For example on WildFly or Karaf you can just deploy multiple XML files
>>> (deployments) each with their own <camelContext>.
>>> In other word manage each customer in their own xml file and have them
>>> separated.
>>>
>>> Then each deployment is per customer and they can manage that as now,
>>> eg stop/start routes and whatnot.
>>>
>>> It was just that in a single XML file you could have multiple
>>> <camelContext> which is bad design as then they end up in the same
>>> deployment and have shared lifecycle, and also its harder to separate
>>> resources between them as they may end up picking up the same
>>> resources (eg a data source) as some camel components have built in
>>> defaults to lookup default resources and use them and so on.
>>>
>>> Its a bad design and practice. And separation is recommended as
>>> individual deployment units in your application server. Then the
>>> application server manages proper lifecycles, separate classloading
>>> and resources etc.
>>>
>>> And this is also where the world is going with cloud and containers to
>>> have separate processes.
>>>
>>> And also to get better help for your situation then it would help to
>>> show more exactly what you do today, and provide some examples. That
>>> help everybody to better understand.
>>>
>>> On Tue, Mar 31, 2020 at 3:04 PM Ronald Feicht
>>> <[hidden email]> wrote:
>>>> Hello everyone,
>>>>
>>>> with version 3 Camel has dropped support for multiple Camel contexts,
>>>> which we have been using extensively. Our software may be licensed as
>>>> on-premises or as cloud service and offers every customer the option of
>>>> using Camel to e. g. import files from email servers (or FTP or REST
>>>> etc.) or publish files / data via REST / SQL / SMB etc. to external servers.
>>>>
>>>> With Camel 2.x we created a separate Camel context for each customer to
>>>> ensure that:
>>>> 1. every customer can choose a meaningful route id (e. g.
>>>> "text-extraction" or "invoices") without duplicates causing errors
>>>> 2. customers may only edit their own configuration and start / stop
>>>> their own routes / context
>>>> 3. customers do not have access to other customers' routes (e. g. by
>>>> allowing the "vm" component to only address routes within the same context)
>>>> 3. configuration errors do not cause Camel processing of other customers
>>>> to stop working
>>>> 4. we can just copy a customer's Camel configuration from our cloud
>>>> system to an on-premises system or vice versa if the customer wishes to
>>>> change his license
>>>> 5. our support team may quickly and easily help in configuring or
>>>> troubleshooting Camel without having to identify which routes belong to
>>>> whom first
>>>>
>>>> So, my question is: With Camel 3+ how may we achieve the same separation
>>>> of services? Info: We use Wildfly application server as environment for
>>>> our code to run (on Linux and Windows).
>>>>
>>>> Best regards
>>>> Ronny
>>>> --
>>>> *sc synergy GmbH*
>>>> Hilgestrasse 14 | 55294 Bodenheim | Deutschland
>>>> Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
>>>> http://www.scsynergy.com | [hidden email]
>>>> Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
>>>> Geschäftsführer: Christian Reichert
>>>
>> --
>> *sc synergy GmbH*
>> Hilgestrasse 14 | 55294 Bodenheim | Deutschland
>> Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
>> http://www.scsynergy.com | [hidden email]
>> Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
>> Geschäftsführer: Christian Reichert
>
>

--
*sc synergy GmbH*
Hilgestrasse 14 | 55294 Bodenheim | Deutschland
Fon: +49 6135 71691 - 000 | Fax: +49 6135 71691 - 199
http://www.scsynergy.com | [hidden email]
Sitz der Gesellschaft Bodenheim, HRB 8830, Amtsgericht Mainz,
Geschäftsführer: Christian Reichert