You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@tapestry.apache.org by Joshua Long <lh...@adelphia.net> on 2005/03/05 12:41:09 UTC

CSV Renderer Link thingy.. CSV Component donation...

Hi guys

I am donating a CSV component if anyone wants it... when used, it allows
you to render a link that when clicked will return a CSV
(comma-seperated value) dump of a 2 dimensional array that you pass in. 

Interesting sidebar: csv dumps whose first row, and first cell, contain
'ID' (without quotes, in capital letters) will cause Excel on OS X to
freak out and die. 'Id','id',  all work fine.. 

ANYWAY! 

I'll post it somewhere like Tacos eventually,but I'm sure it might stand
some improvement/feedback and I'm somewhat pressed for time.


I'm licensing it under the do-whatever-you-want-with-it-but-remember
your-old-pal-Josh-when-you-win-the-lottery-or-make-cool-changes-to-it
license.


Joshua Long 
josh@joshlong.com 




Code, documentation follow




to get it working int he application, of course, put the following in
the application specification 

    <service name="com.roartechnologies.ap.view.services.csv-service"
class="com.roartechnologies.ap.view.services.CSVService"/>


Anyway, here are the various cogs of the machine... 


/// first the component class.... 

package com.roartechnologies.ap.view.components.csv;

import com.roartechnologies.ap.view.services.CSVService;
import org.apache.tapestry.AbstractComponent;
import org.apache.tapestry.IMarkupWriter;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.Tapestry;
import org.apache.tapestry.engine.IEngineService;
import org.apache.tapestry.engine.ILink;


 /**
  * @author Joshua Long (josh@joshlong.com)
  *
  * Builds a request to our CSVService, which in turn
  * does the heavy lifting of generating
  * the actual dump.
  *
  * This follows a pretty standard idiom 
  * as set forth in <i>Tapestry In Action</i>
  *     
  */
public abstract class CSVComponent extends AbstractComponent {

    public abstract Object getMap();

    public abstract void setMap(Object mp);

    public abstract Boolean getDisabled();

    public abstract void setDisabled(Boolean mp);


    protected void renderComponent(IMarkupWriter writer,
                                   IRequestCycle cycle) {

        if (cycle.isRewinding())
            return;

        Boolean disabled = getDisabled();
        if (disabled != null) {
            if (disabled.booleanValue()) {
                writer.begin("span");
                writer.attribute("class", "csv_disabled");
                renderInformalParameters(writer, cycle);
                writer.printRaw("CSV");
                 writer.end();
                return ;
            }
        }

        Object map = getMap();
        if (null == map)
            Tapestry.createRequiredParameterException(this, "map");


        String key = Long.toString(System.currentTimeMillis());
        cycle.getRequestContext().getSession().setAttribute(key, map);
        IEngineService service =
cycle.getEngine().getService(CSVService.SERVICE_NAME);
        ILink link = service.getLink(cycle, this, new Object[]{key});
        String url = link.getURL();
        writer.begin("a");
        writer.attribute("class", "csv_enabled");
        writer.attribute("href", url);
        renderInformalParameters(writer, cycle);
        writer.printRaw("CSV");

        writer.end();

    }
}











// next the backend service

package com.roartechnologies.ap.view.services;

import com.generationjava.io.CsvWriter;
import org.apache.tapestry.IComponent;
import org.apache.tapestry.IRequestCycle;
import org.apache.tapestry.engine.AbstractService;
import org.apache.tapestry.engine.IEngineServiceView;
import org.apache.tapestry.engine.ILink;
import org.apache.tapestry.request.RequestContext;
import org.apache.tapestry.request.ResponseOutputStream;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.MessageFormat;
import java.util.Date;


/**
 * @author Joshua Long (josh@joshlong.com)
 *         <p/>
 *         The service takes the key passed in from
 *         the component and uses it to lookup the dump
 *         in a known place and then it generates the actual dump.
 *         <p/>
 *         This component uses the <i>Generation Java CSV </i>
 *         component to generate the CSV response stream.
 *         <p/>
 *         I am not too sure where to find it,
 *         but it's worked wonders for me and I completely recommend it.
 */
public class CSVService extends AbstractService {

    public static final String SERVICE_NAME =
            "com.roartechnologies.ap.view.services.csv-service";


    public String getName() {
        return SERVICE_NAME;
    }


    public void service(IEngineServiceView service_view,
                        IRequestCycle cycle,
                        ResponseOutputStream os) throws
ServletException, IOException {
        Object[] params = getParameters(cycle);
        String key = (String) params[0];
        HttpSession session = cycle.getRequestContext().getSession();
        Object mp = session.getAttribute(key);
        if (null == mp) {
            System.out.println(MessageFormat.format("There is no key
with value {0} exiting @ {1,date,long}", new Object[]{key, new
Date()}));
        }
        Object[][] rows_array = (Object[][]) mp;
        RequestContext context = cycle.getRequestContext();
        HttpServletResponse response = context.getResponse();
        String dispositionHeader =
MessageFormat.format("attachment;filename=report_{0}.csv",
                                                        new
Object[]{Long.toString(System.currentTimeMillis())});
        response.setHeader("Content-Disposition", dispositionHeader);
        os.setContentType("application/vnd.ms-excel");
        /* "text/comma-separated-values");*/
        CsvWriter csv_writer = new CsvWriter(new
OutputStreamWriter(os));
        for (int i = 0; i < rows_array.length; i++) {
            Object row [] = rows_array[i];
            String[] string_row = new String[row.length];
            for (int a = 0; a < row.length; a++) {
                string_row[a] = row[a] == null ? "" : row[a].toString();
            }
            csv_writer.writeLine(string_row);
        }
        csv_writer.close();
    }

    public ILink getLink(IRequestCycle iRequestCycle, IComponent
iComponent, Object[] objects) {
        return constructLink(iRequestCycle, SERVICE_NAME, null, objects,
false);
    }
}



















/// now, finally, the specification.. 


<!DOCTYPE component-specification PUBLIC
  "-//Apache Software Foundation//Tapestry Specification 3.0//EN"
  "http://jakarta.apache.org/tapestry/dtd/Tapestry_3_0.dtd">

<component-specification
    class="com.roartechnologies.ap.view.components.csv.CSVComponent"
    allow-body="yes"
    allow-informal-parameters="yes">

    <parameter name="map"
        direction="in"
        required="yes"
        type="java.lang.Object"/>
    <parameter name="disabled"
        direction="in"
        required="no"
        type="java.lang.Boolean"/>

    <reserved-parameter name="href"/>
</component-specification>


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: Query on update within form

Posted by Nick Westgate <ni...@key-planning.co.jp>.
I had a similar situation with floors, rooms & beds of a rest home.
Floors and beds are drop-downs. This is how I did my initialisation:
(All the setX() functions are for persistent properties)

public abstract class BedsView extends BedControlPage implements
   PageRenderListener
{
   // ...

   public void pageBeginRender(PageEvent event)
   {
     // initialize properties etc
     if (!event.getRequestCycle().isRewinding())
     {
       // ...
       if (getFloorSelectionModel() == null)
       {
         // this model is created only once
         ArrayList floorList = getBedCache().getFloorStringList();
         floorList.add(0, getMessage("selectAllString"));
         setFloorSelectionModel(new FloorSelectionModel(floorList));
         setFloor(getFloorSelectionModel().getValue(0));
         setPreviousFloor(getFloor());

         if (getRoomSelectionModel() == null)
         {
           setRoomSelectionModel(getNewRoomSelectionModel());
           setRoom(getRoomSelectionModel().getValue(0));
         }
       }
       // ...

Cheers,
Nick.


Derick Fernando wrote:
> Quoting sales <sa...@digiatlas.net>:
> 
> 
>>Anybody?
>>
>>
>>sales wrote:
>>
>>>My question is, where is it best to initialise things? Each list gets
>>>initialised in the model when the models are realised. However, I also
>>>need a way to initialise the page variables (county needs to be
>>>initialised to a real county ID value, not 0, in order for Place to be
>>>populated correctly from the database).
> 
> 
> Hi,
> 
> Check the wiki for lazy initialization and the pageBeginRender method. You
> should implement the PageRenderListener and lazy initialize your variables
> there.
> 
> ........................
> Derick Fernando
> Lead Architect
> TheLab, LLC
> http://www.thelabllc.com
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> 
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: Query on update within form

Posted by Derick Fernando <de...@thelabllc.com>.
Quoting sales <sa...@digiatlas.net>:

> Anybody?
>
>
> sales wrote:
> >
> >
> > I have a form with two drop-downs. The second of these (Place) gives a
> > list of place names which depend on the first drop-down (County).  I
> > have county submit the form when the user selects something so that
> > Place gets populated with a new list of places.
> >
> > My question is, where is it best to initialise things? Each list gets
> > initialised in the model when the models are realised. However, I also
> > need a way to initialise the page variables (county needs to be
> > initialised to a real county ID value, not 0, in order for Place to be
> > populated correctly from the database).
> >
> > I have put the following for my accessors for the models:
> >
> >
> >     public IPropertySelectionModel getPlaceModel()
> >     {
> >         if (placeModel == null)
> >         {
> >             placeModel = new PlaceModel();
> >         }
> >
> >         return placeModel;
> >     }
> >
> >
> >     public IPropertySelectionModel getCountyModel()
> >     {
> >         if (countyModel == null)
> >         {
> >             countyModel = new CountyModel();
> >             setCounty(((Integer)countyModel.getOption(0)).intValue());
> >         }
> >
> >         return countyModel;
> >     }
> >
> >
> > My callback to handle the form asks the Place model to re-fetch its data.
> >
> > But I'm not sure I'm really going about this the right way. It also
> > won't work unless I make the page properties, County and Place,
> > persistent. Obviously I only want to initialise County when the page is
> > first displayed to the user - subsequent submits and redisplays should
> > leave County as-is.
> >
> > dd
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> > For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> >
> >
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
>
>

Hi,

Check the wiki for lazy initialization and the pageBeginRender method. You
should implement the PageRenderListener and lazy initialize your variables
there.

........................
Derick Fernando
Lead Architect
TheLab, LLC
http://www.thelabllc.com

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Re: Query on update within form

Posted by sales <sa...@digiatlas.net>.
Anybody?


sales wrote:
> 
> 
> I have a form with two drop-downs. The second of these (Place) gives a 
> list of place names which depend on the first drop-down (County).  I 
> have county submit the form when the user selects something so that 
> Place gets populated with a new list of places.
> 
> My question is, where is it best to initialise things? Each list gets 
> initialised in the model when the models are realised. However, I also 
> need a way to initialise the page variables (county needs to be 
> initialised to a real county ID value, not 0, in order for Place to be 
> populated correctly from the database).
> 
> I have put the following for my accessors for the models:
> 
> 
>     public IPropertySelectionModel getPlaceModel()
>     {
>         if (placeModel == null)
>         {
>             placeModel = new PlaceModel();
>         }
> 
>         return placeModel;
>     }
> 
> 
>     public IPropertySelectionModel getCountyModel()
>     {
>         if (countyModel == null)
>         {
>             countyModel = new CountyModel();
>             setCounty(((Integer)countyModel.getOption(0)).intValue());
>         }
> 
>         return countyModel;
>     }
> 
> 
> My callback to handle the form asks the Place model to re-fetch its data.
> 
> But I'm not sure I'm really going about this the right way. It also 
> won't work unless I make the page properties, County and Place, 
> persistent. Obviously I only want to initialise County when the page is 
> first displayed to the user - subsequent submits and redisplays should 
> leave County as-is.
> 
> dd
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tapestry-user-help@jakarta.apache.org
> 
> 

---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org


Query on update within form

Posted by sales <sa...@digiatlas.net>.

I have a form with two drop-downs. The second of these (Place) gives a 
list of place names which depend on the first drop-down (County).  I 
have county submit the form when the user selects something so that 
Place gets populated with a new list of places.

My question is, where is it best to initialise things? Each list gets 
initialised in the model when the models are realised. However, I also 
need a way to initialise the page variables (county needs to be 
initialised to a real county ID value, not 0, in order for Place to be 
populated correctly from the database).

I have put the following for my accessors for the models:


     public IPropertySelectionModel getPlaceModel()
     {
         if (placeModel == null)
         {
             placeModel = new PlaceModel();
         }

         return placeModel;
     }


     public IPropertySelectionModel getCountyModel()
     {
         if (countyModel == null)
         {
             countyModel = new CountyModel();
             setCounty(((Integer)countyModel.getOption(0)).intValue());
         }

         return countyModel;
     }


My callback to handle the form asks the Place model to re-fetch its data.

But I'm not sure I'm really going about this the right way. It also 
won't work unless I make the page properties, County and Place, 
persistent. Obviously I only want to initialise County when the page is 
first displayed to the user - subsequent submits and redisplays should 
leave County as-is.

dd


---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-user-help@jakarta.apache.org