@Override
  public ConversionResult convert(final Path path) {

    ConversionResult result = new ConversionResult();

    // Check Asset is of the correct format
    if (!xlsDTableType.accept(path)) {
      result.addMessage("Source Asset is not an XLS Decision Table.", ConversionMessageType.ERROR);
      return result;
    }

    // Perform conversion!
    final GuidedDecisionTableGeneratorListener listener = parseAssets(path, result);

    // Root path for new resources is the same folder as the XLS file
    final Path context = Paths.convert(Paths.convert(path).getParent());

    // Add Ancillary resources
    createNewImports(context, listener.getImports(), result);
    createNewFunctions(context, listener.getImports(), listener.getFunctions(), result);
    createNewQueries(context, listener.getImports(), listener.getQueries(), result);
    makeNewJavaTypes(context, listener.getTypeDeclarations(), result);
    createNewGlobals(context, listener.getGlobals(), result);

    // Add Web Guided Decision Tables
    createNewDecisionTables(
        context, listener.getImports(), listener.getGuidedDecisionTables(), result);

    return result;
  }
  private void createNewDecisionTables(
      final Path context,
      final List<Import> imports,
      final List<GuidedDecisionTable52> dtables,
      final ConversionResult result) {
    if (dtables == null || dtables.isEmpty()) {
      return;
    }

    // Create new assets for Guided Decision Tables
    for (int iCounter = 0; iCounter < dtables.size(); iCounter++) {

      // Add imports
      final GuidedDecisionTable52 dtable = dtables.get(iCounter);
      for (Import item : imports) {
        dtable
            .getImports()
            .addImport(
                new org.drools.workbench.models.datamodel.imports.Import(item.getClassName()));
      }

      // Make new resource
      final String assetName = makeNewAssetName(dtable.getTableName(), guidedDTableType);
      guidedDecisionTableService.create(
          context, assetName, dtable, "Converted from XLS Decision Table");

      result.addMessage(
          "Created Guided Decision Table '" + assetName + "'", ConversionMessageType.INFO);
    }
  }
  private void createNewGlobals(
      final Path context, final List<Global> globals, final ConversionResult result) {
    if (globals == null || globals.isEmpty()) {
      return;
    }

    // Create new asset for Globals. All Globals can be in one file.
    final String assetName = makeNewAssetName("Global", globalsType);
    final GlobalsModel model = makeGlobalsModel(globals);
    globalsService.create(context, assetName, model, "Converted from XLS Decision Table");

    result.addMessage("Created Globals '" + assetName + "'", ConversionMessageType.INFO);
  }
  private void createNewImports(
      final Path context, final List<Import> imports, final ConversionResult result) {

    if (imports == null || imports.isEmpty()) {
      return;
    }

    // Load existing PackageImports
    ProjectImports projectImports = new ProjectImports();
    final org.uberfire.java.nio.file.Path nioExternalImportsPath =
        Paths.convert(context).resolve("project.imports");
    final Path externalImportsPath = Paths.convert(nioExternalImportsPath);
    if (Files.exists(nioExternalImportsPath)) {
      projectImports = importsService.load(externalImportsPath);
    }

    // Make collections of existing Imports so we don't duplicate them when adding the new
    List<String> existingImports = new ArrayList<String>();
    for (org.drools.workbench.models.datamodel.imports.Import item :
        projectImports.getImports().getImports()) {
      existingImports.add(item.getType());
    }

    // Add imports
    boolean isModified = false;
    for (Import item : imports) {
      if (!existingImports.contains(item.getClassName())) {
        isModified = true;
        result.addMessage(
            "Created Import for '" + item.getClassName() + "'.", ConversionMessageType.INFO);
        projectImports
            .getImports()
            .addImport(
                new org.drools.workbench.models.datamodel.imports.Import(item.getClassName()));
      }
    }

    // Save update
    if (isModified) {
      final Metadata metadata = metadataService.getMetadata(context);
      importsService.save(
          externalImportsPath, projectImports, metadata, "Imports added during XLS conversion");
    }
  }
  private void makeNewJavaTypes(
      final Path context, final List<String> declaredTypes, final ConversionResult result) {
    if (declaredTypes == null || declaredTypes.isEmpty()) {
      return;
    }

    final KieProject project = projectService.resolveProject(context);

    for (String declaredType : declaredTypes) {
      final FactModels factModels = FactModelPersistence.unmarshal(declaredType);
      final String packageName = factModels.getPackageName();
      final DataModel dataModel = new DataModelImpl();

      for (FactMetaModel factMetaModel : factModels.getModels()) {
        final DataObject dataObject = new DataObjectImpl(factMetaModel.getName(), packageName);
        dataObject.setSuperClassName(factMetaModel.getSuperType());
        final List<AnnotationMetaModel> annotationMetaModel = factMetaModel.getAnnotations();
        addAnnotations(dataObject, annotationMetaModel);

        final List<FieldMetaModel> fields = factMetaModel.getFields();

        for (FieldMetaModel fieldMetaModel : fields) {
          final String fieldName = fieldMetaModel.name;
          final String fieldType = fieldMetaModel.type;
          // Guvnor 5.5 (and earlier) does not have MultipleType
          boolean isMultiple = false;
          boolean isBaseType = orderedBaseTypes.containsValue(fieldType);
          ObjectProperty property = new ObjectPropertyImpl(fieldName, fieldType, isMultiple);
          property.setBaseType(isBaseType);

          // field has no annotation in Guvnor 5.5 (and earlier)
          dataObject.addProperty(property);

          result.addMessage(
              "Created Java Type " + getJavaTypeFQCN(dataObject), ConversionMessageType.INFO);
        }

        dataModel.getDataObjects().add(dataObject);
      }

      modellerService.saveModel(dataModel, project);
    }
  }
  private void createNewQueries(
      final Path context,
      final List<Import> imports,
      final List<String> queries,
      final ConversionResult result) {
    if (queries == null || queries.isEmpty()) {
      return;
    }

    // Create new assets for Queries
    for (int iCounter = 0; iCounter < queries.size(); iCounter++) {

      final String assetName = makeNewAssetName("Query " + (iCounter + 1), drlType);
      final String drl = makeDRL(imports, queries.get(iCounter));
      drlService.create(context, assetName, drl, "Converted from XLS Decision Table");

      result.addMessage("Created Query '" + assetName + "'", ConversionMessageType.INFO);
    }
  }
  private GuidedDecisionTableGeneratorListener parseAssets(
      final Path path, final ConversionResult result) {

    final List<DataListener> listeners = new ArrayList<DataListener>();
    final GuidedDecisionTableGeneratorListener listener =
        new GuidedDecisionTableGeneratorListener(result);
    listeners.add(listener);

    final ExcelParser parser = new ExcelParser(listeners);
    final InputStream stream = ioService.newInputStream(Paths.convert(path));

    try {
      parser.parseFile(stream);
    } finally {
      try {
        stream.close();
      } catch (IOException ioe) {
        result.addMessage(ioe.getMessage(), ConversionMessageType.ERROR);
      }
    }
    return listener;
  }