001: /*
002: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
003: *
004: * "The contents of this file are subject to the Mozilla Public License
005: * Version 1.1 (the "License"); you may not use this file except in
006: * compliance with the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
011: * License for the specific language governing rights and limitations under
012: * the License.
013: *
014: * The Original Code is ICEfaces 1.5 open source software code, released
015: * November 5, 2006. The Initial Developer of the Original Code is ICEsoft
016: * Technologies Canada, Corp. Portions created by ICEsoft are Copyright (C)
017: * 2004-2006 ICEsoft Technologies Canada, Corp. All Rights Reserved.
018: *
019: * Contributor(s): _____________________.
020: *
021: * Alternatively, the contents of this file may be used under the terms of
022: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"
023: * License), in which case the provisions of the LGPL License are
024: * applicable instead of those above. If you wish to allow use of your
025: * version of this file only under the terms of the LGPL License and not to
026: * allow others to use your version of this file under the MPL, indicate
027: * your decision by deleting the provisions above and replace them with
028: * the notice and other provisions required by the LGPL License. If you do
029: * not delete the provisions above, a recipient may use your version of
030: * this file under either the MPL or the LGPL License."
031: *
032: */
033: /* Original copyright
034: * Copyright 2004 The Apache Software Foundation.
035: *
036: * Licensed under the Apache License, Version 2.0 (the "License");
037: * you may not use this file except in compliance with the License.
038: * You may obtain a copy of the License at
039: *
040: * http://www.apache.org/licenses/LICENSE-2.0
041: *
042: * Unless required by applicable law or agreed to in writing, software
043: * distributed under the License is distributed on an "AS IS" BASIS,
044: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
045: * See the License for the specific language governing permissions and
046: * limitations under the License.
047: */
048: package com.icesoft.faces.component.util;
049:
050: import com.icesoft.faces.renderkit.dom_html_basic.FormRenderer;
051: import org.apache.commons.logging.Log;
052: import org.apache.commons.logging.LogFactory;
053:
054: import javax.faces.FacesException;
055: import javax.faces.component.EditableValueHolder;
056: import javax.faces.component.NamingContainer;
057: import javax.faces.component.UIComponent;
058: import javax.faces.component.UIForm;
059: import javax.faces.component.UIViewRoot;
060: import javax.faces.component.ValueHolder;
061: import javax.faces.component.html.HtmlInputText;
062: import javax.faces.context.FacesContext;
063: import javax.faces.convert.Converter;
064: import javax.faces.el.PropertyNotFoundException;
065: import java.io.IOException;
066: import java.util.Date;
067: import java.util.HashSet;
068: import java.util.Iterator;
069: import java.util.Map;
070: import java.util.Set;
071: import java.util.StringTokenizer;
072:
073: public class CustomComponentUtils {
074:
075: private static final String HIDDEN_COMMAND_INPUTS_SET_ATTR = FormRenderer.class
076: .getName()
077: + ".HIDDEN_COMMAND_INPUTS_SET";
078: public static final String HIDDEN_COMMANDLINK_FIELD_NAME = "_link_hidden_";
079: public static final String FOOTER_CLASS_ATTR = "footerClass";
080: public static final String HEADER_CLASS_ATTR = "headerClass";
081: public static final String[] EMPTY_STRING_ARRAY = new String[0];
082: public static final String EMPTY_STRING = new String();
083: private static final String HIDDEN_TREE_NAV_FIELD_NAME = "_idtn";
084: private static final String HIDDEN_TREE_ACTION_FIELD_NAME = "_idta";
085: private static final Log log = LogFactory
086: .getLog(CustomComponentUtils.class);
087:
088: public static void restoreAncestorState(UIComponent uiComponent) {
089: uiComponent.setId(uiComponent.getId());
090: if ((uiComponent = uiComponent.getParent()) != null) {
091: restoreAncestorState(uiComponent);
092: }
093: }
094:
095: public static void restoreDescendentState(UIComponent uiComponent) {
096: uiComponent.setId(uiComponent.getId());
097: Iterator it = uiComponent.getFacetsAndChildren();
098: while (it.hasNext()) {
099: UIComponent next = (UIComponent) it.next();
100: restoreDescendentState(next);
101: }
102: }
103:
104: public static String getStringValue(FacesContext facesContext,
105: UIComponent component) {
106: try {
107: if (!(component instanceof ValueHolder)) {
108: throw new IllegalArgumentException("Component : "
109: + getPathToComponent(component)
110: + "is not a ValueHolder");
111: }
112:
113: if (component instanceof EditableValueHolder) {
114: Object submittedValue = ((EditableValueHolder) component)
115: .getSubmittedValue();
116: if (submittedValue != null) {
117: if (submittedValue instanceof String) {
118: return (String) submittedValue;
119: } else {
120: throw new IllegalArgumentException(
121: "Expected submitted value of type String for component : "
122: + getPathToComponent(component));
123: }
124: }
125: }
126:
127: Object value = ((ValueHolder) component).getValue();
128:
129: Converter converter = ((ValueHolder) component)
130: .getConverter();
131: if (converter == null && value != null) {
132: if (value instanceof String) {
133: return (String) value;
134: }
135:
136: try {
137: converter = facesContext.getApplication()
138: .createConverter(value.getClass());
139: } catch (FacesException e) {
140:
141: log.error("No converter for class "
142: + value.getClass().getName()
143: + " found (component id="
144: + component.getId() + ").", e);
145: // converter stays null
146: }
147: }
148:
149: if (converter == null) {
150: if (value == null) {
151: return "";
152: } else {
153: return value.toString();
154: }
155: } else {
156: return converter.getAsString(facesContext, component,
157: value);
158: }
159: } catch (PropertyNotFoundException ex) {
160: log.error("Property not found - called by component : "
161: + getPathToComponent(component), ex);
162: throw ex;
163: }
164: }
165:
166: public static String getPathToComponent(UIComponent component) {
167: StringBuffer buf = new StringBuffer();
168:
169: if (component == null) {
170: buf.append("{Component-Path : ");
171: buf.append("[null]}");
172: return buf.toString();
173: }
174:
175: getPathToComponent(component, buf);
176:
177: buf.insert(0, "{Component-Path : ");
178: buf.append("}");
179:
180: return buf.toString();
181: }
182:
183: private static void getPathToComponent(UIComponent component,
184: StringBuffer buf) {
185: if (component == null) {
186: return;
187: }
188:
189: StringBuffer intBuf = new StringBuffer();
190:
191: intBuf.append("[Class: ");
192: intBuf.append(component.getClass().getName());
193: if (component instanceof UIViewRoot) {
194: intBuf.append(",ViewId: ");
195: intBuf.append(((UIViewRoot) component).getViewId());
196: } else {
197: intBuf.append(",Id: ");
198: intBuf.append(component.getId());
199: }
200: intBuf.append("]");
201:
202: //intBuf.toString for non-1.4 JDK 1.5 compiler output
203: buf.insert(0, intBuf.toString());
204:
205: if (component != null) {
206: getPathToComponent(component.getParent(), buf);
207: }
208: }
209:
210: public static void addHiddenCommandParameter(UIComponent form,
211: String paramName) {
212: Set set = (Set) form.getAttributes().get(
213: HIDDEN_COMMAND_INPUTS_SET_ATTR);
214: if (set == null) {
215: set = new HashSet();
216: form.getAttributes().put(HIDDEN_COMMAND_INPUTS_SET_ATTR,
217: set);
218: }
219: set.add(paramName);
220: }
221:
222: public static String getHiddenCommandLinkFieldName(String formName) {
223: return formName + NamingContainer.SEPARATOR_CHAR
224: + HIDDEN_COMMANDLINK_FIELD_NAME;
225: }
226:
227: public static String getHiddenTreeExpandFieldName(
228: String componentId, String formName) {
229: return formName + NamingContainer.SEPARATOR_CHAR + componentId
230: + HIDDEN_TREE_NAV_FIELD_NAME;
231: }
232:
233: public static String getHiddenTreeActionFieldName(
234: String componentId, String formName) {
235: return formName + NamingContainer.SEPARATOR_CHAR + componentId
236: + HIDDEN_TREE_ACTION_FIELD_NAME;
237: }
238:
239: public static String getFormName(UIComponent component,
240: FacesContext context) {
241: //Find form
242: UIComponent parent = component.getParent();
243: while (parent != null && !(parent instanceof UIForm)) {
244: parent = parent.getParent();
245: }
246:
247: if (parent != null) {
248: //link is nested inside a form
249: return ((UIForm) parent).getClientId(context);
250: }
251: return "this";
252: }
253:
254: /**
255: * Split a string into an array of strings arround a character separator.
256: * This function will be efficient for short strings, for longer strings,
257: * another approach may be better
258: *
259: * @param str the string to be split
260: * @param separator the separator character
261: * @return array of string subparts
262: */
263: public static String[] splitShortString(String str, char separator) {
264: int len;
265: if (str == null || (len = str.length()) == 0) {
266: return EMPTY_STRING_ARRAY;
267: }
268:
269: int lastTokenIndex = 0;
270:
271: // Step 1: how many substrings?
272: // We exchange double scan time for less memory allocation
273: for (int pos = str.indexOf(separator); pos >= 0; pos = str
274: .indexOf(separator, pos + 1)) {
275: lastTokenIndex++;
276: }
277:
278: // Step 2: allocate exact size array
279: String[] list = new String[lastTokenIndex + 1];
280:
281: int oldPos = 0;
282:
283: // Step 3: retrieve substrings
284: for (int pos = str.indexOf(separator), i = 0; pos >= 0; pos = str
285: .indexOf(separator, (oldPos = (pos + 1)))) {
286: list[i++] = substring(str, oldPos, pos);
287: }
288:
289: list[lastTokenIndex] = substring(str, oldPos, len);
290:
291: return list;
292: }
293:
294: public static String substring(String str, int begin, int end) {
295: if (begin == end) {
296: return "";
297: }
298:
299: return str.substring(begin, end);
300: }
301:
302: public static String[] trim(String[] strings) {
303: if (strings == null) {
304: return null;
305: }
306:
307: for (int i = 0, len = strings.length; i < len; i++) {
308: strings[i] = strings[i].trim();
309: }
310:
311: return strings;
312: }
313:
314: public static void renderChildren(FacesContext facesContext,
315: UIComponent component) throws IOException {
316: if (component.getChildCount() > 0) {
317: for (Iterator it = component.getChildren().iterator(); it
318: .hasNext();) {
319: UIComponent child = (UIComponent) it.next();
320: renderChild(facesContext, child);
321: }
322: }
323: }
324:
325: public static void renderChild(FacesContext facesContext,
326: UIComponent child) throws IOException {
327: if (!child.isRendered()) {
328: return;
329: }
330:
331: child.encodeBegin(facesContext);
332: if (child.getRendersChildren()) {
333: child.encodeChildren(facesContext);
334: } else {
335: renderChildren(facesContext, child);
336: }
337: child.encodeEnd(facesContext);
338: }
339:
340: /**
341: * Gets the comma separated list of visibility user roles from the given
342: * component and checks if current user is in one of these roles.
343: *
344: * @param component a user role aware component
345: * @return true if no user roles are defined for this component or user is
346: * in one of these roles, false otherwise
347: */
348: public static boolean isVisibleOnUserRole(UIComponent component) {
349: String userRole;
350: if (component instanceof UserRoleAware) {
351: userRole = ((UserRoleAware) component)
352: .getVisibleOnUserRole();
353: } else {
354: userRole = (String) component.getAttributes().get(
355: UserRoleAware.VISIBLE_ON_USER_ROLE_ATTR);
356: }
357:
358: if (userRole == null) {
359: // no restriction
360: return true;
361: }
362:
363: FacesContext facesContext = FacesContext.getCurrentInstance();
364: StringTokenizer st = new StringTokenizer(userRole, ",");
365: while (st.hasMoreTokens()) {
366: if (facesContext.getExternalContext().isUserInRole(
367: st.nextToken().trim())) {
368: return true;
369: }
370: }
371: return false;
372: }
373:
374: /**
375: * Gets the comma separated list of enabling user roles from the given
376: * component and checks if current user is in one of these roles.
377: *
378: * @param component a user role aware component
379: * @return true if no user roles are defined for this component or user is
380: * in one of these roles, false otherwise
381: */
382: public static boolean isEnabledOnUserRole(UIComponent component) {
383: String userRole;
384: if (component instanceof UserRoleAware) {
385: userRole = ((UserRoleAware) component)
386: .getEnabledOnUserRole();
387: } else {
388: userRole = (String) component.getAttributes().get(
389: UserRoleAware.ENABLED_ON_USER_ROLE_ATTR);
390: }
391:
392: if (userRole == null) {
393: // no restriction
394: return true;
395: }
396:
397: FacesContext facesContext = FacesContext.getCurrentInstance();
398: StringTokenizer st = new StringTokenizer(userRole, ",");
399: while (st.hasMoreTokens()) {
400: if (facesContext.getExternalContext().isUserInRole(
401: st.nextToken().trim())) {
402: return true;
403: }
404: }
405: return false;
406: }
407:
408: public static Object newInstance(Class clazz) throws FacesException {
409: try {
410: return clazz.newInstance();
411: } catch (NoClassDefFoundError e) {
412: throw new FacesException(e);
413: } catch (InstantiationException e) {
414: throw new FacesException(e);
415: } catch (IllegalAccessException e) {
416: throw new FacesException(e);
417: }
418: }
419:
420: /**
421: * Same as {@link #classForName(String)}, but throws a RuntimeException
422: * (FacesException) instead of a ClassNotFoundException.
423: *
424: * @return the corresponding Class
425: * @throws NullPointerException if type is null
426: * @throws FacesException if class not found
427: */
428: public static Class simpleClassForName(String type) {
429: try {
430: return classForName(type);
431: } catch (ClassNotFoundException e) {
432: throw new FacesException(e);
433: }
434: }
435:
436: public static Object newInstance(String type) throws FacesException {
437: if (type == null) {
438: return null;
439: }
440: return newInstance(simpleClassForName(type));
441: }
442:
443: /**
444: * Tries a Class.forName with the context class loader of the current thread
445: * first and automatically falls back to the ClassUtils class loader (i.e.
446: * the loader of the myfaces.jar lib) if necessary.
447: *
448: * @param type fully qualified name of a non-primitive non-array class
449: * @return the corresponding Class
450: * @throws NullPointerException if type is null
451: * @throws ClassNotFoundException
452: */
453: public static Class classForName(String type)
454: throws ClassNotFoundException {
455: if (type == null) {
456: throw new NullPointerException("type");
457: }
458: try {
459: // Try WebApp ClassLoader first
460: return Class.forName(type, false, // do not initialize for faster startup
461: Thread.currentThread().getContextClassLoader());
462: } catch (ClassNotFoundException ignore) {
463: // fallback: Try ClassLoader for ClassUtils (i.e. the myfaces.jar lib)
464: return Class.forName(type, false, // do not initialize for faster startup
465: CustomComponentUtils.class.getClassLoader());
466: }
467: }
468:
469: public static boolean isDisabledOrReadOnly(UIComponent component) {
470: return isTrue(component.getAttributes().get("disabled"))
471: || isTrue(component.getAttributes().get("readOnly"));
472: }
473:
474: private static boolean isTrue(Object obj) {
475: if (!(obj instanceof Boolean)) {
476: return false;
477: }
478:
479: return ((Boolean) obj).booleanValue();
480: }
481:
482: public static void decodeUIInput(FacesContext facesContext,
483: UIComponent component) {
484: if (!(component instanceof EditableValueHolder)) {
485: throw new IllegalArgumentException("Component "
486: + component.getClientId(facesContext)
487: + " is not an EditableValueHolder");
488: }
489: Map paramMap = facesContext.getExternalContext()
490: .getRequestParameterMap();
491: String clientId = component.getClientId(facesContext);
492: if (paramMap.containsKey(clientId)) {
493: //request parameter found, set submittedValue
494: ((EditableValueHolder) component)
495: .setSubmittedValue(paramMap.get(clientId));
496: } else {
497: //request parameter not found, nothing to decode - set submitted value to empty
498: //if the component has not been disabled
499: if (!isDisabledOrReadOnly(component)) {
500: ((EditableValueHolder) component)
501: .setSubmittedValue(EMPTY_STRING);
502: }
503: }
504: }
505:
506: public static Date getDateValue(UIComponent component) {
507: if (!(component instanceof ValueHolder)) {
508: throw new IllegalArgumentException("Component : "
509: + getPathToComponent(component)
510: + "is not a ValueHolder");
511: }
512:
513: if (component instanceof EditableValueHolder) {
514: Object submittedValue = ((EditableValueHolder) component)
515: .getSubmittedValue();
516: if (submittedValue != null) {
517: if (submittedValue instanceof Date) {
518: return (Date) submittedValue;
519: } else {
520: throw new IllegalArgumentException(
521: "Expected submitted value of type Date for component : "
522: + getPathToComponent(component));
523: }
524: }
525: }
526:
527: Object value = ((ValueHolder) component).getValue();
528:
529: if (value == null || value instanceof Date) {
530: return (Date) value;
531: } else {
532: throw new IllegalArgumentException(
533: "Expected submitted value of type Date for component : "
534: + getPathToComponent(component));
535: }
536: }
537:
538: public static void copyHtmlInputTextAttributes(HtmlInputText src,
539: HtmlInputText dest) {
540: dest.setId(src.getId());
541: dest.setImmediate(src.isImmediate());
542: dest.setTransient(src.isTransient());
543: dest.setAccesskey(src.getAccesskey());
544: dest.setAlt(src.getAlt());
545: dest.setConverter(src.getConverter());
546: dest.setDir(src.getDir());
547: dest.setDisabled(src.isDisabled());
548: dest.setLang(src.getLang());
549: dest.setLocalValueSet(src.isLocalValueSet());
550: dest.setMaxlength(src.getMaxlength());
551: dest.setOnblur(src.getOnblur());
552: dest.setOnchange(src.getOnchange());
553: dest.setOnclick(src.getOnclick());
554: dest.setOndblclick(src.getOndblclick());
555: dest.setOnfocus(src.getOnfocus());
556: dest.setOnkeydown(src.getOnkeydown());
557: dest.setOnkeypress(src.getOnkeypress());
558: dest.setOnkeyup(src.getOnkeyup());
559: dest.setOnmousedown(src.getOnmousedown());
560: dest.setOnmousemove(src.getOnmousemove());
561: dest.setOnmouseout(src.getOnmouseout());
562: dest.setOnmouseover(src.getOnmouseover());
563: dest.setOnmouseup(src.getOnmouseup());
564: dest.setOnselect(src.getOnselect());
565: dest.setReadonly(src.isReadonly());
566: dest.setRendered(src.isRendered());
567: dest.setRequired(src.isRequired());
568: dest.setSize(src.getSize());
569: dest.setStyle(src.getStyle());
570: dest.setStyleClass(src.getStyleClass());
571: dest.setTabindex(src.getTabindex());
572: dest.setTitle(src.getTitle());
573: dest.setValidator(src.getValidator());
574: }
575:
576: }
|