From ae67cf6faae6c759625a108cafda86f66caa88f4 Mon Sep 17 00:00:00 2001
From: gonzalad
Date: Thu, 27 Oct 2011 17:48:49 +0200
Subject: [PATCH 1/9] Intermediate commit
ViewAction are registered in ViewConfigStore.
Limitation due to ViewConfigStore storing only Annotation.
I need to store at least AnnotatedMethod otherwise I won't be able to know
which method to call if 2 methods have been annotated with exactly the same
annotation (same attribute values I think).
---
.../seam/faces/view/action/Condition.java | 21 ++
.../seam/faces/view/action/Immediate.java | 22 ++
.../seam/faces/view/action/OnPostback.java | 22 ++
.../jboss/seam/faces/view/action/Phase.java | 23 ++
.../seam/faces/view/action/PhaseDefault.java | 22 ++
.../view/action/ViewActionBindingType.java | 27 ++
examples/viewconfig/pom.xml | 23 +-
.../examples/viewconfig/MyViewAction.java | 21 ++
.../examples/viewconfig/PageController.java | 7 +
.../view/action/ViewActionPhaseListener.java | 230 ++++++++++++++++++
.../view/config/ViewConfigExtension.java | 66 ++++-
pom.xml | 8 +-
12 files changed, 482 insertions(+), 10 deletions(-)
create mode 100644 api/src/main/java/org/jboss/seam/faces/view/action/Condition.java
create mode 100644 api/src/main/java/org/jboss/seam/faces/view/action/Immediate.java
create mode 100644 api/src/main/java/org/jboss/seam/faces/view/action/OnPostback.java
create mode 100644 api/src/main/java/org/jboss/seam/faces/view/action/Phase.java
create mode 100644 api/src/main/java/org/jboss/seam/faces/view/action/PhaseDefault.java
create mode 100644 api/src/main/java/org/jboss/seam/faces/view/action/ViewActionBindingType.java
create mode 100644 examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyViewAction.java
create mode 100644 impl/src/main/java/org/jboss/seam/faces/view/action/ViewActionPhaseListener.java
diff --git a/api/src/main/java/org/jboss/seam/faces/view/action/Condition.java b/api/src/main/java/org/jboss/seam/faces/view/action/Condition.java
new file mode 100644
index 0000000..a5448e1
--- /dev/null
+++ b/api/src/main/java/org/jboss/seam/faces/view/action/Condition.java
@@ -0,0 +1,21 @@
+package org.jboss.seam.faces.view.action;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Conditionnally executes a viewAction.
+ *
+ * TODO : refactor me, I'm not type-safe !
+ *
+ * @author Adriàn Gonzalez
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Condition {
+ public String condition = null;
+}
diff --git a/api/src/main/java/org/jboss/seam/faces/view/action/Immediate.java b/api/src/main/java/org/jboss/seam/faces/view/action/Immediate.java
new file mode 100644
index 0000000..6f1a98d
--- /dev/null
+++ b/api/src/main/java/org/jboss/seam/faces/view/action/Immediate.java
@@ -0,0 +1,22 @@
+package org.jboss.seam.faces.view.action;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.jboss.seam.faces.component.UIViewAction;
+
+/**
+ * Can be used instead of Phase.
+ *
+ * @see UIViewAction#isImmediate()
+ * @author Adriàn Gonzalez
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Immediate {
+ public Boolean immediate = null;
+}
diff --git a/api/src/main/java/org/jboss/seam/faces/view/action/OnPostback.java b/api/src/main/java/org/jboss/seam/faces/view/action/OnPostback.java
new file mode 100644
index 0000000..156a7d2
--- /dev/null
+++ b/api/src/main/java/org/jboss/seam/faces/view/action/OnPostback.java
@@ -0,0 +1,22 @@
+package org.jboss.seam.faces.view.action;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.jboss.seam.faces.component.UIViewAction;
+
+/**
+ * Determines if viewAction is executed on postback.
+ *
+ * @see UIViewAction#isOnPostback()
+ * @author Adriàn Gonzalez
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface OnPostback {
+ public Boolean onPostback = false;
+}
diff --git a/api/src/main/java/org/jboss/seam/faces/view/action/Phase.java b/api/src/main/java/org/jboss/seam/faces/view/action/Phase.java
new file mode 100644
index 0000000..28d0487
--- /dev/null
+++ b/api/src/main/java/org/jboss/seam/faces/view/action/Phase.java
@@ -0,0 +1,23 @@
+package org.jboss.seam.faces.view.action;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.jboss.seam.faces.component.UIViewAction;
+import org.jboss.seam.faces.event.PhaseIdType;
+
+/**
+ * Phase on which a viewAction is executed.
+ *
+ * @see UIViewAction#getPhase()
+ * @author Adriàn Gonzalez
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Phase {
+ public PhaseIdType value() default PhaseIdType.RENDER_RESPONSE;
+}
diff --git a/api/src/main/java/org/jboss/seam/faces/view/action/PhaseDefault.java b/api/src/main/java/org/jboss/seam/faces/view/action/PhaseDefault.java
new file mode 100644
index 0000000..b21e929
--- /dev/null
+++ b/api/src/main/java/org/jboss/seam/faces/view/action/PhaseDefault.java
@@ -0,0 +1,22 @@
+package org.jboss.seam.faces.view.action;
+
+import org.jboss.seam.faces.event.PhaseIdType;
+
+/**
+ * The Default values for Phase annotation, extracted as constant.
+ *
+ * @author Adriàn Gonzalez
+ */
+public class PhaseDefault {
+ public static final PhaseIdType DEFAULT_PHASE;
+
+ static {
+ try {
+ DEFAULT_PHASE = (PhaseIdType) Phase.class.getMethod("value").getDefaultValue();
+ } catch (NoSuchMethodException ex) {
+ throw new IllegalStateException("Error initialising values", ex);
+ } catch (SecurityException ex) {
+ throw new IllegalStateException("Error initialising values", ex);
+ }
+ }
+}
diff --git a/api/src/main/java/org/jboss/seam/faces/view/action/ViewActionBindingType.java b/api/src/main/java/org/jboss/seam/faces/view/action/ViewActionBindingType.java
new file mode 100644
index 0000000..93115e5
--- /dev/null
+++ b/api/src/main/java/org/jboss/seam/faces/view/action/ViewActionBindingType.java
@@ -0,0 +1,27 @@
+package org.jboss.seam.faces.view.action;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Applied to an annotation to indicate that it is a faces action binding type
+ *
+ * Additionally, you can customize your view annotation follogin one of those approaches :
+ *
+ *
any other annotations in this package can also be applied to this annotation
+ * to customize view action behaviour (phase, postback, ...). This enables to customize behaviour
+ * per annotation definition
+ *
those annotations can be replaced by methods of the same name in the view action annotation.
+ * This enables to customize behaviour per annotation usage.
+ *
+ *
+ * @author Adriàn Gonzalez
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface ViewActionBindingType {
+}
diff --git a/examples/viewconfig/pom.xml b/examples/viewconfig/pom.xml
index 55e6f76..e40c71a 100644
--- a/examples/viewconfig/pom.xml
+++ b/examples/viewconfig/pom.xml
@@ -36,6 +36,26 @@
org.jboss.seam.facesseam-faces-api
+
+
+ org.jboss.seam.transaction
+ seam-transaction-api
+
+
+
+ org.jboss.seam.transaction
+ seam-transaction
+
+
+
+ org.jboss.seam.international
+ seam-international-api
+
+
+
+ org.jboss.seam.international
+ seam-international
+ org.jboss.seam.security
@@ -47,7 +67,6 @@
org.jboss.seam.securityseam-securitycompile
- 3.1.0.Beta2
@@ -57,6 +76,8 @@
com.ocpsoftprettyfaces-jsf2
+
+ 3.3.0
diff --git a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyViewAction.java b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyViewAction.java
new file mode 100644
index 0000000..2e97b03
--- /dev/null
+++ b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyViewAction.java
@@ -0,0 +1,21 @@
+package org.jboss.seam.faces.examples.viewconfig;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import org.jboss.seam.faces.view.action.ViewActionBindingType;
+
+@ViewActionBindingType
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
+public @interface MyViewAction {
+ MyAppViewConfig.Pages value();
+
+ //just testing value override
+// public PhaseIdType phase() default PhaseIdType.RENDER_RESPONSE;
+// public Boolean immediate = null;
+// public Boolean onPostback = false;
+// public String condition = null;
+}
diff --git a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/PageController.java b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/PageController.java
index 122b3b7..34bdf36 100644
--- a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/PageController.java
+++ b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/PageController.java
@@ -25,6 +25,7 @@
import javax.inject.Inject;
import javax.inject.Named;
+import org.jboss.seam.faces.examples.viewconfig.MyAppViewConfig.Pages;
import org.jboss.seam.faces.examples.viewconfig.model.Current;
import org.jboss.seam.faces.examples.viewconfig.model.Item;
import org.jboss.seam.faces.examples.viewconfig.model.ItemDao;
@@ -53,6 +54,12 @@ public Item getItem() {
return item;
}
+ @MyViewAction(Pages.ITEM)
+ public void loadEntry() {
+ System.out.println("loadEntry called");
+ }
+
+ @MyViewAction(Pages.ITEM)
public void setItem(Item item) {
this.item = item;
}
diff --git a/impl/src/main/java/org/jboss/seam/faces/view/action/ViewActionPhaseListener.java b/impl/src/main/java/org/jboss/seam/faces/view/action/ViewActionPhaseListener.java
new file mode 100644
index 0000000..80f3d57
--- /dev/null
+++ b/impl/src/main/java/org/jboss/seam/faces/view/action/ViewActionPhaseListener.java
@@ -0,0 +1,230 @@
+package org.jboss.seam.faces.view.action;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.BeanManager;
+import javax.faces.component.UIViewRoot;
+import javax.faces.context.FacesContext;
+import javax.faces.event.PhaseEvent;
+import javax.inject.Inject;
+
+import org.jboss.seam.faces.event.PhaseIdType;
+import org.jboss.seam.faces.event.qualifier.After;
+import org.jboss.seam.faces.event.qualifier.ApplyRequestValues;
+import org.jboss.seam.faces.event.qualifier.Before;
+import org.jboss.seam.faces.event.qualifier.InvokeApplication;
+import org.jboss.seam.faces.event.qualifier.ProcessValidations;
+import org.jboss.seam.faces.event.qualifier.RenderResponse;
+import org.jboss.seam.faces.event.qualifier.RestoreView;
+import org.jboss.seam.faces.event.qualifier.UpdateModelValues;
+import org.jboss.seam.faces.view.config.ViewConfigStore;
+import org.jboss.solder.logging.Logger;
+import org.jboss.solder.reflection.AnnotationInspector;
+
+/**
+ * Use the annotations stored in the ViewConfigStore to execute action (MethodExpression) calls.
+ *
+ * Class similar to SecurityPhaseListener.
+ *
+ * @author Adriàn Gonzalez
+ */
+public class ViewActionPhaseListener {
+
+ private transient final Logger log = Logger.getLogger(ViewActionPhaseListener.class);
+
+ @Inject
+ private ViewConfigStore viewConfigStore;
+ @Inject
+ private BeanManager beanManager;
+
+ /**
+ * Execute any action annotations applicable to the RestoreView phase
+ *
+ * @param event
+ */
+ public void observeRestoreView(@Observes @After @RestoreView PhaseEvent event) {
+ log.debug("After Restore View event");
+ performObservation(event, PhaseIdType.RESTORE_VIEW);
+ }
+
+ /**
+ * Execute any action annotations applicable to the ApplyRequestValues phase
+ *
+ * @param event
+ */
+ public void observeApplyRequestValues(@Observes @Before @ApplyRequestValues PhaseEvent event) {
+ log.debug("After Apply Request Values event");
+ performObservation(event, PhaseIdType.APPLY_REQUEST_VALUES);
+ }
+
+ /**
+ * Execute any action annotations applicable to the ProcessValidations phase
+ *
+ * @param event
+ */
+ public void observeProcessValidations(@Observes @Before @ProcessValidations PhaseEvent event) {
+ log.debug("After Process Validations event");
+ performObservation(event, PhaseIdType.PROCESS_VALIDATIONS);
+ }
+
+ /**
+ * Execute any action annotations applicable to the UpdateModelValues phase
+ *
+ * @param event
+ */
+ public void observeUpdateModelValues(@Observes @Before @UpdateModelValues PhaseEvent event) {
+ log.debug("After Update Model Values event");
+ performObservation(event, PhaseIdType.UPDATE_MODEL_VALUES);
+ }
+
+ /**
+ * Execute any action annotations applicable to the InvokeApplication phase
+ *
+ * @param event
+ */
+ public void observeInvokeApplication(@Observes @Before @InvokeApplication PhaseEvent event) {
+ log.debug("Before Render Response event");
+ performObservation(event, PhaseIdType.INVOKE_APPLICATION);
+ }
+
+ /**
+ * Execute any action annotations applicable to the RenderResponse phase
+ *
+ * @param event
+ */
+ public void observeRenderResponse(@Observes @Before @RenderResponse PhaseEvent event) {
+ log.debug("Before Render Response event");
+ performObservation(event, PhaseIdType.RENDER_RESPONSE);
+ }
+
+ /**
+ * Inspect the annotations in the ViewConfigStore, executing any actions applicable to this phase
+ *
+ * @param event
+ * @param phaseIdType
+ */
+ private void performObservation(PhaseEvent event, PhaseIdType phaseIdType) {
+ UIViewRoot viewRoot = (UIViewRoot) event.getFacesContext().getViewRoot();
+ List extends Annotation> actionsForPhase = getViewActionsForPhase(phaseIdType, viewRoot.getViewId());
+ if (actionsForPhase != null) {
+ log.debugf("Enforcing on phase %s", phaseIdType);
+ execute(event.getFacesContext(), viewRoot, actionsForPhase);
+ }
+ }
+
+ /**
+ * Retrieve all annotations from the ViewConfigStore for a given a JSF phase, and a view id,
+ * and where the annotation is qualified by @SecurityBindingType
+ *
+ * @param currentPhase
+ * @param viewId
+ * @return list of restrictions applicable to this viewId and PhaseTypeId
+ */
+ public List extends Annotation> getViewActionsForPhase(PhaseIdType currentPhase, String viewId) {
+ List extends Annotation> allViewActionAnnotations = viewConfigStore.getAllQualifierData(viewId, ViewActionBindingType.class);
+ List applicableViewActionAnnotations = null;
+ for (Annotation annotation : allViewActionAnnotations) {
+ PhaseIdType defaultPhase = getDefaultPhase(viewId);
+ if (isAnnotationApplicableToPhase(annotation, currentPhase, defaultPhase)) {
+ if (applicableViewActionAnnotations == null) { // avoid spawning arrays at all phases of the lifecycle
+ applicableViewActionAnnotations = new ArrayList();
+ }
+ applicableViewActionAnnotations.add(annotation);
+ }
+ }
+ return applicableViewActionAnnotations;
+ }
+
+ /**
+ * Inspect an annotation to see if it specifies a view in which it should be. Fall back on default view otherwise.
+ *
+ * @param annotation
+ * @param currentPhase
+ * @param defaultPhases
+ * @return true if the annotation is applicable to this view and phase, false otherwise
+ */
+ public boolean isAnnotationApplicableToPhase(Annotation annotation, PhaseIdType currentPhase, PhaseIdType defaultPhase) {
+ Method phaseAtViewActionMethod = getPhaseAtViewActionMethod(annotation);
+ PhaseIdType phasedId = null;
+ if (phaseAtViewActionMethod != null) {
+ log.debug("Annotation %s is using the phase method.");
+ phasedId = getViewActionPhaseId(phaseAtViewActionMethod, annotation);
+ }
+ Phase phaseQualifier = AnnotationInspector.getAnnotation(annotation.annotationType(), Phase.class, beanManager);
+ if (phaseQualifier != null) {
+ log.debug("Using Phase found in @Phase qualifier on the annotation.");
+ phasedId = phaseQualifier.value();
+ }
+ if (phasedId == null) {
+ log.debug("Falling back on default phase id");
+ phasedId = defaultPhase;
+ }
+ return phasedId == currentPhase;
+ }
+
+ /**
+ * Get the default phases at which restrictions should be applied, by looking for a @Phase default value
+ *
+ * @param viewId
+ * @return default phase
+ */
+ public PhaseIdType getDefaultPhase(String viewId) {
+ return PhaseDefault.DEFAULT_PHASE;
+ }
+
+ /**
+ * Utility method to extract the "phase" method from an annotation
+ *
+ * @param annotation
+ * @return phaseAtViewActionMethod if found, null otherwise
+ */
+ public Method getPhaseAtViewActionMethod(Annotation annotation) {
+ Method phaseAtViewActionMethod;
+ try {
+ phaseAtViewActionMethod = annotation.annotationType().getDeclaredMethod("phase");
+ } catch (NoSuchMethodException ex) {
+ phaseAtViewActionMethod = null;
+ } catch (SecurityException ex) {
+ throw new IllegalArgumentException("phase method must be accessible", ex);
+ }
+ return phaseAtViewActionMethod;
+ }
+
+ /**
+ * Retrieve the default PhaseIdType defined by the phaseAtViewActionMethod in the annotation
+ *
+ * @param phaseAtViewActionMethod
+ * @param annotation
+ * @return PhaseIdType from the phaseAtViewActionMethod, null if empty
+ */
+ public PhaseIdType getViewActionPhaseId(Method phaseAtViewActionMethod, Annotation annotation) {
+ PhaseIdType phaseId;
+ try {
+ phaseId = (PhaseIdType) phaseAtViewActionMethod.invoke(annotation);
+ } catch (IllegalAccessException ex) {
+ throw new IllegalArgumentException("phase method must be accessible", ex);
+ } catch (InvocationTargetException ex) {
+ throw new RuntimeException(ex);
+ }
+ return phaseId;
+ }
+
+ /**
+ * Execute the list of applicable view action annotations, TODO...
+ *
+ * @param context
+ * @param viewRoot
+ * @param annotations
+ */
+ private void execute(FacesContext context, UIViewRoot viewRoot, List extends Annotation> annotations) {
+ if (annotations == null || annotations.isEmpty()) {
+ log.debug("Annotations is null/empty");
+ return;
+ }
+ }
+}
diff --git a/impl/src/main/java/org/jboss/seam/faces/view/config/ViewConfigExtension.java b/impl/src/main/java/org/jboss/seam/faces/view/config/ViewConfigExtension.java
index 8d9cc59..2cdc7a7 100644
--- a/impl/src/main/java/org/jboss/seam/faces/view/config/ViewConfigExtension.java
+++ b/impl/src/main/java/org/jboss/seam/faces/view/config/ViewConfigExtension.java
@@ -18,6 +18,8 @@
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@@ -25,10 +27,12 @@
import java.util.Set;
import javax.enterprise.event.Observes;
+import javax.enterprise.inject.spi.AnnotatedMethod;
import javax.enterprise.inject.spi.AnnotatedType;
import javax.enterprise.inject.spi.Extension;
import javax.enterprise.inject.spi.ProcessAnnotatedType;
+import org.jboss.seam.faces.view.action.ViewActionBindingType;
import org.jboss.solder.logging.Logger;
/**
@@ -43,6 +47,8 @@ public class ViewConfigExtension implements Extension {
private final Map> data = new HashMap>();
+ private final Map
+ *
+ * @author Adriàn Gonzalez
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+@Documented
+public @interface ViewController {
+ Class>[] value();
+}
diff --git a/api/src/main/java/org/jboss/seam/faces/view/config/ViewConfigDescriptor.java b/api/src/main/java/org/jboss/seam/faces/view/config/ViewConfigDescriptor.java
new file mode 100644
index 0000000..4a70c79
--- /dev/null
+++ b/api/src/main/java/org/jboss/seam/faces/view/config/ViewConfigDescriptor.java
@@ -0,0 +1,106 @@
+package org.jboss.seam.faces.view.config;
+
+import java.lang.annotation.Annotation;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.jboss.solder.logging.Logger;
+
+/**
+ * Information about {@link ViewConfig} enum.
+ *
+ * @author Adriàn Gonzalez
+ */
+public class ViewConfigDescriptor {
+ private transient final Logger log = Logger.getLogger(ViewConfigDescriptor.class);
+
+ private String viewId;
+ private List values = new ArrayList();
+ private List metaData = new ArrayList();
+ private final ConcurrentHashMap, Annotation> metaDataByAnnotation = new ConcurrentHashMap, Annotation>();
+ private ConcurrentHashMap, List extends Annotation>> metaDataByQualifier = new ConcurrentHashMap, List extends Annotation>>();
+
+ /**
+ * ViewConfigDescriptor for view viewId
+ */
+ public ViewConfigDescriptor(String viewId, Object value) {
+ this.viewId = viewId;
+ this.values = new ArrayList();
+ values.add(value);
+ }
+
+ public String getViewId() {
+ return viewId;
+ }
+
+ public void setViewId(String viewId) {
+ this.viewId = viewId;
+ }
+
+ public void addValue(Object value) {
+ if (!values.contains(value)) {
+ values.add(value);
+ }
+ }
+
+ public List getValues() {
+ return values;
+ }
+
+ public void setValues(List values) {
+ this.values = values;
+ }
+
+ public void addMetaData(Annotation metaData) {
+ this.metaData.add(metaData);
+ //add to metaDataByAnnotation
+ metaDataByAnnotation.put(metaData.annotationType(), metaData);
+ log.debugf("Putting new annotation (type: %s) for viewId: %s", metaData.annotationType().getName(), getViewId());
+ //add to metaDataByQualifier
+ Annotation[] annotations = metaData.annotationType().getAnnotations();
+ for (Annotation qualifier : annotations) {
+ if (qualifier.annotationType().getName().startsWith("java.")) {
+ log.debugf("Disregarding java.* package %s", qualifier.annotationType().getName());
+ continue;
+ }
+ List qualifiedAnnotations = new ArrayList();
+ List extends Annotation> exisitngQualifiedAnnotations = metaDataByQualifier.get(qualifier
+ .annotationType());
+ if (exisitngQualifiedAnnotations != null && !exisitngQualifiedAnnotations.isEmpty()) {
+ qualifiedAnnotations.addAll(exisitngQualifiedAnnotations);
+ }
+ qualifiedAnnotations.add(metaData);
+ log.debugf("Adding new annotation (type: %s) for Qualifier %s", metaData.annotationType().getName(), qualifier.annotationType().getName());
+ metaDataByQualifier.put(qualifier.annotationType(), qualifiedAnnotations);
+ }
+ }
+
+ /**
+ * Returns read-only list.
+ *
+ * Use {@link #addMetaData(Annotation)} to modify metaDatas.
+ */
+ public List getMetaData() {
+ return Collections.unmodifiableList(metaData);
+ }
+
+ /**
+ * returns all metaData of the corresponding type.
+ */
+ public T getMetaData(Class type) {
+ return (T) metaDataByAnnotation.get(type);
+ }
+
+ /**
+ * returns all qualified data from metadata annotations.
+ *
+ * returns empty list if there's no metaData for the qualifier.
+ */
+ @SuppressWarnings("unchecked")
+ public List extends Annotation> getAllQualifierData(Class extends Annotation> qualifier) {
+ List extends Annotation> metaData = metaDataByQualifier.get(qualifier);
+ return metaData!=null ? Collections.unmodifiableList(metaData) : Collections.EMPTY_LIST;
+ }
+}
diff --git a/api/src/main/java/org/jboss/seam/faces/view/config/ViewConfigStore.java b/api/src/main/java/org/jboss/seam/faces/view/config/ViewConfigStore.java
index da7b462..f8b85de 100644
--- a/api/src/main/java/org/jboss/seam/faces/view/config/ViewConfigStore.java
+++ b/api/src/main/java/org/jboss/seam/faces/view/config/ViewConfigStore.java
@@ -56,4 +56,8 @@ public interface ViewConfigStore {
*/
public Map getAllAnnotationViewMap(Class type);
+ /**
+ * return the registered viewConfigs
+ */
+ public List getAllViewConfigDescriptors();
}
diff --git a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyAppViewConfig.java b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyAppViewConfig.java
index f74ada0..dcc26d0 100644
--- a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyAppViewConfig.java
+++ b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyAppViewConfig.java
@@ -16,12 +16,16 @@
*/
package org.jboss.seam.faces.examples.viewconfig;
+import org.jboss.seam.faces.event.qualifier.ApplyRequestValues;
+import org.jboss.seam.faces.event.qualifier.Before;
import org.jboss.seam.faces.examples.viewconfig.security.Admin;
import org.jboss.seam.faces.examples.viewconfig.security.Owner;
import org.jboss.seam.faces.rewrite.FacesRedirect;
import org.jboss.seam.faces.rewrite.UrlMapping;
import org.jboss.seam.faces.security.AccessDeniedView;
import org.jboss.seam.faces.security.LoginView;
+import org.jboss.seam.faces.view.action.ViewAction;
+import org.jboss.seam.faces.view.action.ViewController;
import org.jboss.seam.faces.view.config.ViewConfig;
import org.jboss.seam.faces.view.config.ViewPattern;
@@ -39,9 +43,23 @@ static enum Pages {
@UrlMapping(pattern = "/item/#{id}/")
@ViewPattern("/item.xhtml")
+ @ViewController(PageController.class)
@Owner
+ @ViewAction("#{pageController.viewAction(pageController.item)}")
+ @Before @ApplyRequestValues
ITEM,
+ @ViewPattern("/viewcontroller.xhtml")
+ @ViewController(org.jboss.seam.faces.examples.viewconfig.ViewController.class)
+ VIEW_CONTROLLER,
+
+ @ViewPattern("/viewactionbindingtype.xhtml")
+ VIEW_ACTION_BINDING_TYPE,
+
+ @ViewPattern("/viewaction.xhtml")
+ @ViewAction("#{viewActionController.preRenderAction}")
+ VIEW_ACTION,
+
@FacesRedirect
@ViewPattern("/*")
@AccessDeniedView("/denied.xhtml")
diff --git a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyViewAction.java b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyViewAction.java
index 2e97b03..8725143 100644
--- a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyViewAction.java
+++ b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/MyViewAction.java
@@ -12,10 +12,4 @@
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
public @interface MyViewAction {
MyAppViewConfig.Pages value();
-
- //just testing value override
-// public PhaseIdType phase() default PhaseIdType.RENDER_RESPONSE;
-// public Boolean immediate = null;
-// public Boolean onPostback = false;
-// public String condition = null;
}
diff --git a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/PageController.java b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/PageController.java
index 34bdf36..c540cfa 100644
--- a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/PageController.java
+++ b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/PageController.java
@@ -29,6 +29,7 @@
import org.jboss.seam.faces.examples.viewconfig.model.Current;
import org.jboss.seam.faces.examples.viewconfig.model.Item;
import org.jboss.seam.faces.examples.viewconfig.model.ItemDao;
+import org.jboss.seam.faces.view.action.BeforeRenderReponse;
/**
* @author Brian Leathem
@@ -54,12 +55,20 @@ public Item getItem() {
return item;
}
+ @BeforeRenderReponse
+ public void beforeRenderView(@Current Item item) {
+ System.out.println("beforeRenderView called "+item);
+ }
+
+ public void viewAction(@Current Item item) {
+ System.out.println("viewAction "+item);
+ }
+
@MyViewAction(Pages.ITEM)
- public void loadEntry() {
- System.out.println("loadEntry called");
+ public void viewActionBindingType(@Current Item item) {
+ System.out.println("viewActionBindingType "+item);
}
- @MyViewAction(Pages.ITEM)
public void setItem(Item item) {
this.item = item;
}
diff --git a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewActionBindingTypeController.java b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewActionBindingTypeController.java
new file mode 100644
index 0000000..0285282
--- /dev/null
+++ b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewActionBindingTypeController.java
@@ -0,0 +1,18 @@
+package org.jboss.seam.faces.examples.viewconfig;
+
+import javax.enterprise.context.RequestScoped;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+import javax.inject.Named;
+
+import org.jboss.seam.faces.examples.viewconfig.MyAppViewConfig.Pages;
+
+@Named
+@RequestScoped
+public class ViewActionBindingTypeController {
+ @MyViewAction(Pages.VIEW_ACTION_BINDING_TYPE)
+ public void beforeRenderAction() {
+ FacesMessage facesMessages = new FacesMessage("ViewActionBindingTypeController.beforeRenderAction was called");
+ FacesContext.getCurrentInstance().addMessage(null, facesMessages);
+ }
+}
diff --git a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewActionController.java b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewActionController.java
new file mode 100644
index 0000000..0a299a1
--- /dev/null
+++ b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewActionController.java
@@ -0,0 +1,15 @@
+package org.jboss.seam.faces.examples.viewconfig;
+
+import javax.enterprise.context.RequestScoped;
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+import javax.inject.Named;
+
+@Named
+@RequestScoped
+public class ViewActionController {
+ public void preRenderAction() {
+ FacesMessage facesMessages = new FacesMessage("ViewActionController.preRenderAction was called");
+ FacesContext.getCurrentInstance().addMessage(null, facesMessages);
+ }
+}
diff --git a/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewController.java b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewController.java
new file mode 100644
index 0000000..951c922
--- /dev/null
+++ b/examples/viewconfig/src/main/java/org/jboss/seam/faces/examples/viewconfig/ViewController.java
@@ -0,0 +1,71 @@
+package org.jboss.seam.faces.examples.viewconfig;
+
+import javax.faces.application.FacesMessage;
+import javax.faces.context.FacesContext;
+
+import org.jboss.seam.faces.event.qualifier.After;
+import org.jboss.seam.faces.event.qualifier.ApplyRequestValues;
+import org.jboss.seam.faces.event.qualifier.Before;
+import org.jboss.seam.faces.event.qualifier.InvokeApplication;
+import org.jboss.seam.faces.event.qualifier.ProcessValidations;
+import org.jboss.seam.faces.event.qualifier.RenderResponse;
+import org.jboss.seam.faces.event.qualifier.UpdateModelValues;
+import org.jboss.seam.faces.view.action.BeforeRenderReponse;
+
+public class ViewController {
+
+ @Before @ApplyRequestValues
+ public void beforeApplyRequestValues() {
+ addFacesMessage(this.getClass().getSimpleName()+".beforeApplyRequestValues was called");
+ }
+
+ @After @ApplyRequestValues
+ public void afterApplyRequestValues() {
+ addFacesMessage(this.getClass().getSimpleName()+".afterApplyRequestValues was called");
+ }
+
+ @Before @ProcessValidations
+ public void beforeProcessValidations() {
+ addFacesMessage(this.getClass().getSimpleName()+".beforeProcessValidations was called");
+ }
+
+ @After @ProcessValidations
+ public void afterProcessValidations() {
+ addFacesMessage(this.getClass().getSimpleName()+".afterProcessValidations was called");
+ }
+
+ @Before @UpdateModelValues
+ public void beforeUpdateModelValues() {
+ addFacesMessage(this.getClass().getSimpleName()+".beforeUpdateModelValues was called");
+ }
+
+ @After @UpdateModelValues
+ public void afterUpdateModelValues() {
+ addFacesMessage(this.getClass().getSimpleName()+".afterUpdateModelValues was called");
+ }
+
+ @Before @InvokeApplication
+ public void beforeInvokeApplication() {
+ addFacesMessage(this.getClass().getSimpleName()+".beforeInvokeApplication was called");
+ }
+
+ @After @InvokeApplication
+ public void afterInvokeApplication() {
+ addFacesMessage(this.getClass().getSimpleName()+".afterInvokeApplication was called");
+ }
+
+ @BeforeRenderReponse
+ public void beforeRenderResponse() {
+ addFacesMessage(this.getClass().getSimpleName()+".beforeRenderResponse was called");
+ }
+
+ @After @RenderResponse
+ public void afterRenderResponse() {
+ addFacesMessage(this.getClass().getSimpleName()+".RenderResponse was called");
+ }
+
+ private void addFacesMessage(String message) {
+ FacesMessage facesMessages = new FacesMessage(message);
+ FacesContext.getCurrentInstance().addMessage(null, facesMessages);
+ }
+}
diff --git a/examples/viewconfig/src/main/webapp/index.xhtml b/examples/viewconfig/src/main/webapp/index.xhtml
index 7407433..8bc57ac 100644
--- a/examples/viewconfig/src/main/webapp/index.xhtml
+++ b/examples/viewconfig/src/main/webapp/index.xhtml
@@ -22,6 +22,20 @@
+
This example demonstrates shows View Actions in action