This project has retired. For details please refer to its Attic page.
Source code
001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.reef.tang.formats;
020
021import org.apache.reef.tang.ExternalConstructor;
022import org.apache.reef.tang.exceptions.BindException;
023import org.apache.reef.tang.util.MonotonicTreeMap;
024import org.apache.reef.tang.util.ReflectionUtilities;
025
026import java.lang.reflect.Constructor;
027import java.lang.reflect.Type;
028import java.util.Collections;
029import java.util.HashSet;
030import java.util.Set;
031
032public class ParameterParser {
033  private static final Set<String> BUILTIN_NAMES = new HashSet<String>() {
034    private static final long serialVersionUID = 1L;
035
036    {
037      Collections.addAll(this,
038          String.class.getName(),
039          Byte.class.getName(),
040          Character.class.getName(),
041          Short.class.getName(),
042          Integer.class.getName(),
043          Long.class.getName(),
044          Float.class.getName(),
045          Double.class.getName(),
046          Boolean.class.getName(),
047          Void.class.getName());
048    }
049  };
050  MonotonicTreeMap<String, Constructor<? extends ExternalConstructor<?>>> parsers = new MonotonicTreeMap<>();
051
052  @SuppressWarnings({"unchecked", "rawtypes"})
053  public void addParser(Class<? extends ExternalConstructor<?>> ec) throws BindException {
054    Class<?> tc = (Class<?>) ReflectionUtilities.getInterfaceTarget(
055        ExternalConstructor.class, ec);
056    addParser((Class) tc, (Class) ec);
057  }
058
059  public <T, U extends T> void addParser(Class<U> clazz, Class<? extends ExternalConstructor<T>> ec) throws BindException {
060    Constructor<? extends ExternalConstructor<T>> c;
061    try {
062      c = ec.getDeclaredConstructor(String.class);
063      c.setAccessible(true);
064    } catch (NoSuchMethodException e) {
065      throw new BindException("Constructor "
066          + ReflectionUtilities.getFullName(ec) + "(String) does not exist!", e);
067    }
068    c.setAccessible(true);
069    parsers.put(ReflectionUtilities.getFullName(clazz), c);
070  }
071
072  public void mergeIn(ParameterParser p) {
073    for (String s : p.parsers.keySet()) {
074      if (!parsers.containsKey(s)) {
075        parsers.put(s, p.parsers.get(s));
076      } else {
077        if (!parsers.get(s).equals(p.parsers.get(s))) {
078          throw new IllegalArgumentException(
079              "Conflict detected when merging parameter parsers! To parse " + s
080                  + " I have a: " + ReflectionUtilities.getFullName(parsers.get(s).getDeclaringClass())
081                  + " the other instance has a: " + ReflectionUtilities.getFullName(p.parsers.get(s).getDeclaringClass()));
082        }
083      }
084    }
085  }
086
087  public <T> T parse(Class<T> c, String s) {
088    Class<?> d = ReflectionUtilities.boxClass(c);
089    for (Type e : ReflectionUtilities.classAndAncestors(d)) {
090      String name = ReflectionUtilities.getFullName(e);
091      if (parsers.containsKey(name)) {
092        T ret = parse(name, s);
093        if (c.isAssignableFrom(ret.getClass())) {
094          return ret;
095        } else {
096          throw new ClassCastException("Cannot cast from " + ret.getClass() + " to " + c);
097        }
098      }
099    }
100    return parse(ReflectionUtilities.getFullName(d), s);
101  }
102
103  @SuppressWarnings("unchecked")
104  public <T> T parse(String name, String value) {
105    if (parsers.containsKey(name)) {
106      try {
107        return (T) (parsers.get(name).newInstance(value).newInstance());
108      } catch (ReflectiveOperationException e) {
109        throw new IllegalArgumentException("Error invoking constructor for "
110            + name, e);
111      }
112    } else {
113      if (name.equals(String.class.getName())) {
114        return (T) value;
115      }
116      if (name.equals(Byte.class.getName())) {
117        return (T) (Byte) Byte.parseByte(value);
118      }
119      if (name.equals(Character.class.getName())) {
120        return (T) (Character) value.charAt(0);
121      }
122      if (name.equals(Short.class.getName())) {
123        return (T) (Short) Short.parseShort(value);
124      }
125      if (name.equals(Integer.class.getName())) {
126        return (T) (Integer) Integer.parseInt(value);
127      }
128      if (name.equals(Long.class.getName())) {
129        return (T) (Long) Long.parseLong(value);
130      }
131      if (name.equals(Float.class.getName())) {
132        return (T) (Float) Float.parseFloat(value);
133      }
134      if (name.equals(Double.class.getName())) {
135        return (T) (Double) Double.parseDouble(value);
136      }
137      if (name.equals(Boolean.class.getName())) {
138        return (T) (Boolean) Boolean.parseBoolean(value);
139      }
140      if (name.equals(Void.class.getName())) {
141        throw new ClassCastException("Can't instantiate void");
142      }
143      throw new UnsupportedOperationException("Don't know how to parse a " + name);
144    }
145  }
146
147  public boolean canParse(String name) {
148    return parsers.containsKey(name) || BUILTIN_NAMES.contains(name);
149  }
150}