001: /***************************************************************
002: * This file is part of the [fleXive](R) project.
003: *
004: * Copyright (c) 1999-2007
005: * UCS - unique computing solutions gmbh (http://www.ucs.at)
006: * All rights reserved
007: *
008: * The [fleXive](R) project is free software; you can redistribute
009: * it and/or modify it under the terms of the GNU General Public
010: * License as published by the Free Software Foundation;
011: * either version 2 of the License, or (at your option) any
012: * later version.
013: *
014: * The GNU General Public License can be found at
015: * http://www.gnu.org/copyleft/gpl.html.
016: * A copy is found in the textfile GPL.txt and important notices to the
017: * license from the author are found in LICENSE.txt distributed with
018: * these libraries.
019: *
020: * This library is distributed in the hope that it will be useful,
021: * but WITHOUT ANY WARRANTY; without even the implied warranty of
022: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
023: * GNU General Public License for more details.
024: *
025: * For further information about UCS - unique computing solutions gmbh,
026: * please see the company website: http://www.ucs.at
027: *
028: * For further information about [fleXive](R), please see the
029: * project website: http://www.flexive.org
030: *
031: *
032: * This copyright notice MUST APPEAR in all copies of the file!
033: ***************************************************************/package com.flexive.faces;
034:
035: import com.flexive.faces.beans.MessageBean;
036: import com.flexive.faces.messages.FxFacesMessage;
037: import com.flexive.faces.messages.FxFacesMessages;
038: import com.flexive.shared.*;
039: import com.flexive.shared.exceptions.FxNotFoundException;
040: import com.flexive.shared.exceptions.FxInvalidParameterException;
041: import com.flexive.shared.exceptions.FxApplicationException;
042: import com.flexive.shared.scripting.FxScriptInfo;
043: import com.flexive.shared.security.UserTicket;
044: import com.flexive.shared.structure.FxSelectList;
045: import com.flexive.shared.structure.FxSelectListItem;
046: import com.flexive.shared.structure.FxMultiplicity;
047: import com.flexive.war.FxRequest;
048: import com.flexive.war.filter.FxResponseWrapper;
049: import com.sun.facelets.tag.jsf.ComponentSupport;
050: import org.ajax4jsf.renderkit.AjaxContainerRenderer;
051: import org.apache.commons.lang.StringUtils;
052: import org.apache.commons.logging.Log;
053: import org.apache.commons.logging.LogFactory;
054:
055: import javax.el.ValueExpression;
056: import javax.faces.application.Application;
057: import javax.faces.application.FacesMessage;
058: import javax.faces.component.UIComponent;
059: import javax.faces.component.UIViewRoot;
060: import javax.faces.context.FacesContext;
061: import static javax.faces.context.FacesContext.getCurrentInstance;
062: import javax.faces.model.SelectItem;
063: import javax.servlet.ServletContext;
064: import javax.servlet.http.HttpServletRequestWrapper;
065: import javax.servlet.http.HttpServletResponseWrapper;
066: import javax.servlet.http.HttpSession;
067: import java.io.Serializable;
068: import java.text.Collator;
069: import java.util.*;
070:
071: /**
072: * Utility class for JSF functionality within beans.
073: *
074: * @author Gregor Schober (gregor.schober@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
075: * @version $Rev: 225 $
076: */
077: public class FxJsfUtils {
078: private static final Log LOG = LogFactory.getLog(FxJsfUtils.class);
079: private static final String JSON_RPC_SERVLET = "/adm/JSON-RPC";
080: private final static String BRACKET_OPEN = "__-";
081: private final static String BRACKET_CLOSE = "_-_";
082: private final static String SLASH = "-__";
083:
084: /**
085: * Encode identifier to be valid for JSF components
086: *
087: * @param identifier id to encode
088: * @return encoded id
089: */
090: public static String encodeJSFIdentifier(String identifier) {
091: // We may only use '-' and '_' characters to encode JSF identifiers
092: identifier = identifier.replaceAll("/", SLASH);
093: identifier = identifier.replaceAll("\\[", BRACKET_OPEN);
094: identifier = identifier.replaceAll("]", BRACKET_CLOSE);
095: return identifier;
096: }
097:
098: /**
099: * Decode a JSF identifier created by encodeJSFIdentifier
100: *
101: * @param identifier id to decode
102: * @return decoded id
103: */
104: public static String decodeJSFIdentifier(String identifier) {
105: return identifier.replaceAll(BRACKET_CLOSE, "]").replace(SLASH,
106: "/").replace(BRACKET_OPEN, "[");
107: }
108:
109: private static class EmptySelectableObjectWithName extends
110: AbstractSelectableObjectWithName implements Serializable {
111: private static final long serialVersionUID = 7808775494956188839L;
112:
113: public EmptySelectableObjectWithName() {
114: // nothing
115: }
116:
117: public long getId() {
118: return -1;
119: }
120:
121: public String getName() {
122: return "";
123: }
124: }
125:
126: /**
127: * Private constructor to avoid instantiation
128: */
129: private FxJsfUtils() {
130: }
131:
132: /**
133: * Get managed beans based on the beans name.
134: *
135: * @param beanName the beans name
136: * @return the managed beans associated with the beans name
137: */
138: public static Object getManagedBean(String beanName) {
139: return getValueExpression(getJsfEl(beanName)).getValue(
140: getCurrentInstance().getELContext());
141: }
142:
143: /**
144: * Returns the managed beans of the given class. Works only for flexive beans that
145: * have the full class name and a "fx" prefix by convention. For example,
146: * the ContentEditorBean is registered with JSF as "fxContentEditorBean".
147: *
148: * @param beanClass the beans class
149: * @return the managed beans of the given class, or null if none exists
150: */
151: public static <T> T getManagedBean(Class<T> beanClass) {
152: return beanClass.cast(getManagedBean("fx"
153: + beanClass.getSimpleName()));
154: }
155:
156: /**
157: * Remove the managed beans based on the beans name.
158: *
159: * @param beanName the beans name of the managed beans to be removed
160: */
161: public static void resetManagedBean(String beanName) {
162: getValueExpression(getJsfEl(beanName)).setValue(
163: getCurrentInstance().getELContext(), null);
164: }
165:
166: /**
167: * Replace the managed beans based on the beans name.
168: *
169: * @param beanName the beans name of the managed beans to be replaced
170: * @param bean the new beans
171: */
172: public static void replaceManagedBean(String beanName, Object bean) {
173: getValueExpression(getJsfEl(beanName)).setValue(
174: getCurrentInstance().getELContext(), bean);
175: }
176:
177: /**
178: * Store the managed beans inside the session scope.
179: *
180: * @param beanName the name of the managed beans to be stored
181: * @param managedBean the managed beans to be stored
182: */
183: public static void setManagedBeanInSession(String beanName,
184: Object managedBean) {
185: //noinspection unchecked
186: Map<String, Object> map = getCurrentInstance()
187: .getExternalContext().getSessionMap();
188: map.put(beanName, managedBean);
189: }
190:
191: /**
192: * Get parameter value from request scope.
193: *
194: * @param name the name of the parameter
195: * @return the parameter value
196: */
197: public static String getRequestParameter(String name) {
198: return getCurrentInstance().getExternalContext()
199: .getRequestParameterMap().get(name);
200: }
201:
202: /**
203: * Evaluate the value of a JSF expression.
204: *
205: * @param el the JSF expression
206: * @return the integer value associated with the JSF expression
207: */
208: public static Object evalObject(String el) {
209: if (el == null) {
210: return null;
211: }
212: return isValueReference(el) ? getElValue(el) : el;
213: }
214:
215: /**
216: * <a href="http://issues.apache.org/struts/browse/SHALE-305">Source: SHALE-305.</a><br/>
217: * Return true if the specified string contains an EL expression.
218: * <p/>
219: * This is taken almost verbatim from javax.faces.webapp.UIComponentTag
220: * in order to remove JSP dependencies from the renderers.
221: *
222: * @param value the expression to be checked
223: * @return true if the given value contains an EL expression
224: */
225: public static boolean isValueReference(String value) {
226: if (value == null)
227: return false;
228:
229: int start = value.indexOf("#{");
230: if (start < 0)
231: return false;
232:
233: int end = value.lastIndexOf('}');
234: return (end >= 0 && start < end);
235: }
236:
237: /**
238: * Evaluate the integer value of a JSF expression.
239: *
240: * @param el the JSF expression
241: * @return the integer value associated with the JSF expression
242: */
243: public static Integer evalInt(String el) {
244: if (el == null) {
245: return null;
246: }
247: Object value = evalObject(el);
248:
249: if (value instanceof Integer) {
250: return (Integer) value;
251: } else {
252: return new Integer(value.toString());
253: }
254: }
255:
256: /**
257: * Evaluate the string value of a JSF expression.
258: *
259: * @param el the JSF expression
260: * @return the string value associated with the JSF expression
261: */
262: public static String evalString(String el) {
263: if (el == null) {
264: return null;
265: }
266: Object value = evalObject(el);
267:
268: if (value instanceof String) {
269: return (String) value;
270: } else {
271: return value.toString();
272: }
273: }
274:
275: public static Application getApplication() {
276: return getCurrentInstance().getApplication();
277: }
278:
279: private static ValueExpression getValueExpression(String el) {
280: return getApplication().getExpressionFactory()
281: .createValueExpression(
282: getCurrentInstance().getELContext(), el,
283: Object.class);
284: }
285:
286: private static Object getElValue(String el) {
287: return getValueExpression(el).getValue(
288: getCurrentInstance().getELContext());
289: }
290:
291: private static String getJsfEl(String value) {
292: return "#{" + value + "}";
293: }
294:
295: /**
296: * Gets the id of the given parameter name.
297: *
298: * @param parameterName the parameter name
299: * @return the id
300: */
301: public static long getId(String parameterName) {
302: String valueText = null;
303: try {
304: valueText = FacesContext.getCurrentInstance()
305: .getExternalContext().getRequestParameterMap().get(
306: parameterName);
307: return new Long(valueText);
308: } catch (NumberFormatException e) {
309: throw new IllegalArgumentException("Couldn't parse '"
310: + parameterName + "'='" + valueText + "' as a long");
311: }
312: }
313:
314: public static void setSessionAttribute(String key, Object value) {
315: //noinspection unchecked
316: FacesContext.getCurrentInstance().getExternalContext()
317: .getSessionMap().put(key, value);
318: }
319:
320: public static Object getSessionAttribute(String key) {
321: return FacesContext.getCurrentInstance().getExternalContext()
322: .getSessionMap().get(key);
323: }
324:
325: public static void removeSessionAttribute(String key) {
326: FacesContext.getCurrentInstance().getExternalContext()
327: .getSessionMap().remove(key);
328: }
329:
330: public static String getParameter(String name) {
331: return FacesContext.getCurrentInstance().getExternalContext()
332: .getRequestParameterMap().get(name);
333: }
334:
335: public static long getLongParameter(String name, long defaultValue) {
336: return Long.valueOf(StringUtils.defaultString(
337: getParameter(name), String.valueOf(defaultValue)));
338: }
339:
340: public static boolean hasParameter(String name) {
341: String s = getParameter(name);
342: return s != null && s.length() > 0;
343: }
344:
345: public static long getLongParameter(String name) {
346: return Long.valueOf(getParameter(name));
347: }
348:
349: public static int getIntParameter(String name, int defaultValue) {
350: return Integer.valueOf(StringUtils.defaultString(
351: getParameter(name), String.valueOf(defaultValue)));
352: }
353:
354: public static int getIntParameter(String name) {
355: return Integer.valueOf(getParameter(name));
356: }
357:
358: public static boolean getBooleanParameter(String name,
359: boolean defaultValue) {
360: return Boolean.valueOf(StringUtils.defaultString(
361: getParameter(name), String.valueOf(defaultValue)));
362: }
363:
364: public static boolean getBooleanParameter(String name) {
365: return Boolean.valueOf(getParameter(name));
366: }
367:
368: /**
369: * Returns the servlet context.
370: * <p/>
371: * The result is null if no faces context or external context is available.
372: *
373: * @return the servlet context
374: */
375: public static ServletContext getServletContext() {
376: try {
377: return (ServletContext) getCurrentInstance()
378: .getExternalContext().getContext();
379: } catch (Throwable t) {
380: return null;
381: }
382:
383: }
384:
385: /**
386: * Gets the session from the faces context.
387: * <p/>
388: * The result is null if no faces context is available.
389: *
390: * @return the session from the faces context
391: */
392: public static HttpSession getSession() {
393: try {
394: return (HttpSession) getCurrentInstance()
395: .getExternalContext().getSession(false);
396: } catch (Throwable t) {
397: return null;
398: }
399: }
400:
401: /**
402: * Gets the request from the faces context.
403: * <p/>
404: * The result is null if no faces context is available.
405: *
406: * @return the request from the faces context
407: */
408: public static FxRequest getRequest() {
409: try {
410: HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) getCurrentInstance()
411: .getExternalContext().getRequest();
412: while (wrapper != null && !(wrapper instanceof FxRequest)) {
413: wrapper = (HttpServletRequestWrapper) wrapper
414: .getRequest();
415: }
416: return (FxRequest) wrapper;
417: } catch (Throwable t) {
418: return null;
419: }
420: }
421:
422: /**
423: * Gets the response from the faces context.
424: * <p/>
425: * The result is null if no faces context is available.
426: *
427: * @return the response from the faces context
428: */
429: public static FxResponseWrapper getResponse() {
430: HttpServletResponseWrapper resp = (HttpServletResponseWrapper) getCurrentInstance()
431: .getExternalContext().getResponse();
432: FxResponseWrapper fresp;
433: if (resp instanceof FxResponseWrapper) {
434: fresp = (FxResponseWrapper) resp;
435: } else {
436: fresp = (FxResponseWrapper) resp.getResponse();
437: }
438: return fresp;
439: }
440:
441: /**
442: * Returns the URI of the JSON/RPC servlet
443: *
444: * @return the URI of the JSON/RPC servlet
445: */
446: public static String getJsonServletUri() {
447: return getRequest().getContextPath() + JSON_RPC_SERVLET;
448: }
449:
450: /**
451: * Return the localized message for the given key and replace all parameters with the given args.
452: *
453: * @param messageKey key of the message to be translated
454: * @param args optional arguments to be replaced in the message
455: * @return the localized message
456: */
457: public static String getLocalizedMessage(String messageKey,
458: Object... args) {
459: return MessageBean.getInstance().getMessage(messageKey, args);
460: }
461:
462: public static void addMessage(FacesMessage message) {
463: getCurrentInstance().addMessage(null, message);
464: }
465:
466: /**
467: * Clears all faces messages (optional: for the given client id).
468: *
469: * @param clientId the client id to work on, or null to remove all messages.
470: */
471: @SuppressWarnings("unchecked")
472: public static void clearAllMessages(String clientId) {
473: //noinspection unchecked
474: Iterator<FacesMessage> it = (clientId == null || clientId
475: .length() == 0) ? getCurrentInstance().getMessages()
476: : getCurrentInstance().getMessages(clientId);
477: while (it.hasNext()) {
478: it.next();
479: it.remove();
480: }
481: }
482:
483: /**
484: * Gets all faces messages (optional: for the given client id).
485: *
486: * @param clientId the client id to work on, or null to remove all messages.
487: * @return a array holding all messages
488: */
489: @SuppressWarnings("unchecked")
490: public static ArrayList<FacesMessage> getMessages(String clientId) {
491: ArrayList<FacesMessage> result = new ArrayList<FacesMessage>(25);
492: try {
493: //noinspection unchecked
494: Iterator<FacesMessage> it = (clientId == null || clientId
495: .length() == 0) ? getCurrentInstance()
496: .getMessages() : getCurrentInstance().getMessages(
497: clientId);
498:
499: while (it.hasNext()) {
500: result.add(it.next());
501: }
502: } catch (Throwable t) {
503: result.add(new FacesMessage(
504: "Failed to build message list: " + t.getMessage()));
505: }
506: result.trimToSize();
507: return result;
508: }
509:
510: /**
511: * Gets all faces messages wrapped as FxFacesMessage (which gives access to the clientId)
512: *
513: * @return a array holding all messages
514: */
515: @SuppressWarnings("unchecked")
516: public static ArrayList<FxFacesMessage> getFxMessages() {
517: final FacesContext ctx = getCurrentInstance();
518:
519: // Get all messages belonging to an specific client id
520: Iterator it = ctx.getClientIdsWithMessages();
521: ArrayList<FxFacesMessage> result = new ArrayList<FxFacesMessage>(
522: 5);
523: while (it.hasNext()) {
524: String clientId = String.valueOf(it.next());
525: //noinspection unchecked
526: Iterator<FacesMessage> msgs = ctx.getMessages(clientId);
527: while (msgs.hasNext()) {
528: FacesMessage msg = msgs.next();
529: if (!(msg instanceof FxFacesMessage)) {
530: msg = new FxFacesMessage(msg, clientId);
531: }
532: result.add((FxFacesMessage) msg);
533: }
534: }
535:
536: // get all messages that are not linked to an client
537: it = ctx.getMessages();
538: while (it.hasNext()) {
539: FacesMessage msg = (FacesMessage) it.next();
540: // Add the message, but only if it doesnt exist already with a filled in form/client id
541: if (!messageExists(result, msg)) {
542: if (!(msg instanceof FxFacesMessage)) {
543: msg = new FxFacesMessage(msg, null);
544: }
545: result.add((FxFacesMessage) msg);
546: }
547: }
548:
549: // Return the result
550: return result;
551: }
552:
553: private static boolean messageExists(
554: ArrayList<FxFacesMessage> list, FacesMessage msg) {
555: for (FxFacesMessage comp : list) {
556: if (comp.getSeverity() == msg.getSeverity()
557: && comp.getSummary().equals(msg.getSummary())
558: && comp.getDetail().equals(msg.getDetail()))
559: return true;
560: }
561: return false;
562: }
563:
564: /**
565: * Gets all faces messages grouped by a equal summary and wrapped as
566: * FxFacesMessage (which gives access to the clientId). In case of a grouped message
567: * the details of the original FacesMessage can be retrieved by calling getDetails() of
568: * the FxFacesMessage.
569: *
570: * @return a array holding all (grouped) messages
571: */
572: public static List<FxFacesMessages> getGroupedFxMessages() {
573: ArrayList<FxFacesMessage> ffm = getFxMessages();
574: Hashtable<String, FxFacesMessages> grouped = new Hashtable<String, FxFacesMessages>(
575: ffm.size());
576: for (FxFacesMessage msg : ffm) {
577: String key = msg.getSeverity() + ":" + msg.getSummary();
578: FxFacesMessages exists = grouped.get(key);
579: if (exists != null) {
580: exists.addMessage(msg);
581: } else {
582: grouped.put(key, new FxFacesMessages(msg.getSummary(),
583: msg.getSeverity(), msg));
584: }
585: }
586: return new ArrayList<FxFacesMessages>(grouped.values());
587: }
588:
589: /**
590: * Workaround for facelets component tree update problems - deletes
591: * the given component and its children so they can be recreated
592: * when the component tree is rendered again
593: *
594: * @param componentId the complete component ID, e.g. frm:queryEditor
595: */
596: public static void resetFaceletsComponent(String componentId) {
597: if (StringUtils.isBlank(componentId)) {
598: return;
599: }
600: UIViewRoot viewRoot = FacesContext.getCurrentInstance()
601: .getViewRoot();
602: if (viewRoot == null) {
603: return;
604: }
605: try {
606: UIComponent component = viewRoot.findComponent(componentId);
607: if (component != null) {
608: ComponentSupport.markForDeletion(component);
609: ComponentSupport.finalizeForDeletion(component);
610: }
611: } catch (IllegalArgumentException e) {
612: // RI throws IAE when the component isn't found - do nothing
613: }
614: }
615:
616: /**
617: * Find a parent of the given class. Throws a runtime exception if none is found.
618: *
619: * @param component the (child) component that searches an ancestor
620: * @param cls the class or interface to be searched for in the component's ancestors
621: * @return the parent component
622: */
623: public static <T> T findAncestor(UIComponent component, Class<T> cls) {
624: UIComponent current = component;
625: if (current != null) {
626: current = current.getParent();
627: }
628: while (current != null
629: && !(cls.isAssignableFrom(current.getClass()))) {
630: current = current.getParent();
631: }
632: if (current == null) {
633: throw new FxNotFoundException(LOG,
634: "ex.jsf.ancestor.notFound").asRuntimeException();
635: }
636: return cls.cast(current);
637: }
638:
639: /**
640: * Create a new component of the given type.
641: *
642: * @param componentType the component type, e.g. <code>javax.faces.SelectOne</code>
643: * @return the created component
644: */
645: public static UIComponent createComponent(String componentType) {
646: return getApplication().createComponent(componentType);
647: }
648:
649: /**
650: * Add a child component of the given type to the parent component. The child component
651: * is returned to the caller.
652: *
653: * @param parent the parent component
654: * @param componentType child component type, e.g. <code>javax.faces.SelectOne</code>
655: * @return the created child component
656: */
657: public static UIComponent addChildComponent(UIComponent parent,
658: String componentType) {
659: final UIComponent child = createComponent(componentType);
660: parent.getChildren().add(child);
661: return child;
662: }
663:
664: /**
665: * Return true if the current request has been submitted via Ajax4JSF.
666: *
667: * @return true if the current request has been submitted via Ajax4JSF.
668: */
669: public static boolean isAjaxRequest() {
670: return getRequest().getParameterMap().containsKey(
671: AjaxContainerRenderer.AJAX_PARAMETER_NAME);
672: }
673:
674: /**
675: * Recursively search for the first child of the given class type for the component.
676: *
677: * @param component the component to be searched
678: * @param childType the required child type
679: * @return the first child of the given type, or null if no child was found.
680: */
681: public static <T extends UIComponent> T findChild(
682: UIComponent component, Class<T> childType) {
683: for (Object item : component.getChildren()) {
684: final UIComponent child = (UIComponent) item;
685: if (childType.isAssignableFrom(child.getClass())) {
686: return childType.cast(child);
687: }
688: // search in this child's children
689: final T nestedChild = findChild(child, childType);
690: if (nestedChild != null) {
691: return nestedChild;
692: }
693: }
694: return null;
695: }
696:
697: /**
698: * Convert a list of SelectableObjects to JSF SelectItems.
699: *
700: * @param items the items to be converted
701: * @return the given list converted to JSF SelectItems
702: */
703: public static List<SelectItem> asIdSelectList(
704: List<? extends SelectableObjectWithName> items) {
705: final List<SelectItem> result = new ArrayList<SelectItem>(items
706: .size());
707: for (SelectableObjectWithName item : items) {
708: result.add(new SelectItem(item.getId(), item.getName()));
709: }
710: return result;
711: }
712:
713: /**
714: * Convert a list of SelectableObjectWithLabels to JSF SelectItems.
715: *
716: * @param items the items to be converted
717: * @return the given list converted to JSF SelectItems
718: */
719: public static List<SelectItem> asIdSelectListWithLabel(
720: List<? extends SelectableObjectWithLabel> items) {
721: final List<SelectItem> result = new ArrayList<SelectItem>(items
722: .size());
723: for (SelectableObjectWithLabel item : items) {
724: result.add(new SelectItem(item.getId(), item.getLabel()
725: .getBestTranslation()));
726: }
727: return result;
728: }
729:
730: /**
731: * Convert a list of SelectableObjects to JSF SelectItems.
732: *
733: * @param items the items to be converted
734: * @param addEmptyElement if set to true a empty element is added
735: * @return the given list converted to JSF SelectItems
736: */
737: public static List<SelectItem> asSelectList(
738: List<? extends SelectableObjectWithName> items,
739: boolean addEmptyElement) {
740: final List<SelectItem> result = new ArrayList<SelectItem>(items
741: .size()
742: + (addEmptyElement ? 1 : 0));
743: if (addEmptyElement) {
744: result.add(new SelectItem(
745: new EmptySelectableObjectWithName(), ""));
746: }
747: for (SelectableObjectWithName item : items) {
748: result.add(new SelectItem(item, item.getName()));
749: }
750: return result;
751: }
752:
753: /**
754: * Convert the values of an enum to a select list.
755: *
756: * @param values the enum values to be converted
757: * @return the select list backing the given enumeration values.
758: */
759:
760: public static <T extends Enum> List<SelectItem> enumsAsSelectList(
761: T[] values) {
762: final ArrayList<SelectItem> result = new ArrayList<SelectItem>(
763: values.length);
764: for (Enum value : values) {
765: final String label = value instanceof ObjectWithLabel ? ((ObjectWithLabel) value)
766: .getLabel().getBestTranslation()
767: : value.name();
768: result.add(new SelectItem(value, label));
769: }
770: return result;
771: }
772:
773: /**
774: * Convert a list of SelectableObjectsWithLabel to JSF SelectItems.
775: *
776: * @param items the items to be converted
777: * @return the given list converted to JSF SelectItems
778: */
779: public static List<SelectItem> asSelectListWithLabel(
780: List<? extends SelectableObjectWithLabel> items) {
781: return asSelectListWithLabel(items, false);
782: }
783:
784: /**
785: * Convert a list of SelectableObjectsWithLabel to JSF SelectItems.
786: *
787: * @param items the items to be converted
788: * @param addEmptyElement true if an empty first element with id=-1 should be added
789: * @return the given list converted to JSF SelectItems
790: */
791: public static List<SelectItem> asSelectListWithLabel(
792: List<? extends SelectableObjectWithLabel> items,
793: boolean addEmptyElement) {
794: final List<SelectItem> result = new ArrayList<SelectItem>(items
795: .size());
796: final UserTicket ticket = FxContext.get().getTicket();
797: if (addEmptyElement) {
798: result.add(new SelectItem(-1, ""));
799: }
800: for (SelectableObjectWithLabel item : items) {
801: result.add(new SelectItem(item.getId(), item.getLabel()
802: .getBestTranslation(ticket)));
803: }
804: return result;
805: }
806:
807: /**
808: * Converts the given flexive select list to a list of JSF SelectItems.
809: *
810: * @param list the select list to be converted
811: * @return a JSF select list corresponding to the given list options
812: */
813: public static List<SelectItem> asSelectList(FxSelectList list) {
814: final List<SelectItem> result = new ArrayList<SelectItem>(list
815: .getItems().size());
816: for (FxSelectListItem item : list.getItems()) {
817: result.add(new SelectItem(item.getId(), item.getLabel()
818: .getBestTranslation()));
819: }
820: return result;
821: }
822:
823: /**
824: * Converts a list of String arrays (2 dim, containing value and display) to a list of JSF SelectItems.
825: *
826: * @param list the list of String arrays (2 dim, containing value and display)
827: * @return a JSF select list corresponding to the given list options
828: */
829: public static List<SelectItem> asSelectList(List<String[]> list) {
830: final List<SelectItem> result = new ArrayList<SelectItem>(list
831: .size());
832: for (String[] item : list) {
833: if (item == null || item.length != 2)
834: continue;
835: result.add(new SelectItem(item[0], item[1]));
836: }
837: return result;
838: }
839:
840: /**
841: * Comparator for sorting select items by their display label.
842: */
843: public static class SelectItemSorter implements
844: Comparator<SelectItem>, Serializable {
845: private static final long serialVersionUID = -1382307878763605130L;
846: private final Collator collator;
847:
848: public SelectItemSorter() {
849: this .collator = FxSharedUtils.getCollator();
850: }
851:
852: public int compare(SelectItem o1, SelectItem o2) {
853: return this .collator.compare(o1.getLabel(), o2.getLabel());
854: }
855: }
856:
857: /**
858: * Comparator for sorting FxScriptInfo objects by their name.
859: */
860: public static class ScriptInfoSorter implements
861: Comparator<FxScriptInfo>, Serializable {
862: private static final long serialVersionUID = -5034370124391320180L;
863: private final Collator collator;
864:
865: public ScriptInfoSorter() {
866: this .collator = FxSharedUtils.getCollator();
867: }
868:
869: public int compare(FxScriptInfo o1, FxScriptInfo o2) {
870: return this .collator.compare(o1.getName(), o2.getName());
871: }
872: }
873:
874: /**
875: * Checks if the minimum and maximum values of a muliplicity are in valid ranges
876: *
877: * @param min minMultiplicity
878: * @param max maxMultiplicity
879: * @throws FxApplicationException on errors
880: */
881: public static void checkMultiplicity(int min, int max)
882: throws FxApplicationException {
883: if (min < 0)
884: throw new FxApplicationException(
885: "ex.structure.multiplicity.minimum.invalid", min,
886: max);
887: if (max < 1)
888: throw new FxApplicationException(
889: "ex.structure.multiplicity.maximum.invalid", max,
890: min);
891: if (min > max)
892: throw new FxApplicationException(
893: "ex.structure.multiplicity.minimum.invalid", min,
894: max);
895: }
896:
897: }
|