JsonProject#

A Project behind a string API. Each operation takes JSON text and returns an envelope string, so a server endpoint can pass request bodies in and send the result back unchanged. Create one with new JsonProject(optionsJson), then load data with solve.

To mix typed and JSON calls on one project, use the static methods of Wire on a typed Project instead.

Declaration#

package org.dhtmlx.plen;

public final class JsonProject

JsonProject has no public fields. It isn't AutoCloseable and needs no explicit release.

Every operation returns one of two envelopes:

{"ok":true,"result":{...}}
{"error":{"code":null,"kind":"validation","message":"...","path":"tasks[0].start_date"},"ok":false}

error.kind is "parse", "validation" or "project". code is the kebab-case ProjectError for "project" and null otherwise. path is the input path, or null. Keys are sorted at every depth. See Read the envelope.

Engine errors never escape the operations as exceptions: a PlenException becomes an error envelope. Other exceptions propagate. A null argument throws NullPointerException, except the data argument of solve and analyze. Pass "{}" for default options. The only member that throws on bad input is the JsonProject(String) constructor.

All methods are synchronous. JsonProject isn't synchronized, and copy() also updates internal sharing flags on the source. Serialize access to one instance. See Share a project between threads.

Constructors#

JsonProject()#

public JsonProject()

Creates an empty, unsolved project with default options and strict validation. Same as new JsonProject("{}").

JsonProject(String)#

public JsonProject(String optionsJson)

Creates an empty, unsolved project from ProjectOptions JSON, for example {"validation":"repair"}.

Parameters

Name Type Description
optionsJson String ProjectOptions as JSON text. "{}" uses the defaults.

Errors

  • JsonProjectException when optionsJson doesn't decode. getErrorJson() returns the error envelope and getError() the InputException.
  • NullPointerException when optionsJson is null.

Methods#

Each method below except copy runs the typed Project method of the same name and wraps its result in an envelope. The linked operation page has the full contract and the error codes.

Method Input JSON Result in the envelope Operation
solve(data, options) ProjectData or null, SolveOptions ScheduleResult Project#solve
preview(changes, options) SchedulingChanges, PreviewOptions ScheduleResult Project#preview
analyze(data, options) ProjectData or null, AnalyzeOptions ScheduleResult Project#analyze
apply(changes) SchedulingChanges ApplyReport Project#apply
level(options) LevelingOptions LevelingResult Project#level
loadProfile(options) LoadProfileOptions LoadProfile Project#loadProfile
evaluate(candidates, options) array of Candidate, EvaluateOptions EvaluateResult Project#evaluate
slots(pool, requirements) Pool, array of Requirement array of Slot SkillLayer.slots
suggestAssignments(slots, options) array of Slot, SuggestOptions SuggestResult Project#suggestAssignments

Input JSON that doesn't decode gives an error envelope with kind "parse": bad syntax, duplicate keys, a wrong type, a missing required field, a JSON null document, or an unknown key in call options or in the change set's own keys.

solve#

public String solve(String data, String options)

Schedules the project and accepts the scheduled dates as the baseline. data replaces the project's data. null reschedules the current state, for example after apply.

Parameters

Name Type Description
data String ProjectData JSON. Nullable; null re-solves the accepted data.
options String SolveOptions JSON, such as {"includeUnchanged":true}.

Returns an envelope with a ScheduleResult.

preview#

public String preview(String changes, String options)

Schedules a change set on a copy of the solved baseline without keeping it. Needs a solved project; otherwise the envelope has code "no-baseline".

Parameters

Name Type Description
changes String SchedulingChanges JSON.
options String PreviewOptions JSON.

Returns an envelope with a ScheduleResult for the previewed state.

analyze#

public String analyze(String data, String options)

Computes analytics, cycles and overallocations over supplied dates, or over the current dates when data is null. Doesn't schedule and doesn't install data.

Parameters

Name Type Description
data String ProjectData JSON. Nullable; null analyzes the current state.
options String AnalyzeOptions JSON.

Returns an envelope with a ScheduleResult.

apply#

public String apply(String changes)

Commits a change set to the accepted state and marks it unsolved. Rejected operations go into the report's rejected list, set needsResync, and leave the project needing solve(data, …) with full data.

Parameters

Name Type Description
changes String SchedulingChanges JSON.

Returns an envelope with an ApplyReport.

level#

public String level(String options)

Solves the current state, resolves resource overallocation and accepts the leveled state as the baseline.

Parameters

Name Type Description
options String LevelingOptions JSON.

Returns an envelope with a LevelingResult.

loadProfile#

public String loadProfile(String options)

Reads per-bucket load and capacity of resources on the solved baseline. Needs a solved project.

Parameters

Name Type Description
options String LoadProfileOptions JSON: the query fields (from, to, ...) at the top level.

Returns an envelope with a LoadProfile.

evaluate#

public String evaluate(String candidates, String options)

Scores alternative change sets against the solved baseline. Needs a solved project. The project isn't modified.

Parameters

Name Type Description
candidates String JSON array of Candidate. A null element is a "parse" error.
options String EvaluateOptions JSON.

Returns an envelope with an EvaluateResult.

slots#

public String slots(String pool, String requirements)

Builds the slots that suggestAssignments takes from a worker pool and task requirements. Needs a solved project with no unsolved edits. A pool or requirement the skill layer rejects gives an error envelope with kind "validation".

Parameters

Name Type Description
pool String Pool JSON.
requirements String JSON array of Requirement.

Returns an envelope with an array of Slot.

suggestAssignments#

public String suggestAssignments(String slots, String options)

Proposes resources for the slots and returns the proposal as a change set. Needs a solved project. The project isn't modified.

Parameters

Name Type Description
slots String JSON array of Slot, as returned by slots.
options String SuggestOptions JSON.

Returns an envelope with a SuggestResult.

copy#

public JsonProject copy()

Returns an independent JsonProject over Project#copy(). Changes to the copy don't reach the source. Use it to try apply or level before committing them.

Example#

import org.dhtmlx.plen.JsonProject;

public class JsonProjectExample {
  public static void main(String[] args) throws Exception {
    var project = new JsonProject("{\"validation\":\"repair\"}");

    String data =
        """
        {
          "tasks": [
            {"id": "a", "start_date": "2026-01-05", "duration": 2},
            {"id": "b", "start_date": "2026-01-05", "duration": 1}
          ],
          "links": [{"id": 1, "source": "a", "target": "b", "type": "0"}]
        }
        """;
    System.out.println(project.solve(data, "{\"includeUnchanged\":true}"));

    String changes = "{\"tasks\":{\"update\":[{\"id\":\"a\",\"duration\":3}]}}";
    System.out.println(project.preview(changes, "{}"));

    // Not solved yet: an error envelope, not an exception.
    System.out.println(new JsonProject().preview(changes, "{}"));
  }
}

Output (the baselineId differs on every run):

{"ok":true,"result":{"baselineId":"1-eb560363f4cab208","conflicts":[],"converged":true,"cycles":[],"notes":[],"updates":[{"duration":2,"end_date":"2026-01-07 00:00","id":"a","kind":"task","start_date":"2026-01-05 00:00"},{"duration":1,"end_date":"2026-01-08 00:00","id":"b","kind":"task","start_date":"2026-01-07 00:00"}]}}
{"ok":true,"result":{"baselineId":"1-eb560363f4cab208","conflicts":[],"converged":true,"cycles":[],"notes":[],"updates":[{"duration":3,"end_date":"2026-01-08 00:00","id":"a","kind":"task","start_date":"2026-01-05 00:00"},{"end_date":"2026-01-09 00:00","id":"b","kind":"task","start_date":"2026-01-08 00:00"}]}}
{"error":{"code":"no-baseline","kind":"project","message":"no-baseline","path":null},"ok":false}