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    
020    package org.crsh.cli.type;
021    
022    import org.crsh.cli.completers.EmptyCompleter;
023    import org.crsh.cli.completers.EnumCompleter;
024    import org.crsh.cli.completers.ThreadCompleter;
025    import org.crsh.cli.spi.Completer;
026    
027    import javax.management.ObjectName;
028    import java.util.Properties;
029    import java.util.StringTokenizer;
030    
031    /**
032     * A type for values.
033     *
034     * @param <V> the generic value type
035     */
036    public abstract class ValueType<V> {
037    
038      /** . */
039      public static final ValueType<String> STRING = new ValueType<String>(String.class) {
040        @Override
041        public <S extends String> S parse(Class<S> type, String s) throws Exception {
042          return type.cast(s);
043        }
044      };
045    
046      /** . */
047      public static final ValueType<Integer> INTEGER = new ValueType<Integer>(Integer.class) {
048        @Override
049        public <S extends Integer> S parse(Class<S> type, String s) throws Exception {
050          return type.cast(Integer.parseInt(s));
051        }
052      };
053    
054      /** . */
055      public static final ValueType<Boolean> BOOLEAN = new ValueType<Boolean>(Boolean.class) {
056        @Override
057        public <S extends Boolean> S parse(Class<S> type, String s) throws Exception {
058          return type.cast(Boolean.parseBoolean(s));
059        }
060      };
061    
062      /** . */
063      public static final ValueType<Enum> ENUM = new ValueType<Enum>(Enum.class, EnumCompleter.class) {
064        @Override
065        public <S extends Enum> S parse(Class<S> type, String s) {
066          // We cannot express S extends Enum<S> type
067          // so we need this necessary cast to make the java compiler happy
068          S s1 = (S)Enum.valueOf(type, s);
069          return s1;
070        }
071      };
072    
073      /** . */
074      public static final ValueType<Properties> PROPERTIES = new ValueType<Properties>(Properties.class) {
075        @Override
076        public <S extends Properties> S parse(Class<S> type, String s) throws Exception {
077          java.util.Properties props = new java.util.Properties();
078          StringTokenizer tokenizer = new StringTokenizer(s, ";", false);
079          while(tokenizer.hasMoreTokens()){
080            String token = tokenizer.nextToken();
081            if(token.contains("=")) {
082              String key = token.substring(0, token.indexOf('='));
083              String value = token.substring(token.indexOf('=') + 1, token.length());
084              props.put(key, value);
085            }
086          }
087          return type.cast(props);
088        }
089      };
090    
091      /** . */
092      public static final ValueType<ObjectName> OBJECT_NAME = new ValueType<ObjectName>(ObjectName.class) {
093        @Override
094        public <S extends ObjectName> S parse(Class<S> type, String s) throws Exception {
095          return type.cast(ObjectName.getInstance(s));
096        }
097      };
098    
099      /** . */
100      public static final ValueType<Thread> THREAD = new ValueType<Thread>(Thread.class, ThreadCompleter.class) {
101        @Override
102        public <S extends Thread> S parse(Class<S> type, String s) throws Exception {
103          long id = Long.parseLong(s);
104          for (Thread t : Thread.getAllStackTraces().keySet()) {
105            if (t.getId() == id) {
106              return type.cast(t);
107            }
108          }
109          throw new IllegalArgumentException("No thread " + s );
110        }
111      };
112    
113      /** . */
114      protected final Class<V> type;
115    
116      /** . */
117      protected final Class<? extends Completer> completer;
118    
119      protected ValueType(Class<V> type, Class<? extends Completer> completer) throws NullPointerException {
120        if (type == null) {
121          throw new NullPointerException("No null value type accepted");
122        }
123        if (completer == null) {
124          throw new NullPointerException("No null completer accepted");
125        }
126    
127        //
128        this.completer = completer;
129        this.type = type;
130      }
131    
132      protected ValueType(Class<V> type) throws NullPointerException {
133        if (type == null) {
134          throw new NullPointerException("No null value type accepted");
135        }
136    
137        //
138        this.completer = EmptyCompleter.class;
139        this.type = type;
140      }
141    
142      final int getDistance(Class<?> clazz) {
143        if (type == clazz) {
144          return 0;
145        } else if (type.isAssignableFrom(clazz)) {
146          int degree = 0;
147          for (Class<?> current = clazz;current != type;current = current.getSuperclass()) {
148            degree++;
149          }
150          return degree;
151        } else {
152          return -1;
153        }
154      }
155    
156      @Override
157      public final int hashCode() {
158        return type.hashCode();
159      }
160    
161      @Override
162      public final boolean equals(Object obj) {
163        if (obj == null) {
164          return false;
165        } else {
166          if (obj == this) {
167            return true;
168          } else {
169            if (obj.getClass() == ValueType.class) {
170              ValueType that = (ValueType)obj;
171              return type == that.type;
172            } else {
173              return false;
174            }
175          }
176        }
177      }
178    
179      public Class<? extends Completer> getCompleter() {
180        return completer;
181      }
182    
183      public final Class<V> getType() {
184        return type;
185      }
186    
187      public final V parse(String s) throws Exception {
188        return parse(type, s);
189      }
190    
191      public abstract <S extends V> S parse(Class<S> type, String s) throws Exception;
192    
193    }