com.icesoft.tutorial.TimeZoneBean.java Source code

Java tutorial

Introduction

Here is the source code for com.icesoft.tutorial.TimeZoneBean.java

Source

/*
 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
 *
 * "The contents of this file are subject to the Mozilla Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://www.mozilla.org/MPL/
 *
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
 * License for the specific language governing rights and limitations under
 * the License.
 *
 * The Original Code is ICEfaces 1.5 open source software code, released
 * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
 * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
 * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
 *
 * Contributor(s): _____________________.
 *
 * Alternatively, the contents of this file may be used under the terms of
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
 * License), in which case the provisions of the LGPL License are
 * applicable instead of those above. If you wish to allow use of your
 * version of this file only under the terms of the LGPL License and not to
 * allow others to use your version of this file under the MPL, indicate
 * your decision by deleting the provisions above and replace them with
 * the notice and other provisions required by the LGPL License. If you do
 * not delete the provisions above, a recipient may use your version of
 * this file under either the MPL or the LGPL License."
 *
 */

package com.icesoft.tutorial;

import com.icesoft.faces.async.render.IntervalRenderer;
import com.icesoft.faces.async.render.RenderManager;
import com.icesoft.faces.async.render.Renderable;
import com.icesoft.faces.context.DisposableBean;
import com.icesoft.faces.webapp.xmlhttp.PersistentFacesState;
import com.icesoft.faces.webapp.xmlhttp.RenderingException;
import com.icesoft.faces.webapp.xmlhttp.FatalRenderingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.event.ActionEvent;
import javax.faces.event.ValueChangeEvent;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Map;
import java.util.TimeZone;

/**
 * Bean backing the Time Zone application. This bean uses the RenderManager to
 * update state at a specified interval. Also controls time zone information
 * during the session.
 */

public class TimeZoneBean implements Renderable, DisposableBean {
    private static Log log = LogFactory.getLog(TimeZoneBean.class);
    /**
     * The default {@link TimeZone} for this host server.
     */
    private TimeZone serverTimeZone;

    /**
     * {@link DateFormat} used to display the server time.
     */
    private DateFormat serverFormat;

    /**
     * Active {@link TimeZone} displayed at top of UI. Changes when a time zone
     * is selected by pressing one of six commandButtons in UI map.
     */
    private TimeZone selectedTimeZone;

    /**
     * {@link DateFormat} used to display the selected time.
     */
    private DateFormat selectedFormat;

    /**
     * List of all possible {@link TimeZoneWrapper} objects, which determine the
     * map and checkbox UIs.
     */
    private ArrayList allTimeZoneList;

    /**
     * List of checked {@link TimeZoneWrapper} objects, which are shown at the
     * bottom table UI. Changes when a time zone is selected or deselected by
     * checking one of six check boxes underneath map UI.
     */
    private ArrayList checkedTimeZoneList;

    /**
     * Time interval, in milliseconds, between renders.
     */
    private final int renderInterval = 1000;

    /**
     * The state associated with the current user that can be used for
     * server-initiated render calls.
     */
    private PersistentFacesState state;

    /**
     * A named render group that can be shared by all TimeZoneBeans for
     * server-initiated render calls.  Setting the interval determines the
     * frequency of the render call.
     */
    private IntervalRenderer clock;

    /**
     * Constructor initializes time zones.
     */
    public TimeZoneBean() {
        init();
    }

    /**
     * Initializes this TimeZoneBean's properties.
     */
    private void init() {
        serverTimeZone = TimeZone.getDefault();
        serverFormat = buildDateFormatForTimeZone(serverTimeZone);
        selectedTimeZone = TimeZone.getTimeZone("Etc/GMT+0"); // selected time zone set to UTC as default
        selectedFormat = buildDateFormatForTimeZone(selectedTimeZone);

        // Entries in this list determine what will be generated in
        //  the timezone web file, so should be modifiable,
        //  but all ids must be unique to each other
        allTimeZoneList = new ArrayList(7);
        allTimeZoneList.add(new TimeZoneWrapper("Pacific/Honolulu", "GMTminus10", "HADT", hawaiiXCoords,
                hawaiiYCoords, hawaiiXCoords.length));
        allTimeZoneList.add(new TimeZoneWrapper("America/Anchorage", "GMTminus9", "AKST", alaskaXCoords,
                alaskaYCoords, alaskaXCoords.length));
        allTimeZoneList.add(new TimeZoneWrapper("America/Los_Angeles", "GMTminus8", "PST", pacificXCoords,
                pacificYCoords, pacificXCoords.length));
        allTimeZoneList.add(new TimeZoneWrapper("America/Denver", "GMTminus7", "MDT", mountainXCoords,
                mountainYCoords, mountainXCoords.length));
        allTimeZoneList.add(new TimeZoneWrapper("America/Chicago", "GMTminus6", "CDT", centralXCoords,
                centralYCoords, centralXCoords.length));
        allTimeZoneList.add(new TimeZoneWrapper("America/New_York", "GMTminus5", "EST", easternXCoords,
                easternYCoords, easternXCoords.length));
        allTimeZoneList.add(new TimeZoneWrapper("Canada/Newfoundland", "GMTminus4", "NST", nfldXCoords, nfldYCoords,
                nfldXCoords.length));

        checkedTimeZoneList = new ArrayList();

        state = PersistentFacesState.getInstance();
    }

    /**
     * Gets server time.
     *
     * @return Server time.
     */
    public String getServerTime() {
        return formatCurrentTime(serverFormat);
    }

    /**
     * Gets server time zone display name.
     *
     * @return Server time zone display name.
     */
    public String getServerTimeZoneName() {
        return displayNameTokenizer(serverTimeZone.getDisplayName());
    }

    /**
     * Gets selected time zone time. This is the time zone selected by one of
     * six commandButtons from the map in the UI.
     *
     * @return selectedTimeZone time.
     */
    public String getSelectedTime() {
        return formatCurrentTime(selectedFormat);
    }

    /**
     * Gets selected time zone display name.
     *
     * @return selectedTimeZone display name.
     */
    public String getSelectedTimeZoneName() {
        return displayNameTokenizer(selectedTimeZone.getDisplayName());
    }

    /**
     * Gets ArrayList of all possible <code>TimeZoneWrapper</code> objects.
     *
     * @return ArrayList of TimeZoneWrapper objects.
     */
    public ArrayList getAllTimeZoneList() {
        return allTimeZoneList;
    }

    /**
     * Gets ArrayList of currently active <code>TimeZoneWrapper</code> objects.
     * This list is populated by selectBooleanCheckbox components in UI.
     *
     * @return ArrayList of TimeZoneWrapper objects.
     */
    public ArrayList getCheckedTimeZoneList() {
        return checkedTimeZoneList;
    }

    /**
     * Extracts the first word from a TimeZone displayName.
     *
     * @param displayName A TimeZone displayName.
     * @return String The first word from the TimeZone displayName.
     */
    public static String displayNameTokenizer(String displayName) {
        if (displayName == null) {
            displayName = "";
        } else {
            int firstSpace = displayName.indexOf(' ');
            if (firstSpace != -1) {
                displayName = displayName.substring(0, firstSpace);
            }
        }
        return displayName;
    }

    public static DateFormat buildDateFormatForTimeZone(TimeZone timeZone) {
        SimpleDateFormat currentFormat = new SimpleDateFormat("EEE, HH:mm:ss");
        Calendar currentZoneCal = Calendar.getInstance(timeZone);
        currentFormat.setCalendar(currentZoneCal);
        currentFormat.setTimeZone(timeZone);
        return currentFormat;
    }

    public static String formatCurrentTime(DateFormat dateFormat) {
        Calendar cal = dateFormat.getCalendar();
        cal.setTimeInMillis(System.currentTimeMillis());
        return dateFormat.format(cal.getTime());
    }

    /**
     * Each TimeZoneWrapper has one or more ids of components in the UI that
     * correspond to its time zone.  By this, if an event comes from a component
     * in the web page, then this will return the relevant TimeZoneWrapper.
     *
     * @param componentId Id of component in UI
     * @return TimeZoneWrapper
     */
    private TimeZoneWrapper getTimeZoneWrapperByComponentId(String componentId) {
        TimeZoneWrapper tzw;
        for (int i = 0; i < allTimeZoneList.size(); i++) {
            tzw = (TimeZoneWrapper) allTimeZoneList.get(i);
            if (tzw.isRelevantComponentId(componentId)) {
                return tzw;
            }
        }
        return null;
    }

    /**
     * Used to create, setup, and start an IntervalRenderer from the passed
     * renderManager This is used in conjunction with faces-config.xml to allow
     * the same single render manager to be set in all TimeZoneBeans
     *
     * @param renderManager RenderManager to get the IntervalRenderer from
     */
    public void setRenderManager(RenderManager renderManager) {
        clock = renderManager.getIntervalRenderer("clock");
        clock.setInterval(renderInterval);
        clock.add(this);
        clock.requestRender();
    }

    /**
     * Gets RenderManager
     *
     * @return RenderManager null
     */
    public RenderManager getRenderManager() {
        return null;
    }

    //
    // Renderable interface
    //

    /**
     * Gets the current instance of PersistentFacesState
     *
     * @return PersistentFacesState state
     */
    public PersistentFacesState getState() {
        return state;
    }

    /**
     * Callback to inform us that there was an Exception while rendering.
     * Continue from a transientRenderingException but not
     * from a FatalRenderingException
     *
     * @param renderingException render exception passed in frome framework.
     */
    public void renderingException(RenderingException renderingException) {

        if (log.isDebugEnabled()) {
            log.debug("Rendering exception: ", renderingException);
        }

        if (renderingException instanceof FatalRenderingException) {
            performCleanup();
        }
    }

    /**
     * Used to properly shut-off the ticking clock.
     *
     * @return true if properly shut-off, false if not.
     */
    protected boolean performCleanup() {
        try {
            if (clock != null) {
                clock.remove(this);
                // whether or not this is necessary depends on how 'shutdown'
                // you want an empty renderer. If it's emptied often, the cost
                // of shutdown+startup is too great
                if (clock.isEmpty()) {
                    clock.dispose();
                }
                clock = null;
            }
            return true;
        } catch (Exception failedCleanup) {
            if (log.isErrorEnabled()) {
                log.error("Failed to cleanup a clock bean", failedCleanup);
            }

        }
        return false;
    }

    /**
     * Disposes a view either due to a window closing
     * or a timeout.
     */
    public void dispose() throws Exception {
        if (log.isDebugEnabled()) {
            log.debug("Dispose TimeZoneBean for a user - cleaning up");
        }
        performCleanup();
    }

    //
    // Implicit interfaces as defined by the callbacks in the web files
    //

    /**
     * Listens to client input from commandButtons in the UI map and sets the
     * selected time zone.
     *
     * @param event ActionEvent.
     */
    public void listen(ActionEvent event) {
        FacesContext context = FacesContext.getCurrentInstance();
        Map requestParams = context.getExternalContext().getRequestParameterMap();
        // get mouse coordinate of user click
        int x = Integer.parseInt((String) requestParams.get("ice.event.x"));
        int y = Integer.parseInt((String) requestParams.get("ice.event.y"));
        x -= icefacesXOffset;
        y -= icefacesYOffset;
        TimeZoneWrapper tzw;
        // compare mouse coordinate to know timzone polygons.
        for (int i = 0; i < allTimeZoneList.size(); i++) {
            if (((TimeZoneWrapper) allTimeZoneList.get(i)).getMapPolygon().contains(x, y)) {
                tzw = (TimeZoneWrapper) allTimeZoneList.get(i);
                selectedTimeZone = TimeZone.getTimeZone(tzw.getId());
                selectedFormat = buildDateFormatForTimeZone(selectedTimeZone);
            }
        }
    }

    /**
     * Adds or removes a <code>TimeZoneWrapper</code> to
     * <code>checkedTimeZoneList</code> when a selectBooleanCheckbox
     * ValueChangeEvent is fired from the UI.
     *
     * @param event ValueChangeEvent.
     */
    public void timeZoneChanged(ValueChangeEvent event) {
        UIComponent comp = event.getComponent();
        FacesContext context = FacesContext.getCurrentInstance();
        String componentId = comp.getClientId(context);
        TimeZoneWrapper tzw = getTimeZoneWrapperByComponentId(componentId);
        if (tzw != null) {
            boolean checked = ((Boolean) event.getNewValue()).booleanValue();
            // If checkbox is checked, then add tzw to checkedTimeZoneList
            if (checked) {
                tzw.setCurrentlyShowing(true);
                if (!checkedTimeZoneList.contains(tzw)) {
                    checkedTimeZoneList.add(tzw);
                }
            }
            // Otherwise, if checkbox is unchecked, then remove tzw from checkedTimeZoneList
            else {
                tzw.setCurrentlyShowing(false);
                checkedTimeZoneList.remove(tzw);
            }
        }
    }

    // ICEfaces image map integration needs offset values to calculate the
    // correct coordinate values.
    private static int icefacesXOffset = 193;
    private static int icefacesYOffset = 236;
    // Create primary polygon objects for continental country outlines
    private static int[] hawaiiXCoords = { 0, 29, 54, 58, 58, 61, 61, 0 };
    private static int[] hawaiiYCoords = { 186, 194, 208, 215, 223, 243, 254, 254 };

    private static int[] alaskaXCoords = { 117, 118, 125, 132, 135, 138, 141, 146, 147, 157, 164, 165, 162, 156,
            144, 120, 75, 72, 60, 45, 1, 0, 0, 14 };
    private static int[] alaskaYCoords = { 0, 4, 5, 12, 12, 8, 7, 14, 14, 28, 31, 37, 38, 41, 41, 16, 16, 25, 35,
            38, 55, 55, 1, 0 };

    private static int[] pacificXCoords = { 176, 176, 187, 187, 181, 185, 191, 192, 207, 207, 214, 214, 218, 222,
            222, 221, 221, 222, 224, 230, 229, 225, 222, 219, 220, 218, 214, 214, 219, 107, 219, 232, 231, 230, 228,
            228, 229, 228, 226, 226, 229, 231, 238, 233, 226, 217, 205, 198, 195, 197, 194, 187, 188, 189, 190, 186,
            169, 152, 145, 158, 164, 164, 155, 141, 136, 134, 132, 125, 118, 118 };
    private static int[] pacificYCoords = { 0, 3, 3, 7, 7, 20, 19, 25, 32, 43, 47, 50, 54, 59, 64, 68, 67, 71, 71,
            80, 86, 90, 92, 89, 90, 93, 95, 97, 106, 107, 112, 112, 137, 139, 140, 148, 149, 157, 158, 162, 163,
            171, 179, 179, 171, 154, 148, 138, 133, 130, 130, 118, 114, 103, 88, 77, 61, 54, 41, 41, 37, 32, 25, 7,
            9, 11, 11, 4, 4, 0 };

    private static int[] mountainXCoords = { 177, 287, 287, 268, 268, 258, 259, 249, 249, 254, 254, 250, 253, 250,
            253, 254, 250, 250, 277, 277, 284, 289, 288, 290, 290, 285, 286, 281, 281, 272, 270, 265, 258, 256, 256,
            264, 263, 268, 269, 275, 276, 272, 244, 216, 217, 231, 218, 226, 232, 239, 230, 228, 230, 230, 228, 229,
            231, 233, 220, 220, 215, 215, 221, 220, 223, 225, 231, 231, 225, 222, 222, 215, 215, 208, 208, 193, 192,
            185, 182, 182, 189, 189 };
    private static int[] mountainYCoords = { 0, 0, 8, 8, 45, 45, 41, 40, 48, 48, 52, 52, 63, 63, 63, 69, 69, 75, 75,
            80, 81, 86, 98, 101, 110, 116, 137, 138, 160, 160, 164, 161, 161, 165, 181, 190, 194, 198, 201, 204,
            210, 214, 233, 231, 216, 208, 176, 174, 179, 179, 163, 158, 153, 147, 144, 140, 139, 109, 110, 106, 104,
            98, 93, 89, 91, 93, 88, 84, 77, 70, 61, 53, 48, 44, 41, 30, 24, 16, 17, 8, 7, 2 };

    private static int[] centralXCoords = { 288, 317, 314, 314, 321, 325, 330, 340, 336, 336, 338, 346, 348, 349,
            350, 351, 347, 347, 357, 356, 358, 357, 352, 378, 380, 381, 291, 291, 269, 277, 276, 269, 264, 264, 257,
            257, 260, 267, 270, 273, 283, 282, 287, 286, 292, 291, 289, 290, 284, 277, 277, 252, 252, 255, 255, 252,
            255, 255, 251, 251, 256, 256, 270, 270, 289 };
    private static final int[] centralYCoords = { 0, 0, 9, 15, 15, 26, 25, 30, 35, 74, 86, 89, 94, 111, 113, 115,
            118, 129, 137, 145, 155, 170, 210, 242, 243, 252, 252, 241, 217, 210, 203, 198, 193, 189, 179, 164, 162,
            163, 165, 163, 162, 139, 138, 116, 109, 98, 97, 85, 78, 78, 72, 73, 69, 69, 62, 54, 52, 47, 46, 41, 43,
            47, 47, 9, 9 };

    private static int[] easternXCoords = { 388, 417, 446, 446, 449, 447, 448, 447, 450, 449, 442, 438, 431, 437,
            437, 446, 447, 449, 449, 450, 451, 441, 429, 430, 433, 433, 435, 424, 419, 415, 415, 463, 464, 382, 381,
            353, 360, 357, 359, 348, 348, 353, 349, 348, 340, 337, 337, 341, 373 };
    private static int[] easternYCoords = { 0, 0, 5, 10, 16, 19, 21, 28, 36, 41, 40, 38, 44, 52, 57, 57, 51, 50, 54,
            66, 74, 78, 81, 83, 84, 91, 96, 209, 215, 216, 226, 242, 255, 253, 241, 208, 154, 144, 136, 127, 118,
            114, 110, 92, 84, 78, 35, 29, 9 };

    private static int[] nfldXCoords = { 448, 465, 465, 415, 416, 418, 434, 434, 434, 432, 433, 436, 452, 452, 450,
            453, 450, 447, 447, 444, 440, 440, 434, 440, 443, 450, 453, 450, 451, 448, 450, 450, 448 };
    private static int[] nfldYCoords = { 0, 0, 242, 242, 226, 217, 209, 95, 85, 83, 80, 82, 75, 56, 54, 51, 50, 52,
            56, 54, 55, 50, 45, 40, 42, 42, 37, 29, 23, 20, 17, 14, 14 };
}