/**
  * serialize a class hierarchy into a file.
  *
  * @param file
  * @param classHierarchy
  * @throws IOException
  */
 public static void serialize(final File file, final ClassHierarchy classHierarchy)
     throws IOException {
   final ClassHierarchyProto.Node node = serializeNode(classHierarchy.getNamespace());
   try (final FileOutputStream output = new FileOutputStream(file)) {
     try (final DataOutputStream dos = new DataOutputStream(output)) {
       node.writeTo(dos);
     }
   }
 }
 /**
  * Deserialize a class hierarchy from a protocol buffer object. The resulting object is immutable,
  * and does not make use of reflection to fill in any missing values. This allows it to represent
  * non-native classes as well as snapshots of Java class hierarchies.
  */
 public ProtocolBufferClassHierarchy(ClassHierarchyProto.Node root) {
   namespace = new PackageNodeImpl();
   if (!root.hasPackageNode()) {
     throw new IllegalArgumentException("Expected a package node.  Got: " + root);
   }
   // Register all the classes.
   for (ClassHierarchyProto.Node child : root.getChildrenList()) {
     parseSubHierarchy(namespace, child);
   }
   buildLookupTable(namespace);
   // Now, register the implementations
   for (ClassHierarchyProto.Node child : root.getChildrenList()) {
     wireUpInheritanceRelationships(child);
   }
 }
  private static ClassHierarchyProto.Node newNamedParameterNode(
      String name,
      String fullName,
      String simpleArgClassName,
      String fullArgClassName,
      boolean isSet,
      boolean isList,
      String documentation, // can be null
      String shortName, // can be null
      String[] instanceDefault, // can be null
      Iterable<ClassHierarchyProto.Node> children) {
    ClassHierarchyProto.NamedParameterNode.Builder namedParameterNodeBuilder =
        ClassHierarchyProto.NamedParameterNode.newBuilder()
            .setSimpleArgClassName(simpleArgClassName)
            .setFullArgClassName(fullArgClassName)
            .setIsSet(isSet)
            .setIsList(isList);
    if (documentation != null) {
      namedParameterNodeBuilder.setDocumentation(documentation);
    }
    if (shortName != null) {
      namedParameterNodeBuilder.setShortName(shortName);
    }
    if (instanceDefault != null) {
      namedParameterNodeBuilder.addAllInstanceDefault(Arrays.asList(instanceDefault));
    }

    return ClassHierarchyProto.Node.newBuilder()
        .setName(name)
        .setFullName(fullName)
        .setNamedParameterNode(namedParameterNodeBuilder.build())
        .addAllChildren(children)
        .build();
  }
 private static ClassHierarchyProto.Node newClassNode(
     String name,
     String fullName,
     boolean isInjectionCandidate,
     boolean isExternalConstructor,
     boolean isUnit,
     List<ClassHierarchyProto.ConstructorDef> injectableConstructors,
     List<ClassHierarchyProto.ConstructorDef> otherConstructors,
     List<String> implFullNames,
     Iterable<ClassHierarchyProto.Node> children) {
   return ClassHierarchyProto.Node.newBuilder()
       .setName(name)
       .setFullName(fullName)
       .setClassNode(
           ClassHierarchyProto.ClassNode.newBuilder()
               .setIsInjectionCandidate(isInjectionCandidate)
               .setIsExternalConstructor(isExternalConstructor)
               .setIsUnit(isUnit)
               .addAllInjectableConstructors(injectableConstructors)
               .addAllOtherConstructors(otherConstructors)
               .addAllImplFullNames(implFullNames)
               .build())
       .addAllChildren(children)
       .build();
 }
  public void validatePlan() throws IOException, BindException, InjectionException {

    final Tang t = Tang.Factory.getTang();

    // TODO Use the AvroClassHierarchySerializer
    final ClassHierarchyProto.Node root;
    try (final InputStream chin = new FileInputStream(this.ch)) {
      root = ClassHierarchyProto.Node.parseFrom(chin);
    }

    final ClassHierarchy classHierarchy = new ProtocolBufferClassHierarchy(root);
    final ConfigurationBuilder cb = t.newConfigurationBuilder(classHierarchy);

    if (!inConfig.canRead()) {
      throw new IOException("Cannot read input config file: " + inConfig);
    }

    ConfigurationFile.addConfiguration(cb, inConfig);

    if (target != null) {
      final Injector i = t.newInjector(cb.build());
      final InjectionPlan<?> ip = i.getInjectionPlan(target);
      if (!ip.isInjectable()) {
        throw new InjectionException(target + " is not injectable: " + ip.toCantInjectString());
      }
    }

    ConfigurationFile.writeConfigurationFile(cb.build(), outConfig);

    //    Injector i = t.newInjector(cb.build());
    //    InjectionPlan<?> ip = i.getInjectionPlan(target);
    //    try (final OutputStream ipout = new FileOutputStream(injectionPlan)) {
    //      new ProtocolBufferInjectionPlan().serialize(ip).writeTo(ipout);
    //    }
  }
 private static ClassHierarchyProto.Node newPackageNode(
     String name, String fullName, Iterable<ClassHierarchyProto.Node> children) {
   return ClassHierarchyProto.Node.newBuilder()
       .setPackageNode(ClassHierarchyProto.PackageNode.newBuilder().build())
       .setName(name)
       .setFullName(fullName)
       .addAllChildren(children)
       .build();
 }
  @SuppressWarnings({"rawtypes", "unchecked"})
  private void wireUpInheritanceRelationships(final ClassHierarchyProto.Node n) {
    if (n.hasClassNode()) {
      final ClassHierarchyProto.ClassNode cn = n.getClassNode();
      final ClassNode iface;
      try {
        iface = (ClassNode) getNode(n.getFullName());
      } catch (NameResolutionException e) {
        throw new IllegalStateException(
            "When reading protocol buffer node "
                + n.getFullName()
                + " does not exist.  Full record is "
                + n,
            e);
      }
      for (String impl : cn.getImplFullNamesList()) {
        try {
          iface.putImpl((ClassNode) getNode(impl));
        } catch (NameResolutionException e) {
          throw new IllegalStateException(
              "When reading protocol buffer node "
                  + n
                  + " refers to non-existent implementation:"
                  + impl);
        } catch (ClassCastException e) {
          try {
            throw new IllegalStateException(
                "When reading protocol buffer node "
                    + n
                    + " found implementation"
                    + getNode(impl)
                    + " which is not a ClassNode!");
          } catch (NameResolutionException e2) {
            throw new IllegalStateException(
                "Got 'cant happen' exception when producing error message for " + e);
          }
        }
      }
    }

    for (ClassHierarchyProto.Node child : n.getChildrenList()) {
      wireUpInheritanceRelationships(child);
    }
  }
  private static void parseSubHierarchy(Node parent, ClassHierarchyProto.Node n) {
    final Node parsed;
    if (n.hasPackageNode()) {
      parsed = new PackageNodeImpl(parent, n.getName(), n.getFullName());
    } else if (n.hasNamedParameterNode()) {
      ClassHierarchyProto.NamedParameterNode np = n.getNamedParameterNode();
      parsed =
          new NamedParameterNodeImpl<Object>(
              parent,
              n.getName(),
              n.getFullName(),
              np.getFullArgClassName(),
              np.getSimpleArgClassName(),
              np.getIsSet(),
              np.getIsList(),
              np.getDocumentation(),
              np.getShortName(),
              np.getInstanceDefaultList().toArray(new String[0]));
    } else if (n.hasClassNode()) {
      ClassHierarchyProto.ClassNode cn = n.getClassNode();
      List<ConstructorDef<?>> injectableConstructors = new ArrayList<>();
      List<ConstructorDef<?>> allConstructors = new ArrayList<>();

      for (ClassHierarchyProto.ConstructorDef injectable : cn.getInjectableConstructorsList()) {
        ConstructorDef<?> def = parseConstructorDef(injectable, true);
        injectableConstructors.add(def);
        allConstructors.add(def);
      }
      for (ClassHierarchyProto.ConstructorDef other : cn.getOtherConstructorsList()) {
        ConstructorDef<?> def = parseConstructorDef(other, false);
        allConstructors.add(def);
      }
      @SuppressWarnings("unchecked")
      ConstructorDef<Object>[] dummy = new ConstructorDef[0];
      parsed =
          new ClassNodeImpl<>(
              parent,
              n.getName(),
              n.getFullName(),
              cn.getIsUnit(),
              cn.getIsInjectionCandidate(),
              cn.getIsExternalConstructor(),
              injectableConstructors.toArray(dummy),
              allConstructors.toArray(dummy),
              cn.getDefaultImplementation());
    } else {
      throw new IllegalStateException("Bad protocol buffer: got abstract node" + n);
    }
    for (ClassHierarchyProto.Node child : n.getChildrenList()) {
      parseSubHierarchy(parsed, child);
    }
  }
 /**
  * Deserialize a class hierarchy from a file. The file can be generated from either Java or C#
  *
  * @param file
  * @return
  * @throws IOException
  */
 public static ClassHierarchy deserialize(final File file) throws IOException {
   try (final InputStream stream = new FileInputStream(file)) {
     final ClassHierarchyProto.Node root = ClassHierarchyProto.Node.parseFrom(stream);
     return new ProtocolBufferClassHierarchy(root);
   }
 }