Author: jrthomerson
Date: Tue Mar 24 04:44:20 2009
New Revision: 757661

URL: http://svn.apache.org/viewvc?rev=757661&view=rev
Log:
Added a contribution by Marat Radchenko to help with stateless page development
Issue: WICKET-2170

Added:
    wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/
    
wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessChecker.java
    
wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessComponent.java
    wicket/trunk/wicket/src/test/java/org/apache/wicket/annotations/
    
wicket/trunk/wicket/src/test/java/org/apache/wicket/annotations/StatelessCheckerTest.java

Added: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessChecker.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessChecker.java?rev=757661&view=auto
==============================================================================
--- 
wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessChecker.java
 (added)
+++ 
wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessChecker.java
 Tue Mar 24 04:44:20 2009
@@ -0,0 +1,117 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.annotations;
+
+import org.apache.wicket.Component;
+import org.apache.wicket.MarkupContainer;
+import org.apache.wicket.Page;
+import org.apache.wicket.Component.IVisitor;
+import org.apache.wicket.application.IComponentOnBeforeRenderListener;
+
+/**
+ * Stateless checker. Checks if components with {...@link StatelessComponent} 
annotation are really
+ * stateless. This is a utility that is intended for use primarily during 
development. If you add an
+ * instance of this class to your application, it will check all components or 
pages marked with the
+ * <tt>StatelessComponent</tt> annotation to make sure that they are stateless 
as you intended.
+ * 
+ * This is useful when trying to maintain stateless pages since it is very 
easy to inadvertantly add
+ * a component to a page that internally uses stateful links, etc.
+ * 
+ * @author Marat Radchenko
+ * @see StatelessComponent
+ */
+public class StatelessChecker implements IComponentOnBeforeRenderListener
+{
+       /**
+        * Returns <code>true</code> if checker must check given component, 
<code>false</code>
+        * otherwise.
+        * 
+        * @param component
+        *            component to check.
+        * @return <code>true</code> if checker must check given component.
+        */
+       private static boolean mustCheck(final Component component)
+       {
+               final StatelessComponent ann = 
component.getClass().getAnnotation(StatelessComponent.class);
+               return ann != null && ann.enabled();
+       }
+
+       /**
+        * @see 
org.apache.wicket.application.IComponentOnBeforeRenderListener#onBeforeRender(org.apache.wicket.Component)
+        */
+       public void onBeforeRender(final Component component)
+       {
+               if (StatelessChecker.mustCheck(component))
+               {
+                       final IVisitor<Component> visitor = new 
Component.IVisitor<Component>()
+                       {
+                               public Object component(final Component comp)
+                               {
+                                       if (component instanceof Page && 
StatelessChecker.mustCheck(comp))
+                                       {
+                                               // Do not go deeper, because 
this component will be checked by checker
+                                               // itself.
+                                               // Actually we could go deeper 
but that would mean we traverse it twice
+                                               // (for current component and 
for inspected one).
+                                               // We go deeper for Page 
because full tree will be inspected during
+                                               // isPageStateless call.
+                                               return 
IVisitor.CONTINUE_TRAVERSAL_BUT_DONT_GO_DEEPER;
+                                       }
+                                       else if (!comp.isStateless())
+                                       {
+                                               return comp;
+                                       }
+                                       else
+                                       {
+                                               return 
IVisitor.CONTINUE_TRAVERSAL;
+                                       }
+                               }
+                       };
+
+                       final String msg = "'" + component + "' claims to be 
stateless but isn't.";
+                       if (!component.isStateless())
+                       {
+                               throw new IllegalArgumentException(msg +
+                                       " Possible reasons: no stateless hint, 
statefull behaviors");
+                       }
+
+                       if (component instanceof MarkupContainer)
+                       {
+                               // Traverse children
+                               final Object o = 
((MarkupContainer)component).visitChildren(visitor);
+                               if (o == null)
+                               {
+                                       throw new IllegalArgumentException(msg 
+ " Offending component: " + o);
+                               }
+                       }
+
+                       if (component instanceof Page)
+                       {
+                               final Page p = (Page)component;
+                               if (!p.isBookmarkable())
+                               {
+                                       throw new IllegalArgumentException(msg +
+                                               " Only bookmarkable pages can 
be stateless");
+                               }
+                               if (!p.isPageStateless())
+                               {
+                                       throw new IllegalArgumentException(msg 
+ " for unknown reason");
+                               }
+                       }
+               }
+       }
+}

Added: 
wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessComponent.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessComponent.java?rev=757661&view=auto
==============================================================================
--- 
wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessComponent.java
 (added)
+++ 
wicket/trunk/wicket/src/main/java/org/apache/wicket/annotations/StatelessComponent.java
 Tue Mar 24 04:44:20 2009
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.annotations;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation for wicket components that you want to be sure remain stateless 
during the development
+ * cycle. Can be attached to pages and components.
+ * 
+ * <b>Note:</b> this annotation <u><i>does not</i></u> make the component 
stateless or affect it's
+ * statelessness in any way. This annotation should be used in combination with
+ * <tt>StatelessChecker</tt> to give you runtime warning if you inadvertantly 
made a page or
+ * component stateful.
+ * 
+ * @author Marat Radchenko
+ * @see StatelessChecker
+ */
+...@documented
+...@retention(RetentionPolicy.RUNTIME)
+...@target(ElementType.TYPE)
+...@inherited
+public @interface StatelessComponent {
+
+       /**
+        * Can be set to <code>false</code> to disable stateless (this is 
useful if stateful component
+        * inherits from stateless one).
+        */
+       boolean enabled() default true;
+}

Added: 
wicket/trunk/wicket/src/test/java/org/apache/wicket/annotations/StatelessCheckerTest.java
URL: 
http://svn.apache.org/viewvc/wicket/trunk/wicket/src/test/java/org/apache/wicket/annotations/StatelessCheckerTest.java?rev=757661&view=auto
==============================================================================
--- 
wicket/trunk/wicket/src/test/java/org/apache/wicket/annotations/StatelessCheckerTest.java
 (added)
+++ 
wicket/trunk/wicket/src/test/java/org/apache/wicket/annotations/StatelessCheckerTest.java
 Tue Mar 24 04:44:20 2009
@@ -0,0 +1,99 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.wicket.annotations;
+
+import junit.framework.TestCase;
+
+import org.apache.wicket.markup.html.basic.Label;
+import org.apache.wicket.util.tester.DummyHomePage;
+import org.apache.wicket.util.tester.WicketTester;
+
+/**
+ * @author Marat Radchenko
+ */
+public class StatelessCheckerTest extends TestCase
+{
+       /**
+        * 
+        */
+       @StatelessComponent
+       public static class StatelessPage extends DummyHomePage
+       {
+       }
+
+       /**
+        * 
+        */
+       @StatelessComponent
+       private static class StatelessLabel extends Label
+       {
+               private static final long serialVersionUID = 1L;
+
+               public StatelessLabel(final String id)
+               {
+                       super(id);
+               }
+       }
+
+       private final StatelessChecker checker = new StatelessChecker();
+       private WicketTester tester;
+
+       /**
+        * @see junit.framework.TestCase#setUp()
+        */
+       @Override
+       public void setUp()
+       {
+               tester = new WicketTester();
+       }
+
+       /**
+        * @see junit.framework.TestCase#tearDown()
+        */
+       @Override
+       public void tearDown()
+       {
+               tester.destroy();
+       }
+
+       /**
+        * 
+        */
+       public void testNonBookmarkablePage()
+       {
+               boolean hit = false;
+               try
+               {
+                       
tester.getApplication().addPostComponentOnBeforeRenderListener(checker);
+                       tester.startPage(StatelessPage.class);
+               }
+               catch (IllegalArgumentException ex)
+               {
+                       hit = true;
+               }
+               assertTrue("Expected exception", hit);
+       }
+
+       /**
+        * 
+        */
+       public void testPositive()
+       {
+               
tester.getApplication().addPostComponentOnBeforeRenderListener(checker);
+               tester.startComponent(new StatelessLabel("foo"));
+       }
+}


Reply via email to