[ 
https://issues.apache.org/jira/browse/DELTASPIKE-877?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Gerhard Petracek updated DELTASPIKE-877:
----------------------------------------
    Description: 
currently a ConfigPreProcessor can manipulate custom metadata.
such a changed annotation-instance will be used instead of the found one.
however, those changes are currently limited to the current node and they 
aren't visible to child nodes. that can lead to redundant implementations 
(depending on the concrete use-case).

changing metadata in a "mixed" tree (inheritance and nesting) can get complex, 
however, if we allow child nodes to see just the changes done by 
ancestor-nodes, it won't increase the complexity for users and it's possible to 
support nice uses-cases like:

{code}
@View(navigation = REDIRECT)
public interface Pages extends ViewConfig {
    //...

    @Wizard //all wizard-steps inherit this meta-data and Step1 is known as 
entry-point (for all wizard-steps)
    interface MyWizard extends Pages {
        @EntryPoint
        class Step1 implements MyWizard {}

        class Step2 implements MyWizard {} //protected wizard-step (see 
EntryPointHandler)
        class Summary implements MyWizard {} //protected wizard-step (see 
EntryPointHandler)
    }
}

//...
@ViewMetaData
public @interface EntryPoint {
}

//...
@ViewMetaData(preProcessor = Wizard.EntryPointProcessor.class)
public @interface Wizard {
    Class<? extends ViewConfig> entryPoint() default ViewConfig.class;

    class EntryPointProcessor implements ConfigPreProcessor<Wizard> {
        @Override
        public Wizard beforeAddToConfig(Wizard wizard, ViewConfigNode 
viewConfigNode) {
            if (!ViewConfig.class.equals(wizard.entryPoint()) /*explicitly 
defined entry-point*/) {
                return wizard;
            }

            for (ViewConfigNode childNode : viewConfigNode.getChildren()) {
                for (Annotation childMetaData : childNode.getMetaData()) {
                    if 
(EntryPoint.class.equals(childMetaData.annotationType())) {
                        Map<String, Object> values = new HashMap<String, 
Object>();
                        values.put("entryPoint", childNode.getSource());
                        return AnnotationInstanceProvider.of(Wizard.class, 
values);
                    }
                }
            }
            return wizard;
        }
    }
}

@WindowScoped
public class EntryPointHandler implements Serializable {
    private Class<? extends ViewConfig> previousEntryPoint;

    @Inject
    private ViewConfigResolver viewConfigResolver;

    @Inject
    private ViewNavigationHandler viewNavigationHandler;

    protected void checkEntryPointsAndWizardSteps(@Observes 
@BeforePhase(JsfPhaseId.RENDER_RESPONSE) PhaseEvent phaseEvent) {
        UIViewRoot viewRoot = phaseEvent.getFacesContext().getViewRoot();

        if (viewRoot == null) {
            return;
        }
        String viewIdToRender = viewRoot.getViewId();
        ViewConfigDescriptor viewConfigDescriptor = 
viewConfigResolver.getViewConfigDescriptor(viewIdToRender);

        if (viewConfigDescriptor == null) {
            return;
        }
        if (!viewConfigDescriptor.getMetaData(EntryPoint.class).isEmpty()) {
            this.previousEntryPoint = viewConfigDescriptor.getConfigClass();
            //additional entry-point logic - like close open conversation, fire 
an event,...
        } else if (!viewConfigDescriptor.getMetaData(Wizard.class).isEmpty()) {
            Wizard wizard = 
viewConfigDescriptor.getMetaData(Wizard.class).iterator().next();

            Class<? extends ViewConfig> entryPointOfWizard = 
wizard.entryPoint();
            if (!entryPointOfWizard.equals(this.previousEntryPoint)) {
                this.viewNavigationHandler.navigateTo(entryPointOfWizard);
            }
        }
    }
}
{code}

that are less than 100 loc for a simple but generic entry-point logic and 
protection of wizard steps (including redirection to the start/entry-point of 
the corresponding wizard) which replace features like @ConversationRequired and 
way nicer than what's needed currently:

{code}
@View(navigation = REDIRECT)
public interface Pages extends ViewConfig {
    //...

    interface OutdatedWizard extends Pages {
        @EntryPoint
        class Step1 implements MyWizard {}

        @Wizard(EntryPoint = Pages.MyWizard.Step1.class)
        class Step2 implements MyWizard {}

        @Wizard(EntryPoint = Pages.MyWizard.Step1.class)
        class Summary implements PromotionWizard {}
    }
}
//...
{code}

  was:
currently a ConfigPreProcessor can manipulate custom metadata.
such a changed annotation-instance will be used instead of the found one.
however, those changes are currently limited to the current node and they 
aren't visible to child nodes. that can lead to redundant implementations 
(depending on the concrete use-case).

changing metadata in a "mixed" tree (inheritance and nesting) can get complex, 
however, if we allow child nodes to see just the changes done by 
ancestor-nodes, it won't increase the complexity for users and it's possible to 
support nice uses-cases like:

{code}
@View(navigation = REDIRECT)
public interface Pages extends ViewConfig {
    //...

    @Wizard //all wizard-steps inherit this meta-data and Step1 is known as 
entry-point (for all wizard-steps)
    interface MyWizard extends Pages {
        @EntryPoint
        class Step1 implements MyWizard {}

        class Step2 implements MyWizard {} //protected wizard-step (see 
EntryPointHandler)
        class Summary implements Wizard {} //protected wizard-step (see 
EntryPointHandler)
    }
}

//...
@ViewMetaData
public @interface EntryPoint {
}

//...
@ViewMetaData(preProcessor = Wizard.EntryPointProcessor.class)
public @interface Wizard {
    Class<? extends ViewConfig> entryPoint() default ViewConfig.class;

    class EntryPointProcessor implements ConfigPreProcessor<Wizard> {
        @Override
        public Wizard beforeAddToConfig(Wizard wizard, ViewConfigNode 
viewConfigNode) {
            if (!ViewConfig.class.equals(wizard.entryPoint()) /*explicitly 
defined entry-point*/) {
                return wizard;
            }

            for (ViewConfigNode childNode : viewConfigNode.getChildren()) {
                for (Annotation childMetaData : childNode.getMetaData()) {
                    if 
(EntryPoint.class.equals(childMetaData.annotationType())) {
                        Map<String, Object> values = new HashMap<String, 
Object>();
                        values.put("entryPoint", childNode.getSource());
                        return AnnotationInstanceProvider.of(Wizard.class, 
values);
                    }
                }
            }
            return wizard;
        }
    }
}

@WindowScoped
public class EntryPointHandler implements Serializable {
    private Class<? extends ViewConfig> previousEntryPoint;

    @Inject
    private ViewConfigResolver viewConfigResolver;

    @Inject
    private ViewNavigationHandler viewNavigationHandler;

    protected void checkEntryPointsAndWizardSteps(@Observes 
@BeforePhase(JsfPhaseId.RENDER_RESPONSE) PhaseEvent phaseEvent) {
        UIViewRoot viewRoot = phaseEvent.getFacesContext().getViewRoot();

        if (viewRoot == null) {
            return;
        }
        String viewIdToRender = viewRoot.getViewId();
        ViewConfigDescriptor viewConfigDescriptor = 
viewConfigResolver.getViewConfigDescriptor(viewIdToRender);

        if (viewConfigDescriptor == null) {
            return;
        }
        if (!viewConfigDescriptor.getMetaData(EntryPoint.class).isEmpty()) {
            this.previousEntryPoint = viewConfigDescriptor.getConfigClass();
            //additional entry-point logic - like close open conversation, fire 
an event,...
        } else if (!viewConfigDescriptor.getMetaData(Wizard.class).isEmpty()) {
            Wizard wizard = 
viewConfigDescriptor.getMetaData(Wizard.class).iterator().next();

            Class<? extends ViewConfig> entryPointOfWizard = 
wizard.entryPoint();
            if (!entryPointOfWizard.equals(this.previousEntryPoint)) {
                this.viewNavigationHandler.navigateTo(entryPointOfWizard);
            }
        }
    }
}
{code}

that are less than 100 loc for a simple but generic entry-point logic and 
protection of wizard steps (including redirection to the start/entry-point of 
the corresponding wizard) which replace features like @ConversationRequired and 
way nicer than what's needed currently:

{code}
@View(navigation = REDIRECT)
public interface Pages extends ViewConfig {
    //...

    interface OutdatedWizard extends Pages {
        @EntryPoint
        class Step1 implements MyWizard {}

        @Wizard(EntryPoint = Pages.MyWizard.Step1.class)
        class Step2 implements MyWizard {}

        @Wizard(EntryPoint = Pages.MyWizard.Step1.class)
        class Summary implements PromotionWizard {}
    }
}
//...
{code}


> allow to inherit dynamically changed metadata 
> ----------------------------------------------
>
>                 Key: DELTASPIKE-877
>                 URL: https://issues.apache.org/jira/browse/DELTASPIKE-877
>             Project: DeltaSpike
>          Issue Type: New Feature
>          Components: JSF-Module
>    Affects Versions: 1.3.0
>            Reporter: Gerhard Petracek
>            Assignee: Gerhard Petracek
>             Fix For: 1.3.1
>
>
> currently a ConfigPreProcessor can manipulate custom metadata.
> such a changed annotation-instance will be used instead of the found one.
> however, those changes are currently limited to the current node and they 
> aren't visible to child nodes. that can lead to redundant implementations 
> (depending on the concrete use-case).
> changing metadata in a "mixed" tree (inheritance and nesting) can get 
> complex, however, if we allow child nodes to see just the changes done by 
> ancestor-nodes, it won't increase the complexity for users and it's possible 
> to support nice uses-cases like:
> {code}
> @View(navigation = REDIRECT)
> public interface Pages extends ViewConfig {
>     //...
>     @Wizard //all wizard-steps inherit this meta-data and Step1 is known as 
> entry-point (for all wizard-steps)
>     interface MyWizard extends Pages {
>         @EntryPoint
>         class Step1 implements MyWizard {}
>         class Step2 implements MyWizard {} //protected wizard-step (see 
> EntryPointHandler)
>         class Summary implements MyWizard {} //protected wizard-step (see 
> EntryPointHandler)
>     }
> }
> //...
> @ViewMetaData
> public @interface EntryPoint {
> }
> //...
> @ViewMetaData(preProcessor = Wizard.EntryPointProcessor.class)
> public @interface Wizard {
>     Class<? extends ViewConfig> entryPoint() default ViewConfig.class;
>     class EntryPointProcessor implements ConfigPreProcessor<Wizard> {
>         @Override
>         public Wizard beforeAddToConfig(Wizard wizard, ViewConfigNode 
> viewConfigNode) {
>             if (!ViewConfig.class.equals(wizard.entryPoint()) /*explicitly 
> defined entry-point*/) {
>                 return wizard;
>             }
>             for (ViewConfigNode childNode : viewConfigNode.getChildren()) {
>                 for (Annotation childMetaData : childNode.getMetaData()) {
>                     if 
> (EntryPoint.class.equals(childMetaData.annotationType())) {
>                         Map<String, Object> values = new HashMap<String, 
> Object>();
>                         values.put("entryPoint", childNode.getSource());
>                         return AnnotationInstanceProvider.of(Wizard.class, 
> values);
>                     }
>                 }
>             }
>             return wizard;
>         }
>     }
> }
> @WindowScoped
> public class EntryPointHandler implements Serializable {
>     private Class<? extends ViewConfig> previousEntryPoint;
>     @Inject
>     private ViewConfigResolver viewConfigResolver;
>     @Inject
>     private ViewNavigationHandler viewNavigationHandler;
>     protected void checkEntryPointsAndWizardSteps(@Observes 
> @BeforePhase(JsfPhaseId.RENDER_RESPONSE) PhaseEvent phaseEvent) {
>         UIViewRoot viewRoot = phaseEvent.getFacesContext().getViewRoot();
>         if (viewRoot == null) {
>             return;
>         }
>         String viewIdToRender = viewRoot.getViewId();
>         ViewConfigDescriptor viewConfigDescriptor = 
> viewConfigResolver.getViewConfigDescriptor(viewIdToRender);
>         if (viewConfigDescriptor == null) {
>             return;
>         }
>         if (!viewConfigDescriptor.getMetaData(EntryPoint.class).isEmpty()) {
>             this.previousEntryPoint = viewConfigDescriptor.getConfigClass();
>             //additional entry-point logic - like close open conversation, 
> fire an event,...
>         } else if (!viewConfigDescriptor.getMetaData(Wizard.class).isEmpty()) 
> {
>             Wizard wizard = 
> viewConfigDescriptor.getMetaData(Wizard.class).iterator().next();
>             Class<? extends ViewConfig> entryPointOfWizard = 
> wizard.entryPoint();
>             if (!entryPointOfWizard.equals(this.previousEntryPoint)) {
>                 this.viewNavigationHandler.navigateTo(entryPointOfWizard);
>             }
>         }
>     }
> }
> {code}
> that are less than 100 loc for a simple but generic entry-point logic and 
> protection of wizard steps (including redirection to the start/entry-point of 
> the corresponding wizard) which replace features like @ConversationRequired 
> and way nicer than what's needed currently:
> {code}
> @View(navigation = REDIRECT)
> public interface Pages extends ViewConfig {
>     //...
>     interface OutdatedWizard extends Pages {
>         @EntryPoint
>         class Step1 implements MyWizard {}
>         @Wizard(EntryPoint = Pages.MyWizard.Step1.class)
>         class Step2 implements MyWizard {}
>         @Wizard(EntryPoint = Pages.MyWizard.Step1.class)
>         class Summary implements PromotionWizard {}
>     }
> }
> //...
> {code}



--
This message was sent by Atlassian JIRA
(v6.3.4#6332)

Reply via email to