org.exoplatform.social.webui.profile.UIContactSection.java Source code

Java tutorial

Introduction

Here is the source code for org.exoplatform.social.webui.profile.UIContactSection.java

Source

/**
 * Copyright (C) 2003-2007 eXo Platform SAS.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Affero General Public License
 * as published by the Free Software Foundation; either version 3
 * of the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see<http://www.gnu.org/licenses/>.
 */
package org.exoplatform.social.webui.profile;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.exoplatform.portal.application.PortalRequestContext;
import org.exoplatform.social.core.identity.model.Profile;
import org.exoplatform.social.webui.Utils;
import org.exoplatform.webui.application.WebuiRequestContext;
import org.exoplatform.webui.config.annotation.ComponentConfig;
import org.exoplatform.webui.config.annotation.EventConfig;
import org.exoplatform.webui.core.UIComponent;
import org.exoplatform.webui.core.lifecycle.UIFormLifecycle;
import org.exoplatform.webui.core.model.SelectItemOption;
import org.exoplatform.webui.event.Event;
import org.exoplatform.webui.event.EventListener;
import org.exoplatform.webui.event.Event.Phase;
import org.exoplatform.webui.form.UIFormInput;
import org.exoplatform.webui.form.UIFormInputBase;
import org.exoplatform.webui.form.UIFormSelectBox;
import org.exoplatform.webui.form.UIFormStringInput;
import org.exoplatform.webui.form.validator.ExpressionValidator;

/**
 * Component is used for contact information managing.<br>
 * Some contact information such as: phone, ims, website ...
 * This is one part of profile management beside basic information and experience.<br>
 *
 * Modified : hanh.vi
 *          hanhvq@gmail.com
 * Aug 18, 2009
 */
@ComponentConfig(lifecycle = UIFormLifecycle.class, template = "classpath:groovy/social/webui/profile/UIContactSection.gtmpl", events = {
        @EventConfig(listeners = UIContactSection.EditActionListener.class, phase = Phase.DECODE),
        @EventConfig(listeners = UIContactSection.SaveActionListener.class),
        @EventConfig(listeners = UIProfileSection.CancelActionListener.class, phase = Phase.DECODE),
        @EventConfig(listeners = UIContactSection.AddActionListener.class),
        @EventConfig(listeners = UIContactSection.RemoveActionListener.class, phase = Phase.DECODE) })
public class UIContactSection extends UIProfileSection {
    /** GENDER */
    public static final String GENDER_CHILD = "gender";

    /** PHONE. */
    public static final String PHONE = "1phone";

    /** URL. */
    public static final String IM = "2im";

    /** URL. */
    public static final String URL = "3url";

    /** MALE. */
    public static final String VALUE_GENDER_MALE = "Male";

    /** FEMALE. */
    public static final String VALUE_GENDER_FEMALE = "Female";

    /** PHONE_TYPES. */
    public static final String[] PHONE_TYPES = new String[] { "Work", "Home", "Other" };

    /** IM_TYPES. */
    public static final String[] IM_TYPES = new String[] { "Gtalk", "Msn", "Skype", "Yahoo", "Other" };

    /** WEBSITE TITLE. */
    public static final String WEBSITE_TITLE = "Website Title";

    /** KEY. */
    public static final String KEY = "key";

    /** VALUE. */
    public static final String VALUE = "value";

    /** PHONE REGEX EXPRESSION. */
    public static final String PHONE_REGEX_EXPRESSION = "^[\\d\\s ().+-]{3,20}+$";

    /** IM LENGTH REGEX EXPRESSION. */
    public static final String IM_STRINGLENGTH_REGEX_EXPRESSION = "^[\\w\\W]{3,60}+$";

    /** INVALID PHONE. */
    public static final String INVALID_PHONE = "UIContactSect.msg.Invalid-phone";

    /** INVALID IM. */
    public static final String INVALID_IM = "UIContactSect.msg.Invalid-im";

    /** URL REGEX EXPRESSION. */
    public static final String URL_REGEX_EXPRESSION = "\\b(?:(https?|ftp|file)://|www\\.)?[a-z0-9\\-\\.]+\\.[a-z]{2,3}(:[a-z0-9]*)?\\/?([a-z0-9\\-\\._\\?\\,\\'\\/\\\\+&amp;%\\$#\\=~])*$";

    public static final String HTTP_PROTOCOL = "http://";

    /** INVALID URL. */
    public static final String INVALID_URL = "UIContactSect.msg.Invalid-url";

    /** Html attribute title. */
    private static final String HTML_ATTRIBUTE_TITLE = "title";

    /** Html attribute placeholder. */
    private static final String HTML_ATTRIBUTE_PLACEHOLDER = "placeholder";

    /** Number of phone. */
    private int phoneCount = 0;

    /** Number of ims. */
    private int imCount = 0;

    /** Number of url. */
    private int urlCount = 0;

    private String sampleURL;

    /** Get the number of phone. */
    /**
     * @return phoneCount
     */
    public final int getPhoneCount() {
        return phoneCount;
    }

    /** Get the number of ims. */
    /**
     * @return imCount
     */
    public final int getImsCount() {
        return imCount;
    }

    /** Get the number of url. */
    /**
     * @return urlCount
     */
    public final int getUrlCount() {
        return urlCount;
    }

    /**
     * @return the sampleURL
     */
    public String getSampleURL() {
        return sampleURL;
    }

    /**
     * @param sampleURL the sampleURL to set
     */
    public void setSampleURL(String sampleURL) {
        this.sampleURL = sampleURL;
    }

    /**
     * Initializes contact form.<br>
     *
     * @throws Exception
     */
    public UIContactSection() throws Exception {
        addChild(UITitleBar.class, null, null);

        List<SelectItemOption<String>> options = new ArrayList<SelectItemOption<String>>();
        options.add(new SelectItemOption<String>(VALUE_GENDER_MALE));
        options.add(new SelectItemOption<String>(VALUE_GENDER_FEMALE));
        addUIFormInput(new UIFormSelectBox(GENDER_CHILD, GENDER_CHILD, options));

        // Get sample url message from resource bundle and set to variable.
        ResourceBundle resourceBudle = PortalRequestContext.getCurrentInstance().getApplicationResourceBundle();
        setSampleURL(resourceBudle.getString("UIContactSection.msg.sampleUrl"));
    }

    /**
     * Gets and sort all uicomponents.<br>
     *
     * @return All children in order.
     */
    public final List<UIComponent> getChilds() {
        List<UIComponent> listChild = new ArrayList<UIComponent>(getChildren());
        //
        sort(listChild);
        //
        setChildren(listChild);

        return listChild;
    }

    /**
     * Gets all children of Phone.<br>
     *
     * @return All Phone children in order.
     */
    public final List<UIComponent> getPhoneChilds() {
        return sortSubList(getSubList(0, phoneCount));
    }

    /**
     * Gets all children of ims.<br>
     *
     * @return All ims children in order.
     */
    public final List<UIComponent> getImsChilds() {
        return sortSubList(getSubList(phoneCount, phoneCount + imCount));
    }

    /**
     * Gets all children of URL.<br>
     *
     * @return All URL children in order.
     */
    public final List<UIComponent> getUrlChilds() {
        return sortSubList(getSubList(phoneCount + imCount, phoneCount + imCount + urlCount));
    }

    /**
     * Gets gender child<br>
     *
     * @return  gender child.
     */
    @SuppressWarnings("unchecked")
    public final UIFormInput<String> getGenderChild() {
        return (UIFormInput<String>) getChildById(GENDER_CHILD);
    }

    /**
     *  Stores profile information into database when form is submitted.<br>
     *
     */
    public static class SaveActionListener extends UIProfileSection.SaveActionListener {

        @Override
        public final void execute(final Event<UIProfileSection> event) throws Exception {
            super.execute(event);

            UIProfileSection sect = event.getSource();
            UIContactSection uiContactSectionSect = (UIContactSection) sect;

            uiContactSectionSect.removeEmptyComponents();

            uiContactSectionSect.saveProfileInfo();
        }
    }

    /**
     * Adds component when user click add button.<br>
     *
     */
    public static class AddActionListener extends EventListener<UIContactSection> {

        @Override
        public final void execute(final Event<UIContactSection> event) throws Exception {
            UIContactSection sect = event.getSource();
            String typeOfComp = event.getRequestContext().getRequestParameter(OBJECTID);
            sect.addUIFormInput(typeOfComp);
        }
    }

    /**
     * Removes the component that user selected for removing.<br>
     *
     */
    public static class RemoveActionListener extends EventListener<UIContactSection> {

        @Override
        public final void execute(final Event<UIContactSection> event) throws Exception {
            UIContactSection sect = event.getSource();
            String comps = event.getRequestContext().getRequestParameter(OBJECTID);
            String uiComp1 = comps.substring(0, comps.indexOf("."));
            String uiComp2 = comps.substring(comps.indexOf(".") + 1, comps.length());
            sect.removeFormInput(uiComp1, uiComp2);
        }
    }

    /**
     * Changes form into edit mode when user click eddit button.<br>
     *
     */
    public static class EditActionListener extends UIProfileSection.EditActionListener {

        @Override
        public final void execute(final Event<UIProfileSection> event) throws Exception {
            super.execute(event);
            UIProfileSection sect = event.getSource();
            UIContactSection uiContactSectionSect = (UIContactSection) sect;
            uiContactSectionSect.setValue();
            event.getRequestContext().addUIComponentToUpdateByAjax(sect);
        }
    }

    /**
     * Removes empty components that user did not input any values.
     *
     */
    public void removeEmptyComponents() {
        removeEmptyInput(phoneCount, getPhoneChilds(), PHONE);
        removeEmptyInput(imCount, getImsChilds(), IM);
        removeEmptyInput(urlCount, getUrlChilds(), URL);
    }

    private void removeEmptyInput(int count, List<UIComponent> listUIComp, String uiStringType) {
        for (int i = 0; i < count; i += 2) {
            String id1 = null;
            String id2 = ((UIFormStringInput) listUIComp.get(i + 1)).getName();
            String value = ((UIFormStringInput) listUIComp.get(i + 1)).getValue();

            if (uiStringType.equals(URL)) {
                id1 = ((UIFormStringInput) listUIComp.get(i)).getName();
            } else {
                id1 = ((UIFormSelectBox) listUIComp.get(i)).getName();
            }

            if ((value == null) || (value.length() == 0) || (value.startsWith(getSampleURL()))) {
                removeFormInput(id1, id2);
            }
        }
    }

    /**
     * Gets profile information from components and save into Profile.<br>
     *
     * @throws Exception
     */
    private void saveProfileInfo() throws Exception {
        Profile toBeUpdatedProfile = getProfile();

        toBeUpdatedProfile.setProperty(Profile.GENDER, getGenderChild().getValue());
        toBeUpdatedProfile.setProperty(Profile.CONTACT_PHONES,
                getProfileForSave(phoneCount, getPhoneChilds(), PHONE));
        toBeUpdatedProfile.setProperty(Profile.CONTACT_IMS, getProfileForSave(imCount, getImsChilds(), IM));
        toBeUpdatedProfile.setProperty(Profile.CONTACT_URLS, getProfileForSave(urlCount, getUrlChilds(), URL));

        Utils.getIdentityManager().updateProfile(toBeUpdatedProfile);
    }

    /**
     * Gets information input by user for saving profile.<br>
     *
     * @param count Number of children.
     *
     * @param listUIComp Contains children of each input type (phone,...).
     *
     * @param uiStringType Type of component.
     *
     * @return All profile information.
     */
    private ArrayList<HashMap<String, String>> getProfileForSave(final int count,
            final List<UIComponent> listUIComp, final String uiStringType) {
        ArrayList<HashMap<String, String>> profileMap = new ArrayList<HashMap<String, String>>();
        for (int i = 0; i < count; i += 2) {
            HashMap<String, String> uiMap = new HashMap<String, String>();
            String value = null;
            String key = null;
            if (uiStringType.equals(URL)) {
                UIFormStringInput uiStringInput = (UIFormStringInput) listUIComp.get(i + 1);
                key = Profile.URL_POSTFIX.toLowerCase();
                value = uiStringInput.getValue();
                if (!value.matches("^(https?|ftp)://.*$")) {
                    value = HTTP_PROTOCOL + value;
                }
            } else {
                key = ((UIFormSelectBox) listUIComp.get(i)).getValue();
                value = ((UIFormStringInput) listUIComp.get(i + 1)).getValue();
            }

            uiMap.put(KEY, key);
            uiMap.put(VALUE, escapeHtml(value));
            profileMap.add(uiMap);
        }
        return profileMap;
    }

    /**
     * Gets children of each type (phone, ...) from the all children list.<br>
     *
     * @param startIdx Start index of sublist.
     *
     * @param endIdx End index of sublist.
     *
     * @return A list contains children of each type.
     */
    private List<UIComponent> getSubList(final int startIdx, final int endIdx) {
        List<UIComponent> rtnList = new ArrayList<UIComponent>();
        for (int idx = startIdx; idx < endIdx; idx++) {
            rtnList.add(getChilds().get(idx));
        }

        return rtnList;
    }

    /**
     * Sets value for components.<br>
     *
     * @throws Exception
     */
    private void setValue() throws Exception {
        Profile profile = getProfile();
        String gender = (String) profile.getProperty(Profile.GENDER);
        if (gender != null && !gender.isEmpty()) {
            getGenderChild().setValue(gender);
        }

        setValueByType(profile, getPhoneChilds(), Profile.CONTACT_PHONES);
        setValueByType(profile, getImsChilds(), Profile.CONTACT_IMS);
        setValueByType(profile, getUrlChilds(), Profile.CONTACT_URLS);
    }

    /**
     * Sets value for components with each type.<br>
     *
     * @param listChilds List children for setting.
     *
     * @param uiType Type for setting.
     *
     * @throws Exception
     */
    @SuppressWarnings("unchecked")
    private void setValueByType(final Profile profile, final List<UIComponent> listChilds, final String uiType)
            throws Exception {
        if (profile == null || listChilds == null || uiType == null || uiType.equals("")) {
            return;
        }
        List<Map<String, String>> profiles = (List<Map<String, String>>) profile.getProperty(uiType);
        int numberOfUI = listChilds.size();
        int newProfileSize = profiles == null ? 0 : profiles.size();

        while (numberOfUI / 2 > newProfileSize) {
            String id1 = listChilds.get(--numberOfUI).getName();
            String id2 = listChilds.get(--numberOfUI).getName();
            removeFormInput(id1, id2);
        }

        if (newProfileSize == 0) {
            return;
        }

        while (newProfileSize > numberOfUI / 2) {
            if (Profile.CONTACT_IMS.equals(uiType)) {
                addUIFormInput(IM);
            } else if (Profile.CONTACT_PHONES.equals(uiType)) {
                addUIFormInput(PHONE);
            } else if (Profile.CONTACT_URLS.equals(uiType)) {
                addUIFormInput(URL);
            }
            numberOfUI += 2;
        }

        int index = 0;
        if (Profile.CONTACT_IMS.equals(uiType)) {
            for (Map<String, String> map : profiles) {
                ((UIFormInput) getImsChilds().get(index++)).setValue(StringEscapeUtils.unescapeHtml(map.get(KEY)));
                ((UIFormInput) getImsChilds().get(index++))
                        .setValue(StringEscapeUtils.unescapeHtml(map.get(VALUE)));
            }
        } else if (Profile.CONTACT_URLS.equals(uiType)) {
            for (Map<String, String> map : profiles) {
                ((UIFormInput) getUrlChilds().get(index++)).setValue(map.get(KEY));
                ((UIFormInput) getUrlChilds().get(index++)).setValue(map.get(VALUE));
            }
        } else if (Profile.CONTACT_PHONES.equals(uiType)) {
            for (Map<String, String> map : profiles) {
                ((UIFormInput) getPhoneChilds().get(index++)).setValue(map.get(KEY));
                ((UIFormInput) getPhoneChilds().get(index++)).setValue(map.get(VALUE));
            }
        }
    }

    /**
     * Removes components by input id.<br>
     *
     * @param id1 The id of first component.
     *
     * @param id2 The id of next component.
     */
    private void removeFormInput(final String id1, final String id2) {
        removeChildById(id1);
        removeChildById(id2);
        if (id1.startsWith(IM)) {
            imCount -= 2;
            resetComponentId(IM);
        } else if (id1.startsWith(URL)) {
            urlCount -= 2;
            resetComponentId(URL);
        } else if (id1.startsWith(PHONE)) {
            phoneCount -= 2;
            resetComponentId(PHONE);
        }
    }

    /**
     * Resets id and name of components that belong to group components are being modified.
     * 
     * @param componentType Type of components that are being modified.
     */
    private void resetComponentId(String componentType) {
        List<UIComponent> componentByTypes = null;
        int componentCount = 0;
        if (IM.equals(componentType)) {
            componentByTypes = getImsChilds();
            componentCount = getImsCount();
        } else if (URL.equals(componentType)) {
            componentByTypes = getUrlChilds();
            componentCount = getUrlCount();
        } else if (PHONE.equals(componentType)) {
            componentByTypes = getPhoneChilds();
            componentCount = getPhoneCount();
        }

        for (int i = 0; i < componentCount; i += 2) {
            UIFormInputBase comp1 = (UIFormInputBase) componentByTypes.get(i);
            UIFormInputBase comp2 = (UIFormInputBase) componentByTypes.get(i + 1);
            String newComponentId1 = componentType + StringUtils.leftPad(String.valueOf(i), 3, '0');
            String newComponentId2 = componentType + StringUtils.leftPad(String.valueOf(i + 1), 3, '0');
            comp1.setId(newComponentId1);
            comp1.setName(newComponentId1);
            comp2.setId(newComponentId2);
            comp2.setName(newComponentId2);
        }
    }

    /**
     * Adds component with the input type.<br>
     *
     * @param type Type of component is added (email, phone, ...).
     *
     * @throws Exception
     */
    private void addUIFormInput(final String type) throws Exception {
        WebuiRequestContext requestContext = WebuiRequestContext.getCurrentInstance();
        ResourceBundle resourceBundle = requestContext.getApplicationResourceBundle();
        if (PHONE.equals(type)) {
            int phoneIdx = phoneCount;
            createUISelectBox(PHONE_TYPES, PHONE + StringUtils.leftPad(String.valueOf(phoneIdx++), 3, '0'));
            UIFormStringInput phone = new UIFormStringInput(
                    PHONE + StringUtils.leftPad(String.valueOf(phoneIdx++), 3, '0'), null, null);
            phone.setHTMLAttribute(HTML_ATTRIBUTE_TITLE, resourceBundle.getString("UIContactSection.label.phones"));
            addUIFormInput(phone.addValidator(ExpressionValidator.class, PHONE_REGEX_EXPRESSION, INVALID_PHONE));
            phoneCount += 2;
        } else if (IM.equals(type)) {
            int imIdx = imCount;
            createUISelectBox(IM_TYPES, IM + StringUtils.leftPad(String.valueOf(imIdx++), 3, '0'));
            UIFormStringInput im = new UIFormStringInput(IM + StringUtils.leftPad(String.valueOf(imIdx++), 3, '0'),
                    null, null);
            im.setHTMLAttribute(HTML_ATTRIBUTE_TITLE, resourceBundle.getString("UIContactSection.label.ims"));
            addUIFormInput(
                    im.addValidator(ExpressionValidator.class, IM_STRINGLENGTH_REGEX_EXPRESSION, INVALID_IM));
            imCount += 2;
        } else if (URL.equals(type)) {
            int urlIdx = urlCount;
            UIFormStringInput websiteTitle = new UIFormStringInput(
                    URL + StringUtils.leftPad(String.valueOf(urlIdx++), 3, '0'), null, WEBSITE_TITLE);
            websiteTitle.setHTMLAttribute(HTML_ATTRIBUTE_TITLE,
                    resourceBundle.getString("UIContactSection.label.websiteTitle"));
            addUIFormInput(websiteTitle);
            UIFormStringInput sampleUrlForm = new UIFormStringInput(
                    URL + StringUtils.leftPad(String.valueOf(urlIdx++), 3, '0'), null, null);
            sampleUrlForm.setHTMLAttribute(HTML_ATTRIBUTE_TITLE,
                    resourceBundle.getString("UIContactSection.label.urls"));
            sampleUrlForm.setHTMLAttribute(HTML_ATTRIBUTE_PLACEHOLDER, getSampleURL());
            addUIFormInput(
                    sampleUrlForm.addValidator(ExpressionValidator.class, URL_REGEX_EXPRESSION, INVALID_URL));
            urlCount += 2;
        }
    }

    /**
     * Creates UISelectBox with name and values.
     *
     * @param values Array of value for setting.
     *
     * @param uiName Name of component.
     */
    private void createUISelectBox(final String[] values, final String uiName) {
        List<SelectItemOption<String>> options = new ArrayList<SelectItemOption<String>>();
        for (String value : values) {
            options.add(new SelectItemOption<String>(value));
        }
        addUIFormInput(new UIFormSelectBox(uiName, null, options));
    }

    /**
     * Sorts a list in increase order of alphabet.<br>
     *
     * @param lstComps List for sorting.
     *
     * @return A sorted array in increase order.
     */
    private List<UIComponent> sort(final List<UIComponent> lstComps) {
        Collections.sort(lstComps, new UiComponentComparator());
        return lstComps;
    }

    /**
     *   Implement UiComponentComparator class for sorting in increase order of alphabet.<br>
     *
     */
    private static class UiComponentComparator implements Comparator<UIComponent> {
        /**
         * Compare 2 uicomponent by id
         */
        public int compare(final UIComponent uicomp1, final UIComponent uicomp2) {
            return uicomp1.getId().compareToIgnoreCase(uicomp2.getId());
        }
    }

    /**
     * Sort a list in increase order of length.<br>
     *
     * @param lstComps List for sorting.
     * @return A sorted array in increase order.
     */
    private List<UIComponent> sortSubList(final List<UIComponent> lstComps) {
        Collections.sort(lstComps, new UiComponentComparator());
        return lstComps;
    }
}