public void processDirectory(File contentDir) throws Exception {
        Set<String> processedIds = new HashSet<>();
        List<Integer> manufacturerIds;

        if (!contentDir.exists()) {
            throw new RuntimeException("The input directory doesn't exist.");
        }
        // Get an index of all manufacturers that have their product data online
        File manufacturersFile = new File(contentDir, "manufacturers.xml");

        // Parse the content.
        SAXParserFactory factory = SAXParserFactory.newInstance();
        SAXParser saxParser = factory.newSAXParser();
        ManufacturerIdsHandler manufacturerIdsHandler = new ManufacturerIdsHandler();
        saxParser.parse(manufacturersFile, manufacturerIdsHandler);

        // Get the final list of manufacturer ids from the handler.
        manufacturerIds = manufacturerIdsHandler.getManufacturerIds();

        // For each manufacturer id, get the catalog / product index
        // This is a JSON file (Yeah ... I know ... why stick to one
        // format?)
        for (Integer manufacturerId : manufacturerIds) {
            File manufacturerDirectory = new File(contentDir, String.format("M-%04X", manufacturerId));
            if (!manufacturerDirectory.exists()) {
                continue;
            }

            // Read the catalog file for this manufacturer
            File indexFile = new File(manufacturerDirectory, "catalog.json");
            String fileContent = FileUtils.readFileToString(indexFile, "UTF-8");
            JSONObject jsonObject = new JSONObject(fileContent);

            // Iterate over all the products in the catalog and fetch each one.
            // Each request will result in a little ZIP file, that contains some
            // boilerplate files, but also an XML file with the product descriptor.
            JSONArray entries = jsonObject.getJSONArray("Entries");
            for (Object entry : entries) {
                if (!(entry instanceof JSONObject)) {
                    System.out.println("Unexpected entry type");
                    continue;
                }
                JSONArray applicationIdentifier = ((JSONObject) entry).getJSONArray("ApplicationIdentifier");
                int applicationId = applicationIdentifier.getInt(2) << 8 | applicationIdentifier.getInt(3);
                int applicationVersion = applicationIdentifier.getInt(4) & 0xFF;

                String productCode = String.format("M-%04X_A-%04X-%02X", manufacturerId, applicationId, applicationVersion);

                // Make sure we only output one id once.
                if (processedIds.contains(productCode)) {
                    continue;
                } else {
                    processedIds.add(productCode);
                }

                // Check If we've already got that file (There are no updates, just new versions)
                File[] files = manufacturerDirectory.listFiles((dir, name) -> name.startsWith(productCode) && name.endsWith(".xml"));

                // If we've found a file, get the information from it.
                if ((files != null) && (files.length > 0)) {
                    for (File file : files) {
                        processFile(file, manufacturerId, applicationId, applicationVersion);
                    }
                }
            }
        }
    }
Logic to crawl the local knx profile storage for further processing.
@param contentDir points to the directory maintained by the {@link KnxSpecificationStoreUpdater}
@throws Exception something went wrong
protocols/knxnetip/src/test/java/org/apache/plc4x/protocol/knxnetip/BaseKnxWebserviceContentProcessor.java