1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package gov.nist.secauto.metaschema.schemagen.xml.impl;
7   
8   import gov.nist.secauto.metaschema.core.datatype.markup.MarkupLine;
9   import gov.nist.secauto.metaschema.core.datatype.markup.MarkupMultiline;
10  import gov.nist.secauto.metaschema.core.model.IDefinition;
11  import gov.nist.secauto.metaschema.core.model.IModelElement;
12  import gov.nist.secauto.metaschema.core.model.INamedInstance;
13  import gov.nist.secauto.metaschema.core.util.CollectionUtil;
14  import gov.nist.secauto.metaschema.schemagen.SchemaGenerationException;
15  import gov.nist.secauto.metaschema.schemagen.xml.XmlSchemaGenerator;
16  
17  import java.util.ArrayList;
18  import java.util.List;
19  
20  import javax.xml.stream.XMLStreamException;
21  
22  import edu.umd.cs.findbugs.annotations.NonNull;
23  import edu.umd.cs.findbugs.annotations.Nullable;
24  
25  public final class DocumentationGenerator {
26  
27    private final @Nullable String formalName;
28    private final @Nullable MarkupLine description;
29    private final @NonNull List<MarkupMultiline> remarks;
30    private final @NonNull IModelElement modelElement;
31  
32    private DocumentationGenerator(@NonNull IDefinition definition) {
33      this.formalName = definition.getEffectiveFormalName();
34      this.description = definition.getEffectiveDescription();
35  
36      MarkupMultiline remarks = definition.getRemarks();
37      this.remarks = remarks == null ? CollectionUtil.emptyList() : CollectionUtil.singletonList(remarks);
38  
39      this.modelElement = definition;
40    }
41  
42    private DocumentationGenerator(@NonNull INamedInstance instance) {
43      this.formalName = instance.getEffectiveFormalName();
44      this.description = instance.getEffectiveDescription();
45  
46      List<MarkupMultiline> remarks = new ArrayList<>(2);
47      MarkupMultiline remark = instance.getRemarks();
48      if (remark != null) {
49        remarks.add(remark);
50      }
51  
52      remark = instance.getDefinition().getRemarks();
53      if (remark != null) {
54        remarks.add(remark);
55      }
56  
57      this.remarks = CollectionUtil.listOrEmpty(remarks);
58  
59      this.modelElement = instance;
60    }
61  
62    @Nullable
63    public String getFormalName() {
64      return formalName;
65    }
66  
67    @Nullable
68    public MarkupLine getDescription() {
69      return description;
70    }
71  
72    @NonNull
73    public List<MarkupMultiline> getRemarks() {
74      return remarks;
75    }
76  
77    @NonNull
78    public IModelElement getModelElement() {
79      return modelElement;
80    }
81  
82    private void generate(@NonNull XmlGenerationState state) {
83      String formalName = getFormalName();
84      MarkupLine description = getDescription();
85      List<MarkupMultiline> remarks = getRemarks();
86  
87      if (formalName != null || description != null || !remarks.isEmpty()) {
88        generateDocumentation(formalName, description, remarks, state.getNS(getModelElement()), state);
89      }
90    }
91  
92    public static void generateDocumentation(
93        @NonNull IDefinition definition,
94        @NonNull XmlGenerationState state) {
95      new DocumentationGenerator(definition).generate(state);
96    }
97  
98    public static void generateDocumentation(
99        @NonNull INamedInstance instance,
100       @NonNull XmlGenerationState state) {
101     new DocumentationGenerator(instance).generate(state);
102   }
103 
104   public static void generateDocumentation( // NOPMD acceptable complexity
105       @Nullable String formalName,
106       @Nullable MarkupLine description,
107       @NonNull List<MarkupMultiline> remarks,
108       @NonNull String xmlNS, @NonNull XmlGenerationState state) {
109 
110     try {
111       state.writeStartElement(XmlSchemaGenerator.PREFIX_XML_SCHEMA, "annotation", XmlSchemaGenerator.NS_XML_SCHEMA);
112       if (formalName != null || description != null) {
113         state.writeStartElement(XmlSchemaGenerator.PREFIX_XML_SCHEMA, "appinfo", XmlSchemaGenerator.NS_XML_SCHEMA);
114 
115         if (formalName != null) {
116           state.writeStartElement(xmlNS, "formal-name");
117           state.writeCharacters(formalName);
118           state.writeEndElement();
119         }
120 
121         if (description != null) {
122           state.writeStartElement(xmlNS, "description");
123           description.writeXHtml(xmlNS, state.getXMLStreamWriter());
124           state.writeEndElement();
125         }
126 
127         state.writeEndElement(); // xs:appInfo
128       }
129 
130       state.writeStartElement(XmlSchemaGenerator.PREFIX_XML_SCHEMA, "documentation", XmlSchemaGenerator.NS_XML_SCHEMA);
131       state.writeNamespace("", XmlSchemaGenerator.NS_XHTML);
132 
133       if (description != null) {
134         // write description
135         state.writeStartElement(XmlSchemaGenerator.NS_XHTML, "p");
136 
137         if (formalName != null) {
138           state.writeStartElement(XmlSchemaGenerator.NS_XHTML, "b");
139           state.writeCharacters(formalName);
140           state.writeEndElement();
141           state.writeCharacters(": ");
142         }
143 
144         description.writeXHtml(XmlSchemaGenerator.NS_XHTML, state.getXMLStreamWriter());
145         state.writeEndElement(); // p
146       }
147 
148       for (MarkupMultiline remark : remarks) {
149         remark.writeXHtml(XmlSchemaGenerator.NS_XHTML, state.getXMLStreamWriter());
150       }
151 
152       state.writeEndElement(); // xs:documentation
153       state.writeEndElement(); // xs:annotation
154     } catch (XMLStreamException ex) {
155       throw new SchemaGenerationException(ex);
156     }
157   }
158 }