
ALBIQ framework
ALBIQ consist of following components:
This tool allow to generate from textual definition (DSL) particular parts of system like Entities, Repositories, Services and GUI. Responsibility of tool is to generate safe, well structured environment for developer. Than developer can write services, customize entities and repositories. Tool is using latest open source MDA tools like oAW, xText, xPand from Eclipse foundation. Code should be regenerated when it's necessary to change textual DSL. Properties of MDD tool:
Framework consist of well selected components and frameworks. For some parts of system you can choose from more options. Following picture is describing some possibilities:
Image 1: Butterfly mean preferred choice, Hours mean beta version.
Except this you have available other powerful engines. Rule engine is integrated to service tier. Rules should be invoked on every service call (even on service to service call). To ALBIQ also messaging is integrated. Services should be invoked by XML messages.
System services are necessary for correct ALBIQ processing. As basic services you can find:
All this services can used also by business logic or rule engine.
Because we are using ALBIQ for some time we have build also some business services which can be reused. Services are build with re-usability in mind. Some of these modules are used now in more production systems. List of reusable business services:
Whole MDA is build around idea of maximum protection of your business code. Whole system around your business code is generated and you focus on writing pure business logic. That's also reason why MDA systems are so flexible in terms of deployment. You can generate surrounded code for specific environment without changing business code which remain same. Let's look on possible enterprise deployment:
Image 2: Deployment possibilities
As you can see from this basic deployment you can choose between many technologies. All of them should be changed without changing your business code and protect your investment to future when new technology appear. Your business code doesn't depend on communication technologies like EJBs remote call or messaging. You can change also persistent layer technology for example from SQL database to Object Oriented Database.
We should offer you also some interesting consultancy services. We implemented and consulted many development projects and our specialists took part in many interesting projects. We should offer following business experience:
This is sample of rates import service definition. It consist of Entity definition together with Repository and service definition.
Entity RatesImport {
String name
- @InputType inputType
String patternMatch length="50"
- @PatternMatchTo matchTo
String fundName length="4"
String currency length="4"
String isin length="4"
String fundClass length="4" nullable
String issueDate length="4"
String dateFormat length="25" nullable
String typeCapDis length="4" nullable
String nav length="4"
String totalValue length="4" nullable
String domicil length="4" nullable
String overallShares length="4" nullable
int minimumImportRows
int dataFromRow
Repository RatesImportRepository {
findById;
findAll;
save;
delete;
}
}
Service RatesImportService {
inject @SecuritiesService
inject @CurrencyService
inject @RatesService
inject @AuditLogService
inject @PropertyService
findAll => RatesImportRepository.findAll;
findById => RatesImportRepository.findById;
save => RatesImportRepository.save;
delete => RatesImportRepository.delete;
public void ratesImport();
public void exchangeRatesImport(int daysBack, boolean overwrite);
}
| Artifact | Files |
| src/generated/java |
Interfaces: domain/RatesImportRepository.java - repository interface serviceapi/RatesImportService.java - service interface repositoryimpl/RatesImportAccessFactory.java - access factory interface Classes: domain/RatesImport.java - persistent entity class domain/RatesImportProperties.java - properties definition for findByCondition serviceimpl/RatesImportServiceImplBase.java implements serviceapi/RatesImportService.java Exception: exception/RatesImportNotFoundException.java |
| src/main/java |
Classes: serviceimpl/RatesImportServiceImpl.java extends serviceimpl/RatesImportServiceImplBase.java accessimpl/RatesImportAccessFactoryImpl.java implements repositoryimpl/RatesImportAccessFactory.java repositoryimpl/RatesImportRepositoryImpl.java implements domain/RatesImportRepository.java |
| src/test/generated/java |
Classes: test/java/sk/f4s/pic/core/serviceapi/RatesImportServiceTest.java serviceapi/RatesImportServiceTestBase.java |
| src/test/generated/resources | dbunit/RatesImportServiceTest.xml - XML for initial db load for test |
@GuiHints(detailBehavior=DetailBehavior.ON_ALL)
public void exchangeRatesImport(@Name("ctx") ServiceContext ctx, @Name("daysBack") int daysBack, @Name("overwrite") boolean overwrite) {
String url=getPropertyService().getPropertyValue(ctx, "month.report.url", MONTH_REPORT_XML);
String timeout=getPropertyService().getPropertyValue(ctx, "month.report.timeout", DEFAULT_TIMEOUT);
try {
Currency euroTicker = getCurrencyService().findByTicker(ctx, "EUR");
DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
HashMap<String, Currency> realCurrencyCache=new HashMap<String, Currency>();
Calendar startDate=Calendar.getInstance();
startDate.clear(Calendar.HOUR); startDate.clear(Calendar.HOUR_OF_DAY); startDate.clear(Calendar.AM_PM);
startDate.clear(Calendar.MINUTE); startDate.clear(Calendar.SECOND); startDate.clear(Calendar.MILLISECOND);
startDate.add(Calendar.DAY_OF_YEAR, -daysBack);
Calendar now=Calendar.getInstance();
for (; !startDate.after(now); startDate.add(Calendar.MONTH, 1)) {
String result=MessageFormat.format(url, startDate.get(Calendar.MONTH) + 1, startDate.get(Calendar.YEAR));
log.info("Fetching exchange rates from: "+result);
URL service=new URL(result);
URLConnection conn = service.openConnection();
conn.setConnectTimeout(Integer.parseInt(timeout));
conn.setReadTimeout(Integer.parseInt(timeout));
Document doc = docBuilder.parse(conn.getInputStream());
NodeList cubes = doc.getElementsByTagName("Cube");
Date date=null;
for (int i=0; i < cubes.getLength(); i++) {
NamedNodeMap attrs = cubes.item(i).getAttributes();
Node dateN = attrs.getNamedItem("time");
Node tickerN = attrs.getNamedItem("currency");
Node rateN = attrs.getNamedItem("rate");
if (dateN != null) {
try {
date = DATE_FORMAT.parse(dateN.getTextContent());
if (date.before(startDate.getTime())) {
date=null;
}
} catch (ParseException pe) {
// Usually some statistics at end of report
date=null;
}
} else if (tickerN != null && rateN != null && date != null) {
try {
System.out.println("Currency: "+tickerN+", Rate: "+rateN+" Date: "+date);
Double rate=Double.parseDouble(rateN.getTextContent());
String ticker=tickerN.getTextContent();
Currency realTicker;
if (realCurrencyCache.containsKey(ticker)) {
realTicker = realCurrencyCache.get(ticker);
} else {
realTicker = getCurrencyService().findByTicker(ctx, ticker);
realCurrencyCache.put(ticker, realTicker);
}
importOneRate(ctx, euroTicker, realTicker, date, rate, overwrite);
} catch (NumberFormatException nfe) {
// Ignore error, just not imported
}
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
Image 3: Screenshot od default generated application without any change after startup
allow to define column which aggregate more information together with special formatting
Image 4: Summary editor
allow to define new calculation like in spreadsheet (Excel, OpenOffice Calc, ...)
Image 5: Formula editor
Image 6: List customization possibilities
Image 7: Tabbed interface with Enterprise Blue skin and filter
[condition][]Ak sa vykonava pokyn pre=$req : RequestDescriptio...
[condition][]- menu "{currency}"=currency.ticker == "{currency}"
[condition][]- typ uctu je "{accType1}" alebo "{accType2}" alebo "{accType3}"=(account ...
[condition][]- typ uctu je "{accType1}" alebo "{accType2}"=(account.accountType.typeAccount matches ...
[condition][]- typ uctu je "{accType1}"=account.accountType.typeAccount matches "{accType1}.*"
[condition][]Ak sa vykonava pokyn=$req : RequestDescription(serviceName=="SecurityOrderTransactionService" ...
[condition][]Hotovostny vklad klienta=$req : RequestDescription(serviceName == "Accounting", methodName == "book") ...
[condition][]Hotovostny vyber klienta=$req : RequestDescription(serviceName == "Accounting", methodName == "book") ...
[condition][]Vklad cenneho papiera=$req : RequestDescription(serviceName == "Accounting", methodName == "book") ...
[condition][]Vyber cenneho papiera=$req : RequestDescription(serviceName == "Accounting", methodName == "book") ...
[consequence][]Odpocitaj poplatky=$order.setCalcAmount($fees.dischargeFees($order.getCalcAmount(), 2));
[consequence][]Log {message}=System.out.println({message});
[consequence][]LogError {message}=log.warn({message});
[consequence][]LogFatal {message}=log.error({message});
[consequence][]Audit {audit}=makeAuditRecord(serviceContext, servlet, {audit});
PRAVIDLO "Vklad cenneho papiera"
AK
Vklad cenneho papiera
POTOM
Log "Vklad cenneho papiera"
Priprav uctovnictvo
Najdi bezny ucet klienta $document.getAccount() v mene $document.getSecurity() a uloz do CREDIT_ACC
Najdi firemny ucet "KU" v mene $document.getSecurity() a uloz do DEBET_ACC
Zauctuj z uctu DEBET_ACC na ucet CREDIT_ACC v hodnote $document.getAmount() popis "SecDeposit"
KONIEC
PRAVIDLO "Validacia bezneho nakupneho pokynu - po spocitani poplatkov"
priorita -100
AK
Validacia bezneho nakupneho pokynu
Poplatky su priradene
POTOM
Vypis poplatky
Log "### Poplatky pre sumu "+$order.getInvestAmount().floatValue()+" su "+$fees.dischargeFees($order.getInvestAmount(), 2)
Odpocitaj poplatky
KONIEC
You can define rules also with excel sheet. Sheet has to contain some additional definitions which are necessary for correct rules generation. However this definition should be hidden. In first screen you see pure rules with definition hidden and second screenshot with rules definition uncovered. On screenshot you can see price list implementation. It's important that this rules are processed directly by engine (no other hand touching or retyping).
Screen with definition hidden:
Image 8: XLS table with all definitions hidden (group level 1 collapsed)
Image 9: XLS where definition are shown