docs: @Override
      synchronized public Map<String, Serializable> generateDDL() {
          Map<String, Serializable> returnMap = new HashMap<String, Serializable>();
          WsResource ddlOutputDirectory = locationService.get().resolveResource(OUTPUT_DIR);
          if (ddlOutputDirectory.exists() == false) {
              ddlOutputDirectory.create();
          }
  
          // Try to put the canonical path to the DDL output directory in the results.  
          // If we can't, then put the symbolic name.
          try {
              returnMap.put(OUTPUT_DIRECTORY, ddlOutputDirectory.asFile().getCanonicalPath());
          } catch (IOException ioe) {
              returnMap.put(OUTPUT_DIRECTORY, OUTPUT_DIR);
          }
          boolean success = true;
          int fileCount = 0;
  
          Map<String, DDLGenerationParticipant> participants = new HashMap<String, DDLGenerationParticipant>();
          Iterator<ServiceAndServiceReferencePair<DDLGenerationParticipant>> i = generators.getServicesWithReferences();
          while (i.hasNext()) {
              // We'll request the DDL be written to a file whose name is chosen by the component providing the service.
              ServiceAndServiceReferencePair<DDLGenerationParticipant> generatorPair = i.next();
              DDLGenerationParticipant generator = generatorPair.getService();
              String rawId = generator.getDDLFileName();
  
              // Remove any restricted characters from the file name, and make sure
              // that the resulting string is not empty.  If it's empty, supply a
              // default name.
              String id = (rawId != null) ? PathUtils.replaceRestrictedCharactersInFileName(rawId) : null;
              if ((id == null) || (id.length() == 0)) {
                  throw new IllegalArgumentException("Service " + generator.toString() + " DDL file name: " + rawId);
              }
  
              participants.put(id, generator);
          }
  
          for (Map.Entry<String, DDLGenerationParticipant> entry : participants.entrySet()) {
              String id = entry.getKey();
              DDLGenerationParticipant participant = entry.getValue();
  
              // The path to the file is in the server's output directory.
              WsResource ddlOutputResource = locationService.get().resolveResource(OUTPUT_DIR + id + ".ddl");
              if (ddlOutputResource.exists() == false) {
                  ddlOutputResource.create();
              }
  
              // Use the text file output stream factory to create the file so that
              // it is readable on distributed and z/OS platforms.  Overwrite the
              // file if it already exists.  We have to specify the encoding explicitly
              // on the OutputStreamWriter or Findbugs gets upset.  We always specify
              // UTF-8 because the output DDL might have UNICODE characters.  We use
              // a TextFileOutputStreamFactory in an attempt to make the file readable
              // on z/OS.  The file will be tagged as 'ISO8859-1' on z/OS, allowing at
              // least some of the characters to be printable.  The z/OS chtag command
              // does not appear to honor 'UTF-8' as an encoding, even though iconv
              // supports it.  The data on the disk will be correct in any case, the
              // customer may need to FTP it to a distributed machine, or use iconv,
              // to be able to view the data.
              try {
                  TextFileOutputStreamFactory f = TrConfigurator.getFileOutputStreamFactory();
                  OutputStream os = f.createOutputStream(ddlOutputResource.asFile(), false);
                  BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
                  participant.generate(bw);
  
                  // The JPA code may close the stream for us.  Just make sure it's
                  // closed so that we flush any data out.
                  bw.close();
                  fileCount++;
              } catch (Throwable t) {
                  // We'll get an FFDC here... indicate that we had trouble. 
                  success = false;
              }
          }
  
          returnMap.put(SUCCESS, Boolean.valueOf(success));
          returnMap.put(FILE_COUNT, Integer.valueOf(fileCount));
          return returnMap;
      }