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.messages;
034:
035: import com.flexive.faces.FxJsfUtils;
036: import com.flexive.shared.FxContext;
037: import com.flexive.shared.exceptions.FxInvalidParameterException;
038: import com.flexive.shared.exceptions.FxLocalizedException;
039: import com.flexive.shared.security.UserTicket;
040: import org.apache.commons.lang.StringUtils;
041:
042: import javax.faces.application.FacesMessage;
043: import static javax.faces.context.FacesContext.getCurrentInstance;
044: import java.io.PrintWriter;
045: import java.io.Serializable;
046: import java.io.StringWriter;
047:
048: /**
049: * A Flexive Faces Message.
050: * <p/>
051: * This class is extends the FacesMessages by adding access to the form and client id that the message belongs to.
052: *
053: * @author Gregor Schober (gregor.schober@flexive.com), UCS - unique computing solutions gmbh (http://www.ucs.at)
054: */
055: public class FxFacesMessage extends FacesMessage implements
056: Serializable {
057: private static final long serialVersionUID = 8756831033361611047L;
058:
059: private String form;
060: private String id;
061:
062: /**
063: * Constructor.
064: *
065: * @param msg the original faces message
066: * @param component the client id, or null for a global message. The client id may conain the form (JSF style), eg
067: * 'myForm:myComponentId'
068: */
069: public FxFacesMessage(FacesMessage msg, String component) {
070: super (msg.getSeverity(), msg.getSummary(), msg.getDetail());
071: if (component != null) {
072: String split[] = component.split(":");
073: this .form = split[0];
074: this .id = split[1];
075: } else {
076: this .form = "";
077: this .id = "";
078: }
079: }
080:
081: /**
082: * Constructor.
083: *
084: * @param severity the severity
085: * @param summaryKey the summary key
086: * @param summaryParams the summary parameters
087: */
088: public FxFacesMessage(Severity severity, String summaryKey,
089: Object... summaryParams) {
090: super (severity, summaryKey, "");
091: setLocalizedSummary(summaryKey, summaryParams);
092: }
093:
094: /**
095: * Returns the detail message for use in javascripts.
096: *
097: * @return the detail message for use in javascripts
098: */
099: public String getDetailForJavascript() {
100: String detail = super .getDetail();
101: detail = detail.replaceAll("'", "′");
102: detail = detail.replaceAll("\"", "″");
103: detail = detail.replaceAll("\n", "<br>");
104: detail = detail.replaceAll("\r", "");
105: return detail;
106: }
107:
108: /**
109: * Constructor.
110: *
111: * @param exc the Exception
112: * @param severity the severity
113: * @param summaryKey the summary key
114: * @param summaryParams the summary parameters
115: */
116: public FxFacesMessage(Throwable exc, Severity severity,
117: String summaryKey, Object... summaryParams) {
118: super (severity, summaryKey, summaryKey);
119: setLocalizedSummary(summaryKey, summaryParams);
120: processException(exc, true, false);
121: }
122:
123: /**
124: * Constructor.
125: *
126: * @param exc the Exception
127: * @param severity the severity
128: */
129: public FxFacesMessage(Throwable exc, Severity severity) {
130: super (severity, "", "");
131: processException(exc, false, true);
132: }
133:
134: /**
135: * Extracts the message of the exception, and set the this.id property in
136: * case of a found FxInvalidParameterException.
137: *
138: * @param exc the Exception the exception to process
139: * @param setDetail set the detail to the message of the exception
140: * @param setSummary set the summaray to the message of the exception
141: */
142: private void processException(Throwable exc, boolean setDetail,
143: boolean setSummary) {
144:
145: // Try to find a FX__ type within the exception stack
146: Throwable tmp = exc;
147: while (!isFxThrowable(tmp) && tmp.getCause() != null) {
148: tmp = tmp.getCause();
149: }
150:
151: // If we found a FX__ type we use it
152: if (isFxThrowable(tmp)) {
153: exc = tmp;
154: }
155:
156: // Obtain id of the invalid parameter
157: if (exc instanceof FxInvalidParameterException) {
158: this .id = ((FxInvalidParameterException) exc)
159: .getParameter();
160: }
161:
162: String msg;
163: if (exc instanceof FxLocalizedException) {
164: UserTicket ticket = FxContext.get().getTicket();
165: FxLocalizedException le = ((FxLocalizedException) exc);
166: msg = le.getMessage(ticket);
167: } else {
168: msg = (exc.getMessage() == null) ? String.valueOf(exc
169: .getClass()) : exc.getMessage();
170: }
171:
172: if (setSummary) {
173: setSummary(msg);
174: }
175:
176: if (setDetail) {
177: String sDetail = "";
178: if (exc.getCause() != null) {
179: String sCause;
180: sCause = exc.getCause().getMessage();
181: if (sCause == null || sCause.trim().length() == 0
182: || sCause.equalsIgnoreCase("null")) {
183: sCause = exc.getCause().getClass().getName();
184: }
185: sDetail += "Cause message: " + sCause + "\n\t";
186: }
187: sDetail += getStackTrace(exc);
188: setDetail(sDetail);
189: }
190: }
191:
192: /**
193: * Gets the stacktrace as a string from a throwable.
194: *
195: * @param th the throwable
196: * @return the stacktrace as string
197: */
198: private String getStackTrace(Throwable th) {
199: StringWriter sw = null;
200: PrintWriter pw = null;
201: try {
202: sw = new StringWriter();
203: pw = new PrintWriter(sw);
204: th.printStackTrace(pw);
205: return sw.toString();
206: } catch (Throwable t) {
207: return "n/a";
208: } finally {
209: try {
210: if (sw != null)
211: sw.close();
212: } catch (Throwable t) {/*ignore*/
213: }
214: try {
215: if (pw != null)
216: pw.close();
217: } catch (Throwable t) {/*ignore*/
218: }
219: }
220: }
221:
222: private boolean isFxThrowable(Throwable exc) {
223: return exc != null && (exc instanceof FxLocalizedException);
224: }
225:
226: /**
227: * The form the message belongs to, or a empty string for a global message.
228: *
229: * @return The form the message belong to, or a empty string for a global message
230: */
231: public String getForm() {
232: return form;
233: }
234:
235: /**
236: * The client id that the message belongs (without the jsf form prefix) to, or a empty string for a global message.
237: *
238: * @return The client id that the message belongs to, or a empty string for a global message
239: */
240: public String getId() {
241: return id;
242: }
243:
244: /**
245: * Returns the client id (may be a empty string).
246: *
247: * @return the client id
248: */
249: public String getClientId() {
250: return (id == null || id.length() == 0) ? ""
251: : (form + ":" + id);
252: }
253:
254: /**
255: * Sets the client id that the message belongs to.
256: *
257: * @param id the client id to set
258: */
259: public void setId(String id) {
260: this .id = id;
261: }
262:
263: /**
264: * Sets the summary
265: *
266: * @param key the message key
267: * @param params the message parameters
268: */
269: public final void setLocalizedSummary(String key, Object... params) {
270: super .setSummary(FxJsfUtils.getLocalizedMessage(key, params));
271: }
272:
273: /**
274: * Sets the message detail.
275: *
276: * @param key The detail text key
277: * @param params the message parameters
278: */
279: public void setLocalizedDetail(String key, Object... params) {
280: super .setDetail(FxJsfUtils.getLocalizedMessage(key, params));
281: }
282:
283: /**
284: * {@inheritDoc}
285: */
286: @Override
287: public boolean equals(Object obj) {
288: if (obj == null)
289: return false;
290: if (!(obj instanceof FxFacesMessage))
291: return false;
292: //noinspection ConstantConditions
293: FxFacesMessage comp = (FxFacesMessage) obj;
294: // Compare properties
295: return (StringUtils
296: .equals(this .getSummary(), comp.getSummary())
297: && StringUtils.equals(this .getDetail(), comp
298: .getDetail())
299: && this .getSeverity() == comp.getSeverity()
300: && StringUtils.equals(this .getForm(), comp.getForm()) && StringUtils
301: .equals(this .getClientId(), comp.getClientId()));
302: }
303:
304: /**
305: * {@inheritDoc}
306: */
307: @Override
308: public int hashCode() {
309: int hashCode = 0;
310: if (getDetail() != null) {
311: hashCode = getDetail().hashCode();
312: }
313: if (getSummary() != null) {
314: hashCode = hashCode * 31 + getSummary().hashCode();
315: }
316: if (getForm() != null) {
317: hashCode = hashCode * 31 + getForm().hashCode();
318: }
319: if (getClientId() != null) {
320: hashCode = hashCode * 31 + getClientId().hashCode();
321: }
322: return hashCode;
323: }
324:
325: /**
326: * Adds the message to the context.
327: * <p/>
328: * A message will only be available to the client (UI) when it was added to the context
329: */
330: public void addToContext() {
331: getCurrentInstance().addMessage(null, this );
332: }
333:
334: /**
335: * Adds the message to the context.
336: * <p/>
337: * A message will only be available to the client (UI) when it was added to the context
338: *
339: * @param clientId the client id of the message
340: */
341: public void addToContext(String clientId) {
342: getCurrentInstance().addMessage(clientId, this );
343: }
344:
345: /**
346: * Returns true if the message has a detail information.
347: *
348: * @return true if the message has a detail information
349: */
350: public boolean getHasDetail() {
351: return this .getDetail() != null
352: && this .getDetail().trim().length() > 0;
353: }
354: }
|