001/*
002 * Copyright (C) 2012 eXo Platform SAS.
003 *
004 * This is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU Lesser General Public License as
006 * published by the Free Software Foundation; either version 2.1 of
007 * the License, or (at your option) any later version.
008 *
009 * This software is distributed in the hope that it will be useful,
010 * but WITHOUT ANY WARRANTY; without even the implied warranty of
011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012 * Lesser General Public License for more details.
013 *
014 * You should have received a copy of the GNU Lesser General Public
015 * License along with this software; if not, write to the Free
016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018 */
019
020package org.crsh.util;
021
022import java.util.ArrayList;
023import java.util.Arrays;
024import java.util.Collections;
025import java.util.HashMap;
026import java.util.HashSet;
027import java.util.Iterator;
028import java.util.LinkedList;
029import java.util.List;
030import java.util.Map;
031import java.util.NoSuchElementException;
032import java.util.regex.Matcher;
033import java.util.regex.Pattern;
034
035public class Utils {
036
037  /** . */
038  private static final Iterator EMPTY_ITERATOR = Collections.emptyList().iterator();
039
040  public static <E> Iterator<E> iterator() {
041    @SuppressWarnings("unchecked")
042    Iterator<E> iterator = (Iterator<E>)EMPTY_ITERATOR;
043    return iterator;
044  }
045
046  public static <E> Iterator<E> iterator(final E element) {
047    return new BaseIterator<E>() {
048      boolean hasNext = true;
049      @Override
050      public boolean hasNext() {
051        return hasNext;
052      }
053      @Override
054      public E next() {
055        if (hasNext) {
056          hasNext = false;
057          return element;
058        } else {
059          throw new NoSuchElementException();
060        }
061      }
062    };
063  }
064
065  public static <E> ArrayList<E> newArrayList() {
066    return new ArrayList<E>();
067  }
068
069  public static <E> LinkedList<E> newLinkedList() {
070    return new LinkedList<E>();
071  }
072
073  public static <E> HashSet<E> newHashSet() {
074    return new HashSet<E>();
075  }
076
077  public static <K, V> HashMap<K, V> newHashMap() {
078    return new HashMap<K, V>();
079  }
080
081  public static <E> E first(Iterable<E> elements) {
082    Iterator<E> i = elements.iterator();
083    return i.hasNext() ? i.next() : null;
084  }
085
086  public static <K, V, M extends Map<K, V>> M map(M map, K key, V value) {
087    map.put(key, value);
088    return map;
089  }
090
091  public static <K, V> HashMap<K, V> map(K key, V value) {
092    HashMap<K, V> map = new HashMap<K, V>();
093    map.put(key, value);
094    return map;
095  }
096
097  public static <E> List<E> list(E... elements) {
098    return Arrays.asList(elements);
099  }
100
101  public static <E> List<E> list(Iterable<E> iterable) {
102    return list(iterable.iterator());
103  }
104
105  public static <E> List<E> list(Iterator<E> iterator) {
106    ArrayList<E> list = new ArrayList<E>();
107    while (iterator.hasNext()) {
108      list.add(iterator.next());
109    }
110    return list;
111  }
112
113  public static int indexOf(CharSequence s, int off, char c) {
114    for (int len = s.length();off < len;off++) {
115      if (s.charAt(off) == c) {
116        return off;
117      }
118    }
119    return -1;
120  }
121
122  public static String trimLeft(String s) {
123    if (s == null) {
124      throw new NullPointerException("No null string accepted");
125    }
126    int index = 0;
127    int len = s.length();
128    while (index < len) {
129      if (s.charAt(index) == ' ') {
130        index++;
131      } else {
132        break;
133      }
134    }
135    if (index > 0) {
136      return s.substring(index);
137    } else {
138      return s;
139    }
140  }
141
142  public static <E> E notNull(E e1, E e2) {
143    if (e1 != null) {
144      return e1;
145    } else {
146      return e2;
147    }
148  }
149
150  private static final Pattern FOO = Pattern.compile("" +
151      "(\\*)" + // Wildcard *
152      "|" +
153      "(\\?)" + // Wildcard ?
154      "|" +
155      "(?:\\[([^)]+)\\])" + // Range
156      "|" +
157      "(\\\\.)" // Escape
158  );
159
160  /**
161   * Create a pattern that transforms a glob expression into a regular expression, the following task are supported
162   * <ul>
163   *   <li>* : Match any number of unknown characters</li>
164   *   <li>? : Match one unknown character</li>
165   *   <li>[characters] : Match a character as part of a group of characters</li>
166   *   <li>\ : Escape character</li>
167   * </ul>
168   *
169   * @param globex the glob expression
170   * @return the regular expression
171   * @throws NullPointerException when the globex argument is null
172   */
173  public static String globexToRegex(String globex) throws NullPointerException {
174    if (globex == null) {
175      throw new NullPointerException("No null globex accepted");
176    }
177    StringBuilder regex = new StringBuilder();
178    int prev = 0;
179    Matcher matcher = FOO.matcher(globex);
180    while (matcher.find()) {
181      int next = matcher.start();
182      if (next > prev) {
183        regex.append(Pattern.quote(globex.substring(prev, next)));
184      }
185      if (matcher.group(1) != null) {
186        regex.append(".*");
187      } else if (matcher.group(2) != null) {
188        regex.append(".");
189      } else if (matcher.group(3) != null) {
190        regex.append("[");
191        regex.append(Pattern.quote(matcher.group(3)));
192        regex.append("]");
193      } else if (matcher.group(4) != null) {
194        regex.append(Pattern.quote(Character.toString(matcher.group(4).charAt(1))));
195      } else {
196        throw new UnsupportedOperationException("Not handled yet");
197      }
198      prev = matcher.end();
199    }
200    if (prev < globex.length()) {
201      regex.append(Pattern.quote(globex.substring(prev)));
202    }
203    return regex.toString();
204  }
205
206}