glassfish
  1. glassfish
  2. GLASSFISH-20731

Application deployed on standalone instance does not initialize database

    Details

    • Type: Improvement Improvement
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 3.1.2_b08, 4.0
    • Fix Version/s: None
    • Component/s: ejb_container
    • Labels:
      None
    • Environment:

      glassfish DAS with several standalone instances under control

      Description

      This problem has deep roots. First of all - for some strange reason all resources has domain global definitions. I.e. if I have same application deployed on each, dedicated for customer, standalone instance and I really want each application use it's own database - how should I do that? Since connection pool definition is shared across all instances I either have to alter each application installation and point it to different jdbc resource (create dedicated pools and jdbc resources for all of them, which is tedios) or configure pool using system property references like $

      {database.name.system.property}

      and provide different values at different instances. Latter approach is OK, but works only for jdbc pools - custom resources would not expand system properties in values and $

      {my.custom.resource.value}

      will stay like this.
      Back to the jdbc pools and deployment issues. Right now, when you deploy application at some standalone instance, initial database initialization happens on DAS. I.e., all tables will be created at database which DAS sees, not at database which instance will see considering mentioned above configuration approach. When application will be actually deployed at standalone instance - no database initialization will happen because this is actually not a "deployment" but "load". This creates obvious problem - database that application will be actually using does not contain proper tables and DAS will actually complain during deployment if database that it sees either inaccessible or already contains all structures (not mentioning the fact that this database MUST exists for no good reason, since DAS itself will never use it).
      More to that, issue with database initialization basically breaks Timer Service at each standalone instance! If application use scheduled EJB methods glassfish will try to create Timer Service (by deploing ejb-timer-service-app.war) and since it is happening at instance not at DAS, database for _TimerPool will NOT be initialized which causes "EJBTIMER_TBL table does not exists" exceptions during runtime.
      I see not good reason having "load" mode deployment happens at instance level first of all, in my opinion DAS should use "load" and instance "deploy".

        Activity

        Hide
        Hong Zhang added a comment -

        I think all the resources need to be explicitly created on the standalone instances (except for a few system default resources which are now available automatically on all instances in late 4.0 builds), but I will let resource team provide more accurate comments on this.

        Show
        Hong Zhang added a comment - I think all the resources need to be explicitly created on the standalone instances (except for a few system default resources which are now available automatically on all instances in late 4.0 builds), but I will let resource team provide more accurate comments on this.
        Hide
        gray added a comment -

        There is no way to "explicitly create resource on the standalone instance". Pool is just pool - you can't specify where it is actually created. Jdbc resource can be assigned to set of instances, but same resource can't point to different pools for different standalone instances, and therefore I still can't use different databases for different instances.
        But main issue is actually Timer Service failure - what can you say about that?

        Show
        gray added a comment - There is no way to "explicitly create resource on the standalone instance". Pool is just pool - you can't specify where it is actually created. Jdbc resource can be assigned to set of instances, but same resource can't point to different pools for different standalone instances, and therefore I still can't use different databases for different instances. But main issue is actually Timer Service failure - what can you say about that?
        Hide
        gray added a comment -

        So, any news on this?

        Show
        gray added a comment - So, any news on this?
        Hide
        Jagadish added a comment -

        There may not be a complete solution, but here is my attempt :

        To be able to have customized pool configuration for each instance :
        I don't think it's possible (other than the system-property approach you are already aware of), since both application and resources are meant to be uniform (homogeneous) across standalone instances/clusters. This is by design.

        An alternate approach I can think of is to use application scoped resources.
        a) via GlassFish specific glassfish-resources.xml
        or
        b) Java EE 7 descriptors which support @DatasourceDefintion, @MailSessionDefinition, @JMSConnectionFactory, @ConnectionFactoryDefinition etc., (@DataSourceDefinition is available from Java EE 6). You can specify these annotation equivalents in the appropriate descriptors (eg: ejb-jar.xml, web.xml, application.xml etc.,)

        So, you can deploy multiple copies of same application (by different name) in DAS each using different glassfish-resources.xml (or standard descriptors) and then enable them selectively in standalone instances/clusters.

        Show
        Jagadish added a comment - There may not be a complete solution, but here is my attempt : To be able to have customized pool configuration for each instance : I don't think it's possible (other than the system-property approach you are already aware of), since both application and resources are meant to be uniform (homogeneous) across standalone instances/clusters. This is by design. An alternate approach I can think of is to use application scoped resources. a) via GlassFish specific glassfish-resources.xml or b) Java EE 7 descriptors which support @DatasourceDefintion, @MailSessionDefinition, @JMSConnectionFactory, @ConnectionFactoryDefinition etc., (@DataSourceDefinition is available from Java EE 6). You can specify these annotation equivalents in the appropriate descriptors (eg: ejb-jar.xml, web.xml, application.xml etc.,) So, you can deploy multiple copies of same application (by different name) in DAS each using different glassfish-resources.xml (or standard descriptors) and then enable them selectively in standalone instances/clusters.
        Hide
        gray added a comment -

        It looks like you have misunderstood the topic
        I have resolved problem with making different applications use different databases with system properties - and I'm pretty happy with that. The problem is that database that this application is pointing to does not get initialized with schema structure (i.e. create-tables not happening). This in particular causing TimerService to fail. Timer service war get deployed at standalone instance during first use of the timers in one of the applications. Since I don't want centralized timer service (all my application instances are independent) I did not configure it to use some central database intentionally - i.e. timer service use derby db that is created during startup. When application get deployed on standalone instance it use "load" deployment mode and because of that all "create-table" steps skipped. Timer service will eventually try to make query against this database and fail because EJB_TIMER_TBL does not exists.

        Regarding you suggestion for using glassfish-resources.xml and JavaEE 7 - both are unacceptable, because I don't want to have different ear file for each instance, this is actually exactly what I want to avoid first of all.

        Regarding "uniform (homogenious) resources" - I can understand why this is true for clusters, but for standalone instances? As I see use case for standalone instances - I use DAS as single point of configuration and each standalone instance is independent application server that generally may have nothing to do with other standalone instances under same DAS. Or am I wrong?

        Show
        gray added a comment - It looks like you have misunderstood the topic I have resolved problem with making different applications use different databases with system properties - and I'm pretty happy with that. The problem is that database that this application is pointing to does not get initialized with schema structure (i.e. create-tables not happening). This in particular causing TimerService to fail. Timer service war get deployed at standalone instance during first use of the timers in one of the applications. Since I don't want centralized timer service (all my application instances are independent) I did not configure it to use some central database intentionally - i.e. timer service use derby db that is created during startup. When application get deployed on standalone instance it use "load" deployment mode and because of that all "create-table" steps skipped. Timer service will eventually try to make query against this database and fail because EJB_TIMER_TBL does not exists. Regarding you suggestion for using glassfish-resources.xml and JavaEE 7 - both are unacceptable, because I don't want to have different ear file for each instance, this is actually exactly what I want to avoid first of all. Regarding "uniform (homogenious) resources" - I can understand why this is true for clusters, but for standalone instances? As I see use case for standalone instances - I use DAS as single point of configuration and each standalone instance is independent application server that generally may have nothing to do with other standalone instances under same DAS. Or am I wrong?
        Hide
        Jagadish added a comment -

        OK. This looks like deployment+timer-service related query. I shall transfer this to ejb component.

        w.r.t homogeneous resources :
        Applications and resources are global in nature, one can enable them in individual targets cluster/standalone instances based on their need. This is by design.
        If they were not global (domain wide), what you are suggesting would have been feasible.

        Show
        Jagadish added a comment - OK. This looks like deployment+timer-service related query. I shall transfer this to ejb component. w.r.t homogeneous resources : Applications and resources are global in nature, one can enable them in individual targets cluster/standalone instances based on their need. This is by design. If they were not global (domain wide), what you are suggesting would have been feasible.
        Hide
        gray added a comment -

        I understood that this is "by design" - I just don't understand why this is designed like this. What is the use case?

        And by the way - I really doubt that this issue have anything to do with jdbc (may be JPA), since table creation step get completely skipped because of that code:

        package org.glassfish.ejb.persistent.timer;
        ...
        public class PersistentEJBTimerService extends EJBTimerService {
        ...
            private static boolean deployEJBTimerService(File root, File appScratchFile, 
                    String resourceName, boolean is_upgrade) {
        ...
                        if (_ejbContainerUtil.isDas() && appScratchFile.createNewFile() && !is_upgrade) {
                            params.origin = OpsParams.Origin.deploy; // this is for DAS
                        } else {
                            params.origin = OpsParams.Origin.load; // this is for instance/cluster
                        }
        ...
        

        Note that if we are currently not at DAS origin will be set to "load".
        And later JPADeployer:

        package org.glassfish.persistence.jpa;
        ...
        public class JPADeployer extends SimpleDeployer<JPAContainer, JPApplicationContainer> implements PostConstruct, EventListener {
        ...
            private void iterateInitializedPUsAtApplicationPrepare(final DeploymentContext context) {
        ...
                PersistenceUnitDescriptorIterator pudIterator = new PersistenceUnitDescriptorIterator() {
                    @Override void visitPUD(PersistenceUnitDescriptor pud, DeploymentContext context) {
        ...
                            if(isDas()) { //We do validation and execute Java2DB only on DAS
                                if(deployCommandParameters.origin.isDeploy()) { //APPLICATION_PREPARED will be called for create-application-ref also. We should perform java2db only on first deploy
        ...
        

        In case of Timer Service application on standalone instance it is obvious that "isDaS()" is false along with "origin.isDeploy()" and no database initialization happen.

        Show
        gray added a comment - I understood that this is "by design" - I just don't understand why this is designed like this. What is the use case? And by the way - I really doubt that this issue have anything to do with jdbc (may be JPA), since table creation step get completely skipped because of that code: package org.glassfish.ejb.persistent.timer; ... public class PersistentEJBTimerService extends EJBTimerService { ... private static boolean deployEJBTimerService(File root, File appScratchFile, String resourceName, boolean is_upgrade) { ... if (_ejbContainerUtil.isDas() && appScratchFile.createNewFile() && !is_upgrade) { params.origin = OpsParams.Origin.deploy; // this is for DAS } else { params.origin = OpsParams.Origin.load; // this is for instance/cluster } ... Note that if we are currently not at DAS origin will be set to "load". And later JPADeployer: package org.glassfish.persistence.jpa; ... public class JPADeployer extends SimpleDeployer<JPAContainer, JPApplicationContainer> implements PostConstruct, EventListener { ... private void iterateInitializedPUsAtApplicationPrepare( final DeploymentContext context) { ... PersistenceUnitDescriptorIterator pudIterator = new PersistenceUnitDescriptorIterator() { @Override void visitPUD(PersistenceUnitDescriptor pud, DeploymentContext context) { ... if (isDas()) { //We do validation and execute Java2DB only on DAS if (deployCommandParameters.origin.isDeploy()) { //APPLICATION_PREPARED will be called for create-application-ref also. We should perform java2db only on first deploy ... In case of Timer Service application on standalone instance it is obvious that "isDaS()" is false along with "origin.isDeploy()" and no database initialization happen.
        Hide
        marina vatkina added a comment -

        This is per design - the Timer Service on DAS sometimes needs to precreate the timers and it can't support more than one database at this time. So changing to an RFE.

        Until then you can create the tables manually - the DLL is available under glassfish3/glassfish/lib/install/databases or glassfish4/glassfish/lib/install/databases

        Show
        marina vatkina added a comment - This is per design - the Timer Service on DAS sometimes needs to precreate the timers and it can't support more than one database at this time. So changing to an RFE. Until then you can create the tables manually - the DLL is available under glassfish3/glassfish/lib/install/databases or glassfish4/glassfish/lib/install/databases

          People

          • Assignee:
            marina vatkina
            Reporter:
            gray
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated: