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.implementation;
020
021import org.apache.reef.tang.*;
022import org.apache.reef.tang.exceptions.BindException;
023import org.apache.reef.tang.exceptions.NameResolutionException;
024import org.apache.reef.tang.exceptions.ParseException;
025import org.apache.reef.tang.implementation.java.ClassHierarchyImpl;
026import org.apache.reef.tang.types.*;
027import org.apache.reef.tang.util.MonotonicMultiMap;
028import org.apache.reef.tang.util.TracingMonotonicMap;
029import org.apache.reef.tang.util.TracingMonotonicTreeMap;
030
031import java.net.URL;
032import java.util.List;
033import java.util.Map;
034import java.util.Map.Entry;
035import java.util.Set;
036
037public class ConfigurationBuilderImpl implements ConfigurationBuilder {
038  public final static String IMPORT = "import";
039  public final static String INIT = "<init>";
040  final TracingMonotonicMap<ClassNode<?>, ClassNode<?>> boundImpls = new TracingMonotonicTreeMap<>();
041  final TracingMonotonicMap<ClassNode<?>, ClassNode<? extends ExternalConstructor<?>>> boundConstructors = new TracingMonotonicTreeMap<>();
042  final Map<NamedParameterNode<?>, String> namedParameters = new TracingMonotonicTreeMap<>();
043  final Map<ClassNode<?>, ConstructorDef<?>> legacyConstructors = new TracingMonotonicTreeMap<>();
044  final MonotonicMultiMap<NamedParameterNode<Set<?>>, Object> boundSetEntries = new MonotonicMultiMap<>();
045  final TracingMonotonicMap<NamedParameterNode<List<?>>, List<Object>> boundLists = new TracingMonotonicTreeMap<>();
046  // TODO: None of these should be public! - Move to configurationBuilder. Have
047  // that wrap itself
048  // in a sane Configuration interface...
049  // TODO: Should be final again!
050  public ClassHierarchy namespace;
051
052  protected ConfigurationBuilderImpl() {
053    this.namespace = Tang.Factory.getTang().getDefaultClassHierarchy();
054  }
055
056  protected ConfigurationBuilderImpl(ClassHierarchy namespace) {
057    this.namespace = namespace;
058  }
059
060  protected ConfigurationBuilderImpl(URL[] jars, Configuration[] confs, Class<? extends ExternalConstructor<?>>[] parsers)
061      throws BindException {
062    this.namespace = Tang.Factory.getTang().getDefaultClassHierarchy(jars, parsers);
063    for (Configuration tc : confs) {
064      addConfiguration(((ConfigurationImpl) tc));
065    }
066  }
067
068  protected ConfigurationBuilderImpl(ConfigurationBuilderImpl t) {
069    this.namespace = t.getClassHierarchy();
070    try {
071      addConfiguration(t.getClassHierarchy(), t);
072    } catch (BindException e) {
073      throw new IllegalStateException("Could not copy builder", e);
074    }
075  }
076
077  @SuppressWarnings("unchecked")
078  protected ConfigurationBuilderImpl(URL... jars) throws BindException {
079    this(jars, new Configuration[0], new Class[0]);
080  }
081
082  @SuppressWarnings("unchecked")
083  protected ConfigurationBuilderImpl(Configuration... confs) throws BindException {
084    this(new URL[0], confs, new Class[0]);
085  }
086
087  @Override
088  public void addConfiguration(Configuration conf) throws BindException {
089    // XXX remove cast!
090    addConfiguration(conf.getClassHierarchy(), ((ConfigurationImpl) conf).builder);
091  }
092
093  @SuppressWarnings("unchecked")
094  private <T> void addConfiguration(ClassHierarchy ns, ConfigurationBuilderImpl builder)
095      throws BindException {
096    namespace = namespace.merge(ns);
097    if ((namespace instanceof ClassHierarchyImpl || builder.namespace instanceof ClassHierarchyImpl)) {
098      if ((namespace instanceof ClassHierarchyImpl && builder.namespace instanceof ClassHierarchyImpl)) {
099        ((ClassHierarchyImpl) namespace).parameterParser
100            .mergeIn(((ClassHierarchyImpl) builder.namespace).parameterParser);
101      } else {
102        throw new IllegalArgumentException("Attempt to merge Java and non-Java class hierarchy!  Not supported.");
103      }
104    }
105
106    for (ClassNode<?> cn : builder.boundImpls.keySet()) {
107      bind(cn.getFullName(), builder.boundImpls.get(cn).getFullName());
108    }
109    for (ClassNode<?> cn : builder.boundConstructors.keySet()) {
110      bind(cn.getFullName(), builder.boundConstructors.get(cn).getFullName());
111    }
112    // The namedParameters set contains the strings that can be used to
113    // instantiate new
114    // named parameter instances. Create new ones where we can.
115    for (NamedParameterNode<?> np : builder.namedParameters.keySet()) {
116      bind(np.getFullName(), builder.namedParameters.get(np));
117    }
118    for (ClassNode<?> cn : builder.legacyConstructors.keySet()) {
119      registerLegacyConstructor(cn, builder.legacyConstructors.get(cn)
120          .getArgs());
121    }
122    for (Entry<NamedParameterNode<Set<?>>, Object> e : builder.boundSetEntries) {
123      String name = ((NamedParameterNode<Set<T>>) (NamedParameterNode<?>) e.getKey()).getFullName();
124      if (e.getValue() instanceof Node) {
125        bindSetEntry(name, (Node) e.getValue());
126      } else if (e.getValue() instanceof String) {
127        bindSetEntry(name, (String) e.getValue());
128      } else {
129        throw new IllegalStateException();
130      }
131    }
132    // The boundLists set contains bound lists with their target NamedParameters
133    for (NamedParameterNode<List<?>> np : builder.boundLists.keySet()) {
134      bindList(np.getFullName(), builder.boundLists.get(np));
135    }
136  }
137
138  @Override
139  public ClassHierarchy getClassHierarchy() {
140    return namespace;
141  }
142
143  @Override
144  public void registerLegacyConstructor(ClassNode<?> c,
145                                        final ConstructorArg... args) throws BindException {
146    String cn[] = new String[args.length];
147    for (int i = 0; i < args.length; i++) {
148      cn[i] = args[i].getType();
149    }
150    registerLegacyConstructor(c.getFullName(), cn);
151  }
152
153  @Override
154  public void registerLegacyConstructor(String s, final String... args)
155      throws BindException {
156    ClassNode<?> cn = (ClassNode<?>) namespace.getNode(s);
157    ClassNode<?>[] cnArgs = new ClassNode[args.length];
158    for (int i = 0; i < args.length; i++) {
159      cnArgs[i] = (ClassNode<?>) namespace.getNode(args[i]);
160    }
161    registerLegacyConstructor(cn, cnArgs);
162  }
163
164  @Override
165  public void registerLegacyConstructor(ClassNode<?> cn,
166                                        final ClassNode<?>... args) throws BindException {
167    legacyConstructors.put(cn, cn.getConstructorDef(args));
168  }
169
170  @Override
171  public <T> void bind(String key, String value) throws BindException {
172    Node n = namespace.getNode(key);
173    if (n instanceof NamedParameterNode) {
174      bindParameter((NamedParameterNode<?>) n, value);
175    } else if (n instanceof ClassNode) {
176      Node m = namespace.getNode(value);
177      bind((ClassNode<?>) n, (ClassNode<?>) m);
178    } else {
179      throw new IllegalStateException("getNode() returned " + n + " which is neither a ClassNode nor a NamedParameterNode");
180    }
181  }
182
183  @SuppressWarnings({"unchecked", "rawtypes"})
184  public void bind(Node key, Node value) throws BindException {
185    if (key instanceof NamedParameterNode) {
186      bindParameter((NamedParameterNode<?>) key, value.getFullName());
187    } else if (key instanceof ClassNode) {
188      ClassNode<?> k = (ClassNode<?>) key;
189      if (value instanceof ClassNode) {
190        ClassNode<?> val = (ClassNode<?>) value;
191        if (val.isExternalConstructor() && !k.isExternalConstructor()) {
192          bindConstructor(k, (ClassNode) val);
193        } else {
194          bindImplementation(k, (ClassNode) val);
195        }
196      }
197    }
198  }
199
200  public <T> void bindImplementation(ClassNode<T> n, ClassNode<? extends T> m)
201      throws BindException {
202    if (namespace.isImplementation(n, m)) {
203      boundImpls.put(n, m);
204    } else {
205      throw new IllegalArgumentException("Class" + m + " does not extend " + n);
206    }
207  }
208
209  @SuppressWarnings({"unchecked", "rawtypes"})
210  public <T> void bindParameter(NamedParameterNode<T> name, String value)
211      throws BindException {
212    /* Parse and discard value; this is just for type checking */
213    if (namespace instanceof JavaClassHierarchy) {
214      ((JavaClassHierarchy) namespace).parse(name, value);
215    }
216    if (name.isSet()) {
217      bindSetEntry((NamedParameterNode) name, value);
218    } else {
219      namedParameters.put(name, value);
220    }
221  }
222
223  @SuppressWarnings("unchecked")
224  @Override
225  public void bindSetEntry(String iface, String impl)
226      throws BindException {
227    boundSetEntries.put((NamedParameterNode<Set<?>>) namespace.getNode(iface), impl);
228  }
229
230  @SuppressWarnings("unchecked")
231  @Override
232  public void bindSetEntry(String iface, Node impl)
233      throws BindException {
234    boundSetEntries.put((NamedParameterNode<Set<?>>) namespace.getNode(iface), impl);
235  }
236
237  @SuppressWarnings("unchecked")
238  @Override
239  public <T> void bindSetEntry(NamedParameterNode<Set<T>> iface, String impl)
240      throws BindException {
241    if (namespace instanceof ClassHierarchyImpl) {
242      JavaClassHierarchy javanamespace = (ClassHierarchyImpl) namespace;
243      try {
244        javanamespace.parse(iface, impl);
245      } catch (ParseException e) {
246        throw new IllegalStateException("Could not parse " + impl + " which was passed to " + iface);
247      }
248    }
249    boundSetEntries.put((NamedParameterNode<Set<?>>) (NamedParameterNode<?>) iface, impl);
250  }
251
252  @SuppressWarnings("unchecked")
253  @Override
254  public <T> void bindSetEntry(NamedParameterNode<Set<T>> iface, Node impl)
255      throws BindException {
256    boundSetEntries.put((NamedParameterNode<Set<?>>) (NamedParameterNode<?>) iface, impl);
257  }
258
259  @SuppressWarnings("unchecked")
260  @Override
261  public <T> void bindList(NamedParameterNode<List<T>> iface, List implList) {
262    // Check parsability of list items
263    for (Object item : implList) {
264      if (item instanceof String) {
265        JavaClassHierarchy javanamespace = (ClassHierarchyImpl) namespace;
266        try {
267          // Just for parsability checking.
268          javanamespace.parse(iface, (String) item);
269        } catch (ParseException e) {
270          throw new IllegalStateException("Could not parse " + item + " which was passed to " + iface);
271        }
272      }
273    }
274    boundLists.put((NamedParameterNode<List<?>>) (NamedParameterNode<?>) iface, implList);
275  }
276
277  @SuppressWarnings("unchecked")
278  @Override
279  public void bindList(String iface, List implList) {
280    NamedParameterNode<List<?>> ifaceNode = (NamedParameterNode<List<?>>) namespace.getNode(iface);
281    // Check parsability of list items
282    for (Object item : implList) {
283      if (item instanceof String) {
284        JavaClassHierarchy javanamespace = (ClassHierarchyImpl) namespace;
285        try {
286          // Just for parsability checking.
287          javanamespace.parse(ifaceNode, (String) item);
288        } catch (ParseException e) {
289          throw new IllegalStateException("Could not parse " + item + " which was passed to " + iface);
290        }
291      }
292    }
293    boundLists.put(ifaceNode, implList);
294  }
295
296  @Override
297  public <T> void bindConstructor(ClassNode<T> k,
298                                  ClassNode<? extends ExternalConstructor<? extends T>> v) {
299    boundConstructors.put(k, v);
300  }
301
302  @Override
303  public ConfigurationImpl build() {
304    return new ConfigurationImpl(new ConfigurationBuilderImpl(this));
305  }
306
307  @Override
308  public String classPrettyDefaultString(String longName) throws NameResolutionException {
309    final NamedParameterNode<?> param = (NamedParameterNode<?>) namespace
310        .getNode(longName);
311    return param.getSimpleArgName() + "=" + join(",", param.getDefaultInstanceAsStrings());
312  }
313
314  private String join(String sep, String[] s) {
315    if (s.length == 0) {
316      return null;
317    } else {
318      StringBuilder sb = new StringBuilder(s[0]);
319      for (int i = 1; i < s.length; i++) {
320        sb.append(sep);
321        sb.append(s[i]);
322      }
323      return sb.toString();
324    }
325  }
326
327  @Override
328  public String classPrettyDescriptionString(String fullName)
329      throws NameResolutionException {
330    final NamedParameterNode<?> param = (NamedParameterNode<?>) namespace
331        .getNode(fullName);
332    return param.getDocumentation() + "\n" + param.getFullName();
333  }
334
335  @Override
336  public boolean equals(final Object o) {
337    if (this == o) {
338      return true;
339    }
340    if (o == null || getClass() != o.getClass()) {
341      return false;
342    }
343
344    ConfigurationBuilderImpl that = (ConfigurationBuilderImpl) o;
345
346    if (boundConstructors != null ? !boundConstructors.equals(that.boundConstructors) : that.boundConstructors != null) {
347      return false;
348    }
349    if (boundImpls != null ? !boundImpls.equals(that.boundImpls) : that.boundImpls != null) {
350      return false;
351    }
352    if (boundSetEntries != null ? !boundSetEntries.equals(that.boundSetEntries) : that.boundSetEntries != null) {
353      return false;
354    }
355    if (boundLists != null ? !boundLists.equals(that.boundLists) : that.boundLists != null) {
356      return false;
357    }
358    if (legacyConstructors != null ? !legacyConstructors.equals(that.legacyConstructors) : that.legacyConstructors != null) {
359      return false;
360    }
361    if (namedParameters != null ? !namedParameters.equals(that.namedParameters) : that.namedParameters != null) {
362      return false;
363    }
364
365    return true;
366  }
367
368  @Override
369  public int hashCode() {
370    int result = boundImpls != null ? boundImpls.hashCode() : 0;
371    result = 31 * result + (boundConstructors != null ? boundConstructors.hashCode() : 0);
372    result = 31 * result + (namedParameters != null ? namedParameters.hashCode() : 0);
373    result = 31 * result + (legacyConstructors != null ? legacyConstructors.hashCode() : 0);
374    result = 31 * result + (boundSetEntries != null ? boundSetEntries.hashCode() : 0);
375    result = 31 * result + (boundLists != null ? boundLists.hashCode() : 0);
376    return result;
377  }
378}