Skip to content

Commit

Permalink
add #46, #47, #48, #49.
Browse files Browse the repository at this point in the history
  • Loading branch information
fill0llif committed Jan 25, 2019
1 parent cfc3f25 commit 9be6058
Show file tree
Hide file tree
Showing 14 changed files with 352 additions and 46 deletions.
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,23 @@

# Change Log

## 5.1.0 (2019-01-25)

**Added:**
- [#46 - Add DisposeOnClose and HideOnClose reactions](https://github.com/fill0llif/yayoi/issues/46);
- [#47 - Add Swing ComponentPopupMenu, MouseListener, MouseMotionListener collectors support](https://github.com/fill0llif/yayoi/issues/47);
- [#48 - Add method autowiring support for non-Component beans using `autowired` or `qualifier`](https://github.com/fill0llif/yayoi/issues/48);
- [#49 - Add Spring scan of Yayoi packages](https://github.com/fill0llif/yayoi/issues/49);

**Changed:**

**Closed bugs/regressions:**

**Regression:**

**Open:**
- [#19 - LateValue should use late annotation to retain the late value](https://github.com/fill0llif/yayoi/issues/19);

## 4.1.1 (2019-01-16)

**Added:**
Expand Down
27 changes: 12 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ _Yayoi_ is a GUI annotation framework and provides/allows:
* a default log writer is already registered;
* visitor structure on component, container, collection and window;
* layout construction on container declaration;
* autowiring support for components with **named** annotation on method parameters.
* autowiring support for components with **named** and for any other beans with **autowired** or **qualifier** annotations on method parameters;
* defining _Settings_, top level class, method or object holding a reference to an object the user decide to use where he wants:
* Look and Feel setting;
* defining Collectors for collecting internal values of components (using **collectable** and **collecting** annotation);
Expand All @@ -33,33 +33,30 @@ _Yayoi_ is a GUI annotation framework and provides/allows:
* Window collect/remove WindowListener;
* AbstractButton collect/remove ActionListener;
* MenuItem collect/remove ActionListener;
* JComponent collect/remove JPopupMenu;
* Component collect/remove MouseListener;
* Component collect/remove MouseMotionListener;
* abstract collections (Containers, Collections and Windows) are now mutable maps of components;
* abstract components deal now with mutable maps of listeners;
* automatically validating all the hierarchy whenever it is all invalidated;
* ordering components of **ordering** annotated abstract collections.
* ordering components of **ordering** annotated abstract collections;
* scanning of Spring components contained in Yayoi packages.

_Yayoi_ is written in [Ceylon](https://ceylon-lang.org) and is built on top of Spring

# Change Log

## 4.1.1 (2019-01-16)
## 5.1.0 (2019-01-25)

**Added:**
- [#37 - Let the user define default framework and framework overrides with `framework` annotation](https://github.com/fill0llif/yayoi/issues/37);
- [#43 - Add AWT framework implementation](https://github.com/fill0llif/yayoi/issues/43);
- [#45 - Collections can be roots](https://github.com/fill0llif/yayoi/issues/45);
- [#46 - Add DisposeOnClose and HideOnClose reactions](https://github.com/fill0llif/yayoi/issues/46);
- [#47 - Add Swing ComponentPopupMenu, MouseListener, MouseMotionListener collectors support](https://github.com/fill0llif/yayoi/issues/47);
- [#48 - Add method autowiring support for non-Component beans using `autowired` or `qualifier`](https://github.com/fill0llif/yayoi/issues/48);
- [#49 - Add Spring scan of Yayoi packages](https://github.com/fill0llif/yayoi/issues/49);

**Changed:**
- [#36 - Let the default log writer write on standard error if level is above info](https://github.com/fill0llif/yayoi/issues/36);
- [#37 - Let the user define default framework and framework overrides with `framework` annotation](https://github.com/fill0llif/yayoi/issues/37);
- [#41 - There is absolutely no need to use the metamodel to perform reactions](https://github.com/fill0llif/yayoi/issues/41);
- [#42 - Container doesn't need to specify generic layout type](https://github.com/fill0llif/yayoi/issues/42);

**Closed bugs/regressions:**
- [#38 - Application does not correctly shut down](https://github.com/fill0llif/yayoi/issues/38);
- [#39 - Collect and remove value settings replaced by Collectors](https://github.com/fill0llif/yayoi/issues/39);
- [#40 - Window's validation cycle may still not be defined when window is invalidated (causing NoSuchBeanDefinitionException)](https://github.com/fill0llif/yayoi/issues/40);
- [#44 - Assigning null layout when adding an unsuitable layout type on Swing/AWT container](https://github.com/fill0llif/yayoi/issues/44);

**Regression:**

Expand All @@ -75,6 +72,6 @@ _Yayoi_ is written in [Ceylon](https://ceylon-lang.org) and is built on top of S
You just need to add this declaration to your Ceylon module:

```ceylon
import it.feelburst.yayoi "4.1.1";
import it.feelburst.yayoi "5.1.0";
```

1 change: 1 addition & 0 deletions source/it/feelburst/yayoi/Yayoi.ceylon
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ shared final class Yayoi(
value frmwrkImpl = registerFrameworkImpl(context);
log.info("Framework implementation '``framework``' found.");
context.register(classForType<Conf>());
context.scan(*(appAnn.basePackages*.name));
context.refresh();
addShutdownHooks(context);
log.info("Registering components...");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ import ceylon.language.meta.declaration {
FunctionDeclaration,
ValueDeclaration,
NestableDeclaration,
FunctionOrValueDeclaration
FunctionOrValueDeclaration,
OpenClassType,
OpenInterfaceType
}

import it.feelburst.yayoi.behaviour.action {
Expand All @@ -28,7 +30,9 @@ import it.feelburst.yayoi.behaviour.reaction.impl {
LocationReaction,
WithLayoutReaction,
CollectReaction,
ListenableReaction
ListenableReaction,
DisposeOnCloseReaction,
HideOnCloseReaction
}
import it.feelburst.yayoi.marker {
ContainerAnnotation,
Expand All @@ -50,7 +54,9 @@ import it.feelburst.yayoi.marker {
CollectAnnotation,
ListenableAnnotation,
lowestPrecedenceOrder,
FrameworkAnnotation
FrameworkAnnotation,
DisposeOnCloseAnnotation,
HideOnCloseAnnotation
}
import it.feelburst.yayoi.model {
Framework
Expand All @@ -75,8 +81,17 @@ import it.feelburst.yayoi.model.window {
Window
}

import java.lang {
Types {
classForDeclaration
}
}

import org.springframework.beans.factory.annotation {
autowired
autowired,
Autowired,
Qualifier,
qualifier
}
import org.springframework.beans.factory.config {
ConfigurableListableBeanFactory
Expand Down Expand Up @@ -287,7 +302,29 @@ shared class ComponentRegistryImpl() satisfies ComponentRegistry {
}
else {
log.error(
"WindowEvent Reaction on Component '``cmp``' cannot be registered. " +
"ExitOnClose Reaction on Component '``cmp``' cannot be registered. " +
"Component must be a Window.");
}
}
if (exists ann = annotations(`DisposeOnCloseAnnotation`,cmp.decl)) {
if (is Window<Object> cmp) {
cmp.addReaction(DisposeOnCloseReaction(cmp,ann));
log.info("DisposeOnClose Reaction on Component '``cmp``' registered.");
}
else {
log.error(
"DisposeOnClose Reaction on Component '``cmp``' cannot be registered. " +
"Component must be a Window.");
}
}
if (exists ann = annotations(`HideOnCloseAnnotation`,cmp.decl)) {
if (is Window<Object> cmp) {
cmp.addReaction(HideOnCloseReaction(cmp,ann));
log.info("HideOnClose Reaction on Component '``cmp``' registered.");
}
else {
log.error(
"HideOnClose Reaction on Component '``cmp``' cannot be registered. " +
"Component must be a Window.");
}
}
Expand All @@ -305,48 +342,140 @@ shared class ComponentRegistryImpl() satisfies ComponentRegistry {
}
}

function getClassOrInterfaceType(
FunctionDeclaration|ValueDeclaration decl) {
try {
switch (type = decl.openType)
case (is OpenClassType|OpenInterfaceType) {
return type;
}
else {
return Exception(
"Type of declararion '``decl``' must be a class or an interface.");
}
}
catch (Exception e) {
return e;
}
}

function sameType(FunctionDeclaration decl,ValueDeclaration prmtrDecl) {
value mthdType = getClassOrInterfaceType(decl);
value prmtrType = getClassOrInterfaceType(prmtrDecl);
if (is OpenClassType|OpenInterfaceType mthdType) {
if (is OpenClassType|OpenInterfaceType prmtrType) {
return mthdType.declaration == prmtrType.declaration;
}
else {
return prmtrType;
}
}
else {
return mthdType;
}
}


function getBeanByType(ValueDeclaration prmtrDecl) {
try {
value prmtrType = getClassOrInterfaceType(prmtrDecl);
if (is OpenClassType|OpenInterfaceType prmtrType) {
return context.getBean(classForDeclaration(prmtrType.declaration));
}
else {
return prmtrType;
}
}
catch (Exception e) {
return e;
}
}

function getBeanByName(
String name,
FunctionDeclaration decl,
String prmtrName,
ValueDeclaration prmtrDecl) =>
// you cannot autowire the same object
if (prmtrName != name) then
if (context.containsBean(prmtrName)) then
context.getBean(prmtrName)
else
Exception(
"No object named '``prmtrName``' to autowire into " +
"declaration '``prmtrDecl``' of declaration '``decl``' " +
"has been found.")
else
Exception(
"Cannot autowire object '``prmtrName``' into declaration " +
"'``prmtrDecl``' of declaration '``decl``'. They are the same " +
"object! An object cannot autowire itself!");


shared actual <Type|Exception>() autowired<Type>(
String name,
FunctionDeclaration decl) =>
let (cmpsOrExs = decl.parameterDeclarations
let (cmpsOrObjsOrExs = decl.parameterDeclarations
.collect((FunctionOrValueDeclaration prmtrDecl) =>
//parameter must be a value
if (is ValueDeclaration prmtrDecl) then
//named for components
if (exists prmtrNmd = annotations(`NamedAnnotation`,prmtrDecl)) then
let (prmtrName = nameResolver.resolveNamed(decl, prmtrNmd))
if (prmtrName != name) then
if (context.containsBean(prmtrName)) then
context.getBean(prmtrName)
getBeanByName(name,decl,prmtrName,prmtrDecl)
//autowire any other bean by name
else if (nonempty qlfrAnns = prmtrDecl.annotations<Qualifier>()) then
let (prmtrName = qlfrAnns.first.\ivalue())
getBeanByName(name,decl,prmtrName,prmtrDecl)
//autowired any other bean by type
else if (prmtrDecl.annotated<Autowired>()) then
let (stap = sameType(decl,prmtrDecl))
if (is Boolean stap) then
//autowire by type
if (!stap) then
let (bbt = getBeanByType(prmtrDecl))
if (is Exception bbt) then
Exception(
"Cannot autowire object into declaration " +
"'``prmtrDecl``' of declaration '``decl``' due to the " +
"following error: ``bbt.message``.")
else
bbt
else
Exception(
"No component named '``prmtrName``' to autowire into " +
"declaration '``prmtrDecl``' of declaration '``decl``' " +
"has been found.")
"Cannot autowire object into declaration " +
"'``prmtrDecl``' of declaration '``decl``'. They both " +
"produce the same type and no '`` `function qualifier`.name ``' " +
"has been found, so it cannot be safely autowired.")
else
Exception(
"Cannot autowire component '``prmtrName``' into declaration " +
"'``prmtrDecl``' of declaration '``decl``'. They are the same " +
"object! A component cannot autowire itself!")
"Cannot autowire object into declaration " +
"'``prmtrDecl``' of declaration '``decl``' due to the " +
"following error: ``stap.message``.")
else
Exception(
"No named annotation found on declaration " +
"No named or autowired annotation found on declaration " +
"'``prmtrDecl``' of declaration '``decl``'.")
else
Exception(
"Parameter declaration '``prmtrDecl``' of declaration " +
"'``decl``' must be a value declaration.")))

let (exs = cmpsOrExs.narrow<Exception>())
let (exs = cmpsOrObjsOrExs.narrow<Exception>())
if (exs.empty) then
(() {
value cmps = cmpsOrExs
.narrow<
Component<Object>|
Container<Object>|
Collection<Object>|
Window<Object>|
Layout<Object>|
Listener<Object>>();
assert (is Type obj = decl.invoke([],*(cmps*.val)));
value cmpsOrObjs = cmpsOrObjsOrExs
.collect((Object cmpOrObj) =>
if (is Component<Object>|
Container<Object>|
Collection<Object>|
Window<Object>|
Layout<Object>|
Listener<Object> cmpOrObj) then
cmpOrObj.val
else
cmpOrObj);
assert (is Type obj = decl.invoke([],*cmpsOrObjs));
return obj;
})
else
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import it.feelburst.yayoi.model.window {
Window
}
"An event that reports dispose window on close has been set on a window"
shared class DisposeOnCloseSet(
shared Window<Object> source) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import it.feelburst.yayoi.model.window {
Window
}
"An event that reports hide window on close has been set on a window"
shared class HideOnCloseSet(
shared Window<Object> source) {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import it.feelburst.yayoi.behaviour.reaction {
Reaction
}
import it.feelburst.yayoi.marker {
DisposeOnCloseAnnotation
}
import it.feelburst.yayoi.model.window {
Window
}

"A reaction that disposes window
as a default window close operation"
shared class DisposeOnCloseReaction(
shared actual Window<Object> cmp,
shared actual DisposeOnCloseAnnotation ann)
satisfies Reaction<Window<Object>> {
shared actual void execute() {
cmp.setDisposeOnClose();
log.debug("Reaction: DisposeOnClose operation requested for Window '``cmp``'.");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import it.feelburst.yayoi.behaviour.reaction {
Reaction
}
import it.feelburst.yayoi.marker {
HideOnCloseAnnotation
}
import it.feelburst.yayoi.model.window {
Window
}

"A reaction that hides window
as a default window close operation"
shared class HideOnCloseReaction(
shared actual Window<Object> cmp,
shared actual HideOnCloseAnnotation ann)
satisfies Reaction<Window<Object>> {
shared actual void execute() {
cmp.setHideOnClose();
log.debug("Reaction: HideOnClose operation requested for Window '``cmp``'.");
}
}
Loading

0 comments on commit 9be6058

Please sign in to comment.