1: package com.yourcompany.zw;
2:
3: import java.awt.AlphaComposite;
4: import java.awt.BorderLayout;
5: import java.awt.Color;
6: import java.awt.Container;
7: import java.awt.Dimension;
8: import java.awt.Font;
9: import java.awt.GradientPaint;
10: import java.awt.Graphics;
11: import java.awt.Graphics2D;
12: import java.awt.GraphicsConfiguration;
13: import java.awt.Point;
14: import java.awt.Toolkit;
15: import java.awt.Transparency;
16: import java.awt.event.ActionEvent;
17: import java.awt.event.ActionListener;
18: import java.awt.event.MouseAdapter;
19: import java.awt.event.MouseEvent;
20: import java.awt.event.MouseListener;
21: import java.awt.event.MouseMotionAdapter;
22: import java.awt.event.MouseMotionListener;
23: import java.awt.geom.AffineTransform;
24: import java.awt.geom.Rectangle2D;
25: import java.awt.image.BufferedImage;
26: import java.io.File;
27: import java.io.IOException;
28: import java.net.URI;
29: import java.net.URISyntaxException;
30: import java.net.URL;
31: import java.util.ArrayList;
32: import java.util.Arrays;
33: import java.util.HashMap;
34: import java.util.HashSet;
35: import java.util.List;
36: import java.util.Map;
37: import java.util.Set;
38: import java.util.regex.Pattern;
39:
40: import javax.imageio.ImageIO;
41: import javax.swing.ImageIcon;
42: import javax.swing.JButton;
43: import javax.swing.JComponent;
44: import javax.swing.JDialog;
45: import javax.swing.JFrame;
46: import javax.swing.JPanel;
47: import javax.swing.Timer;
48: import javax.swing.UIManager;
49: import javax.swing.text.AbstractDocument;
50:
51: public class Bubble extends JDialog {
52:
53: // this code is static to manage the number of windows that are open
54: protected static int numOpen;
55: protected static int getOpen() { return numOpen; }
56: protected static void windowOpen() { numOpen++; }
57: protected static void windowClose() { numOpen--; }
58:
59: private int X=0;
60: private int Y=0;
61: private String fromMobileNumber;
62: private String message;
63: private String replyUrl;
64: private boolean toFade = true;
65: private float currOpacity;
66: private Timer fadeInTimer;
67: private Timer fadeOutTimer;
68:
69: javax.swing.JTextPane jTextPaneTxtMsg;
70: AbstractDocument doc;
71:
72: public Bubble(String fromMobileNumber, String message, String replyUrl) {
73: this(fromMobileNumber, message, replyUrl, true);
74: }
75:
76: public Bubble(String fromMobileNumber, String message, String replyUrl, boolean toFade) {
77:
78: // initialize properties
79: setFromMobileNumber(fromMobileNumber);
80: setMessage(message);
81: setReplyUrl(replyUrl);
82:
83: // initialize the UI of the bubble
84: init();
85:
86: // set the location of where this bubble will be shown
87: Dimension ourDim = Toolkit.getDefaultToolkit().getScreenSize();
88: this.setLocation(
89: (int)ourDim.getWidth() - this.getWidth() - 10,
90: 0 + ((this.getHeight() + -20) * getOpen()));
91:
92: // increment how many bubbles are open
93: windowOpen();
94:
95: // ok, show it finally
96: this.setVisible(true);
97: }
98:
99: // Getters/setters
100: public String getFromMobileNumber() {
101: return StringUtil.format(fromMobileNumber, "(###) ###-####");
102: }
103:
104: public void setFromMobileNumber(String fromMobileNumber) {
105: this.fromMobileNumber = fromMobileNumber;
106: }
107:
108: public String getMessage() {
109: return message;
110: }
111:
112: public void setMessage(String message) {
113: this.message = message;
114: }
115:
116: public String getReplyUrl() {
117: return replyUrl;
118: }
119:
120: public void setReplyUrl(String replyUrl) {
121: this.replyUrl = replyUrl;
122: }
123:
124: public boolean isToFade() {
125: return toFade;
126: }
127: public void setToFade(boolean toFade) {
128: this.toFade = toFade;
129: }
130:
131: // Initialize the GUI
132: public void init() {
133: try {
134:
135: // When JFrame or JDialog
136: this.setUndecorated(true);
137: this.setModal(false);
138: this.setFocusableWindowState(false);
139: this.setAlwaysOnTop(true);
140:
141: try {
142: UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
143: } catch (Exception evt) {}
144:
145: // Get bg image
146: final BufferedImage backgroundImg = ImageIO.read(getClass().getResource("/resources/riser_shd.png"));
147:
148: // Set icon & title
149: final BufferedImage z = ImageIO.read(getClass().getResource("/resources/z.png"));
150: ((java.awt.Frame)this.getOwner()).setIconImage(z);
151: this.setTitle(this.getFromMobileNumber() + ": " + this.getMessage());
152:
153: // Set layout
154: this.setLayout(new BorderLayout());
155: JPanel mainPanel = new JPanel(new BorderLayout()) {
156:
157: private static final long serialVersionUID = 1L;
158:
159: // The paintComponent override let's us make the entire
160: // window transparent on the desktop so we get a cool effect
161: @Override
162: protected void paintComponent(Graphics g) {
163: Graphics2D g2d = (Graphics2D) g.create();
164:
165: // code from
166: // http://weblogs.java.net/blog/campbell/archive/2006/07/java_2d_tricker.html
167: int width = backgroundImg.getWidth();
168: int height = backgroundImg.getHeight();
169: GraphicsConfiguration gc = g2d.getDeviceConfiguration();
170: BufferedImage img = gc.createCompatibleImage(
171: width,
172: height,
173: Transparency.TRANSLUCENT);
174: Graphics2D g2 = img.createGraphics();
175: g2.setComposite(AlphaComposite.Src);
176: g2.drawImage(backgroundImg, 0, 0, null);
177: g2.dispose();
178: g2d.drawImage(img, 0, 0, this);
179: g2d.dispose();
180: }
181: };
182:
183: // Setup the window
184: final JDialog wnd = this;
185:
186: // This is the phone number and textarea message panel
187: javax.swing.JPanel jPanelAll = new javax.swing.JPanel();
188: javax.swing.JLabel jLabelMobileNum = new javax.swing.JLabel();
189: this.jTextPaneTxtMsg = new javax.swing.JTextPane();
190: JButton jButtonClose = new javax.swing.JButton();
191: JButton jButtonReply = new javax.swing.JButton();
192:
193: jPanelAll.setOpaque(false);
194: jPanelAll.setDoubleBuffered(false);
195: jPanelAll.setName("jPanelAll"); // NOI18N
196:
197: jLabelMobileNum.setFont( new Font(null, Font.BOLD, 14));
198: jLabelMobileNum.setForeground(new Color(67, 74, 84));
199: jLabelMobileNum.setText(getFromMobileNumber());
200: jLabelMobileNum.setName("jLabelMobileNum"); // NOI18N
201:
202: jTextPaneTxtMsg.setBorder(null);
203: jTextPaneTxtMsg.setEditable(false);
204: jTextPaneTxtMsg.setFont( new Font(null, Font.PLAIN, 12));
205: jTextPaneTxtMsg.setOpaque(false);
206: jTextPaneTxtMsg.setDoubleBuffered(false);
207: jTextPaneTxtMsg.setText(getMessage());
208: jTextPaneTxtMsg.setName("jTextPane1"); // NOI18N
209: jTextPaneTxtMsg.setCaretPosition(0);
210:
211: javax.swing.JScrollPane jScrollPane1 = new javax.swing.JScrollPane(jTextPaneTxtMsg);
212: jScrollPane1.getViewport().setOpaque(false);
213: jScrollPane1.getViewport().setDoubleBuffered(false);
214:
215: jScrollPane1.setBorder(null);
216: jScrollPane1.setHorizontalScrollBarPolicy(javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
217: jScrollPane1.setVerticalScrollBarPolicy(javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
218: jScrollPane1.setOpaque(false);
219: jScrollPane1.setDoubleBuffered(false);
220: jScrollPane1.setWheelScrollingEnabled(true);
221:
222: BufferedImage riserSpriteBtnImg = ImageIO.read(getClass().getResource("/resources/risergang.png"));
223:
224: // Define the close button
225: jButtonClose.setIcon(new ImageIcon(riserSpriteBtnImg.getSubimage(1,1,14,14)));
226: jButtonClose.setRolloverIcon(new ImageIcon(riserSpriteBtnImg.getSubimage(16,1,14,14)));
227: jButtonClose.setPressedIcon(new ImageIcon(riserSpriteBtnImg.getSubimage(31,1,14,14)));
228: jButtonClose.setBorder(null);
229: jButtonClose.setBorderPainted(false);
230: jButtonClose.setContentAreaFilled(false);
231: jButtonClose.addActionListener(new ActionListener() {
232: @Override
233: public void actionPerformed(ActionEvent e) {
234: wnd.setVisible(false);
235: }
236: });
237:
238: // Define the reply button
239: jButtonReply.setIcon(new ImageIcon(riserSpriteBtnImg.getSubimage(0,16,58,30)));
240: jButtonReply.setRolloverIcon(new ImageIcon(riserSpriteBtnImg.getSubimage(0,47,58,30)));
241: jButtonReply.setPressedIcon(new ImageIcon(riserSpriteBtnImg.getSubimage(0,78,58,30)));
242: jButtonReply.setBorder(null);
243: jButtonReply.setBorderPainted(false);
244: jButtonReply.setContentAreaFilled(false);
245: jButtonReply.addActionListener(new ActionListener() {
246: @Override
247: public void actionPerformed(ActionEvent e) {
248: openUri(getReplyUrl());
249: wnd.setVisible(false);
250: }
251: });
252:
253: // Do the layout positioning using horiz/vert groups
254: javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanelAll);
255: jPanelAll.setLayout(jPanel2Layout);
256:
257: jPanel2Layout.setHorizontalGroup(
258: jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
259: .addGroup(jPanel2Layout.createSequentialGroup()
260: .addGap(32)
261: .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
262: .addComponent(jLabelMobileNum)
263: .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 150, javax.swing.GroupLayout.PREFERRED_SIZE)
264: )
265: .addContainerGap(73, Short.MAX_VALUE))
266: .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
267: .addGroup(jPanel2Layout.createSequentialGroup()
268: .addGap(169)
269: .addComponent(jButtonClose, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
270: .addContainerGap(261, Short.MAX_VALUE)))
271: .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
272: .addGroup(jPanel2Layout.createSequentialGroup()
273: .addGap(128)
274: .addComponent(jButtonReply, javax.swing.GroupLayout.PREFERRED_SIZE, 58, javax.swing.GroupLayout.PREFERRED_SIZE)
275: .addContainerGap(251, Short.MAX_VALUE)))
276: );
277:
278: jPanel2Layout.setVerticalGroup(
279: jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
280: .addGroup(jPanel2Layout.createSequentialGroup()
281: .addGap(32)
282: .addComponent(jLabelMobileNum)
283: .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
284: .addComponent(false, jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 100, javax.swing.GroupLayout.PREFERRED_SIZE)
285: .addContainerGap(64, Short.MAX_VALUE))
286: .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
287: .addGroup(jPanel2Layout.createSequentialGroup()
288: .addGap(28)
289: .addComponent(jButtonClose, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE)
290: .addContainerGap(300, Short.MAX_VALUE)))
291: .addGroup(jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
292: .addGroup(jPanel2Layout.createSequentialGroup()
293: .addGap(168)
294: .addComponent(jButtonReply, javax.swing.GroupLayout.PREFERRED_SIZE, 30, javax.swing.GroupLayout.PREFERRED_SIZE)
295: .addContainerGap(146, Short.MAX_VALUE)))
296: );
297:
298: // End phone/message panel
299:
300: // Setup final main paenl
301: mainPanel.add(jPanelAll, BorderLayout.WEST);
302: mainPanel.setDoubleBuffered(false);
303: mainPanel.setOpaque(true);
304: this.add(mainPanel, BorderLayout.CENTER);
305:
306: this.setAlwaysOnTop(true);
307: this.setSize(216, 234);
308: this.setLocationRelativeTo(null);
309: com.sun.awt.AWTUtilities.setWindowOpaque(this, false);
310:
311: // Watch mouse movements and clicks to allow dragging of window
312: addMouseListener(new MouseAdapter()
313: {
314: public void mousePressed(MouseEvent e)
315: {
316: // Check for double-click
317: if (e.getClickCount() >= 2) {
318: // Open the website to let them reply
319: openUri(getReplyUrl());
320: setVisible(false);
321: } else {
322: // Do drag operation
323: X=e.getX();
324: Y=e.getY();
325: }
326: }
327:
328: });
329:
330: addMouseMotionListener(new MouseMotionAdapter()
331: {
332: public void mouseDragged(MouseEvent e)
333: {
334: setLocation(getLocation().x+(e.getX()-X),getLocation().y+(e.getY()-Y));
335: }
336: });
337:
338: } catch (IOException e) {
339: e.printStackTrace();
340: }
341: }
342:
343: @Override
344: public void setVisible(boolean b) {
345:
346: // Handle fading in or fading out
347:
348: // If setvisible is true
349: if (b) {
350:
351: // See if we need to fade in
352: if (this.toFade) {
353: // mark the popup with 0% opacity
354: this.currOpacity = 0;
355: com.sun.awt.AWTUtilities.setWindowOpacity(this, 0.0f);
356: }
357:
358: super.setVisible(b);
359:
360: final JDialog popupWindow = this;
361:
362: if (this.toFade) {
363: // start fading in
364: this.fadeInTimer = new Timer(50, new ActionListener() {
365: public void actionPerformed(ActionEvent e) {
366: currOpacity += 10;
367: if (currOpacity <= 100) {
368: com.sun.awt.AWTUtilities.setWindowOpacity(popupWindow,
369: currOpacity / 100.0f);
370: // workaround bug 6670649 - should call
371: // popupWindow.repaint() but that will not repaint the
372: // panel
373: popupWindow.getContentPane().repaint();
374: } else {
375: currOpacity = 100;
376: fadeInTimer.stop();
377: }
378: }
379: });
380: this.fadeInTimer.setRepeats(true);
381: this.fadeInTimer.start();
382: }
383:
384: } else {
385:
386: // If setvisible is false
387:
388: // Handle fading out, if they want a fade
389: if (this.toFade) {
390:
391: // cancel fade-in if it's running.
392: if (this.fadeInTimer.isRunning())
393: this.fadeInTimer.stop();
394:
395: final Bubble popupWindow = this;
396:
397: // start fading out
398: this.fadeOutTimer = new Timer(50, new ActionListener() {
399: public void actionPerformed(ActionEvent e) {
400: currOpacity -= 10;
401: if (currOpacity >= 0) {
402: com.sun.awt.AWTUtilities.setWindowOpacity(popupWindow,
403: currOpacity / 100.0f);
404: // workaround bug 6670649 - should call
405: // popupWindow.repaint() but that will not repaint the
406: // panel
407: popupWindow.getContentPane().repaint();
408: } else {
409: fadeOutTimer.stop();
410: popupWindow.setToFade(false);
411: popupWindow.setVisible(false);
412: currOpacity = 0;
413: }
414: }
415: });
416: this.fadeOutTimer.setRepeats(true);
417: this.fadeOutTimer.start();
418:
419: } else {
420:
421: // setVisible is being set to false and we're not in fadeout mode,
422: // so let's let the super handle
423: // it cuz we don't want to interfere if there's no fading going on
424: windowClose();
425: super.setVisible(false);
426: this.removeAll();
427: this.dispose();
428:
429: }
430: }
431: }
432:
433: public void openUri(String url) {
434:
435: if( !java.awt.Desktop.isDesktopSupported() ) {
436:
437: System.err.println( "Desktop is not supported (fatal)" );
438: return;
439: }
440:
441: java.awt.Desktop desktop = java.awt.Desktop.getDesktop();
442:
443: if( !desktop.isSupported( java.awt.Desktop.Action.BROWSE ) ) {
444:
445: System.err.println( "Desktop doesn't support the browse action (fatal)" );
446: return;
447: }
448:
449: try {
450:
451: java.net.URI uri = new java.net.URI( url );
452: desktop.browse( uri );
453: }
454: catch ( Exception e ) {
455:
456: System.err.println( e.getMessage() );
457: }
458:
459: }
460:
461: }
462:
463: class MoveMouseListener implements MouseListener, MouseMotionListener {
464: JComponent target;
465: Point start_drag;
466: Point start_loc;
467:
468: public MoveMouseListener(JComponent target) {
469: this.target = target;
470: }
471:
472: public static JFrame getFrame(Container target) {
473: if (target instanceof JFrame) {
474: return (JFrame) target;
475: }
476: return getFrame(target.getParent());
477: }
478:
479: Point getScreenLocation(MouseEvent e) {
480: Point cursor = e.getPoint();
481: Point target_location = this.target.getLocationOnScreen();
482: return new Point((int) (target_location.getX() + cursor.getX()),
483: (int) (target_location.getY() + cursor.getY()));
484: }
485:
486: public void mouseClicked(MouseEvent e) {
487: }
488:
489: public void mouseEntered(MouseEvent e) {
490: }
491:
492: public void mouseExited(MouseEvent e) {
493: }
494:
495: public void mousePressed(MouseEvent e) {
496: this.start_drag = this.getScreenLocation(e);
497: this.start_loc = this.getFrame(this.target).getLocation();
498: }
499:
500: public void mouseReleased(MouseEvent e) {
501: }
502:
503: public void mouseDragged(MouseEvent e) {
504: Point current = this.getScreenLocation(e);
505: Point offset = new Point((int) current.getX() - (int) start_drag.getX(),
506: (int) current.getY() - (int) start_drag.getY());
507: JFrame frame = this.getFrame(target);
508: Point new_location = new Point(
509: (int) (this.start_loc.getX() + offset.getX()), (int) (this.start_loc
510: .getY() + offset.getY()));
511: frame.setLocation(new_location);
512: }
513:
514: public void mouseMoved(MouseEvent e) {
515: }
516: }
517:
518: class StringUtil {
519:
520: //private static final Logger logger = LoggerFactory.getLogger(StringUtil.class);
521:
522: public static final String EMPTY_STRING = "";
523: public static final int MAX_MOBILE_NUMBER_DIGITS = 16; // Finland being the longest we could find 99500-1-202-444-1212, plus a buffer...
524: public static final List<Character> VALID_NUMBERS;
525: public static final List<Character> VALID_SPECIAL_CHARACTERS;
526:
527: static {
528: VALID_NUMBERS = Arrays.asList(new Character[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' });
529: VALID_SPECIAL_CHARACTERS = Arrays.asList(new Character[]{'!', '@', '#', '$', '%', '^', '&', '*', '(', ')', '`', '[', ']', '\\', '{', '}', '|', '<', '>', '?', ',', '.', '/', ':', ';', '\'', '"', '+', '~', '*', '.'});
530: }
531:
532: /**
533: * Strips all characters that are not numbers (0 - 9) and returns a new
534: * string. Returns and empty string if the mobile number is null or empty.
535: *
536: * @param mobileNumber - mobile number string to parse
537: * @return String - parsed mobile number
538: */
539: public static String safeCleanMobileNumber(String mobileNumber) {
540:
541: //logger.debug("getting clean for " + mobileNumber);
542:
543: if (isNullOrEmpty(mobileNumber)) {
544: //logger.debug("was nullOrEmpty ");
545: return null;
546: }
547:
548: StringBuilder cleanMobileNumber = new StringBuilder();
549: for (int i = 0; i < mobileNumber.length(); i++) {
550: if (VALID_NUMBERS.contains(mobileNumber.charAt(i))) {
551: cleanMobileNumber.append(mobileNumber.charAt(i));
552: }
553: }
554:
555: // remove the first (1) at the beginning of the to match default us
556: // numbers
557: // 10 digits
558: if (cleanMobileNumber.length() > 10 && startsWith(cleanMobileNumber.toString(), "1")) {
559: //logger.debug("clean 1 " + cleanMobileNumber.substring(1));
560: return cleanMobileNumber.substring(1);
561: }
562: if (cleanMobileNumber.length() > 10 && startsWith(cleanMobileNumber.toString(), "+1")) {
563: //logger.debug("clean 2 " + cleanMobileNumber.substring(1));
564: return cleanMobileNumber.substring(2);
565: }
566:
567: //logger.debug("clean " + cleanMobileNumber.toString());
568: return cleanMobileNumber.toString();
569: }
570:
571: /**
572: * Same as safeCleanMobileNumber except for devices
573: * in which case the device number is removed first
574: *
575: * @param mobileNumber - mobile number string to parse
576: * @return String - parsed mobile number
577: */
578: public static String safeCleanMobileNumberRemoveDevice(String mobileNumber) {
579:
580: if (startsWith(mobileNumber, "device:/")) {
581:
582: int index = mobileNumber.lastIndexOf('/');
583:
584: // If the last index of '/' is > than the first
585: if (index > 7) {
586: mobileNumber = mobileNumber.substring(0, index);
587: }
588: }
589:
590: return safeCleanMobileNumber(mobileNumber);
591: }
592:
593: public static boolean isValidEmail(String email){
594: // see http://www.mkyong.com/regular-expressions/how-to-validate-email-address-with-regular-expression/
595: Pattern pattern ;
596: java.util.regex.Matcher matcher;
597: final String EMAIL_PATTERN = "^[\\w\\-]+(\\.[\\w\\-]+)*@([A-Za-z0-9-]+\\.)+[A-Za-z]{2,4}$";
598:
599: pattern = Pattern.compile(EMAIL_PATTERN);
600: matcher = pattern.matcher(email);
601:
602: return matcher.matches();
603: }
604:
605:
606: /**
607: * The length is valid if it is between 3 and 6 or over
608: * 10 and up to and including 20
609: * 3-6 length means short codes
610: * 10 length 000-000-0000
611: * 10+ means international
612: *
613: * @param mobileNumber
614: * @return
615: */
616: public static boolean isValidLengthMobileNumber(String mobileNumber) {
617:
618: if (isNullOrEmpty(mobileNumber)) {
619: return false;
620: }
621:
622: int numberLength = mobileNumber.length();
623:
624: // Wrong if under 3 and between 7 and 9 digits long or longer than 20
625: if (numberLength < 3 || numberLength == 7 || numberLength == 8 || numberLength == 9 || numberLength > MAX_MOBILE_NUMBER_DIGITS) {
626: return false;
627: }
628: // Correct is 3 to 6 for short codes and 10 to 20 for long international
629: // numbers, including a buffer
630: return true;
631: }
632:
633: public static boolean startsWith(String string1, String toFind) {
634: if (string1 == null && toFind == null){
635: // null contains null.
636: return true;
637: } else if (string1 == null){
638: return false;
639: }
640:
641: if (StringUtil.equalsIgnoreCase(string1, toFind)){
642: return true;
643: }
644:
645: return string1.toLowerCase().startsWith(toFind.toLowerCase());
646: }
647:
648: public static boolean endsWith(String source, String toFind) {
649: if (source == null) {
650: return false;
651: }
652:
653: return source.endsWith(toFind);
654: }
655:
656: public static String defaultValue(String string, String defaultValue) {
657: if (StringUtil.isNullOrEmpty(string)){
658: return defaultValue;
659: }
660: return string;
661: }
662:
663: public static final class Schema {
664:
665: public static final String TEL = "tel";
666: }
667:
668: /**
669: * Takes a string representing the display name and returns and array with
670: * first name and last name.
671: *
672: * Returns null if null or empty input
673: *
674: * @param displayName
675: * @return String[]
676: */
677: public static String[] splitDisplayName(String displayName) {
678: if (displayName == null || displayName.length() < 1) {
679: return null;
680: }
681:
682: String[] names = displayName.split(" ");
683:
684: return names;
685: }
686:
687: /**
688: * Takes a string representing a list of mobile numbers as
689: * 5555551212, 5556667878 or
690: * 5555551212; 5556667878
691: *
692: * Returns null if null or empty input
693: *
694: * @param sourceNumber
695: * @return List<String>
696: */
697: public static List<String> splitMobileNumbers(String sourceNumber) {
698:
699: ArrayList<String> result = new ArrayList<String>();
700: int last = 0;
701:
702: for (int i = 0; i < sourceNumber.length(); i++) {
703: if (sourceNumber.charAt(i) == ';' || sourceNumber.charAt(i) == ',') {
704: String number = sourceNumber.substring(last, i).trim();
705: result.add(number);
706: last = i + 1;
707: }
708: }
709: result.add(sourceNumber.substring(last).trim());
710: return result;
711: }
712:
713: /**
714: * Format the mobile number
715: *
716: * @param mobileNumber
717: * @param format
718: * - ###-###-####
719: * @return
720: */
721: public static String format(String mobileNumber, String format) {
722: if (mobileNumber == null || mobileNumber.length() < 1 || format == null || format.length() < 1) {
723: return mobileNumber;
724: }
725:
726: int numberCount = 0;
727: for (int i = 0; i < format.length(); i++) {
728: if (format.charAt(i) == '#') {
729: numberCount++;
730: }
731: }
732: String number = safeCleanMobileNumber(mobileNumber);
733: if (numberCount != number.length()) {
734: return mobileNumber;
735: }
736:
737: List<Character> numberChars = new ArrayList<Character>();
738: char[] chars = new char[format.length()];
739: int count = 0;
740: for (int i = 0; i < format.length(); i++) {
741: if (format.charAt(i) == '#') {
742: numberChars.add(number.charAt(count));
743: chars[i] = number.charAt(count);
744: count++;
745: } else {
746: numberChars.add(format.charAt(i));
747: chars[i] = format.charAt(i);
748: }
749: }
750:
751: return new String(chars);
752: }
753:
754: public static String stringArrayToDelimittedString(String[] arrayString, String delimiter) {
755: return stringArrayToDelimittedString(arrayString, delimiter, null);
756: }
757:
758: public static String stringArrayToDelimittedString(String[] arrayString, String delimiter, String format) {
759:
760: if (arrayString == null || delimiter == null) {
761: return null;
762: }
763:
764: StringBuilder delimittedString = new StringBuilder();
765: if (format == null || format.length() < 1) {
766: for (String number : arrayString) {
767: delimittedString.append(number).append(delimiter);
768: }
769: } else {
770: for (String number : arrayString) {
771: number = StringUtil.format(number, format);
772: delimittedString.append(number).append(delimiter);
773: }
774: }
775:
776: return delimittedString.toString();
777: }
778:
779: /**
780: * Takes a delimited values string and returns is as a set
781: *
782: * @param string
783: * @param delimiter
784: * @return Set<String>
785: */
786: public static Set<String> stringToSet(String string, String delimiter) {
787: if (isNullOrEmpty(string) || isNullOrEmpty(delimiter)) {
788: return null;
789: }
790:
791: String[] toArray = string.split(delimiter);
792: Set<String> toSet = null;
793: if (toArray != null && toArray.length > 0) {
794: toSet = new HashSet<String>();
795: for (String value : toArray) {
796: if (!isNullOrEmpty(value)) toSet.add(value);
797: }
798: }
799: return toSet;
800: }
801:
802: /**
803: * Return true if the string is null. Trims the string and checks if it is
804: * an empty string
805: *
806: * @param string
807: * @return
808: */
809: public static boolean isNullOrEmpty(String string) {
810: return (string == null || string.trim().length() < 1);
811: }
812:
813: public static boolean isNullOrEmpty(String... strings) {
814: for (String string : strings) {
815: if (isNullOrEmpty(string)) {
816: return true;
817: }
818: }
819: return false;
820: }
821:
822: public static boolean exists(String string) {
823: return !isNullOrEmpty(string);
824: }
825:
826: public static boolean equals(String string1, String string2){
827: if (string1 == string2)
828: return true; // covers both null, or both same instance
829: if (string1 == null){
830: return false; // covers 1 null, other not.
831: }
832:
833: return (string1.equals(string2)); // covers equals
834: }
835:
836: public static boolean equalsIgnoreCase(String string, String type) {
837: boolean oneEmpty = isNullOrEmpty(string);
838: boolean otherEmpty = isNullOrEmpty(type);
839: if (oneEmpty && otherEmpty) {
840: return true;
841: }
842: if (oneEmpty || otherEmpty) {
843: return false;
844: }
845:
846: return string.equalsIgnoreCase(type);
847: }
848:
849: public static boolean isIntegerParsable(String toCheck){
850: if (toCheck == null) return false;
851: try {
852: Integer.parseInt(toCheck);
853: return true;
854: } catch (NumberFormatException e){
855: return false;
856: }
857: }
858:
859: public static boolean isLongParsable(String toCheck){
860: if (toCheck == null) return false;
861: try {
862: Long.parseLong(toCheck);
863: return true;
864: } catch (NumberFormatException e){
865: return false;
866: }
867: }
868:
869: public static String[] convert(Object... parameters){
870: String[] args = new String[parameters.length];
871:
872: int idx = 0;
873: for(Object object : parameters){
874: args[idx] = String.valueOf(object);
875: idx ++;
876: }
877:
878: return args;
879: }
880:
881: public static String join(Object... parts) {
882: StringBuilder sb = new StringBuilder();
883: for(Object part : parts){
884: if (part == null){
885: continue;
886: }
887: sb.append(String.valueOf(part));
888: }
889: return sb.toString();
890: }
891:
892: /**
893: * Check if the last character in the string matches the input character and
894: * removes. If the match fails, we return the string as it is.
895: *
896: * @param inputString
897: * @param c
898: * @return string
899: */
900: public static String removeLast(String inputString, char c) {
901:
902: if (isNullOrEmpty(inputString)) {
903: return inputString;
904: }
905:
906: if (inputString.charAt(inputString.length() - 1) == c) {
907: return inputString.substring(0, inputString.length() - 1);
908: }
909:
910: return inputString;
911: }
912:
913: public static String stripStringNull(String param) {
914: return (StringUtil.isNullOrEmpty(param) || "null".equalsIgnoreCase(param)) ? StringUtil.EMPTY_STRING : param;
915: }
916:
917: /**
918: *
919: * @param contents
920: * @param key
921: * @param value
922: * @return
923: */
924: public static String convertPatterns(String contents, Map<String, String> keyVals) {
925:
926: if (contents == null) {
927: throw new NullPointerException("Cannot convert null pattern");
928: }
929:
930: for(Map.Entry<String, String> entry : keyVals.entrySet()) {
931: contents = contents.replaceAll(entry.getKey(), entry.getValue());
932: }
933:
934: return contents;
935: }
936:
937: public static String convertPatterns(
938: final String contents,
939: final String hostnamePattern,
940: final String string
941: ) {
942:
943: final Map<String, String> keyVals = new HashMap<String, String>();
944:
945: return convertPatterns(contents, keyVals);
946:
947: }
948:
949: }