You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@myfaces.apache.org by mjovanov <mi...@jpmchase.com> on 2008/06/16 21:50:35 UTC

Weird Lifecycle Behavior - help please!!! (code included)

One my page I have two drop-down menus and a data table. When selecting an
option from either drop-down, the page is refreshed to display a different
report. There is also a link to export data to Excel. The problem is that
after clicking on the Export to Excel link and getting the File Download
popup, every subsequent action results in the same File Download popup
appearing again. 

I have created a small mock up example and am including the code bellow; can
someone please help?!  What am I doing wrong?


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:c="http://java.sun.com/jstl/core"
	xmlns:t="http://myfaces.apache.org/tomahawk">

<ui:composition template="/WEB-INF/layout/layout.xhtml">
	<ui:define name="title">Export Issue Demo</ui:define>
	<ui:define name="content">
		<t:saveState id="form1" value="#{backingBean}" />
		<h:form id="backingBean">
			<table cellspacing="0" cellpadding="0" width="100%" border="1">
				<tbody>
					<tr>
						<td class="cellWorkbenchDisplay" width="30%">
						<table cellspacing="0" cellpadding="0" width="100%">
							<tbody>
								<tr>
									<td class="cellDataHeader" colspan="2"><h:outputText value="Option
1"/>
									</td>
								</tr>
								<tr>
									<td class="cellWorkBenchItem">
									  <h:selectOneMenu
										value="#{backingBean.option1}" id="selOpt1" required="false"
										styleClass="selQueueOptions"
										onchange="dropdownValueChanged('backingBean',
'option1ValueChangedButton');">
										<f:selectItems value="#{backingBean.option1Map}" />
									</h:selectOneMenu></td>
								</tr>
							</tbody>
						</table>
						</td>
						<td></td>
						<td class="cellWorkbenchDisplay">
						<table cellspacing="0" cellpadding="0" width="100%">
							<tbody>
								<tr>
									<td class="cellDataHeader" colspan="2">Option 2</td>
								</tr>
								<tr>
									<td class="cellWorkBenchItem"><h:selectOneMenu
										value="#{backingBean.option2}" id="selOpt2"
										required="false" styleClass="selQueueOptions"
										onchange="dropdownValueChanged('backingBean',
'option2ValueChangedButton');">
										<f:selectItems value="#{backingBean.option2Map}" />
									</h:selectOneMenu></td>
								</tr>
							</tbody>
						</table>
						</td>
					</tr>
				</tbody>
			</table>
			<br />
			<t:buffer into="#{table}">
				<t:dataTable id="reportDetails"
					styleClass="recordSetTable"
					headerClass="resultSetTableHeader"
					rowClasses="cellDataAltRow,cellDataFirstRow"
					renderedIfEmpty="false"
					var="row" 
					preserveDataModel="false"
					binding="#{backingBean.data}"
					value="#{backingBean.rows}"
					rows="25"
					sortColumn="#{backingBean.sortColumn}"
					sortAscending="#{backingBean.sortAscending}"
					preserveSort="true" >
					<t:columns styleClass="resultSetTableCells" id="columns"
value="#{backingBean.columns}" var="column"  >
						<f:facet name="header">
							<t:commandSortHeader columnName="#{column}" arrow="true"
actionListener="#{backingBean.actionListener}" immediate="true"
styleClass="cellDataHeader">
								<h:outputText value="#{column}" />
							</t:commandSortHeader>
						</f:facet>
						<h:outputText value="#{backingBean.columnValue}" />
					</t:columns>
				</t:dataTable>
			</t:buffer>
			<t:buffer into="#{emptyTable}">
				<table class="recordSetTable">
					<tr>
						<td class="cellDataFirstRow">No data found.</td>
					</tr>
				</table>
			</t:buffer>
			<t:buffer into="#{tableOptions}">
				<h:panelGrid columns="2" cellspacing="0" cellpadding="0" width="100%">
					<h:commandLink class="linkDataDisplay" immediate="true"
action="#{backingBean.reset}" value="Reset" />

					<h:commandLink action="#{backingBean.exportHtmlTableToExcel}"
class="linkCaption">
						<t:graphicImage url="images/icon_excel.gif"
							alt="Export to Excel" width="21" height="16" />
						<h:outputText value="Export to Excel" />
					</h:commandLink>
				</h:panelGrid>
			</t:buffer>
			<div class="tableOptions">
			<h:outputText value="#{tableOptions}" escape="false"
rendered="#{backingBean.dataFound}" />
			</div>

			<h:outputText value="#{table}" escape="false"
rendered="#{backingBean.dataFound}" />
			<h:outputText value="#{emptyTable}" escape="false"
rendered="#{!backingBean.dataFound and !backingBean.workbenchReset}" />
			
			<!-- Hidden buttons -->
			<h:commandButton id="option1ValueChangedButton" type="submit"
				action="#{backingBean.option1ValueChanged}"
				style="visibility:hidden;" />
			<h:commandButton id="option2ValueChangedButton" type="submit"
				action="#{backingBean.option2ValueChanged}"
				style="visibility:hidden;" />
		</h:form>
	</ui:define>
</ui:composition>
</html>

BackingBean.java:

import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;

import javax.faces.component.UIData;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.servlet.http.HttpServletResponse;

public class BackingBean implements Serializable {

    private static final long serialVersionUID = 472335795756643L;

    private static final boolean DEFAULT_SORTASCENDING = true;

    private static final int SORT_ASCENDING = 1;

    private static final int SORT_DESCENDING = -1;

    private Map<String, Long> option1Map;

    private Map<String, Long> option2Map;

    private Long option1 = null;

    private Long option2 = null;

    /**
     * Need a reference to dataTable UIData
     * component to be able to reset it by
     * calling data.setFirst(0)
     */
    private transient UIData data;

    private transient DataModel rows;

    private transient DataModel columns;

    private transient String sortColumn;

    private boolean sortAscending = DEFAULT_SORTASCENDING;

    private transient boolean sortChanged = false;

    public BackingBean() throws Exception {

        super();
        option1Map = new LinkedHashMap<String, Long>();
        option2Map = new LinkedHashMap<String, Long>();
        for (int i = 1; i < 9; i++) {
            option1Map.put("Report #" + i, new Long(i));
            option2Map.put("Summary #" + i, new Long(i));
        }
        columns = new ListDataModel(Arrays.asList(new Object[] { new
String("ID"),
                new String("Name"), new String("Type"), new
String("Description"),
                new String("Notes") }));
        List<List> rowData = new ArrayList<List>();
        rowData.add(Arrays.asList(new Object[] { new Long(1), new
String("Sam"),
                new String("Person"), new String("Something..."), new
String("") }));
        rowData.add(Arrays.asList(new Object[] { new Long(2), new
String("Nikole"),
                new String("Person"), new String("Something..."), new
String("") }));
        rowData.add(Arrays.asList(new Object[] { new Long(3), new
String("Andrea"),
                new String("Person"), new String("Something..."), new
String("") }));
        rowData.add(Arrays.asList(new Object[] { new Long(4), new
String("Lisa"),
                new String("Person"), new String("Ecuador"), new
String("Really HOT!!!") }));
        rows = new ListDataModel(rowData);
    }

    /**
     * Responds to a queue drop-down selection event.
     * @param event A queue drop-down selection event.
     */
    public void option1ValueChanged() {

        if (getOption1() != null && getOption1().longValue() > 0) {
            //
        }
        else {
            resetTable();
        }

        setSortColumn(null);
        setOption2(null);

        // Set the component back to page 1
        data.setFirst(0);
    }

    /**
     * Responds to a summary drop-down selection event.
     * @param event A summary drop-down selection event.
     */
    public void option2ValueChanged() {

        if (getOption2() != null && getOption2().longValue() > 0) {
            //
        }
        else {
            resetTable();
        }

        setSortColumn(null);
        setOption1(null);
        // Set the component back to page 1
        data.setFirst(0);
    }

    private void resetTable() {

        rows.setWrappedData(null);
        columns.setWrappedData(null);
    }

    public void actionListener(final ActionEvent event) {

        // Set a flag to indicate that a user requested data to be resorted
        sortChanged = !sortChanged;
        // Set the component back to page 1
        data.setFirst(0);
    }

    public Object getColumnValue() {

        Object columnValue = null;
        if (rows.isRowAvailable() && columns.isRowAvailable()) {

            columnValue = ((List)
rows.getRowData()).get(columns.getRowIndex());
        }
        if (columnValue instanceof Date) {
            return new SimpleDateFormat("MM/dd/yyyy").format(columnValue);
        }
        return columnValue;
    }

    public boolean isDataFound() {

        if (rows.getRowCount() > 0) {
            return true;
        }
        return false;
    }

    /**
     * Only show the welcome message when no data is being displayed.
     * @return True is neither queue or summary is selected.
     */
    public boolean isReset() {

        if ((option1 == null || option1.equals("")) && (option2 == null ||
option2.equals(""))) {
            return true;
        }
        return false;
    }

    public DataModel getRows() {

        sort();
        return rows;

    }

    private void sort() {

        if (sortChanged) {
            if (option1 != null || option2 != null) {
                List tableData = (List) rows.getWrappedData();
                final int sortColumnIndex = getSortColumnIndex();
                final int direction = (isSortAscending() ? SORT_ASCENDING :
SORT_DESCENDING);
                java.util.Collections.sort(tableData, new Comparator() {

                    public int compare(Object o1, Object o2) {

                        int result = 0;
                        List row1 = (List) o1;
                        List row2 = (List) o2;
                        Object col1 = row1.get(sortColumnIndex);
                        Object col2 = row2.get(sortColumnIndex);
                        if (col1 == null && col2 == null) {
                            result = 0;
                        }
                        else if (col1 != null && col2 == null) {
                            result = 1;
                        }
                        else if (col1 == null && col2 != null) {
                            result = -1;
                        }
                        else {
                            /*
                             * If column type implements Comparable
interface, use its compareTo() method
                             */
                            if (col1 instanceof Comparable && col2
instanceof Comparable) {
                                /*
                                 * If String type, ignore case in
comparisons
                                 */
                                if (col1.getClass() == String.class
                                        && col2.getClass() == String.class)
{
                                    result = ((String)
col1).compareToIgnoreCase((String) col2);
                                }
                                else {
                                    result = ((Comparable)
col1).compareTo(col2);
                                }
                            }
                            else {
                                /*
                                 * Column type does not implement
Comparable: 
                                 * convert it to String for sorting purposes
                                 */
                                result =
col1.toString().compareTo(col2.toString());
                            }
                        }
                        return result * direction;
                    }
                });
                synchronized (this) {
                    rows.setWrappedData(tableData);
                }
            }
            else {
                throw new RuntimeException("No options selected - something
went horribly wrong!");
            }
        }
    }

    /**
     * @return Index of the column to perform the sort on, -1 columns
     * are null, sort column has not been set, or no match found.
     */
    private int getSortColumnIndex() {

        if (getColumns() != null && getSortColumn() != null &&
getSortColumn().length() > 0) {
            int i = 0;
            for (Iterator<String> it = ((List<String>)
columns.getWrappedData()).iterator(); it
                    .hasNext();) {
                String column = it.next();
                if (column.equals(getSortColumn())) {
                    return i;
                }
                i++;
            }
        }
        return -1;

    }

    private void readObject(ObjectInputStream aInputStream) throws
ClassNotFoundException,
            IOException {

        //always perform the default deserialization first
        aInputStream.defaultReadObject();
        rows = new ListDataModel();
        rows.setWrappedData(aInputStream.readObject());
        columns = new ListDataModel();
        columns.setWrappedData(aInputStream.readObject());
    }

    private void writeObject(ObjectOutputStream aOutputStream) throws
IOException {

        //perform the default serialization for all non-transient,
non-static fields
        aOutputStream.defaultWriteObject();
        aOutputStream.writeObject(rows.getWrappedData());
        aOutputStream.writeObject(columns.getWrappedData());
    }

    /**
     * Exports the Queue/Summary HTML table to Excel.
     * @throws IOException IOException
     */
    public void exportHtmlTableToExcel() throws IOException {

        // Setup the output
        String contentType = "application/vnd.ms-excel"
        FacesContext fc = FacesContext.getCurrentInstance();
        String filename =
fc.getExternalContext().getUserPrincipal().getName() + "-"
                + System.currentTimeMillis() + ".xls"
        HttpServletResponse response = (HttpServletResponse)
fc.getExternalContext().getResponse();
        response.setHeader("Content-disposition", "attachment; filename=" +
filename);
        response.setContentType(contentType);

        StringBuffer htmlBuffer = new StringBuffer();

        // Write the table back out
        PrintWriter out = response.getWriter();
        htmlBuffer.append("<HTML>\n");
        htmlBuffer.append("Exported " + new Date() + "<BR>\n");

        // Write Queue/Summary column headings
        htmlBuffer.append("<TABLE border=\"0\">\n");
        htmlBuffer.append("    <TR>\n");
        List<String> columnList = (List<String>) columns.getWrappedData();
        for (Iterator<String> it = columnList.iterator(); it.hasNext();) {
            htmlBuffer.append("        <TD>" + it.next() + "</TD>");
        }
        htmlBuffer.append("    </TR>\n");

        // Finally, write the Queue/Summary data rows
        List<List> data = (List<List>) rows.getWrappedData();
        for (Iterator<List> i = data.iterator(); i.hasNext();) {
            htmlBuffer.append("    <TR>\n");
            List row = i.next();
            boolean isFirstCol = true;
            for (Iterator j = row.iterator(); j.hasNext();) {
                Object value = j.next();
                /*
                 * The first column in each row is now a flag used to 
                 * indicate entity type (i.e. Case, Event, Subject), 
                 * which should not be displayed; hence we are stripping it.
                 */
                if (isFirstCol) {
                    isFirstCol = false;
                    continue;
                }
                htmlBuffer.append("        <TD>" + (value != null ? value :
"") + "</TD>\n");
            }
            htmlBuffer.append("    </TR>\n");
        }

        htmlBuffer.append("</TABLE>\n");
        htmlBuffer.append("</HTML>\n");
        //System.out.println(htmlBuffer);
        out.print(htmlBuffer);
        out.close();
        fc.responseComplete();
    }

    public String reset() {

       
FacesContext.getCurrentInstance().getExternalContext().getRequestMap()
                .remove("backingBean");
        return "demoPage"
    }

   
/******************************************************************************
     * Getters/Setters bellow
    
******************************************************************************/

    public Long getOption1() {

        return option1;
    }

    public void setOption1(Long option1) {

        this.option1 = option1;
    }

    public Long getOption2() {

        return option2;
    }

    public void setOption2(Long option2) {

        this.option2 = option2;
    }

    public Map<String, Long> getOption1Map() {

        return option1Map;
    }

    public Map<String, Long> getOption2Map() {

        return option2Map;
    }

    public UIData getData() {

        return data;
    }

    public void setData(final UIData data) {

        this.data = data;
    }

    public DataModel getColumns() {

        return columns;
    }

    public void setRows(DataModel rows) {

        this.rows = rows;
        //throw new UnsupportedOperationException("setRows");
    }

    public void setColumns(DataModel columns) {

        this.columns = columns;
    }

    public boolean isSortAscending() {

        return sortAscending;
    }

    public void setSortAscending(boolean sortAscending) {

        this.sortAscending = sortAscending;
    }

    public String getSortColumn() {

        return sortColumn;
    }

    public void setSortColumn(String sortColumn) {

        this.sortColumn = sortColumn;
    }

}

faces-config.xml:

	<managed-bean>
		<managed-bean-name>backingBean</managed-bean-name>
		<managed-bean-class>
			halo.webapp.action.BackingBean
		</managed-bean-class>
		<managed-bean-scope>request</managed-bean-scope>
	</managed-bean>
-- 
View this message in context: http://www.nabble.com/Weird-Lifecycle-Behavior---help-please%21%21%21-%28code-included%29-tp17872067p17872067.html
Sent from the MyFaces - Users mailing list archive at Nabble.com.