Podpora zpracování konfigurace modulu
Možnosti
Pro účely zjednodušení načítání XML konfigurace je dostupná třída ConfigHelper. Ta obsahuje užitečné metody, které vám umožní:
vytvářet instance a class objekty z řetězce
získávat class objekty ze stringu a tyto classy bezpečně instanciovat (s obalením chyby do případné CpsException s návodným hlášením problému)
metody getClassByPath, getClassInPackageByElementName, getImplementationClassInPackage, instantiateClass
napopulovat data ze sitemapy přes POJO settery do existujících instancí
do existující instance nastaví property dle XML atributů nebo poduzlů
metody configureAccordingToAttributes, configureAccordingToSubElements, configure
inicializovat objekty Springovým způsobem
umožní zpracovat lifecycle callbacky jako InitializingBean, *Aware interfacy atd., autowiring by name z dodaného aplikačního kontextu
metody addUsedObject, initUsedObjects, isObjectRegisteredInUsedObjects
kombinovaně vytvářet instanci dle konfigurace a naplnit ji hodnotami
kombinované metody, které zároveň instanciují i konfigurují třídu podle sitemapy
metody getInstantiatedAndConfiguredClass, getInstantiatedAndConfiguredClassInPackage, getInstantiatedInstanceFromIndex, getInstantiatedAndConfiguredInstanceFromIndex
„indexové” metody nečtou informace o kompletních názvech tříd ze sitemap, ale hledají je podle klíčového slova v mapě - jeden index obsahuje jen třídy objektů Map, druhý index již hotové instance Map, v případě instancí se nevytváří kopie, ale použije se již hotový objekt, který se dále z dat sitemapy již nekonfiguruje
získat data z XML v jednoduché formě k dalšímu zpracování
převede konfigurační tagy do základních datových struktur
metody getChildrenAsMap, recursivelyAddSubElements
Vazba na lifecycle
Typicky probíhá načítání konfigurace ze sitemapy ještě před inicializací aplikačního kontextu - tj. instance objektů vznikají před tím, než máme k dispozici funkční aplikační kontext, ze kterého bychom mohli autowirovat dependence, načítat Resourcy atp.
Z toho důvodu je ConfigHelper navrhnut dvoufázově
- v první fázi vám pomůže vytvořit instance objektů a napopulovat je daty ze sitemapy
- a v druhé fázi, kdy už máte k dispozici funkční aplikační kontext zavoláte metodu
initUsedObjectskterá provede Springovou inicializaci všech objektů- objekty se nestanou součástí aplikačního kontextu (jsou bezejmenné)
- jen se provede jejich inicializace jako by v něm byly + autowiring byName.
Registrace objektů
Pokud vytváříte instance prostřednictvím metod ConfigHelperu (např. instantiateClass), nemusíte se o registraci instance
starat - je do sady „usedObjects” zařazena automaticky. Pokud si vytváříte instance objektů bokem, je nutné je do seznamu
zařadit explicitně voláním metody addUsedObject(s).
Resource populace
Jak již bylo uvedeno populace dat se děje ve chvíli, kdy ještě nemáme k dispozici funkční kontext.
Nicméně objekty typu Resource vznikají pomocí tzv. ResourceLoaderu, kterým je právě zmíněný aplikační kontext -
tj. vzniká nám tu cyklická dependence pro inicializaci.
Z toho důvodu vznikla třída zvaná DelegatingResource a odpovídající DelegatingResourceEditor, které umí zastupovat
libovolný cílový Resource objekt.
Tj. vytvořené instance budou mít do fieldů typu Resource injektován objekt typu DelegatingResource, jehož inicializace
finální inicializace se provede až ve chvíli, kdy je aplikační kontext k dispozici. Inicializace všech DelegatingResourců
se děje ve chvíli volání metody initUsedObjects.
Příklady
public class JobMgrXmlConfigParser { public JobMgrConfig parse(CpsModuleConfigSupport configSupport) { final JobMgrConfig jobMgrConfig = new JobMgrConfig(); // prevede xml <asyncDisabled>false</asyncDisabled> do volani setAsyncDisabled(false) configHelper.configureAccordingToSubElements( getConfigRootElement(configSupport), jobMgrConfig, new String[] {"checks", "jobsConfigOverride"} ); return jobMgrConfig; }}Složitější parser
public class XmlWorkflowConfigParser implements WorkflowConfigParser { public WorkflowDefinition configureWorkflow(ConfigElement workflowElement) { // naplni XML atributy do pojo field WorkflowDefinition workflowDefinition = new WorkflowDefinition(workflowElement.getAttributeValue("id")); configHelper.configureAccordingToAttributes(workflowElement,workflowDefinition,new String[]{"id","class"}); // dataloader plne dle XML konfigurace vcetne volby cilove tridy ConfigElement dataLoaderElement = workflowElement.getChildElement("dataLoader"); if (dataLoaderElement!=null) { // instance z <dataLoader class="com.fg.edee.workflow.integration.business.EdeePageWorkflowExternalDataLoader"/> WorkflowExternalDataLoader dataLoader = (WorkflowExternalDataLoader) configHelper.getInstantiatedAndConfiguredClassInPackage(dataLoaderElement, null, true, true); workflowDefinition.setDataLoader(dataLoader); } // metadata - zpracovani dle fixni package, kde nazev tagu odpovida nazvu tridy List<ConfigElement> metadataList = workflowElement.getChildElements(); for (ConfigElement metadataElement : metadataList) { final String metadataName = metadataElement.getElementName(); // chceme pouze tagy dle konvence if (metadataName.endsWith("Metadata")) { // instance z konfigurace <pageMetadata pageSystemId="TARGET_PAGE" pageLang="cs"/> final Class metadataClass = configHelper.getImplementationClassInPackage(metadataElement, "com.fg.edee.workflow.core.metadata"); final Object metadata = configHelper.instantiateClass(metadataClass, null); configHelper.configureAccordingToAttributes(metadataElement, metadata, new String[]{"class"}); configHelper.configureAccordingToSubElements(metadataElement, metadata); Assert.isInstanceOf(WorkflowMetadata.class,metadata); workflowDefinition.setMetadata(metadata); } } return workflowDefinition; }}