I.4.  SJS source files organization

I.4.1. Default organization

When a project is initialized using the Jspresso application archetype, 5 standard SJS source files are created :

  • application.groovy is a wrapper for the other files. You will rarely modify it unless you want to change the default project setup (to split the SJS files in functional domains for instance).

  • model.groovy contains the application domain model (compiled using SJS Domain).

  • view.groovy contains the application views (compiled using SJS Front).

  • frontend.groovy contains everything that is frontend related but distinct from the views, e.g. modules and workspaces for instance (compiled using SJS Front).

  • backend.groovy contains everything that is backend related but distinct from the domain model, e.g. backend actions for instance (compiled using SJS Front).

All the boiler plate SJS code is already written in application.groovy. This means that you don't have to deal with the application namespace, error reporting, and so on. All you have to do is directly write you application SJS code into the pre-initialized SJS files. For instance, the following declaration in model.groovy is enough to generate an entity :

Entity('Person') {
  string_32 'name'
  integer 'age'
}

I.4.2. Further modularization

You can further modularize SJS applications using the include statement :

include('filename.groovy')

included files are merged exactly as if all their statements had been written directly into the in the including SJS source file. This is actually the same mecanism that is used by the application.groovy wrapper to include the standard SJS source files.

I.4.3. Identifiers unicity scope and "spec" section

As a general rule, component identifers must be unique across the appliction. If 2 components are declared using the same identifier, SJS will raise a compilation error duringthe build.

However, SJS allows an advanced usage in order to open specific scopes in which you can define components with the same identifier. A typical usage of this feature is to declare different implementation for the same identifier depending on the UI channel (e.g. Qooxdoo vs Flex vs Swing). This specific scopes feature is only available for SJS Front and not for SJS Domain.

Opening a specific scope is achieved using the spec statement, e.g. :

spec('qooxdoo') {
    ...
}
spec('flex') {
    ...
}
spec('swing') {
    ...
}

All the declarations that are placed inside the spec closure belong to this scope.

Contrary to what you might believe, components that are declared in a specific scope are visible from their inner AND outer scopes. They are only isolated from their same level scopes.

Scopes meaning are not limited to UI based customization. You could define staging scopes like development pre-production and production.

Scopes are then used in application.groovy to write specific Spring XML context files that are afterwards used to compose specific Spring contexts to declare in beanRefFactory.xml.

In application.groovy :

frontendBuilder.writeOutputFile('swing',
     project.properties['outputDir'],
     'swing-'+project.properties['viewOutputFileName'])

This will produce a custom swing-dsl-view.xml Spring context file in the build output directory. This custom Spring context file is then available for inclusion in a custom Spring context.

In beanRefFactory.xml :

  <bean
    id="hrsample-swing-context"
    class="org.springframework.context.support.ClassPathXmlApplicationContext"
    lazy-init="true">
    <constructor-arg>
      <list>
        ...
        <value>org/jspresso/hrsample/spec/swing-dsl-view.xml</value>
        ...
      </list>
    </constructor-arg>
  </bean>