foam3

Overview

FOAM (Feature Oriented Active Modeller), is a full-stack model-driven framework, and Spring Boot, is a popular Java application framework. Both are enterprise-grade frameworks for building server-side applications, but they take fundamentally different architectural approaches.

Core Philosophy

FOAM is a model-driven, cross-language framework where you define declarative models that generate code for multiple platforms (JavaScript, Java, Swift). The framework centers on foam.CLASS() definitions that describe properties, methods, and behaviors.

Spring Boot is a convention-over-configuration Java framework built on dependency injection and annotations. It focuses on rapid application development with auto-configuration and embedded servers.

Architecture Patterns

FOAM’s Approach

FOAM uses a unified class system across languages with declarative models:

foam.CLASS({
  package: 'com.google.project',
  name: 'MyModel',
  extends: 'com.google.project.MyBaseModel',
  properties: [...],
  methods: [...],
  javaImports: [...]
});

Key architectural features:

Spring Boot’s Approach

Spring Boot uses Java annotations and auto-configuration:

@RestController
@Service
public class MyService {
  @Autowired
  private UserRepository userRepository;

  @GetMapping("/users")
  public List<User> getUsers() { ... }
}

Key features:

Dependency Management

FOAM has a sophisticated multi-tier system:

Spring Boot uses:

Data Access Layer

FOAM includes a comprehensive DAO (Data Access Object) system with decorator pattern:

Spring Boot uses:

Code Generation vs Runtime

FOAM generates Java (and Swift) code at build time and builds JavaScript classes at runtime:

Spring Boot is runtime-based:

Context and Dependency Injection

FOAM’s Context System:

Spring’s IoC Container:

Server Architecture

FOAM provides:

Spring Boot provides:

Development Experience

FOAM requires:

Spring Boot requires:

Persistence and Journaling

FOAM includes built-in persistence:

Spring Boot requires:

Use Cases

FOAM excels at:

Spring Boot excels at:

Notes

FOAM is a full-stack, model-driven framework with cross-language code generation and built-in data persistence, while Spring Boot is a Java-specific framework focused on convention-over-configuration and rapid application development. FOAM’s context-based dependency injection and DAO system provide a unified programming model across client and server, whereas Spring Boot requires separate frontend frameworks and relies on external databases. FOAM has a steeper learning curve due to its unique concepts, but provides more built-in functionality for complex enterprise applications.

Wiki pages you might want to explore:

Citations

File: README.md (L27-36)

## Feature Oriented Active Modeller

FOAM is a modeling tool and class based object system.  To use FOAM,
you create a model of your class by describing the properties, methods,
event topics, listeners, and dependencies of your class.  FOAM takes
this model and generates a usable JavaScript class along with several
companion features such as database support and network marshaling.

While FOAM is written in JavaScript, it can be used to generate code
for any language or platform, including Android Java and iOS Swift.

File: README.md (L39-52)

## Dependencies

FOAM has no runtime dependencies, but does have build dependencies:

* git
* npm
* nodejs (version >= 16)
* maven
* java (version >= 21)

Once dependencies are installed, update FOAM's javascript dependencies:
From the root of the FOAM repository, execute:

    ./build.sh --install

    sudo chown -R $USER /opt

File: README.md (L188-194)

## CORE
To run CORE, the FOAM Java Application Server, run:

    ./build.sh -Jdemo

- visit: http://localhost:8080
- login with username `admin` and password `admin`

File: doc/guides/cheat-sheet.md (L40-80)

Model/class definition:
```javascript
foam.CLASS({
  package: 'com.google.project',
  name: 'MyModel',
  extends: 'com.google.project.MyBaseModel',
  implements: [
    'com.google.project.MyFirstTrait',
    'com.google.project.MyFirstSecondTrait'
  ],
  requires: [
    'foam.u2.detail.SectionedDetailView',
    'com.google.project.MyOtherModel'
  ],
  imports: ['myOtherModelExportedProperty'],
  exports: ['myModelExportedProperty'],
  constants: {
     CONSTANT1: value,
     ...
  },
  topics: [
  ],
  axioms: [
  ],
  properties: [
    …
  ],
  methods: [
    …
  ],
  templates: [
    …
  ],
  actions: [
    …
  ],
  listeners: [
    …
  ]
});

File: doc/guides/cheat-sheet.md

Every FOAM object has two context variables:
**`__context__`** - The main context passed when object was created.
**`__subContext__`** - Created only if object has `exports`; contains main context + exported services.

Context variables:
```javascript
// Object with no exports
var obj = SomeClass.create({}, mainContext);
console.log(obj.__context__);    // mainContext
console.log(obj.__subContext__); // same as __context__

// Object with exports creates subcontext
foam.CLASS({
  name: 'Service',
  exports: ['userDAO', 'as notificationService']
});

var service = Service.create({}, mainContext);
console.log(service.__context__);    // mainContext
console.log(service.__subContext__); // mainContext + exports (userDAO, notificationService)
```

Context inheritance:
```javascript
// Child inherits parent's __subContext__ as its __context__
var child = ChildView.create({}, service.__subContext__);
console.log(child.__context__); // mainContext + parent's exports
```

File: doc/guides/cheat-sheet.md

## **Context and Object Creation**

Always use `requires` + `this.ClassName.create()` for proper context inheritance.

Context-aware object creation:
```javascript
foam.CLASS({
  requires: ['foam.u2.detail.SectionedDetailView', 'com.project.MyModel'],
  methods: [
    function render() {
      // Inherits full context (imports, exports, etc.)
      var view = this.SectionedDetailView.create({ data: this.data });
      var model = this.MyModel.create({ name: 'test' });
    }
  ]
});
```

Direct instantiation (loses context):
```javascript
foam.CLASS({
  methods: [
    function render() {
      // No context inheritance - imports/exports unavailable
      var view = foam.u2.detail.SectionedDetailView.create({ data: this.data });
      var model = com.project.MyModel.create({ name: 'test' });
    }
  ]
});
```

File: src/foam/lang/Context.js (L27-44)


/**
 * Context Support
 *
 * Contexts, also known as frames, scopes or environments, are used to store
 * named resources. They provide an object-oriented replacement for global
 * variables. Contexts are immutable. New bindings are added by creating
 * "sub-contexts" with new bindings, from an existing parent context.
 * Sub-contexts inherit bindings from their parent.
 *
 * Contexts provide a form of inversion-of-control or dependendency-injection.
 * Normally, contexts are not explicitly used because FOAM's imports/exports
 * mechanism provides a high-level declarative method of dependency management
 * which hides their use.
 *
 * foam.__context__ references the root context, which is the ancestor of all other
 * contexts.
 */

File: src/foam/lang/Boot.js (L18-53)

/**
 FOAM Bootstrap
<p>
 FOAM uses Models to specify class definitions.
 The FOAM Model class is itself specified with a FOAM model, meaning
 that Model is defined in the same language which it defines.
 This self-modeling system requires some care to bootstrap, but results
 in a very compact, uniform, and powerful system.
<pre>

 FObject -> FObject Class                     Prototype
    ^                        +-.prototype---------^
    |                        |                    |
  Model  -> buildClass()  -> Class -> create() -> instance
</pre>
  FObject is the root model/class of all other classes, including Model.
  Abstract Class is the prototype of FObject's Class, which makes it the root of all Classes.
  From a Model we call buildClass() to create a Class (or the previously created Class) object.
  From the Class we call create() to create new instances of that class.
  New instances extend the classes prototype object, which is stored on the class as .prototype.
<pre>
  instance ---> .cls_   -> Object's Class
       |
       +------> .model_ -> Object's Model
</pre>
  All descendents of FObject have references to both their Model and Class.
    - obj.cls_ refers to an Object's Class
    - obj.model_ refers to an Object's Model

<p>  Classes also refer to their Model with .model_.

<p>  Model is its own definition:
<pre>
    Model.buildClass().create(Model) == Model
    Model.model_ === Model
</pre>

File: src/foam/lang/Boot.js (L54-97)

  Models are defined as a collection of Axioms.
  It is the responsibility of Axioms to install itself onto a Model's Class and/or Prototype.

<p>
  Axioms are defined with the following psedo-interface:
<pre>
    public interface Axiom {
      optional installInClass(cls)
      optional installInProto(proto)
    }
</pre>
  Ex. of a Model with one Axiom:
<pre>
  foam.CLASS({
    name: 'Sample',

    axioms: [
      {
        name: 'axiom1',
        installInClass: function(cls) { ... },
        installInProto: function(proto) { ... }
      }
    ]
  });
</pre>
  Axioms can be added either during the initial creation of a class and prototype,
  or anytime after.  This allows classes to be extended with new functionality,
  and this is very important to the bootstrap process because it allows us to
  start out with very simple definitions of Model and FObject, and then build
  them up until they're fully bootstrapped.
<p>
  However, raw axioms are rarely used directly. Instead we model higher-level
  axiom types, including:
<ul>
  <li>Requires   - Require other classes
  <li>Imports    - Context imports
  <li>Exports    - Context exports
  <li>Implements - Declare interfaces implemented / mix-ins mixed-in
  <li>Constants  - Add constants to the prototype and class
  <li>Properties - High-level instance variable definitions
  <li>Methods    - Prototype methods
  <li>Topics     - Publish/sub topics
  <li>Listeners  - Like methods, but with extra features for use as callbacks
</ul>

File: doc/guides/REQUIRES_VS_IMPORTS.md (L19-51)

## `requires:` - Class Dependencies

### Purpose
Declares class dependencies so you can refer to classes by their short name rather than their fully qualified name. **`requires` requires classes.**

### Conceptual Model
When you `requires: 'com.acme.Foo'`, you can refer to it as just `Foo` rather than its fully qualified name `com.acme.Foo`. This is similar to:
- `require()` statements in JavaScript
- `import` statements in Java
- `#include` in C++

### Syntax
```javascript
foam.CLASS({
  name: 'MyClass',
  requires: [
    'foam.u2.DetailView',                           // Available as this.DetailView
    'foam.dao.MDAO',                               // Available as this.MDAO
    'foam.net.web.XMLHTTPRequest as HTTPRequest'   // Available as this.HTTPRequest
  ]
});
```

### How It Works
- Classes listed in `requires` become available as factory methods
- Accessed via `this.ClassName` (e.g., `this.DetailView`, `this.MDAO`)
- Factory methods create new instances: `this.DetailView.create()`
- Supports aliasing with the `as` keyword
- **These are classes/constructors, not instances**
- When you call `this.Abc.create(args)`, it automatically calls `this.Abc.create(args, this)` - the current context (`this`) is added as the second argument
- The second argument to `create()` is either a context or an object whose `.subContext` is used
- If you created `com.acme.Abc` directly you would need to manually pass `this` as the second argument, but `this.Abc.create()` adds it automatically
- This automatic context passing is needed to support dependency injection and the import/export system

File: doc/guides/REQUIRES_VS_IMPORTS.md (L96-133)

## `imports:` - Dependency Injection

### Purpose
Declares that you want a **live instance** of a service or value for use in your class. This is **dependency injection** or **inversion of control**.

**You get runtime objects/services, not classes.**

### Conceptual Model
Instead of your class going fishing around the system looking for services (which leads to complexity and tight-coupling), you simply declare what services you want to import and they're provided to you - even possibly from across the network.

This follows the **dependency injection** pattern:
- **Don't ask for dependencies** - declare what you need
- **Dependencies are injected** into your class at runtime
- **Loose coupling** - your class doesn't know where dependencies come from
- **Testability** - dependencies can be easily mocked or substituted

### Syntax
```javascript
foam.CLASS({
  name: 'MyView',
  imports: [
    'currentUser',              // A user object instance
    'userDAO',                  // A live DAO instance
    'log',                      // A logging service instance
    'optionalService?',         // Optional service (won't error if missing)
    'someDAO as myDAO'          // Aliased service
  ]
});
```

### How It Works
- Values from the parent context are injected as properties
- Accessed directly via `this.propertyName`
- **Values are instances/objects/services, not classes**
- Supports optional imports with `?` suffix
- Supports aliasing with the `as` keyword
- Dependencies can come from anywhere in the context chain, even across networks

File: doc/guides/REQUIRES_VS_IMPORTS.md (L334-352)

### Network Services
`imports:` can work across networks:

```javascript
foam.CLASS({
  name: 'ClientView',

  imports: [
    'userService'  // Could be a remote service accessed over HTTP
  ],

  methods: [
    function loadUser() {
      // userService might be running on a different server
      return this.userService.getCurrentUser();
    }
  ]
});
```

File: doc/templates/Model.js (L71-74)

   javaImports: [
     'com.acme.package.ClassX',
     'com.acme.package.ClassY',
   ],

File: src/foam/dao/java/JDAO.js (L7-54)

foam.CLASS({
  package: 'foam.dao.java',
  name: 'JDAO',
  extends: 'foam.dao.ProxyDAO',
  flags: ['java'],

  documentation: `Implements a Journal DAO - a file based DAO.
In this current implementation setDelegate must be called last.`,

  javaImports: [
    'foam.lang.X',
    'foam.dao.BulkLoadDAO',
    'foam.dao.CompositeJournal',
    'foam.dao.DAO',
    'foam.dao.F3FileJournal',
    'foam.dao.Journal',
    'foam.dao.MDAO',
    'foam.dao.NullJournal',
    'foam.dao.JournalGenerations',
    'foam.dao.ReadOnlyF3FileJournal',
    'foam.dao.WriteOnlyF3FileJournal',
    'foam.core.boot.CSpec',
    'foam.core.ndiff.NDiffJournal',
    'foam.dao.compaction.CompactionCmd',
    'foam.dao.compaction.Compactor',
    'foam.util.SafetyUtil',
    'java.util.ArrayList',
    'java.util.List'
  ],

  javaCode: `
    // TODO: These convenience constructors should be removed and done using the facade pattern.
    public JDAO(X x, foam.lang.ClassInfo classInfo, String filename) {
      this(x, new MDAO(classInfo), filename, false);
    }

    public JDAO(X x, DAO delegate, String filename) {
      this(x, delegate, filename, false);
    }

    public JDAO(X x, DAO delegate, String filename, Boolean cluster) {
      setX(x);
      setOf(delegate.getOf());
      setFilename(filename);
      setCluster(cluster);
      setDelegate(delegate);
    }
  `,

File: src/foam/dao/java/JDAO.js (L56-87)

  properties: [
    {
      name: 'filename',
      class: 'String'
    },
    {
      name: 'cluster',
      class: 'Boolean',
      value: false
    },
    {
      class: 'FObjectProperty',
      of: 'foam.dao.Journal',
      name: 'journal'
    },
    {
      documentation: 'Filesystem is read-only, journals updates are factilitated through some other means such as medusa.',
      class: 'Boolean',
      name: 'readOnly',
      javaFactory: 'return "ro".equals(System.getProperty("FS", "rw"));'
    },
    {
      documentation: 'Only load the runtime generated journal file.  Used by Medusa to bootstrap a system with existing data.',
      class: 'Boolean',
      name: 'runtimeOnly',
      value: false
    },
    {
      documentation: `Enable NDiff in JDAO. Enable per DAO with this property or globally via JVM Parameter 'UseNDiff', see EasyDAO.ndiff`,
      class: 'Boolean',
      name: 'ndiff'
    },

File: src/foam/swift/GenSwift.js (L7-22)

foam.CLASS({
  package: 'foam.swift',
  name: 'GenSwift',
  flags: ['swift','node'],
  requires: [
    'foam.lang.Model',
    'foam.swift.Enum',
    'foam.swift.EnumValue',
    'foam.swift.SwiftClass',
    'foam.swift.EmptyClass',
    'foam.swift.Field',
    'foam.swift.Method',
  ],
  imports: [
    'classloader',
  ],