[ http://issues.apache.org/jira/browse/TAPESTRY-631?page=all ]
     
Howard M. Lewis Ship resolved TAPESTRY-631:
-------------------------------------------

    Resolution: Invalid

The Foreach component is working as designed; it does not handle this case.

Because of this, the For component was created.  Use it instead.  It is "form 
aware" and quite flexible.

> Foreach doesn't render the nested form components when rewind
> -------------------------------------------------------------
>
>          Key: TAPESTRY-631
>          URL: http://issues.apache.org/jira/browse/TAPESTRY-631
>      Project: Tapestry
>         Type: Bug
>   Components: Framework
>     Versions: 4.0
>  Environment: Windows 2000, tomcat, hivemind-1.1-beta3, tapestry-4.0-beta5
>     Reporter: Andrew Love

>
> when rewind, Foreach doesn't render the nested components, the getSource() 
> method always return null, so if there are form compenents in it, and a form 
> components after it, exception will happen.
> the error message is like this:
> Rewind of form admin/productEdit/productForm expected allocated id #5 to be 
> 'Upload', but was 'Submit' (requested by component admin/productEdit/$Submit).
> Here are the code:
> products.html
> <title><span jwcid="@Insert" value="message:userList.title"/></title>
> <content tag="heading"><span key="productList.heading"/></content>
> <!-- Success Messages -->
> <span jwcid="@Conditional" condition="ognl:message != null">
>     <div class="message">
>         <img jwcid="@Any" 
> src="ognl:engine.contextPath+'/images/iconInformation.gif'"
>                 alt="message:icon.information" class="icon" />
>         <span jwcid="@Insert" value="ognl:message" raw="true"/>
>     </div>
> </span>
> <button class="button" onclick="location.href='productEdit.html'"><span 
> key="button.add"/></button>
> <button class="button" onclick="location.href='mainMenu.html'"><span 
> key="button.cancel"/></button>
> <table jwcid="[EMAIL PROTECTED]:Table" class="list productList" 
> id="productList"
>     rowsClass="ognl:beans.evenOdd.next" row="ognl:row" 
>     columns="product.id:id,productName:name, product.price:price, 
> product.description:description" 
>     source="ognl:listPageOfProducts.list" initialSortColumn="name"
>     arrowUpAsset="ognl:assets.upArrow" arrowDownAsset="ognl:assets.downArrow">
>     <span jwcid="[EMAIL PROTECTED]">
>         <a jwcid="@DirectLink" listener="listener:edit" 
> parameters="ognl:row.id">
>             <span jwcid="@Insert" value="ognl:row.name"/>
>         </a>
>     </span>
>     <tr jwcid="[EMAIL PROTECTED]">
>         <a jwcid="@Any" href="ognl:+'mailto:'+row.price">
>             <span jwcid="@Insert" value="ognl:row.price"/>
>         </a>
>     </tr>
> </table>
>       <form jwcid="@Form">
> <input class="button" jwcid="@Submit" value="message:button.add" id="add" 
> listener="ognl:listeners.add" 
>                                                       type="submit" />
> <button class="button" onclick="location.href='mainMenu.html'"><span 
> key="button.cancel"/></button>
> </form>
> <script type="text/javascript">
> highlightTableRows("productList");
> </script>
> products.page
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE page-specification
>       PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN"
>       "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd";>
> <page-specification class="org.myproduct.webapp.action.ProductList">
>     <inject property="productManager" object="spring:productManager" />    
>     
>     <property name="message"/>
>     <property name="row"/>
>     <property name="listPageOfProducts"/>
>     
>     <bean name="evenOdd" class="org.apache.tapestry.bean.EvenOdd"/>
>     <asset name="upArrow" path="/images/arrow_up.png"/>
>     <asset name="downArrow" path="/images/arrow_down.png"/>
> </page-specification>
> ProductList.java
> package org.myproduct.webapp.action;
> import java.util.HashSet;
> import java.util.Set;
> import net.mlw.vlh.ValueList;
> import net.mlw.vlh.ValueListInfo;
> import org.apache.tapestry.IRequestCycle;
> import org.apache.tapestry.event.PageBeginRenderListener;
> import org.apache.tapestry.event.PageEvent;
> import org.myproduct.model.Image;
> import org.myproduct.model.Product;
> import org.myproduct.service.ProductManager;
> public abstract class ProductList extends BasePage implements 
> PageBeginRenderListener {
>     public abstract ProductManager getProductManager();
>     public abstract ValueList getListPageOfProducts();
>     public abstract void setListPageOfProducts(ValueList products);
>     public void pageBeginRender(PageEvent event) {
>         setListPageOfProducts(getProductManager().listPage("productList",new 
> ValueListInfo()));
>     }
>     public void edit(IRequestCycle cycle) { 
>         ProductForm nextPage = (ProductForm) 
> cycle.getPage("admin/productEdit");
>         Product product=findProduct(cycle);
>         initialProduct(product);
>         fetchProduct(cycle,product,nextPage);
>     }
>     
>     public void add(IRequestCycle cycle) {
>         ProductForm nextPage = (ProductForm) 
> cycle.getPage("admin/productEdit");
>         Product product=new Product();
>         initialProduct(product);
>         fetchProduct(cycle,product,nextPage);
>     }
>     
>     public void detail(IRequestCycle cycle) { 
>         ProductForm nextPage = (ProductForm) cycle.getPage("productDetail");
>         Product product=findProduct(cycle);
>         fetchProduct(cycle,product,nextPage);
>     }
>     
>     private void fetchProduct(IRequestCycle cycle,Product product,ProductForm 
> nextPage){
>         nextPage.setProduct(product);
>         cycle.activate(nextPage);
>     }
>     
>     private Product findProduct(IRequestCycle cycle){
>         Object[] parameters = cycle.getListenerParameters();
>         Long id = (Long) parameters[0];
>         Product product = getProductManager().getProduct(id);
>         if (log.isDebugEnabled()) {
>             log.debug("fetching product with id: " + id);
>         }
>         return product;
>     }
>     
>     private void initialProduct(Product product){
>         Set images=product.getImages();
>         if(images==null){
>             images=new HashSet();
>             product.setImages(images);
>         }
>         images.add(new Image());        
>     }
> }
> productEdit.html
> <html>
> <head>
>   <title><span jwcid="@Insert" value="message:product.detail"/></title>
>   <content tag="heading"></content>
> </head>
> <body jwcid="@Body">
>       <!-- Error Messages -->
>       <span jwcid="@Conditional" condition="ognl:beans.delegate.hasErrors">
>               <div class="error">
>                       <img jwcid="@Any" 
>                               
> src="ognl:engine.contextPath+'/images/iconWarning.gif'" 
>                               alt="message:icon.warning" class="icon" />
>                       <span jwcid="@Delegator" 
> delegate="ognl:beans.delegate.firstError" 
>                               raw="true"> Error Message </span>
>               </div>
>       </span>
>       <!-- Success Messages -->
>       <span jwcid="@Conditional" condition="ognl:message != null">
>               <div class="message">
>                       <img jwcid="@Any" 
>                               
> src="ognl:engine.contextPath+'/images/iconInformation.gif'" 
>                               alt="message:icon.information" class="icon" />
>                       <span jwcid="@Insert" value="ognl:message" 
> raw="true"></span>
>               </div>
>       </span>
>       <div class="separator"></div>
>       <form jwcid="[EMAIL PROTECTED]" delegate="ognl:beans.delegate" 
>               id="productForm">
>               <input jwcid="@Hidden" value="ognl:product.id" type="hidden" />
>               <table class="detail" cellpadding="10" cellspacing="10">
>                       <tbody>
>                               <tr>
>                                <td width="45%">
>                                 <table width="100%">
>                                  <tr>
>                                       <th><span jwcid="@Insert" 
> value="message:productName"/></th>
>                                       <td>
>                                               <div>
>                                                       <input 
> jwcid="@TextField" value="ognl:product.name" 
>                                                               type="text" />
>                                               </div>
>                                       </td>
>                                  </tr>
>                               <tr>
>                                       <th><span jwcid="@Insert" 
> value="message:product.price"/></th>
>                                       <td>
>                                               <input jwcid="priceField" 
> size="40" type="text" />
>                                       </td>
>                               </tr>
>                               <tr>
>                                       <th><span jwcid="@Insert" 
> value="message:product.description"/></th>
>                                       <td>
>                                               <input jwcid="@TextField" 
> size="40" 
>                                                       
> value="ognl:product.description" type="text" />
>                                       </td>
>                               </tr>
>                               </table>
>                               </td>
>                                       
>                                       
>                               <td>
>                                       <table>
>                                       <tr jwcid="images">
>                                       <td>
>                                       <img jwcid="productImg" />
>                                       <br />
>                                       <input jwcid="@Upload" 
> file="ognl:image.uploadFile" size="50" 
>                                                       type="file" />
>                                       </td>
>                                       </tr>
>                                       </table>
>                                               
>                                       </td>
>                               </tr>
>                               <tr>
>                                       <td colspan="2">
>                                       
>                                               <input class="button" 
> jwcid="@Submit" 
>                                                       
> value="message:button.save" id="save" 
>                                                       
> listener="ognl:listeners.save" type="submit" />
>                                               <span 
> jwcid="@contrib:FormConditional" 
>                                                       
> condition="ognl:product.name != null">
>                                                       <input class="button" 
> jwcid="@Submit" 
>                                                               
> value="message:button.delete" id="delete" 
>                                                               
> listener="ognl:listeners.delete" 
>                                                               
> onclick="form.onsubmit = null" type="submit" />
>                                                       <!-- Removed confirm 
> since WebTest can't handle it: ;return confirmDelete('User') -->
>                                               </span>
>                                               <input class="button" 
> jwcid="@Submit" 
>                                                       
> value="message:button.cancel" id="cancel" 
>                                                       
> listener="ognl:listeners.cancel" 
>                                                       onclick="form.onsubmit 
> = null" type="submit" />
>                                       </td>                                   
>                               </tr>
>                       </tbody>
>               </table>
>       </form>
>       <script type="text/javascript"> <span jwcid="@Conditional" 
>               condition="ognl:product.name == null"> 
>               document.getElementById("name").focus(); </span> <span 
>               jwcid="@Conditional" condition="ognl:product.price == null"> 
>               document.getElementById("price").focus(); </span> 
>               highlightFormElements(); </script>
> </body>
> </html>
> productEdit.page
> <?xml version="1.0" encoding="UTF-8"?>
> <!DOCTYPE page-specification 
>     PUBLIC "-//Apache Software Foundation//Tapestry Specification 4.0//EN" 
>     "http://jakarta.apache.org/tapestry/dtd/Tapestry_4_0.dtd";> 
>         
> <page-specification class="org.myproduct.webapp.action.ProductForm">
>     <inject property="productManager" object="spring:productManager" />
>         
>     <property name="product"/>
>     <bean name="delegate" class="org.myproduct.webapp.action.Validator"/>
>       <bean name="priceValidator" 
> class="org.apache.tapestry.valid.NumberValidator">
>           <set name="required" value="true"/>
>           <set name="valueType" value="'float'"/>    
>       </bean>
>         <component id="images" type="Foreach">
>           <binding name="source" value="product.images"/>
>           <binding name="value" value="image"/>
>           <binding name="element" value="literal:tr"/>
>         </component>
>     <component id="priceField" type="ValidField">
>         <binding name="value" value="product.price"/>
>         <binding name="validator" value="bean:priceValidator"/>
>         <binding name="displayName" value="product.price"/>
>     </component>
>     <component id="productImg" type="Any">
>         <binding name="src" value="asset:productImage"/>
>     </component>
>       <asset name="productImage" path="ognl:image.url+image.name"/>
> </page-specification>
> package org.myproduct.webapp.action;
> import java.io.File;
> import java.io.FileOutputStream;
> import java.io.IOException;
> import java.io.InputStream;
> import java.io.OutputStream;
> import java.nio.ByteBuffer;
> import java.util.ArrayList;
> import java.util.List;
> import java.util.Set;
> import org.apache.tapestry.IRequestCycle;
> import org.apache.tapestry.event.PageBeginRenderListener;
> import org.apache.tapestry.event.PageEvent;
> import org.apache.tapestry.request.IUploadFile;
> import org.myproduct.Constants;
> import org.myproduct.model.Image;
> import org.myproduct.model.Product;
> import org.myproduct.service.ProductManager;
> public abstract class ProductForm extends BasePage implements 
> PageBeginRenderListener {
>     public abstract ProductManager getProductManager();
>     public abstract void setProduct(Product product);
>     public abstract Product getProduct();
>     public abstract Image getImage();
>     
>     public void pageBeginRender(PageEvent event) {
>         if ((getProduct() == null) && !event.getRequestCycle().isRewinding()) 
> {
>             setProduct(new Product());
>         } else if (event.getRequestCycle().isRewinding()) { // add
>             setProduct(new Product());
>         }
>     }
>     public void cancel(IRequestCycle cycle) {
>         if (log.isDebugEnabled()) {
>             log.debug("Entering 'cancel' method");
>         }
>         cycle.activate("admin/products");
>     }
>     public void delete(IRequestCycle cycle) {
>         if (log.isDebugEnabled()) {
>             log.debug("entered 'delete' method");
>         }
>         getProductManager().removeProduct(getProduct().getId());
>         ProductList nextPage = (ProductList) 
> cycle.getPage(Constants.AdminProductListPage);
>         nextPage.setMessage(getMessage("product.deleted"));
>         cycle.activate(nextPage);
>     }
>     public void save(IRequestCycle cycle) throws IOException {
>         if (getValidationDelegate().getHasErrors()) {
>             return;
>         }
>         boolean isNew = (getProduct().getId() == null);
>         Product product=getProduct();
>         String key = (isNew) ? "product.added" : "product.updated";
>         upload(cycle,product);
>         
>         this.getProductManager().saveProduct(product);
>         if (isNew) {
>             ProductList nextPage = (ProductList) 
> cycle.getPage(Constants.AdminProductListPage);
>             nextPage.setMessage(getMessage(key));
>             cycle.activate(nextPage);
>         } else {
>             ProductForm nextPage = (ProductForm) 
> cycle.getPage(Constants.AdminProductPage);
>             nextPage.setMessage(getMessage(key));
>             cycle.activate(nextPage); // return to current page
>         }
>     }
>     
>     private void upload(IRequestCycle cycle,Product product) throws 
> IOException {
>       
>       Set images=product.getImages();
>       List imagesList=new ArrayList(images);
>         // write the file to the filesystem
>         // the directory to upload to
>         String uploadDir =
>             getServletContext().getRealPath("/img") + "/";
>         // Create the directory if it doesn't exist
>         File dirPath = new File(uploadDir);
>         if (!dirPath.exists()) {
>             dirPath.mkdirs();
>         }
>       for(int i=0;i<imagesList.size();i++){
>               Image image=(Image) imagesList.get(i);                  
>             IUploadFile file = image.getUploadFile();            
>             if (file == null) {
>               if(image.getId()==null){
>                       imagesList.remove(image);
>                       i--;
>               }
>                 continue;
>             }
>             //retrieve the file data
>             InputStream stream = file.getStream();
>             int fileSize=(int)file.getSize();
>             ByteBuffer bbuffer=ByteBuffer.allocate(fileSize);
>             byte[] buffer = new byte[8192];
>             int bytesRead = 0;
>             while ((bytesRead = stream.read(buffer, 0, 8192)) != -1) {
>               bbuffer.put(buffer,0,bytesRead);
>             }
>             stream.close();
>             
>             //first, store the file to database
>             image.setName(file.getFileName());
>             image.setFile(bbuffer.array());
>             image.setUrl(uploadDir);
>             image.setProduct(product);
>             
>             //write the file to the file specified
>             OutputStream bos =
>                 new FileOutputStream(uploadDir + file.getFileName());
>                 bos.write(bbuffer.array(), 0, fileSize);
>             bos.close();
>             //close the stream
>       }       
>     }
> }

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira


---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to