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  private MonotonicTreeMap<String, Constructor<? extends ExternalConstructor<?>>> parsers = new MonotonicTreeMap<>();
051
052  @SuppressWarnings({"unchecked", "rawtypes"})
053  public void addParser(final Class<? extends ExternalConstructor<?>> ec) throws BindException {
054    final 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(final Class<U> clazz, final Class<? extends ExternalConstructor<T>> ec)
060      throws BindException {
061    final Constructor<? extends ExternalConstructor<T>> c;
062    try {
063      c = ec.getDeclaredConstructor(String.class);
064      c.setAccessible(true);
065    } catch (final NoSuchMethodException e) {
066      throw new BindException("Constructor "
067          + ReflectionUtilities.getFullName(ec) + "(String) does not exist!", e);
068    }
069    c.setAccessible(true);
070    parsers.put(ReflectionUtilities.getFullName(clazz), c);
071  }
072
073  public void mergeIn(final ParameterParser p) {
074    for (final String s : p.parsers.keySet()) {
075      if (!parsers.containsKey(s)) {
076        parsers.put(s, p.parsers.get(s));
077      } else {
078        if (!parsers.get(s).equals(p.parsers.get(s))) {
079          throw new IllegalArgumentException(
080              "Conflict detected when merging parameter parsers! To parse " + s
081                  + " I have a: " + ReflectionUtilities.getFullName(parsers.get(s).getDeclaringClass())
082                  + " the other instance has a: "
083                  + ReflectionUtilities.getFullName(p.parsers.get(s).getDeclaringClass()));
084        }
085      }
086    }
087  }
088
089  public <T> T parse(final Class<T> c, final String s) {
090    final Class<?> d = ReflectionUtilities.boxClass(c);
091    for (final Type e : ReflectionUtilities.classAndAncestors(d)) {
092      final String name = ReflectionUtilities.getFullName(e);
093      if (parsers.containsKey(name)) {
094        final T ret = parse(name, s);
095        if (c.isAssignableFrom(ret.getClass())) {
096          return ret;
097        } else {
098          throw new ClassCastException("Cannot cast from " + ret.getClass() + " to " + c);
099        }
100      }
101    }
102    return parse(ReflectionUtilities.getFullName(d), s);
103  }
104
105  @SuppressWarnings("unchecked")
106  public <T> T parse(final String name, final String value) {
107    if (parsers.containsKey(name)) {
108      try {
109        return (T) (parsers.get(name).newInstance(value).newInstance());
110      } catch (final ReflectiveOperationException e) {
111        throw new IllegalArgumentException("Error invoking constructor for "
112            + name, e);
113      }
114    } else {
115      if (name.equals(String.class.getName())) {
116        return (T) value;
117      }
118      if (name.equals(Byte.class.getName())) {
119        return (T) (Byte) Byte.parseByte(value);
120      }
121      if (name.equals(Character.class.getName())) {
122        return (T) (Character) value.charAt(0);
123      }
124      if (name.equals(Short.class.getName())) {
125        return (T) (Short) Short.parseShort(value);
126      }
127      if (name.equals(Integer.class.getName())) {
128        return (T) (Integer) Integer.parseInt(value);
129      }
130      if (name.equals(Long.class.getName())) {
131        return (T) (Long) Long.parseLong(value);
132      }
133      if (name.equals(Float.class.getName())) {
134        return (T) (Float) Float.parseFloat(value);
135      }
136      if (name.equals(Double.class.getName())) {
137        return (T) (Double) Double.parseDouble(value);
138      }
139      if (name.equals(Boolean.class.getName())) {
140        return (T) (Boolean) Boolean.parseBoolean(value);
141      }
142      if (name.equals(Void.class.getName())) {
143        throw new ClassCastException("Can't instantiate void");
144      }
145      throw new UnsupportedOperationException("Don't know how to parse a " + name);
146    }
147  }
148
149  public boolean canParse(final String name) {
150    return parsers.containsKey(name) || BUILTIN_NAMES.contains(name);
151  }
152}