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 }