Hi Vladimir,

I was also tired with this converter stuff in my day. Yes, surely, there is converter facility in JSF! But to make such statement is IMO the only useful way, how one can utilize it :( Take a look at topic "Converter.getAsString not called?" started by Toppac. I've studied source code of API and implementation for lot of hours and found, that it's just impossible to get it work properly without to change too many things in code. In fact this lack (indirectly in spec itself) is covered sometimes at component level, or else nowhere. That's why some (but not all!) components works with conversion correctly, and that's why "convert" brings hundreds of hit in this list. The date conversion is not only tender spot... just try to implement trivial tristate boolean (i.e. true-false-doesn't matter) with a standard checkbox or even to bind the checkbox not to boolean, but to String property wit simple conversion rules (YES - > true, NO or "" or null ->FALSE), and you will see, what I'm talking about :) Few months ago I've opened JIRA issue and had a long discussion about this, but it has end up with nothing. The workaround stay to maintain conversion yourself, in backing bean.

My Date fields are more often the regular Oracle Date mapped to java.util.Date, but the values must be 'transported' in Strings. So, I'm using in this case just an inputText with extra JS calendar from http://www.dynarch.com/projects/calendar/ (because no one from Tomahawk works really correct with String ) I've written an extra class, which has getter and setter for each data type (String, Date, boolean) and makes conversion internally (when applicable). However you can try following to get your Date displayed properly:

<f:convertDateTime *pattern*="dd.MM.yyyy"/> //'regular' Java format pattern as you would use with String.format()

As input for Date I'm using:
<t:inputDate value="#{myBean.dateValue}"
popupCalendar="true"
renderAsPopup="true"
/>
I've no joy with getting t:inputCalendar to work correctly. There is also calendar component from Jenia project and some other "AJAX compatible", which are often suggested, but only difference is look and feel. The bugs are the same, although this time not with conversion: all of this components (except JS) are buggy with positioning of DIV, if you just get an idea to use some advanced CSS in your project. However - rehashing your idea - "one could not use CSS somehow" :) or use it with a lot of handicraft, i.e. with JS calendar from http://www.dynarch.com/projects/calendar/:

<h:inputText
                id="cal-field-1"
                value="#{myBean.myDateValue}"/>
<img id="cal-button-1" src="tools/calendar/calendar_icon_1.gif" style="cursor: pointer; border: none;margin-top:2px;margin-left:2px;" />
<script  id="scriptInitCa-l">
               Calendar.setup({
inputField : "searchform:cal-field-1", //we need here "formID:inputTextID" !
                 button        : "cal-button-1",
ifFormat : "%d.%m.%Y", //another one format pattern to maintain in config :(!
                 align         : "Tr"
               });
</script>

Looks terrible, but if you are using Facelet, you can declare custom namespace and pack this code in separate file, i.e.:
<facelet-taglib>
   <namespace>http://my.url</namespace>

   <!-- my:inputDate  -->
   <tag>
       <tag-name>inputDate</tag-name>
       <source>../includes/inputDate.xhtml</source>
   </tag>
</facelet-taglib>


regards,
paul


Vladimir Isakovich schrieb:
I was trying not to massage the incoming data in any way, but using the attributes in convertDateTime only. What I found so far, this approach works with the following setting:

<t:inputText value="#{customers.date }"
valueChangeListener="#{customers.orderChanged}">
<f:convertDateTime type="both" dateStyle="default" timeStyle="default" timeZone="EST"/>
</t:inputText>

The most important I think is type=both, then I can see exact match and no event is fired: ...validate: previousValue: Sun Jul 08 19:45:23 EDT 2007 convertedValue: Sun Jul 08 19:45:23 EDT 2007

However this for me is not acceptable for the date entry, I'd like to see something simple like Jul 08 2007 - no time or timezone at all.
Well I'll play with this isssue some more.

vlad


On 7/8/07, *daniel ccss* <[EMAIL PROTECTED] <mailto:[EMAIL PROTECTED]>> wrote:

    Vladimir you can´t use a Calendar to pick the date in the format
    you want?


    On 7/8/07, *Vladimir Isakovich* <[EMAIL PROTECTED]
    <mailto:[EMAIL PROTECTED]>> wrote:

        Paul,
        may be you know how to deal with this problem. On a date field
        I'm using valueChangeListener (I have java.util.Date in the
        backing bean). This listener is firing on submit no matter if
        the value is changed or not . In UIInput I see:

            public void validate(FacesContext context)
            {
                if (context == null) throw new
        NullPointerException("context");
                Object submittedValue = getSubmittedValue();
                System.out.println("...validate: submittedValue:
        "+submittedValue);
                if (submittedValue == null) return;

                Object convertedValue = getConvertedValue(context,
        submittedValue);

                if (!isValid()) return;

                validateValue(context, convertedValue);

                if (!isValid()) return;

                Object previousValue = getValue();
                System.out.println("...validate: previousValue:
        "+previousValue+ " convertedValue: "+convertedValue);
                try{    //-I added this
                    Converter converter =
        _SharedRendererUtils.findUIOutputConverter(context, this);
                    if (converter != null)
                    {
                        System.out.println("...validate: previousValue
        converted: "+converter.getAsString(context,this, previousValue));
                    }
                }catch(Exception e){
                    e.printStackTrace ();
                }
                setValue(convertedValue);
                setSubmittedValue(null);
                if (compareValues(previousValue, convertedValue))
                {
                    queueEvent(new ValueChangeEvent(this,
        previousValue, convertedValue));
                }
            }

        In my log:
        ...validate: submittedValue:
        [EMAIL PROTECTED]
        ...validate: previousValue: 2007-01-02 00:00:00.0
        convertedValue: Tue Jan 02 00:00:00 EST 2007
        ...validate: previousValue converted: Jan 2, 2007

        As you can see, the values are not the same, so here I'm
        getting the event.
        In my page:
                              <t:inputDate value="#{order.orderDate }"
        type="date" dateStyle="default" timeZone="EST"
valueChangeListener="#{customers.orderChanged}" id="orderDate">
                                    <!--f:convertDateTime type="date"
        dateStyle="default" timeZone="EST"/-->
                              </t:inputDate>

        I tried t:inputText with the converter first, and that time
        the first log was showing exact same value as the 3rd one.

        But I think, that I'm making some basic mistake with the use
        of date field, my init value from the DB has no timezone, and
        may be something else is missed. See the 'prevoiusValue'.
        Even so I get through this issue with the valueChangeEvent,
        I'm facing the loading the new value into the DB, and this one
        has obviously a different format.

        I guess the solution should be in adjusting the date format in
        the DB somehow. (I'm using mySql now). When retrieved from DB,
        my date should read: Tue Jan 02 00:00:00 EST 2007 - not
        2007-01-02 00:00:00.0

        Your thoughts???

        thanks
        vlad


        On 7/8/07, *Paul Iov* < [EMAIL PROTECTED]
        <mailto:[EMAIL PROTECTED]>> wrote:

            Daniel, I think your approach is ok. But... why do you
            need some properties-file? You can just extend my class
            with something like

            private boolean _invalidated = true;

            public void Invalidate(){
              this._invalidated = true;
            }
            and then in

            private DataPage<T> doFetchPage(int startRow, int pageSize){
                    if ((_lastPage == null) || (_lastStartRow !=
            startRow) || (_lastPageSize != pageSize) || *_invalidated*){
                        _log.debug("**Fetch: required -> fetching...");
                        _lastPage = fetchPage(startRow, pageSize);
                        _lastStartRow = startRow;
                        _lastPageSize = pageSize;
                       _invalidated = false;//don't vorget to set it
            to FALSE
                    }else{
                        _log.debug("**Fetch: not required (already
            fetched)!");
                    }
                    return _lastPage;
                }


            Just call this Invalidate() method from your bean after
            making changes, and the current page becomes refetched
            during next access at rendering phase. (It's exactly what
            you are doing now with the property file :)) The
            _invalidated flag 'overrides' any other condition and
            forces the page to be refetched just once.

            Unfortunately I have not enough time right now to explain
            the approach in my implementation in detail (because I
            have to switch to another nonJSF-project), but I plan to
            build small example application next week, you have asked
            for. It would be nice, if someone be able then to correct
            my terrible English and publish it at Wiki...

            Just few tips about delete/edit situation:
            - If you delete some record, you have to 'reload' at least
            the total count value (since the stored in instance of
            paged list value becomes incorrect). (The worst case: you
            land at incorrect page number, if you delete the only one
            item being at the LAST page.)
            - If you edit something, what (due to your sorting order)
            can affect the subset of items being displayed at current
            page, you have to reload the page as well. (This can lead
            into situation, when your just edited item 'disappears'
            from the current page.)

            regards,
            paul

            daniel ccss schrieb:
            Ok Paul, this is the thing,

            Since I´m new in this and in my work they are asking for
            results from the Tomahawk investigation that i'm doing
            implementing a simple maintain module, I think that I
            can´t impplement all that you have done, at least in this
            moment.

            This is what i have done until now, I changed the
            PagedList class from the wiki for yours, that was the
            only class that Ichanged, the other change was to put the
            bean in session (Vladimir idea) (by the way nice tip, you
            gave for put it in session from code). Until now all
            works fine.

            Then i made my delete, add and edit methods, they simple
            recived the Patient id and call an EJB that calls to the
            DAOs methods to do that. They are called from an
            actionlistener on the JSP. They all works fine, but I
            don`t saw the changes on the DataTable, in the moment,
            but when I click on the pages numbers I saw the changes.

            What I need, is from code, and after call a
            delte/add/edit method, fetch the data(as happen when i
            click on a page number) from my backing bean, and of
            course always pass for the filter to do the fetch after
            this methods are called, something like:

            backing_bean:
            public void delete()
            ...
            EJB.deletePatient(...)
            fetch data

            I made a hardcore test ( I need to do it for test my idea
            :( ) I made a properties file, and put a key call
            forceToFetch = false, and in the dofetch method I get
            this property then in your filter (If) I add this:
            if(.... || forceToFetch). Inside the if I ask if the
            forceToFetch is true and put it again in false in the
            properties file.Then in the backing_bean after call the
            add/delete/edit methods I put the value in the properties
            in true, and as I thought it wors fine, I can saw all the
            changes on the DataTable. Can you give a way to do this
            witout use the properties file?  Can you give me an step
            by step solution since I`m new in this and I still
            understanding all your code.

            Other thing I see a problem with this solution when I
            delete the last row of a DataPage (example the last row
            of the second DataPage) or when I delete the last row of
            the first DataPage, I recived a row index exception. How
            can I fix this issue, can you explain me. If I delete the
            last row of dataPage 3 how can I show, from code, the
            dataPage2 and in the case of the last row of the first
            DataPage how can I delete that last row and show the
            First DataPage without data? Can you also explain me this
            step by step?

            Paul really really sorry for all this, but I think that
            your are the person that more knows of this, you are a
            Guru on this, and I really need help, also thanks to you
            Vladimir!!



            On 7/6/07, *Paul Iov* <[EMAIL PROTECTED]
            <mailto:[EMAIL PROTECTED]>> wrote:

                Vladimir Isakovich schrieb:
                > Yes, I have just one call getting through to my DB,
                the session scoped
                > bean with Paul's blocking method worked. The
                drawback with this
                > approach, we may start thinking on cleaning session
                off of the unused
                > objects, otherwise our app may consume too much
                cache on the server.
                >
                > vlad
                That's why I don't utilize the JSF backing bean
                facility. It's not
                flexibly enough to maintain high dynamically
                applications.
                I've implement own session controller and it's the
                only backing bean I
                have to declare in my faces-config.xml ;) The other
                part of magic is
                application wide controller (started with
                ServletContextListener) to
                maintain some global issues and, first of all the
                sessions, which I
                catch with HTTPSessionListener.

                Just a little hint: you can 'inject' your beans into
                session without
                declaring it in config.

                <managed-bean>
                      <managed-bean-name>MyBean</managed-bean-name>
                      <managed-bean-class>my.MyClass</managed-bean-class>
                      <managed-bean-scope>session</managed-bean-scope>
                </managed-bean>

                is equal to:

                FacesContext fCtx    = FacesContext.getCurrentInstance();
                ExternalContext eCtx    = _fCtx.getExternalContext();
                ServletContext srvCtx  =
                (ServletContext)_eCtx.getContext();
                HttpSession session =
                (HttpSession)_eCtx.getSession(false);
                ...
                MyClass myInstance = new MyClass();
                session.setAttribute("MyBean", myInstance);//put
                MBean to session








Reply via email to