Ctrl+K

Data Layer Architecture

The data layer follows a three-tier pattern: Parser → Repository → Service. Each tier has a single, well-defined responsibility.

Pattern Overview

TierResponsibilityShould touch DB?
ParserRead XML / SQL source, produce domain objectsNo
RepositoryHold in-memory data, expose query methodsOnly for initial load
ServiceRuntime logic — DB writes, item manipulation, state transitionsYes
// Loading sequence at startup:
Parser.load()           // reads XML, creates objects
  └─► Repository.init() // stores into indexed maps
        └─► Service (called at runtime, not startup)

Concrete Examples

Items

ItemParser        →  parses items XML, creates ItemTemplate instances
ItemRepository    →  Map<Integer, ItemTemplate> by item ID, query by type / grade
ItemService       →  create L2ItemInstance, equip, transfer, DB persist

NPCs

NpcParser         →  parses NPC XML, creates NpcTemplate instances
NpcRepository     →  Map<Integer, NpcTemplate> by NPC ID
                     (no NpcService needed — NPC spawning handled by SpawnTable)

Skills

SkillParser       →  parses skill XML including effects and conditions
SkillRepository   →  Map<Integer, Map<Integer, Skill>> by skillId + level
SkillService      →  cast, reuse timers, buff persistence

Repository Design Conventions

  • Repositories are singletons — getInstance() or static init() / get().
  • All maps are populated once at startup and treated as immutable at runtime.
  • Query methods are named descriptively: getById, getByType, getAll.
  • Return types are explicit — never return raw Object or unchecked casts.

Parser Design Conventions

  • Parsers use the SAX or StAX API — no DOM for large XML files.
  • A parser produces only plain Java objects — no DB calls, no side effects.
  • Parsing errors log a warning and skip the offending entry. They do not crash startup.
public class ItemParser {
    public List<ItemTemplate> parse(String xmlPath) {
        // SAX parse, return list
    }
}

public class ItemRepository {
    private static final Map<Integer, ItemTemplate> ITEMS = new HashMap<>();

    public static void init(List<ItemTemplate> items) {
        items.forEach(t -> ITEMS.put(t.getId(), t));
    }

    public static ItemTemplate getById(int id) {
        return ITEMS.get(id);
    }
}

Adding a New Data Loader

  1. Create MyDataParser.java — takes a file path, returns a list of domain objects.
  2. Create MyDataRepository.javastatic init(List) + query methods.
  3. If runtime DB interaction is needed, create MyDataService.java.
  4. Call MyDataRepository.init(new MyDataParser().parse("data/mydata.xml")) from GameServer during the data loading phase.
If the data does not require runtime DB writes — for example, static reference data like item templates — a Service tier is not needed. Parser → Repository is sufficient.