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