1

How do I send the current javax.mail.Message which the ListDataTable is on for the particular row back to the backing bean in order to get some header information for that specific Message instance? I think the problem is that this is from within the client dataTable.

How do I make getUrl available to the ListDataTable?

I've tried:

<h:outputText value="#{messageBean.foo(m.header("Archived-at"))}"></h:outputText>

which returns an error of:

Element type "h:outputText" must be followed by either attribute specifications, ">" or "/>".

I think it's something along the lines of a command link, which suggests a syntax of:

<h:commandLink action="#{bean.insert(item.id)}" value="insert" />

Which is near to what I'm doing. In my case, I just want to send the specific message back to MessageBean.getUrl(Message) yet that doesn't work as I expect.

I've also tried:

/foo/client.xhtml @48,61 value="#{messageBean.url(m)}": Method url not found

So that's clearly not the correct way to send an object from the template client to the backing bean. However, that's the approach which I would like, to send the actual Message instance back to the bean.

the facelets 2.0 client:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<ui:composition xmlns:ui="http://java.sun.com/jsf/facelets"
                template="./template.xhtml"
                xmlns:h="http://java.sun.com/jsf/html"
                xmlns:c="http://java.sun.com/jsp/jstl/core"
                xmlns:f="http://java.sun.com/jsf/core">
    <ui:define name="content">
        <h:dataTable value="#{messageBean.model}" var="m">
            <h:column>
                <f:facet name="subject">
                    <h:outputText value="subject" />
                </f:facet>
                <h:outputText value="#{m.subject}"></h:outputText>
            </h:column>
            <h:column>
                <f:facet name="content">
                    <h:outputText value="content" />
                </f:facet>
                <h:outputText value="#{m.sentDate}"></h:outputText>
            </h:column>
            <h:column>
                <f:facet name="date">
                    <h:outputText value="date" />
                </f:facet>
                <h:outputText value="#{m.sentDate}"></h:outputText>
            </h:column>
        </h:dataTable>
    </ui:define>
</ui:composition>

the backing bean:

package net.bounceme.dur.nntp;

import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.enterprise.context.SessionScoped;
import javax.faces.model.DataModel;
import javax.faces.model.ListDataModel;
import javax.inject.Named;
import javax.mail.Header;
import javax.mail.Message;

@Named
@SessionScoped
public class MessageBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger logger = Logger.getLogger(MessageBean.class.getName());
    private static Level level = Level.INFO;

    public MessageBean() {
        logger.log(level, "MessageBean..");
    }

    public DataModel getModel() throws Exception {
        logger.log(level, "MessageBean.getModel..");
        List<Message> messages = new ArrayList<Message>();
        SingletonNNTP nntp = SingletonNNTP.INSTANCE;
        messages = nntp.getMessages();
        DataModel messagesDataModel = new ListDataModel(messages);
        return messagesDataModel;
    }

    public List<String> getStringHeaders(Message message) throws Exception {
        List<Header> headerListOfHeaders = getHeaders(message);
        List<String> stringListOfHeaders = new ArrayList<String>();
        for (Header h : headerListOfHeaders) {
            stringListOfHeaders.add(h.getName() + " " + h.getValue() + "\n");
        }
        return stringListOfHeaders;
    }

    public URL getUrl(Message message) throws Exception {
        List<Header> headers = getHeaders(message);
        URL url = new URL("http://www.google.com/");
        for (Header h : headers) {
            if ("Archived-at".equals(h.getName())) {
                String s = h.getValue();
                s = s.substring(1, s.length() - 1);
                url = new URL(s);
            }
        }
        return url;
    }

    private List<Header> getHeaders(Message message) throws Exception {
            Enumeration allHeaders = message.getAllHeaders();
            List<Header> headers = new ArrayList<Header>();
            while (allHeaders.hasMoreElements()) {
                Header hdr = (Header) allHeaders.nextElement();
                headers.add(hdr);
            }
            return headers;
        }
}

I would like to keep getUrl with MessageBean, but am willing to break that method out to another class. However, which class, and how to reference it? just something like MyBeanOps or something?

Community
  • 1
  • 1
Thufir
  • 8,216
  • 28
  • 125
  • 273
  • You are not using JSP or Servlets. You are using JSF with Facelets. Please don't put wrong tags on the question. – BalusC Apr 06 '12 at 04:28

1 Answers1

3

As to your first attempt,

<h:outputText value="#{messageBean.foo(m.header("Archived-at"))}" />

This fails because you're ending the attribute value too soon and then starting with an invalid attribute name=value syntax. Pay attention to the syntax highlighting. Use single quotes instead of double quotes for the nested strings:

<h:outputText value="#{messageBean.foo(m.header('Archived-at'))}" />

As to your second attempt,

<h:commandLink action="#{bean.insert(item.id)}" value="insert" />

I'm not sure why that fails for you as it seems legit syntax.

As to your third attempt for which you didn't show any code but only the error message,

/foo/client.xhtml @48,61 value="#{messageBean.url(m)}": Method url not found

That's because you don't have a method url(Message message). Instead you have a method getUrl(Message message). So you should use

<h:commandLink action="#{messageBean.getUrl(m)}" value="insert" />

However, that won't fix the problem. This is namely not a valid action method. This should just be treated as a value expression. So, this should do:

<a href="#{messageBean.getUrl(m)}">insert</a>

This will print the result of URL#toString() as value of href attribute, which is exactly what you want. You can of course also use a <h:outputLink> for this:

<h:outputLink value="#{messageBean.getUrl(m)}">insert</h:outputLink>
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • Ok, I'm still reading your answer, thank you. I also found http://stackoverflow.com/questions/3951263/jsf-command-button-inside-a-jsf-data-table so I'll try your suggestions here and at that other question. Tags fixed. – Thufir Apr 06 '12 at 04:33
  • That answer is targeted on older environments which doesn't have EL 2.2 available. Yours, however, supports EL 2.2. This way you can end up with simpler code. A more complete overview can be found in http://stackoverflow.com/questions/4994458/how-can-i-pass-a-parameter-to-a-commandlink-inside-a-datatable Please note that this is **unsuitable** for your particular functional requirement of just printing the URL. Read the answer from top to bottom :) – BalusC Apr 06 '12 at 04:38
  • insert is good. Why is is it messageBean.getUrl(m) and not messageBean.url(m)? Is that because it's an action, so there's no "url" attribute for the bean? thanks again. Instead of "insert" can I make that the actual link text? http://etc... ? – Thufir Apr 06 '12 at 15:39
  • '#{messageBean.getUrl(m)}' thanks again. – Thufir Apr 06 '12 at 17:43
  • Because you're invoking a method using `()`, not accessing a property which would implicitly prefix `get` and suffix `()`. – BalusC Apr 06 '12 at 19:38